Skip to main content

polyval/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
6    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
7)]
8
9#[cfg(feature = "hazmat")]
10pub mod hazmat;
11
12mod backend;
13mod field_element;
14
15pub use universal_hash;
16
17use crate::backend::State;
18use core::fmt::{self, Debug};
19use universal_hash::{
20    KeyInit, Reset, UhfBackend, UhfClosure, UniversalHash,
21    common::{BlockSizeUser, KeySizeUser, ParBlocksSizeUser},
22    consts::{U4, U16},
23};
24
25/// Size of a POLYVAL block in bytes
26pub const BLOCK_SIZE: usize = 16;
27
28/// Size of a POLYVAL key in bytes
29pub const KEY_SIZE: usize = 16;
30
31/// POLYVAL keys (16-bytes)
32pub type Key = universal_hash::Key<Polyval>;
33
34/// POLYVAL blocks (16-bytes)
35pub type Block = universal_hash::Block<Polyval>;
36
37/// POLYVAL parallel blocks (4 x 16-bytes)
38pub type ParBlocks = universal_hash::ParBlocks<Polyval>;
39
40/// POLYVAL tags (16-bytes)
41pub type Tag = universal_hash::Block<Polyval>;
42
43/// **POLYVAL**: GHASH-like universal hash over GF(2^128), but optimized for little-endian
44/// architectures.
45#[derive(Clone)]
46pub struct Polyval {
47    /// State of the internal hash being computed.
48    state: State,
49}
50
51impl Polyval {
52    /// Initialize POLYVAL with the given `H` field element (i.e. hash key).
53    #[must_use]
54    pub fn new(h: &Key) -> Self {
55        Self {
56            state: State::new(h),
57        }
58    }
59}
60
61impl KeyInit for Polyval {
62    fn new(h: &Key) -> Self {
63        Self::new(h)
64    }
65}
66
67impl KeySizeUser for Polyval {
68    type KeySize = U16;
69}
70
71impl BlockSizeUser for Polyval {
72    type BlockSize = U16;
73}
74
75impl ParBlocksSizeUser for Polyval {
76    type ParBlocksSize = U4;
77}
78
79impl UniversalHash for Polyval {
80    fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>) {
81        f.call(self);
82    }
83
84    fn finalize(self) -> Tag {
85        self.state.finalize()
86    }
87}
88
89impl UhfBackend for Polyval {
90    fn proc_block(&mut self, block: &Block) {
91        self.state.proc_block(block);
92    }
93
94    fn proc_par_blocks(&mut self, blocks: &ParBlocks) {
95        self.state.proc_par_blocks(blocks);
96    }
97}
98
99impl Reset for Polyval {
100    fn reset(&mut self) {
101        self.state.reset();
102    }
103}
104
105impl Debug for Polyval {
106    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
107        f.debug_struct("Polyval").finish_non_exhaustive()
108    }
109}
110
111impl Drop for Polyval {
112    fn drop(&mut self) {
113        // SAFETY: `Polyval` satisfies the safety conditions of `zeroize_flat_type`
114        #[cfg(feature = "zeroize")]
115        unsafe {
116            zeroize::zeroize_flat_type(self);
117        }
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use crate::{BLOCK_SIZE, Polyval, universal_hash::UniversalHash};
124    use hex_literal::hex;
125
126    //
127    // Test vectors for POLYVAL from RFC 8452 Appendix A
128    // <https://tools.ietf.org/html/rfc8452#appendix-A>
129    //
130
131    const H: [u8; BLOCK_SIZE] = hex!("25629347589242761d31f826ba4b757b");
132    const X_1: [u8; BLOCK_SIZE] = hex!("4f4f95668c83dfb6401762bb2d01a262");
133    const X_2: [u8; BLOCK_SIZE] = hex!("d1a24ddd2721d006bbe45f20d3c9f362");
134
135    /// POLYVAL(H, X_1, X_2)
136    const POLYVAL_RESULT: [u8; BLOCK_SIZE] = hex!("f7a3b47b846119fae5b7866cf5e5b77e");
137
138    #[test]
139    fn polyval_test_vector() {
140        let mut poly = Polyval::new(&H.into());
141        poly.update(&[X_1.into(), X_2.into()]);
142
143        let result = poly.finalize();
144        assert_eq!(&POLYVAL_RESULT[..], result.as_slice());
145    }
146}