Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/external/libecc/src/sig/ecrdsa.c
2066 views
1
/*
2
* Copyright (C) 2017 - This file is part of libecc project
3
*
4
* Authors:
5
* Ryad BENADJILA <[email protected]>
6
* Arnaud EBALARD <[email protected]>
7
* Jean-Pierre FLORI <[email protected]>
8
*
9
* Contributors:
10
* Nicolas VIVET <[email protected]>
11
* Karim KHALFALLAH <[email protected]>
12
*
13
* This software is licensed under a dual BSD and GPL v2 license.
14
* See LICENSE file at the root folder of the project.
15
*/
16
#include <libecc/lib_ecc_config.h>
17
#ifdef WITH_SIG_ECRDSA
18
19
#include <libecc/nn/nn_rand.h>
20
#include <libecc/nn/nn_mul_public.h>
21
#include <libecc/nn/nn_logical.h>
22
23
#include <libecc/sig/sig_algs_internal.h>
24
#include <libecc/sig/ec_key.h>
25
#ifdef VERBOSE_INNER_VALUES
26
#define EC_SIG_ALG "ECRDSA"
27
#endif
28
#include <libecc/utils/dbg_sig.h>
29
30
31
/*
32
* NOTE: ISO/IEC 14888-3 standard seems to diverge from the existing implementations
33
* of ECRDSA when treating the message hash, and from the examples of certificates provided
34
* in RFC 7091 and draft-deremin-rfc4491-bis. While in ISO/IEC 14888-3 it is explicitely asked
35
* to proceed with the hash of the message as big endian, the RFCs derived from the Russian
36
* standard expect the hash value to be treated as little endian when importing it as an integer
37
* (this discrepancy is exhibited and confirmed by test vectors present in ISO/IEC 14888-3, and
38
* by X.509 certificates present in the RFCs). This seems (to be confirmed) to be a discrepancy of
39
* ISO/IEC 14888-3 algorithm description that must be fixed there.
40
*
41
* In order to be conservative, libecc uses the Russian standard behavior as expected to be in line with
42
* other implemetations, but keeps the ISO/IEC 14888-3 behavior if forced/asked by the user using
43
* the USE_ISO14888_3_ECRDSA toggle. This allows to keep backward compatibility with previous versions of the
44
* library if needed.
45
*
46
*/
47
#ifndef USE_ISO14888_3_ECRDSA
48
/* Reverses the endiannes of a buffer in place */
49
ATTRIBUTE_WARN_UNUSED_RET static inline int _reverse_endianness(u8 *buf, u16 buf_size)
50
{
51
u16 i;
52
u8 tmp;
53
int ret;
54
55
MUST_HAVE((buf != NULL), ret, err);
56
57
if(buf_size > 1){
58
for(i = 0; i < (buf_size / 2); i++){
59
tmp = buf[i];
60
buf[i] = buf[buf_size - 1 - i];
61
buf[buf_size - 1 - i] = tmp;
62
}
63
}
64
65
ret = 0;
66
err:
67
return ret;
68
}
69
#endif
70
71
int ecrdsa_init_pub_key(ec_pub_key *out_pub, const ec_priv_key *in_priv)
72
{
73
int ret, cmp;
74
prj_pt_src_t G;
75
nn_src_t q;
76
77
MUST_HAVE((out_pub != NULL), ret, err);
78
79
/* Zero init public key to be generated */
80
ret = local_memset(out_pub, 0, sizeof(ec_pub_key)); EG(ret, err);
81
82
ret = priv_key_check_initialized_and_type(in_priv, ECRDSA); EG(ret, err);
83
q = &(in_priv->params->ec_gen_order);
84
85
/* Sanity check on key */
86
MUST_HAVE((!nn_cmp(&(in_priv->x), q, &cmp)) && (cmp < 0), ret, err);
87
88
/* Y = xG */
89
G = &(in_priv->params->ec_gen);
90
/* Use blinding when computing point scalar multiplication */
91
ret = prj_pt_mul_blind(&(out_pub->y), &(in_priv->x), G); EG(ret, err);
92
93
out_pub->key_type = ECRDSA;
94
out_pub->params = in_priv->params;
95
out_pub->magic = PUB_KEY_MAGIC;
96
97
err:
98
return ret;
99
}
100
101
int ecrdsa_siglen(u16 p_bit_len, u16 q_bit_len, u8 hsize, u8 blocksize, u8 *siglen)
102
{
103
int ret;
104
105
MUST_HAVE((siglen != NULL), ret, err);
106
MUST_HAVE((p_bit_len <= CURVES_MAX_P_BIT_LEN) &&
107
(q_bit_len <= CURVES_MAX_Q_BIT_LEN) &&
108
(hsize <= MAX_DIGEST_SIZE) && (blocksize <= MAX_BLOCK_SIZE), ret, err);
109
(*siglen) = (u8)ECRDSA_SIGLEN(q_bit_len);
110
ret = 0;
111
112
err:
113
return ret;
114
}
115
116
/*
117
* Generic *internal* EC-RDSA signature functions (init, update and finalize).
118
* Their purpose is to allow passing a specific hash function (along with
119
* its output size) and the random ephemeral key k, so that compliance
120
* tests against test vectors can be made without ugly hack in the code
121
* itself.
122
*
123
* Global EC-RDSA signature process is as follows (I,U,F provides
124
* information in which function(s) (init(), update() or finalize())
125
* a specific step is performed):
126
*
127
*| IUF - EC-RDSA signature
128
*|
129
*| UF 1. Compute h = H(m)
130
*| F 2. Get a random value k in ]0,q[
131
*| F 3. Compute W = (W_x,W_y) = kG
132
*| F 4. Compute r = W_x mod q
133
*| F 5. If r is 0, restart the process at step 2.
134
*| F 6. Compute e = OS2I(h) mod q. If e is 0, set e to 1.
135
*| NOTE: here, ISO/IEC 14888-3 and RFCs differ in the way e treated.
136
*| e = OS2I(h) for ISO/IEC 14888-3, or e = OS2I(reversed(h)) when endianness of h
137
*| is reversed for RFCs.
138
*| F 7. Compute s = (rx + ke) mod q
139
*| F 8. If s is 0, restart the process at step 2.
140
*| F 11. Return (r,s)
141
*
142
*/
143
144
#define ECRDSA_SIGN_MAGIC ((word_t)(0xcc97bbc8ada8973cULL))
145
#define ECRDSA_SIGN_CHECK_INITIALIZED(A, ret, err) \
146
MUST_HAVE((((void *)(A)) != NULL) && \
147
((A)->magic == ECRDSA_SIGN_MAGIC), ret, err)
148
149
int _ecrdsa_sign_init(struct ec_sign_context *ctx)
150
{
151
int ret;
152
153
/* First, verify context has been initialized */
154
ret = sig_sign_check_initialized(ctx); EG(ret, err);
155
156
/* Additional sanity checks on input params from context */
157
ret = key_pair_check_initialized_and_type(ctx->key_pair, ECRDSA); EG(ret, err);
158
MUST_HAVE((ctx->h != NULL) && (ctx->h->digest_size <= MAX_DIGEST_SIZE) &&
159
(ctx->h->block_size <= MAX_BLOCK_SIZE), ret, err);
160
161
/*
162
* Initialize hash context stored in our private part of context
163
* and record data init has been done
164
*/
165
/* Since we call a callback, sanity check our mapping */
166
ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err);
167
ret = ctx->h->hfunc_init(&(ctx->sign_data.ecrdsa.h_ctx)); EG(ret, err);
168
169
ctx->sign_data.ecrdsa.magic = ECRDSA_SIGN_MAGIC;
170
171
err:
172
return ret;
173
}
174
175
int _ecrdsa_sign_update(struct ec_sign_context *ctx,
176
const u8 *chunk, u32 chunklen)
177
{
178
int ret;
179
/*
180
* First, verify context has been initialized and private
181
* part too. This guarantees the context is an EC-RDSA
182
* signature one and we do not update() or finalize()
183
* before init().
184
*/
185
ret = sig_sign_check_initialized(ctx); EG(ret, err);
186
ECRDSA_SIGN_CHECK_INITIALIZED(&(ctx->sign_data.ecrdsa), ret, err);
187
188
/* Since we call a callback, sanity check our mapping */
189
ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err);
190
ret = ctx->h->hfunc_update(&(ctx->sign_data.ecrdsa.h_ctx), chunk, chunklen);
191
192
err:
193
return ret;
194
}
195
196
int _ecrdsa_sign_finalize(struct ec_sign_context *ctx, u8 *sig, u8 siglen)
197
{
198
bitcnt_t q_bit_len, p_bit_len;
199
const ec_priv_key *priv_key;
200
u8 h_buf[MAX_DIGEST_SIZE];
201
prj_pt_src_t G;
202
prj_pt kG;
203
nn_src_t q, x;
204
u8 hsize, r_len, s_len;
205
int ret, iszero, cmp;
206
nn s, rx, ke, k, r, e;
207
#ifdef USE_SIG_BLINDING
208
/* b is the blinding mask */
209
nn b, binv;
210
b.magic = binv.magic = WORD(0);
211
#endif /* USE_SIG_BLINDING */
212
213
kG.magic = WORD(0);
214
s.magic = rx.magic = ke.magic = WORD(0);
215
k.magic = r.magic = e.magic = WORD(0);
216
217
/*
218
* First, verify context has been initialized and private
219
* part too. This guarantees the context is an EC-RDSA
220
* signature one and we do not finalize() before init().
221
*/
222
ret = sig_sign_check_initialized(ctx); EG(ret, err);
223
ECRDSA_SIGN_CHECK_INITIALIZED(&(ctx->sign_data.ecrdsa), ret, err);
224
225
/* Zero init points */
226
ret = local_memset(&kG, 0, sizeof(prj_pt)); EG(ret, err);
227
228
/* Make things more readable */
229
priv_key = &(ctx->key_pair->priv_key);
230
G = &(priv_key->params->ec_gen);
231
q = &(priv_key->params->ec_gen_order);
232
p_bit_len = priv_key->params->ec_fp.p_bitlen;
233
q_bit_len = priv_key->params->ec_gen_order_bitlen;
234
x = &(priv_key->x);
235
r_len = (u8)ECRDSA_R_LEN(q_bit_len);
236
s_len = (u8)ECRDSA_S_LEN(q_bit_len);
237
hsize = ctx->h->digest_size;
238
239
/* Sanity check */
240
ret = nn_cmp(x, q, &cmp); EG(ret, err);
241
/* This should not happen and means that our
242
* private key is not compliant!
243
*/
244
MUST_HAVE((cmp < 0) && (p_bit_len <= NN_MAX_BIT_LEN) && (siglen == ECRDSA_SIGLEN(q_bit_len)), ret, err);
245
246
dbg_nn_print("p", &(priv_key->params->ec_fp.p));
247
dbg_nn_print("q", q);
248
dbg_priv_key_print("x", priv_key);
249
dbg_pub_key_print("Y", &(ctx->key_pair->pub_key));
250
dbg_ec_point_print("G", G);
251
252
restart:
253
/* 2. Get a random value k in ]0, q[ ... */
254
#ifdef NO_KNOWN_VECTORS
255
/* NOTE: when we do not need self tests for known vectors,
256
* we can be strict about random function handler!
257
* This allows us to avoid the corruption of such a pointer.
258
*/
259
/* Sanity check on the handler before calling it */
260
MUST_HAVE((ctx->rand == nn_get_random_mod), ret, err);
261
#endif
262
MUST_HAVE((ctx->rand != NULL), ret, err);
263
ret = ctx->rand(&k, q); EG(ret, err);
264
265
dbg_nn_print("k", &k);
266
#ifdef USE_SIG_BLINDING
267
/* Note: if we use blinding, k and e are multiplied by
268
* a random value b in ]0,q[ */
269
ret = nn_get_random_mod(&b, q); EG(ret, err);
270
dbg_nn_print("b", &b);
271
#endif /* USE_SIG_BLINDING */
272
273
/* 3. Compute W = kG = (Wx, Wy) */
274
#ifdef USE_SIG_BLINDING
275
/* We use blinding for the scalar multiplication */
276
ret = prj_pt_mul_blind(&kG, &k, G); EG(ret, err);
277
#else
278
ret = prj_pt_mul(&kG, &k, G); EG(ret, err);
279
#endif /* USE_SIG_BLINDING */
280
ret = prj_pt_unique(&kG, &kG); EG(ret, err);
281
dbg_nn_print("W_x", &(kG.X.fp_val));
282
dbg_nn_print("W_y", &(kG.Y.fp_val));
283
284
/* 4. Compute r = Wx mod q */
285
ret = nn_mod(&r, &(kG.X.fp_val), q); EG(ret, err);
286
287
/* 5. If r is 0, restart the process at step 2. */
288
ret = nn_iszero(&r, &iszero); EG(ret, err);
289
if (iszero) {
290
goto restart;
291
}
292
dbg_nn_print("r", &r);
293
294
/* Export r */
295
ret = nn_export_to_buf(sig, r_len, &r); EG(ret, err);
296
297
/* 6. Compute e = OS2I(h) mod q. If e is 0, set e to 1. */
298
ret = local_memset(h_buf, 0, hsize); EG(ret, err);
299
/* Since we call a callback, sanity check our mapping */
300
ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err);
301
ret = ctx->h->hfunc_finalize(&(ctx->sign_data.ecrdsa.h_ctx), h_buf); EG(ret, err);
302
dbg_buf_print("H(m)", h_buf, hsize);
303
/* NOTE: this handles a discrepancy between ISO/IEC 14888-3 and
304
* Russian standard based RFCs.
305
*/
306
#ifndef USE_ISO14888_3_ECRDSA
307
ret = _reverse_endianness(h_buf, hsize); EG(ret, err);
308
#endif
309
ret = nn_init_from_buf(&e, h_buf, hsize); EG(ret, err);
310
ret = local_memset(h_buf, 0, hsize); EG(ret, err);
311
ret = nn_mod(&e, &e, q); EG(ret, err);
312
ret = nn_iszero(&e, &iszero); EG(ret, err);
313
if (iszero) {
314
ret = nn_inc(&e, &e); EG(ret, err);
315
}
316
dbg_nn_print("e", &e);
317
318
#ifdef USE_SIG_BLINDING
319
/* In case of blinding, we blind r and e */
320
ret = nn_mod_mul(&r, &r, &b, q); EG(ret, err);
321
ret = nn_mod_mul(&e, &e, &b, q); EG(ret, err);
322
#endif /* USE_SIG_BLINDING */
323
324
/* Compute s = (rx + ke) mod q */
325
ret = nn_mod_mul(&rx, &r, x, q); EG(ret, err);
326
ret = nn_mod_mul(&ke, &k, &e, q); EG(ret, err);
327
ret = nn_mod_add(&s, &rx, &ke, q); EG(ret, err);
328
#ifdef USE_SIG_BLINDING
329
/* Unblind s */
330
/* NOTE: we use Fermat's little theorem inversion for
331
* constant time here. This is possible since q is prime.
332
*/
333
ret = nn_modinv_fermat(&binv, &b, q); EG(ret, err);
334
ret = nn_mod_mul(&s, &s, &binv, q); EG(ret, err);
335
#endif /* USE_SIG_BLINDING */
336
337
/* If s is 0, restart the process at step 2. */
338
ret = nn_iszero(&s, &iszero); EG(ret, err);
339
if (iszero) {
340
goto restart;
341
}
342
343
dbg_nn_print("s", &s);
344
345
/* Return (r,s) */
346
ret = nn_export_to_buf(sig + r_len, s_len, &s);
347
348
err:
349
prj_pt_uninit(&kG);
350
nn_uninit(&r);
351
nn_uninit(&s);
352
nn_uninit(&s);
353
nn_uninit(&rx);
354
nn_uninit(&ke);
355
nn_uninit(&k);
356
nn_uninit(&r);
357
nn_uninit(&e);
358
#ifdef USE_SIG_BLINDING
359
nn_uninit(&b);
360
nn_uninit(&binv);
361
#endif
362
363
/*
364
* We can now clear data part of the context. This will clear
365
* magic and avoid further reuse of the whole context.
366
*/
367
if(ctx != NULL){
368
IGNORE_RET_VAL(local_memset(&(ctx->sign_data.ecrdsa), 0, sizeof(ecrdsa_sign_data)));
369
}
370
371
/* Clean what remains on the stack */
372
VAR_ZEROIFY(r_len);
373
VAR_ZEROIFY(s_len);
374
VAR_ZEROIFY(q_bit_len);
375
VAR_ZEROIFY(p_bit_len);
376
VAR_ZEROIFY(hsize);
377
PTR_NULLIFY(priv_key);
378
PTR_NULLIFY(G);
379
PTR_NULLIFY(q);
380
PTR_NULLIFY(x);
381
382
return ret;
383
}
384
385
#define ECRDSA_VERIFY_MAGIC ((word_t)(0xa8e16b7e8180cb9aULL))
386
#define ECRDSA_VERIFY_CHECK_INITIALIZED(A, ret, err) \
387
MUST_HAVE((((void *)(A)) != NULL) && \
388
((A)->magic == ECRDSA_VERIFY_MAGIC), ret, err)
389
390
/*
391
* Generic *internal* EC-RDSA verification functions (init, update and finalize).
392
* Their purpose is to allow passing a specific hash function (along with
393
* their output size) and the random ephemeral key k, so that compliance
394
* tests against test vectors can be made without ugly hack in the code
395
* itself.
396
*
397
* Global EC-RDSA verification process is as follows (I,U,F provides
398
* information in which function(s) (init(), update() or finalize())
399
* a specific step is performed):
400
*
401
*| IUF - EC-RDSA verification
402
*|
403
*| UF 1. Check that r and s are both in ]0,q[
404
*| F 2. Compute h = H(m)
405
*| F 3. Compute e = OS2I(h)^-1 mod q
406
*| NOTE: here, ISO/IEC 14888-3 and RFCs differ in the way e treated.
407
*| e = OS2I(h) for ISO/IEC 14888-3, or e = OS2I(reversed(h)) when endianness of h
408
*| is reversed for RFCs.
409
*| F 4. Compute u = es mod q
410
*| F 5. Compute v = -er mod q
411
*| F 6. Compute W' = uG + vY = (W'_x, W'_y)
412
*| F 7. Compute r' = W'_x mod q
413
*| F 8. Check r and r' are the same
414
*
415
*/
416
417
int _ecrdsa_verify_init(struct ec_verify_context *ctx,
418
const u8 *sig, u8 siglen)
419
{
420
bitcnt_t q_bit_len;
421
u8 r_len, s_len;
422
nn_src_t q;
423
nn s, r;
424
int ret, iszero1, iszero2, cmp1, cmp2;
425
s.magic = r.magic = WORD(0);
426
427
/* First, verify context has been initialized */
428
ret = sig_verify_check_initialized(ctx); EG(ret, err);
429
430
/* Do some sanity checks on input params */
431
ret = pub_key_check_initialized_and_type(ctx->pub_key, ECRDSA); EG(ret, err);
432
MUST_HAVE((ctx->h != NULL) && (ctx->h->digest_size <= MAX_DIGEST_SIZE) &&
433
(ctx->h->block_size <= MAX_BLOCK_SIZE), ret, err);
434
435
/* Make things more readable */
436
q = &(ctx->pub_key->params->ec_gen_order);
437
q_bit_len = ctx->pub_key->params->ec_gen_order_bitlen;
438
r_len = (u8)ECRDSA_R_LEN(q_bit_len);
439
s_len = (u8)ECRDSA_S_LEN(q_bit_len);
440
441
MUST_HAVE(siglen == ECRDSA_SIGLEN(q_bit_len), ret, err);
442
443
/* 1. Check that r and s are both in ]0,q[ */
444
ret = nn_init_from_buf(&r, sig, r_len); EG(ret, err);
445
ret = nn_init_from_buf(&s, sig + r_len, s_len); EG(ret, err);
446
ret = nn_iszero(&s, &iszero1); EG(ret, err);
447
ret = nn_iszero(&r, &iszero2); EG(ret, err);
448
ret = nn_cmp(&s, q, &cmp1); EG(ret, err);
449
ret = nn_cmp(&s, q, &cmp2); EG(ret, err);
450
MUST_HAVE((!iszero1) && (cmp1 < 0) && (!iszero2) && (cmp2 < 0), ret, err);
451
452
/* Initialize the remaining of verify context. */
453
ret = nn_copy(&(ctx->verify_data.ecrdsa.r), &r); EG(ret, err);
454
ret = nn_copy(&(ctx->verify_data.ecrdsa.s), &s); EG(ret, err);
455
/* Since we call a callback, sanity check our mapping */
456
ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err);
457
ret = ctx->h->hfunc_init(&(ctx->verify_data.ecrdsa.h_ctx)); EG(ret, err);
458
459
ctx->verify_data.ecrdsa.magic = ECRDSA_VERIFY_MAGIC;
460
461
err:
462
nn_uninit(&s);
463
nn_uninit(&r);
464
465
/* Clean what remains on the stack */
466
VAR_ZEROIFY(q_bit_len);
467
VAR_ZEROIFY(r_len);
468
VAR_ZEROIFY(s_len);
469
PTR_NULLIFY(q);
470
471
return ret;
472
}
473
474
int _ecrdsa_verify_update(struct ec_verify_context *ctx,
475
const u8 *chunk, u32 chunklen)
476
{
477
int ret;
478
479
/*
480
* First, verify context has been initialized and public
481
* part too. This guarantees the context is an EC-RDSA
482
* verification one and we do not update() or finalize()
483
* before init().
484
*/
485
ret = sig_verify_check_initialized(ctx); EG(ret, err);
486
ECRDSA_VERIFY_CHECK_INITIALIZED(&(ctx->verify_data.ecrdsa), ret, err);
487
488
/* 2. Compute h = H(m) */
489
/* Since we call a callback, sanity check our mapping */
490
ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err);
491
ret = ctx->h->hfunc_update(&(ctx->verify_data.ecrdsa.h_ctx), chunk,
492
chunklen);
493
494
err:
495
return ret;
496
}
497
498
int _ecrdsa_verify_finalize(struct ec_verify_context *ctx)
499
{
500
prj_pt_src_t G, Y;
501
nn_src_t q;
502
nn h, r_prime, e, v, u;
503
prj_pt vY, uG;
504
prj_pt_t Wprime;
505
u8 h_buf[MAX_DIGEST_SIZE];
506
nn *r, *s;
507
u8 hsize;
508
int ret, iszero, cmp;
509
510
h.magic = r_prime.magic = e.magic = v.magic = u.magic = WORD(0);
511
vY.magic = uG.magic = WORD(0);
512
513
/* NOTE: we reuse uG for Wprime to optimize local variables */
514
Wprime = &uG;
515
516
/*
517
* First, verify context has been initialized and public
518
* part too. This guarantees the context is an EC-RDSA
519
* verification one and we do not finalize() before init().
520
*/
521
ret = sig_verify_check_initialized(ctx); EG(ret, err);
522
ECRDSA_VERIFY_CHECK_INITIALIZED(&(ctx->verify_data.ecrdsa), ret, err);
523
524
/* Zero init points */
525
ret = local_memset(&uG, 0, sizeof(prj_pt)); EG(ret, err);
526
ret = local_memset(&vY, 0, sizeof(prj_pt)); EG(ret, err);
527
528
/* Make things more readable */
529
G = &(ctx->pub_key->params->ec_gen);
530
Y = &(ctx->pub_key->y);
531
q = &(ctx->pub_key->params->ec_gen_order);
532
r = &(ctx->verify_data.ecrdsa.r);
533
s = &(ctx->verify_data.ecrdsa.s);
534
hsize = ctx->h->digest_size;
535
536
/* 2. Compute h = H(m) */
537
ret = local_memset(h_buf, 0, hsize); EG(ret, err);
538
/* Since we call a callback, sanity check our mapping */
539
ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err);
540
ret = ctx->h->hfunc_finalize(&(ctx->verify_data.ecrdsa.h_ctx), h_buf); EG(ret, err);
541
dbg_buf_print("H(m)", h_buf, hsize);
542
/* NOTE: this handles a discrepancy between ISO/IEC 14888-3 and
543
* Russian standard based RFCs.
544
*/
545
#ifndef USE_ISO14888_3_ECRDSA
546
ret = _reverse_endianness(h_buf, hsize); EG(ret, err);
547
#endif
548
549
/* 3. Compute e = OS2I(h)^-1 mod q */
550
ret = nn_init_from_buf(&h, h_buf, hsize); EG(ret, err);
551
ret = local_memset(h_buf, 0, hsize); EG(ret, err);
552
ret = nn_mod(&h, &h, q); EG(ret, err); /* h = OS2I(h) mod q */
553
ret = nn_iszero(&h, &iszero); EG(ret, err);
554
if (iszero) { /* If h is equal to 0, set it to 1 */
555
ret = nn_inc(&h, &h); EG(ret, err);
556
}
557
ret = nn_modinv(&e, &h, q); EG(ret, err); /* e = h^-1 mod q */
558
559
/* 4. Compute u = es mod q */
560
ret = nn_mod_mul(&u, &e, s, q); EG(ret, err);
561
562
/* 5. Compute v = -er mod q
563
*
564
* Because we only support positive integers, we compute
565
* v = -er mod q = q - (er mod q) (except when er is 0).
566
* NOTE: we reuse e for er computation to avoid losing
567
* a variable.
568
*/
569
ret = nn_mod_mul(&e, &e, r, q); EG(ret, err);
570
ret = nn_mod_neg(&v, &e, q); EG(ret, err);
571
572
/* 6. Compute W' = uG + vY = (W'_x, W'_y) */
573
ret = prj_pt_mul(&uG, &u, G); EG(ret, err);
574
ret = prj_pt_mul(&vY, &v, Y); EG(ret, err);
575
ret = prj_pt_add(Wprime, &uG, &vY); EG(ret, err);
576
ret = prj_pt_unique(Wprime, Wprime); EG(ret, err);
577
dbg_nn_print("W'_x", &(Wprime->X.fp_val));
578
dbg_nn_print("W'_y", &(Wprime->Y.fp_val));
579
580
/* 7. Compute r' = W'_x mod q */
581
ret = nn_mod(&r_prime, &(Wprime->X.fp_val), q); EG(ret, err);
582
583
/* 8. Check r and r' are the same */
584
ret = nn_cmp(r, &r_prime, &cmp); EG(ret, err);
585
ret = (cmp == 0) ? 0 : -1;
586
587
err:
588
nn_uninit(&h);
589
nn_uninit(&r_prime);
590
nn_uninit(&e);
591
nn_uninit(&v);
592
nn_uninit(&u);
593
prj_pt_uninit(&vY);
594
prj_pt_uninit(&uG);
595
596
/*
597
* We can now clear data part of the context. This will clear
598
* magic and avoid further reuse of the whole context.
599
*/
600
if(ctx != NULL){
601
IGNORE_RET_VAL(local_memset(&(ctx->verify_data.ecrdsa), 0,
602
sizeof(ecrdsa_verify_data)));
603
}
604
605
/* Clean what remains on the stack */
606
PTR_NULLIFY(Wprime);
607
PTR_NULLIFY(G);
608
PTR_NULLIFY(Y);
609
PTR_NULLIFY(q);
610
PTR_NULLIFY(r);
611
PTR_NULLIFY(s);
612
VAR_ZEROIFY(hsize);
613
614
return ret;
615
}
616
617
#else /* WITH_SIG_ECRDSA */
618
619
/*
620
* Dummy definition to avoid the empty translation unit ISO C warning
621
*/
622
typedef int dummy;
623
#endif /* WITH_SIG_ECRDSA */
624
625