ghash/
lib.rs

1//! **GHASH**: universal hash over GF(2^128) used by AES-GCM for message
2//! authentication (i.e. GMAC).
3//!
4//! ## Implementation Notes
5//!
6//! The implementation of GHASH found in this crate internally uses the
7//! [`polyval`] crate, which provides a similar universal hash function used by
8//! AES-GCM-SIV (RFC 8452).
9//!
10//! By implementing GHASH in terms of POLYVAL, the two universal hash functions
11//! can share a common core, meaning any optimization work (e.g. CPU-specific
12//! SIMD implementations) which happens upstream in the `polyval` crate
13//! benefits GHASH as well.
14//!
15//! From RFC 8452 Appendix A:
16//! <https://tools.ietf.org/html/rfc8452#appendix-A>
17//!
18//! > GHASH and POLYVAL both operate in GF(2^128), although with different
19//! > irreducible polynomials: POLYVAL works modulo x^128 + x^127 + x^126 +
20//! > x^121 + 1 and GHASH works modulo x^128 + x^7 + x^2 + x + 1.  Note
21//! > that these irreducible polynomials are the "reverse" of each other.
22//!
23//! [`polyval`]: https://github.com/RustCrypto/universal-hashes/tree/master/polyval
24
25#![no_std]
26#![doc(
27    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
28    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
29)]
30#![warn(missing_docs, rust_2018_idioms)]
31
32pub use polyval::universal_hash;
33
34use polyval::Polyval;
35use universal_hash::{
36    consts::U16,
37    crypto_common::{BlockSizeUser, KeySizeUser, ParBlocksSizeUser},
38    KeyInit, UhfBackend, UhfClosure, UniversalHash,
39};
40
41#[cfg(feature = "zeroize")]
42use zeroize::Zeroize;
43
44/// GHASH keys (16-bytes)
45pub type Key = universal_hash::Key<GHash>;
46
47/// GHASH blocks (16-bytes)
48pub type Block = universal_hash::Block<GHash>;
49
50/// GHASH tags (16-bytes)
51pub type Tag = universal_hash::Block<GHash>;
52
53/// **GHASH**: universal hash over GF(2^128) used by AES-GCM.
54///
55/// GHASH is a universal hash function used for message authentication in
56/// the AES-GCM authenticated encryption cipher.
57#[derive(Clone)]
58pub struct GHash(Polyval);
59
60impl KeySizeUser for GHash {
61    type KeySize = U16;
62}
63
64impl GHash {
65    /// Initialize GHASH with the given `H` field element and initial block
66    #[inline]
67    pub fn new_with_init_block(h: &Key, init_block: u128) -> Self {
68        let mut h = *h;
69        h.reverse();
70
71        #[allow(unused_mut)]
72        let mut h_polyval = polyval::mulx(&h);
73
74        #[cfg(feature = "zeroize")]
75        h.zeroize();
76
77        #[allow(clippy::let_and_return)]
78        let result = GHash(Polyval::new_with_init_block(&h_polyval, init_block));
79
80        #[cfg(feature = "zeroize")]
81        h_polyval.zeroize();
82
83        result
84    }
85}
86
87impl KeyInit for GHash {
88    /// Initialize GHASH with the given `H` field element
89    #[inline]
90    fn new(h: &Key) -> Self {
91        Self::new_with_init_block(h, 0)
92    }
93}
94
95struct GHashBackend<'b, B: UhfBackend>(&'b mut B);
96
97impl<'b, B: UhfBackend> BlockSizeUser for GHashBackend<'b, B> {
98    type BlockSize = B::BlockSize;
99}
100
101impl<'b, B: UhfBackend> ParBlocksSizeUser for GHashBackend<'b, B> {
102    type ParBlocksSize = B::ParBlocksSize;
103}
104
105impl<'b, B: UhfBackend> UhfBackend for GHashBackend<'b, B> {
106    fn proc_block(&mut self, x: &universal_hash::Block<B>) {
107        let mut x = x.clone();
108        x.reverse();
109        self.0.proc_block(&x);
110    }
111}
112
113impl BlockSizeUser for GHash {
114    type BlockSize = U16;
115}
116
117impl UniversalHash for GHash {
118    fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>) {
119        struct GHashClosure<C: UhfClosure>(C);
120
121        impl<C: UhfClosure> BlockSizeUser for GHashClosure<C> {
122            type BlockSize = C::BlockSize;
123        }
124
125        impl<C: UhfClosure> UhfClosure for GHashClosure<C> {
126            fn call<B: UhfBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B) {
127                self.0.call(&mut GHashBackend(backend));
128            }
129        }
130
131        self.0.update_with_backend(GHashClosure(f));
132    }
133
134    /// Get GHASH output
135    #[inline]
136    fn finalize(self) -> Tag {
137        let mut output = self.0.finalize();
138        output.reverse();
139        output
140    }
141}
142
143opaque_debug::implement!(GHash);