polyval/backend/
soft64.rs1use crate::{Block, Key};
9use core::{
10 convert::TryInto,
11 num::Wrapping,
12 ops::{Add, Mul},
13};
14use universal_hash::{consts::U16, NewUniversalHash, Output, UniversalHash};
15
16#[cfg(feature = "zeroize")]
17use zeroize::Zeroize;
18
19#[derive(Clone)]
21pub struct Polyval {
22 h: U64x2,
24
25 s: U64x2,
27}
28
29impl NewUniversalHash for Polyval {
30 type KeySize = U16;
31
32 fn new(h: &Key) -> Self {
34 Self {
35 h: h.into(),
36 s: U64x2::default(),
37 }
38 }
39}
40
41impl UniversalHash for Polyval {
42 type BlockSize = U16;
43
44 fn update(&mut self, x: &Block) {
46 let x = U64x2::from(x);
47 self.s = (self.s + x) * self.h;
48 }
49
50 fn reset(&mut self) {
52 self.s = U64x2::default();
53 }
54
55 fn finalize(self) -> Output<Self> {
57 let mut block = Block::default();
58
59 for (chunk, i) in block.chunks_mut(8).zip(&[self.s.0, self.s.1]) {
60 chunk.copy_from_slice(&i.to_le_bytes());
61 }
62
63 Output::new(block)
64 }
65}
66
67#[cfg(feature = "zeroize")]
68impl Drop for Polyval {
69 fn drop(&mut self) {
70 self.h.zeroize();
71 self.s.zeroize();
72 }
73}
74
75#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
77struct U64x2(u64, u64);
78
79impl From<&Block> for U64x2 {
80 fn from(bytes: &Block) -> U64x2 {
81 U64x2(
82 u64::from_le_bytes(bytes[..8].try_into().unwrap()),
83 u64::from_le_bytes(bytes[8..].try_into().unwrap()),
84 )
85 }
86}
87
88#[allow(clippy::suspicious_arithmetic_impl)]
89impl Add for U64x2 {
90 type Output = Self;
91
92 fn add(self, rhs: Self) -> Self::Output {
94 U64x2(self.0 ^ rhs.0, self.1 ^ rhs.1)
95 }
96}
97
98#[allow(clippy::suspicious_arithmetic_impl)]
99impl Mul for U64x2 {
100 type Output = Self;
101
102 fn mul(self, rhs: Self) -> Self {
120 let h0 = self.0;
121 let h1 = self.1;
122 let h0r = rev64(h0);
123 let h1r = rev64(h1);
124 let h2 = h0 ^ h1;
125 let h2r = h0r ^ h1r;
126
127 let y0 = rhs.0;
128 let y1 = rhs.1;
129 let y0r = rev64(y0);
130 let y1r = rev64(y1);
131 let y2 = y0 ^ y1;
132 let y2r = y0r ^ y1r;
133 let z0 = bmul64(y0, h0);
134 let z1 = bmul64(y1, h1);
135
136 let mut z2 = bmul64(y2, h2);
137 let mut z0h = bmul64(y0r, h0r);
138 let mut z1h = bmul64(y1r, h1r);
139 let mut z2h = bmul64(y2r, h2r);
140
141 z2 ^= z0 ^ z1;
142 z2h ^= z0h ^ z1h;
143 z0h = rev64(z0h) >> 1;
144 z1h = rev64(z1h) >> 1;
145 z2h = rev64(z2h) >> 1;
146
147 let v0 = z0;
148 let mut v1 = z0h ^ z2;
149 let mut v2 = z1 ^ z2h;
150 let mut v3 = z1h;
151
152 v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7);
153 v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57);
154 v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7);
155 v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57);
156
157 U64x2(v2, v3)
158 }
159}
160
161#[cfg(feature = "zeroize")]
162impl Zeroize for U64x2 {
163 fn zeroize(&mut self) {
164 self.0.zeroize();
165 self.1.zeroize();
166 }
167}
168
169fn bmul64(x: u64, y: u64) -> u64 {
175 let x0 = Wrapping(x & 0x1111_1111_1111_1111);
176 let x1 = Wrapping(x & 0x2222_2222_2222_2222);
177 let x2 = Wrapping(x & 0x4444_4444_4444_4444);
178 let x3 = Wrapping(x & 0x8888_8888_8888_8888);
179 let y0 = Wrapping(y & 0x1111_1111_1111_1111);
180 let y1 = Wrapping(y & 0x2222_2222_2222_2222);
181 let y2 = Wrapping(y & 0x4444_4444_4444_4444);
182 let y3 = Wrapping(y & 0x8888_8888_8888_8888);
183
184 let mut z0 = ((x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1)).0;
185 let mut z1 = ((x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2)).0;
186 let mut z2 = ((x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3)).0;
187 let mut z3 = ((x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0)).0;
188
189 z0 &= 0x1111_1111_1111_1111;
190 z1 &= 0x2222_2222_2222_2222;
191 z2 &= 0x4444_4444_4444_4444;
192 z3 &= 0x8888_8888_8888_8888;
193
194 z0 | z1 | z2 | z3
195}
196
197fn rev64(mut x: u64) -> u64 {
199 x = ((x & 0x5555_5555_5555_5555) << 1) | ((x >> 1) & 0x5555_5555_5555_5555);
200 x = ((x & 0x3333_3333_3333_3333) << 2) | ((x >> 2) & 0x3333_3333_3333_3333);
201 x = ((x & 0x0f0f_0f0f_0f0f_0f0f) << 4) | ((x >> 4) & 0x0f0f_0f0f_0f0f_0f0f);
202 x = ((x & 0x00ff_00ff_00ff_00ff) << 8) | ((x >> 8) & 0x00ff_00ff_00ff_00ff);
203 x = ((x & 0xffff_0000_ffff) << 16) | ((x >> 16) & 0xffff_0000_ffff);
204 (x << 32) | (x >> 32)
205}