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