michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* Uses Montgomery reduction for field arithmetic. See mpi/mpmontg.c for michael@0: * code implementation. */ michael@0: michael@0: #include "mpi.h" michael@0: #include "mplogic.h" michael@0: #include "mpi-priv.h" michael@0: #include "ecl-priv.h" michael@0: #include "ecp.h" michael@0: #include michael@0: #include michael@0: michael@0: /* Construct a generic GFMethod for arithmetic over prime fields with michael@0: * irreducible irr. */ michael@0: GFMethod * michael@0: GFMethod_consGFp_mont(const mp_int *irr) michael@0: { michael@0: mp_err res = MP_OKAY; michael@0: GFMethod *meth = NULL; michael@0: mp_mont_modulus *mmm; michael@0: michael@0: meth = GFMethod_consGFp(irr); michael@0: if (meth == NULL) michael@0: return NULL; michael@0: michael@0: mmm = (mp_mont_modulus *) malloc(sizeof(mp_mont_modulus)); michael@0: if (mmm == NULL) { michael@0: res = MP_MEM; michael@0: goto CLEANUP; michael@0: } michael@0: michael@0: meth->field_mul = &ec_GFp_mul_mont; michael@0: meth->field_sqr = &ec_GFp_sqr_mont; michael@0: meth->field_div = &ec_GFp_div_mont; michael@0: meth->field_enc = &ec_GFp_enc_mont; michael@0: meth->field_dec = &ec_GFp_dec_mont; michael@0: meth->extra1 = mmm; michael@0: meth->extra2 = NULL; michael@0: meth->extra_free = &ec_GFp_extra_free_mont; michael@0: michael@0: mmm->N = meth->irr; michael@0: mmm->n0prime = 0 - s_mp_invmod_radix(MP_DIGIT(&meth->irr, 0)); michael@0: michael@0: CLEANUP: michael@0: if (res != MP_OKAY) { michael@0: GFMethod_free(meth); michael@0: return NULL; michael@0: } michael@0: return meth; michael@0: } michael@0: michael@0: /* Wrapper functions for generic prime field arithmetic. */ michael@0: michael@0: /* Field multiplication using Montgomery reduction. */ michael@0: mp_err michael@0: ec_GFp_mul_mont(const mp_int *a, const mp_int *b, mp_int *r, michael@0: const GFMethod *meth) michael@0: { michael@0: mp_err res = MP_OKAY; michael@0: michael@0: #ifdef MP_MONT_USE_MP_MUL michael@0: /* if MP_MONT_USE_MP_MUL is defined, then the function s_mp_mul_mont michael@0: * is not implemented and we have to use mp_mul and s_mp_redc directly michael@0: */ michael@0: MP_CHECKOK(mp_mul(a, b, r)); michael@0: MP_CHECKOK(s_mp_redc(r, (mp_mont_modulus *) meth->extra1)); michael@0: #else michael@0: mp_int s; michael@0: michael@0: MP_DIGITS(&s) = 0; michael@0: /* s_mp_mul_mont doesn't allow source and destination to be the same */ michael@0: if ((a == r) || (b == r)) { michael@0: MP_CHECKOK(mp_init(&s)); michael@0: MP_CHECKOK(s_mp_mul_mont michael@0: (a, b, &s, (mp_mont_modulus *) meth->extra1)); michael@0: MP_CHECKOK(mp_copy(&s, r)); michael@0: mp_clear(&s); michael@0: } else { michael@0: return s_mp_mul_mont(a, b, r, (mp_mont_modulus *) meth->extra1); michael@0: } michael@0: #endif michael@0: CLEANUP: michael@0: return res; michael@0: } michael@0: michael@0: /* Field squaring using Montgomery reduction. */ michael@0: mp_err michael@0: ec_GFp_sqr_mont(const mp_int *a, mp_int *r, const GFMethod *meth) michael@0: { michael@0: return ec_GFp_mul_mont(a, a, r, meth); michael@0: } michael@0: michael@0: /* Field division using Montgomery reduction. */ michael@0: mp_err michael@0: ec_GFp_div_mont(const mp_int *a, const mp_int *b, mp_int *r, michael@0: const GFMethod *meth) michael@0: { michael@0: mp_err res = MP_OKAY; michael@0: michael@0: /* if A=aZ represents a encoded in montgomery coordinates with Z and # michael@0: * and \ respectively represent multiplication and division in michael@0: * montgomery coordinates, then A\B = (a/b)Z = (A/B)Z and Binv = michael@0: * (1/b)Z = (1/B)(Z^2) where B # Binv = Z */ michael@0: MP_CHECKOK(ec_GFp_div(a, b, r, meth)); michael@0: MP_CHECKOK(ec_GFp_enc_mont(r, r, meth)); michael@0: if (a == NULL) { michael@0: MP_CHECKOK(ec_GFp_enc_mont(r, r, meth)); michael@0: } michael@0: CLEANUP: michael@0: return res; michael@0: } michael@0: michael@0: /* Encode a field element in Montgomery form. See s_mp_to_mont in michael@0: * mpi/mpmontg.c */ michael@0: mp_err michael@0: ec_GFp_enc_mont(const mp_int *a, mp_int *r, const GFMethod *meth) michael@0: { michael@0: mp_mont_modulus *mmm; michael@0: mp_err res = MP_OKAY; michael@0: michael@0: mmm = (mp_mont_modulus *) meth->extra1; michael@0: MP_CHECKOK(mp_copy(a, r)); michael@0: MP_CHECKOK(s_mp_lshd(r, MP_USED(&mmm->N))); michael@0: MP_CHECKOK(mp_mod(r, &mmm->N, r)); michael@0: CLEANUP: michael@0: return res; michael@0: } michael@0: michael@0: /* Decode a field element from Montgomery form. */ michael@0: mp_err michael@0: ec_GFp_dec_mont(const mp_int *a, mp_int *r, const GFMethod *meth) michael@0: { michael@0: mp_err res = MP_OKAY; michael@0: michael@0: if (a != r) { michael@0: MP_CHECKOK(mp_copy(a, r)); michael@0: } michael@0: MP_CHECKOK(s_mp_redc(r, (mp_mont_modulus *) meth->extra1)); michael@0: CLEANUP: michael@0: return res; michael@0: } michael@0: michael@0: /* Free the memory allocated to the extra fields of Montgomery GFMethod michael@0: * object. */ michael@0: void michael@0: ec_GFp_extra_free_mont(GFMethod *meth) michael@0: { michael@0: if (meth->extra1 != NULL) { michael@0: free(meth->extra1); michael@0: meth->extra1 = NULL; michael@0: } michael@0: }