1225 lines
28 KiB
C
1225 lines
28 KiB
C
/*
|
|
* Copyright (c) 1997, 1998, 1999, 2000, 2001 Virtual Unlimited B.V.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
/*!\file mpbarrett.c
|
|
* \brief Multi-precision integer routines using Barrett modular reduction.
|
|
* For more information on this algorithm, see:
|
|
* "Handbook of Applied Cryptography", Chapter 14.3.3
|
|
* Menezes, van Oorschot, Vanstone
|
|
* CRC Press
|
|
* \author Bob Deblier <bob@virtualunlimited.com>
|
|
* \ingroup MP__m
|
|
*/
|
|
|
|
#include "system.h"
|
|
#include "mp.h"
|
|
#include "mpprime.h"
|
|
#include "mpbarrett.h"
|
|
#include "debug.h"
|
|
|
|
/**
|
|
* mpbzero
|
|
*/
|
|
void mpbzero(mpbarrett* b)
|
|
{
|
|
b->size = 0;
|
|
b->modl = (mpw*) 0;
|
|
b->mu = (mpw*) 0;
|
|
}
|
|
|
|
/*@-nullstate@*/ /* b->modl may be null @*/
|
|
/**
|
|
* Allocates the data words for an mpbarrett structure.
|
|
* will allocate 2*size+1 words
|
|
*/
|
|
void mpbinit(mpbarrett* b, size_t size)
|
|
{
|
|
b->size = size;
|
|
if (b->modl)
|
|
free(b->modl);
|
|
b->modl = (mpw*) calloc(2*size+1, sizeof(*b->modl));
|
|
|
|
if (b->modl != (mpw*) 0)
|
|
b->mu = b->modl+size;
|
|
else
|
|
b->mu = (mpw*) 0;
|
|
}
|
|
/*@=nullstate@*/
|
|
|
|
/**
|
|
* mpbfree
|
|
*/
|
|
void mpbfree(mpbarrett* b)
|
|
{
|
|
if (b->modl != (mpw*) 0)
|
|
{
|
|
free(b->modl);
|
|
b->modl = (mpw*) 0;
|
|
b->mu = (mpw*) 0;
|
|
}
|
|
b->size = 0;
|
|
}
|
|
|
|
/*@-nullstate -compdef @*/ /* b->modl may be null @*/
|
|
void mpbcopy(mpbarrett* b, const mpbarrett* copy)
|
|
{
|
|
register size_t size = copy->size;
|
|
|
|
if (size)
|
|
{
|
|
if (b->modl)
|
|
{
|
|
if (b->size != size)
|
|
b->modl = (mpw*) realloc(b->modl, (2*size+1) * sizeof(*b->modl));
|
|
}
|
|
else
|
|
b->modl = (mpw*) malloc((2*size+1) * sizeof(*b->modl));
|
|
|
|
if (b->modl)
|
|
{
|
|
b->size = size;
|
|
b->mu = b->modl+copy->size;
|
|
mpcopy(2*size+1, b->modl, copy->modl);
|
|
}
|
|
else
|
|
{
|
|
b->size = 0;
|
|
b->mu = (mpw*) 0;
|
|
}
|
|
}
|
|
else if (b->modl)
|
|
{
|
|
free(b->modl);
|
|
b->size = 0;
|
|
b->modl = (mpw*) 0;
|
|
b->mu = (mpw*) 0;
|
|
}
|
|
}
|
|
/*@=nullstate =compdef @*/
|
|
|
|
/*@-nullstate -compdef @*/ /* b->modl may be null @*/
|
|
/**
|
|
* mpbset
|
|
*/
|
|
void mpbset(mpbarrett* b, size_t size, const mpw* data)
|
|
{
|
|
if (size > 0)
|
|
{
|
|
if (b->modl)
|
|
{
|
|
if (b->size != size)
|
|
b->modl = (mpw*) realloc(b->modl, (2*size+1) * sizeof(*b->modl));
|
|
}
|
|
else
|
|
b->modl = (mpw*) malloc((2*size+1) * sizeof(*b->modl));
|
|
|
|
if (b->modl)
|
|
{
|
|
mpw* temp = (mpw*) malloc((6*size+4) * sizeof(*temp));
|
|
|
|
b->size = size;
|
|
b->mu = b->modl+size;
|
|
mpcopy(size, b->modl, data);
|
|
/*@-nullpass@*/ /* temp may be NULL */
|
|
mpbmu_w(b, temp);
|
|
|
|
free(temp);
|
|
/*@=nullpass@*/
|
|
}
|
|
else
|
|
{
|
|
b->size = 0;
|
|
b->mu = (mpw*) 0;
|
|
}
|
|
}
|
|
}
|
|
/*@=nullstate =compdef @*/
|
|
|
|
/*@-nullstate -compdef @*/ /* b->modl may be null @*/
|
|
void mpbsethex(mpbarrett* b, const char* hex)
|
|
{
|
|
size_t len = strlen(hex);
|
|
size_t size = MP_NIBBLES_TO_WORDS(len + MP_WNIBBLES - 1);
|
|
|
|
if (b->modl)
|
|
{
|
|
if (b->size != size)
|
|
b->modl = (mpw*) realloc(b->modl, (2*size+1) * sizeof(*b->modl));
|
|
}
|
|
else
|
|
b->modl = (mpw*) malloc((2*size+1) * sizeof(*b->modl));
|
|
|
|
if (b->modl != (mpw*) 0)
|
|
{
|
|
register mpw* temp = (mpw*) malloc((6*size+4) * sizeof(*temp));
|
|
|
|
assert(temp != NULL);
|
|
b->size = size;
|
|
b->mu = b->modl+size;
|
|
|
|
(void) hs2ip(b->modl, size, hex, len);
|
|
|
|
mpbmu_w(b, temp);
|
|
|
|
free(temp);
|
|
}
|
|
else
|
|
{
|
|
b->size = 0;
|
|
b->mu = 0;
|
|
}
|
|
}
|
|
/*@=nullstate =compdef @*/
|
|
|
|
/**
|
|
* Computes the Barrett 'mu' coefficient.
|
|
* needs workspace of (6*size+4) words
|
|
*/
|
|
void mpbmu_w(mpbarrett* b, mpw* wksp)
|
|
{
|
|
register size_t size = b->size;
|
|
register size_t shift;
|
|
register mpw* divmod = wksp;
|
|
register mpw* dividend = divmod+(size*2+2);
|
|
register mpw* workspace = dividend+(size*2+1);
|
|
|
|
/* normalize modulus before division */
|
|
shift = mpnorm(size, b->modl);
|
|
/* make the dividend, initialize first word to 1 (shifted); the rest is zero */
|
|
*dividend = ((mpw) MP_LSBMASK << shift);
|
|
mpzero(size*2, dividend+1);
|
|
mpndivmod(divmod, size*2+1, dividend, size, b->modl, workspace);
|
|
/*@-nullpass@*/ /* b->mu may be NULL */
|
|
mpcopy(size+1, b->mu, divmod+1);
|
|
/*@=nullpass@*/
|
|
/* de-normalize */
|
|
mprshift(size, b->modl, shift);
|
|
}
|
|
|
|
/**
|
|
* Generates a random number in the range 1 < r < b-1.
|
|
* need workspace of (size) words
|
|
*/
|
|
void mpbrnd_w(const mpbarrett* b, randomGeneratorContext* rc, mpw* result, mpw* wksp)
|
|
{
|
|
size_t msz = mpmszcnt(b->size, b->modl);
|
|
|
|
mpcopy(b->size, wksp, b->modl);
|
|
(void) mpsubw(b->size, wksp, 1);
|
|
|
|
do
|
|
{
|
|
/*@-noeffectuncon@*/ /* LCL: ??? */
|
|
(void) rc->rng->next(rc->param, (byte*) result, MP_WORDS_TO_BYTES(b->size));
|
|
/*@=noeffectuncon@*/
|
|
|
|
/*@-shiftimplementation -usedef@*/
|
|
result[0] &= (MP_ALLMASK >> msz);
|
|
/*@=shiftimplementation =usedef@*/
|
|
|
|
while (mpge(b->size, result, wksp))
|
|
(void) mpsub(b->size, result, wksp);
|
|
} while (mpleone(b->size, result));
|
|
}
|
|
|
|
/**
|
|
* Generates a random odd number in the range 1 < r < b-1.
|
|
* needs workspace of (size) words
|
|
*/
|
|
void mpbrndodd_w(const mpbarrett* b, randomGeneratorContext* rc, mpw* result, mpw* wksp)
|
|
{
|
|
size_t msz = mpmszcnt(b->size, b->modl);
|
|
|
|
mpcopy(b->size, wksp, b->modl);
|
|
(void) mpsubw(b->size, wksp, 1);
|
|
|
|
do
|
|
{
|
|
/*@-noeffectuncon@*/ /* LCL: ??? */
|
|
(void) rc->rng->next(rc->param, (byte*) result, MP_WORDS_TO_BYTES(b->size));
|
|
/*@=noeffectuncon@*/
|
|
|
|
/*@-shiftimplementation -usedef@*/
|
|
result[0] &= (MP_ALLMASK >> msz);
|
|
/*@=shiftimplementation =usedef@*/
|
|
mpsetlsb(b->size, result);
|
|
|
|
while (mpge(b->size, result, wksp))
|
|
{
|
|
(void) mpsub(b->size, result, wksp);
|
|
mpsetlsb(b->size, result);
|
|
}
|
|
} while (mpleone(b->size, result));
|
|
}
|
|
|
|
/**
|
|
* Generates a random invertible (modulo b) in the range 1 < r < b-1.
|
|
* needs workspace of (6*size+6) words
|
|
*/
|
|
void mpbrndinv_w(const mpbarrett* b, randomGeneratorContext* rc, mpw* result, mpw* inverse, mpw* wksp)
|
|
{
|
|
register size_t size = b->size;
|
|
|
|
do
|
|
{
|
|
if (mpeven(size, b->modl))
|
|
mpbrndodd_w(b, rc, result, wksp);
|
|
else
|
|
mpbrnd_w(b, rc, result, wksp);
|
|
|
|
} while (mpbinv_w(b, size, result, inverse, wksp) == 0);
|
|
}
|
|
|
|
/**
|
|
* Computes the barrett modular reduction of a number x, which has twice the size of b.
|
|
* needs workspace of (2*size+2) words
|
|
*/
|
|
void mpbmod_w(const mpbarrett* b, const mpw* data, mpw* result, mpw* wksp)
|
|
{
|
|
register mpw rc;
|
|
register size_t sp = 2;
|
|
register const mpw* src = data+b->size+1;
|
|
register mpw* dst = wksp+b->size+1;
|
|
|
|
/*@-nullpass@*/ /* b->mu may be NULL */
|
|
rc = mpsetmul(sp, dst, b->mu, *(--src));
|
|
*(--dst) = rc;
|
|
|
|
while (sp <= b->size)
|
|
{
|
|
sp++;
|
|
if ((rc = *(--src)))
|
|
{
|
|
rc = mpaddmul(sp, dst, b->mu, rc);
|
|
*(--dst) = rc;
|
|
}
|
|
else
|
|
*(--dst) = 0;
|
|
}
|
|
if ((rc = *(--src)))
|
|
{
|
|
rc = mpaddmul(sp, dst, b->mu, rc);
|
|
*(--dst) = rc;
|
|
}
|
|
else
|
|
*(--dst) = 0;
|
|
/*@=nullpass@*/
|
|
|
|
sp = b->size;
|
|
rc = 0;
|
|
|
|
dst = wksp+b->size+1;
|
|
src = dst;
|
|
|
|
/*@-evalorder@*/ /* --src side effect, dst/src aliases */
|
|
*dst = mpsetmul(sp, dst+1, b->modl, *(--src));
|
|
/*@=evalorder@*/
|
|
|
|
while (sp > 0)
|
|
(void) mpaddmul(sp--, dst, b->modl+(rc++), *(--src));
|
|
|
|
mpsetx(b->size+1, wksp, b->size*2, data);
|
|
(void) mpsub(b->size+1, wksp, wksp+b->size+1);
|
|
|
|
while (mpgex(b->size+1, wksp, b->size, b->modl))
|
|
(void) mpsubx(b->size+1, wksp, b->size, b->modl);
|
|
mpcopy(b->size, result, wksp+1);
|
|
}
|
|
|
|
/**
|
|
* Copies (b-1) into result.
|
|
*/
|
|
void mpbsubone(const mpbarrett* b, mpw* result)
|
|
{
|
|
register size_t size = b->size;
|
|
|
|
mpcopy(size, result, b->modl);
|
|
(void) mpsubw(size, result, 1);
|
|
}
|
|
|
|
/**
|
|
* Computes the negative (modulo b) of x, where x must contain a value between 0 and b-1.
|
|
*/
|
|
void mpbneg(const mpbarrett* b, const mpw* data, mpw* result)
|
|
{
|
|
register size_t size = b->size;
|
|
|
|
mpcopy(size, result, data);
|
|
mpneg(size, result);
|
|
(void) mpadd(size, result, b->modl);
|
|
}
|
|
|
|
/**
|
|
* Computes the sum (modulo b) of x and y.
|
|
* needs a workspace of (4*size+2) words
|
|
*/
|
|
void mpbaddmod_w(const mpbarrett* b, size_t xsize, const mpw* xdata, size_t ysize, const mpw* ydata, mpw* result, mpw* wksp)
|
|
{
|
|
/* xsize and ysize must be less than or equal to b->size */
|
|
register size_t size = b->size;
|
|
register mpw* temp = wksp + size*2+2;
|
|
|
|
mpsetx(2*size, temp, xsize, xdata);
|
|
(void) mpaddx(2*size, temp, ysize, ydata);
|
|
|
|
mpbmod_w(b, temp, result, wksp);
|
|
}
|
|
|
|
/**
|
|
* Computes the difference (modulo b) of x and y.
|
|
* needs a workspace of (4*size+2) words
|
|
*/
|
|
void mpbsubmod_w(const mpbarrett* b, size_t xsize, const mpw* xdata, size_t ysize, const mpw* ydata, mpw* result, mpw* wksp)
|
|
{
|
|
/* xsize and ysize must be less than or equal to b->size */
|
|
register size_t size = b->size;
|
|
register mpw* temp = wksp + size*2+2;
|
|
|
|
mpsetx(2*size, temp, xsize, xdata);
|
|
if (mpsubx(2*size, temp, ysize, ydata)) /* if there's carry, i.e. the result would be negative, add the modulus */
|
|
(void) mpaddx(2*size, temp, size, b->modl);
|
|
|
|
mpbmod_w(b, temp, result, wksp);
|
|
}
|
|
|
|
/**
|
|
* Computes the product (modulo b) of x and y.
|
|
* needs a workspace of (4*size+2) words
|
|
*/
|
|
void mpbmulmod_w(const mpbarrett* b, size_t xsize, const mpw* xdata, size_t ysize, const mpw* ydata, mpw* result, mpw* wksp)
|
|
{
|
|
/* xsize and ysize must be <= b->size */
|
|
register size_t size = b->size;
|
|
register mpw* temp = wksp + size*2+2;
|
|
register mpw fill = size*2-xsize-ysize;
|
|
|
|
if (fill)
|
|
mpzero(fill, temp);
|
|
|
|
mpmul(temp+fill, xsize, xdata, ysize, ydata);
|
|
/*@-compdef@*/ /* *temp undefined */
|
|
mpbmod_w(b, temp, result, wksp);
|
|
/*@=compdef@*/
|
|
}
|
|
|
|
/**
|
|
* Computes the square (modulo b) of x.
|
|
* needs a workspace of (4*size+2) words
|
|
*/
|
|
void mpbsqrmod_w(const mpbarrett* b, size_t xsize, const mpw* xdata, mpw* result, mpw* wksp)
|
|
{
|
|
/* xsize must be <= b->size */
|
|
register size_t size = b->size;
|
|
register mpw* temp = wksp + size*2+2;
|
|
register mpw fill = 2*(size-xsize);
|
|
|
|
if (fill)
|
|
mpzero(fill, temp);
|
|
|
|
mpsqr(temp+fill, xsize, xdata);
|
|
/*@-compdef@*/ /* *temp undefined */
|
|
mpbmod_w(b, temp, result, wksp);
|
|
/*@=compdef@*/
|
|
}
|
|
|
|
/**
|
|
* Precomputes the sliding window table for computing powers of x modulo b.
|
|
* needs workspace (4*size+2)
|
|
*
|
|
* Sliding Window Exponentiation technique, slightly altered from the method Applied Cryptography:
|
|
*
|
|
* First of all, the table with the powers of g can be reduced by about half; the even powers don't
|
|
* need to be accessed or stored.
|
|
*
|
|
* Get up to K bits starting with a one, if we have that many still available
|
|
*
|
|
* Do the number of squarings of A in the first column, the multiply by the value in column two,
|
|
* and finally do the number of squarings in column three.
|
|
*
|
|
* This table can be used for K=2,3,4 and can be extended
|
|
*
|
|
*
|
|
\verbatim
|
|
0 : - | - | -
|
|
1 : 1 | g1 @ 0 | 0
|
|
10 : 1 | g1 @ 0 | 1
|
|
11 : 2 | g3 @ 1 | 0
|
|
100 : 1 | g1 @ 0 | 2
|
|
101 : 3 | g5 @ 2 | 0
|
|
110 : 2 | g3 @ 1 | 1
|
|
111 : 3 | g7 @ 3 | 0
|
|
1000 : 1 | g1 @ 0 | 3
|
|
1001 : 4 | g9 @ 4 | 0
|
|
1010 : 3 | g5 @ 2 | 1
|
|
1011 : 4 | g11 @ 5 | 0
|
|
1100 : 2 | g3 @ 1 | 2
|
|
1101 : 4 | g13 @ 6 | 0
|
|
1110 : 3 | g7 @ 3 | 1
|
|
1111 : 4 | g15 @ 7 | 0
|
|
\endverbatim
|
|
*
|
|
*/
|
|
static void mpbslide_w(const mpbarrett* b, size_t xsize, const mpw* xdata, /*@out@*/ mpw* slide, /*@out@*/ mpw* wksp)
|
|
/*@modifies slide, wksp @*/
|
|
{
|
|
register size_t size = b->size;
|
|
mpbsqrmod_w(b, xsize, xdata, slide , wksp); /* x^2 mod b, temp */
|
|
mpbmulmod_w(b, xsize, xdata, size, slide , slide+size , wksp); /* x^3 mod b */
|
|
mpbmulmod_w(b, size, slide, size, slide+size , slide+2*size, wksp); /* x^5 mod b */
|
|
mpbmulmod_w(b, size, slide, size, slide+2*size, slide+3*size, wksp); /* x^7 mod b */
|
|
mpbmulmod_w(b, size, slide, size, slide+3*size, slide+4*size, wksp); /* x^9 mod b */
|
|
mpbmulmod_w(b, size, slide, size, slide+4*size, slide+5*size, wksp); /* x^11 mod b */
|
|
mpbmulmod_w(b, size, slide, size, slide+5*size, slide+6*size, wksp); /* x^13 mod b */
|
|
mpbmulmod_w(b, size, slide, size, slide+6*size, slide+7*size, wksp); /* x^15 mod b */
|
|
mpsetx(size, slide, xsize, xdata); /* x^1 mod b */
|
|
}
|
|
|
|
/*@observer@*/ /*@unchecked@*/
|
|
static byte mpbslide_presq[16] =
|
|
{ 0, 1, 1, 2, 1, 3, 2, 3, 1, 4, 3, 4, 2, 4, 3, 4 };
|
|
|
|
/*@observer@*/ /*@unchecked@*/
|
|
static byte mpbslide_mulg[16] =
|
|
{ 0, 0, 0, 1, 0, 2, 1, 3, 0, 4, 2, 5, 1, 6, 3, 7 };
|
|
|
|
/*@observer@*/ /*@unchecked@*/
|
|
static byte mpbslide_postsq[16] =
|
|
{ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };
|
|
|
|
/**
|
|
* mpbpowmod_w
|
|
* needs workspace of 4*size+2 words
|
|
*/
|
|
void mpbpowmod_w(const mpbarrett* b, size_t xsize, const mpw* xdata, size_t psize, const mpw* pdata, mpw* result, mpw* wksp)
|
|
{
|
|
/*
|
|
* Modular exponention
|
|
*
|
|
* Uses sliding window exponentiation; needs extra storage: if K=3, needs 8*size, if K=4, needs 16*size
|
|
*
|
|
*/
|
|
|
|
/* K == 4 for the first try */
|
|
|
|
size_t size = b->size;
|
|
mpw temp = 0;
|
|
|
|
while (psize)
|
|
{
|
|
if ((temp = *(pdata++))) /* break when first non-zero word found */
|
|
break;
|
|
psize--;
|
|
}
|
|
|
|
/* if temp is still zero, then we're trying to raise x to power zero, and result stays one */
|
|
if (temp)
|
|
{
|
|
mpw* slide = (mpw*) malloc((8*size)*sizeof(*slide));
|
|
|
|
assert(slide != NULL);
|
|
mpbslide_w(b, xsize, xdata, slide, wksp);
|
|
|
|
/*@-internalglobs -mods@*/ /* noisy */
|
|
mpbpowmodsld_w(b, slide, psize, pdata-1, result, wksp);
|
|
/*@=internalglobs =mods@*/
|
|
|
|
free(slide);
|
|
}
|
|
}
|
|
|
|
void mpbpowmodsld_w(const mpbarrett* b, const mpw* slide, size_t psize, const mpw* pdata, mpw* result, mpw* wksp)
|
|
{
|
|
/*
|
|
* Modular exponentiation with precomputed sliding window table, so no x is required
|
|
*
|
|
*/
|
|
|
|
size_t size = b->size;
|
|
mpw temp = 0;
|
|
|
|
mpsetw(size, result, 1);
|
|
|
|
while (psize)
|
|
{
|
|
if ((temp = *(pdata++))) /* break when first non-zero word found in power */
|
|
break;
|
|
psize--;
|
|
}
|
|
|
|
/* if temp is still zero, then we're trying to raise x to power zero, and result stays one */
|
|
if (temp)
|
|
{
|
|
unsigned int l = 0, n = 0, count = MP_WBITS;
|
|
|
|
/* first skip bits until we reach a one */
|
|
while (count != 0)
|
|
{
|
|
if (temp & MP_MSBMASK)
|
|
break;
|
|
temp <<= 1;
|
|
count--;
|
|
}
|
|
|
|
while (psize)
|
|
{
|
|
while (count != 0)
|
|
{
|
|
byte bit = (temp & MP_MSBMASK) ? 1 : 0;
|
|
|
|
n <<= 1;
|
|
n += bit;
|
|
|
|
if (n != 0)
|
|
{
|
|
if (l != 0)
|
|
l++;
|
|
else if (bit != 0)
|
|
l = 1U;
|
|
|
|
if (l == 4U)
|
|
{
|
|
byte s = mpbslide_presq[n];
|
|
|
|
while (s--)
|
|
mpbsqrmod_w(b, size, result, result, wksp);
|
|
|
|
mpbmulmod_w(b, size, result, size, slide+mpbslide_mulg[n]*size, result, wksp);
|
|
|
|
s = mpbslide_postsq[n];
|
|
|
|
while (s--)
|
|
mpbsqrmod_w(b, size, result, result, wksp);
|
|
|
|
l = n = 0;
|
|
}
|
|
}
|
|
else
|
|
mpbsqrmod_w(b, size, result, result, wksp);
|
|
|
|
temp <<= 1;
|
|
count--;
|
|
}
|
|
if (--psize)
|
|
{
|
|
count = MP_WBITS;
|
|
temp = *(pdata++);
|
|
}
|
|
}
|
|
|
|
if (n != 0)
|
|
{
|
|
byte s = mpbslide_presq[n];
|
|
while (s--)
|
|
mpbsqrmod_w(b, size, result, result, wksp);
|
|
|
|
mpbmulmod_w(b, size, result, size, slide+mpbslide_mulg[n]*size, result, wksp);
|
|
|
|
s = mpbslide_postsq[n];
|
|
|
|
while (s--)
|
|
mpbsqrmod_w(b, size, result, result, wksp);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* mpbtwopowmod_w
|
|
* needs workspace of (4*size+2) words
|
|
*/
|
|
void mpbtwopowmod_w(const mpbarrett* b, size_t psize, const mpw* pdata, mpw* result, mpw* wksp)
|
|
{
|
|
/*
|
|
* Modular exponention, 2^p mod modulus, special optimization
|
|
*
|
|
* Uses left-to-right exponentiation; needs no extra storage
|
|
*
|
|
*/
|
|
|
|
/* this routine calls mpbmod, which needs (size*2+2), this routine needs (size*2) for sdata */
|
|
|
|
register size_t size = b->size;
|
|
register mpw temp = 0;
|
|
|
|
mpsetw(size, result, 1);
|
|
|
|
while (psize)
|
|
{
|
|
if ((temp = *(pdata++))) /* break when first non-zero word found */
|
|
break;
|
|
psize--;
|
|
}
|
|
|
|
/* if temp is still zero, then we're trying to raise x to power zero, and result stays one */
|
|
if (temp)
|
|
{
|
|
register unsigned int count = MP_WBITS;
|
|
|
|
/* first skip bits until we reach a one */
|
|
while (count)
|
|
{
|
|
if (temp & MP_MSBMASK)
|
|
break;
|
|
temp <<= 1;
|
|
count--;
|
|
}
|
|
|
|
while (psize--)
|
|
{
|
|
while (count)
|
|
{
|
|
/* always square */
|
|
mpbsqrmod_w(b, size, result, result, wksp);
|
|
|
|
/* multiply by two if bit is 1 */
|
|
if (temp & MP_MSBMASK)
|
|
{
|
|
if (mpadd(size, result, result) || mpge(size, result, b->modl))
|
|
{
|
|
/* there was carry, or the result is greater than the modulus, so we need to adjust */
|
|
(void) mpsub(size, result, b->modl);
|
|
}
|
|
}
|
|
|
|
temp <<= 1;
|
|
count--;
|
|
}
|
|
count = MP_WBITS;
|
|
temp = *(pdata++);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DYING
|
|
/**
|
|
* Computes the inverse (modulo b) of x, and returns 1 if x was invertible.
|
|
* needs workspace of (6*size+6) words
|
|
* @note xdata and result cannot point to the same area
|
|
*/
|
|
int mpbinv_w(const mpbarrett* b, size_t xsize, const mpw* xdata, mpw* result, mpw* wksp)
|
|
{
|
|
/*
|
|
* Fact: if a element of Zn, then a is invertible if and only if gcd(a,n) = 1
|
|
* Hence: if b->modl is even, then x must be odd, otherwise the gcd(x,n) >= 2
|
|
*
|
|
* The calling routine must guarantee this condition.
|
|
*/
|
|
|
|
register size_t size = b->size;
|
|
|
|
mpw* udata = wksp;
|
|
mpw* vdata = udata+size+1;
|
|
mpw* adata = vdata+size+1;
|
|
mpw* bdata = adata+size+1;
|
|
mpw* cdata = bdata+size+1;
|
|
mpw* ddata = cdata+size+1;
|
|
|
|
mpsetx(size+1, udata, size, b->modl);
|
|
mpsetx(size+1, vdata, xsize, xdata);
|
|
mpzero(size+1, bdata);
|
|
mpsetw(size+1, ddata, 1);
|
|
|
|
if (mpodd(b->size, b->modl))
|
|
{
|
|
/* use simplified binary extended gcd algorithm */
|
|
|
|
while (1)
|
|
{
|
|
while (mpeven(size+1, udata))
|
|
{
|
|
mpdivtwo(size+1, udata);
|
|
|
|
if (mpodd(size+1, bdata))
|
|
(void) mpsubx(size+1, bdata, size, b->modl);
|
|
|
|
mpsdivtwo(size+1, bdata);
|
|
}
|
|
while (mpeven(size+1, vdata))
|
|
{
|
|
mpdivtwo(size+1, vdata);
|
|
|
|
if (mpodd(size+1, ddata))
|
|
(void) mpsubx(size+1, ddata, size, b->modl);
|
|
|
|
mpsdivtwo(size+1, ddata);
|
|
}
|
|
if (mpge(size+1, udata, vdata))
|
|
{
|
|
(void) mpsub(size+1, udata, vdata);
|
|
(void) mpsub(size+1, bdata, ddata);
|
|
}
|
|
else
|
|
{
|
|
(void) mpsub(size+1, vdata, udata);
|
|
(void) mpsub(size+1, ddata, bdata);
|
|
}
|
|
|
|
if (mpz(size+1, udata))
|
|
{
|
|
if (mpisone(size+1, vdata))
|
|
{
|
|
if (result)
|
|
{
|
|
mpsetx(size, result, size+1, ddata);
|
|
/*@-usedef@*/
|
|
if (*ddata & MP_MSBMASK)
|
|
{
|
|
/* keep adding the modulus until we get a carry */
|
|
while (!mpadd(size, result, b->modl));
|
|
}
|
|
/*@=usedef@*/
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* use full binary extended gcd algorithm */
|
|
mpsetw(size+1, adata, 1);
|
|
mpzero(size+1, cdata);
|
|
|
|
while (1)
|
|
{
|
|
while (mpeven(size+1, udata))
|
|
{
|
|
mpdivtwo(size+1, udata);
|
|
|
|
if (mpodd(size+1, adata) || mpodd(size+1, bdata))
|
|
{
|
|
(void) mpaddx(size+1, adata, xsize, xdata);
|
|
(void) mpsubx(size+1, bdata, size, b->modl);
|
|
}
|
|
|
|
mpsdivtwo(size+1, adata);
|
|
mpsdivtwo(size+1, bdata);
|
|
}
|
|
while (mpeven(size+1, vdata))
|
|
{
|
|
mpdivtwo(size+1, vdata);
|
|
|
|
if (mpodd(size+1, cdata) || mpodd(size+1, ddata))
|
|
{
|
|
(void) mpaddx(size+1, cdata, xsize, xdata);
|
|
(void) mpsubx(size+1, ddata, size, b->modl);
|
|
}
|
|
|
|
mpsdivtwo(size+1, cdata);
|
|
mpsdivtwo(size+1, ddata);
|
|
}
|
|
if (mpge(size+1, udata, vdata))
|
|
{
|
|
(void) mpsub(size+1, udata, vdata);
|
|
(void) mpsub(size+1, adata, cdata);
|
|
(void) mpsub(size+1, bdata, ddata);
|
|
}
|
|
else
|
|
{
|
|
(void) mpsub(size+1, vdata, udata);
|
|
(void) mpsub(size+1, cdata, adata);
|
|
(void) mpsub(size+1, ddata, bdata);
|
|
}
|
|
|
|
if (mpz(size+1, udata))
|
|
{
|
|
if (mpisone(size+1, vdata))
|
|
{
|
|
if (result)
|
|
{
|
|
mpsetx(size, result, size+1, ddata);
|
|
/*@-usedef@*/
|
|
if (*ddata & MP_MSBMASK)
|
|
{
|
|
/* keep adding the modulus until we get a carry */
|
|
while (!mpadd(size, result, b->modl));
|
|
}
|
|
/*@=usedef@*/
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
|
|
/*@unchecked@*/
|
|
static int _debug = 0;
|
|
|
|
#undef FULL_BINARY_EXTENDED_GCD
|
|
|
|
/**
|
|
* Computes the inverse (modulo b) of x, and returns 1 if x was invertible.
|
|
*/
|
|
int mpbinv_w(const mpbarrett* b, size_t xsize, const mpw* xdata, mpw* result, mpw* wksp)
|
|
{
|
|
size_t ysize = b->size+1;
|
|
int k;
|
|
mpw* u = wksp;
|
|
mpw* v = u+ysize;
|
|
mpw* u1 = v+ysize;
|
|
mpw* v1 = u1+ysize;
|
|
mpw* t1 = v1+ysize;
|
|
mpw* u3 = t1+ysize;
|
|
mpw* v3 = u3+ysize;
|
|
mpw* t3 = v3+ysize;
|
|
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
mpw* u2 = t3+ysize;
|
|
mpw* v2 = u2+ysize;
|
|
mpw* t2 = v2+ysize;
|
|
#endif
|
|
|
|
mpsetx(ysize, u, xsize, xdata);
|
|
mpsetx(ysize, v, b->size, b->modl);
|
|
|
|
/* Y1. Find power of 2. */
|
|
for (k = 0; mpeven(ysize, u) && mpeven(ysize, v); k++) {
|
|
mpdivtwo(ysize, u);
|
|
mpdivtwo(ysize, v);
|
|
}
|
|
|
|
/* Y2. Initialize. */
|
|
mpsetw(ysize, u1, 1);
|
|
mpsetx(ysize, v1, ysize, v);
|
|
mpsetx(ysize, u3, ysize, u);
|
|
mpsetx(ysize, v3, ysize, v);
|
|
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
mpzero(ysize, u2);
|
|
mpsetw(ysize, v2, 1);
|
|
(void) mpsub(ysize, v2, u);
|
|
#endif
|
|
|
|
if (_debug < 0) {
|
|
/*@-modfilesys@*/
|
|
fprintf(stderr, " u: "), mpfprintln(stderr, ysize, u);
|
|
fprintf(stderr, " v: "), mpfprintln(stderr, ysize, v);
|
|
fprintf(stderr, " u1: "), mpfprintln(stderr, ysize, u1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
fprintf(stderr, " u2: "), mpfprintln(stderr, ysize, u2);
|
|
#endif
|
|
fprintf(stderr, " u3: "), mpfprintln(stderr, ysize, u3);
|
|
fprintf(stderr, " v1: "), mpfprintln(stderr, ysize, v1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
fprintf(stderr, " v2: "), mpfprintln(stderr, ysize, v2);
|
|
#endif
|
|
fprintf(stderr, " v3: "), mpfprintln(stderr, ysize, v3);
|
|
/*@=modfilesys@*/
|
|
}
|
|
|
|
if (mpodd(ysize, u)) {
|
|
mpzero(ysize, t1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
mpzero(ysize, t2);
|
|
mpsubw(ysize, t2, 1);
|
|
#endif
|
|
mpzero(ysize, t3);
|
|
(void) mpsub(ysize, t3, v);
|
|
goto Y4;
|
|
} else {
|
|
mpsetw(ysize, t1, 1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
mpzero(ysize, t2);
|
|
#endif
|
|
mpsetx(ysize, t3, ysize, u);
|
|
}
|
|
|
|
do {
|
|
do {
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
if (mpodd(ysize, t1) || mpodd(ysize, t2)) {
|
|
(void) mpadd(ysize, t1, v);
|
|
(void) mpsub(ysize, t2, u);
|
|
}
|
|
#else
|
|
/* XXX this assumes v is odd, true for DSA inversion. */
|
|
if (mpodd(ysize, t1))
|
|
(void) mpadd(ysize, t1, v);
|
|
#endif
|
|
|
|
mpsdivtwo(ysize, t1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
mpsdivtwo(ysize, t2);
|
|
#endif
|
|
mpsdivtwo(ysize, t3);
|
|
Y4:
|
|
if (_debug < 0) {
|
|
/*@-modfilesys@*/
|
|
fprintf(stderr, "-->Y4 t3: "), mpfprintln(stderr, ysize, t3);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
fprintf(stderr, " t2: "), mpfprintln(stderr, ysize, t2);
|
|
#endif
|
|
fprintf(stderr, " t1: "), mpfprintln(stderr, ysize, t1);
|
|
/*@=modfilesys@*/
|
|
}
|
|
} while (mpeven(ysize, t3));
|
|
|
|
/* Y5. Reset max(u3,v3). */
|
|
if (!(*t3 & MP_MSBMASK)) {
|
|
mpsetx(ysize, u1, ysize, t1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
mpsetx(ysize, u2, ysize, t2);
|
|
#endif
|
|
mpsetx(ysize, u3, ysize, t3);
|
|
if (_debug < 0) {
|
|
/*@-modfilesys@*/
|
|
fprintf(stderr, "-->Y5 u1: "), mpfprintln(stderr, ysize, u1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
fprintf(stderr, " u2: "), mpfprintln(stderr, ysize, u2);
|
|
#endif
|
|
fprintf(stderr, " u3: "), mpfprintln(stderr, ysize, u3);
|
|
/*@=modfilesys@*/
|
|
}
|
|
} else {
|
|
mpsetx(ysize, v1, ysize, v);
|
|
(void) mpsub(ysize, v1, t1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
mpsetx(ysize, v2, ysize, u);
|
|
mpneg(ysize, v2);
|
|
(void) mpsub(ysize, v2, t2);
|
|
#endif
|
|
mpzero(ysize, v3);
|
|
(void) mpsub(ysize, v3, t3);
|
|
if (_debug < 0) {
|
|
/*@-modfilesys@*/
|
|
fprintf(stderr, "-->Y5 v1: "), mpfprintln(stderr, ysize, v1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
fprintf(stderr, " v2: "), mpfprintln(stderr, ysize, v2);
|
|
#endif
|
|
fprintf(stderr, " v3: "), mpfprintln(stderr, ysize, v3);
|
|
/*@=modfilesys@*/
|
|
}
|
|
}
|
|
|
|
/* Y6. Subtract. */
|
|
mpsetx(ysize, t1, ysize, u1);
|
|
(void) mpsub(ysize, t1, v1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
mpsetx(ysize, t2, ysize, u2);
|
|
(void) mpsub(ysize, t2, v2);
|
|
#endif
|
|
mpsetx(ysize, t3, ysize, u3);
|
|
(void) mpsub(ysize, t3, v3);
|
|
|
|
if (*t1 & MP_MSBMASK) {
|
|
(void) mpadd(ysize, t1, v);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
(void) mpsub(ysize, t2, u);
|
|
#endif
|
|
}
|
|
|
|
if (_debug < 0) {
|
|
/*@-modfilesys@*/
|
|
fprintf(stderr, "-->Y6 t1: "), mpfprintln(stderr, ysize, t1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
fprintf(stderr, " t2: "), mpfprintln(stderr, ysize, t2);
|
|
#endif
|
|
fprintf(stderr, " t3: "), mpfprintln(stderr, ysize, t3);
|
|
/*@=modfilesys@*/
|
|
}
|
|
|
|
} while (mpnz(ysize, t3));
|
|
|
|
if (!mpisone(ysize, u3) || !mpisone(ysize, v3))
|
|
return 0;
|
|
|
|
if (result) {
|
|
while (--k > 0)
|
|
(void) mpadd(ysize, u1, u1);
|
|
mpsetx(b->size, result, ysize, u1);
|
|
}
|
|
|
|
if (_debug) {
|
|
/*@-modfilesys@*/
|
|
if (result)
|
|
fprintf(stderr, "=== EXIT: "), mpfprintln(stderr, b->size, result);
|
|
fprintf(stderr, " u1: "), mpfprintln(stderr, ysize, u1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
fprintf(stderr, " u2: "), mpfprintln(stderr, ysize, u2);
|
|
#endif
|
|
fprintf(stderr, " u3: "), mpfprintln(stderr, ysize, u3);
|
|
fprintf(stderr, " v1: "), mpfprintln(stderr, ysize, v1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
fprintf(stderr, " v2: "), mpfprintln(stderr, ysize, v2);
|
|
#endif
|
|
fprintf(stderr, " v3: "), mpfprintln(stderr, ysize, v3);
|
|
fprintf(stderr, " t1: "), mpfprintln(stderr, ysize, t1);
|
|
#ifdef FULL_BINARY_EXTENDED_GCD
|
|
fprintf(stderr, " t2: "), mpfprintln(stderr, ysize, t2);
|
|
#endif
|
|
fprintf(stderr, " t3: "), mpfprintln(stderr, ysize, t3);
|
|
/*@=modfilesys@*/
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
#endif
|
|
|
|
/**
|
|
* needs workspace of (7*size+2) words
|
|
*/
|
|
int mpbpprime_w(const mpbarrett* b, randomGeneratorContext* r, int t, mpw* wksp)
|
|
{
|
|
/*
|
|
* This test works for candidate probable primes >= 3, which are also not small primes.
|
|
*
|
|
* It assumes that b->modl contains the candidate prime
|
|
*
|
|
*/
|
|
|
|
size_t size = b->size;
|
|
|
|
/* first test if modl is odd */
|
|
|
|
if (mpodd(b->size, b->modl))
|
|
{
|
|
/*
|
|
* Small prime factor test:
|
|
*
|
|
* Tables in mpspprod contain multi-precision integers with products of small primes
|
|
* If the greatest common divisor of this product and the candidate is not one, then
|
|
* the candidate has small prime factors, or is a small prime. Neither is acceptable when
|
|
* we are looking for large probable primes =)
|
|
*
|
|
*/
|
|
|
|
if (size > SMALL_PRIMES_PRODUCT_MAX)
|
|
{
|
|
/*@-globs@*/
|
|
mpsetx(size, wksp+size, SMALL_PRIMES_PRODUCT_MAX, mpspprod[SMALL_PRIMES_PRODUCT_MAX-1]);
|
|
/*@=globs@*/
|
|
/*@-compdef@*/ /* LCL: wksp+size */
|
|
mpgcd_w(size, b->modl, wksp+size, wksp, wksp+2*size);
|
|
/*@=compdef@*/
|
|
}
|
|
else
|
|
{
|
|
/*@-globs@*/
|
|
mpgcd_w(size, b->modl, mpspprod[size-1], wksp, wksp+2*size);
|
|
/*@=globs@*/
|
|
}
|
|
|
|
if (mpisone(size, wksp))
|
|
{
|
|
return mppmilrab_w(b, r, t, wksp);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void mpbnrnd(const mpbarrett* b, randomGeneratorContext* rc, mpnumber* result)
|
|
{
|
|
register size_t size = b->size;
|
|
register mpw* temp = (mpw*) malloc(size * sizeof(*temp));
|
|
|
|
assert(temp != NULL);
|
|
mpnfree(result);
|
|
mpnsize(result, size);
|
|
/*@-usedef@*/ /* result->data unallocated? */
|
|
mpbrnd_w(b, rc, result->data, temp);
|
|
/*@=usedef@*/
|
|
|
|
free(temp);
|
|
}
|
|
|
|
void mpbnmulmod(const mpbarrett* b, const mpnumber* x, const mpnumber* y, mpnumber* result)
|
|
{
|
|
register size_t size = b->size;
|
|
register mpw* temp = (mpw*) malloc((4*size+2) * sizeof(*temp));
|
|
|
|
/* xsize and ysize must be <= b->size */
|
|
register size_t fill = 2*size-x->size-y->size;
|
|
register mpw* opnd;
|
|
|
|
assert(temp != NULL);
|
|
opnd = temp + size*2+2;
|
|
|
|
mpnfree(result);
|
|
mpnsize(result, size);
|
|
|
|
if (fill)
|
|
mpzero(fill, opnd);
|
|
|
|
mpmul(opnd+fill, x->size, x->data, y->size, y->data);
|
|
/*@-usedef -compdef @*/ /* result->data unallocated? */
|
|
mpbmod_w(b, opnd, result->data, temp);
|
|
/*@=usedef =compdef @*/
|
|
|
|
free(temp);
|
|
}
|
|
|
|
void mpbnsqrmod(const mpbarrett* b, const mpnumber* x, mpnumber* result)
|
|
{
|
|
register size_t size = b->size;
|
|
register mpw* temp = (mpw*) malloc(size * sizeof(*temp));
|
|
|
|
/* xsize must be <= b->size */
|
|
register size_t fill = 2*(size-x->size);
|
|
register mpw* opnd;
|
|
|
|
assert(temp != NULL);
|
|
opnd = temp + size*2+2;
|
|
|
|
if (fill)
|
|
mpzero(fill, opnd);
|
|
|
|
mpsqr(opnd+fill, x->size, x->data);
|
|
mpnsize(result, size);
|
|
/*@-usedef -compdef @*/ /* result->data unallocated? */
|
|
mpbmod_w(b, opnd, result->data, temp);
|
|
/*@=usedef =compdef @*/
|
|
|
|
free(temp);
|
|
}
|
|
|
|
void mpbnpowmod(const mpbarrett* b, const mpnumber* x, const mpnumber* pow, mpnumber* y)
|
|
{
|
|
register size_t size = b->size;
|
|
register mpw* temp = (mpw*) malloc((4*size+2) * sizeof(*temp));
|
|
|
|
assert(temp != NULL);
|
|
mpnfree(y);
|
|
mpnsize(y, size);
|
|
|
|
mpbpowmod_w(b, x->size, x->data, pow->size, pow->data, y->data, temp);
|
|
|
|
free(temp);
|
|
}
|
|
|
|
void mpbnpowmodsld(const mpbarrett* b, const mpw* slide, const mpnumber* pow, mpnumber* y)
|
|
{
|
|
register size_t size = b->size;
|
|
register mpw* temp = (mpw*) malloc((4*size+2) * sizeof(*temp));
|
|
|
|
assert(temp != NULL);
|
|
mpnfree(y);
|
|
mpnsize(y, size);
|
|
|
|
/*@-internalglobs -mods@*/ /* noisy */
|
|
mpbpowmodsld_w(b, slide, pow->size, pow->data, y->data, temp);
|
|
/*@=internalglobs =mods@*/
|
|
|
|
free(temp);
|
|
}
|