/*1* Copyright (C) 2017 - This file is part of libecc project2*3* Authors:4* Ryad BENADJILA <[email protected]>5* Arnaud EBALARD <[email protected]>6* Jean-Pierre FLORI <[email protected]>7*8* Contributors:9* Nicolas VIVET <[email protected]>10* Karim KHALFALLAH <[email protected]>11*12* This software is licensed under a dual BSD and GPL v2 license.13* See LICENSE file at the root folder of the project.14*/15#include <libecc/fp/fp.h>16#include <libecc/fp/fp_add.h>17#include <libecc/nn/nn_add.h>18#include <libecc/nn/nn_logical.h>19#include <libecc/nn/nn_mul_redc1.h>20/* Include the "internal" header as we use non public API here */21#include "../nn/nn_div.h"2223#define FP_CTX_MAGIC ((word_t)(0x114366fc34955125ULL))2425/*26* Verify given Fp context has been correctly initialized, by checking27* given pointer is valid and structure's magic has expected value.28* Returns 0 on success, -1 on error.29*/30int fp_ctx_check_initialized(fp_ctx_src_t ctx)31{32int ret = 0;3334MUST_HAVE(((ctx != NULL) && (ctx->magic == FP_CTX_MAGIC)), ret, err);3536err:37return ret;38}3940/*41* Initialize pointed Fp context structure from given parameters:42* - p: pointer to the prime defining Fp43* - p_bitlen: the bit length of p44* - r, r_square, mpinv: pointers to the Montgomery parameters r,45* (2^|p|) mod p), r^2 mod p and -p^-1 mod B (where B is the46* size in bits of words, as defined for the project, 16, 3247* or 64).48* - p_shift, p_normalized and p_reciprocal are precomputed49* division parameters (see ec_params_external.h for details).50*51* Returns 0 on success, -1 on error.52*/53int fp_ctx_init(fp_ctx_t ctx, nn_src_t p, bitcnt_t p_bitlen,54nn_src_t r, nn_src_t r_square,55word_t mpinv,56bitcnt_t p_shift, nn_src_t p_normalized, word_t p_reciprocal)57{58int ret;5960MUST_HAVE((ctx != NULL), ret, err);61ret = nn_check_initialized(p); EG(ret, err);62ret = nn_check_initialized(r); EG(ret, err);63ret = nn_check_initialized(r_square); EG(ret, err);64ret = nn_check_initialized(p_normalized); EG(ret, err);6566ret = nn_copy(&(ctx->p), p); EG(ret, err);67ctx->p_bitlen = p_bitlen;68ctx->mpinv = mpinv;69ctx->p_shift = p_shift;70ctx->p_reciprocal = p_reciprocal;71ret = nn_copy(&(ctx->p_normalized), p_normalized); EG(ret, err);72ret = nn_copy(&(ctx->r), r); EG(ret, err);73ret = nn_copy(&(ctx->r_square), r_square); EG(ret, err);74ctx->magic = FP_CTX_MAGIC;7576err:77return ret;78}7980/*81* Initialize pointed Fp context structure only from the prime p.82* The Montgomery related parameters are dynamically computed83* using our redc1 helpers from the NN layer. Returns 0 on success,84* -1 on error.85*/86int fp_ctx_init_from_p(fp_ctx_t ctx, nn_src_t p_in)87{88nn p, r, r_square, p_normalized;89word_t mpinv, p_shift, p_reciprocal;90bitcnt_t p_bitlen;91int ret;92p.magic = r.magic = r_square.magic = p_normalized.magic = WORD(0);9394MUST_HAVE((ctx != NULL), ret, err);95ret = nn_check_initialized(p_in); EG(ret, err);9697ret = nn_init(&p, 0); EG(ret, err);98ret = nn_copy(&p, p_in); EG(ret, err);99ret = nn_init(&r, 0); EG(ret, err);100ret = nn_init(&r_square, 0); EG(ret, err);101ret = nn_init(&p_normalized, 0); EG(ret, err);102103/*104* In order for our reciprocal division routines to work, it is105* expected that the bit length (including leading zeroes) of106* input prime p is >= 2 * wlen where wlen is the number of bits107* of a word size.108*/109if (p.wlen < 2) {110ret = nn_set_wlen(&p, 2); EG(ret, err);111}112113ret = nn_compute_redc1_coefs(&r, &r_square, &p, &mpinv); EG(ret, err);114ret = nn_compute_div_coefs(&p_normalized, &p_shift, &p_reciprocal, &p); EG(ret, err);115ret = nn_bitlen(p_in, &p_bitlen); EG(ret, err);116ret = fp_ctx_init(ctx, &p, p_bitlen, &r, &r_square,117mpinv, (bitcnt_t)p_shift, &p_normalized, p_reciprocal);118119err:120nn_uninit(&p);121nn_uninit(&r);122nn_uninit(&r_square);123nn_uninit(&p_normalized);124125return ret;126}127128#define FP_MAGIC ((word_t)(0x14e96c8ab28221efULL))129130/*131* Verify given Fp element has been correctly intialized, by checking132* given pointer is valid and structure magic has expected value.133* Returns 0 on success, -1 on error.134*/135int fp_check_initialized(fp_src_t in)136{137int ret = 0;138139MUST_HAVE(((in != NULL) && (in->magic == FP_MAGIC) && (in->ctx != NULL) && (in->ctx->magic == FP_CTX_MAGIC)), ret, err);140141err:142return ret;143}144145/*146* Initialilize pointed Fp element structure with given Fp context. Initial147* value of Fp element is set to 0.Returns 0 on success, -1 on error.148*/149int fp_init(fp_t in, fp_ctx_src_t fpctx)150{151int ret;152153MUST_HAVE((in != NULL), ret, err);154155ret = fp_ctx_check_initialized(fpctx); EG(ret, err);156ret = nn_init(&(in->fp_val), (u16)((fpctx->p.wlen) * WORD_BYTES)); EG(ret, err);157158in->ctx = fpctx;159in->magic = FP_MAGIC;160161err:162return ret;163}164165/*166* Same as above but providing the element an initial value given by 'buf'167* content (in big endian order) of size 'buflen'. Content of 'buf' must168* be less than p. Returns 0 on success, -1 on error.169*/170int fp_init_from_buf(fp_t in, fp_ctx_src_t fpctx, const u8 *buf, u16 buflen)171{172int ret;173174ret = fp_ctx_check_initialized(fpctx); EG(ret, err);175ret = fp_init(in, fpctx); EG(ret, err);176ret = fp_import_from_buf(in, buf, buflen);177178err:179return ret;180}181182/*183* Uninitialize pointed Fp element to prevent further use (magic field184* in the structure is zeroized) and zeroize associated storage space.185* Note that the Fp context pointed to by Fp element (passed during186* init) is left untouched.187*/188void fp_uninit(fp_t in)189{190if((in != NULL) && (in->magic == FP_MAGIC) && (in->ctx != NULL)){191nn_uninit(&in->fp_val);192193in->ctx = NULL;194in->magic = WORD(0);195}196197return;198}199200/*201* Set value of given Fp element to that of given nn. The value of202* given nn must be less than that of p, i.e. no reduction modulo203* p is performed by the function. Returns 0 on success, -1 on error.204*/205int fp_set_nn(fp_t out, nn_src_t in)206{207int ret, cmp;208209ret = fp_check_initialized(out); EG(ret, err);210ret = nn_check_initialized(in); EG(ret, err);211ret = nn_copy(&(out->fp_val), in); EG(ret, err);212ret = nn_cmp(&(out->fp_val), &(out->ctx->p), &cmp); EG(ret, err);213214MUST_HAVE((cmp < 0), ret, err);215216/* Set the wlen to the length of p */217ret = nn_set_wlen(&(out->fp_val), out->ctx->p.wlen);218219err:220return ret;221}222223/*224* Set 'out' to the element 0 of Fp (neutral element for addition). Returns 0225* on success, -1 on error.226*/227int fp_zero(fp_t out)228{229int ret;230231ret = fp_check_initialized(out); EG(ret, err);232ret = nn_set_word_value(&(out->fp_val), 0); EG(ret, err);233/* Set the wlen to the length of p */234ret = nn_set_wlen(&(out->fp_val), out->ctx->p.wlen);235236err:237return ret;238}239240/*241* Set out to the element 1 of Fp (neutral element for multiplication). Returns242* 0 on success, -1 on error.243*/244int fp_one(fp_t out)245{246int ret, isone;247word_t val;248249ret = fp_check_initialized(out); EG(ret, err);250/* One is indeed 1 except if p = 1 where it is 0 */251ret = nn_isone(&(out->ctx->p), &isone); EG(ret, err);252253val = isone ? WORD(0) : WORD(1);254255ret = nn_set_word_value(&(out->fp_val), val); EG(ret, err);256257/* Set the wlen to the length of p */258ret = nn_set_wlen(&(out->fp_val), out->ctx->p.wlen);259260err:261return ret;262}263264/* Set out to the asked word: the value must be < p */265int fp_set_word_value(fp_t out, word_t val)266{267int ret, cmp;268269ret = fp_check_initialized(out); EG(ret, err);270271/* Check that our value is indeed < p */272ret = nn_cmp_word(&(out->ctx->p), val, &cmp); EG(ret, err);273MUST_HAVE((cmp > 0), ret, err);274275/* Set the word in the NN layer */276ret = nn_set_word_value(&(out->fp_val), val); EG(ret, err);277278/* Set the wlen to the length of p */279ret = nn_set_wlen(&(out->fp_val), out->ctx->p.wlen);280281err:282return ret;283}284285286/*287* Compare given Fp elements. The function returns -1 if the value of in1 is288* less than that of in2, 0 if they are equal and 1 if the value of in2 is289* more than that of in1. Obviously, both parameters must be initialized and290* belong to the same field (i.e. must have been initialized from the same291* context). Returns 0 on success, -1 on error.292*/293int fp_cmp(fp_src_t in1, fp_src_t in2, int *cmp)294{295int ret;296297ret = fp_check_initialized(in1); EG(ret, err);298ret = fp_check_initialized(in2); EG(ret, err);299300MUST_HAVE((in1->ctx == in2->ctx), ret, err);301302ret = nn_cmp(&(in1->fp_val), &(in2->fp_val), cmp);303304err:305return ret;306}307308/* Check if given Fp element has value 0. Returns 0 on success, -1 on error. */309int fp_iszero(fp_src_t in, int *iszero)310{311int ret;312313ret = fp_check_initialized(in); EG(ret, err);314ret = nn_iszero(&(in->fp_val), iszero);315316err:317return ret;318}319320321/*322* Copy value of pointed Fp element (in) into pointed Fp element (out). If323* output is already initialized, check that the Fp contexts are consistent.324* Else, output is initialized with the same field context as input. Returns 0325* on success, -1 on error.326*327* Aliasing of input and output is supported.328*/329int fp_copy(fp_t out, fp_src_t in)330{331int ret;332333ret = fp_check_initialized(in); EG(ret, err);334335MUST_HAVE((out != NULL), ret, err);336337if ((out->magic == FP_MAGIC) && (out->ctx != NULL)) {338MUST_HAVE((out->ctx == in->ctx), ret, err);339} else {340ret = fp_init(out, in->ctx); EG(ret, err);341}342343ret = nn_copy(&(out->fp_val), &(in->fp_val));344345err:346return ret;347}348349350/*351* Given a table 'tab' pointing to a set of 'tabsize' Fp elements, the352* function copies the value of element at position idx (idx < tabsize)353* in 'out' parameters. Masking is used to avoid leaking which element354* was copied.355*356* Note that the main copying loop is done on the |p| bits for all357* Fp elements and not based on the specific effective size of each358* Fp elements in 'tab'359*360* Returns 0 on success, -1 on error.361*362* Aliasing of out and the selected element inside the tab is NOT supported.363*364*/365int fp_tabselect(fp_t out, u8 idx, fp_src_t *tab, u8 tabsize)366{367u8 i, k, p_wlen;368word_t mask;369nn_src_t p;370int ret;371372/* Basic sanity checks */373MUST_HAVE(((tab != NULL) && (idx < tabsize)), ret, err);374375ret = fp_check_initialized(out); EG(ret, err);376377/* Make things more readable */378p = &(out->ctx->p);379MUST_HAVE((p != NULL), ret, err);380p_wlen = p->wlen;381382/* Zeroize out and enforce its size. */383ret = nn_zero(&(out->fp_val)); EG(ret, err);384out->fp_val.wlen = p_wlen;385386for (k = 0; k < tabsize; k++) {387/* Check current element is initialized and from Fp */388ret = fp_check_initialized(tab[k]); EG(ret, err);389390MUST_HAVE(((&(tab[k]->ctx->p)) == p), ret, err);391392mask = WORD_MASK_IFNOTZERO(idx == k);393394for (i = 0; i < p_wlen; i++) {395out->fp_val.val[i] |= (tab[k]->fp_val.val[i] & mask);396}397}398399err:400return ret;401}402403/*404* The function tests if in1 and in2 parameters are equal or opposite in405* Fp. In that case, 'eq_or_opp' out parameter is set to 1. When in1 and406* in2 are not equal or opposite, 'eq_or_opp' is set to 0. The function407* returns 0 on success and -1 on error. 'eq_or_opp' is only meaningful408* on success, i.e. if the return value is 0.409*410* Aliasing of inputs is supported.411*/412int fp_eq_or_opp(fp_src_t in1, fp_src_t in2, int *eq_or_opp)413{414int ret, cmp_eq, cmp_opp;415fp opp;416opp.magic = WORD(0);417418MUST_HAVE((eq_or_opp != NULL), ret, err);419ret = fp_check_initialized(in1); EG(ret, err);420ret = fp_check_initialized(in2); EG(ret, err);421MUST_HAVE((in1->ctx == in2->ctx), ret, err);422423ret = fp_init(&opp, in1->ctx); EG(ret, err);424ret = fp_neg(&opp, in2); EG(ret, err);425ret = nn_cmp(&(in1->fp_val), &(in2->fp_val), &cmp_eq); EG(ret, err);426ret = nn_cmp(&(in1->fp_val), &(opp.fp_val), &cmp_opp); EG(ret, err);427428(*eq_or_opp) = ((cmp_eq == 0) | (cmp_opp == 0));429430err:431fp_uninit(&opp);432433return ret;434}435436/*437* Import given buffer of length buflen as a value for out_fp. Buffer is438* expected to be in big endian format. out_fp is expected to be already439* initialized w/ a proper Fp context, providing a value for p. The value440* in buf is also expected to be less than the one of p. The function441* returns 0 on success and -1 on error.442*/443int fp_import_from_buf(fp_t out_fp, const u8 *buf, u16 buflen)444{445int ret, cmp;446447ret = fp_check_initialized(out_fp); EG(ret, err);448ret = nn_init_from_buf(&(out_fp->fp_val), buf, buflen); EG(ret, err);449ret = nn_cmp(&(out_fp->fp_val), &(out_fp->ctx->p), &cmp); EG(ret, err);450MUST_HAVE((cmp < 0), ret, err);451452err:453return ret;454}455456/*457* Export an element from Fp to a buffer using the underlying NN export458* primitive. The function returns 0 on sucess, -1 on error.459*/460int fp_export_to_buf(u8 *buf, u16 buflen, fp_src_t in_fp)461{462int ret;463464ret = fp_check_initialized(in_fp); EG(ret, err);465ret = nn_export_to_buf(buf, buflen, &(in_fp->fp_val));466467err:468return ret;469}470471472