123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182 |
- /*
- * 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
- #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 "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;
- }
|