/* * Copyright (c) 2012-2020 MIRACL UK Ltd. * * This file is part of MIRACL Core * (see https://github.com/miracl/core). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* CORE mod p functions */ /* Small Finite Field arithmetic */ /* SU=m, SU is Stack Usage (NOT_SPECIAL Modulus) */ #include "fp_YYY.h" using namespace XXX; /* Fast Modular Reduction Methods */ /* r=d mod m */ /* d MUST be normalised */ /* Products must be less than pR in all cases !!! */ /* So when multiplying two numbers, their product *must* be less than MODBITS_YYY+BASEBITS_XXX*NLEN_XXX */ /* Results *may* be one bit bigger than MODBITS_YYY */ #if MODTYPE_YYY == PSEUDO_MERSENNE /* r=d mod m */ /* Converts from BIG integer to residue form mod Modulus */ void YYY::FP_nres(FP *y, BIG x) { BIG mdls; BIG_rcopy(mdls, Modulus); BIG_copy(y->g, x); BIG_mod(y->g,mdls); y->XES = 1; } /* Converts from residue form back to BIG integer form */ void YYY::FP_redc(BIG x, FP *y) { BIG_copy(x, y->g); } /* reduce a DBIG to a BIG exploiting the special form of the modulus */ void YYY::FP_mod(BIG r, DBIG d) { BIG t, b; chunk v, tw; BIG_split(t, b, d, MODBITS_YYY); /* Note that all of the excess gets pushed into t. So if squaring a value with a 4-bit excess, this results in t getting all 8 bits of the excess product! So products must be less than pR which is Montgomery compatible */ if (MConst < NEXCESS_XXX) { BIG_imul(t, t, MConst); BIG_norm(t); BIG_add(r, t, b); BIG_norm(r); tw = r[NLEN_XXX - 1]; r[NLEN_XXX - 1] &= TMASK_YYY; r[0] += MConst * ((tw >> TBITS_YYY)); } else { v = BIG_pmul(t, t, MConst); BIG_add(r, t, b); BIG_norm(r); tw = r[NLEN_XXX - 1]; r[NLEN_XXX - 1] &= TMASK_YYY; #if CHUNK == 16 r[1] += muladd(MConst, ((tw >> TBITS_YYY) + (v << (BASEBITS_XXX - TBITS_YYY))), 0, &r[0]); #else r[0] += MConst * ((tw >> TBITS_YYY) + (v << (BASEBITS_XXX - TBITS_YYY))); #endif } BIG_norm(r); } #endif /* This only applies to Curve C448, so specialised (for now) */ #if MODTYPE_YYY == GENERALISED_MERSENNE void YYY::FP_nres(FP *y, BIG x) { BIG mdls; BIG_rcopy(mdls, Modulus); BIG_copy(y->g, x); BIG_mod(y->g,mdls); y->XES = 1; } /* Converts from residue form back to BIG integer form */ void YYY::FP_redc(BIG x, FP *y) { BIG_copy(x, y->g); } /* reduce a DBIG to a BIG exploiting the special form of a modulus 2^m - 2^n -c */ void YYY::FP_mod(BIG r, DBIG d) { BIG t, b; chunk carry; BIG_split(t, b, d, MBITS_YYY); BIG_add(r, t, b); BIG_dscopy(d, t); BIG_dshl(d, MBITS_YYY / 2); BIG_split(t, b, d, MBITS_YYY); BIG_add(r, r, t); BIG_add(r, r, b); BIG_norm(r); BIG_shl(t, MBITS_YYY / 2); BIG_add(r, r, t); carry = r[NLEN_XXX - 1] >> TBITS_YYY; r[NLEN_XXX - 1] &= TMASK_YYY; r[0] += carry; r[224 / BASEBITS_XXX] += carry << (224 % BASEBITS_XXX); /* need to check that this falls mid-word */ BIG_norm(r); /* BIG t, b, t2, b2; int BTset = MBITS_YYY / 2; chunk carry; BIG_split(t, b, d, MBITS_YYY); BIG_dscopy(d, t); BIG_dshl(d, BTset); BIG_split(t2, b2, d, MBITS_YYY); BIG_add(b, b, b2); // 2 BIG_add(t, t, t2); // 2 BIG_shl(t2, BTset); BIG_add(b, b, t2); // 3 BIG_norm(t); // carry=0; // Now multiply t by MConst..(?) and extract carry // if (MConst!=1) // carry=BIG_pmul(t,t,MConst); BIG_add(r, t, b); BIG_norm(r); carry = r[NLEN_XXX - 1] >> TBITS_YYY; // + (carry<<(BASEBITS_XXX-TBITS_YYY)); r[NLEN_XXX - 1] &= TMASK_YYY; r[BTset / BASEBITS_XXX] += carry << (BTset % BASEBITS_XXX); // need to check that this falls mid-word // if (MConst!=1) carry*=MConst; r[0] += carry; BIG_norm(r); */ } #endif #if MODTYPE_YYY == MONTGOMERY_FRIENDLY /* convert to Montgomery n-residue form */ void YYY::FP_nres(FP *y, BIG x) { DBIG d; BIG r; BIG_rcopy(r, R2modp); BIG_mul(d, x, r); FP_mod(y->g, d); y->XES = 2; } /* convert back to regular form */ void YYY::FP_redc(BIG x, FP *y) { DBIG d; BIG_dzero(d); BIG_dscopy(d, y->g); FP_mod(x, d); } /* fast modular reduction from DBIG to BIG exploiting special form of the modulus */ void YYY::FP_mod(BIG a, DBIG d) { int i; for (i = 0; i < NLEN_XXX; i++) d[NLEN_XXX + i] += muladd(d[i], MConst - 1, d[i], &d[NLEN_XXX + i - 1]); BIG_sducopy(a, d); BIG_norm(a); } #endif #if MODTYPE_YYY == NOT_SPECIAL /* convert to Montgomery n-residue form */ void YYY::FP_nres(FP *y, BIG x) { DBIG d; BIG r; BIG_rcopy(r, R2modp); BIG_mul(d, x, r); FP_mod(y->g, d); y->XES = 2; } /* convert back to regular form */ void YYY::FP_redc(BIG x, FP *y) { DBIG d; BIG_dzero(d); BIG_dscopy(d, y->g); FP_mod(x, d); } /* reduce a DBIG to a BIG using Montgomery's no trial division method */ /* d is expected to be dnormed before entry */ /* SU= 112 */ void YYY::FP_mod(BIG a, DBIG d) { BIG mdls; BIG_rcopy(mdls, Modulus); BIG_monty(a, mdls, MConst, d); } #endif void YYY::FP_from_int(FP *x,int a) { BIG w; if (a<0) BIG_rcopy(w, Modulus); else BIG_zero(w); BIG_inc(w,a); BIG_norm(w); FP_nres(x,w); } /* test x==0 ? */ /* SU= 48 */ int YYY::FP_iszilch(FP *x) { BIG m; FP y; FP_copy(&y,x); FP_reduce(&y); FP_redc(m,&y); return BIG_iszilch(m); } /* input must be reduced */ int YYY::FP_isunity(FP *x) { BIG m; FP y; FP_copy(&y,x); FP_reduce(&y); FP_redc(m,&y); return BIG_isunity(m); } void YYY::FP_copy(FP *y, FP *x) { BIG_copy(y->g, x->g); y->XES = x->XES; } void YYY::FP_rcopy(FP *y, const BIG c) { BIG b; BIG_rcopy(b, c); FP_nres(y, b); } /* Swap a and b if d=1 */ void YYY::FP_cswap(FP *a, FP *b, int d) { sign32 t, c = d; BIG_cswap(a->g, b->g, d); c = ~(c - 1); t = c & ((a->XES) ^ (b->XES)); a->XES ^= t; b->XES ^= t; } /* Move b to a if d=1 */ void YYY::FP_cmove(FP *a, FP *b, int d) { sign32 c = -d; BIG_cmove(a->g, b->g, d); a->XES ^= (a->XES ^ b->XES)&c; } void YYY::FP_zero(FP *x) { BIG_zero(x->g); x->XES = 1; } int YYY::FP_equals(FP *x, FP *y) { FP xg, yg; FP_copy(&xg, x); FP_copy(&yg, y); FP_reduce(&xg); FP_reduce(&yg); if (BIG_comp(xg.g, yg.g) == 0) return 1; return 0; } // Is x lexically larger than p-x? // return -1 for no, 0 if x=0, 1 for yes int YYY::FP_islarger(FP *x) { BIG p,fx,sx; if (FP_iszilch(x)) return 0; BIG_rcopy(p,Modulus); FP_redc(fx,x); BIG_sub(sx,p,fx); BIG_norm(sx); return BIG_comp(fx,sx); } void YYY::FP_toBytes(char *b,FP *x) { BIG t; FP_redc(t, x); BIG_toBytes(b, t); } void YYY::FP_fromBytes(FP *x,char *b) { BIG t; BIG_fromBytes(t, b); FP_nres(x, t); } /* output FP */ /* SU= 48 */ void YYY::FP_output(FP *r) { BIG c; FP_reduce(r); FP_redc(c, r); BIG_output(c); } void YYY::FP_rawoutput(FP *r) { BIG_rawoutput(r->g); } #ifdef GET_STATS int tsqr = 0, rsqr = 0, tmul = 0, rmul = 0; int tadd = 0, radd = 0, tneg = 0, rneg = 0; int tdadd = 0, rdadd = 0, tdneg = 0, rdneg = 0; #endif #ifdef FUSED_MODMUL /* Insert fastest code here */ #endif /* r=a*b mod Modulus */ /* product must be less that p.R - and we need to know this in advance! */ /* SU= 88 */ void YYY::FP_mul(FP *r, FP *a, FP *b) { DBIG d; if ((sign64)a->XES * b->XES > (sign64)FEXCESS_YYY) { #ifdef DEBUG_REDUCE printf("Product too large - reducing it\n"); #endif FP_reduce(a); /* it is sufficient to fully reduce just one of them < p */ } #ifdef FUSED_MODMUL FP_modmul(r->g, a->g, b->g); #else BIG_mul(d, a->g, b->g); FP_mod(r->g, d); #endif r->XES = 2; } /* multiplication by an integer, r=a*c */ /* SU= 136 */ void YYY::FP_imul(FP *r, FP *a, int c) { DBIG d; BIG k; FP f; int s = 0; if (c < 0) { c = -c; s = 1; } #if MODTYPE_YYY==PSEUDO_MERSENNE || MODTYPE_YYY==GENERALISED_MERSENNE BIG_pxmul(d, a->g, c); FP_mod(r->g, d); r->XES = 2; #else //Montgomery if (a->XES * c <= FEXCESS_YYY) { BIG_pmul(r->g, a->g, c); r->XES = a->XES * c; // careful here - XES jumps! } else { // don't want to do this - only a problem for Montgomery modulus and larger constants BIG_zero(k); BIG_inc(k, c); BIG_norm(k); FP_nres(&f, k); FP_mul(r, a, &f); } #endif if (s) { FP_neg(r, r); FP_norm(r); } } /* Set r=a^2 mod m */ /* SU= 88 */ void YYY::FP_sqr(FP *r, FP *a) { DBIG d; if ((sign64)a->XES * a->XES > (sign64)FEXCESS_YYY) { #ifdef DEBUG_REDUCE printf("Product too large - reducing it\n"); #endif FP_reduce(a); } BIG_sqr(d, a->g); FP_mod(r->g, d); r->XES = 2; } /* SU= 16 */ /* Set r=a+b */ void YYY::FP_add(FP *r, FP *a, FP *b) { BIG_add(r->g, a->g, b->g); r->XES = a->XES + b->XES; if (r->XES > FEXCESS_YYY) { #ifdef DEBUG_REDUCE printf("Sum too large - reducing it \n"); #endif FP_reduce(r); } } /* Set r=a-b mod m */ /* SU= 56 */ void YYY::FP_sub(FP *r, FP *a, FP *b) { FP n; FP_neg(&n, b); FP_add(r, a, &n); } // https://graphics.stanford.edu/~seander/bithacks.html // constant time log to base 2 (or number of bits in) static int logb2(unsign32 v) { int r; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v = v - ((v >> 1) & 0x55555555); v = (v & 0x33333333) + ((v >> 2) & 0x33333333); r = (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; return r; } // find appoximation to quotient of a/m // Out by at most 2. // Note that MAXXES is bounded to be 2-bits less than half a word static int quo(BIG n, BIG m) { int sh; chunk num, den; int hb = CHUNK / 2; if (TBITS_YYY < hb) { sh = hb - TBITS_YYY; num = (n[NLEN_XXX - 1] << sh) | (n[NLEN_XXX - 2] >> (BASEBITS_XXX - sh)); den = (m[NLEN_XXX - 1] << sh) | (m[NLEN_XXX - 2] >> (BASEBITS_XXX - sh)); } else { num = n[NLEN_XXX - 1]; den = m[NLEN_XXX - 1]; } return (int)(num / (den + 1)); } /* SU= 48 */ /* Fully reduce a mod Modulus */ void YYY::FP_reduce(FP *a) { BIG m, r; int sr, sb, q; chunk carry; BIG_rcopy(m, Modulus); BIG_norm(a->g); if (a->XES > 16) { q = quo(a->g, m); carry = BIG_pmul(r, m, q); r[NLEN_XXX - 1] += (carry << BASEBITS_XXX); // correction - put any carry out back in again BIG_sub(a->g, a->g, r); BIG_norm(a->g); sb = 2; } else sb = logb2(a->XES - 1); // sb does not depend on the actual data BIG_fshl(m, sb); while (sb > 0) { // constant time... sr = BIG_ssn(r, a->g, m); // optimized combined shift, subtract and norm BIG_cmove(a->g, r, 1 - sr); sb--; } a->XES = 1; } void YYY::FP_norm(FP *x) { BIG_norm(x->g); } /* Set r=-a mod Modulus */ /* SU= 64 */ void YYY::FP_neg(FP *r, FP *a) { int sb; BIG m; BIG_rcopy(m, Modulus); sb = logb2(a->XES - 1); BIG_fshl(m, sb); BIG_sub(r->g, m, a->g); r->XES = ((sign32)1 << sb) + 1; // +1 to cover case where a is zero ? if (r->XES > FEXCESS_YYY) { #ifdef DEBUG_REDUCE printf("Negation too large - reducing it \n"); #endif FP_reduce(r); } } /* Set r=a/2. */ /* SU= 56 */ void YYY::FP_div2(FP *r, FP *a) { BIG m; BIG w; BIG_rcopy(m, Modulus); int pr=BIG_parity(a->g); FP_copy(r, a); BIG_copy(w,r->g); BIG_fshr(r->g,1); BIG_add(w, w, m); BIG_norm(w); BIG_fshr(w, 1); BIG_cmove(r->g,w,pr); } // Could leak size of b // but not used here with secret exponent b void YYY::FP_pow(FP *r, FP *a, BIG b) { sign8 w[1 + (NLEN_XXX * BASEBITS_XXX + 3) / 4]; FP tb[16]; BIG t; int i, nb; FP_copy(r,a); FP_norm(r); BIG_copy(t, b); BIG_norm(t); nb = 1 + (BIG_nbits(t) + 3) / 4; // convert exponent to 4-bit window for (i = 0; i < nb; i++) { w[i] = BIG_lastbits(t, 4); BIG_dec(t, w[i]); BIG_norm(t); BIG_fshr(t, 4); } FP_one(&tb[0]); FP_copy(&tb[1], r); for (i = 2; i < 16; i++) FP_mul(&tb[i], &tb[i - 1], r); FP_copy(r, &tb[w[nb - 1]]); for (i = nb - 2; i >= 0; i--) { FP_sqr(r, r); FP_sqr(r, r); FP_sqr(r, r); FP_sqr(r, r); FP_mul(r, r, &tb[w[i]]); } FP_reduce(r); } #if MODTYPE_YYY==PSEUDO_MERSENNE || MODTYPE_YYY==GENERALISED_MERSENNE // See eprint paper https://eprint.iacr.org/2018/1038 // e.g. If p=3 mod 4 r= x^{(p-3)/4}, if p=5 mod 8 r=x^{(p-5)/8} void YYY::FP_fpow(FP *r, FP *x) { int i, j, k, bw, w, nw, lo, m, n, c, nd, e=PM1D2_YYY; FP xp[11], t, key; const int ac[] = {1, 2, 3, 6, 12, 15, 30, 60, 120, 240, 255}; // phase 1 FP_copy(&xp[0], x); // 1 FP_sqr(&xp[1], x); // 2 FP_mul(&xp[2], &xp[1], x); //3 FP_sqr(&xp[3], &xp[2]); // 6 FP_sqr(&xp[4], &xp[3]); // 12 FP_mul(&xp[5], &xp[4], &xp[2]); // 15 FP_sqr(&xp[6], &xp[5]); // 30 FP_sqr(&xp[7], &xp[6]); // 60 FP_sqr(&xp[8], &xp[7]); // 120 FP_sqr(&xp[9], &xp[8]); // 240 FP_mul(&xp[10], &xp[9], &xp[5]); // 255 #if MODTYPE_YYY==PSEUDO_MERSENNE n = MODBITS_YYY; #endif #if MODTYPE_YYY==GENERALISED_MERSENNE // Ed448 ONLY n = MODBITS_YYY / 2; #endif n-=(e+1); c=(MConst+(1< k) i--; FP_copy(&key, &xp[i]); k -= ac[i]; } while (k != 0) { i--; if (ac[i] > k) continue; FP_mul(&key, &key, &xp[i]); k -= ac[i]; } // phase 2 FP_copy(&xp[1], &xp[2]); FP_copy(&xp[2], &xp[5]); FP_copy(&xp[3], &xp[10]); j = 3; m = 8; nw = n - bw; while (2 * m < nw) { FP_copy(&t, &xp[j++]); for (i = 0; i < m; i++) FP_sqr(&t, &t); FP_mul(&xp[j], &xp[j - 1], &t); m *= 2; } lo = nw - m; FP_copy(r, &xp[j]); while (lo != 0) { m /= 2; j--; if (lo < m) continue; lo -= m; FP_copy(&t, r); for (i = 0; i < m; i++) FP_sqr(&t, &t); FP_mul(r, &t, &xp[j]); } // phase 3 if (bw != 0) { for (i = 0; i < bw; i++ ) FP_sqr(r, r); FP_mul(r, r, &key); } #if MODTYPE_YYY==GENERALISED_MERSENNE // Ed448 ONLY FP_copy(&key, r); FP_sqr(&t, &key); FP_mul(r, &t, &xp[0]); for (i = 0; i < n + 1; i++) FP_sqr(r, r); FP_mul(r, r, &key); #endif for (i=0;i1;k--) { for (j=1;j>1; #else BIG m; FP y; FP_copy(&y,x); FP_reduce(&y); FP_redc(m,&y); return BIG_parity(m); #endif } void YYY::FP_rand(FP *x,csprng *rng) { BIG w,m; BIG_rcopy(m,Modulus); BIG_randomnum(w,m,rng); FP_nres(x,w); }