X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/8c3cd914db62fcba242eba74eba223c1c927aaa5..6e522441172d5b1c2a2fa4d0f6bbe905ce6b647a:/sshbn.c diff --git a/sshbn.c b/sshbn.c index 51e59015..693b4ac7 100644 --- a/sshbn.c +++ b/sshbn.c @@ -65,17 +65,17 @@ static void internal_mul(unsigned short *a, unsigned short *b, } } -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++; } @@ -577,7 +577,7 @@ Bignum bigmuladd(Bignum a, Bignum b, Bignum addend) { 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; @@ -620,7 +620,7 @@ Bignum bignum_add_long(Bignum number, unsigned long addend) { 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; @@ -633,7 +633,6 @@ Bignum bignum_add_long(Bignum number, unsigned long addend) { * 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; @@ -641,7 +640,7 @@ unsigned short bignum_mod_short(Bignum number, unsigned short modulus) { 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) { @@ -736,3 +735,74 @@ Bignum modinv(Bignum number, Bignum modulus) { /* 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; +}