~ubuntu-branches/debian/sid/botan/sid

« back to all changes in this revision

Viewing changes to src/lib/mac/poly1305/poly1305.cpp

  • Committer: Package Import Robot
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2018-03-01 22:23:25 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20180301222325-7p7vc45gu3hta34d
Tags: 2.4.0-2
* Don't remove .doctrees from the manual if it doesn't exist.
* Don't specify parallel to debhelper.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/poly1305.h>
 
12
#include <botan/loadstor.h>
 
13
#include <botan/mul128.h>
 
14
#include <botan/internal/donna128.h>
 
15
 
 
16
namespace Botan {
 
17
 
 
18
namespace {
 
19
 
 
20
void poly1305_init(secure_vector<uint64_t>& X, const uint8_t key[32])
 
21
   {
 
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);
 
25
 
 
26
   X[0] = ( t0                    ) & 0xffc0fffffff;
 
27
   X[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
 
28
   X[2] = ((t1 >> 24)             ) & 0x00ffffffc0f;
 
29
 
 
30
   /* h = 0 */
 
31
   X[3] = 0;
 
32
   X[4] = 0;
 
33
   X[5] = 0;
 
34
 
 
35
   /* save pad for later */
 
36
   X[6] = load_le<uint64_t>(key, 2);
 
37
   X[7] = load_le<uint64_t>(key, 3);
 
38
   }
 
39
 
 
40
void poly1305_blocks(secure_vector<uint64_t>& X, const uint8_t *m, size_t blocks, bool is_final = false)
 
41
   {
 
42
#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128)
 
43
   typedef donna128 uint128_t;
 
44
#endif
 
45
 
 
46
   const uint64_t hibit = is_final ? 0 : (static_cast<uint64_t>(1) << 40); /* 1 << 128 */
 
47
 
 
48
   const uint64_t r0 = X[0];
 
49
   const uint64_t r1 = X[1];
 
50
   const uint64_t r2 = X[2];
 
51
 
 
52
   uint64_t h0 = X[3+0];
 
53
   uint64_t h1 = X[3+1];
 
54
   uint64_t h2 = X[3+2];
 
55
 
 
56
   const uint64_t s1 = r1 * (5 << 2);
 
57
   const uint64_t s2 = r2 * (5 << 2);
 
58
 
 
59
   while(blocks--)
 
60
      {
 
61
      /* h += m[i] */
 
62
      const uint64_t t0 = load_le<uint64_t>(m, 0);
 
63
      const uint64_t t1 = load_le<uint64_t>(m, 1);
 
64
 
 
65
      h0 += (( t0                    ) & 0xfffffffffff);
 
66
      h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
 
67
      h2 += (((t1 >> 24)             ) & 0x3ffffffffff) | hibit;
 
68
 
 
69
      /* h *= r */
 
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;
 
73
 
 
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;
 
79
      h1 += c;
 
80
 
 
81
      m += 16;
 
82
      }
 
83
 
 
84
   X[3+0] = h0;
 
85
   X[3+1] = h1;
 
86
   X[3+2] = h2;
 
87
   }
 
88
 
 
89
void poly1305_finish(secure_vector<uint64_t>& X, uint8_t mac[16])
 
90
   {
 
91
   /* fully carry h */
 
92
   uint64_t h0 = X[3+0];
 
93
   uint64_t h1 = X[3+1];
 
94
   uint64_t h2 = X[3+2];
 
95
 
 
96
   uint64_t c;
 
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;
 
103
   h1 += c;
 
104
 
 
105
   /* compute h + -p */
 
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);
 
109
 
 
110
   /* select h if h < p, or h + -p if h >= p */
 
111
   c = (g2 >> ((sizeof(uint64_t) * 8) - 1)) - 1;
 
112
   g0 &= c;
 
113
   g1 &= c;
 
114
   g2 &= c;
 
115
   c = ~c;
 
116
   h0 = (h0 & c) | g0;
 
117
   h1 = (h1 & c) | g1;
 
118
   h2 = (h2 & c) | g2;
 
119
 
 
120
   /* h = (h + pad) */
 
121
   const uint64_t t0 = X[6];
 
122
   const uint64_t t1 = X[7];
 
123
 
 
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;
 
127
 
 
128
   /* mac = h % (2^128) */
 
129
   h0 = ((h0      ) | (h1 << 44));
 
130
   h1 = ((h1 >> 20) | (h2 << 24));
 
131
 
 
132
   store_le(mac, h0, h1);
 
133
 
 
134
   /* zero out the state */
 
135
   clear_mem(X.data(), X.size());
 
136
   }
 
137
 
 
138
}
 
139
 
 
140
void Poly1305::clear()
 
141
   {
 
142
   zap(m_poly);
 
143
   zap(m_buf);
 
144
   m_buf_pos = 0;
 
145
   }
 
146
 
 
147
void Poly1305::key_schedule(const uint8_t key[], size_t)
 
148
   {
 
149
   m_buf_pos = 0;
 
150
   m_buf.resize(16);
 
151
   m_poly.resize(8);
 
152
 
 
153
   poly1305_init(m_poly, key);
 
154
   }
 
155
 
 
156
void Poly1305::add_data(const uint8_t input[], size_t length)
 
157
   {
 
158
   verify_key_set(m_poly.size() == 8);
 
159
 
 
160
   if(m_buf_pos)
 
161
      {
 
162
      buffer_insert(m_buf, m_buf_pos, input, length);
 
163
 
 
164
      if(m_buf_pos + length >= m_buf.size())
 
165
         {
 
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);
 
169
         m_buf_pos = 0;
 
170
         }
 
171
      }
 
172
 
 
173
   const size_t full_blocks = length / m_buf.size();
 
174
   const size_t remaining   = length % m_buf.size();
 
175
 
 
176
   if(full_blocks)
 
177
      poly1305_blocks(m_poly, input, full_blocks);
 
178
 
 
179
   buffer_insert(m_buf, m_buf_pos, input + full_blocks * m_buf.size(), remaining);
 
180
   m_buf_pos += remaining;
 
181
   }
 
182
 
 
183
void Poly1305::final_result(uint8_t out[])
 
184
   {
 
185
   verify_key_set(m_poly.size() == 8);
 
186
 
 
187
   if(m_buf_pos != 0)
 
188
      {
 
189
      m_buf[m_buf_pos] = 1;
 
190
      const size_t len = m_buf.size() - m_buf_pos - 1;
 
191
      if (len > 0)
 
192
         {
 
193
         clear_mem(&m_buf[m_buf_pos+1], len);
 
194
         }
 
195
      poly1305_blocks(m_poly, m_buf.data(), 1, true);
 
196
      }
 
197
 
 
198
   poly1305_finish(m_poly, out);
 
199
 
 
200
   m_poly.clear();
 
201
   m_buf_pos = 0;
 
202
   }
 
203
 
 
204
}