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_mul.h> 17*f0865ec9SKyle Evans #include <libecc/fp/fp_pow.h> 18*f0865ec9SKyle Evans #include <libecc/nn/nn_add.h> 19*f0865ec9SKyle Evans #include <libecc/nn/nn_mul_public.h> 20*f0865ec9SKyle Evans #include <libecc/nn/nn_modinv.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 /* 25*f0865ec9SKyle Evans * Compute out = in1 * in2 mod p. 'out' parameter must have been initialized 26*f0865ec9SKyle Evans * by the caller. Returns 0 on success, -1 on error. 27*f0865ec9SKyle Evans * 28*f0865ec9SKyle Evans * Aliasing is supported. 29*f0865ec9SKyle Evans */ 30*f0865ec9SKyle Evans int fp_mul(fp_t out, fp_src_t in1, fp_src_t in2) 31*f0865ec9SKyle Evans { 32*f0865ec9SKyle Evans int ret; 33*f0865ec9SKyle Evans 34*f0865ec9SKyle Evans ret = fp_check_initialized(in1); EG(ret, err); 35*f0865ec9SKyle Evans ret = fp_check_initialized(in2); EG(ret, err); 36*f0865ec9SKyle Evans ret = fp_check_initialized(out); EG(ret, err); 37*f0865ec9SKyle Evans 38*f0865ec9SKyle Evans MUST_HAVE(out->ctx == in1->ctx, ret, err); 39*f0865ec9SKyle Evans MUST_HAVE(out->ctx == in2->ctx, ret, err); 40*f0865ec9SKyle Evans 41*f0865ec9SKyle Evans ret = nn_mul(&(out->fp_val), &(in1->fp_val), &(in2->fp_val)); EG(ret, err); 42*f0865ec9SKyle Evans ret = nn_mod_unshifted(&(out->fp_val), &(out->fp_val), &(in1->ctx->p_normalized), 43*f0865ec9SKyle Evans in1->ctx->p_reciprocal, in1->ctx->p_shift); 44*f0865ec9SKyle Evans 45*f0865ec9SKyle Evans err: 46*f0865ec9SKyle Evans return ret; 47*f0865ec9SKyle Evans } 48*f0865ec9SKyle Evans 49*f0865ec9SKyle Evans /* 50*f0865ec9SKyle Evans * Compute out = in * in mod p. 'out' parameter must have been initialized 51*f0865ec9SKyle Evans * by the caller. Returns 0 on success, -1 on error. 52*f0865ec9SKyle Evans * 53*f0865ec9SKyle Evans * Aliasing is supported. 54*f0865ec9SKyle Evans */ 55*f0865ec9SKyle Evans int fp_sqr(fp_t out, fp_src_t in) 56*f0865ec9SKyle Evans { 57*f0865ec9SKyle Evans return fp_mul(out, in, in); 58*f0865ec9SKyle Evans } 59*f0865ec9SKyle Evans 60*f0865ec9SKyle Evans /* We use Fermat's little theorem for our inversion in Fp: 61*f0865ec9SKyle Evans * x^(p-1) = 1 mod (p) means that x^(p-2) mod(p) is the modular 62*f0865ec9SKyle Evans * inverse of x mod (p) 63*f0865ec9SKyle Evans * 64*f0865ec9SKyle Evans * Aliasing is supported. 65*f0865ec9SKyle Evans */ 66*f0865ec9SKyle Evans int fp_inv(fp_t out, fp_src_t in) 67*f0865ec9SKyle Evans { 68*f0865ec9SKyle Evans /* Use our lower layer Fermat modular inversion with precomputed 69*f0865ec9SKyle Evans * Montgomery coefficients. 70*f0865ec9SKyle Evans */ 71*f0865ec9SKyle Evans int ret; 72*f0865ec9SKyle Evans 73*f0865ec9SKyle Evans ret = fp_check_initialized(in); EG(ret, err); 74*f0865ec9SKyle Evans ret = fp_check_initialized(out); EG(ret, err); 75*f0865ec9SKyle Evans 76*f0865ec9SKyle Evans MUST_HAVE(out->ctx == in->ctx, ret, err); 77*f0865ec9SKyle Evans 78*f0865ec9SKyle Evans /* We can use the Fermat inversion as p is surely prime here */ 79*f0865ec9SKyle Evans ret = nn_modinv_fermat_redc(&(out->fp_val), &(in->fp_val), &(in->ctx->p), &(in->ctx->r), &(in->ctx->r_square), in->ctx->mpinv); 80*f0865ec9SKyle Evans 81*f0865ec9SKyle Evans err: 82*f0865ec9SKyle Evans return ret; 83*f0865ec9SKyle Evans } 84*f0865ec9SKyle Evans 85*f0865ec9SKyle Evans /* 86*f0865ec9SKyle Evans * Compute out = w^-1 mod p. 'out' parameter must have been initialized 87*f0865ec9SKyle Evans * by the caller. Returns 0 on success, -1 on error. 88*f0865ec9SKyle Evans */ 89*f0865ec9SKyle Evans int fp_inv_word(fp_t out, word_t w) 90*f0865ec9SKyle Evans { 91*f0865ec9SKyle Evans int ret; 92*f0865ec9SKyle Evans 93*f0865ec9SKyle Evans ret = fp_check_initialized(out); EG(ret, err); 94*f0865ec9SKyle Evans 95*f0865ec9SKyle Evans ret = nn_modinv_word(&(out->fp_val), w, &(out->ctx->p)); 96*f0865ec9SKyle Evans 97*f0865ec9SKyle Evans err: 98*f0865ec9SKyle Evans return ret; 99*f0865ec9SKyle Evans } 100*f0865ec9SKyle Evans 101*f0865ec9SKyle Evans /* 102*f0865ec9SKyle Evans * Compute out such that num = out * den mod p. 'out' parameter must have been initialized 103*f0865ec9SKyle Evans * by the caller. Returns 0 on success, -1 on error. 104*f0865ec9SKyle Evans * 105*f0865ec9SKyle Evans * Aliasing is supported. 106*f0865ec9SKyle Evans */ 107*f0865ec9SKyle Evans int fp_div(fp_t out, fp_src_t num, fp_src_t den) 108*f0865ec9SKyle Evans { 109*f0865ec9SKyle Evans int ret; 110*f0865ec9SKyle Evans 111*f0865ec9SKyle Evans ret = fp_check_initialized(num); EG(ret, err); 112*f0865ec9SKyle Evans ret = fp_check_initialized(den); EG(ret, err); 113*f0865ec9SKyle Evans ret = fp_check_initialized(out); EG(ret, err); 114*f0865ec9SKyle Evans 115*f0865ec9SKyle Evans MUST_HAVE(out->ctx == num->ctx, ret, err); 116*f0865ec9SKyle Evans MUST_HAVE(out->ctx == den->ctx, ret, err); 117*f0865ec9SKyle Evans 118*f0865ec9SKyle Evans if(out == num){ 119*f0865ec9SKyle Evans /* Handle aliasing of out and num */ 120*f0865ec9SKyle Evans fp _num; 121*f0865ec9SKyle Evans _num.magic = WORD(0); 122*f0865ec9SKyle Evans 123*f0865ec9SKyle Evans ret = fp_copy(&_num, num); EG(ret, err1); 124*f0865ec9SKyle Evans ret = fp_inv(out, den); EG(ret, err1); 125*f0865ec9SKyle Evans ret = fp_mul(out, &_num, out); 126*f0865ec9SKyle Evans 127*f0865ec9SKyle Evans err1: 128*f0865ec9SKyle Evans fp_uninit(&_num); 129*f0865ec9SKyle Evans EG(ret, err); 130*f0865ec9SKyle Evans } 131*f0865ec9SKyle Evans else{ 132*f0865ec9SKyle Evans ret = fp_inv(out, den); EG(ret, err); 133*f0865ec9SKyle Evans ret = fp_mul(out, num, out); 134*f0865ec9SKyle Evans } 135*f0865ec9SKyle Evans 136*f0865ec9SKyle Evans err: 137*f0865ec9SKyle Evans return ret; 138*f0865ec9SKyle Evans } 139