Travis Cross d2edcad66e Merge Phil Zimmermann's libzrtp as a FreeSWITCH library
Thanks to Phil Zimmermann for the code and for the license exception
we needed to include it.

There remains some build system integration work to be done before
this code will build properly in the FreeSWITCH tree.
2012-03-31 23:42:27 +00:00

1189 lines
29 KiB
C

/*
* Copyright (c) 1995 Colin Plumb. All rights reserved.
* For licensing and other legal details, see the file legal.c.
*
* bn16.c - the high-level bignum interface
*
* Like lbn16.c, this reserves the string "16" 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
#ifndef NEED_MEMORY_H
#define NEED_MEMORY_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
#if NEED_MEMORY_H
#include <memory.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 "lbn16.h"
#include "lbnmem.h"
#include "bn16.h"
#include "bn.h"
/* Work-arounds for some particularly broken systems */
#include "kludge.h" /* For memmove() */
/* Functions */
void
bnInit_16(void)
{
bnEnd = bnEnd_16;
bnPrealloc = bnPrealloc_16;
bnCopy = bnCopy_16;
bnNorm = bnNorm_16;
bnExtractBigBytes = bnExtractBigBytes_16;
bnInsertBigBytes = bnInsertBigBytes_16;
bnExtractLittleBytes = bnExtractLittleBytes_16;
bnInsertLittleBytes = bnInsertLittleBytes_16;
bnLSWord = bnLSWord_16;
bnReadBit = bnReadBit_16;
bnBits = bnBits_16;
bnAdd = bnAdd_16;
bnSub = bnSub_16;
bnCmpQ = bnCmpQ_16;
bnSetQ = bnSetQ_16;
bnAddQ = bnAddQ_16;
bnSubQ = bnSubQ_16;
bnCmp = bnCmp_16;
bnSquare = bnSquare_16;
bnMul = bnMul_16;
bnMulQ = bnMulQ_16;
bnDivMod = bnDivMod_16;
bnMod = bnMod_16;
bnModQ = bnModQ_16;
bnExpMod = bnExpMod_16;
bnDoubleExpMod = bnDoubleExpMod_16;
bnTwoExpMod = bnTwoExpMod_16;
bnGcd = bnGcd_16;
bnInv = bnInv_16;
bnLShift = bnLShift_16;
bnRShift = bnRShift_16;
bnMakeOdd = bnMakeOdd_16;
bnBasePrecompBegin = bnBasePrecompBegin_16;
bnBasePrecompEnd = bnBasePrecompEnd_16;
bnBasePrecompExpMod = bnBasePrecompExpMod_16;
bnDoubleBasePrecompExpMod = bnDoubleBasePrecompExpMod_16;
}
void
bnEnd_16(struct BigNum *bn)
{
if (bn->ptr) {
LBNFREE((BNWORD16 *)bn->ptr, bn->allocated);
bn->ptr = 0;
}
bn->size = 0;
bn->allocated = 0;
MALLOCDB;
}
/* Internal function. It operates in words. */
static int
bnResize_16(struct BigNum *bn, unsigned len)
{
void *p;
/* Round size up: most mallocs impose 8-byte granularity anyway */
len = (len + (8/sizeof(BNWORD16) - 1)) & ~(8/sizeof(BNWORD16) - 1);
p = LBNREALLOC((BNWORD16 *)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_16(bn, size) < 0) \
return -1
/* Preallocate enough space in bn to hold "bits" bits. */
int
bnPrealloc_16(struct BigNum *bn, unsigned bits)
{
bits = (bits + 16-1)/16;
bnSizeCheck(bn, bits);
MALLOCDB;
return 0;
}
int
bnCopy_16(struct BigNum *dest, struct BigNum const *src)
{
bnSizeCheck(dest, src->size);
dest->size = src->size;
lbnCopy_16((BNWORD16 *)dest->ptr, (BNWORD16 *)src->ptr, src->size);
MALLOCDB;
return 0;
}
/* Is this ever needed? Normalize the bn by deleting high-order 0 words */
void
bnNorm_16(struct BigNum *bn)
{
bn->size = lbnNorm_16((BNWORD16 *)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_16(struct BigNum const *bn, unsigned char *dest,
unsigned lsbyte, unsigned len)
{
unsigned s = bn->size * (16 / 8);
/* Fill unused leading bytes with 0 */
while (s < lsbyte + len) {
*dest++ = 0;
len--;
}
if (len)
lbnExtractBigBytes_16((BNWORD16 *)bn->ptr, dest, lsbyte, len);
MALLOCDB;
}
/* The inverse of the above. */
int
bnInsertBigBytes_16(struct BigNum *bn, unsigned char const *src,
unsigned lsbyte, unsigned len)
{
unsigned s = bn->size;
unsigned words = (len+lsbyte+sizeof(BNWORD16)-1) / sizeof(BNWORD16);
/* Pad with zeros as required */
bnSizeCheck(bn, words);
if (s < words) {
lbnZero_16((BNWORD16 *)bn->ptr BIGLITTLE(-s,+s), words-s);
s = words;
}
lbnInsertBigBytes_16((BNWORD16 *)bn->ptr, src, lsbyte, len);
bn->size = lbnNorm_16((BNWORD16 *)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_16(struct BigNum const *bn, unsigned char *dest,
unsigned lsbyte, unsigned len)
{
unsigned s = bn->size * (16 / 8);
/* Fill unused leading bytes with 0 */
while (s < lsbyte + len)
dest[--len] = 0;
if (len)
lbnExtractLittleBytes_16((BNWORD16 *)bn->ptr, dest,
lsbyte, len);
MALLOCDB;
}
/* The inverse of the above */
int
bnInsertLittleBytes_16(struct BigNum *bn, unsigned char const *src,
unsigned lsbyte, unsigned len)
{
unsigned s = bn->size;
unsigned words = (len+lsbyte+sizeof(BNWORD16)-1) / sizeof(BNWORD16);
/* Pad with zeros as required */
bnSizeCheck(bn, words);
if (s < words) {
lbnZero_16((BNWORD16 *)bn->ptr BIGLITTLE(-s,+s), words-s);
s = words;
}
lbnInsertLittleBytes_16((BNWORD16 *)bn->ptr, src, lsbyte, len);
bn->size = lbnNorm_16((BNWORD16 *)bn->ptr, s);
MALLOCDB;
return 0;
}
/* Return the least-significant word of the input. */
unsigned
bnLSWord_16(struct BigNum const *bn)
{
return bn->size ? (unsigned)((BNWORD16 *)bn->ptr)[BIGLITTLE(-1,0)]: 0;
}
/* Return a selected bit of the data */
int
bnReadBit_16(struct BigNum const *bn, unsigned bit)
{
BNWORD16 word;
if (bit/16 >= bn->size)
return 0;
word = ((BNWORD16 *)bn->ptr)[BIGLITTLE(-1-bit/16,bit/16)];
return (int)(word >> (bit % 16) & 1);
}
/* Count the number of significant bits. */
unsigned
bnBits_16(struct BigNum const *bn)
{
return lbnBits_16((BNWORD16 *)bn->ptr, bn->size);
}
/* dest += src */
int
bnAdd_16(struct BigNum *dest, struct BigNum const *src)
{
unsigned s = src->size, d = dest->size;
BNWORD16 t;
if (!s)
return 0;
bnSizeCheck(dest, s);
if (d < s) {
lbnZero_16((BNWORD16 *)dest->ptr BIGLITTLE(-d,+d), s-d);
dest->size = d = s;
MALLOCDB;
}
t = lbnAddN_16((BNWORD16 *)dest->ptr, (BNWORD16 *)src->ptr, s);
MALLOCDB;
if (t) {
if (d > s) {
t = lbnAdd1_16((BNWORD16 *)dest->ptr BIGLITTLE(-s,+s),
d-s, t);
MALLOCDB;
}
if (t) {
bnSizeCheck(dest, d+1);
((BNWORD16 *)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_16(struct BigNum *dest, struct BigNum const *src)
{
unsigned s = src->size, d = dest->size;
BNWORD16 t;
if (d < s && d < (s = lbnNorm_16((BNWORD16 *)src->ptr, s))) {
bnSizeCheck(dest, s);
lbnZero_16((BNWORD16 *)dest->ptr BIGLITTLE(-d,+d), s-d);
dest->size = d = s;
MALLOCDB;
}
if (!s)
return 0;
t = lbnSubN_16((BNWORD16 *)dest->ptr, (BNWORD16 *)src->ptr, s);
MALLOCDB;
if (t) {
if (d > s) {
t = lbnSub1_16((BNWORD16 *)dest->ptr BIGLITTLE(-s,+s),
d-s, t);
MALLOCDB;
}
if (t) {
lbnNeg_16((BNWORD16 *)dest->ptr, d);
dest->size = lbnNorm_16((BNWORD16 *)dest->ptr,
dest->size);
MALLOCDB;
return 1;
}
}
dest->size = lbnNorm_16((BNWORD16 *)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_16(struct BigNum const *a, unsigned b)
{
unsigned t;
BNWORD16 v;
t = lbnNorm_16((BNWORD16 *)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)((BNWORD16 *)a->ptr)[BIGLITTLE(-1,0)];
return (v > b) ? 1 : ((v < b) ? -1 : 0);
}
/* Set dest to a small value */
int
bnSetQ_16(struct BigNum *dest, unsigned src)
{
if (src) {
bnSizeCheck(dest, 1);
((BNWORD16 *)dest->ptr)[BIGLITTLE(-1,0)] = (BNWORD16)src;
dest->size = 1;
} else {
dest->size = 0;
}
return 0;
}
/* dest += src */
int
bnAddQ_16(struct BigNum *dest, unsigned src)
{
BNWORD16 t;
if (!dest->size)
return bnSetQ(dest, src);
t = lbnAdd1_16((BNWORD16 *)dest->ptr, dest->size, (BNWORD16)src);
MALLOCDB;
if (t) {
src = dest->size;
bnSizeCheck(dest, src+1);
((BNWORD16 *)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_16(struct BigNum *dest, unsigned src)
{
BNWORD16 t;
if (!dest->size)
return bnSetQ(dest, src) < 0 ? -1 : (src != 0);
t = lbnSub1_16((BNWORD16 *)dest->ptr, dest->size, src);
MALLOCDB;
if (t) {
/* Underflow. <= 1 word, so do it simply. */
lbnNeg_16((BNWORD16 *)dest->ptr, 1);
dest->size = 1;
return 1;
}
/* Try to normalize? Needing this is going to be pretty damn rare. */
/* dest->size = lbnNorm_16((BNWORD16 *)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_16(struct BigNum const *a, struct BigNum const *b)
{
unsigned s, t;
s = lbnNorm_16((BNWORD16 *)a->ptr, a->size);
t = lbnNorm_16((BNWORD16 *)b->ptr, b->size);
if (s != t)
return s > t ? 1 : -1;
return lbnCmp_16((BNWORD16 *)a->ptr, (BNWORD16 *)b->ptr, s);
}
/* dest = src*src. This is more efficient than bnMul. */
int
bnSquare_16(struct BigNum *dest, struct BigNum const *src)
{
unsigned s;
BNWORD16 *srcbuf;
s = lbnNorm_16((BNWORD16 *)src->ptr, src->size);
if (!s) {
dest->size = 0;
return 0;
}
bnSizeCheck(dest, 2*s);
if (src == dest) {
LBNALLOC(srcbuf, BNWORD16, s);
if (!srcbuf)
return -1;
lbnCopy_16(srcbuf, (BNWORD16 *)src->ptr, s);
lbnSquare_16((BNWORD16 *)dest->ptr, (BNWORD16 *)srcbuf, s);
LBNFREE(srcbuf, s);
} else {
lbnSquare_16((BNWORD16 *)dest->ptr, (BNWORD16 *)src->ptr, s);
}
dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, 2*s);
MALLOCDB;
return 0;
}
/* dest = a * b. Any overlap between operands is allowed. */
int
bnMul_16(struct BigNum *dest, struct BigNum const *a, struct BigNum const *b)
{
unsigned s, t;
BNWORD16 *srcbuf;
s = lbnNorm_16((BNWORD16 *)a->ptr, a->size);
t = lbnNorm_16((BNWORD16 *)b->ptr, b->size);
if (!s || !t) {
dest->size = 0;
return 0;
}
if (a == b)
return bnSquare_16(dest, a);
bnSizeCheck(dest, s+t);
if (dest == a) {
LBNALLOC(srcbuf, BNWORD16, s);
if (!srcbuf)
return -1;
lbnCopy_16(srcbuf, (BNWORD16 *)a->ptr, s);
lbnMul_16((BNWORD16 *)dest->ptr, srcbuf, s,
(BNWORD16 *)b->ptr, t);
LBNFREE(srcbuf, s);
} else if (dest == b) {
LBNALLOC(srcbuf, BNWORD16, t);
if (!srcbuf)
return -1;
lbnCopy_16(srcbuf, (BNWORD16 *)b->ptr, t);
lbnMul_16((BNWORD16 *)dest->ptr, (BNWORD16 *)a->ptr, s,
srcbuf, t);
LBNFREE(srcbuf, t);
} else {
lbnMul_16((BNWORD16 *)dest->ptr, (BNWORD16 *)a->ptr, s,
(BNWORD16 *)b->ptr, t);
}
dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, s+t);
MALLOCDB;
return 0;
}
/* dest = a * b */
int
bnMulQ_16(struct BigNum *dest, struct BigNum const *a, unsigned b)
{
unsigned s;
s = lbnNorm_16((BNWORD16 *)a->ptr, a->size);
if (!s || !b) {
dest->size = 0;
return 0;
}
if (b == 1)
return bnCopy_16(dest, a);
bnSizeCheck(dest, s+1);
lbnMulN1_16((BNWORD16 *)dest->ptr, (BNWORD16 *)a->ptr, s, b);
dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, s+1);
MALLOCDB;
return 0;
}
/* q = n/d, r = n % d */
int
bnDivMod_16(struct BigNum *q, struct BigNum *r, struct BigNum const *n,
struct BigNum const *d)
{
unsigned dsize, nsize;
BNWORD16 qhigh;
dsize = lbnNorm_16((BNWORD16 *)d->ptr, d->size);
nsize = lbnNorm_16((BNWORD16 *)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_16((BNWORD16 *)r->ptr, (BNWORD16 *)n->ptr, nsize);
}
qhigh = lbnDiv_16((BNWORD16 *)q->ptr, (BNWORD16 *)r->ptr, nsize,
(BNWORD16 *)d->ptr, dsize);
nsize -= dsize;
if (qhigh) {
bnSizeCheck(q, nsize+1);
*((BNWORD16 *)q->ptr BIGLITTLE(-nsize-1,+nsize)) = qhigh;
q->size = nsize+1;
} else {
q->size = lbnNorm_16((BNWORD16 *)q->ptr, nsize);
}
r->size = lbnNorm_16((BNWORD16 *)r->ptr, dsize);
MALLOCDB;
return 0;
}
/* det = src % d */
int
bnMod_16(struct BigNum *dest, struct BigNum const *src, struct BigNum const *d)
{
unsigned dsize, nsize;
nsize = lbnNorm_16((BNWORD16 *)src->ptr, src->size);
dsize = lbnNorm_16((BNWORD16 *)d->ptr, d->size);
if (dest != src) {
bnSizeCheck(dest, nsize);
lbnCopy_16((BNWORD16 *)dest->ptr, (BNWORD16 *)src->ptr, nsize);
}
if (nsize < dsize) {
dest->size = nsize; /* No quotient */
return 0;
}
(void)lbnDiv_16((BNWORD16 *)dest->ptr BIGLITTLE(-dsize,+dsize),
(BNWORD16 *)dest->ptr, nsize,
(BNWORD16 *)d->ptr, dsize);
dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, dsize);
MALLOCDB;
return 0;
}
/* return src % d. */
unsigned
bnModQ_16(struct BigNum const *src, unsigned d)
{
unsigned s;
s = lbnNorm_16((BNWORD16 *)src->ptr, src->size);
if (!s)
return 0;
if (d & (d-1)) /* Not a power of 2 */
d = lbnModQ_16((BNWORD16 *)src->ptr, s, d);
else
d = (unsigned)((BNWORD16 *)src->ptr)[BIGLITTLE(-1,0)] & (d-1);
return d;
}
/* dest = n^exp (mod mod) */
int
bnExpMod_16(struct BigNum *dest, struct BigNum const *n,
struct BigNum const *exp, struct BigNum const *mod)
{
unsigned nsize, esize, msize;
nsize = lbnNorm_16((BNWORD16 *)n->ptr, n->size);
esize = lbnNorm_16((BNWORD16 *)exp->ptr, exp->size);
msize = lbnNorm_16((BNWORD16 *)mod->ptr, mod->size);
if (!msize || (((BNWORD16 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
return -1; /* Illegal modulus! */
bnSizeCheck(dest, msize);
/* Special-case base of 2 */
if (nsize == 1 && ((BNWORD16 *)n->ptr)[BIGLITTLE(-1,0)] == 2) {
if (lbnTwoExpMod_16((BNWORD16 *)dest->ptr,
(BNWORD16 *)exp->ptr, esize,
(BNWORD16 *)mod->ptr, msize) < 0)
return -1;
} else {
if (lbnExpMod_16((BNWORD16 *)dest->ptr,
(BNWORD16 *)n->ptr, nsize,
(BNWORD16 *)exp->ptr, esize,
(BNWORD16 *)mod->ptr, msize) < 0)
return -1;
}
dest->size = lbnNorm_16((BNWORD16 *)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_16(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_16((BNWORD16 *)n1->ptr, n1->size);
e1size = lbnNorm_16((BNWORD16 *)e1->ptr, e1->size);
n2size = lbnNorm_16((BNWORD16 *)n2->ptr, n2->size);
e2size = lbnNorm_16((BNWORD16 *)e2->ptr, e2->size);
msize = lbnNorm_16((BNWORD16 *)mod->ptr, mod->size);
if (!msize || (((BNWORD16 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
return -1; /* Illegal modulus! */
bnSizeCheck(dest, msize);
if (lbnDoubleExpMod_16((BNWORD16 *)dest->ptr,
(BNWORD16 *)n1->ptr, n1size, (BNWORD16 *)e1->ptr, e1size,
(BNWORD16 *)n2->ptr, n2size, (BNWORD16 *)e2->ptr, e2size,
(BNWORD16 *)mod->ptr, msize) < 0)
return -1;
dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, msize);
MALLOCDB;
return 0;
}
/* n = 2^exp (mod mod) */
int
bnTwoExpMod_16(struct BigNum *n, struct BigNum const *exp,
struct BigNum const *mod)
{
unsigned esize, msize;
esize = lbnNorm_16((BNWORD16 *)exp->ptr, exp->size);
msize = lbnNorm_16((BNWORD16 *)mod->ptr, mod->size);
if (!msize || (((BNWORD16 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
return -1; /* Illegal modulus! */
bnSizeCheck(n, msize);
if (lbnTwoExpMod_16((BNWORD16 *)n->ptr, (BNWORD16 *)exp->ptr, esize,
(BNWORD16 *)mod->ptr, msize) < 0)
return -1;
n->size = lbnNorm_16((BNWORD16 *)n->ptr, msize);
MALLOCDB;
return 0;
}
/* dest = gcd(a, b) */
int
bnGcd_16(struct BigNum *dest, struct BigNum const *a, struct BigNum const *b)
{
BNWORD16 *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_16((BNWORD16 *)a->ptr, a->size);
bsize = lbnNorm_16((BNWORD16 *)b->ptr, b->size);
bnSizeCheck(dest, bsize+1);
/* Copy a to tmp */
LBNALLOC(tmp, BNWORD16, asize+1);
if (!tmp)
return -1;
lbnCopy_16(tmp, (BNWORD16 *)a->ptr, asize);
/* Copy b to dest, if necessary */
if (dest != b)
lbnCopy_16((BNWORD16 *)dest->ptr,
(BNWORD16 *)b->ptr, bsize);
if (bsize > asize || (bsize == asize &&
lbnCmp_16((BNWORD16 *)b->ptr, (BNWORD16 *)a->ptr, asize) > 0))
{
i = lbnGcd_16((BNWORD16 *)dest->ptr, bsize, tmp, asize,
&dest->size);
if (i > 0) /* Result in tmp, not dest */
lbnCopy_16((BNWORD16 *)dest->ptr, tmp, dest->size);
} else {
i = lbnGcd_16(tmp, asize, (BNWORD16 *)dest->ptr, bsize,
&dest->size);
if (i == 0) /* Result in tmp, not dest */
lbnCopy_16((BNWORD16 *)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_16(struct BigNum *dest, struct BigNum const *src,
struct BigNum const *mod)
{
unsigned s, m;
int i;
s = lbnNorm_16((BNWORD16 *)src->ptr, src->size);
m = lbnNorm_16((BNWORD16 *)mod->ptr, mod->size);
/* lbnInv_16 requires that the input be less than the modulus */
if (m < s ||
(m==s && lbnCmp_16((BNWORD16 *)src->ptr, (BNWORD16 *)mod->ptr, s)))
{
bnSizeCheck(dest, s + (m==s));
if (dest != src)
lbnCopy_16((BNWORD16 *)dest->ptr,
(BNWORD16 *)src->ptr, s);
/* Pre-reduce modulo the modulus */
(void)lbnDiv_16((BNWORD16 *)dest->ptr BIGLITTLE(-m,+m),
(BNWORD16 *)dest->ptr, s,
(BNWORD16 *)mod->ptr, m);
s = lbnNorm_16((BNWORD16 *)dest->ptr, m);
MALLOCDB;
} else {
bnSizeCheck(dest, m+1);
if (dest != src)
lbnCopy_16((BNWORD16 *)dest->ptr,
(BNWORD16 *)src->ptr, s);
}
i = lbnInv_16((BNWORD16 *)dest->ptr, s, (BNWORD16 *)mod->ptr, m);
if (i == 0)
dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, m);
MALLOCDB;
return i;
}
/*
* Shift a bignum left the appropriate number of bits,
* multiplying by 2^amt.
*/
int
bnLShift_16(struct BigNum *dest, unsigned amt)
{
unsigned s = dest->size;
BNWORD16 carry;
if (amt % 16) {
carry = lbnLshift_16((BNWORD16 *)dest->ptr, s, amt % 16);
if (carry) {
s++;
bnSizeCheck(dest, s);
((BNWORD16 *)dest->ptr)[BIGLITTLE(-s,s-1)] = carry;
}
}
amt /= 16;
if (amt) {
bnSizeCheck(dest, s+amt);
memmove((BNWORD16 *)dest->ptr BIGLITTLE(-s-amt, +amt),
(BNWORD16 *)dest->ptr BIG(-s),
s * sizeof(BNWORD16));
lbnZero_16((BNWORD16 *)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_16(struct BigNum *dest, unsigned amt)
{
unsigned s = dest->size;
if (amt >= 16) {
memmove(
(BNWORD16 *)dest->ptr BIG(-s+amt/16),
(BNWORD16 *)dest->ptr BIGLITTLE(-s, +amt/16),
(s-amt/16) * sizeof(BNWORD16));
s -= amt/16;
amt %= 16;
}
if (amt)
(void)lbnRshift_16((BNWORD16 *)dest->ptr, s, amt);
dest->size = lbnNorm_16((BNWORD16 *)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_16(struct BigNum *n)
{
unsigned size;
unsigned s; /* shift amount */
BNWORD16 *p;
BNWORD16 t;
p = (BNWORD16 *)n->ptr;
size = lbnNorm_16(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 *= 16;
memmove((BNWORD16 *)n->ptr BIG(-size), p BIG(-size),
size * sizeof(BNWORD16));
p = (BNWORD16 *)n->ptr;
MALLOCDB;
}
assert(t);
if (!(t & 1)) {
/* Now count the bits */
do {
t >>= 1;
s++;
} while ((t & 1) == 0);
/* Shift the bits */
lbnRshift_16(p, size, s & (16-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 lbn16.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 160 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_16(struct BnBasePrecomp *pre, struct BigNum const *base,
struct BigNum const *mod, unsigned maxebits)
{
int i;
BNWORD16 **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_16((BNWORD16 *)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++) {
BNWORD16 *entry;
LBNALLOC(entry, BNWORD16, 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 */
BNWORD16 **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) {
BNWORD16 *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_16(array, n, bits,
(BNWORD16 *)base->ptr, base->size,
(BNWORD16 *)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_16(struct BnBasePrecomp *pre)
{
BNWORD16 **array = pre->array;
if (array) {
unsigned entries = pre->entries;
unsigned msize = pre->msize;
unsigned m;
for (m = 0; m < entries; m++) {
BNWORD16 *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_16(struct BigNum *dest, struct BnBasePrecomp const *pre,
struct BigNum const *exp, struct BigNum const *mod)
{
unsigned msize = lbnNorm_16((BNWORD16 *)mod->ptr, mod->size);
unsigned esize = lbnNorm_16((BNWORD16 *)exp->ptr, exp->size);
BNWORD16 const * const *array = pre->array;
int i;
assert(msize == pre->msize);
assert(((BNWORD16 *)mod->ptr)[BIGLITTLE(-1,0)] & 1);
assert(lbnBits_16((BNWORD16 *)exp->ptr, esize) <= pre->maxebits);
bnSizeCheck(dest, msize);
i = lbnBasePrecompExp_16(dest->ptr, array, pre->bits,
exp->ptr, esize, mod->ptr, msize);
if (i == 0)
dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, msize);
return i;
}
int
bnDoubleBasePrecompExpMod_16(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_16((BNWORD16 *)mod->ptr, mod->size);
unsigned e1size = lbnNorm_16((BNWORD16 *)exp1->ptr, exp1->size);
unsigned e2size = lbnNorm_16((BNWORD16 *)exp1->ptr, exp2->size);
BNWORD16 const * const *array1 = pre1->array;
BNWORD16 const * const *array2 = pre2->array;
int i;
assert(msize == pre1->msize);
assert(msize == pre2->msize);
assert(((BNWORD16 *)mod->ptr)[BIGLITTLE(-1,0)] & 1);
assert(lbnBits_16((BNWORD16 *)exp1->ptr, e1size) <= pre1->maxebits);
assert(lbnBits_16((BNWORD16 *)exp2->ptr, e2size) <= pre2->maxebits);
assert(pre1->bits == pre2->bits);
bnSizeCheck(dest, msize);
i = lbnDoubleBasePrecompExp_16(dest->ptr, pre1->bits, array1,
exp1->ptr, e1size, array2, exp2->ptr, e2size,
mod->ptr, msize);
if (i == 0)
dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, msize);
return i;
}