Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/libecc/src/fp/fp.c
34889 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/fp/fp.h>
17
#include <libecc/fp/fp_add.h>
18
#include <libecc/nn/nn_add.h>
19
#include <libecc/nn/nn_logical.h>
20
#include <libecc/nn/nn_mul_redc1.h>
21
/* Include the "internal" header as we use non public API here */
22
#include "../nn/nn_div.h"
23
24
#define FP_CTX_MAGIC ((word_t)(0x114366fc34955125ULL))
25
26
/*
27
* Verify given Fp context has been correctly initialized, by checking
28
* given pointer is valid and structure's magic has expected value.
29
* Returns 0 on success, -1 on error.
30
*/
31
int fp_ctx_check_initialized(fp_ctx_src_t ctx)
32
{
33
int ret = 0;
34
35
MUST_HAVE(((ctx != NULL) && (ctx->magic == FP_CTX_MAGIC)), ret, err);
36
37
err:
38
return ret;
39
}
40
41
/*
42
* Initialize pointed Fp context structure from given parameters:
43
* - p: pointer to the prime defining Fp
44
* - p_bitlen: the bit length of p
45
* - r, r_square, mpinv: pointers to the Montgomery parameters r,
46
* (2^|p|) mod p), r^2 mod p and -p^-1 mod B (where B is the
47
* size in bits of words, as defined for the project, 16, 32
48
* or 64).
49
* - p_shift, p_normalized and p_reciprocal are precomputed
50
* division parameters (see ec_params_external.h for details).
51
*
52
* Returns 0 on success, -1 on error.
53
*/
54
int fp_ctx_init(fp_ctx_t ctx, nn_src_t p, bitcnt_t p_bitlen,
55
nn_src_t r, nn_src_t r_square,
56
word_t mpinv,
57
bitcnt_t p_shift, nn_src_t p_normalized, word_t p_reciprocal)
58
{
59
int ret;
60
61
MUST_HAVE((ctx != NULL), ret, err);
62
ret = nn_check_initialized(p); EG(ret, err);
63
ret = nn_check_initialized(r); EG(ret, err);
64
ret = nn_check_initialized(r_square); EG(ret, err);
65
ret = nn_check_initialized(p_normalized); EG(ret, err);
66
67
ret = nn_copy(&(ctx->p), p); EG(ret, err);
68
ctx->p_bitlen = p_bitlen;
69
ctx->mpinv = mpinv;
70
ctx->p_shift = p_shift;
71
ctx->p_reciprocal = p_reciprocal;
72
ret = nn_copy(&(ctx->p_normalized), p_normalized); EG(ret, err);
73
ret = nn_copy(&(ctx->r), r); EG(ret, err);
74
ret = nn_copy(&(ctx->r_square), r_square); EG(ret, err);
75
ctx->magic = FP_CTX_MAGIC;
76
77
err:
78
return ret;
79
}
80
81
/*
82
* Initialize pointed Fp context structure only from the prime p.
83
* The Montgomery related parameters are dynamically computed
84
* using our redc1 helpers from the NN layer. Returns 0 on success,
85
* -1 on error.
86
*/
87
int fp_ctx_init_from_p(fp_ctx_t ctx, nn_src_t p_in)
88
{
89
nn p, r, r_square, p_normalized;
90
word_t mpinv, p_shift, p_reciprocal;
91
bitcnt_t p_bitlen;
92
int ret;
93
p.magic = r.magic = r_square.magic = p_normalized.magic = WORD(0);
94
95
MUST_HAVE((ctx != NULL), ret, err);
96
ret = nn_check_initialized(p_in); EG(ret, err);
97
98
ret = nn_init(&p, 0); EG(ret, err);
99
ret = nn_copy(&p, p_in); EG(ret, err);
100
ret = nn_init(&r, 0); EG(ret, err);
101
ret = nn_init(&r_square, 0); EG(ret, err);
102
ret = nn_init(&p_normalized, 0); EG(ret, err);
103
104
/*
105
* In order for our reciprocal division routines to work, it is
106
* expected that the bit length (including leading zeroes) of
107
* input prime p is >= 2 * wlen where wlen is the number of bits
108
* of a word size.
109
*/
110
if (p.wlen < 2) {
111
ret = nn_set_wlen(&p, 2); EG(ret, err);
112
}
113
114
ret = nn_compute_redc1_coefs(&r, &r_square, &p, &mpinv); EG(ret, err);
115
ret = nn_compute_div_coefs(&p_normalized, &p_shift, &p_reciprocal, &p); EG(ret, err);
116
ret = nn_bitlen(p_in, &p_bitlen); EG(ret, err);
117
ret = fp_ctx_init(ctx, &p, p_bitlen, &r, &r_square,
118
mpinv, (bitcnt_t)p_shift, &p_normalized, p_reciprocal);
119
120
err:
121
nn_uninit(&p);
122
nn_uninit(&r);
123
nn_uninit(&r_square);
124
nn_uninit(&p_normalized);
125
126
return ret;
127
}
128
129
#define FP_MAGIC ((word_t)(0x14e96c8ab28221efULL))
130
131
/*
132
* Verify given Fp element has been correctly intialized, by checking
133
* given pointer is valid and structure magic has expected value.
134
* Returns 0 on success, -1 on error.
135
*/
136
int fp_check_initialized(fp_src_t in)
137
{
138
int ret = 0;
139
140
MUST_HAVE(((in != NULL) && (in->magic == FP_MAGIC) && (in->ctx != NULL) && (in->ctx->magic == FP_CTX_MAGIC)), ret, err);
141
142
err:
143
return ret;
144
}
145
146
/*
147
* Initialilize pointed Fp element structure with given Fp context. Initial
148
* value of Fp element is set to 0.Returns 0 on success, -1 on error.
149
*/
150
int fp_init(fp_t in, fp_ctx_src_t fpctx)
151
{
152
int ret;
153
154
MUST_HAVE((in != NULL), ret, err);
155
156
ret = fp_ctx_check_initialized(fpctx); EG(ret, err);
157
ret = nn_init(&(in->fp_val), (u16)((fpctx->p.wlen) * WORD_BYTES)); EG(ret, err);
158
159
in->ctx = fpctx;
160
in->magic = FP_MAGIC;
161
162
err:
163
return ret;
164
}
165
166
/*
167
* Same as above but providing the element an initial value given by 'buf'
168
* content (in big endian order) of size 'buflen'. Content of 'buf' must
169
* be less than p. Returns 0 on success, -1 on error.
170
*/
171
int fp_init_from_buf(fp_t in, fp_ctx_src_t fpctx, const u8 *buf, u16 buflen)
172
{
173
int ret;
174
175
ret = fp_ctx_check_initialized(fpctx); EG(ret, err);
176
ret = fp_init(in, fpctx); EG(ret, err);
177
ret = fp_import_from_buf(in, buf, buflen);
178
179
err:
180
return ret;
181
}
182
183
/*
184
* Uninitialize pointed Fp element to prevent further use (magic field
185
* in the structure is zeroized) and zeroize associated storage space.
186
* Note that the Fp context pointed to by Fp element (passed during
187
* init) is left untouched.
188
*/
189
void fp_uninit(fp_t in)
190
{
191
if((in != NULL) && (in->magic == FP_MAGIC) && (in->ctx != NULL)){
192
nn_uninit(&in->fp_val);
193
194
in->ctx = NULL;
195
in->magic = WORD(0);
196
}
197
198
return;
199
}
200
201
/*
202
* Set value of given Fp element to that of given nn. The value of
203
* given nn must be less than that of p, i.e. no reduction modulo
204
* p is performed by the function. Returns 0 on success, -1 on error.
205
*/
206
int fp_set_nn(fp_t out, nn_src_t in)
207
{
208
int ret, cmp;
209
210
ret = fp_check_initialized(out); EG(ret, err);
211
ret = nn_check_initialized(in); EG(ret, err);
212
ret = nn_copy(&(out->fp_val), in); EG(ret, err);
213
ret = nn_cmp(&(out->fp_val), &(out->ctx->p), &cmp); EG(ret, err);
214
215
MUST_HAVE((cmp < 0), ret, err);
216
217
/* Set the wlen to the length of p */
218
ret = nn_set_wlen(&(out->fp_val), out->ctx->p.wlen);
219
220
err:
221
return ret;
222
}
223
224
/*
225
* Set 'out' to the element 0 of Fp (neutral element for addition). Returns 0
226
* on success, -1 on error.
227
*/
228
int fp_zero(fp_t out)
229
{
230
int ret;
231
232
ret = fp_check_initialized(out); EG(ret, err);
233
ret = nn_set_word_value(&(out->fp_val), 0); EG(ret, err);
234
/* Set the wlen to the length of p */
235
ret = nn_set_wlen(&(out->fp_val), out->ctx->p.wlen);
236
237
err:
238
return ret;
239
}
240
241
/*
242
* Set out to the element 1 of Fp (neutral element for multiplication). Returns
243
* 0 on success, -1 on error.
244
*/
245
int fp_one(fp_t out)
246
{
247
int ret, isone;
248
word_t val;
249
250
ret = fp_check_initialized(out); EG(ret, err);
251
/* One is indeed 1 except if p = 1 where it is 0 */
252
ret = nn_isone(&(out->ctx->p), &isone); EG(ret, err);
253
254
val = isone ? WORD(0) : WORD(1);
255
256
ret = nn_set_word_value(&(out->fp_val), val); EG(ret, err);
257
258
/* Set the wlen to the length of p */
259
ret = nn_set_wlen(&(out->fp_val), out->ctx->p.wlen);
260
261
err:
262
return ret;
263
}
264
265
/* Set out to the asked word: the value must be < p */
266
int fp_set_word_value(fp_t out, word_t val)
267
{
268
int ret, cmp;
269
270
ret = fp_check_initialized(out); EG(ret, err);
271
272
/* Check that our value is indeed < p */
273
ret = nn_cmp_word(&(out->ctx->p), val, &cmp); EG(ret, err);
274
MUST_HAVE((cmp > 0), ret, err);
275
276
/* Set the word in the NN layer */
277
ret = nn_set_word_value(&(out->fp_val), val); EG(ret, err);
278
279
/* Set the wlen to the length of p */
280
ret = nn_set_wlen(&(out->fp_val), out->ctx->p.wlen);
281
282
err:
283
return ret;
284
}
285
286
287
/*
288
* Compare given Fp elements. The function returns -1 if the value of in1 is
289
* less than that of in2, 0 if they are equal and 1 if the value of in2 is
290
* more than that of in1. Obviously, both parameters must be initialized and
291
* belong to the same field (i.e. must have been initialized from the same
292
* context). Returns 0 on success, -1 on error.
293
*/
294
int fp_cmp(fp_src_t in1, fp_src_t in2, int *cmp)
295
{
296
int ret;
297
298
ret = fp_check_initialized(in1); EG(ret, err);
299
ret = fp_check_initialized(in2); EG(ret, err);
300
301
MUST_HAVE((in1->ctx == in2->ctx), ret, err);
302
303
ret = nn_cmp(&(in1->fp_val), &(in2->fp_val), cmp);
304
305
err:
306
return ret;
307
}
308
309
/* Check if given Fp element has value 0. Returns 0 on success, -1 on error. */
310
int fp_iszero(fp_src_t in, int *iszero)
311
{
312
int ret;
313
314
ret = fp_check_initialized(in); EG(ret, err);
315
ret = nn_iszero(&(in->fp_val), iszero);
316
317
err:
318
return ret;
319
}
320
321
322
/*
323
* Copy value of pointed Fp element (in) into pointed Fp element (out). If
324
* output is already initialized, check that the Fp contexts are consistent.
325
* Else, output is initialized with the same field context as input. Returns 0
326
* on success, -1 on error.
327
*
328
* Aliasing of input and output is supported.
329
*/
330
int fp_copy(fp_t out, fp_src_t in)
331
{
332
int ret;
333
334
ret = fp_check_initialized(in); EG(ret, err);
335
336
MUST_HAVE((out != NULL), ret, err);
337
338
if ((out->magic == FP_MAGIC) && (out->ctx != NULL)) {
339
MUST_HAVE((out->ctx == in->ctx), ret, err);
340
} else {
341
ret = fp_init(out, in->ctx); EG(ret, err);
342
}
343
344
ret = nn_copy(&(out->fp_val), &(in->fp_val));
345
346
err:
347
return ret;
348
}
349
350
351
/*
352
* Given a table 'tab' pointing to a set of 'tabsize' Fp elements, the
353
* function copies the value of element at position idx (idx < tabsize)
354
* in 'out' parameters. Masking is used to avoid leaking which element
355
* was copied.
356
*
357
* Note that the main copying loop is done on the |p| bits for all
358
* Fp elements and not based on the specific effective size of each
359
* Fp elements in 'tab'
360
*
361
* Returns 0 on success, -1 on error.
362
*
363
* Aliasing of out and the selected element inside the tab is NOT supported.
364
*
365
*/
366
int fp_tabselect(fp_t out, u8 idx, fp_src_t *tab, u8 tabsize)
367
{
368
u8 i, k, p_wlen;
369
word_t mask;
370
nn_src_t p;
371
int ret;
372
373
/* Basic sanity checks */
374
MUST_HAVE(((tab != NULL) && (idx < tabsize)), ret, err);
375
376
ret = fp_check_initialized(out); EG(ret, err);
377
378
/* Make things more readable */
379
p = &(out->ctx->p);
380
MUST_HAVE((p != NULL), ret, err);
381
p_wlen = p->wlen;
382
383
/* Zeroize out and enforce its size. */
384
ret = nn_zero(&(out->fp_val)); EG(ret, err);
385
out->fp_val.wlen = p_wlen;
386
387
for (k = 0; k < tabsize; k++) {
388
/* Check current element is initialized and from Fp */
389
ret = fp_check_initialized(tab[k]); EG(ret, err);
390
391
MUST_HAVE(((&(tab[k]->ctx->p)) == p), ret, err);
392
393
mask = WORD_MASK_IFNOTZERO(idx == k);
394
395
for (i = 0; i < p_wlen; i++) {
396
out->fp_val.val[i] |= (tab[k]->fp_val.val[i] & mask);
397
}
398
}
399
400
err:
401
return ret;
402
}
403
404
/*
405
* The function tests if in1 and in2 parameters are equal or opposite in
406
* Fp. In that case, 'eq_or_opp' out parameter is set to 1. When in1 and
407
* in2 are not equal or opposite, 'eq_or_opp' is set to 0. The function
408
* returns 0 on success and -1 on error. 'eq_or_opp' is only meaningful
409
* on success, i.e. if the return value is 0.
410
*
411
* Aliasing of inputs is supported.
412
*/
413
int fp_eq_or_opp(fp_src_t in1, fp_src_t in2, int *eq_or_opp)
414
{
415
int ret, cmp_eq, cmp_opp;
416
fp opp;
417
opp.magic = WORD(0);
418
419
MUST_HAVE((eq_or_opp != NULL), ret, err);
420
ret = fp_check_initialized(in1); EG(ret, err);
421
ret = fp_check_initialized(in2); EG(ret, err);
422
MUST_HAVE((in1->ctx == in2->ctx), ret, err);
423
424
ret = fp_init(&opp, in1->ctx); EG(ret, err);
425
ret = fp_neg(&opp, in2); EG(ret, err);
426
ret = nn_cmp(&(in1->fp_val), &(in2->fp_val), &cmp_eq); EG(ret, err);
427
ret = nn_cmp(&(in1->fp_val), &(opp.fp_val), &cmp_opp); EG(ret, err);
428
429
(*eq_or_opp) = ((cmp_eq == 0) | (cmp_opp == 0));
430
431
err:
432
fp_uninit(&opp);
433
434
return ret;
435
}
436
437
/*
438
* Import given buffer of length buflen as a value for out_fp. Buffer is
439
* expected to be in big endian format. out_fp is expected to be already
440
* initialized w/ a proper Fp context, providing a value for p. The value
441
* in buf is also expected to be less than the one of p. The function
442
* returns 0 on success and -1 on error.
443
*/
444
int fp_import_from_buf(fp_t out_fp, const u8 *buf, u16 buflen)
445
{
446
int ret, cmp;
447
448
ret = fp_check_initialized(out_fp); EG(ret, err);
449
ret = nn_init_from_buf(&(out_fp->fp_val), buf, buflen); EG(ret, err);
450
ret = nn_cmp(&(out_fp->fp_val), &(out_fp->ctx->p), &cmp); EG(ret, err);
451
MUST_HAVE((cmp < 0), ret, err);
452
453
err:
454
return ret;
455
}
456
457
/*
458
* Export an element from Fp to a buffer using the underlying NN export
459
* primitive. The function returns 0 on sucess, -1 on error.
460
*/
461
int fp_export_to_buf(u8 *buf, u16 buflen, fp_src_t in_fp)
462
{
463
int ret;
464
465
ret = fp_check_initialized(in_fp); EG(ret, err);
466
ret = nn_export_to_buf(buf, buflen, &(in_fp->fp_val));
467
468
err:
469
return ret;
470
}
471
472