/* * 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 basic functions for Large Finite Field support */ #include "ff_WWW.h" using namespace XXX; namespace WWW { static void FF_dsucopy(BIG x[], BIG y[], int); static void FF_dscopy(BIG x[], BIG y[], int); static void FF_sducopy(BIG x[], BIG y[], int); static void FF_shrw(BIG a[], int); static void FF_shlw(BIG a[], int); static void FF_radd(BIG z[], int, BIG x[], int, BIG y[], int, int); static void FF_rinc(BIG z[], int, BIG y[], int, int); static void FF_rdec(BIG z[], int, BIG y[], int, int); static void FF_rnorm(BIG z[], int, int); static void FF_cswap(BIG a[], BIG b[], int, int); static void FF_karmul(BIG z[], int, BIG x[], int, BIG y[], int, BIG t[], int, int); static void FF_karsqr(BIG z[], int, BIG x[], int, BIG t[], int, int); static void FF_karmul_lower(BIG z[], int, BIG x[], int, BIG y[], int, BIG t[], int, int); static void FF_karmul_upper(BIG z[], BIG x[], BIG y[], BIG t[], int); static void FF_lmul(BIG z[], BIG x[], BIG y[], int); static void FF_reduce(BIG r[], BIG T[], BIG N[], BIG ND[], int); static void FF_nres(BIG a[], BIG m[], int); static void FF_redc(BIG a[], BIG m[], BIG ND[], int); static void FF_invmod2m(BIG U[], BIG a[], int); static void FF_modmul(BIG z[], BIG x[], BIG y[], BIG p[], BIG ND[], int); static void FF_modsqr(BIG z[], BIG x[], BIG p[], BIG ND[], int); } /* x=y */ void WWW::FF_copy(BIG x[], BIG y[], int n) { int i; for (i = 0; i < n; i++) BIG_copy(x[i], y[i]); } /* x=y<>n */ static void WWW::FF_sducopy(BIG x[], BIG y[], int n) { int i; for (i = 0; i < n; i++) BIG_copy(x[i], y[n + i]); } /* set to zero */ void WWW::FF_zero(BIG x[], int n) { int i; for (i = 0; i < n; i++) BIG_zero(x[i]); } /* test equals 0 */ int WWW::FF_iszilch(BIG x[], int n) { int i; for (i = 0; i < n; i++) if (!BIG_iszilch(x[i])) return 0; return 1; } /* shift right by BIGBITS_XXX-bit words */ static void WWW::FF_shrw(BIG a[], int n) { int i; for (i = 0; i < n; i++) { BIG_copy(a[i], a[i + n]); BIG_zero(a[i + n]); } } /* shift left by BIGBITS_XXX-bit words */ static void WWW::FF_shlw(BIG a[], int n) { int i; for (i = 0; i < n; i++) { BIG_copy(a[i + n], a[i]); BIG_zero(a[i]); } } /* extract last bit */ int WWW::FF_parity(BIG x[]) { return BIG_parity(x[0]); } /* extract last m bits */ int WWW::FF_lastbits(BIG x[], int m) { return BIG_lastbits(x[0], m); } /* x=1 */ void WWW::FF_one(BIG x[], int n) { int i; BIG_one(x[0]); for (i = 1; i < n; i++) BIG_zero(x[i]); } /* x=m, where m is 32-bit int */ void WWW::FF_init(BIG x[], sign32 m, int n) { int i; BIG_zero(x[0]); #if CHUNK<64 x[0][0] = (chunk)(m & BMASK_XXX); x[0][1] = (chunk)(m >> BASEBITS_XXX); #else x[0][0] = (chunk)m; #endif for (i = 1; i < n; i++) BIG_zero(x[i]); } /* compare x and y - must be normalised */ int WWW::FF_comp(BIG x[], BIG y[], int n) { int i, j; for (i = n - 1; i >= 0; i--) { j = BIG_comp(x[i], y[i]); if (j != 0) return j; } return 0; } /* recursive add */ static void WWW::FF_radd(BIG z[], int zp, BIG x[], int xp, BIG y[], int yp, int n) { int i; for (i = 0; i < n; i++) BIG_add(z[zp + i], x[xp + i], y[yp + i]); } /* recursive inc */ static void WWW::FF_rinc(BIG z[], int zp, BIG y[], int yp, int n) { int i; for (i = 0; i < n; i++) BIG_add(z[zp + i], z[zp + i], y[yp + i]); } /* recursive dec */ static void WWW::FF_rdec(BIG z[], int zp, BIG y[], int yp, int n) { int i; for (i = 0; i < n; i++) BIG_sub(z[zp + i], z[zp + i], y[yp + i]); } /* simple add */ void WWW::FF_add(BIG z[], BIG x[], BIG y[], int n) { int i; for (i = 0; i < n; i++) BIG_add(z[i], x[i], y[i]); } /* simple sub */ void WWW::FF_sub(BIG z[], BIG x[], BIG y[], int n) { int i; for (i = 0; i < n; i++) BIG_sub(z[i], x[i], y[i]); } /* increment/decrement by a small integer */ void WWW::FF_inc(BIG x[], int m, int n) { BIG_inc(x[0], m); FF_norm(x, n); } void WWW::FF_dec(BIG x[], int m, int n) { BIG_dec(x[0], m); FF_norm(x, n); } /* normalise - but hold any overflow in top part unless n<0 */ static void WWW::FF_rnorm(BIG z[], int zp, int n) { int i, trunc = 0; chunk carry; if (n < 0) { /* -v n signals to do truncation */ n = -n; trunc = 1; } for (i = 0; i < n - 1; i++) { carry = BIG_norm(z[zp + i]); z[zp + i][NLEN_XXX - 1] ^= carry << P_TBITS_WWW; /* remove it */ z[zp + i + 1][0] += carry; } carry = BIG_norm(z[zp + n - 1]); if (trunc) z[zp + n - 1][NLEN_XXX - 1] ^= carry << P_TBITS_WWW; } void WWW::FF_norm(BIG z[], int n) { FF_rnorm(z, 0, n); } /* shift left by one bit */ void WWW::FF_shl(BIG x[], int n) { int i; int carry, delay_carry = 0; for (i = 0; i < n - 1; i++) { carry = BIG_fshl(x[i], 1); x[i][0] |= delay_carry; x[i][NLEN_XXX - 1] ^= (chunk)carry << P_TBITS_WWW; delay_carry = carry; } BIG_fshl(x[n - 1], 1); x[n - 1][0] |= delay_carry; } /* shift right by one bit */ void WWW::FF_shr(BIG x[], int n) { int i; int carry; for (i = n - 1; i > 0; i--) { carry = BIG_fshr(x[i], 1); x[i - 1][NLEN_XXX - 1] |= (chunk)carry << P_TBITS_WWW; } BIG_fshr(x[0], 1); } void WWW::FF_output(BIG x[], int n) { int i; FF_norm(x, n); for (i = n - 1; i >= 0; i--) { BIG_output(x[i]); printf(" "); } } void WWW::FF_rawoutput(BIG x[], int n) { int i; for (i = n - 1; i >= 0; i--) { BIG_rawoutput(x[i]); printf(" "); } } /* Convert FFs to/from octet strings */ void WWW::FF_toOctet(octet *w, BIG x[], int n) { int i; w->len = n * MODBYTES_XXX; for (i = 0; i < n; i++) { BIG_toBytes(&(w->val[(n - i - 1)*MODBYTES_XXX]), x[i]); } } void WWW::FF_fromOctet(BIG x[], octet *w, int n) { int i; for (i = 0; i < n; i++) { BIG_fromBytes(x[i], &(w->val[(n - i - 1)*MODBYTES_XXX])); } } /* in-place swapping using xor - side channel resistant */ static void WWW::FF_cswap(BIG a[], BIG b[], int d, int n) { int i; for (i = 0; i < n; i++) BIG_cswap(a[i], b[i], d); return; } /* z=x*y, t is workspace */ static void WWW::FF_karmul(BIG z[], int zp, BIG x[], int xp, BIG y[], int yp, BIG t[], int tp, int n) { int nd2; if (n == 1) { BIG_norm(x[xp]); BIG_norm(y[yp]); BIG_mul(t[tp], x[xp], y[yp]); BIG_split(z[zp + 1], z[zp], t[tp], BIGBITS_XXX); return; } nd2 = n / 2; FF_radd(z, zp, x, xp, x, xp + nd2, nd2); FF_rnorm(z, zp, nd2); /* needs this if recursion level too deep */ FF_radd(z, zp + nd2, y, yp, y, yp + nd2, nd2); FF_rnorm(z, zp + nd2, nd2); FF_karmul(t, tp, z, zp, z, zp + nd2, t, tp + n, nd2); FF_karmul(z, zp, x, xp, y, yp, t, tp + n, nd2); FF_karmul(z, zp + n, x, xp + nd2, y, yp + nd2, t, tp + n, nd2); FF_rdec(t, tp, z, zp, n); FF_rdec(t, tp, z, zp + n, n); FF_rinc(z, zp + nd2, t, tp, n); FF_rnorm(z, zp, 2 * n); } static void WWW::FF_karsqr(BIG z[], int zp, BIG x[], int xp, BIG t[], int tp, int n) { int nd2; if (n == 1) { BIG_norm(x[xp]); BIG_sqr(t[tp], x[xp]); BIG_split(z[zp + 1], z[zp], t[tp], BIGBITS_XXX); return; } nd2 = n / 2; FF_karsqr(z, zp, x, xp, t, tp + n, nd2); FF_karsqr(z, zp + n, x, xp + nd2, t, tp + n, nd2); FF_karmul(t, tp, x, xp, x, xp + nd2, t, tp + n, nd2); FF_rinc(z, zp + nd2, t, tp, n); FF_rinc(z, zp + nd2, t, tp, n); FF_rnorm(z, zp + nd2, n); /* was FF_rnorm(z,zp,2*n) */ } static void WWW::FF_karmul_lower(BIG z[], int zp, BIG x[], int xp, BIG y[], int yp, BIG t[], int tp, int n) { /* Calculates Least Significant bottom half of x*y */ int nd2; if (n == 1) { /* only calculate bottom half of product */ BIG_norm(x[xp]); BIG_norm(y[yp]); BIG_smul(z[zp], x[xp], y[yp]); return; } nd2 = n / 2; FF_karmul(z, zp, x, xp, y, yp, t, tp + n, nd2); FF_karmul_lower(t, tp, x, xp + nd2, y, yp, t, tp + n, nd2); FF_rinc(z, zp + nd2, t, tp, nd2); FF_karmul_lower(t, tp, x, xp, y, yp + nd2, t, tp + n, nd2); FF_rinc(z, zp + nd2, t, tp, nd2); FF_rnorm(z, zp + nd2, -nd2); /* truncate it */ } static void WWW::FF_karmul_upper(BIG z[], BIG x[], BIG y[], BIG t[], int n) { /* Calculates Most Significant upper half of x*y, given lower part */ int nd2; nd2 = n / 2; FF_radd(z, n, x, 0, x, nd2, nd2); FF_radd(z, n + nd2, y, 0, y, nd2, nd2); FF_rnorm(z, n, nd2); FF_rnorm(z, n + nd2, nd2); FF_karmul(t, 0, z, n + nd2, z, n, t, n, nd2); /* t = (a0+a1)(b0+b1) */ FF_karmul(z, n, x, nd2, y, nd2, t, n, nd2); /* z[n]= a1*b1 */ /* z[0-nd2]=l(a0b0) z[nd2-n]= h(a0b0)+l(t)-l(a0b0)-l(a1b1) */ FF_rdec(t, 0, z, n, n); /* t=t-a1b1 */ FF_rinc(z, nd2, z, 0, nd2); /* z[nd2-n]+=l(a0b0) = h(a0b0)+l(t)-l(a1b1) */ FF_rdec(z, nd2, t, 0, nd2); /* z[nd2-n]=h(a0b0)+l(t)-l(a1b1)-l(t-a1b1)=h(a0b0) */ FF_rnorm(z, 0, -n); /* a0b0 now in z - truncate it */ FF_rdec(t, 0, z, 0, n); /* (a0+a1)(b0+b1) - a0b0 */ FF_rinc(z, nd2, t, 0, n); FF_rnorm(z, nd2, n); } /* z=x*y */ void WWW::FF_mul(BIG z[], BIG x[], BIG y[], int n) { #ifndef USE_VLAS BIG t[2 * FFLEN_WWW]; #else BIG t[2 * n]; #endif FF_karmul(z, 0, x, 0, y, 0, t, 0, n); } /* return low part of product */ static void WWW::FF_lmul(BIG z[], BIG x[], BIG y[], int n) { #ifndef USE_VLAS BIG t[2 * FFLEN_WWW]; #else BIG t[2 * n]; #endif FF_karmul_lower(z, 0, x, 0, y, 0, t, 0, n); } /* Set b=b mod c */ void WWW::FF_mod(BIG b[], BIG c[], int n) { int k = 0; FF_norm(b, n); if (FF_comp(b, c, n) < 0) return; do { FF_shl(c, n); k++; } while (FF_comp(b, c, n) >= 0); while (k > 0) { FF_shr(c, n); if (FF_comp(b, c, n) >= 0) { FF_sub(b, b, c, n); FF_norm(b, n); } k--; } } /* z=x^2 */ void WWW::FF_sqr(BIG z[], BIG x[], int n) { #ifndef USE_VLAS BIG t[2 * FFLEN_WWW]; #else BIG t[2 * n]; #endif FF_karsqr(z, 0, x, 0, t, 0, n); } /* r=t mod modulus, N is modulus, ND is Montgomery Constant */ static void WWW::FF_reduce(BIG r[], BIG T[], BIG N[], BIG ND[], int n) { /* fast karatsuba Montgomery reduction */ #ifndef USE_VLAS BIG t[2 * FFLEN_WWW]; BIG m[FFLEN_WWW]; #else BIG t[2 * n]; BIG m[n]; #endif WWW::FF_sducopy(r, T, n); /* keep top half of T */ FF_karmul_lower(m, 0, T, 0, ND, 0, t, 0, n); /* m=T.(1/N) mod R */ FF_karmul_upper(T, N, m, t, n); /* T=mN */ FF_sducopy(m, T, n); FF_add(r, r, N, n); FF_sub(r, r, m, n); FF_norm(r, n); } /* Set r=a mod b */ /* a is of length - 2*n */ /* r,b is of length - n */ void WWW::FF_dmod(BIG r[], BIG a[], BIG b[], int n) { int k; #ifndef USE_VLAS BIG m[2 * FFLEN_WWW]; BIG x[2 * FFLEN_WWW]; #else BIG m[2 * n]; BIG x[2 * n]; #endif FF_copy(x, a, 2 * n); FF_norm(x, 2 * n); FF_dsucopy(m, b, n); k = BIGBITS_XXX * n; while (FF_comp(x, m, 2 * n) >= 0) { FF_sub(x, x, m, 2 * n); FF_norm(x, 2 * n); } while (k > 0) { FF_shr(m, 2 * n); if (FF_comp(x, m, 2 * n) >= 0) { FF_sub(x, x, m, 2 * n); FF_norm(x, 2 * n); } k--; } FF_copy(r, x, n); FF_mod(r, b, n); } /* Set r=1/a mod p. Binary method - a

= 0) { FF_sub(u, u, v, n); FF_norm(u, n); if (FF_comp(x1, x2, n) >= 0) FF_sub(x1, x1, x2, n); else { FF_sub(t, p, x2, n); FF_add(x1, x1, t, n); } FF_norm(x1, n); } else { FF_sub(v, v, u, n); FF_norm(v, n); if (FF_comp(x2, x1, n) >= 0) FF_sub(x2, x2, x1, n); else { FF_sub(t, p, x1, n); FF_add(x2, x2, t, n); } FF_norm(x2, n); } } if (FF_comp(u, one, n) == 0) FF_copy(r, x1, n); else FF_copy(r, x2, n); } /* nesidue mod m */ static void WWW::FF_nres(BIG a[], BIG m[], int n) { #ifndef USE_VLAS BIG d[2 * FFLEN_WWW]; #else BIG d[2 * n]; #endif if (n == 1) { BIG_dscopy(d[0], a[0]); BIG_dshl(d[0], NLEN_XXX * BASEBITS_XXX); BIG_dmod(a[0], d[0], m[0]); } else { FF_dsucopy(d, a, n); FF_dmod(a, d, m, n); } } static void WWW::FF_redc(BIG a[], BIG m[], BIG ND[], int n) { #ifndef USE_VLAS BIG d[2 * FFLEN_WWW]; #else BIG d[2 * n]; #endif if (n == 1) { BIG_dzero(d[0]); BIG_dscopy(d[0], a[0]); BIG_monty(a[0], m[0], ((chunk)1 << BASEBITS_XXX) - ND[0][0], d[0]); } else { FF_mod(a, m, n); FF_dscopy(d, a, n); FF_reduce(a, d, m, ND, n); FF_mod(a, m, n); } } /* U=1/a mod 2^m - Arazi & Qi */ static void WWW::FF_invmod2m(BIG U[], BIG a[], int n) { int i; #ifndef USE_VLAS BIG t1[2*FFLEN_WWW], b[FFLEN_WWW], c[FFLEN_WWW]; #else BIG t1[2 * n], b[n], c[n]; #endif FF_zero(U, n); FF_zero(b, n); FF_zero(c, n); FF_zero(t1, 2 * n); BIG_copy(U[0], a[0]); BIG_invmod2m(U[0]); for (i = 1; i < n; i <<= 1) { FF_copy(b, a, i); FF_mul(t1, U, b, i); FF_shrw(t1, i); // top half to bottom half, top half=0 FF_copy(c, a, 2 * i); FF_shrw(c, i); // top half of c FF_lmul(b, U, c, i); // should set top half of b=0 FF_add(t1, t1, b, i); FF_norm(t1, 2 * i); FF_lmul(b, t1, U, i); FF_copy(t1, b, i); FF_one(b, i); FF_shlw(b, i); FF_sub(t1, b, t1, 2 * i); FF_norm(t1, 2 * i); FF_shlw(t1, i); FF_add(U, U, t1, 2 * i); } FF_norm(U, n); } void WWW::FF_random(BIG x[], csprng *rng, int n) { int i; for (i = 0; i < n; i++) { BIG_random(x[i], rng); } /* make sure top bit is 1 */ while (BIG_nbits(x[n - 1]) < MODBYTES_XXX * 8) BIG_random(x[n - 1], rng); } /* generate random x mod p */ void WWW::FF_randomnum(BIG x[], BIG p[], csprng *rng, int n) { int i; #ifndef USE_VLAS BIG d[2 * FFLEN_WWW]; #else BIG d[2 * n]; #endif for (i = 0; i < 2 * n; i++) { BIG_random(d[i], rng); } FF_dmod(x, d, p, n); } static void WWW::FF_modmul(BIG z[], BIG x[], BIG y[], BIG p[], BIG ND[], int n) { #ifndef USE_VLAS BIG d[2 * FFLEN_WWW]; #else BIG d[2 * n]; #endif chunk ex = P_EXCESS_WWW(x[n - 1]); chunk ey = P_EXCESS_WWW(y[n - 1]); #ifdef dchunk if ((dchunk)(ex + 1) * (ey + 1) > (dchunk)P_FEXCESS_WWW) #else if ((ex + 1) > P_FEXCESS_WWW / (ey + 1)) #endif { #ifdef DEBUG_REDUCE printf("Product too large - reducing it %d %d\n", ex, ey); #endif FF_mod(x, p, n); } if (n == 1) { BIG_mul(d[0], x[0], y[0]); BIG_monty(z[0], p[0], ((chunk)1 << BASEBITS_XXX) - ND[0][0], d[0]); } else { FF_mul(d, x, y, n); FF_reduce(z, d, p, ND, n); } } static void WWW::FF_modsqr(BIG z[], BIG x[], BIG p[], BIG ND[], int n) { #ifndef USE_VLAS BIG d[2 * FFLEN_WWW]; #else BIG d[2 * n]; #endif chunk ex = P_EXCESS_WWW(x[n - 1]); #ifdef dchunk if ((dchunk)(ex + 1) * (ex + 1) > (dchunk)P_FEXCESS_WWW) #else if ((ex + 1) > P_FEXCESS_WWW / (ex + 1)) #endif { #ifdef DEBUG_REDUCE printf("Product too large - reducing it %d\n", ex); #endif FF_mod(x, p, n); } if (n == 1) { BIG_sqr(d[0], x[0]); BIG_monty(z[0], p[0], ((chunk)1 << BASEBITS_XXX) - ND[0][0], d[0]); } else { FF_sqr(d, x, n); FF_reduce(z, d, p, ND, n); } } /* r=x^e mod p using side-channel resistant Montgomery Ladder, for large e */ void WWW::FF_skpow(BIG r[], BIG x[], BIG e[], BIG p[], int n) { int i, b; #ifndef USE_VLAS BIG R0[FFLEN_WWW], R1[FFLEN_WWW], ND[FFLEN_WWW]; #else BIG R0[n], R1[n], ND[n]; #endif FF_invmod2m(ND, p, n); FF_one(R0, n); FF_copy(R1, x, n); FF_nres(R0, p, n); FF_nres(R1, p, n); for (i = 8 * MODBYTES_XXX * n - 1; i >= 0; i--) { b = BIG_bit(e[i / BIGBITS_XXX], i % BIGBITS_XXX); FF_modmul(r, R0, R1, p, ND, n); FF_cswap(R0, R1, b, n); FF_modsqr(R0, R0, p, ND, n); FF_copy(R1, r, n); FF_cswap(R0, R1, b, n); } FF_copy(r, R0, n); FF_redc(r, p, ND, n); } /* r=x^e mod p using side-channel resistant Montgomery Ladder, for short e */ void WWW::FF_skspow(BIG r[], BIG x[], BIG e, BIG p[], int n) { int i, b; #ifndef USE_VLAS BIG R0[FFLEN_WWW], R1[FFLEN_WWW], ND[FFLEN_WWW]; #else BIG R0[n], R1[n], ND[n]; #endif FF_invmod2m(ND, p, n); FF_one(R0, n); FF_copy(R1, x, n); FF_nres(R0, p, n); FF_nres(R1, p, n); for (i = 8 * MODBYTES_XXX - 1; i >= 0; i--) { b = BIG_bit(e, i); FF_modmul(r, R0, R1, p, ND, n); FF_cswap(R0, R1, b, n); FF_modsqr(R0, R0, p, ND, n); FF_copy(R1, r, n); FF_cswap(R0, R1, b, n); } FF_copy(r, R0, n); FF_redc(r, p, ND, n); } /* raise to an integer power - right-to-left method */ void WWW::FF_power(BIG r[], BIG x[], int e, BIG p[], int n) { int f = 1; #ifndef USE_VLAS BIG w[FFLEN_WWW], ND[FFLEN_WWW]; #else BIG w[n], ND[n]; #endif FF_invmod2m(ND, p, n); FF_copy(w, x, n); FF_nres(w, p, n); if (e == 2) { FF_modsqr(r, w, p, ND, n); } else for (;;) { if (e % 2 == 1) { if (f) FF_copy(r, w, n); else FF_modmul(r, r, w, p, ND, n); f = 0; } e >>= 1; if (e == 0) break; FF_modsqr(w, w, p, ND, n); } FF_redc(r, p, ND, n); } /* r=x^e mod p, faster but not side channel resistant */ void WWW::FF_pow(BIG r[], BIG x[], BIG e[], BIG p[], int n) { int i, b; #ifndef USE_VLAS BIG w[FFLEN_WWW], ND[FFLEN_WWW]; #else BIG w[n], ND[n]; #endif FF_invmod2m(ND, p, n); FF_copy(w, x, n); FF_one(r, n); FF_nres(r, p, n); FF_nres(w, p, n); for (i = 8 * MODBYTES_XXX * n - 1; i >= 0; i--) { FF_modsqr(r, r, p, ND, n); b = BIG_bit(e[i / BIGBITS_XXX], i % BIGBITS_XXX); if (b == 1) FF_modmul(r, r, w, p, ND, n); } FF_redc(r, p, ND, n); } /* double exponentiation r=x^e.y^f mod p */ void WWW::FF_pow2(BIG r[], BIG x[], BIG e, BIG y[], BIG f, BIG p[], int n) { int i, eb, fb; #ifndef USE_VLAS BIG xn[FFLEN_WWW], yn[FFLEN_WWW], xy[FFLEN_WWW], ND[FFLEN_WWW]; #else BIG xn[n], yn[n], xy[n], ND[n]; #endif FF_invmod2m(ND, p, n); FF_copy(xn, x, n); FF_copy(yn, y, n); FF_nres(xn, p, n); FF_nres(yn, p, n); FF_modmul(xy, xn, yn, p, ND, n); FF_one(r, n); FF_nres(r, p, n); for (i = 8 * MODBYTES_XXX - 1; i >= 0; i--) { eb = BIG_bit(e, i); fb = BIG_bit(f, i); FF_modsqr(r, r, p, ND, n); if (eb == 1) { if (fb == 1) FF_modmul(r, r, xy, p, ND, n); else FF_modmul(r, r, xn, p, ND, n); } else { if (fb == 1) FF_modmul(r, r, yn, p, ND, n); } } FF_redc(r, p, ND, n); } static sign32 igcd(sign32 x, sign32 y) { /* integer GCD, returns GCD of x and y */ sign32 r; if (y == 0) return x; while ((r = x % y) != 0) x = y, y = r; return y; } /* quick and dirty check for common factor with s */ int WWW::FF_cfactor(BIG w[], sign32 s, int n) { int r; sign32 g; #ifndef USE_VLAS BIG x[FFLEN_WWW], y[FFLEN_WWW]; #else BIG x[n], y[n]; #endif FF_init(y, s, n); FF_copy(x, w, n); FF_norm(x, n); do { FF_sub(x, x, y, n); FF_norm(x, n); while (!FF_iszilch(x, n) && FF_parity(x) == 0) FF_shr(x, n); } while (FF_comp(x, y, n) > 0); #if CHUNK<32 g = x[0][0] + ((sign32)(x[0][1]) << BASEBITS_XXX); #else g = (sign32)x[0][0]; #endif r = igcd(s, g); if (r > 1) return 1; return 0; } /* Miller-Rabin test for primality. Slow. */ int WWW::FF_prime(BIG p[], csprng *rng, int n) { int i, j, loop, s = 0; #ifndef USE_VLAS BIG d[FFLEN_WWW], x[FFLEN_WWW], unity[FFLEN_WWW], nm1[FFLEN_WWW]; #else BIG d[n], x[n], unity[n], nm1[n]; #endif sign32 sf = 4849845; /* 3*5*.. *19 */ FF_norm(p, n); if (FF_cfactor(p, sf, n)) return 0; FF_one(unity, n); FF_sub(nm1, p, unity, n); FF_norm(nm1, n); FF_copy(d, nm1, n); while (FF_parity(d) == 0) { FF_shr(d, n); s++; } if (s == 0) return 0; for (i = 0; i < 10; i++) { FF_randomnum(x, p, rng, n); FF_pow(x, x, d, p, n); if (FF_comp(x, unity, n) == 0 || FF_comp(x, nm1, n) == 0) continue; loop = 0; for (j = 1; j < s; j++) { FF_power(x, x, 2, p, n); if (FF_comp(x, unity, n) == 0) return 0; if (FF_comp(x, nm1, n) == 0 ) { loop = 1; break; } } if (loop) continue; return 0; } return 1; }