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