Skip to main content

poly1305/backend/
soft.rs

1//! Software implementation of the Poly1305 state machine.
2
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8//
9// This code originates from the rust-crypto project:
10// <https://github.com/DaGenix/rust-crypto>
11//
12// ...and was originally a port of Andrew Moons poly1305-donna
13// https://github.com/floodyberry/poly1305-donna
14
15use universal_hash::{
16    UhfBackend, UhfClosure,
17    common::{BlockSizeUser, ParBlocksSizeUser},
18    consts::{U1, U16},
19};
20
21use crate::{Block, Key, Tag};
22
23#[derive(Clone, Default)]
24pub(crate) struct State {
25    r: [u32; 5],
26    h: [u32; 5],
27    pad: [u32; 4],
28}
29
30impl State {
31    /// Initialize Poly1305 [`State`] with the given key
32    pub(crate) fn new(key: &Key) -> State {
33        let mut poly = State::default();
34
35        // r &= 0x0ffffffc_0ffffffc_0ffffffc_0fffffff
36        poly.r[0] = (u32::from_le_bytes(key[0..4].try_into().unwrap())) & 0x3ff_ffff;
37        poly.r[1] = (u32::from_le_bytes(key[3..7].try_into().unwrap()) >> 2) & 0x3ff_ff03;
38        poly.r[2] = (u32::from_le_bytes(key[6..10].try_into().unwrap()) >> 4) & 0x3ff_c0ff;
39        poly.r[3] = (u32::from_le_bytes(key[9..13].try_into().unwrap()) >> 6) & 0x3f0_3fff;
40        poly.r[4] = (u32::from_le_bytes(key[12..16].try_into().unwrap()) >> 8) & 0x00f_ffff;
41
42        poly.pad[0] = u32::from_le_bytes(key[16..20].try_into().unwrap());
43        poly.pad[1] = u32::from_le_bytes(key[20..24].try_into().unwrap());
44        poly.pad[2] = u32::from_le_bytes(key[24..28].try_into().unwrap());
45        poly.pad[3] = u32::from_le_bytes(key[28..32].try_into().unwrap());
46
47        poly
48    }
49
50    /// Compute a Poly1305 block
51    pub(crate) fn compute_block(&mut self, block: &Block, partial: bool) {
52        let hibit = if partial { 0 } else { 1 << 24 };
53
54        let r0 = self.r[0];
55        let r1 = self.r[1];
56        let r2 = self.r[2];
57        let r3 = self.r[3];
58        let r4 = self.r[4];
59
60        let s1 = r1 * 5;
61        let s2 = r2 * 5;
62        let s3 = r3 * 5;
63        let s4 = r4 * 5;
64
65        let mut h0 = self.h[0];
66        let mut h1 = self.h[1];
67        let mut h2 = self.h[2];
68        let mut h3 = self.h[3];
69        let mut h4 = self.h[4];
70
71        // h += m
72        h0 += (u32::from_le_bytes(block[0..4].try_into().unwrap())) & 0x3ff_ffff;
73        h1 += (u32::from_le_bytes(block[3..7].try_into().unwrap()) >> 2) & 0x3ff_ffff;
74        h2 += (u32::from_le_bytes(block[6..10].try_into().unwrap()) >> 4) & 0x3ff_ffff;
75        h3 += (u32::from_le_bytes(block[9..13].try_into().unwrap()) >> 6) & 0x3ff_ffff;
76        h4 += (u32::from_le_bytes(block[12..16].try_into().unwrap()) >> 8) | hibit;
77
78        // h *= r
79        let d0 = (u64::from(h0) * u64::from(r0))
80            + (u64::from(h1) * u64::from(s4))
81            + (u64::from(h2) * u64::from(s3))
82            + (u64::from(h3) * u64::from(s2))
83            + (u64::from(h4) * u64::from(s1));
84
85        let mut d1 = (u64::from(h0) * u64::from(r1))
86            + (u64::from(h1) * u64::from(r0))
87            + (u64::from(h2) * u64::from(s4))
88            + (u64::from(h3) * u64::from(s3))
89            + (u64::from(h4) * u64::from(s2));
90
91        let mut d2 = (u64::from(h0) * u64::from(r2))
92            + (u64::from(h1) * u64::from(r1))
93            + (u64::from(h2) * u64::from(r0))
94            + (u64::from(h3) * u64::from(s4))
95            + (u64::from(h4) * u64::from(s3));
96
97        let mut d3 = (u64::from(h0) * u64::from(r3))
98            + (u64::from(h1) * u64::from(r2))
99            + (u64::from(h2) * u64::from(r1))
100            + (u64::from(h3) * u64::from(r0))
101            + (u64::from(h4) * u64::from(s4));
102
103        let mut d4 = (u64::from(h0) * u64::from(r4))
104            + (u64::from(h1) * u64::from(r3))
105            + (u64::from(h2) * u64::from(r2))
106            + (u64::from(h3) * u64::from(r1))
107            + (u64::from(h4) * u64::from(r0));
108
109        // (partial) h %= p
110        let mut c: u32;
111        c = (d0 >> 26) as u32;
112        h0 = d0 as u32 & 0x3ff_ffff;
113        d1 += u64::from(c);
114
115        c = (d1 >> 26) as u32;
116        h1 = d1 as u32 & 0x3ff_ffff;
117        d2 += u64::from(c);
118
119        c = (d2 >> 26) as u32;
120        h2 = d2 as u32 & 0x3ff_ffff;
121        d3 += u64::from(c);
122
123        c = (d3 >> 26) as u32;
124        h3 = d3 as u32 & 0x3ff_ffff;
125        d4 += u64::from(c);
126
127        c = (d4 >> 26) as u32;
128        h4 = d4 as u32 & 0x3ff_ffff;
129        h0 += c * 5;
130
131        c = h0 >> 26;
132        h0 &= 0x3ff_ffff;
133        h1 += c;
134
135        self.h[0] = h0;
136        self.h[1] = h1;
137        self.h[2] = h2;
138        self.h[3] = h3;
139        self.h[4] = h4;
140    }
141
142    #[allow(unused, reason = "this method is used by some targets")]
143    pub(crate) fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = U16>) {
144        f.call(self);
145    }
146
147    /// Finalize output producing a [`Tag`]
148    pub(crate) fn finalize(&mut self) -> Tag {
149        // fully carry h
150        let mut h0 = self.h[0];
151        let mut h1 = self.h[1];
152        let mut h2 = self.h[2];
153        let mut h3 = self.h[3];
154        let mut h4 = self.h[4];
155
156        let mut c: u32;
157        c = h1 >> 26;
158        h1 &= 0x3ff_ffff;
159        h2 += c;
160
161        c = h2 >> 26;
162        h2 &= 0x3ff_ffff;
163        h3 += c;
164
165        c = h3 >> 26;
166        h3 &= 0x3ff_ffff;
167        h4 += c;
168
169        c = h4 >> 26;
170        h4 &= 0x3ff_ffff;
171        h0 += c * 5;
172
173        c = h0 >> 26;
174        h0 &= 0x3ff_ffff;
175        h1 += c;
176
177        // compute h + -p
178        let mut g0 = h0.wrapping_add(5);
179        c = g0 >> 26;
180        g0 &= 0x3ff_ffff;
181
182        let mut g1 = h1.wrapping_add(c);
183        c = g1 >> 26;
184        g1 &= 0x3ff_ffff;
185
186        let mut g2 = h2.wrapping_add(c);
187        c = g2 >> 26;
188        g2 &= 0x3ff_ffff;
189
190        let mut g3 = h3.wrapping_add(c);
191        c = g3 >> 26;
192        g3 &= 0x3ff_ffff;
193
194        let mut g4 = h4.wrapping_add(c).wrapping_sub(1 << 26);
195
196        // select h if h < p, or h + -p if h >= p
197        let mut mask = (g4 >> (32 - 1)).wrapping_sub(1);
198        g0 &= mask;
199        g1 &= mask;
200        g2 &= mask;
201        g3 &= mask;
202        g4 &= mask;
203        mask = !mask;
204        h0 = (h0 & mask) | g0;
205        h1 = (h1 & mask) | g1;
206        h2 = (h2 & mask) | g2;
207        h3 = (h3 & mask) | g3;
208        h4 = (h4 & mask) | g4;
209
210        // h = h % (2^128)
211        h0 |= h1 << 26;
212        h1 = (h1 >> 6) | (h2 << 20);
213        h2 = (h2 >> 12) | (h3 << 14);
214        h3 = (h3 >> 18) | (h4 << 8);
215
216        // h = mac = (h + pad) % (2^128)
217        let mut f: u64;
218        f = u64::from(h0) + u64::from(self.pad[0]);
219        h0 = f as u32;
220
221        f = u64::from(h1) + u64::from(self.pad[1]) + (f >> 32);
222        h1 = f as u32;
223
224        f = u64::from(h2) + u64::from(self.pad[2]) + (f >> 32);
225        h2 = f as u32;
226
227        f = u64::from(h3) + u64::from(self.pad[3]) + (f >> 32);
228        h3 = f as u32;
229
230        let mut tag = Block::default();
231        tag[0..4].copy_from_slice(&h0.to_le_bytes());
232        tag[4..8].copy_from_slice(&h1.to_le_bytes());
233        tag[8..12].copy_from_slice(&h2.to_le_bytes());
234        tag[12..16].copy_from_slice(&h3.to_le_bytes());
235
236        tag
237    }
238}
239
240impl BlockSizeUser for State {
241    type BlockSize = U16;
242}
243
244impl ParBlocksSizeUser for State {
245    type ParBlocksSize = U1;
246}
247
248impl UhfBackend for State {
249    fn proc_block(&mut self, block: &Block) {
250        self.compute_block(block, false);
251    }
252}