-
Notifications
You must be signed in to change notification settings - Fork 8
/
ed25519-sha512.c
324 lines (268 loc) · 6.43 KB
/
ed25519-sha512.c
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/*
* implementing ed25519-sha512 from [1].
*
* This code is public domain.
*
* Philipp Lay <[email protected]>
*
*
* References:
* [1] High-speed high-security signatures, 2011/09/26,
* Bernstein, Duif, Lange, Schwabe, Yang
*
* TODO:
* - batch verify
*/
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "eddsa.h"
#include "sha512.h"
#include "sc.h"
#include "fld.h"
#include "ed.h"
#include "burnstack.h"
static void
ed25519_key_setup(uint8_t out[SHA512_HASH_LENGTH],
const uint8_t sk[ED25519_KEY_LEN])
{
struct sha512 hash;
/* hash secret-key */
sha512_init(&hash);
sha512_add(&hash, sk, ED25519_KEY_LEN);
sha512_final(&hash, out);
/* delete bit 255 and set bit 254 */
out[31] &= 0x7f;
out[31] |= 0x40;
/* delete 3 lowest bits */
out[0] &= 0xf8;
}
/*
* genpub - derive public key from secret key
*/
static void
genpub(uint8_t pub[ED25519_KEY_LEN], const uint8_t sec[ED25519_KEY_LEN])
{
uint8_t h[SHA512_HASH_LENGTH];
struct ed A;
sc_t a;
/* derive secret and import it */
ed25519_key_setup(h, sec);
sc_import(a, h, 32);
/* multiply with base point to calculate public key */
ed_scale_base(&A, a);
ed_export(pub, &A);
}
/*
* ed25519_genpub - stack-clearing wrapper for genpub
*/
void
ed25519_genpub(uint8_t pub[ED25519_KEY_LEN], const uint8_t sec[ED25519_KEY_LEN])
{
genpub(pub, sec);
burnstack(2048);
}
/*
* sign - create ed25519 signature of data using secret key sec
*/
static void
sign(uint8_t sig[ED25519_SIG_LEN],
const uint8_t sec[ED25519_KEY_LEN],
const uint8_t pub[ED25519_KEY_LEN],
const uint8_t *data, size_t len)
{
struct sha512 hash;
uint8_t h[SHA512_HASH_LENGTH];
sc_t a, r, t, S;
struct ed R;
/* derive secret scalar a */
ed25519_key_setup(h, sec);
sc_import(a, h, 32);
/* hash next 32 bytes together with data to form r */
sha512_init(&hash);
sha512_add(&hash, h+32, 32);
sha512_add(&hash, data, len);
sha512_final(&hash, h);
sc_import(r, h, sizeof(h));
/* calculate R = r * B which form the first 256bit of the signature */
ed_scale_base(&R, r);
ed_export(sig, &R);
/* calculate t := Hash(export(R), export(A), data) mod m */
sha512_init(&hash);
sha512_add(&hash, sig, 32);
sha512_add(&hash, pub, 32);
sha512_add(&hash, data, len);
sha512_final(&hash, h);
sc_import(t, h, sizeof(h));
/* calculate S := r + t*a mod m and finish the signature */
sc_mul(S, t, a);
sc_add(S, r, S);
sc_export(sig+32, S);
}
/*
* ed25519_sign - stack-cleaning wrapper for sign
*/
void
ed25519_sign(uint8_t sig[ED25519_SIG_LEN],
const uint8_t sec[ED25519_KEY_LEN],
const uint8_t pub[ED25519_KEY_LEN],
const uint8_t *data, size_t len)
{
sign(sig, sec, pub, data, len);
burnstack(4096);
}
/*
* ed25519_verify - verifies an ed25519-signature of given data.
*
* note: this functions runs in vartime and does no stack cleanup, since
* all information are considered public.
*
* returns true if signature is ok and false otherwise.
*/
bool
ed25519_verify(const uint8_t sig[ED25519_SIG_LEN],
const uint8_t pub[ED25519_KEY_LEN],
const uint8_t *data, size_t len)
{
struct sha512 hash;
uint8_t h[SHA512_HASH_LENGTH];
struct ed A, C;
sc_t t, S;
uint8_t check[32];
/* import public key */
ed_import(&A, pub);
/* import S from second half of the signature */
sc_import(S, sig+32, 32);
/* calculate t := Hash(export(R), export(A), data) mod m */
sha512_init(&hash);
sha512_add(&hash, sig, 32);
sha512_add(&hash, pub, 32);
sha512_add(&hash, data, len);
sha512_final(&hash, h);
sc_import(t, h, 64);
/* verify signature (vartime!) */
fld_neg(A.x, A.x);
fld_neg(A.t, A.t);
ed_dual_scale(&C, S, t, &A);
ed_export(check, &C);
/* is export(C) == export(R) (vartime!) */
return (memcmp(check, sig, 32) == 0);
}
/*
* pk_ed25519_to_x25519 - convert a ed25519 public key to x25519
*/
void
pk_ed25519_to_x25519(uint8_t out[X25519_KEY_LEN], const uint8_t in[ED25519_KEY_LEN])
{
struct ed P;
fld_t u, t;
/* import ed25519 public key */
ed_import(&P, in);
/*
* We now have the point P = (x,y) on the curve
*
* x^2 + y^2 = 1 + (121665/121666)x^2y^2
*
* and want the u-component of the corresponding point
* on the birationally equivalent montgomery curve
*
* v^2 = u^3 + 486662 u^2 + u.
*
*
* From the paper [1] we get
*
* y = (u - 1) / (u + 1),
*
* which immediately yields
*
* u = (1 + y) / (1 - y)
*
* or, by using projective coordinantes,
*
* u = (z + y) / (z - y).
*/
/* u <- z + y */
fld_add(u, P.z, P.y);
/* t <- (z - y)^-1 */
fld_sub(t, P.z, P.y);
fld_inv(t, t);
/* u <- u * t = (z+y) / (z-y) */
fld_mul(u, u, t);
/* export curve25519 public key */
fld_export(out, u);
}
/*
* conv_sk_ed25519_to_x25519 - convert a ed25519 secret key to x25519 secret.
*/
static void
conv_sk_ed25519_to_x25519(uint8_t out[X25519_KEY_LEN], const uint8_t in[ED25519_KEY_LEN])
{
uint8_t h[SHA512_HASH_LENGTH];
ed25519_key_setup(h, in);
memcpy(out, h, X25519_KEY_LEN);
}
/*
* sk_ed25519_to_x25519 - stack-clearing wrapper for conv_sk_ed25519_to_x25519.
*/
void
sk_ed25519_to_x25519(uint8_t out[X25519_KEY_LEN], const uint8_t in[ED25519_KEY_LEN])
{
conv_sk_ed25519_to_x25519(out, in);
burnstack(1024);
}
/*
* Obsolete Interface, this will be removed in the future.
*/
/*
* eddsa_genpub - stack-clearing wrapper for genpub (obsolete interface!)
*/
void
eddsa_genpub(uint8_t pub[32], const uint8_t sec[32])
{
genpub(pub, sec);
burnstack(2048);
}
/*
* eddsa_sign - stack-cleaning wrapper for sign (obsolete interface!)
*/
void
eddsa_sign(uint8_t sig[ED25519_SIG_LEN],
const uint8_t sec[ED25519_KEY_LEN],
const uint8_t pub[ED25519_KEY_LEN],
const uint8_t *data, size_t len)
{
sign(sig, sec, pub, data, len);
burnstack(4096);
}
/*
* eddsa_verify - verifies an ed25519 signature of given data.
* (obsolete interface!)
*
*/
bool
eddsa_verify(const uint8_t sig[ED25519_SIG_LEN],
const uint8_t pub[ED25519_KEY_LEN],
const uint8_t *data, size_t len)
{
return ed25519_verify(sig, pub, data, len);
}
/*
* eddsa_pk_eddsa_to_dh - convert a ed25519 public key to x25519.
* (obsolete interface!)
*/
void
eddsa_pk_eddsa_to_dh(uint8_t out[X25519_KEY_LEN], const uint8_t in[ED25519_KEY_LEN])
{
pk_ed25519_to_x25519(out, in);
}
/*
* eddsa_sk_eddsa_to_dh - convert a ed25519 secret key to x25519 secret.
* (obsolete interface!)
*/
void
eddsa_sk_eddsa_to_dh(uint8_t out[X25519_KEY_LEN], const uint8_t in[ED25519_KEY_LEN])
{
conv_sk_ed25519_to_x25519(out, in);
burnstack(1024);
}