xref: /freebsd/crypto/libecc/src/fp/fp.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1 /*
2  *  Copyright (C) 2017 - This file is part of libecc project
3  *
4  *  Authors:
5  *      Ryad BENADJILA <ryadbenadjila@gmail.com>
6  *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7  *      Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8  *
9  *  Contributors:
10  *      Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11  *      Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
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  */
fp_ctx_check_initialized(fp_ctx_src_t ctx)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  */
fp_ctx_init(fp_ctx_t ctx,nn_src_t p,bitcnt_t p_bitlen,nn_src_t r,nn_src_t r_square,word_t mpinv,bitcnt_t p_shift,nn_src_t p_normalized,word_t p_reciprocal)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  */
fp_ctx_init_from_p(fp_ctx_t ctx,nn_src_t p_in)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  */
fp_check_initialized(fp_src_t in)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  */
fp_init(fp_t in,fp_ctx_src_t fpctx)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  */
fp_init_from_buf(fp_t in,fp_ctx_src_t fpctx,const u8 * buf,u16 buflen)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  */
fp_uninit(fp_t in)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  */
fp_set_nn(fp_t out,nn_src_t in)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  */
fp_zero(fp_t out)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  */
fp_one(fp_t out)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 */
fp_set_word_value(fp_t out,word_t val)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  */
fp_cmp(fp_src_t in1,fp_src_t in2,int * cmp)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. */
fp_iszero(fp_src_t in,int * iszero)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  */
fp_copy(fp_t out,fp_src_t in)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  */
fp_tabselect(fp_t out,u8 idx,fp_src_t * tab,u8 tabsize)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  */
fp_eq_or_opp(fp_src_t in1,fp_src_t in2,int * eq_or_opp)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  */
fp_import_from_buf(fp_t out_fp,const u8 * buf,u16 buflen)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  */
fp_export_to_buf(u8 * buf,u16 buflen,fp_src_t in_fp)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