1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-05-28 15:24:49 -05:00

Some extra bignum functions: modsub, lshift, random_in_range.

This commit is contained in:
Chris Staite 2014-11-01 09:15:08 +00:00 committed by Simon Tatham
parent 66970c4258
commit 7d1c30cd50
2 changed files with 105 additions and 0 deletions

3
ssh.h
View File

@ -515,9 +515,11 @@ Bignum bignum_from_long(unsigned long n);
void freebn(Bignum b);
Bignum modpow(Bignum base, Bignum exp, Bignum mod);
Bignum modmul(Bignum a, Bignum b, Bignum mod);
Bignum modsub(const Bignum a, const Bignum b, const Bignum n);
void decbn(Bignum n);
extern Bignum Zero, One;
Bignum bignum_from_bytes(const unsigned char *data, int nbytes);
Bignum bignum_random_in_range(const Bignum lower, const Bignum upper);
int ssh1_read_bignum(const unsigned char *data, int len, Bignum * result);
int bignum_bitcount(Bignum bn);
int ssh1_bignum_length(Bignum bn);
@ -538,6 +540,7 @@ Bignum bigmod(Bignum a, Bignum b);
Bignum modinv(Bignum number, Bignum modulus);
Bignum bignum_bitmask(Bignum number);
Bignum bignum_rshift(Bignum number, int shift);
Bignum bignum_lshift(Bignum number, int shift);
int bignum_cmp(Bignum a, Bignum b);
char *bignum_decimal(Bignum x);

102
sshbn.c
View File

@ -1092,6 +1092,38 @@ Bignum modmul(Bignum p, Bignum q, Bignum mod)
return result;
}
Bignum modsub(const Bignum a, const Bignum b, const Bignum n)
{
Bignum a1, b1, ret;
if (bignum_cmp(a, n) >= 0) a1 = bigmod(a, n);
else a1 = a;
if (bignum_cmp(b, n) >= 0) b1 = bigmod(b, n);
else b1 = b;
if (bignum_cmp(a1, b1) >= 0) /* a >= b */
{
ret = bigsub(a1, b1);
}
else
{
/* Handle going round the corner of the modulus without having
* negative support in Bignum */
Bignum tmp = bigsub(n, b1);
if (tmp) {
ret = bigadd(tmp, a1);
freebn(tmp);
} else {
ret = NULL;
}
}
if (a != a1) freebn(a1);
if (b != b1) freebn(b1);
return ret;
}
/*
* Compute p % mod.
* The most significant word of mod MUST be non-zero.
@ -1201,6 +1233,37 @@ Bignum bignum_from_bytes(const unsigned char *data, int nbytes)
return result;
}
Bignum bignum_random_in_range(const Bignum lower, const Bignum upper)
{
Bignum ret = NULL;
int upper_len = bignum_bitcount(upper);
int upper_bytes = upper_len / 8;
int upper_bits = upper_len % 8;
if (upper_bits) ++upper_bytes;
do {
unsigned char *bytes;
int i;
if (ret) freebn(ret);
bytes = snewn(upper_bytes, unsigned char);
for (i = 0; i < upper_bytes; ++i)
{
bytes[i] = (unsigned char)random_byte();
}
/* Mask the top to reduce failure rate to 50/50 */
if (upper_bits)
{
bytes[i - 1] &= 0xFF >> (8 - upper_bits);
}
ret = bignum_from_bytes(bytes, upper_bytes);
} while (bignum_cmp(ret, lower) < 0 || bignum_cmp(ret, upper) > 0);
return ret;
}
/*
* Read an SSH-1-format bignum from a data buffer. Return the number
* of bytes consumed, or -1 if there wasn't enough data.
@ -1375,6 +1438,45 @@ Bignum bignum_rshift(Bignum a, int shift)
return ret;
}
/*
* Left-shift one bignum to form another.
*/
Bignum bignum_lshift(Bignum a, int shift)
{
Bignum ret;
int bits, shiftWords, shiftBits;
assert(shift >= 0);
bits = bignum_bitcount(a) + shift;
ret = newbn((bits + BIGNUM_INT_BITS - 1) / BIGNUM_INT_BITS);
if (!ret) return NULL;
shiftWords = shift / BIGNUM_INT_BITS;
shiftBits = shift % BIGNUM_INT_BITS;
if (shiftBits == 0)
{
memcpy(&ret[1 + shiftWords], &a[1], sizeof(BignumInt) * a[0]);
}
else
{
int i;
BignumInt carry = 0;
/* Remember that Bignum[0] is length, so add 1 */
for (i = shiftWords + 1; i < ((int)a[0]) + shiftWords + 1; ++i)
{
BignumInt from = a[i - shiftWords];
ret[i] = (from << shiftBits) | carry;
carry = from >> (BIGNUM_INT_BITS - shiftBits);
}
if (carry) ret[i] = carry;
}
return ret;
}
/*
* Non-modular multiplication and addition.
*/