cryptography/modes/
poly1305.rs1use crate::public_key::bigint::BigUint;
7
8#[inline]
9fn le_bytes_to_biguint(bytes: &[u8]) -> BigUint {
10 let mut be = bytes.to_vec();
11 be.reverse();
12 BigUint::from_be_bytes(&be)
13}
14
15#[inline]
16fn biguint_to_16_le(value: &BigUint) -> [u8; 16] {
17 let be = value.to_be_bytes();
18 let mut out = [0u8; 16];
19 if be.len() >= 16 {
20 out.copy_from_slice(&be[be.len() - 16..]);
21 } else {
22 out[16 - be.len()..].copy_from_slice(&be);
23 }
24 out.reverse();
25 out
26}
27
28pub fn poly1305_mac(msg: &[u8], key: &[u8; 32]) -> [u8; 16] {
32 let mut r = [0u8; 16];
33 r.copy_from_slice(&key[..16]);
34
35 r[3] &= 15;
38 r[7] &= 15;
39 r[11] &= 15;
40 r[15] &= 15;
41 r[4] &= 252;
42 r[8] &= 252;
43 r[12] &= 252;
44
45 let r_big = le_bytes_to_biguint(&r);
46 let s_big = le_bytes_to_biguint(&key[16..32]);
47
48 let mut p = BigUint::one();
49 p.shl_bits(130);
50 p = p.sub_ref(&BigUint::from_u64(5));
51
52 let mut acc = BigUint::zero();
53 for chunk in msg.chunks(16) {
54 let mut block = Vec::with_capacity(chunk.len() + 1);
55 block.extend_from_slice(chunk);
56 block.push(1);
57 let n = le_bytes_to_biguint(&block);
58 acc = acc.add_ref(&n).modulo(&p);
59 acc = BigUint::mod_mul(&acc, &r_big, &p);
60 }
61
62 let mut mod_2_128 = BigUint::one();
63 mod_2_128.shl_bits(128);
64 let tag = acc.add_ref(&s_big).modulo(&mod_2_128);
65 biguint_to_16_le(&tag)
66}
67
68pub struct Poly1305 {
71 key: [u8; 32],
72}
73
74impl Poly1305 {
75 #[must_use]
77 pub fn new(key: &[u8; 32]) -> Self {
78 Self { key: *key }
79 }
80
81 pub fn new_wiping(key: &mut [u8; 32]) -> Self {
83 let out = Self::new(key);
84 crate::ct::zeroize_slice(key.as_mut_slice());
85 out
86 }
87
88 #[must_use]
90 pub fn compute(&self, msg: &[u8]) -> [u8; 16] {
91 poly1305_mac(msg, &self.key)
92 }
93
94 #[must_use]
96 pub fn verify(&self, msg: &[u8], tag: &[u8; 16]) -> bool {
97 crate::ct::constant_time_eq_mask(&self.compute(msg), tag) == u8::MAX
98 }
99}
100
101impl Drop for Poly1305 {
102 fn drop(&mut self) {
103 crate::ct::zeroize_slice(self.key.as_mut_slice());
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::{poly1305_mac, Poly1305};
110
111 fn unhex(input: &str) -> Vec<u8> {
112 let mut out = Vec::with_capacity(input.len() / 2);
113 let bytes = input.as_bytes();
114 let mut i = 0usize;
115 while i + 1 < bytes.len() {
116 let hi = (bytes[i] as char).to_digit(16).expect("hex") as u8;
117 let lo = (bytes[i + 1] as char).to_digit(16).expect("hex") as u8;
118 out.push((hi << 4) | lo);
119 i += 2;
120 }
121 out
122 }
123
124 #[test]
125 fn rfc8439_poly1305_vector() {
126 let key = <[u8; 32]>::try_from(unhex(
127 "85d6be7857556d337f4452fe42d506a8\
128 0103808afb0db2fd4abff6af4149f51b",
129 ))
130 .expect("key");
131 let msg = b"Cryptographic Forum Research Group";
132 let expected =
133 <[u8; 16]>::try_from(unhex("a8061dc1305136c6c22b8baf0c0127a9")).expect("tag");
134 assert_eq!(poly1305_mac(msg, &key), expected);
135 }
136
137 #[test]
138 fn wrapper_verify_roundtrip() {
139 let key = [0x11u8; 32];
140 let mac = Poly1305::new(&key);
141 let msg = b"poly1305 message";
142 let tag = mac.compute(msg);
143 assert!(mac.verify(msg, &tag));
144
145 let mut tampered = tag;
146 tampered[0] ^= 0x80;
147 assert!(!mac.verify(msg, &tampered));
148 }
149}