polyval/backend/
soft64.rs
1use crate::{Block, Key, Tag};
9use core::{
10 num::Wrapping,
11 ops::{Add, Mul},
12};
13use universal_hash::{
14 consts::{U1, U16},
15 crypto_common::{BlockSizeUser, KeySizeUser, ParBlocksSizeUser},
16 KeyInit, Reset, UhfBackend, UniversalHash,
17};
18
19#[cfg(feature = "zeroize")]
20use zeroize::Zeroize;
21
22#[derive(Clone)]
24pub struct Polyval {
25 h: U64x2,
27
28 s: U64x2,
30}
31
32impl KeySizeUser for Polyval {
33 type KeySize = U16;
34}
35
36impl KeyInit for Polyval {
37 fn new(h: &Key) -> Self {
39 Self {
40 h: h.into(),
41 s: U64x2::default(),
42 }
43 }
44}
45
46impl BlockSizeUser for Polyval {
47 type BlockSize = U16;
48}
49
50impl ParBlocksSizeUser for Polyval {
51 type ParBlocksSize = U1;
52}
53
54impl UhfBackend for Polyval {
55 fn proc_block(&mut self, x: &Block) {
56 let x = U64x2::from(x);
57 self.s = (self.s + x) * self.h;
58 }
59}
60
61impl UniversalHash for Polyval {
62 fn update_with_backend(
63 &mut self,
64 f: impl universal_hash::UhfClosure<BlockSize = Self::BlockSize>,
65 ) {
66 f.call(self);
67 }
68
69 fn finalize(self) -> Tag {
71 let mut block = Block::default();
72
73 for (chunk, i) in block.chunks_mut(8).zip(&[self.s.0, self.s.1]) {
74 chunk.copy_from_slice(&i.to_le_bytes());
75 }
76
77 block
78 }
79}
80
81impl Reset for Polyval {
82 fn reset(&mut self) {
83 self.s = U64x2::default();
84 }
85}
86
87#[cfg(feature = "zeroize")]
88impl Drop for Polyval {
89 fn drop(&mut self) {
90 self.h.zeroize();
91 self.s.zeroize();
92 }
93}
94
95#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
97struct U64x2(u64, u64);
98
99impl From<&Block> for U64x2 {
100 fn from(bytes: &Block) -> U64x2 {
101 U64x2(
102 u64::from_le_bytes(bytes[..8].try_into().unwrap()),
103 u64::from_le_bytes(bytes[8..].try_into().unwrap()),
104 )
105 }
106}
107
108#[allow(clippy::suspicious_arithmetic_impl)]
109impl Add for U64x2 {
110 type Output = Self;
111
112 fn add(self, rhs: Self) -> Self::Output {
114 U64x2(self.0 ^ rhs.0, self.1 ^ rhs.1)
115 }
116}
117
118#[allow(clippy::suspicious_arithmetic_impl)]
119impl Mul for U64x2 {
120 type Output = Self;
121
122 fn mul(self, rhs: Self) -> Self {
140 let h0 = self.0;
141 let h1 = self.1;
142 let h0r = rev64(h0);
143 let h1r = rev64(h1);
144 let h2 = h0 ^ h1;
145 let h2r = h0r ^ h1r;
146
147 let y0 = rhs.0;
148 let y1 = rhs.1;
149 let y0r = rev64(y0);
150 let y1r = rev64(y1);
151 let y2 = y0 ^ y1;
152 let y2r = y0r ^ y1r;
153 let z0 = bmul64(y0, h0);
154 let z1 = bmul64(y1, h1);
155
156 let mut z2 = bmul64(y2, h2);
157 let mut z0h = bmul64(y0r, h0r);
158 let mut z1h = bmul64(y1r, h1r);
159 let mut z2h = bmul64(y2r, h2r);
160
161 z2 ^= z0 ^ z1;
162 z2h ^= z0h ^ z1h;
163 z0h = rev64(z0h) >> 1;
164 z1h = rev64(z1h) >> 1;
165 z2h = rev64(z2h) >> 1;
166
167 let v0 = z0;
168 let mut v1 = z0h ^ z2;
169 let mut v2 = z1 ^ z2h;
170 let mut v3 = z1h;
171
172 v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7);
173 v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57);
174 v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7);
175 v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57);
176
177 U64x2(v2, v3)
178 }
179}
180
181#[cfg(feature = "zeroize")]
182impl Zeroize for U64x2 {
183 fn zeroize(&mut self) {
184 self.0.zeroize();
185 self.1.zeroize();
186 }
187}
188
189fn bmul64(x: u64, y: u64) -> u64 {
195 let x0 = Wrapping(x & 0x1111_1111_1111_1111);
196 let x1 = Wrapping(x & 0x2222_2222_2222_2222);
197 let x2 = Wrapping(x & 0x4444_4444_4444_4444);
198 let x3 = Wrapping(x & 0x8888_8888_8888_8888);
199 let y0 = Wrapping(y & 0x1111_1111_1111_1111);
200 let y1 = Wrapping(y & 0x2222_2222_2222_2222);
201 let y2 = Wrapping(y & 0x4444_4444_4444_4444);
202 let y3 = Wrapping(y & 0x8888_8888_8888_8888);
203
204 let mut z0 = ((x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1)).0;
205 let mut z1 = ((x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2)).0;
206 let mut z2 = ((x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3)).0;
207 let mut z3 = ((x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0)).0;
208
209 z0 &= 0x1111_1111_1111_1111;
210 z1 &= 0x2222_2222_2222_2222;
211 z2 &= 0x4444_4444_4444_4444;
212 z3 &= 0x8888_8888_8888_8888;
213
214 z0 | z1 | z2 | z3
215}
216
217fn rev64(mut x: u64) -> u64 {
219 x = ((x & 0x5555_5555_5555_5555) << 1) | ((x >> 1) & 0x5555_5555_5555_5555);
220 x = ((x & 0x3333_3333_3333_3333) << 2) | ((x >> 2) & 0x3333_3333_3333_3333);
221 x = ((x & 0x0f0f_0f0f_0f0f_0f0f) << 4) | ((x >> 4) & 0x0f0f_0f0f_0f0f_0f0f);
222 x = ((x & 0x00ff_00ff_00ff_00ff) << 8) | ((x >> 8) & 0x00ff_00ff_00ff_00ff);
223 x = ((x & 0xffff_0000_ffff) << 16) | ((x >> 16) & 0xffff_0000_ffff);
224 (x << 32) | (x >> 32)
225}