Botan 3.4.0
Crypto and TLS for C&
poly1305.cpp
Go to the documentation of this file.
1/*
2* Derived from poly1305-donna-64.h by Andrew Moon <liquidsun@gmail.com>
3* in https://github.com/floodyberry/poly1305-donna
4*
5* (C) 2014 Andrew Moon
6* (C) 2014 Jack Lloyd
7*
8* Botan is released under the Simplified BSD License (see license.txt)
9*/
10
11#include <botan/internal/poly1305.h>
12
13#include <botan/internal/ct_utils.h>
14#include <botan/internal/donna128.h>
15#include <botan/internal/loadstor.h>
16#include <botan/internal/mul128.h>
17#include <botan/internal/stl_util.h>
18
19namespace Botan {
20
21namespace {
22
23void poly1305_init(secure_vector<uint64_t>& X, const uint8_t key[32]) {
24 /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
25 const uint64_t t0 = load_le<uint64_t>(key, 0);
26 const uint64_t t1 = load_le<uint64_t>(key, 1);
27
28 X[0] = (t0)&0xffc0fffffff;
29 X[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
30 X[2] = ((t1 >> 24)) & 0x00ffffffc0f;
31
32 /* h = 0 */
33 X[3] = 0;
34 X[4] = 0;
35 X[5] = 0;
36
37 /* save pad for later */
38 X[6] = load_le<uint64_t>(key, 2);
39 X[7] = load_le<uint64_t>(key, 3);
40}
41
42void poly1305_blocks(secure_vector<uint64_t>& X, const uint8_t* m, size_t blocks, bool is_final = false) {
43#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128)
44 typedef donna128 uint128_t;
45#endif
46
47 const uint64_t hibit = is_final ? 0 : (static_cast<uint64_t>(1) << 40); /* 1 << 128 */
48
49 const uint64_t r0 = X[0];
50 const uint64_t r1 = X[1];
51 const uint64_t r2 = X[2];
52
53 const uint64_t M44 = 0xFFFFFFFFFFF;
54 const uint64_t M42 = 0x3FFFFFFFFFF;
55
56 uint64_t h0 = X[3 + 0];
57 uint64_t h1 = X[3 + 1];
58 uint64_t h2 = X[3 + 2];
59
60 const uint64_t s1 = r1 * 20;
61 const uint64_t s2 = r2 * 20;
62
63 for(size_t i = 0; i != blocks; ++i) {
64 const uint64_t t0 = load_le<uint64_t>(m, 0);
65 const uint64_t t1 = load_le<uint64_t>(m, 1);
66
67 h0 += ((t0)&M44);
68 h1 += (((t0 >> 44) | (t1 << 20)) & M44);
69 h2 += (((t1 >> 24)) & M42) | hibit;
70
71 const uint128_t d0 = uint128_t(h0) * r0 + uint128_t(h1) * s2 + uint128_t(h2) * s1;
72 const uint64_t c0 = carry_shift(d0, 44);
73
74 const uint128_t d1 = uint128_t(h0) * r1 + uint128_t(h1) * r0 + uint128_t(h2) * s2 + c0;
75 const uint64_t c1 = carry_shift(d1, 44);
76
77 const uint128_t d2 = uint128_t(h0) * r2 + uint128_t(h1) * r1 + uint128_t(h2) * r0 + c1;
78 const uint64_t c2 = carry_shift(d2, 42);
79
80 h0 = d0 & M44;
81 h1 = d1 & M44;
82 h2 = d2 & M42;
83
84 h0 += c2 * 5;
85 h1 += carry_shift(h0, 44);
86 h0 = h0 & M44;
87
88 m += 16;
89 }
90
91 X[3 + 0] = h0;
92 X[3 + 1] = h1;
93 X[3 + 2] = h2;
94}
95
96void poly1305_finish(secure_vector<uint64_t>& X, uint8_t mac[16]) {
97 const uint64_t M44 = 0xFFFFFFFFFFF;
98 const uint64_t M42 = 0x3FFFFFFFFFF;
99
100 /* fully carry h */
101 uint64_t h0 = X[3 + 0];
102 uint64_t h1 = X[3 + 1];
103 uint64_t h2 = X[3 + 2];
104
105 uint64_t c;
106 c = (h1 >> 44);
107 h1 &= M44;
108 h2 += c;
109 c = (h2 >> 42);
110 h2 &= M42;
111 h0 += c * 5;
112 c = (h0 >> 44);
113 h0 &= M44;
114 h1 += c;
115 c = (h1 >> 44);
116 h1 &= M44;
117 h2 += c;
118 c = (h2 >> 42);
119 h2 &= M42;
120 h0 += c * 5;
121 c = (h0 >> 44);
122 h0 &= M44;
123 h1 += c;
124
125 /* compute h + -p */
126 uint64_t g0 = h0 + 5;
127 c = (g0 >> 44);
128 g0 &= M44;
129 uint64_t g1 = h1 + c;
130 c = (g1 >> 44);
131 g1 &= M44;
132 uint64_t g2 = h2 + c - (static_cast<uint64_t>(1) << 42);
133
134 /* select h if h < p, or h + -p if h >= p */
135 const auto c_mask = CT::Mask<uint64_t>::expand(c);
136 h0 = c_mask.select(g0, h0);
137 h1 = c_mask.select(g1, h1);
138 h2 = c_mask.select(g2, h2);
139
140 /* h = (h + pad) */
141 const uint64_t t0 = X[6];
142 const uint64_t t1 = X[7];
143
144 h0 += ((t0)&M44);
145 c = (h0 >> 44);
146 h0 &= M44;
147 h1 += (((t0 >> 44) | (t1 << 20)) & M44) + c;
148 c = (h1 >> 44);
149 h1 &= M44;
150 h2 += (((t1 >> 24)) & M42) + c;
151 h2 &= M42;
152
153 /* mac = h % (2^128) */
154 h0 = ((h0) | (h1 << 44));
155 h1 = ((h1 >> 20) | (h2 << 24));
156
157 store_le(mac, h0, h1);
158
159 /* zero out the state */
160 clear_mem(X.data(), X.size());
161}
162
163} // namespace
164
166 zap(m_poly);
167 m_buffer.clear();
168}
169
171 return m_poly.size() == 8;
172}
173
174void Poly1305::key_schedule(std::span<const uint8_t> key) {
175 m_buffer.clear();
176 m_poly.resize(8);
177
178 poly1305_init(m_poly, key.data());
179}
180
181void Poly1305::add_data(std::span<const uint8_t> input) {
183
184 BufferSlicer in(input);
185
186 while(!in.empty()) {
187 if(const auto one_block = m_buffer.handle_unaligned_data(in)) {
188 poly1305_blocks(m_poly, one_block->data(), 1);
189 }
190
191 if(m_buffer.in_alignment()) {
192 const auto [aligned_data, full_blocks] = m_buffer.aligned_data_to_process(in);
193 if(full_blocks > 0) {
194 poly1305_blocks(m_poly, aligned_data.data(), full_blocks);
195 }
196 }
197 }
198}
199
200void Poly1305::final_result(std::span<uint8_t> out) {
202
203 if(!m_buffer.in_alignment()) {
204 const uint8_t final_byte = 0x01;
205 m_buffer.append({&final_byte, 1});
206 m_buffer.fill_up_with_zeros();
207 poly1305_blocks(m_poly, m_buffer.consume().data(), 1, true);
208 }
209
210 poly1305_finish(m_poly, out.data());
211
212 m_poly.clear();
213 m_buffer.clear();
214}
215
216} // namespace Botan
std::tuple< std::span< const uint8_t >, size_t > aligned_data_to_process(BufferSlicer &slicer) const
void append(std::span< const T > elements)
std::optional< std::span< const T > > handle_unaligned_data(BufferSlicer &slicer)
std::span< const T > consume()
static constexpr Mask< T > expand(T v)
Definition ct_utils.h:115
void clear() override
Definition poly1305.cpp:165
bool has_keying_material() const override
Definition poly1305.cpp:170
void assert_key_material_set() const
Definition sym_algo.h:139
FE_25519 X
Definition ge.cpp:25
constexpr uint64_t carry_shift(const donna128 &a, size_t shift)
Definition donna128.h:132
void zap(std::vector< T, Alloc > &vec)
Definition secmem.h:117
constexpr auto store_le(ParamTs &&... params)
Definition loadstor.h:702
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:120