Skip to main content

ghash/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
5    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
6)]
7#![warn(missing_docs)]
8
9pub use polyval::universal_hash;
10
11use polyval::{Polyval, hazmat::FieldElement};
12use universal_hash::{
13    KeyInit, UhfBackend, UhfClosure, UniversalHash,
14    common::{BlockSizeUser, KeySizeUser, ParBlocksSizeUser},
15    consts::U16,
16};
17
18#[cfg(feature = "zeroize")]
19use zeroize::Zeroize;
20
21/// GHASH keys (16-bytes)
22pub type Key = universal_hash::Key<GHash>;
23
24/// GHASH blocks (16-bytes)
25pub type Block = universal_hash::Block<GHash>;
26
27/// GHASH tags (16-bytes)
28pub type Tag = universal_hash::Block<GHash>;
29
30/// **GHASH**: universal hash over GF(2^128) used by AES-GCM.
31///
32/// GHASH is a universal hash function used for message authentication in the AES-GCM authenticated
33/// encryption cipher.
34#[derive(Clone)]
35pub struct GHash(Polyval);
36
37impl KeySizeUser for GHash {
38    type KeySize = U16;
39}
40
41impl GHash {
42    /// Initialize GHASH with the given `H` field element as the key.
43    #[inline]
44    pub fn new(h: &Key) -> Self {
45        #[allow(unused_mut)]
46        let mut h_polyval = FieldElement::from(*h).reverse().mulx();
47        #[allow(clippy::let_and_return)]
48        let result = Self(Polyval::new(&h_polyval.into()));
49        #[cfg(feature = "zeroize")]
50        h_polyval.zeroize();
51        result
52    }
53}
54
55impl KeyInit for GHash {
56    /// Initialize GHASH with the given `H` field element
57    #[inline]
58    fn new(h: &Key) -> Self {
59        Self::new(h)
60    }
61}
62
63struct GHashBackend<'b, B: UhfBackend>(&'b mut B);
64
65impl<B: UhfBackend> BlockSizeUser for GHashBackend<'_, B> {
66    type BlockSize = B::BlockSize;
67}
68
69impl<B: UhfBackend> ParBlocksSizeUser for GHashBackend<'_, B> {
70    type ParBlocksSize = B::ParBlocksSize;
71}
72
73impl<B: UhfBackend> UhfBackend for GHashBackend<'_, B> {
74    fn proc_block(&mut self, x: &universal_hash::Block<B>) {
75        let mut x = x.clone();
76        x.reverse();
77        self.0.proc_block(&x);
78    }
79
80    fn proc_par_blocks(&mut self, par_blocks: &universal_hash::ParBlocks<B>) {
81        let mut par_blocks = par_blocks.clone();
82        for block in &mut par_blocks {
83            block.reverse();
84        }
85        self.0.proc_par_blocks(&par_blocks);
86    }
87}
88
89impl BlockSizeUser for GHash {
90    type BlockSize = U16;
91}
92
93impl UniversalHash for GHash {
94    fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>) {
95        struct GHashClosure<C: UhfClosure>(C);
96
97        impl<C: UhfClosure> BlockSizeUser for GHashClosure<C> {
98            type BlockSize = C::BlockSize;
99        }
100
101        impl<C: UhfClosure> UhfClosure for GHashClosure<C> {
102            fn call<B: UhfBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B) {
103                self.0.call(&mut GHashBackend(backend));
104            }
105        }
106
107        self.0.update_with_backend(GHashClosure(f));
108    }
109
110    /// Get GHASH output
111    #[inline]
112    fn finalize(self) -> Tag {
113        let mut output = self.0.finalize();
114        output.reverse();
115        output
116    }
117}
118
119impl core::fmt::Debug for GHash {
120    fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
121        f.debug_tuple("GHash").finish_non_exhaustive()
122    }
123}