dcrypt_algorithms/mac/poly1305/
mod.rs1#[cfg(not(feature = "std"))]
9use alloc::vec::Vec;
10
11use crate::error::{validate, Result};
12use crate::mac::MacAlgorithm;
13use crate::types::Tag;
14use dcrypt_common::security::SecretBuffer;
15use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
16
17pub const POLY1305_KEY_SIZE: usize = 32;
19pub const POLY1305_TAG_SIZE: usize = 16;
21
22pub enum Poly1305Algorithm {}
24
25impl MacAlgorithm for Poly1305Algorithm {
26 const KEY_SIZE: usize = POLY1305_KEY_SIZE;
27 const TAG_SIZE: usize = POLY1305_TAG_SIZE;
28 const BLOCK_SIZE: usize = 16;
29
30 fn name() -> &'static str {
31 "Poly1305"
32 }
33}
34
35#[derive(Zeroize, ZeroizeOnDrop)]
37pub struct Poly1305 {
38 r: SecretBuffer<24>, s: SecretBuffer<16>, data: Zeroizing<Vec<u8>>, }
42
43impl Poly1305 {
44 pub fn new(key: &[u8]) -> Result<Self> {
53 validate::length("Poly1305 key", key.len(), POLY1305_KEY_SIZE)?;
54
55 let mut r_bytes = Zeroizing::new([0u8; 16]);
57 r_bytes.copy_from_slice(&key[..16]);
58 r_bytes[3] &= 15;
59 r_bytes[7] &= 15;
60 r_bytes[11] &= 15;
61 r_bytes[15] &= 15;
62 r_bytes[4] &= 252;
63 r_bytes[8] &= 252;
64 r_bytes[12] &= 252;
65
66 let mut r = SecretBuffer::<24>::zeroed();
68 r.as_mut()[..16].copy_from_slice(r_bytes.as_ref());
69
70 let mut s = SecretBuffer::<16>::zeroed();
72 s.as_mut().copy_from_slice(&key[16..32]);
73
74 Ok(Self {
75 r,
76 s,
77 data: Zeroizing::new(Vec::new()),
78 })
79 }
80
81 fn get_r(&self) -> [u64; 3] {
87 let bytes = self.r.as_ref();
88 [
89 u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
90 u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
91 u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
92 ]
93 }
94
95 fn get_s(&self) -> [u64; 2] {
97 let bytes = self.s.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 ]
102 }
103
104 pub fn update(&mut self, chunk: &[u8]) -> Result<()> {
114 if !chunk.is_empty() {
115 self.data.extend_from_slice(chunk);
116 }
117 Ok(())
118 }
119
120 pub fn finalize(self) -> Tag<POLY1305_TAG_SIZE> {
129 let mut h = [0u64; 3];
131 let r = Zeroizing::new(self.get_r());
132
133 for block in self.data.chunks(16) {
134 let mut buf = Zeroizing::new([0u8; 16]);
135 buf[..block.len()].copy_from_slice(block);
136 let n2 = if block.len() == 16 {
137 1
138 } else {
139 buf[block.len()] = 1;
140 0
141 };
142 let n0 = u64::from_le_bytes(buf[0..8].try_into().unwrap());
143 let n1 = u64::from_le_bytes(buf[8..16].try_into().unwrap());
144
145 let (h0, c0) = h[0].overflowing_add(n0);
147 let (h1a, c1a) = h[1].overflowing_add(n1);
148 let (h1, c1b) = h1a.overflowing_add(c0 as u64);
149 let c1 = (c1a || c1b) as u64;
150 let (h2a, _) = h[2].overflowing_add(n2);
151 let (h2, _) = h2a.overflowing_add(c1);
152
153 h = mul_reduce([h0, h1, h2], &r);
154 }
155
156 const P0: u64 = 0xffff_ffff_ffff_fffb;
158 const P1: u64 = 0xffff_ffff_ffff_ffff;
159 const P2: u64 = 3;
160
161 let (g0, b0) = h[0].overflowing_sub(P0);
162 let (g1a, b1a) = h[1].overflowing_sub(P1);
163 let (g1, b1b) = g1a.overflowing_sub(b0 as u64);
164 let borrow1 = (b1a || b1b) as u64;
165 let (g2, borrow2_bool) = h[2].overflowing_sub(P2 + borrow1);
166
167 let mask = (borrow2_bool as u64).wrapping_sub(1);
169 h[0] = (h[0] & !mask) | (g0 & mask);
170 h[1] = (h[1] & !mask) | (g1 & mask);
171 h[2] = (h[2] & !mask) | (g2 & mask);
172
173 let s = Zeroizing::new(self.get_s());
175 let (t0, carry0) = h[0].overflowing_add(s[0]);
176 let (t1a, _) = h[1].overflowing_add(s[1]);
177 let (t1, _) = t1a.overflowing_add(carry0 as u64);
178
179 let mut out = [0u8; POLY1305_TAG_SIZE];
180 out[..8].copy_from_slice(&t0.to_le_bytes());
181 out[8..16].copy_from_slice(&t1.to_le_bytes());
182 Tag::new(out)
183 }
184}
185
186fn mul_reduce(h: [u64; 3], r: &[u64; 3]) -> [u64; 3] {
190 let (h0, h1, h2) = (h[0] as u128, h[1] as u128, h[2] as u128);
191 let (r0, r1, r2) = (r[0] as u128, r[1] as u128, r[2] as u128);
192
193 let mut t0 = h0 * r0;
195 let mut t1 = h0 * r1 + h1 * r0;
196 let mut t2 = h0 * r2 + h1 * r1 + h2 * r0;
197 let mut t3 = h1 * r2 + h2 * r1;
198 let mut t4 = h2 * r2;
199
200 let c1 = (t0 >> 64) as u64;
202 t0 &= u128::from(u64::MAX);
203 t1 += c1 as u128;
204 let c2 = (t1 >> 64) as u64;
205 t1 &= u128::from(u64::MAX);
206 t2 += c2 as u128;
207 let c3 = (t2 >> 64) as u64;
208 t2 &= u128::from(u64::MAX);
209 t3 += c3 as u128;
210 let c4 = (t3 >> 64) as u64;
211 t3 &= u128::from(u64::MAX);
212 t4 += c4 as u128;
213 let _c5 = (t4 >> 64) as u64;
214 t4 &= u128::from(u64::MAX);
215
216 let high = (t2 >> 2) + (t3 << 62) + (t4 << 126);
218 let low2 = t2 & 0x3;
219
220 let mut m0 = t0 + high * 5;
222 let mut m1 = t1;
223 let mut m2 = low2;
224
225 let f1 = (m0 >> 64) as u64;
227 m0 &= u128::from(u64::MAX);
228 m1 += f1 as u128;
229 let f2 = (m1 >> 64) as u64;
230 m1 &= u128::from(u64::MAX);
231 m2 += f2 as u128;
232
233 m2 &= 0x3fff_ffff_ffff_ffff;
234 [m0 as u64, m1 as u64, m2 as u64]
235}
236
237#[cfg(test)]
238mod tests;