Always pad fingerprints to 16 characters
[project/usign.git] / f25519.c
1 /* Arithmetic mod p = 2^255-19
2 * Daniel Beer <dlbeer@gmail.com>, 5 Jan 2014
3 *
4 * This file is in the public domain.
5 */
6
7 #include "f25519.h"
8
9 const uint8_t f25519_one[F25519_SIZE] = {1};
10
11 void f25519_load(uint8_t *x, uint32_t c)
12 {
13 int i;
14
15 for (i = 0; i < sizeof(c); i++) {
16 x[i] = c;
17 c >>= 8;
18 }
19
20 for (; i < F25519_SIZE; i++)
21 x[i] = 0;
22 }
23
24 void f25519_normalize(uint8_t *x)
25 {
26 uint8_t minusp[F25519_SIZE];
27 uint16_t c;
28 int i;
29
30 /* Reduce using 2^255 = 19 mod p */
31 c = (x[31] >> 7) * 19;
32 x[31] &= 127;
33
34 for (i = 0; i < F25519_SIZE; i++) {
35 c += x[i];
36 x[i] = c;
37 c >>= 8;
38 }
39
40 /* The number is now less than 2^255 + 18, and therefore less than
41 * 2p. Try subtracting p, and conditionally load the subtracted
42 * value if underflow did not occur.
43 */
44 c = 19;
45
46 for (i = 0; i + 1 < F25519_SIZE; i++) {
47 c += x[i];
48 minusp[i] = c;
49 c >>= 8;
50 }
51
52 c += ((uint16_t)x[i]) - 128;
53 minusp[31] = c;
54
55 /* Load x-p if no underflow */
56 f25519_select(x, minusp, x, (c >> 15) & 1);
57 }
58
59 uint8_t f25519_eq(const uint8_t *x, const uint8_t *y)
60 {
61 uint8_t sum = 0;
62 int i;
63
64 for (i = 0; i < F25519_SIZE; i++)
65 sum |= x[i] ^ y[i];
66
67 sum |= (sum >> 4);
68 sum |= (sum >> 2);
69 sum |= (sum >> 1);
70
71 return (sum ^ 1) & 1;
72 }
73
74 void f25519_select(uint8_t *dst,
75 const uint8_t *zero, const uint8_t *one,
76 uint8_t condition)
77 {
78 const uint8_t mask = -condition;
79 int i;
80
81 for (i = 0; i < F25519_SIZE; i++)
82 dst[i] = zero[i] ^ (mask & (one[i] ^ zero[i]));
83 }
84
85 void f25519_add(uint8_t *r, const uint8_t *a, const uint8_t *b)
86 {
87 uint16_t c = 0;
88 int i;
89
90 /* Add */
91 for (i = 0; i < F25519_SIZE; i++) {
92 c >>= 8;
93 c += ((uint16_t)a[i]) + ((uint16_t)b[i]);
94 r[i] = c;
95 }
96
97 /* Reduce with 2^255 = 19 mod p */
98 r[31] &= 127;
99 c = (c >> 7) * 19;
100
101 for (i = 0; i < F25519_SIZE; i++) {
102 c += r[i];
103 r[i] = c;
104 c >>= 8;
105 }
106 }
107
108 void f25519_sub(uint8_t *r, const uint8_t *a, const uint8_t *b)
109 {
110 uint32_t c = 0;
111 int i;
112
113 /* Calculate a + 2p - b, to avoid underflow */
114 c = 218;
115 for (i = 0; i + 1 < F25519_SIZE; i++) {
116 c += 65280 + ((uint32_t)a[i]) - ((uint32_t)b[i]);
117 r[i] = c;
118 c >>= 8;
119 }
120
121 c += ((uint32_t)a[31]) - ((uint32_t)b[31]);
122 r[31] = c & 127;
123 c = (c >> 7) * 19;
124
125 for (i = 0; i < F25519_SIZE; i++) {
126 c += r[i];
127 r[i] = c;
128 c >>= 8;
129 }
130 }
131
132 void f25519_neg(uint8_t *r, const uint8_t *a)
133 {
134 uint32_t c = 0;
135 int i;
136
137 /* Calculate 2p - a, to avoid underflow */
138 c = 218;
139 for (i = 0; i + 1 < F25519_SIZE; i++) {
140 c += 65280 - ((uint32_t)a[i]);
141 r[i] = c;
142 c >>= 8;
143 }
144
145 c -= ((uint32_t)a[31]);
146 r[31] = c & 127;
147 c = (c >> 7) * 19;
148
149 for (i = 0; i < F25519_SIZE; i++) {
150 c += r[i];
151 r[i] = c;
152 c >>= 8;
153 }
154 }
155
156 void f25519_mul__distinct(uint8_t *r, const uint8_t *a, const uint8_t *b)
157 {
158 uint32_t c = 0;
159 int i;
160
161 for (i = 0; i < F25519_SIZE; i++) {
162 int j;
163
164 c >>= 8;
165 for (j = 0; j <= i; j++)
166 c += ((uint32_t)a[j]) * ((uint32_t)b[i - j]);
167
168 for (; j < F25519_SIZE; j++)
169 c += ((uint32_t)a[j]) *
170 ((uint32_t)b[i + F25519_SIZE - j]) * 38;
171
172 r[i] = c;
173 }
174
175 r[31] &= 127;
176 c = (c >> 7) * 19;
177
178 for (i = 0; i < F25519_SIZE; i++) {
179 c += r[i];
180 r[i] = c;
181 c >>= 8;
182 }
183 }
184
185 static void f25519_mul_c(uint8_t *r, const uint8_t *a, uint32_t b)
186 {
187 uint32_t c = 0;
188 int i;
189
190 for (i = 0; i < F25519_SIZE; i++) {
191 c >>= 8;
192 c += b * ((uint32_t)a[i]);
193 r[i] = c;
194 }
195
196 r[31] &= 127;
197 c >>= 7;
198 c *= 19;
199
200 for (i = 0; i < F25519_SIZE; i++) {
201 c += r[i];
202 r[i] = c;
203 c >>= 8;
204 }
205 }
206
207 void f25519_inv__distinct(uint8_t *r, const uint8_t *x)
208 {
209 uint8_t s[F25519_SIZE];
210 int i;
211
212 /* This is a prime field, so by Fermat's little theorem:
213 *
214 * x^(p-1) = 1 mod p
215 *
216 * Therefore, raise to (p-2) = 2^255-21 to get a multiplicative
217 * inverse.
218 *
219 * This is a 255-bit binary number with the digits:
220 *
221 * 11111111... 01011
222 *
223 * We compute the result by the usual binary chain, but
224 * alternate between keeping the accumulator in r and s, so as
225 * to avoid copying temporaries.
226 */
227
228 /* 1 1 */
229 f25519_mul__distinct(s, x, x);
230 f25519_mul__distinct(r, s, x);
231
232 /* 1 x 248 */
233 for (i = 0; i < 248; i++) {
234 f25519_mul__distinct(s, r, r);
235 f25519_mul__distinct(r, s, x);
236 }
237
238 /* 0 */
239 f25519_mul__distinct(s, r, r);
240
241 /* 1 */
242 f25519_mul__distinct(r, s, s);
243 f25519_mul__distinct(s, r, x);
244
245 /* 0 */
246 f25519_mul__distinct(r, s, s);
247
248 /* 1 */
249 f25519_mul__distinct(s, r, r);
250 f25519_mul__distinct(r, s, x);
251
252 /* 1 */
253 f25519_mul__distinct(s, r, r);
254 f25519_mul__distinct(r, s, x);
255 }
256
257 /* Raise x to the power of (p-5)/8 = 2^252-3, using s for temporary
258 * storage.
259 */
260 static void exp2523(uint8_t *r, const uint8_t *x, uint8_t *s)
261 {
262 int i;
263
264 /* This number is a 252-bit number with the binary expansion:
265 *
266 * 111111... 01
267 */
268
269 /* 1 1 */
270 f25519_mul__distinct(r, x, x);
271 f25519_mul__distinct(s, r, x);
272
273 /* 1 x 248 */
274 for (i = 0; i < 248; i++) {
275 f25519_mul__distinct(r, s, s);
276 f25519_mul__distinct(s, r, x);
277 }
278
279 /* 0 */
280 f25519_mul__distinct(r, s, s);
281
282 /* 1 */
283 f25519_mul__distinct(s, r, r);
284 f25519_mul__distinct(r, s, x);
285 }
286
287 void f25519_sqrt(uint8_t *r, const uint8_t *a)
288 {
289 uint8_t v[F25519_SIZE];
290 uint8_t i[F25519_SIZE];
291 uint8_t x[F25519_SIZE];
292 uint8_t y[F25519_SIZE];
293
294 /* v = (2a)^((p-5)/8) [x = 2a] */
295 f25519_mul_c(x, a, 2);
296 exp2523(v, x, y);
297
298 /* i = 2av^2 - 1 */
299 f25519_mul__distinct(y, v, v);
300 f25519_mul__distinct(i, x, y);
301 f25519_load(y, 1);
302 f25519_sub(i, i, y);
303
304 /* r = avi */
305 f25519_mul__distinct(x, v, a);
306 f25519_mul__distinct(r, x, i);
307 }