1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! **GHASH**: universal hash over GF(2^128) used by AES-GCM for message
//! authentication (i.e. GMAC).
//!
//! ## Implementation Notes
//!
//! The implementation of GHASH found in this crate internally uses the
//! [`polyval`] crate, which provides a similar universal hash function used by
//! AES-GCM-SIV (RFC 8452).
//!
//! By implementing GHASH in terms of POLYVAL, the two universal hash functions
//! can share a common core, meaning any optimization work (e.g. CPU-specific
//! SIMD implementations) which happens upstream in the `polyval` crate
//! benefits GHASH as well.
//!
//! From RFC 8452 Appendix A:
//! <https://tools.ietf.org/html/rfc8452#appendix-A>
//!
//! > GHASH and POLYVAL both operate in GF(2^128), although with different
//! > irreducible polynomials: POLYVAL works modulo x^128 + x^127 + x^126 +
//! > x^121 + 1 and GHASH works modulo x^128 + x^7 + x^2 + x + 1.  Note
//! > that these irreducible polynomials are the "reverse" of each other.
//!
//! [`polyval`]: https://github.com/RustCrypto/universal-hashes/tree/master/polyval

#![no_std]
#![doc(
    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
)]
#![warn(missing_docs, rust_2018_idioms)]

pub use polyval::universal_hash;

use polyval::Polyval;
use universal_hash::{
    consts::U16,
    crypto_common::{BlockSizeUser, KeySizeUser, ParBlocksSizeUser},
    KeyInit, UhfBackend, UhfClosure, UniversalHash,
};

#[cfg(feature = "zeroize")]
use zeroize::Zeroize;

/// GHASH keys (16-bytes)
pub type Key = universal_hash::Key<GHash>;

/// GHASH blocks (16-bytes)
pub type Block = universal_hash::Block<GHash>;

/// GHASH tags (16-bytes)
pub type Tag = universal_hash::Block<GHash>;

/// **GHASH**: universal hash over GF(2^128) used by AES-GCM.
///
/// GHASH is a universal hash function used for message authentication in
/// the AES-GCM authenticated encryption cipher.
#[derive(Clone)]
pub struct GHash(Polyval);

impl KeySizeUser for GHash {
    type KeySize = U16;
}

impl KeyInit for GHash {
    /// Initialize GHASH with the given `H` field element
    #[inline]
    fn new(h: &Key) -> Self {
        let mut h = *h;
        h.reverse();

        #[allow(unused_mut)]
        let mut h_polyval = polyval::mulx(&h);

        #[cfg(feature = "zeroize")]
        h.zeroize();

        #[allow(clippy::let_and_return)]
        let result = GHash(Polyval::new(&h_polyval));

        #[cfg(feature = "zeroize")]
        h_polyval.zeroize();

        result
    }
}

struct GHashBackend<'b, B: UhfBackend>(&'b mut B);

impl<'b, B: UhfBackend> BlockSizeUser for GHashBackend<'b, B> {
    type BlockSize = B::BlockSize;
}

impl<'b, B: UhfBackend> ParBlocksSizeUser for GHashBackend<'b, B> {
    type ParBlocksSize = B::ParBlocksSize;
}

impl<'b, B: UhfBackend> UhfBackend for GHashBackend<'b, B> {
    fn proc_block(&mut self, x: &universal_hash::Block<B>) {
        let mut x = x.clone();
        x.reverse();
        self.0.proc_block(&x);
    }
}

impl BlockSizeUser for GHash {
    type BlockSize = U16;
}

impl UniversalHash for GHash {
    fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>) {
        struct GHashClosure<C: UhfClosure>(C);

        impl<C: UhfClosure> BlockSizeUser for GHashClosure<C> {
            type BlockSize = C::BlockSize;
        }

        impl<C: UhfClosure> UhfClosure for GHashClosure<C> {
            fn call<B: UhfBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B) {
                self.0.call(&mut GHashBackend(backend));
            }
        }

        self.0.update_with_backend(GHashClosure(f));
    }

    /// Get GHASH output
    #[inline]
    fn finalize(self) -> Tag {
        let mut output = self.0.finalize();
        output.reverse();
        output
    }
}

opaque_debug::implement!(GHash);