unsigned short bnZero[1] = { 0 };
unsigned short bnOne[2] = { 1, 1 };
+/*
+ * The Bignum format is an array of `unsigned short'. The first
+ * element of the array counts the remaining elements. The
+ * remaining elements express the actual number, base 2^16, _least_
+ * significant digit first. (So it's trivial to extract the bit
+ * with value 2^n for any n.)
+ *
+ * All Bignums in this module are positive. Negative numbers must
+ * be dealt with outside it.
+ *
+ * INVARIANT: the most significant word of any Bignum must be
+ * nonzero.
+ */
+
Bignum Zero = bnZero, One = bnOne;
Bignum newbn(int length) {
}
}
-static int internal_add_shifted(unsigned short *number,
- unsigned short n, int shift) {
+static void internal_add_shifted(unsigned short *number,
+ unsigned n, int shift) {
int word = 1 + (shift / 16);
int bshift = shift % 16;
- unsigned long carry, addend;
+ unsigned long addend;
addend = n << bshift;
while (addend) {
addend += number[word];
- number[word] = addend & 0xFFFF;
+ number[word] = (unsigned short) addend & 0xFFFF;
addend >>= 16;
word++;
}
* The most significant word of mod MUST be non-zero.
* We assume that the result array is the same size as the mod array.
*/
-void modpow(Bignum base, Bignum exp, Bignum mod, Bignum result)
+Bignum modpow(Bignum base, Bignum exp, Bignum mod)
{
unsigned short *a, *b, *n, *m;
int mshift;
int mlen, i, j;
+ Bignum result;
/* Allocate m of size mlen, copy mod to m */
/* We use big endian internally */
}
/* Copy result to buffer */
+ result = newbn(mod[0]);
for (i = 0; i < mlen; i++)
result[result[0] - i] = a[i+mlen];
+ while (result[0] > 1 && result[result[0]] == 0) result[0]--;
/* Free temporary arrays */
for (i = 0; i < 2*mlen; i++) a[i] = 0; free(a);
for (i = 0; i < 2*mlen; i++) b[i] = 0; free(b);
for (i = 0; i < mlen; i++) m[i] = 0; free(m);
for (i = 0; i < mlen; i++) n[i] = 0; free(n);
+
+ return result;
}
/*
* The most significant word of mod MUST be non-zero.
* We assume that the result array is the same size as the mod array.
*/
-void modmul(Bignum p, Bignum q, Bignum mod, Bignum result)
+Bignum modmul(Bignum p, Bignum q, Bignum mod)
{
unsigned short *a, *n, *m, *o;
int mshift;
int pqlen, mlen, i, j;
+ Bignum result;
/* Allocate m of size mlen, copy mod to m */
/* We use big endian internally */
}
/* Copy result to buffer */
+ result = newbn(mod[0]);
for (i = 0; i < mlen; i++)
result[result[0] - i] = a[i+2*pqlen-mlen];
+ while (result[0] > 1 && result[result[0]] == 0) result[0]--;
/* Free temporary arrays */
for (i = 0; i < 2*pqlen; i++) a[i] = 0; free(a);
for (i = 0; i < mlen; i++) m[i] = 0; free(m);
for (i = 0; i < pqlen; i++) n[i] = 0; free(n);
for (i = 0; i < pqlen; i++) o[i] = 0; free(o);
+
+ return result;
}
/*
for (i = 1; i <= rlen; i++) {
carry += (i <= ret[0] ? ret[i] : 0);
carry += (i <= addend[0] ? addend[i] : 0);
- ret[i] = carry & 0xFFFF;
+ ret[i] = (unsigned short) carry & 0xFFFF;
carry >>= 16;
if (ret[i] != 0 && i > maxspot)
maxspot = i;
carry += addend & 0xFFFF;
carry += (i <= number[0] ? number[i] : 0);
addend >>= 16;
- ret[i] = carry & 0xFFFF;
+ ret[i] = (unsigned short) carry & 0xFFFF;
carry >>= 16;
if (ret[i] != 0)
maxspot = i;
* Compute the residue of a bignum, modulo a (max 16-bit) short.
*/
unsigned short bignum_mod_short(Bignum number, unsigned short modulus) {
- Bignum ret;
unsigned long mod, r;
int i;
mod = modulus;
for (i = number[0]; i > 0; i--)
r = (r * 65536 + number[i]) % mod;
- return r;
+ return (unsigned short) r;
}
static void diagbn(char *prefix, Bignum md) {
/* and return. */
return x;
}
+
+/*
+ * Render a bignum into decimal. Return a malloced string holding
+ * the decimal representation.
+ */
+char *bignum_decimal(Bignum x) {
+ int ndigits, ndigit;
+ int i, iszero;
+ unsigned long carry;
+ char *ret;
+ unsigned short *workspace;
+
+ /*
+ * First, estimate the number of digits. Since log(10)/log(2)
+ * is just greater than 93/28 (the joys of continued fraction
+ * approximations...) we know that for every 93 bits, we need
+ * at most 28 digits. This will tell us how much to malloc.
+ *
+ * Formally: if x has i bits, that means x is strictly less
+ * than 2^i. Since 2 is less than 10^(28/93), this is less than
+ * 10^(28i/93). We need an integer power of ten, so we must
+ * round up (rounding down might make it less than x again).
+ * Therefore if we multiply the bit count by 28/93, rounding
+ * up, we will have enough digits.
+ */
+ i = ssh1_bignum_bitcount(x);
+ ndigits = (28*i + 92)/93; /* multiply by 28/93 and round up */
+ ndigits++; /* allow for trailing \0 */
+ ret = malloc(ndigits);
+
+ /*
+ * Now allocate some workspace to hold the binary form as we
+ * repeatedly divide it by ten. Initialise this to the
+ * big-endian form of the number.
+ */
+ workspace = malloc(sizeof(unsigned short) * x[0]);
+ for (i = 0; i < x[0]; i++)
+ workspace[i] = x[x[0] - i];
+
+ /*
+ * Next, write the decimal number starting with the last digit.
+ * We use ordinary short division, dividing 10 into the
+ * workspace.
+ */
+ ndigit = ndigits-1;
+ ret[ndigit] = '\0';
+ do {
+ iszero = 1;
+ carry = 0;
+ for (i = 0; i < x[0]; i++) {
+ carry = (carry << 16) + workspace[i];
+ workspace[i] = (unsigned short) (carry / 10);
+ if (workspace[i])
+ iszero = 0;
+ carry %= 10;
+ }
+ ret[--ndigit] = (char)(carry + '0');
+ } while (!iszero);
+
+ /*
+ * There's a chance we've fallen short of the start of the
+ * string. Correct if so.
+ */
+ if (ndigit > 0)
+ memmove(ret, ret+ndigit, ndigits-ndigit);
+
+ /*
+ * Done.
+ */
+ return ret;
+}