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