MastersThesis/PQ_TIIGER_TLS/sal/miracl-ubuntu22-11-04-24/includes/ff.cpp
2024-04-19 14:16:07 +02:00

1040 lines
23 KiB
C++

/*
* 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_dsucopy(BIG x[], BIG y[], int n)
{
int i;
for (i = 0; i < n; i++)
{
BIG_copy(x[n + i], y[i]);
BIG_zero(x[i]);
}
}
/* x=y */
static void WWW::FF_dscopy(BIG x[], BIG y[], int n)
{
int i;
for (i = 0; i < n; i++)
{
BIG_copy(x[i], y[i]);
BIG_zero(x[n + 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<p on entry */
void WWW::FF_invmodp(BIG r[], BIG a[], BIG p[], int n)
{
#ifndef USE_VLAS
BIG u[FFLEN_WWW], v[FFLEN_WWW], x1[FFLEN_WWW], x2[FFLEN_WWW], t[FFLEN_WWW], one[FFLEN_WWW];
#else
BIG u[n], v[n], x1[n], x2[n], t[n], one[n];
#endif
FF_copy(u, a, n);
FF_copy(v, p, n);
FF_one(one, n);
FF_copy(x1, one, n);
FF_zero(x2, n);
// reduce n in here as well!
while (FF_comp(u, one, n) != 0 && FF_comp(v, one, n) != 0)
{
while (FF_parity(u) == 0)
{
FF_shr(u, n);
if (FF_parity(x1) != 0)
{
FF_add(x1, p, x1, n);
FF_norm(x1, n);
}
FF_shr(x1, n);
}
while (FF_parity(v) == 0)
{
FF_shr(v, n);
if (FF_parity(x2) != 0)
{
FF_add(x2, p, x2, n);
FF_norm(x2, n);
}
FF_shr(x2, n);
}
if (FF_comp(u, v, n) >= 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;
}