crypto/
poly1305.rs

1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7// This is a port of Andrew Moons poly1305-donna
8// https://github.com/floodyberry/poly1305-donna
9
10use std::cmp::min;
11
12use cryptoutil::{read_u32_le, write_u32_le};
13use mac::{Mac, MacResult};
14
15#[derive(Clone, Copy)]
16pub struct Poly1305 {
17    r         : [u32; 5],
18    h         : [u32; 5],
19    pad       : [u32; 4],
20    leftover  : usize,
21    buffer    : [u8; 16],
22    finalized : bool,
23}
24
25impl Poly1305 {
26    pub fn new(key: &[u8]) -> Poly1305 {
27        assert!(key.len() == 32);
28        let mut poly = Poly1305{ r: [0u32; 5], h: [0u32; 5], pad: [0u32; 4], leftover: 0, buffer: [0u8; 16], finalized: false };
29
30        // r &= 0xffffffc0ffffffc0ffffffc0fffffff
31        poly.r[0] = (read_u32_le(&key[0..4])     ) & 0x3ffffff;
32        poly.r[1] = (read_u32_le(&key[3..7]) >> 2) & 0x3ffff03;
33        poly.r[2] = (read_u32_le(&key[6..10]) >> 4) & 0x3ffc0ff;
34        poly.r[3] = (read_u32_le(&key[9..13]) >> 6) & 0x3f03fff;
35        poly.r[4] = (read_u32_le(&key[12..16]) >> 8) & 0x00fffff;
36
37        poly.pad[0] = read_u32_le(&key[16..20]);
38        poly.pad[1] = read_u32_le(&key[20..24]);
39        poly.pad[2] = read_u32_le(&key[24..28]);
40        poly.pad[3] = read_u32_le(&key[28..32]);
41
42        poly
43    }
44
45    fn block(&mut self, m: &[u8]) {
46        let hibit : u32 = if self.finalized { 0 } else { 1 << 24 };
47
48        let r0 = self.r[0];
49        let r1 = self.r[1];
50        let r2 = self.r[2];
51        let r3 = self.r[3];
52        let r4 = self.r[4];
53
54        let s1 = r1 * 5;
55        let s2 = r2 * 5;
56        let s3 = r3 * 5;
57        let s4 = r4 * 5;
58
59        let mut h0 = self.h[0];
60        let mut h1 = self.h[1];
61        let mut h2 = self.h[2];
62        let mut h3 = self.h[3];
63        let mut h4 = self.h[4];
64
65        // h += m
66        h0 += (read_u32_le(&m[0..4])     ) & 0x3ffffff;
67        h1 += (read_u32_le(&m[3..7]) >> 2) & 0x3ffffff;
68        h2 += (read_u32_le(&m[6..10]) >> 4) & 0x3ffffff;
69        h3 += (read_u32_le(&m[9..13]) >> 6) & 0x3ffffff;
70        h4 += (read_u32_le(&m[12..16]) >> 8) | hibit;
71
72        // h *= r
73        let     d0 = (h0 as u64 * r0 as u64) + (h1 as u64 * s4 as u64) + (h2 as u64 * s3 as u64) + (h3 as u64 * s2 as u64) + (h4 as u64 * s1 as u64);
74        let mut d1 = (h0 as u64 * r1 as u64) + (h1 as u64 * r0 as u64) + (h2 as u64 * s4 as u64) + (h3 as u64 * s3 as u64) + (h4 as u64 * s2 as u64);
75        let mut d2 = (h0 as u64 * r2 as u64) + (h1 as u64 * r1 as u64) + (h2 as u64 * r0 as u64) + (h3 as u64 * s4 as u64) + (h4 as u64 * s3 as u64);
76        let mut d3 = (h0 as u64 * r3 as u64) + (h1 as u64 * r2 as u64) + (h2 as u64 * r1 as u64) + (h3 as u64 * r0 as u64) + (h4 as u64 * s4 as u64);
77        let mut d4 = (h0 as u64 * r4 as u64) + (h1 as u64 * r3 as u64) + (h2 as u64 * r2 as u64) + (h3 as u64 * r1 as u64) + (h4 as u64 * r0 as u64);
78
79        // (partial) h %= p
80        let mut c : u32;
81                        c = (d0 >> 26) as u32; h0 = d0 as u32 & 0x3ffffff;
82        d1 += c as u64; c = (d1 >> 26) as u32; h1 = d1 as u32 & 0x3ffffff;
83        d2 += c as u64; c = (d2 >> 26) as u32; h2 = d2 as u32 & 0x3ffffff;
84        d3 += c as u64; c = (d3 >> 26) as u32; h3 = d3 as u32 & 0x3ffffff;
85        d4 += c as u64; c = (d4 >> 26) as u32; h4 = d4 as u32 & 0x3ffffff;
86        h0 += c * 5;    c = h0 >> 26; h0 = h0 & 0x3ffffff;
87        h1 += c;
88
89        self.h[0] = h0;
90        self.h[1] = h1;
91        self.h[2] = h2;
92        self.h[3] = h3;
93        self.h[4] = h4;
94    }
95
96    fn finish(&mut self) {
97        if self.leftover > 0 {
98            self.buffer[self.leftover] = 1;
99            for i in self.leftover+1..16 {
100                self.buffer[i] = 0;
101            }
102            self.finalized = true;
103            let tmp = self.buffer;
104            self.block(&tmp);
105        }
106
107        // fully carry h
108        let mut h0 = self.h[0];
109        let mut h1 = self.h[1];
110        let mut h2 = self.h[2];
111        let mut h3 = self.h[3];
112        let mut h4 = self.h[4];
113
114        let mut c : u32;
115                     c = h1 >> 26; h1 = h1 & 0x3ffffff;
116        h2 +=     c; c = h2 >> 26; h2 = h2 & 0x3ffffff;
117        h3 +=     c; c = h3 >> 26; h3 = h3 & 0x3ffffff;
118        h4 +=     c; c = h4 >> 26; h4 = h4 & 0x3ffffff;
119        h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
120        h1 +=     c;
121
122        // compute h + -p
123        let mut g0 = h0.wrapping_add(5); c = g0 >> 26; g0 &= 0x3ffffff;
124        let mut g1 = h1.wrapping_add(c); c = g1 >> 26; g1 &= 0x3ffffff;
125        let mut g2 = h2.wrapping_add(c); c = g2 >> 26; g2 &= 0x3ffffff;
126        let mut g3 = h3.wrapping_add(c); c = g3 >> 26; g3 &= 0x3ffffff;
127        let mut g4 = h4.wrapping_add(c).wrapping_sub(1 << 26);
128
129        // select h if h < p, or h + -p if h >= p
130        let mut mask = (g4 >> (32 - 1)).wrapping_sub(1);
131        g0 &= mask;
132        g1 &= mask;
133        g2 &= mask;
134        g3 &= mask;
135        g4 &= mask;
136        mask = !mask;
137        h0 = (h0 & mask) | g0;
138        h1 = (h1 & mask) | g1;
139        h2 = (h2 & mask) | g2;
140        h3 = (h3 & mask) | g3;
141        h4 = (h4 & mask) | g4;
142
143        // h = h % (2^128)
144        h0 = ((h0      ) | (h1 << 26)) & 0xffffffff;
145        h1 = ((h1 >>  6) | (h2 << 20)) & 0xffffffff;
146        h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
147        h3 = ((h3 >> 18) | (h4 <<  8)) & 0xffffffff;
148
149        // h = mac = (h + pad) % (2^128)
150        let mut f : u64;
151        f = h0 as u64 + self.pad[0] as u64            ; h0 = f as u32;
152        f = h1 as u64 + self.pad[1] as u64 + (f >> 32); h1 = f as u32;
153        f = h2 as u64 + self.pad[2] as u64 + (f >> 32); h2 = f as u32;
154        f = h3 as u64 + self.pad[3] as u64 + (f >> 32); h3 = f as u32;
155
156        self.h[0] = h0;
157        self.h[1] = h1;
158        self.h[2] = h2;
159        self.h[3] = h3;
160    }
161}
162
163impl Mac for Poly1305 {
164    fn input(&mut self, data: &[u8]) {
165        assert!(!self.finalized);
166        let mut m = data;
167
168        if self.leftover > 0 {
169            let want = min(16 - self.leftover, m.len());
170            for i in 0..want {
171                self.buffer[self.leftover+i] = m[i];
172            }
173            m = &m[want..];
174            self.leftover += want;
175
176            if self.leftover < 16 {
177                return;
178            }
179
180            // self.block(self.buffer[..]);
181            let tmp = self.buffer;
182            self.block(&tmp);
183
184            self.leftover = 0;
185        }
186
187        while m.len() >= 16 {
188            self.block(&m[0..16]);
189            m = &m[16..];
190        }
191
192        for i in 0..m.len() {
193            self.buffer[i] = m[i];
194        }
195        self.leftover = m.len();
196    }
197
198    fn reset(&mut self) {
199        self.h = [0u32; 5];
200        self.leftover = 0;
201        self.finalized = false;
202    }
203
204    fn result(&mut self) -> MacResult {
205        let mut mac = [0u8; 16];
206        self.raw_result(&mut mac);
207        MacResult::new(&mac[..])
208    }
209
210    fn raw_result(&mut self, output: &mut [u8]) {
211        assert!(output.len() >= 16);
212        if !self.finalized{
213            self.finish();
214        }
215        write_u32_le(&mut output[0..4], self.h[0]);
216        write_u32_le(&mut output[4..8], self.h[1]);
217        write_u32_le(&mut output[8..12], self.h[2]);
218        write_u32_le(&mut output[12..16], self.h[3]);
219    }
220
221    fn output_bytes(&self) -> usize { 16 }
222}
223
224#[cfg(test)]
225mod test {
226    use std::iter::repeat;
227
228    use poly1305::Poly1305;
229    use mac::Mac;
230
231    fn poly1305(key: &[u8], msg: &[u8], mac: &mut [u8]) {
232        let mut poly = Poly1305::new(key);
233        poly.input(msg);
234        poly.raw_result(mac);
235    }
236
237    #[test]
238    fn test_nacl_vector() {
239        let key = [
240            0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91,
241            0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25,
242            0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65,
243            0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80,
244        ];
245
246        let msg = [
247            0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73,
248            0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce,
249            0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4,
250            0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a,
251            0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b,
252            0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72,
253            0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2,
254            0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38,
255            0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a,
256            0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae,
257            0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea,
258            0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda,
259            0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde,
260            0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3,
261            0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6,
262            0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74,
263            0xe3,0x55,0xa5,
264        ];
265
266        let expected = [
267            0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5,
268            0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9,
269        ];
270
271        let mut mac = [0u8; 16];
272        poly1305(&key, &msg, &mut mac);
273        assert_eq!(&mac[..], &expected[..]);
274
275        let mut poly = Poly1305::new(&key);
276        poly.input(&msg[0..32]);
277        poly.input(&msg[32..96]);
278        poly.input(&msg[96..112]);
279        poly.input(&msg[112..120]);
280        poly.input(&msg[120..124]);
281        poly.input(&msg[124..126]);
282        poly.input(&msg[126..127]);
283        poly.input(&msg[127..128]);
284        poly.input(&msg[128..129]);
285        poly.input(&msg[129..130]);
286        poly.input(&msg[130..131]);
287        poly.raw_result(&mut mac);
288        assert_eq!(&mac[..], &expected[..]);
289    }
290
291    #[test]
292    fn donna_self_test() {
293        let wrap_key = [
294            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298        ];
299
300        let wrap_msg = [
301            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
302            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
303        ];
304
305        let wrap_mac = [
306            0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308        ];
309
310        let mut mac = [0u8; 16];
311        poly1305(&wrap_key, &wrap_msg, &mut mac);
312        assert_eq!(&mac[..], &wrap_mac[..]);
313
314        let total_key = [
315            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff,
316            0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xff, 0xff,
317            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
318            0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
319        ];
320
321        let total_mac = [
322            0x64, 0xaf, 0xe2, 0xe8, 0xd6, 0xad, 0x7b, 0xbd,
323            0xd2, 0x87, 0xf9, 0x7c, 0x44, 0x62, 0x3d, 0x39,
324        ];
325
326        let mut tpoly = Poly1305::new(&total_key);
327        for i in 0..256 {
328            let key: Vec<u8> = repeat(i as u8).take(32).collect();
329            let msg: Vec<u8> = repeat(i as u8).take(256).collect();
330            let mut mac = [0u8; 16];
331            poly1305(&key[..], &msg[0..i], &mut mac);
332            tpoly.input(&mac);
333        }
334        tpoly.raw_result(&mut mac);
335        assert_eq!(&mac[..], &total_mac[..]);
336    }
337
338    #[test]
339    fn test_tls_vectors() {
340        // from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
341        let key = b"this is 32-byte key for Poly1305";
342        let msg = [0u8; 32];
343        let expected = [
344            0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6,
345            0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07,
346        ];
347        let mut mac = [0u8; 16];
348        poly1305(key, &msg, &mut mac);
349        assert_eq!(&mac[..], &expected[..]);
350
351        let msg = b"Hello world!";
352        let expected= [
353            0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16,
354            0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0,
355        ];
356        poly1305(key, msg, &mut mac);
357        assert_eq!(&mac[..], &expected[..]);
358    }
359}
360
361#[cfg(all(test, feature = "with-bench"))]
362mod bench {
363    use test::Bencher;
364    use mac::Mac;
365    use poly1305::Poly1305;
366
367    #[bench]
368    pub fn poly1305_10(bh: & mut Bencher) {
369        let mut mac = [0u8; 16];
370        let key     = [0u8; 32];
371        let bytes   = [1u8; 10];
372        bh.iter( || {
373            let mut poly = Poly1305::new(&key);
374            poly.input(&bytes);
375            poly.raw_result(&mut mac);
376        });
377        bh.bytes = bytes.len() as u64;
378    }
379
380    #[bench]
381    pub fn poly1305_1k(bh: & mut Bencher) {
382        let mut mac = [0u8; 16];
383        let key     = [0u8; 32];
384        let bytes   = [1u8; 1024];
385        bh.iter( || {
386            let mut poly = Poly1305::new(&key);
387            poly.input(&bytes);
388            poly.raw_result(&mut mac);
389        });
390        bh.bytes = bytes.len() as u64;
391    }
392
393    #[bench]
394    pub fn poly1305_64k(bh: & mut Bencher) {
395        let mut mac = [0u8; 16];
396        let key     = [0u8; 32];
397        let bytes   = [1u8; 65536];
398        bh.iter( || {
399            let mut poly = Poly1305::new(&key);
400            poly.input(&bytes);
401            poly.raw_result(&mut mac);
402        });
403        bh.bytes = bytes.len() as u64;
404    }
405}