1040 lines
23 KiB
C++
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;
|
||
|
}
|
||
|
|