2
* Derived from poly1305-donna-64.h by Andrew Moon <liquidsun@gmail.com>
3
* in https://github.com/floodyberry/poly1305-donna
8
* Botan is released under the Simplified BSD License (see license.txt)
11
#include <botan/poly1305.h>
12
#include <botan/loadstor.h>
13
#include <botan/mul128.h>
14
#include <botan/internal/donna128.h>
20
void poly1305_init(secure_vector<uint64_t>& X, const uint8_t key[32])
22
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
23
const uint64_t t0 = load_le<uint64_t>(key, 0);
24
const uint64_t t1 = load_le<uint64_t>(key, 1);
26
X[0] = ( t0 ) & 0xffc0fffffff;
27
X[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
28
X[2] = ((t1 >> 24) ) & 0x00ffffffc0f;
35
/* save pad for later */
36
X[6] = load_le<uint64_t>(key, 2);
37
X[7] = load_le<uint64_t>(key, 3);
40
void poly1305_blocks(secure_vector<uint64_t>& X, const uint8_t *m, size_t blocks, bool is_final = false)
42
#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128)
43
typedef donna128 uint128_t;
46
const uint64_t hibit = is_final ? 0 : (static_cast<uint64_t>(1) << 40); /* 1 << 128 */
48
const uint64_t r0 = X[0];
49
const uint64_t r1 = X[1];
50
const uint64_t r2 = X[2];
56
const uint64_t s1 = r1 * (5 << 2);
57
const uint64_t s2 = r2 * (5 << 2);
62
const uint64_t t0 = load_le<uint64_t>(m, 0);
63
const uint64_t t1 = load_le<uint64_t>(m, 1);
65
h0 += (( t0 ) & 0xfffffffffff);
66
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
67
h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit;
70
uint128_t d0 = uint128_t(h0) * r0 + uint128_t(h1) * s2 + uint128_t(h2) * s1;
71
uint128_t d1 = uint128_t(h0) * r1 + uint128_t(h1) * r0 + uint128_t(h2) * s2;
72
uint128_t d2 = uint128_t(h0) * r2 + uint128_t(h1) * r1 + uint128_t(h2) * r0;
74
/* (partial) h %= p */
75
uint64_t c = carry_shift(d0, 44); h0 = d0 & 0xfffffffffff;
76
d1 += c; c = carry_shift(d1, 44); h1 = d1 & 0xfffffffffff;
77
d2 += c; c = carry_shift(d2, 42); h2 = d2 & 0x3ffffffffff;
78
h0 += c * 5; c = carry_shift(h0, 44); h0 = h0 & 0xfffffffffff;
89
void poly1305_finish(secure_vector<uint64_t>& X, uint8_t mac[16])
97
c = (h1 >> 44); h1 &= 0xfffffffffff;
98
h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
99
h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
100
h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff;
101
h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
102
h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
106
uint64_t g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff;
107
uint64_t g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff;
108
uint64_t g2 = h2 + c - (static_cast<uint64_t>(1) << 42);
110
/* select h if h < p, or h + -p if h >= p */
111
c = (g2 >> ((sizeof(uint64_t) * 8) - 1)) - 1;
121
const uint64_t t0 = X[6];
122
const uint64_t t1 = X[7];
124
h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff;
125
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff;
126
h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff;
128
/* mac = h % (2^128) */
129
h0 = ((h0 ) | (h1 << 44));
130
h1 = ((h1 >> 20) | (h2 << 24));
132
store_le(mac, h0, h1);
134
/* zero out the state */
135
clear_mem(X.data(), X.size());
140
void Poly1305::clear()
147
void Poly1305::key_schedule(const uint8_t key[], size_t)
153
poly1305_init(m_poly, key);
156
void Poly1305::add_data(const uint8_t input[], size_t length)
158
verify_key_set(m_poly.size() == 8);
162
buffer_insert(m_buf, m_buf_pos, input, length);
164
if(m_buf_pos + length >= m_buf.size())
166
poly1305_blocks(m_poly, m_buf.data(), 1);
167
input += (m_buf.size() - m_buf_pos);
168
length -= (m_buf.size() - m_buf_pos);
173
const size_t full_blocks = length / m_buf.size();
174
const size_t remaining = length % m_buf.size();
177
poly1305_blocks(m_poly, input, full_blocks);
179
buffer_insert(m_buf, m_buf_pos, input + full_blocks * m_buf.size(), remaining);
180
m_buf_pos += remaining;
183
void Poly1305::final_result(uint8_t out[])
185
verify_key_set(m_poly.size() == 8);
189
m_buf[m_buf_pos] = 1;
190
const size_t len = m_buf.size() - m_buf_pos - 1;
193
clear_mem(&m_buf[m_buf_pos+1], len);
195
poly1305_blocks(m_poly, m_buf.data(), 1, true);
198
poly1305_finish(m_poly, out);