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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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. */ 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 */ 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 */ 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 */ 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 */ 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 */ 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