dcrypt_algorithms/mac/poly1305/
mod.rs1#[cfg(not(feature = "std"))]
7use alloc::vec::Vec;
8
9use crate::error::{validate, Result};
10use crate::mac::{Mac, MacAlgorithm};
11use crate::types::Tag;
12use dcrypt_common::security::SecretBuffer;
13use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
14
15pub const POLY1305_KEY_SIZE: usize = 32;
17pub const POLY1305_TAG_SIZE: usize = 16;
19
20pub enum Poly1305Algorithm {}
22
23impl MacAlgorithm for Poly1305Algorithm {
24 const KEY_SIZE: usize = POLY1305_KEY_SIZE;
25 const TAG_SIZE: usize = POLY1305_TAG_SIZE;
26 const BLOCK_SIZE: usize = 16;
27
28 fn name() -> &'static str {
29 "Poly1305"
30 }
31}
32
33#[derive(Zeroize, ZeroizeOnDrop)]
35pub struct Poly1305 {
36 r: SecretBuffer<24>, s: SecretBuffer<16>, data: Zeroizing<Vec<u8>>, }
40
41impl Poly1305 {
42 pub fn new(key: &[u8]) -> Result<Self> {
51 validate::length("Poly1305 key", key.len(), POLY1305_KEY_SIZE)?;
52
53 let mut r_bytes = [0u8; 16];
55 r_bytes.copy_from_slice(&key[..16]);
56 r_bytes[3] &= 15;
57 r_bytes[7] &= 15;
58 r_bytes[11] &= 15;
59 r_bytes[15] &= 15;
60 r_bytes[4] &= 252;
61 r_bytes[8] &= 252;
62 r_bytes[12] &= 252;
63
64 let r0 = u64::from_le_bytes(r_bytes[0..8].try_into().unwrap());
66 let r1 = u64::from_le_bytes(r_bytes[8..16].try_into().unwrap());
67 let r2 = 0u64;
68
69 let mut r_buf = [0u8; 24];
71 r_buf[0..8].copy_from_slice(&r0.to_le_bytes());
72 r_buf[8..16].copy_from_slice(&r1.to_le_bytes());
73 r_buf[16..24].copy_from_slice(&r2.to_le_bytes());
74
75 let s0 = u64::from_le_bytes(key[16..24].try_into().unwrap());
77 let s1 = u64::from_le_bytes(key[24..32].try_into().unwrap());
78
79 let mut s_buf = [0u8; 16];
81 s_buf[0..8].copy_from_slice(&s0.to_le_bytes());
82 s_buf[8..16].copy_from_slice(&s1.to_le_bytes());
83
84 Ok(Self {
85 r: SecretBuffer::new(r_buf),
86 s: SecretBuffer::new(s_buf),
87 data: Zeroizing::new(Vec::new()),
88 })
89 }
90
91 fn get_r(&self) -> [u64; 3] {
97 let bytes = self.r.as_ref();
98 [
99 u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
100 u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
101 u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
102 ]
103 }
104
105 fn get_s(&self) -> [u64; 2] {
107 let bytes = self.s.as_ref();
108 [
109 u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
110 u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
111 ]
112 }
113
114 pub fn update(&mut self, chunk: &[u8]) -> Result<()> {
124 if !chunk.is_empty() {
125 self.data.extend_from_slice(chunk);
126 }
127 Ok(())
128 }
129
130 pub fn finalize(self) -> Tag<POLY1305_TAG_SIZE> {
139 let mut h = [0u64; 3];
141 let r = self.get_r(); for block in self.data.chunks(16) {
144 let mut buf = [0u8; 16];
145 buf[..block.len()].copy_from_slice(block);
146 let n2 = if block.len() == 16 {
147 1
148 } else {
149 buf[block.len()] = 1;
150 0
151 };
152 let n0 = u64::from_le_bytes(buf[0..8].try_into().unwrap());
153 let n1 = u64::from_le_bytes(buf[8..16].try_into().unwrap());
154
155 let (h0, c0) = h[0].overflowing_add(n0);
157 let (h1a, c1a) = h[1].overflowing_add(n1);
158 let (h1, c1b) = h1a.overflowing_add(c0 as u64);
159 let c1 = (c1a || c1b) as u64;
160 let (h2a, _) = h[2].overflowing_add(n2);
161 let (h2, _) = h2a.overflowing_add(c1);
162
163 h = mul_reduce([h0, h1, h2], r);
164 }
165
166 const P0: u64 = 0xffff_ffff_ffff_fffb;
168 const P1: u64 = 0xffff_ffff_ffff_ffff;
169 const P2: u64 = 3;
170
171 let (g0, b0) = h[0].overflowing_sub(P0);
172 let (g1a, b1a) = h[1].overflowing_sub(P1);
173 let (g1, b1b) = g1a.overflowing_sub(b0 as u64);
174 let borrow1 = (b1a || b1b) as u64;
175 let (g2, borrow2_bool) = h[2].overflowing_sub(P2 + borrow1);
176
177 let mask = (borrow2_bool as u64).wrapping_sub(1);
179 h[0] = (h[0] & !mask) | (g0 & mask);
180 h[1] = (h[1] & !mask) | (g1 & mask);
181 h[2] = (h[2] & !mask) | (g2 & mask);
182
183 let s = self.get_s(); let (t0, carry0) = h[0].overflowing_add(s[0]);
186 let (t1a, _) = h[1].overflowing_add(s[1]);
187 let (t1, _) = t1a.overflowing_add(carry0 as u64);
188
189 let mut out = [0u8; POLY1305_TAG_SIZE];
190 out[..8].copy_from_slice(&t0.to_le_bytes());
191 out[8..16].copy_from_slice(&t1.to_le_bytes());
192 Tag::new(out)
193 }
194}
195
196impl Mac for Poly1305 {
200 type Key = [u8; POLY1305_KEY_SIZE];
201 type Tag = Tag<POLY1305_TAG_SIZE>;
202
203 fn new(key: &[u8]) -> Result<Self> {
204 Self::new(key)
205 }
206 fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
207 self.update(data)?;
208 Ok(self)
209 }
210 fn finalize(&mut self) -> Result<Self::Tag> {
211 Ok(self.clone().finalize())
212 }
213 fn reset(&mut self) -> Result<()> {
214 self.data.clear();
215 Ok(())
216 }
217}
218
219impl Clone for Poly1305 {
220 fn clone(&self) -> Self {
221 Self {
222 r: self.r.clone(),
223 s: self.s.clone(),
224 data: self.data.clone(),
225 }
226 }
227}
228
229fn mul_reduce(h: [u64; 3], r: [u64; 3]) -> [u64; 3] {
233 let (h0, h1, h2) = (h[0] as u128, h[1] as u128, h[2] as u128);
234 let (r0, r1, r2) = (r[0] as u128, r[1] as u128, r[2] as u128);
235
236 let mut t0 = h0 * r0;
238 let mut t1 = h0 * r1 + h1 * r0;
239 let mut t2 = h0 * r2 + h1 * r1 + h2 * r0;
240 let mut t3 = h1 * r2 + h2 * r1;
241 let mut t4 = h2 * r2;
242
243 let c1 = (t0 >> 64) as u64;
245 t0 &= u128::from(u64::MAX);
246 t1 += c1 as u128;
247 let c2 = (t1 >> 64) as u64;
248 t1 &= u128::from(u64::MAX);
249 t2 += c2 as u128;
250 let c3 = (t2 >> 64) as u64;
251 t2 &= u128::from(u64::MAX);
252 t3 += c3 as u128;
253 let c4 = (t3 >> 64) as u64;
254 t3 &= u128::from(u64::MAX);
255 t4 += c4 as u128;
256 let _c5 = (t4 >> 64) as u64;
257 t4 &= u128::from(u64::MAX);
258
259 let high = (t2 >> 2) + (t3 << 62) + (t4 << 126);
261 let low2 = t2 & 0x3;
262
263 let mut m0 = t0 + high * 5;
265 let mut m1 = t1;
266 let mut m2 = low2;
267
268 let f1 = (m0 >> 64) as u64;
270 m0 &= u128::from(u64::MAX);
271 m1 += f1 as u128;
272 let f2 = (m1 >> 64) as u64;
273 m1 &= u128::from(u64::MAX);
274 m2 += f2 as u128;
275
276 m2 &= 0x3fff_ffff_ffff_ffff;
277 [m0 as u64, m1 as u64, m2 as u64]
278}
279
280#[cfg(test)]
281mod tests;