#include <stdlib.h>
#include <string.h>
+#if 0 // use PuTTY main debugging for diagbn()
+#include <windows.h>
+#include "putty.h"
+#define debugprint debug
+#else
+#define debugprint(x) printf x
+#endif
+
+#define BIGNUM_INTERNAL
+typedef unsigned short *Bignum;
+
#include "ssh.h"
unsigned short bnZero[1] = { 0 };
Bignum Zero = bnZero, One = bnOne;
-Bignum newbn(int length) {
+static Bignum newbn(int length) {
Bignum b = smalloc((length+1)*sizeof(unsigned short));
if (!b)
abort(); /* FIXME */
return b;
}
+void bn_restore_invariant(Bignum b) {
+ while (b[0] > 1 && b[b[0]] == 0) b[0]--;
+}
+
Bignum copybn(Bignum orig) {
Bignum b = smalloc((orig[0]+1)*sizeof(unsigned short));
if (!b)
sfree(b);
}
+Bignum bn_power_2(int n) {
+ Bignum ret = newbn((n+15)/16);
+ bignum_set_bit(ret, n, 1);
+ return ret;
+}
+
/*
* Compute c = a * b.
* Input is in the first len words of a and b.
{
unsigned short *a, *n, *m, *o;
int mshift;
- int pqlen, mlen, i, j;
+ int pqlen, mlen, rlen, i, j;
Bignum result;
/* Allocate m of size mlen, copy mod to m */
}
/* Copy result to buffer */
- result = newbn(mod[0]);
- for (i = 0; i < mlen; i++)
- result[result[0] - i] = a[i+2*pqlen-mlen];
+ rlen = (mlen < pqlen*2 ? mlen : pqlen*2);
+ result = newbn(rlen);
+ for (i = 0; i < rlen; i++)
+ result[result[0] - i] = a[i+2*pqlen-rlen];
while (result[0] > 1 && result[result[0]] == 0) result[0]--;
/* Free temporary arrays */
bn[i]--;
}
+Bignum bignum_from_bytes(unsigned char *data, int nbytes) {
+ Bignum result;
+ int w, i;
+
+ w = (nbytes+1)/2; /* bytes -> words */
+
+ result = newbn(w);
+ for (i=1; i<=w; i++)
+ result[i] = 0;
+ for (i=nbytes; i-- ;) {
+ unsigned char byte = *data++;
+ if (i & 1)
+ result[1+i/2] |= byte<<8;
+ else
+ result[1+i/2] |= byte;
+ }
+
+ while (result[0] > 1 && result[result[0]] == 0) result[0]--;
+ return result;
+}
+
/*
* Read an ssh1-format bignum from a data buffer. Return the number
* of bytes consumed.
*/
int ssh1_read_bignum(unsigned char *data, Bignum *result) {
unsigned char *p = data;
- Bignum bn;
int i;
int w, b;
w = 0;
for (i=0; i<2; i++)
w = (w << 8) + *p++;
-
b = (w+7)/8; /* bits -> bytes */
- w = (w+15)/16; /* bits -> words */
if (!result) /* just return length */
return b + 2;
- bn = newbn(w);
-
- for (i=1; i<=w; i++)
- bn[i] = 0;
- for (i=b; i-- ;) {
- unsigned char byte = *p++;
- if (i & 1)
- bn[1+i/2] |= byte<<8;
- else
- bn[1+i/2] |= byte;
- }
-
- *result = bn;
+ *result = bignum_from_bytes(p, b);
- return p - data;
+ return p + b - data;
}
/*
*/
int ssh1_bignum_bitcount(Bignum bn) {
int bitcount = bn[0] * 16 - 1;
-
while (bitcount >= 0 && (bn[bitcount/16+1] >> (bitcount % 16)) == 0)
bitcount--;
return bitcount + 1;
return bigmuladd(a, b, NULL);
}
+/*
+ * Create a bignum which is the bitmask covering another one. That
+ * is, the smallest integer which is >= N and is also one less than
+ * a power of two.
+ */
+Bignum bignum_bitmask(Bignum n) {
+ Bignum ret = copybn(n);
+ int i;
+ unsigned short j;
+
+ i = ret[0];
+ while (n[i] == 0 && i > 0)
+ i--;
+ if (i <= 0)
+ return ret; /* input was zero */
+ j = 1;
+ while (j < n[i])
+ j = 2*j+1;
+ ret[i] = j;
+ while (--i > 0)
+ ret[i] = 0xFFFF;
+ return ret;
+}
+
/*
* Convert a (max 16-bit) short into a bignum.
*/
return (unsigned short) r;
}
-static void diagbn(char *prefix, Bignum md) {
+void diagbn(char *prefix, Bignum md) {
int i, nibbles, morenibbles;
static const char hex[] = "0123456789ABCDEF";
- printf("%s0x", prefix ? prefix : "");
+ debugprint(("%s0x", prefix ? prefix : ""));
nibbles = (3 + ssh1_bignum_bitcount(md))/4; if (nibbles<1) nibbles=1;
morenibbles = 4*md[0] - nibbles;
- for (i=0; i<morenibbles; i++) putchar('-');
+ for (i=0; i<morenibbles; i++) debugprint(("-"));
for (i=nibbles; i-- ;)
- putchar(hex[(bignum_byte(md, i/2) >> (4*(i%2))) & 0xF]);
+ debugprint(("%c",hex[(bignum_byte(md, i/2) >> (4*(i%2))) & 0xF]));
- if (prefix) putchar('\n');
+ if (prefix) debugprint(("\n"));
}
/*