1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use hacspec_lib::*;
bytes!(PolyKey, 32);
const BLOCKSIZE: usize = 16;
bytes!(PolyBlock, 16);
bytes!(Poly1305Tag, 16);
pub type SubBlock = ByteSeq;
pub type BlockIndex = usize;
public_nat_mod!(
type_name: FieldElement,
type_of_canvas: FieldCanvas,
bit_size_of_field: 131,
modulo_value: "03fffffffffffffffffffffffffffffffb"
);
pub type PolyState = (FieldElement, FieldElement, PolyKey);
pub fn poly1305_encode_r(b: &PolyBlock) -> FieldElement {
let mut n = U128_from_le_bytes(U128Word::from_seq(b));
n = n & U128(0x0fff_fffc_0fff_fffc_0fff_fffc_0fff_ffffu128);
FieldElement::from_secret_literal(n)
}
pub fn poly1305_encode_block(b: &PolyBlock) -> FieldElement {
let n = U128_from_le_bytes(U128Word::from_seq(b));
let f = FieldElement::from_secret_literal(n);
f + FieldElement::pow2(128)
}
pub fn poly1305_encode_last(pad_len: BlockIndex, b: &SubBlock) -> FieldElement {
let n = U128_from_le_bytes(U128Word::from_slice(b, 0, b.len()));
let f = FieldElement::from_secret_literal(n);
f + FieldElement::pow2(8 * pad_len)
}
pub fn poly1305_init(k: PolyKey) -> PolyState {
let r = poly1305_encode_r(&PolyBlock::from_slice(&k, 0, 16));
(FieldElement::ZERO(), r, k)
}
pub fn poly1305_update_block(b: &PolyBlock, st: PolyState) -> PolyState {
let (acc, r, k) = st;
((poly1305_encode_block(b) + acc) * r, r, k)
}
pub fn poly1305_update_blocks(m: &ByteSeq, st: PolyState) -> PolyState {
let mut st = st;
let n_blocks = m.len() / BLOCKSIZE;
for i in 0..n_blocks {
let block = PolyBlock::from_seq(&m.get_exact_chunk(BLOCKSIZE, i));
st = poly1305_update_block(&block, st);
}
st
}
pub fn poly1305_update_last(pad_len: usize, b: &SubBlock, st: PolyState) -> PolyState {
let mut st = st;
if b.len() != 0 {
let (acc, r, k) = st;
st = ((poly1305_encode_last(pad_len, b) + acc) * r, r, k);
}
st
}
pub fn poly1305_update(m: &ByteSeq, st: PolyState) -> PolyState {
let st = poly1305_update_blocks(m, st);
let last = m.get_remainder_chunk(BLOCKSIZE);
poly1305_update_last(last.len(), &last, st)
}
pub fn poly1305_finish(st: PolyState) -> Poly1305Tag {
let (acc, _, k) = st;
let n = U128_from_le_bytes(U128Word::from_slice(&k, 16, 16));
let aby = acc.to_byte_seq_le();
let a = U128_from_le_bytes(U128Word::from_slice(&aby, 0, 16));
Poly1305Tag::from_seq(&U128_to_le_bytes(a + n))
}
pub fn poly1305(m: &ByteSeq, key: PolyKey) -> Poly1305Tag {
let mut st = poly1305_init(key);
st = poly1305_update(m, st);
poly1305_finish(st)
}