freeswitch/libs/libzrtp/third_party/bnlib/bn64.c

1183 lines
28 KiB
C

/*
* Copyright (c) 1995 Colin Plumb. All rights reserved.
* For licensing and other legal details, see the file legal.c.
*
* bn64.c - the high-level bignum interface
*
* Like lbn64.c, this reserves the string "64" for textual replacement.
* The string must not appear anywhere unless it is intended to be replaced
* to generate other bignum interface functions.
*/
#ifndef HAVE_CONFIG_H
#define HAVE_CONFIG_H 0
#endif
#if HAVE_CONFIG_H
#include "bnconfig.h"
#endif
/*
* Some compilers complain about #if FOO if FOO isn't defined,
* so do the ANSI-mandated thing explicitly...
*/
#ifndef NO_ASSERT_H
#define NO_ASSERT_H 0
#endif
#ifndef NO_STRING_H
#define NO_STRING_H 0
#endif
#ifndef HAVE_STRINGS_H
#define HAVE_STRINGS_H 0
#endif
#if !NO_ASSERT_H
#include <assert.h>
#else
#define assert(x) (void)0
#endif
#if !NO_STRING_H
#include <string.h> /* for memmove() in bnMakeOdd */
#elif HAVE_STRINGS_H
#include <strings.h>
#endif
/*
* This was useful during debugging, so it's left in here.
* You can ignore it. DBMALLOC is generally undefined.
*/
#ifndef DBMALLOC
#define DBMALLOC 0
#endif
#if DBMALLOC
#include "../dbmalloc/malloc.h"
#define MALLOCDB malloc_chain_check(1)
#else
#define MALLOCDB (void)0
#endif
#include "lbn.h"
#include "lbn64.h"
#include "lbnmem.h"
#include "bn64.h"
#include "bn.h"
/* Work-arounds for some particularly broken systems */
#include "kludge.h" /* For memmove() */
/* Functions */
void
bnInit_64(void)
{
bnEnd = bnEnd_64;
bnPrealloc = bnPrealloc_64;
bnCopy = bnCopy_64;
bnNorm = bnNorm_64;
bnExtractBigBytes = bnExtractBigBytes_64;
bnInsertBigBytes = bnInsertBigBytes_64;
bnExtractLittleBytes = bnExtractLittleBytes_64;
bnInsertLittleBytes = bnInsertLittleBytes_64;
bnLSWord = bnLSWord_64;
bnReadBit = bnReadBit_64;
bnBits = bnBits_64;
bnAdd = bnAdd_64;
bnSub = bnSub_64;
bnCmpQ = bnCmpQ_64;
bnSetQ = bnSetQ_64;
bnAddQ = bnAddQ_64;
bnSubQ = bnSubQ_64;
bnCmp = bnCmp_64;
bnSquare = bnSquare_64;
bnMul = bnMul_64;
bnMulQ = bnMulQ_64;
bnDivMod = bnDivMod_64;
bnMod = bnMod_64;
bnModQ = bnModQ_64;
bnExpMod = bnExpMod_64;
bnDoubleExpMod = bnDoubleExpMod_64;
bnTwoExpMod = bnTwoExpMod_64;
bnGcd = bnGcd_64;
bnInv = bnInv_64;
bnLShift = bnLShift_64;
bnRShift = bnRShift_64;
bnMakeOdd = bnMakeOdd_64;
bnBasePrecompBegin = bnBasePrecompBegin_64;
bnBasePrecompEnd = bnBasePrecompEnd_64;
bnBasePrecompExpMod = bnBasePrecompExpMod_64;
bnDoubleBasePrecompExpMod = bnDoubleBasePrecompExpMod_64;
}
void
bnEnd_64(struct BigNum *bn)
{
if (bn->ptr) {
LBNFREE((BNWORD64 *)bn->ptr, bn->allocated);
bn->ptr = 0;
}
bn->size = 0;
bn->allocated = 0;
MALLOCDB;
}
/* Internal function. It operates in words. */
static int
bnResize_64(struct BigNum *bn, unsigned len)
{
void *p;
/* Round size up: most mallocs impose 8-byte granularity anyway */
len = (len + (8/sizeof(BNWORD64) - 1)) & ~(8/sizeof(BNWORD64) - 1);
p = LBNREALLOC((BNWORD64 *)bn->ptr, bn->allocated, len);
if (!p)
return -1;
bn->ptr = p;
bn->allocated = len;
MALLOCDB;
return 0;
}
#define bnSizeCheck(bn, size) \
if (bn->allocated < size && bnResize_64(bn, size) < 0) \
return -1
/* Preallocate enough space in bn to hold "bits" bits. */
int
bnPrealloc_64(struct BigNum *bn, unsigned bits)
{
bits = (bits + 64-1)/64;
bnSizeCheck(bn, bits);
MALLOCDB;
return 0;
}
int
bnCopy_64(struct BigNum *dest, struct BigNum const *src)
{
bnSizeCheck(dest, src->size);
dest->size = src->size;
lbnCopy_64((BNWORD64 *)dest->ptr, (BNWORD64 *)src->ptr, src->size);
MALLOCDB;
return 0;
}
/* Is this ever needed? Normalize the bn by deleting high-order 0 words */
void
bnNorm_64(struct BigNum *bn)
{
bn->size = lbnNorm_64((BNWORD64 *)bn->ptr, bn->size);
}
/*
* Convert a bignum to big-endian bytes. Returns, in big-endian form, a
* substring of the bignum starting from lsbyte and "len" bytes long.
* Unused high-order (leading) bytes are filled with 0.
*/
void
bnExtractBigBytes_64(struct BigNum const *bn, unsigned char *dest,
unsigned lsbyte, unsigned len)
{
unsigned s = bn->size * (64 / 8);
/* Fill unused leading bytes with 0 */
while (s < lsbyte + len) {
*dest++ = 0;
len--;
}
if (len)
lbnExtractBigBytes_64((BNWORD64 *)bn->ptr, dest, lsbyte, len);
MALLOCDB;
}
/* The inverse of the above. */
int
bnInsertBigBytes_64(struct BigNum *bn, unsigned char const *src,
unsigned lsbyte, unsigned len)
{
unsigned s = bn->size;
unsigned words = (len+lsbyte+sizeof(BNWORD64)-1) / sizeof(BNWORD64);
/* Pad with zeros as required */
bnSizeCheck(bn, words);
if (s < words) {
lbnZero_64((BNWORD64 *)bn->ptr BIGLITTLE(-s,+s), words-s);
s = words;
}
lbnInsertBigBytes_64((BNWORD64 *)bn->ptr, src, lsbyte, len);
bn->size = lbnNorm_64((BNWORD64 *)bn->ptr, s);
MALLOCDB;
return 0;
}
/*
* Convert a bignum to little-endian bytes. Returns, in little-endian form, a
* substring of the bignum starting from lsbyte and "len" bytes long.
* Unused high-order (trailing) bytes are filled with 0.
*/
void
bnExtractLittleBytes_64(struct BigNum const *bn, unsigned char *dest,
unsigned lsbyte, unsigned len)
{
unsigned s = bn->size * (64 / 8);
/* Fill unused leading bytes with 0 */
while (s < lsbyte + len)
dest[--len] = 0;
if (len)
lbnExtractLittleBytes_64((BNWORD64 *)bn->ptr, dest,
lsbyte, len);
MALLOCDB;
}
/* The inverse of the above */
int
bnInsertLittleBytes_64(struct BigNum *bn, unsigned char const *src,
unsigned lsbyte, unsigned len)
{
unsigned s = bn->size;
unsigned words = (len+lsbyte+sizeof(BNWORD64)-1) / sizeof(BNWORD64);
/* Pad with zeros as required */
bnSizeCheck(bn, words);
if (s < words) {
lbnZero_64((BNWORD64 *)bn->ptr BIGLITTLE(-s,+s), words-s);
s = words;
}
lbnInsertLittleBytes_64((BNWORD64 *)bn->ptr, src, lsbyte, len);
bn->size = lbnNorm_64((BNWORD64 *)bn->ptr, s);
MALLOCDB;
return 0;
}
/* Return the least-significant word of the input. */
unsigned
bnLSWord_64(struct BigNum const *bn)
{
return bn->size ? (unsigned)((BNWORD64 *)bn->ptr)[BIGLITTLE(-1,0)]: 0;
}
/* Return a selected bit of the data */
int
bnReadBit_64(struct BigNum const *bn, unsigned bit)
{
BNWORD64 word;
if (bit/64 >= bn->size)
return 0;
word = ((BNWORD64 *)bn->ptr)[BIGLITTLE(-1-bit/64,bit/64)];
return (int)(word >> (bit % 64) & 1);
}
/* Count the number of significant bits. */
unsigned
bnBits_64(struct BigNum const *bn)
{
return lbnBits_64((BNWORD64 *)bn->ptr, bn->size);
}
/* dest += src */
int
bnAdd_64(struct BigNum *dest, struct BigNum const *src)
{
unsigned s = src->size, d = dest->size;
BNWORD64 t;
if (!s)
return 0;
bnSizeCheck(dest, s);
if (d < s) {
lbnZero_64((BNWORD64 *)dest->ptr BIGLITTLE(-d,+d), s-d);
dest->size = d = s;
MALLOCDB;
}
t = lbnAddN_64((BNWORD64 *)dest->ptr, (BNWORD64 *)src->ptr, s);
MALLOCDB;
if (t) {
if (d > s) {
t = lbnAdd1_64((BNWORD64 *)dest->ptr BIGLITTLE(-s,+s),
d-s, t);
MALLOCDB;
}
if (t) {
bnSizeCheck(dest, d+1);
((BNWORD64 *)dest->ptr)[BIGLITTLE(-1-d,d)] = t;
dest->size = d+1;
}
}
return 0;
}
/*
* dest -= src.
* If dest goes negative, this produces the absolute value of
* the difference (the negative of the true value) and returns 1.
* Otherwise, it returls 0.
*/
int
bnSub_64(struct BigNum *dest, struct BigNum const *src)
{
unsigned s = src->size, d = dest->size;
BNWORD64 t;
if (d < s && d < (s = lbnNorm_64((BNWORD64 *)src->ptr, s))) {
bnSizeCheck(dest, s);
lbnZero_64((BNWORD64 *)dest->ptr BIGLITTLE(-d,+d), s-d);
dest->size = d = s;
MALLOCDB;
}
if (!s)
return 0;
t = lbnSubN_64((BNWORD64 *)dest->ptr, (BNWORD64 *)src->ptr, s);
MALLOCDB;
if (t) {
if (d > s) {
t = lbnSub1_64((BNWORD64 *)dest->ptr BIGLITTLE(-s,+s),
d-s, t);
MALLOCDB;
}
if (t) {
lbnNeg_64((BNWORD64 *)dest->ptr, d);
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr,
dest->size);
MALLOCDB;
return 1;
}
}
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, dest->size);
return 0;
}
/*
* Compare the BigNum to the given value, which must be < 65536.
* Returns -1. 0 or 1 if a<b, a == b or a>b.
* a <=> b --> bnCmpQ(a,b) <=> 0
*/
int
bnCmpQ_64(struct BigNum const *a, unsigned b)
{
unsigned t;
BNWORD64 v;
t = lbnNorm_64((BNWORD64 *)a->ptr, a->size);
/* If a is more than one word long or zero, it's easy... */
if (t != 1)
return (t > 1) ? 1 : (b ? -1 : 0);
v = (unsigned)((BNWORD64 *)a->ptr)[BIGLITTLE(-1,0)];
return (v > b) ? 1 : ((v < b) ? -1 : 0);
}
/* Set dest to a small value */
int
bnSetQ_64(struct BigNum *dest, unsigned src)
{
if (src) {
bnSizeCheck(dest, 1);
((BNWORD64 *)dest->ptr)[BIGLITTLE(-1,0)] = (BNWORD64)src;
dest->size = 1;
} else {
dest->size = 0;
}
return 0;
}
/* dest += src */
int
bnAddQ_64(struct BigNum *dest, unsigned src)
{
BNWORD64 t;
if (!dest->size)
return bnSetQ(dest, src);
t = lbnAdd1_64((BNWORD64 *)dest->ptr, dest->size, (BNWORD64)src);
MALLOCDB;
if (t) {
src = dest->size;
bnSizeCheck(dest, src+1);
((BNWORD64 *)dest->ptr)[BIGLITTLE(-1-src,src)] = t;
dest->size = src+1;
}
return 0;
}
/*
* Return value as for bnSub: 1 if subtract underflowed, in which
* case the return is the negative of the computed value.
*/
int
bnSubQ_64(struct BigNum *dest, unsigned src)
{
BNWORD64 t;
if (!dest->size)
return bnSetQ(dest, src) < 0 ? -1 : (src != 0);
t = lbnSub1_64((BNWORD64 *)dest->ptr, dest->size, src);
MALLOCDB;
if (t) {
/* Underflow. <= 1 word, so do it simply. */
lbnNeg_64((BNWORD64 *)dest->ptr, 1);
dest->size = 1;
return 1;
}
/* Try to normalize? Needing this is going to be pretty damn rare. */
/* dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, dest->size); */
return 0;
}
/*
* Compare two BigNums. Returns -1. 0 or 1 if a<b, a == b or a>b.
* a <=> b --> bnCmp(a,b) <=> 0
*/
int
bnCmp_64(struct BigNum const *a, struct BigNum const *b)
{
unsigned s, t;
s = lbnNorm_64((BNWORD64 *)a->ptr, a->size);
t = lbnNorm_64((BNWORD64 *)b->ptr, b->size);
if (s != t)
return s > t ? 1 : -1;
return lbnCmp_64((BNWORD64 *)a->ptr, (BNWORD64 *)b->ptr, s);
}
/* dest = src*src. This is more efficient than bnMul. */
int
bnSquare_64(struct BigNum *dest, struct BigNum const *src)
{
unsigned s;
BNWORD64 *srcbuf;
s = lbnNorm_64((BNWORD64 *)src->ptr, src->size);
if (!s) {
dest->size = 0;
return 0;
}
bnSizeCheck(dest, 2*s);
if (src == dest) {
LBNALLOC(srcbuf, BNWORD64, s);
if (!srcbuf)
return -1;
lbnCopy_64(srcbuf, (BNWORD64 *)src->ptr, s);
lbnSquare_64((BNWORD64 *)dest->ptr, (BNWORD64 *)srcbuf, s);
LBNFREE(srcbuf, s);
} else {
lbnSquare_64((BNWORD64 *)dest->ptr, (BNWORD64 *)src->ptr, s);
}
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, 2*s);
MALLOCDB;
return 0;
}
/* dest = a * b. Any overlap between operands is allowed. */
int
bnMul_64(struct BigNum *dest, struct BigNum const *a, struct BigNum const *b)
{
unsigned s, t;
BNWORD64 *srcbuf;
s = lbnNorm_64((BNWORD64 *)a->ptr, a->size);
t = lbnNorm_64((BNWORD64 *)b->ptr, b->size);
if (!s || !t) {
dest->size = 0;
return 0;
}
if (a == b)
return bnSquare_64(dest, a);
bnSizeCheck(dest, s+t);
if (dest == a) {
LBNALLOC(srcbuf, BNWORD64, s);
if (!srcbuf)
return -1;
lbnCopy_64(srcbuf, (BNWORD64 *)a->ptr, s);
lbnMul_64((BNWORD64 *)dest->ptr, srcbuf, s,
(BNWORD64 *)b->ptr, t);
LBNFREE(srcbuf, s);
} else if (dest == b) {
LBNALLOC(srcbuf, BNWORD64, t);
if (!srcbuf)
return -1;
lbnCopy_64(srcbuf, (BNWORD64 *)b->ptr, t);
lbnMul_64((BNWORD64 *)dest->ptr, (BNWORD64 *)a->ptr, s,
srcbuf, t);
LBNFREE(srcbuf, t);
} else {
lbnMul_64((BNWORD64 *)dest->ptr, (BNWORD64 *)a->ptr, s,
(BNWORD64 *)b->ptr, t);
}
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, s+t);
MALLOCDB;
return 0;
}
/* dest = a * b */
int
bnMulQ_64(struct BigNum *dest, struct BigNum const *a, unsigned b)
{
unsigned s;
s = lbnNorm_64((BNWORD64 *)a->ptr, a->size);
if (!s || !b) {
dest->size = 0;
return 0;
}
if (b == 1)
return bnCopy_64(dest, a);
bnSizeCheck(dest, s+1);
lbnMulN1_64((BNWORD64 *)dest->ptr, (BNWORD64 *)a->ptr, s, b);
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, s+1);
MALLOCDB;
return 0;
}
/* q = n/d, r = n % d */
int
bnDivMod_64(struct BigNum *q, struct BigNum *r, struct BigNum const *n,
struct BigNum const *d)
{
unsigned dsize, nsize;
BNWORD64 qhigh;
dsize = lbnNorm_64((BNWORD64 *)d->ptr, d->size);
nsize = lbnNorm_64((BNWORD64 *)n->ptr, n->size);
if (nsize < dsize) {
q->size = 0; /* No quotient */
r->size = nsize;
return 0; /* Success */
}
bnSizeCheck(q, nsize-dsize);
if (r != n) { /* You are allowed to reduce in place */
bnSizeCheck(r, nsize);
lbnCopy_64((BNWORD64 *)r->ptr, (BNWORD64 *)n->ptr, nsize);
}
qhigh = lbnDiv_64((BNWORD64 *)q->ptr, (BNWORD64 *)r->ptr, nsize,
(BNWORD64 *)d->ptr, dsize);
nsize -= dsize;
if (qhigh) {
bnSizeCheck(q, nsize+1);
*((BNWORD64 *)q->ptr BIGLITTLE(-nsize-1,+nsize)) = qhigh;
q->size = nsize+1;
} else {
q->size = lbnNorm_64((BNWORD64 *)q->ptr, nsize);
}
r->size = lbnNorm_64((BNWORD64 *)r->ptr, dsize);
MALLOCDB;
return 0;
}
/* det = src % d */
int
bnMod_64(struct BigNum *dest, struct BigNum const *src, struct BigNum const *d)
{
unsigned dsize, nsize;
nsize = lbnNorm_64((BNWORD64 *)src->ptr, src->size);
dsize = lbnNorm_64((BNWORD64 *)d->ptr, d->size);
if (dest != src) {
bnSizeCheck(dest, nsize);
lbnCopy_64((BNWORD64 *)dest->ptr, (BNWORD64 *)src->ptr, nsize);
}
if (nsize < dsize) {
dest->size = nsize; /* No quotient */
return 0;
}
(void)lbnDiv_64((BNWORD64 *)dest->ptr BIGLITTLE(-dsize,+dsize),
(BNWORD64 *)dest->ptr, nsize,
(BNWORD64 *)d->ptr, dsize);
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, dsize);
MALLOCDB;
return 0;
}
/* return src % d. */
unsigned
bnModQ_64(struct BigNum const *src, unsigned d)
{
unsigned s;
s = lbnNorm_64((BNWORD64 *)src->ptr, src->size);
if (!s)
return 0;
if (d & (d-1)) /* Not a power of 2 */
d = lbnModQ_64((BNWORD64 *)src->ptr, s, d);
else
d = (unsigned)((BNWORD64 *)src->ptr)[BIGLITTLE(-1,0)] & (d-1);
return d;
}
/* dest = n^exp (mod mod) */
int
bnExpMod_64(struct BigNum *dest, struct BigNum const *n,
struct BigNum const *exp, struct BigNum const *mod)
{
unsigned nsize, esize, msize;
nsize = lbnNorm_64((BNWORD64 *)n->ptr, n->size);
esize = lbnNorm_64((BNWORD64 *)exp->ptr, exp->size);
msize = lbnNorm_64((BNWORD64 *)mod->ptr, mod->size);
if (!msize || (((BNWORD64 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
return -1; /* Illegal modulus! */
bnSizeCheck(dest, msize);
/* Special-case base of 2 */
if (nsize == 1 && ((BNWORD64 *)n->ptr)[BIGLITTLE(-1,0)] == 2) {
if (lbnTwoExpMod_64((BNWORD64 *)dest->ptr,
(BNWORD64 *)exp->ptr, esize,
(BNWORD64 *)mod->ptr, msize) < 0)
return -1;
} else {
if (lbnExpMod_64((BNWORD64 *)dest->ptr,
(BNWORD64 *)n->ptr, nsize,
(BNWORD64 *)exp->ptr, esize,
(BNWORD64 *)mod->ptr, msize) < 0)
return -1;
}
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, msize);
MALLOCDB;
return 0;
}
/*
* dest = n1^e1 * n2^e2 (mod mod). This is more efficient than two
* separate modular exponentiations, and in fact asymptotically approaches
* the cost of one.
*/
int
bnDoubleExpMod_64(struct BigNum *dest,
struct BigNum const *n1, struct BigNum const *e1,
struct BigNum const *n2, struct BigNum const *e2,
struct BigNum const *mod)
{
unsigned n1size, e1size, n2size, e2size, msize;
n1size = lbnNorm_64((BNWORD64 *)n1->ptr, n1->size);
e1size = lbnNorm_64((BNWORD64 *)e1->ptr, e1->size);
n2size = lbnNorm_64((BNWORD64 *)n2->ptr, n2->size);
e2size = lbnNorm_64((BNWORD64 *)e2->ptr, e2->size);
msize = lbnNorm_64((BNWORD64 *)mod->ptr, mod->size);
if (!msize || (((BNWORD64 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
return -1; /* Illegal modulus! */
bnSizeCheck(dest, msize);
if (lbnDoubleExpMod_64((BNWORD64 *)dest->ptr,
(BNWORD64 *)n1->ptr, n1size, (BNWORD64 *)e1->ptr, e1size,
(BNWORD64 *)n2->ptr, n2size, (BNWORD64 *)e2->ptr, e2size,
(BNWORD64 *)mod->ptr, msize) < 0)
return -1;
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, msize);
MALLOCDB;
return 0;
}
/* n = 2^exp (mod mod) */
int
bnTwoExpMod_64(struct BigNum *n, struct BigNum const *exp,
struct BigNum const *mod)
{
unsigned esize, msize;
esize = lbnNorm_64((BNWORD64 *)exp->ptr, exp->size);
msize = lbnNorm_64((BNWORD64 *)mod->ptr, mod->size);
if (!msize || (((BNWORD64 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
return -1; /* Illegal modulus! */
bnSizeCheck(n, msize);
if (lbnTwoExpMod_64((BNWORD64 *)n->ptr, (BNWORD64 *)exp->ptr, esize,
(BNWORD64 *)mod->ptr, msize) < 0)
return -1;
n->size = lbnNorm_64((BNWORD64 *)n->ptr, msize);
MALLOCDB;
return 0;
}
/* dest = gcd(a, b) */
int
bnGcd_64(struct BigNum *dest, struct BigNum const *a, struct BigNum const *b)
{
BNWORD64 *tmp;
unsigned asize, bsize;
int i;
/* Kind of silly, but we might as well permit it... */
if (a == b)
return dest == a ? 0 : bnCopy(dest, a);
/* Ensure a is not the same as "dest" */
if (a == dest) {
a = b;
b = dest;
}
asize = lbnNorm_64((BNWORD64 *)a->ptr, a->size);
bsize = lbnNorm_64((BNWORD64 *)b->ptr, b->size);
bnSizeCheck(dest, bsize+1);
/* Copy a to tmp */
LBNALLOC(tmp, BNWORD64, asize+1);
if (!tmp)
return -1;
lbnCopy_64(tmp, (BNWORD64 *)a->ptr, asize);
/* Copy b to dest, if necessary */
if (dest != b)
lbnCopy_64((BNWORD64 *)dest->ptr,
(BNWORD64 *)b->ptr, bsize);
if (bsize > asize || (bsize == asize &&
lbnCmp_64((BNWORD64 *)b->ptr, (BNWORD64 *)a->ptr, asize) > 0))
{
i = lbnGcd_64((BNWORD64 *)dest->ptr, bsize, tmp, asize,
&dest->size);
if (i > 0) /* Result in tmp, not dest */
lbnCopy_64((BNWORD64 *)dest->ptr, tmp, dest->size);
} else {
i = lbnGcd_64(tmp, asize, (BNWORD64 *)dest->ptr, bsize,
&dest->size);
if (i == 0) /* Result in tmp, not dest */
lbnCopy_64((BNWORD64 *)dest->ptr, tmp, dest->size);
}
LBNFREE(tmp, asize+1);
MALLOCDB;
return (i < 0) ? i : 0;
}
/*
* dest = 1/src (mod mod). Returns >0 if gcd(src, mod) != 1 (in which case
* the inverse does not exist).
*/
int
bnInv_64(struct BigNum *dest, struct BigNum const *src,
struct BigNum const *mod)
{
unsigned s, m;
int i;
s = lbnNorm_64((BNWORD64 *)src->ptr, src->size);
m = lbnNorm_64((BNWORD64 *)mod->ptr, mod->size);
/* lbnInv_64 requires that the input be less than the modulus */
if (m < s ||
(m==s && lbnCmp_64((BNWORD64 *)src->ptr, (BNWORD64 *)mod->ptr, s)))
{
bnSizeCheck(dest, s + (m==s));
if (dest != src)
lbnCopy_64((BNWORD64 *)dest->ptr,
(BNWORD64 *)src->ptr, s);
/* Pre-reduce modulo the modulus */
(void)lbnDiv_64((BNWORD64 *)dest->ptr BIGLITTLE(-m,+m),
(BNWORD64 *)dest->ptr, s,
(BNWORD64 *)mod->ptr, m);
s = lbnNorm_64((BNWORD64 *)dest->ptr, m);
MALLOCDB;
} else {
bnSizeCheck(dest, m+1);
if (dest != src)
lbnCopy_64((BNWORD64 *)dest->ptr,
(BNWORD64 *)src->ptr, s);
}
i = lbnInv_64((BNWORD64 *)dest->ptr, s, (BNWORD64 *)mod->ptr, m);
if (i == 0)
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, m);
MALLOCDB;
return i;
}
/*
* Shift a bignum left the appropriate number of bits,
* multiplying by 2^amt.
*/
int
bnLShift_64(struct BigNum *dest, unsigned amt)
{
unsigned s = dest->size;
BNWORD64 carry;
if (amt % 64) {
carry = lbnLshift_64((BNWORD64 *)dest->ptr, s, amt % 64);
if (carry) {
s++;
bnSizeCheck(dest, s);
((BNWORD64 *)dest->ptr)[BIGLITTLE(-s,s-1)] = carry;
}
}
amt /= 64;
if (amt) {
bnSizeCheck(dest, s+amt);
memmove((BNWORD64 *)dest->ptr BIGLITTLE(-s-amt, +amt),
(BNWORD64 *)dest->ptr BIG(-s),
s * sizeof(BNWORD64));
lbnZero_64((BNWORD64 *)dest->ptr, amt);
s += amt;
}
dest->size = s;
MALLOCDB;
return 0;
}
/*
* Shift a bignum right the appropriate number of bits,
* dividing by 2^amt.
*/
void
bnRShift_64(struct BigNum *dest, unsigned amt)
{
unsigned s = dest->size;
if (amt >= 64) {
memmove(
(BNWORD64 *)dest->ptr BIG(-s+amt/64),
(BNWORD64 *)dest->ptr BIGLITTLE(-s, +amt/64),
(s-amt/64) * sizeof(BNWORD64));
s -= amt/64;
amt %= 64;
}
if (amt)
(void)lbnRshift_64((BNWORD64 *)dest->ptr, s, amt);
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, s);
MALLOCDB;
}
/*
* Shift a bignum right until it is odd, and return the number of
* bits shifted. n = d * 2^s. Replaces n with d and returns s.
* Returns 0 when given 0. (Another valid answer is infinity.)
*/
unsigned
bnMakeOdd_64(struct BigNum *n)
{
unsigned size;
unsigned s; /* shift amount */
BNWORD64 *p;
BNWORD64 t;
p = (BNWORD64 *)n->ptr;
size = lbnNorm_64(p, n->size);
if (!size)
return 0;
t = BIGLITTLE(p[-1],p[0]);
s = 0;
/* See how many words we have to shift */
if (!t) {
/* Shift by words */
do {
s++;
BIGLITTLE(--p,p++);
} while ((t = BIGLITTLE(p[-1],p[0])) == 0);
size -= s;
s *= 64;
memmove((BNWORD64 *)n->ptr BIG(-size), p BIG(-size),
size * sizeof(BNWORD64));
p = (BNWORD64 *)n->ptr;
MALLOCDB;
}
assert(t);
if (!(t & 1)) {
/* Now count the bits */
do {
t >>= 1;
s++;
} while ((t & 1) == 0);
/* Shift the bits */
lbnRshift_64(p, size, s & (64-1));
/* Renormalize */
if (BIGLITTLE(*(p-size),*(p+(size-1))) == 0)
--size;
}
n->size = size;
MALLOCDB;
return s;
}
/*
* Do base- and modulus-dependent precomputation for rapid computation of
* base^exp (mod mod) with various exponents.
*
* See lbn64.c for the details on how the algorithm works. Basically,
* it involves precomputing a table of powers of base, base^(order^k),
* for a suitable range 0 <= k < n detemined by the maximum exponent size
* desired. To do eht exponentiation, the exponent is expressed in base
* "order" (sorry for the confusing terminology) and the precomputed powers
* are combined.
*
* This implementation allows only power-of-2 values for "order". Using
* other numbers can be more efficient, but it's more work and for the
* popular exponent size of 640 bits, an order of 8 is optimal, so it
* hasn't seemed worth it to implement.
*
* Here's a table of the optimal power-of-2 order for various exponent
* sizes and the associated (average) cost for an exponentiation.
* Note that *higher* orders are more memory-efficient; the number
* of precomputed values required is ceil(ebits/order). (Ignore the
* underscores in the middle of numbers; they're harmless.)
*
* At 2 bits, order 2 uses 0.000000 multiplies
* At 4 bits, order 2 uses 1.000000 multiplies
* At 8 bits, order 2 uses 3.000000 multiplies
* At 1_6 bits, order 2 uses 7.000000 multiplies
* At 3_2 bits, order 2 uses 15.000000 multiplies
* At 34 bits, 15.750000 (order 4) < 1_6.000000 (order 2)
* At 6_4 bits, order 4 uses 27.000000 multiplies
* At 99 bits, 39.875000 (order 8) < 40.250000 (order 4)
* At 128 bits, order 8 uses 48.500000 multiplies
* At 256 bits, order 8 uses 85.875000 multiplies
* At 280 bits, 92.625000 (order 1_6) < 92.875000 (order 8)
* At 512 bits, order 1_6 uses 147.000000 multiplies
* At 785 bits, 211.093750 (order 3_2) < 211.250000 (order 1_6)
* At 1024 bits, order 3_2 uses 257.562500 multiplies
* At 2048 bits, order 3_2 uses 456.093750 multiplies
* At 2148 bits, 475.406250 (order 6_4) < 475.468750 (order 3_2)
* At 4096 bits, order 6_4 uses 795.281250 multiplies
* At 5726 bits, 1062.609375 (order 128) < 1062.843750 (order 6_4)
* At 8192 bits, order 128 uses 1412.609375 multiplies
* At 14848 bits, 2355.750000 (order 256) < 2355.929688 (order 128)
* At 37593 bits, 5187.841797 (order 512) < 5188.144531 (order 256)
*/
int
bnBasePrecompBegin_64(struct BnBasePrecomp *pre, struct BigNum const *base,
struct BigNum const *mod, unsigned maxebits)
{
int i;
BNWORD64 **array; /* Array of precomputed powers of base */
unsigned n; /* Number of entries in array (needed) */
unsigned m; /* Number of entries in array (non-NULL) */
unsigned arraysize; /* Number of entries in array (allocated) */
unsigned bits; /* log2(order) */
unsigned msize = lbnNorm_64((BNWORD64 *)mod->ptr, mod->size);
static unsigned const bnBasePrecompThreshTable[] = {
33, 98, 279, 784, 2147, 5725, 14847, 37592, (unsigned)-1
};
/* Clear pre in case of failure */
pre->array = 0;
pre->msize = 0;
pre->bits = 0;
pre->maxebits = 0;
pre->arraysize = 0;
pre->entries = 0;
/* Find the correct bit-window size */
bits = 0;
do
bits++;
while (maxebits > bnBasePrecompThreshTable[bits]);
/* Now the number of precomputed values we need */
n = (maxebits+bits-1)/bits;
assert(n*bits >= maxebits);
arraysize = n+1; /* Add one trailing NULL for safety */
array = lbnMemAlloc(arraysize * sizeof(*array));
if (!array)
return -1; /* Out of memory */
/* Now allocate the entries (precomputed powers of base) */
for (m = 0; m < n; m++) {
BNWORD64 *entry;
LBNALLOC(entry, BNWORD64, msize);
if (!entry)
break;
array[m] = entry;
}
/* "m" is the number of successfully allocated entries */
if (m < n) {
/* Ran out of memory; see if we can use a smaller array */
BNWORD64 **newarray;
if (m < 2) {
n = 0; /* Forget it */
} else {
/* How few bits can we use with what's allocated? */
bits = (maxebits + m - 1) / m;
retry:
n = (maxebits + bits - 1) / bits;
if (! (n >> bits) )
n = 0; /* Not enough to amount to anything */
}
/* Free excess allocated array entries */
while (m > n) {
BNWORD64 *entry = array[--m];
LBNFREE(entry, msize);
}
if (!n) {
/* Give it up */
lbnMemFree(array, arraysize * sizeof(*array));
return -1;
}
/*
* Try to shrink the pointer array. This might fail, but
* it's not critical. lbnMemRealloc isn't guarnateed to
* exist, so we may have to allocate, copy, and free.
*/
#ifdef lbnMemRealloc
newarray = lbnMemRealloc(array, arraysize * sizeof(*array),
(n+1) * sizeof(*array));
if (newarray) {
array = newarray;
arraysize = n+1;
}
#else
newarray = lbnMemAlloc((n+1) * sizeof(*array));
if (newarray) {
memcpy(newarray, array, n * sizeof(*array));
lbnMemFree(array, arraysize * sizeof(*array));
array = newarray;
arraysize = n+1;
}
#endif
}
/* Pad with null pointers */
while (m < arraysize)
array[m++] = 0;
/* Okay, we have our array, now initialize it */
i = lbnBasePrecompBegin_64(array, n, bits,
(BNWORD64 *)base->ptr, base->size,
(BNWORD64 *)mod->ptr, msize);
if (i < 0) {
/* Ack, still out of memory */
bits++;
m = n;
goto retry;
}
/* Finally, totoal success */
pre->array = array;
pre->bits = bits;
pre->msize = msize;
pre->maxebits = n * bits;
pre->arraysize = arraysize;
pre->entries = n;
return 0;
}
/* Free everything preallocated */
void
bnBasePrecompEnd_64(struct BnBasePrecomp *pre)
{
BNWORD64 **array = pre->array;
if (array) {
unsigned entries = pre->entries;
unsigned msize = pre->msize;
unsigned m;
for (m = 0; m < entries; m++) {
BNWORD64 *entry = array[m];
if (entry)
LBNFREE(entry, msize);
}
lbnMemFree(array, pre->arraysize * sizeof(array));
}
pre->array = 0;
pre->bits = 0;
pre->msize = 0;
pre->maxebits = 0;
pre->arraysize = 0;
pre->entries = 0;
}
int
bnBasePrecompExpMod_64(struct BigNum *dest, struct BnBasePrecomp const *pre,
struct BigNum const *exp, struct BigNum const *mod)
{
unsigned msize = lbnNorm_64((BNWORD64 *)mod->ptr, mod->size);
unsigned esize = lbnNorm_64((BNWORD64 *)exp->ptr, exp->size);
BNWORD64 const * const *array = pre->array;
int i;
assert(msize == pre->msize);
assert(((BNWORD64 *)mod->ptr)[BIGLITTLE(-1,0)] & 1);
assert(lbnBits_64((BNWORD64 *)exp->ptr, esize) <= pre->maxebits);
bnSizeCheck(dest, msize);
i = lbnBasePrecompExp_64(dest->ptr, array, pre->bits,
exp->ptr, esize, mod->ptr, msize);
if (i == 0)
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, msize);
return i;
}
int
bnDoubleBasePrecompExpMod_64(struct BigNum *dest,
struct BnBasePrecomp const *pre1, struct BigNum const *exp1,
struct BnBasePrecomp const *pre2, struct BigNum const *exp2,
struct BigNum const *mod)
{
unsigned msize = lbnNorm_64((BNWORD64 *)mod->ptr, mod->size);
unsigned e1size = lbnNorm_64((BNWORD64 *)exp1->ptr, exp1->size);
unsigned e2size = lbnNorm_64((BNWORD64 *)exp1->ptr, exp2->size);
BNWORD64 const * const *array1 = pre1->array;
BNWORD64 const * const *array2 = pre2->array;
int i;
assert(msize == pre1->msize);
assert(msize == pre2->msize);
assert(((BNWORD64 *)mod->ptr)[BIGLITTLE(-1,0)] & 1);
assert(lbnBits_64((BNWORD64 *)exp1->ptr, e1size) <= pre1->maxebits);
assert(lbnBits_64((BNWORD64 *)exp2->ptr, e2size) <= pre2->maxebits);
assert(pre1->bits == pre2->bits);
bnSizeCheck(dest, msize);
i = lbnDoubleBasePrecompExp_64(dest->ptr, pre1->bits, array1,
exp1->ptr, e1size, array2, exp2->ptr, e2size,
mod->ptr, msize);
if (i == 0)
dest->size = lbnNorm_64((BNWORD64 *)dest->ptr, msize);
return i;
}