1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-17 05:03:07 +00:00

crypto/bignum: change limb size to 29, add tests

This commit is contained in:
Ondřej Vejpustek 2019-04-20 15:56:50 +02:00 committed by Tomas Susanka
parent a5eecf7a3c
commit 24ceb0ab6b
12 changed files with 4954 additions and 3255 deletions

View File

@ -519,13 +519,21 @@ STATIC mp_obj_t mod_trezorcrypto_monero_inv256_modm(size_t n_args,
assert_scalar(args[1 + off]);
// bn_prime = curve order, little endian encoded
bignum256 bn_prime = {.val = {0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8,
0x14, 0x0, 0x0, 0x0, 0x1000}};
bignum256 bn_prime = {.val = {0x1cf5d3ed, 0x9318d2, 0x1de73596, 0x1df3bd45,
0x14d, 0x0, 0x0, 0x0, 0x100000}};
bignum256 bn_x;
bignum256modm bm_x;
uint8_t raw_x[32];
memcpy(bm_x, MP_OBJ_C_SCALAR(args[1 + off]), sizeof(bignum256modm));
contract256_modm(raw_x, bm_x);
bn_read_le(raw_x, &bn_x);
memcpy(&bn_x.val, MP_OBJ_C_SCALAR(args[1 + off]), sizeof(bignum256modm));
bn_inverse(&bn_x, &bn_prime);
memcpy(MP_OBJ_SCALAR(res), bn_x.val, sizeof(bignum256modm));
bn_write_le(&bn_x, raw_x);
expand_raw256_modm(bm_x, raw_x);
memcpy(MP_OBJ_SCALAR(res), bm_x, sizeof(bignum256modm));
return res;
}

File diff suppressed because it is too large Load Diff

View File

@ -28,141 +28,145 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "options.h"
// bignum256 are 256 bits stored as 8*30 bit + 1*16 bit
// val[0] are lowest 30 bits, val[8] highest 16 bits
#define BN_LIMBS 9
#define BN_BITS_PER_LIMB 29
#define BN_BASE (1u << BN_BITS_PER_LIMB)
#define BN_LIMB_MASK ((1u << BN_BITS_PER_LIMB) - 1)
#define BN_EXTRA_BITS (32 - BN_BITS_PER_LIMB)
#define BN_BITS_LAST_LIMB (256 - (BN_LIMBS - 1) * BN_BITS_PER_LIMB)
// Represents the number sum([val[i] * 2**(29*i) for i in range(9))
typedef struct {
uint32_t val[9];
uint32_t val[BN_LIMBS];
} bignum256;
// read 4 big endian bytes into uint32
uint32_t read_be(const uint8_t *data);
static inline uint32_t read_be(const uint8_t *data) {
return (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) |
(((uint32_t)data[2]) << 8) | (((uint32_t)data[3]));
}
// write 4 big endian bytes
void write_be(uint8_t *data, uint32_t x);
static inline void write_be(uint8_t *data, uint32_t x) {
data[0] = x >> 24;
data[1] = x >> 16;
data[2] = x >> 8;
data[3] = x;
}
// read 4 little endian bytes into uint32
uint32_t read_le(const uint8_t *data);
static inline uint32_t read_le(const uint8_t *data) {
return (((uint32_t)data[3]) << 24) | (((uint32_t)data[2]) << 16) |
(((uint32_t)data[1]) << 8) | (((uint32_t)data[0]));
}
// write 4 little endian bytes
void write_le(uint8_t *data, uint32_t x);
static inline void write_le(uint8_t *data, uint32_t x) {
data[3] = x >> 24;
data[2] = x >> 16;
data[1] = x >> 8;
data[0] = x;
}
void bn_read_be(const uint8_t *in_number, bignum256 *out_number);
void bn_write_be(const bignum256 *in_number, uint8_t *out_number);
void bn_read_le(const uint8_t *in_number, bignum256 *out_number);
void bn_write_le(const bignum256 *in_number, uint8_t *out_number);
void bn_read_uint32(uint32_t in_number, bignum256 *out_number);
void bn_read_uint64(uint64_t in_number, bignum256 *out_number);
static inline uint32_t bn_write_uint32(const bignum256 *in_number) {
return in_number->val[0] | (in_number->val[1] << 30);
}
static inline uint64_t bn_write_uint64(const bignum256 *in_number) {
uint64_t tmp;
tmp = in_number->val[2];
tmp <<= 30;
tmp |= in_number->val[1];
tmp <<= 30;
tmp |= in_number->val[0];
return tmp;
}
// copies number a to b
static inline void bn_copy(const bignum256 *a, bignum256 *b) { *b = *a; }
int bn_bitcount(const bignum256 *a);
unsigned int bn_digitcount(const bignum256 *a);
void bn_zero(bignum256 *a);
int bn_is_zero(const bignum256 *a);
void bn_one(bignum256 *a);
static inline int bn_is_even(const bignum256 *a) {
return (a->val[0] & 1) == 0;
}
static inline int bn_is_odd(const bignum256 *a) { return (a->val[0] & 1) == 1; }
int bn_is_less(const bignum256 *a, const bignum256 *b);
int bn_is_equal(const bignum256 *a, const bignum256 *b);
void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase,
int bn_bitcount(const bignum256 *x);
unsigned int bn_digitcount(const bignum256 *x);
void bn_zero(bignum256 *x);
void bn_one(bignum256 *x);
int bn_is_zero(const bignum256 *x);
int bn_is_one(const bignum256 *x);
int bn_is_less(const bignum256 *x, const bignum256 *y);
int bn_is_equal(const bignum256 *x, const bignum256 *y);
void bn_cmov(bignum256 *res, volatile uint32_t cond, const bignum256 *truecase,
const bignum256 *falsecase);
void bn_lshift(bignum256 *a);
void bn_rshift(bignum256 *a);
void bn_setbit(bignum256 *a, uint8_t bit);
void bn_clearbit(bignum256 *a, uint8_t bit);
uint32_t bn_testbit(bignum256 *a, uint8_t bit);
void bn_xor(bignum256 *a, const bignum256 *b, const bignum256 *c);
void bn_cnegate(volatile uint32_t cond, bignum256 *x, const bignum256 *prime);
void bn_lshift(bignum256 *x);
void bn_rshift(bignum256 *x);
void bn_setbit(bignum256 *x, uint16_t i);
void bn_clearbit(bignum256 *x, uint16_t i);
uint32_t bn_testbit(const bignum256 *x, uint16_t i);
void bn_xor(bignum256 *res, const bignum256 *x, const bignum256 *y);
void bn_mult_half(bignum256 *x, const bignum256 *prime);
void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime);
void bn_mod(bignum256 *x, const bignum256 *prime);
void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime);
void bn_fast_mod_old(bignum256 *x, const bignum256 *prime);
void bn_fast_mod(bignum256 *x, const bignum256 *prime);
void bn_power_mod(const bignum256 *x, const bignum256 *e,
const bignum256 *prime, bignum256 *res);
void bn_sqrt(bignum256 *x, const bignum256 *prime);
void bn_inverse(bignum256 *x, const bignum256 *prime);
void bn_normalize(bignum256 *a);
void bn_add(bignum256 *a, const bignum256 *b);
void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime);
void bn_addi(bignum256 *a, uint32_t b);
void bn_subi(bignum256 *a, uint32_t b, const bignum256 *prime);
void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res,
uint32_t inverse_mod_power_two(uint32_t a, uint32_t n);
void bn_divide_base(bignum256 *x, const bignum256 *prime);
void bn_inverse_slow(bignum256 *x, const bignum256 *prime);
void bn_inverse_fast_1(bignum256 *x, const bignum256 *prime);
void bn_inverse_fast_2(bignum256 *x, const bignum256 *prime);
void bn_inverse_fast_3(bignum256 *x, const bignum256 *prime);
void bn_inverse_old(bignum256 *x, const bignum256 *prime);
void bn_normalize(bignum256 *x);
void bn_add(bignum256 *x, const bignum256 *y);
void bn_addmod(bignum256 *x, const bignum256 *y, const bignum256 *prime);
void bn_addi(bignum256 *x, uint32_t y);
void bn_subi(bignum256 *x, uint32_t y, const bignum256 *prime);
void bn_subtractmod(const bignum256 *x, const bignum256 *y, bignum256 *res,
const bignum256 *prime);
void bn_subtract(const bignum256 *x, const bignum256 *y, bignum256 *res);
void bn_long_division(bignum256 *x, uint32_t d, bignum256 *q, uint32_t *r);
void bn_divmod58(bignum256 *x, uint32_t *r);
void bn_divmod1000(bignum256 *x, uint32_t *r);
void bn_inverse(bignum256 *x, const bignum256 *prime);
size_t bn_format(const bignum256 *amount, const char *prefix,
const char *suffix, unsigned int decimals, int exponent,
bool trailing, char *output, size_t output_length);
void bn_subtract(const bignum256 *a, const bignum256 *b, bignum256 *res);
// Returns (uint32_t) in_number
// Assumes in_number < 2**32
// Assumes in_number is normalized
static inline uint32_t bn_write_uint32(const bignum256 *in_number) {
return in_number->val[0] | (in_number->val[1] << BN_BITS_PER_LIMB);
}
void bn_divmod58(bignum256 *a, uint32_t *r);
// Returns (uint64_t) in_number
// Assumes in_number < 2**64
// Assumes in_number is normalized
static inline uint64_t bn_write_uint64(const bignum256 *in_number) {
uint64_t acc;
acc = in_number->val[2];
acc <<= BN_BITS_PER_LIMB;
acc |= in_number->val[1];
acc <<= BN_BITS_PER_LIMB;
acc |= in_number->val[0];
return acc;
}
void bn_divmod1000(bignum256 *a, uint32_t *r);
// y = x
static inline void bn_copy(const bignum256 *x, bignum256 *y) { *y = *x; }
size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix,
unsigned int decimals, int exponent, bool trailing, char *out,
size_t outlen);
// Returns x % 2 == 0
static inline int bn_is_even(const bignum256 *x) {
return (x->val[0] & 1) == 0;
}
// Returns x % 2 == 0
static inline int bn_is_odd(const bignum256 *x) { return (x->val[0] & 1) == 1; }
static inline size_t bn_format_uint64(uint64_t amount, const char *prefix,
const char *suffix, unsigned int decimals,
int exponent, bool trailing, char *out,
size_t outlen) {
bignum256 amnt;
bn_read_uint64(amount, &amnt);
int exponent, bool trailing, char *output,
size_t output_length) {
bignum256 bn_amount;
bn_read_uint64(amount, &bn_amount);
return bn_format(&amnt, prefix, suffix, decimals, exponent, trailing, out,
outlen);
return bn_format(&bn_amount, prefix, suffix, decimals, exponent, trailing,
output, output_length);
}
#if USE_BN_PRINT
void bn_print(const bignum256 *a);
void bn_print_raw(const bignum256 *a);
void bn_print(const bignum256 *x);
void bn_print_raw(const bignum256 *x);
#endif
#endif

View File

@ -61,6 +61,7 @@ void point_add(const ecdsa_curve *curve, const curve_point *cp1,
return;
}
// lambda = (y2 - y1) / (x2 - x1)
bn_subtractmod(&(cp2->x), &(cp1->x), &inv, &curve->prime);
bn_inverse(&inv, &curve->prime);
bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &curve->prime);
@ -101,6 +102,8 @@ void point_double(const ecdsa_curve *curve, curve_point *cp) {
// lambda = (3 x^2 + a) / (2 y)
lambda = cp->y;
bn_mult_k(&lambda, 2, &curve->prime);
bn_fast_mod(&lambda, &curve->prime);
bn_mod(&lambda, &curve->prime);
bn_inverse(&lambda, &curve->prime);
xr = cp->x;
@ -162,22 +165,6 @@ int point_is_negative_of(const curve_point *p, const curve_point *q) {
return !bn_is_equal(&(p->y), &(q->y));
}
// Negate a (modulo prime) if cond is 0xffffffff, keep it if cond is 0.
// The timing of this function does not depend on cond.
void conditional_negate(uint32_t cond, bignum256 *a, const bignum256 *prime) {
int j = 0;
uint32_t tmp = 1;
assert(a->val[8] < 0x20000);
for (j = 0; j < 8; j++) {
tmp += 0x3fffffff + 2 * prime->val[j] - a->val[j];
a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond);
tmp >>= 30;
}
tmp += 0x3fffffff + 2 * prime->val[j] - a->val[j];
a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond);
assert(a->val[8] < 0x20000);
}
typedef struct jacobian_curve_point {
bignum256 x, y, z;
} jacobian_curve_point;
@ -187,9 +174,9 @@ static void generate_k_random(bignum256 *k, const bignum256 *prime) {
do {
int i = 0;
for (i = 0; i < 8; i++) {
k->val[i] = random32() & 0x3FFFFFFF;
k->val[i] = random32() & ((1u << BN_BITS_PER_LIMB) - 1);
}
k->val[8] = random32() & 0xFFFF;
k->val[8] = random32() & ((1u << BN_BITS_LAST_LIMB) - 1);
// check that k is in range and not zero.
} while (bn_is_zero(k) || !bn_is_less(k, prime));
}
@ -443,12 +430,12 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k,
uint32_t is_non_zero = 0;
for (j = 0; j < 8; j++) {
is_non_zero |= k->val[j];
tmp += 0x3fffffff + k->val[j] - (curve->order.val[j] & is_even);
a.val[j] = tmp & 0x3fffffff;
tmp >>= 30;
tmp += (BN_BASE - 1) + k->val[j] - (curve->order.val[j] & is_even);
a.val[j] = tmp & (BN_BASE - 1);
tmp >>= BN_BITS_PER_LIMB;
}
is_non_zero |= k->val[j];
a.val[j] = tmp + 0xffff + k->val[j] - (curve->order.val[j] & is_even);
a.val[j] = tmp + 0xffffff + k->val[j] - (curve->order.val[j] & is_even);
assert((a.val[0] & 1) != 0);
// special case 0*p: just return zero. We don't care about constant time.
@ -490,7 +477,7 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k,
// since a is odd.
aptr = &a.val[8];
abits = *aptr;
ashift = 12;
ashift = 256 - (BN_BITS_PER_LIMB * 8) - 4;
bits = abits >> ashift;
sign = (bits >> 4) - 1;
bits ^= sign;
@ -513,7 +500,7 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k,
// leaks no private information to a side-channel.
bits = abits << (-ashift);
abits = *(--aptr);
ashift += 30;
ashift += BN_BITS_PER_LIMB;
bits |= abits >> ashift;
} else {
bits = abits >> ashift;
@ -525,13 +512,13 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k,
// negate last result to make signs of this round and the
// last round equal.
conditional_negate(sign ^ nsign, &jres.z, prime);
bn_cnegate((sign ^ nsign) & 1, &jres.z, prime);
// add odd factor
point_jacobian_add(&pmult[bits >> 1], &jres, curve);
sign = nsign;
}
conditional_negate(sign, &jres.z, prime);
bn_cnegate(sign & 1, &jres.z, prime);
jacobian_to_curve(&jres, res, prime);
memzero(&a, sizeof(a));
memzero(&jres, sizeof(jres));
@ -560,12 +547,12 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k,
uint32_t is_non_zero = 0;
for (j = 0; j < 8; j++) {
is_non_zero |= k->val[j];
tmp += 0x3fffffff + k->val[j] - (curve->order.val[j] & is_even);
a.val[j] = tmp & 0x3fffffff;
tmp >>= 30;
tmp += (BN_BASE - 1) + k->val[j] - (curve->order.val[j] & is_even);
a.val[j] = tmp & (BN_BASE - 1);
tmp >>= BN_BITS_PER_LIMB;
}
is_non_zero |= k->val[j];
a.val[j] = tmp + 0xffff + k->val[j] - (curve->order.val[j] & is_even);
a.val[j] = tmp + 0xffffff + k->val[j] - (curve->order.val[j] & is_even);
assert((a.val[0] & 1) != 0);
// special case 0*G: just return zero. We don't care about constant time.
@ -603,7 +590,8 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k,
// shift a by 4 places.
for (j = 0; j < 8; j++) {
a.val[j] = (a.val[j] >> 4) | ((a.val[j + 1] & 0xf) << 26);
a.val[j] =
(a.val[j] >> 4) | ((a.val[j + 1] & 0xf) << (BN_BITS_PER_LIMB - 4));
}
a.val[j] >>= 4;
// a = old(a)>>(4*i)
@ -614,12 +602,12 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k,
lowbits &= 15;
// negate last result to make signs of this round and the
// last round equal.
conditional_negate((lowbits & 1) - 1, &jres.y, prime);
bn_cnegate(~lowbits & 1, &jres.y, prime);
// add odd factor
point_jacobian_add(&curve->cp[i][lowbits >> 1], &jres, curve);
}
conditional_negate(((a.val[0] >> 4) & 1) - 1, &jres.y, prime);
bn_cnegate(~(a.val[0] >> 4) & 1, &jres.y, prime);
jacobian_to_curve(&jres, res, prime);
memzero(&a, sizeof(a));
memzero(&jres, sizeof(jres));

View File

@ -24,30 +24,31 @@
#include "nist256p1.h"
const ecdsa_curve nist256p1 = {
/* .prime */ {/*.val =*/{0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0,
0x1000, 0x3fffc000, 0xffff}},
/* .prime */ {/*.val =*/{0x1fffffff, 0x1fffffff, 0x1fffffff, 0x000001ff,
0x00000000, 0x00000000, 0x00040000, 0x1fe00000,
0xffffff}},
/* G */
{/*.x =*/{/*.val =*/{0x1898c296, 0x1284e517, 0x1eb33a0f, 0xdf604b,
0x2440f277, 0x339b958e, 0x4247f8b, 0x347cb84b,
0x6b17}},
/*.y =*/{/*.val =*/{0x37bf51f5, 0x2ed901a0, 0x3315ecec, 0x338cd5da,
0xf9e162b, 0x1fad29f0, 0x27f9b8ee, 0x10b8bf86,
0x4fe3}}},
{/*.x =*/{/*.val =*/{0x1898c296, 0x0509ca2e, 0x1acce83d, 0x06fb025b,
0x040f2770, 0x1372b1d2, 0x091fe2f3, 0x1e5c2588,
0x6b17d1}},
/*.y =*/{/*.val =*/{0x17bf51f5, 0x1db20341, 0x0c57b3b2, 0x1c66aed6,
0x19e162bc, 0x15a53e07, 0x1e6e3b9f, 0x1c5fc34f,
0x4fe342}}},
/* order */
{/*.val =*/{0x3c632551, 0xee72b0b, 0x3179e84f, 0x39beab69, 0x3fffffbc,
0x3fffffff, 0xfff, 0x3fffc000, 0xffff}},
{/*.val =*/{0x1c632551, 0x1dce5617, 0x05e7a13c, 0x0df55b4e, 0x1ffffbce,
0x1fffffff, 0x0003ffff, 0x1fe00000, 0xffffff}},
/* order_half */
{/*.val =*/{0x3e3192a8, 0x27739585, 0x38bcf427, 0x1cdf55b4, 0x3fffffde,
0x3fffffff, 0x7ff, 0x3fffe000, 0x7fff}},
{/*.val =*/{0x1e3192a8, 0x0ee72b0b, 0x02f3d09e, 0x06faada7, 0x1ffffde7,
0x1fffffff, 0x0001ffff, 0x1ff00000, 0x7fffff}},
/* a */ -3,
/* b */
{/*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65,
0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6}}
{/*.val =*/{0x07d2604b, 0x1e71e1f1, 0x14ec3d8e, 0x1a0d6198, 0x086bc651,
0x1eaabb4c, 0x0f9ecfae, 0x1b154752, 0x005ac635}}
#if USE_PRECOMPUTED_CP
,

File diff suppressed because it is too large Load Diff

View File

@ -24,24 +24,25 @@
#include "secp256k1.h"
const ecdsa_curve secp256k1 = {
/* .prime */ {/*.val =*/{0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
0xffff}},
/* .prime */ {/*.val =*/{0x1ffffc2f, 0x1ffffff7, 0x1fffffff, 0x1fffffff,
0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
0xffffff}},
/* G */
{/*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb,
0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}},
/*.y =*/{/*.val =*/{0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229,
0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8,
0x483a}}},
{/*.x =*/{/*.val =*/{0x16f81798, 0x0f940ad8, 0x138a3656, 0x17f9b65b,
0x10b07029, 0x114ae743, 0x0eb15681, 0x0fdf3b97,
0x79be66}},
/*.y =*/{/*.val =*/{0x1b10d4b8, 0x023e847f, 0x01550667, 0x0f68914d,
0x108a8fd1, 0x1dfe0708, 0x11957693, 0x0ee4d478,
0x483ada}}},
/* order */
{/*.val =*/{0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}},
{/*.val =*/{0x10364141, 0x1e92f466, 0x12280eef, 0x1db9cd5e, 0x1fffebaa,
0x1fffffff, 0x1fffffff, 0x1fffffff, 0xffffff}},
/* order_half */
{/*.val =*/{0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}},
{/*.val =*/{0x081b20a0, 0x1f497a33, 0x09140777, 0x0edce6af, 0x1ffff5d5,
0x1fffffff, 0x1fffffff, 0x1fffffff, 0x7fffff}},
/* a */ 0,

File diff suppressed because it is too large Load Diff

1028
crypto/tests/test_bignum.py Executable file

File diff suppressed because it is too large Load Diff

View File

@ -131,8 +131,8 @@ START_TEST(test_bignum_read_be) {
bn_read_be(input, &a);
bignum256 b = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3,
0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}};
bignum256 b = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b,
0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}};
for (int i = 0; i < 9; i++) {
ck_assert_int_eq(a.val[i], b.val[i]);
@ -141,8 +141,8 @@ START_TEST(test_bignum_read_be) {
END_TEST
START_TEST(test_bignum_write_be) {
bignum256 a = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3,
0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}};
bignum256 a = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b,
0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}};
uint8_t tmp[32];
bn_write_be(&a, tmp);
@ -156,10 +156,10 @@ START_TEST(test_bignum_write_be) {
END_TEST
START_TEST(test_bignum_is_equal) {
bignum256 a = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3,
0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}};
bignum256 b = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3,
0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}};
bignum256 a = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b,
0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}};
bignum256 b = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b,
0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}};
bignum256 c = {{
0,
}};
@ -339,6 +339,13 @@ END_TEST
START_TEST(test_bignum_write_uint32) {
bignum256 a;
// lowest 29 bits set
bn_read_be(
fromhex(
"000000000000000000000000000000000000000000000000000000001fffffff"),
&a);
ck_assert_int_eq(bn_write_uint32(&a), 0x1fffffff);
// lowest 30 bits set
bn_read_be(
fromhex(
@ -637,8 +644,8 @@ START_TEST(test_bignum_format) {
"0000000000000000000000000000000000000000000000000000000000000000"),
&a);
r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf));
ck_assert_int_eq(r, 3);
ck_assert_str_eq(buf, "0.0");
ck_assert_int_eq(r, 1);
ck_assert_str_eq(buf, "0");
bn_read_be(
fromhex(
@ -757,8 +764,8 @@ START_TEST(test_bignum_format) {
"0000000000000000000000000000000000000000000000000000000000989680"),
&a);
r = bn_format(&a, NULL, NULL, 7, 0, false, buf, sizeof(buf));
ck_assert_int_eq(r, 3);
ck_assert_str_eq(buf, "1.0");
ck_assert_int_eq(r, 1);
ck_assert_str_eq(buf, "1");
bn_read_be(
fromhex(
@ -805,10 +812,10 @@ START_TEST(test_bignum_format) {
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3bbb00"),
&a);
r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf));
ck_assert_int_eq(r, 72);
ck_assert_int_eq(r, 70);
ck_assert_str_eq(buf,
"11579208923731619542357098500868790785326998466564056403945"
"75840079131.0");
"75840079131");
bn_read_be(
fromhex(
@ -825,9 +832,9 @@ START_TEST(test_bignum_format) {
"fffffffffffffffffffffffffffffffffffffffffffffffff7e52fe5afe40000"),
&a);
r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf));
ck_assert_int_eq(r, 62);
ck_assert_int_eq(r, 60);
ck_assert_str_eq(
buf, "115792089237316195423570985008687907853269984665640564039457.0");
buf, "115792089237316195423570985008687907853269984665640564039457");
bn_read_be(
fromhex(
@ -875,7 +882,69 @@ START_TEST(test_bignum_format) {
memset(buf, 'a', sizeof(buf));
r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 30);
ck_assert_int_eq(r, 0);
ck_assert_str_eq(buf, "prefix198552.9216486895suffix");
ck_assert_str_eq(buf, "");
}
END_TEST
START_TEST(test_bignum_sqrt) {
uint32_t quadratic_residua[] = {
1, 2, 4, 8, 9, 11, 15, 16, 17, 18, 19, 21, 22, 25, 29,
30, 31, 32, 34, 35, 36, 38, 39, 42, 43, 44, 47, 49, 50, 58,
59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 71, 72, 76, 78, 81,
83, 84, 86, 88, 91, 94, 98, 99, 100, 103, 107, 111, 115, 116, 118,
120, 121, 122, 123, 124, 127, 128, 130, 131, 134, 135, 136, 137, 138, 139,
140, 142, 144, 149, 152, 153, 156, 159, 161, 162, 165, 166, 167, 168, 169,
171, 172, 176, 181, 182, 185, 187, 188, 189, 191, 193, 196, 197, 198, 200,
205, 206, 209, 214, 219, 222, 223, 225, 229, 230, 231, 232, 233, 236, 237,
239, 240, 242, 244, 246, 248, 254, 255, 256, 259, 260, 261, 262, 265, 267,
268, 269, 270, 272, 274, 275, 276, 277, 278, 279, 280, 281, 284, 285, 287,
288, 289, 291, 293, 298, 299, 303, 304, 306, 311, 312, 315, 318, 319, 322,
323, 324, 327, 330, 331, 332, 334, 336, 337, 338, 339, 341, 342, 344, 349,
351, 352, 353, 357, 359, 361, 362, 364, 365, 370, 371, 373, 374, 375, 376,
378, 379, 382, 383, 385, 386, 387, 389, 392, 394, 395, 396, 399, 400, 409,
410, 412, 418, 421, 423, 425, 428, 429, 431, 435, 438, 439, 441, 443, 444,
445, 446, 450, 453, 458, 460, 461, 462, 463, 464, 465, 466, 467, 471, 472,
473, 474, 475, 478, 479, 480, 481, 484, 485, 487, 488, 489, 492, 493, 496,
503, 505, 508, 510, 511, 512, 517, 518, 519, 520, 521, 522, 523, 524, 525,
527, 529, 530, 531, 533, 534, 536, 537, 538, 539, 540, 541, 544, 545, 547,
548, 549, 550, 551, 552, 553, 554, 556, 557, 558, 560, 562, 563, 565, 568,
570, 571, 574, 576, 578, 582, 585, 586, 587, 589, 595, 596, 597, 598, 599,
603, 606, 607, 608, 609, 612, 613, 619, 621, 622, 623, 624, 625, 630, 633,
636, 638, 639, 644, 645, 646, 648, 649, 651, 653, 654, 660, 662, 663, 664,
665, 668, 671, 672, 673, 674, 676, 678, 679, 681, 682, 684, 688, 689, 698,
702, 704, 705, 706, 707, 714, 715, 718, 722, 723, 724, 725, 728, 729, 730,
731, 733, 735, 737, 740, 741, 742, 746, 747, 748, 750, 751, 752, 753, 755,
756, 758, 759, 761, 763, 764, 766, 769, 770, 771, 772, 774, 775, 778, 781,
784, 785, 788, 789, 790, 791, 792, 797, 798, 799, 800, 813, 815, 817, 818,
819, 820, 823, 824, 833, 836, 841, 842, 846, 849, 850, 851, 856, 857, 858,
862, 865, 870, 875, 876, 878, 882, 885, 886, 887, 888, 890, 891, 892, 893,
895, 899, 900, 903, 906, 907, 911, 913, 915, 916, 919, 920, 921, 922, 924,
926, 927, 928, 930, 931, 932, 934, 937, 939, 942, 943, 944, 946, 948, 949,
950, 951, 953, 956, 958, 960, 961, 962, 963, 968, 970, 971, 974, 975, 976,
977, 978, 984, 986, 987, 992, 995, 999};
bignum256 a, b;
bn_zero(&a);
b = a;
bn_sqrt(&b, &secp256k1.prime);
ck_assert_int_eq(bn_is_equal(&a, &b), 1);
bn_one(&a);
b = a;
bn_sqrt(&b, &secp256k1.prime);
ck_assert_int_eq(bn_is_equal(&a, &b), 1);
// test some quadratic residua
for (size_t i = 0; i < sizeof(quadratic_residua) / sizeof(*quadratic_residua);
i++) {
bn_read_uint32(quadratic_residua[i], &a);
b = a;
bn_sqrt(&b, &secp256k1.prime);
bn_multiply(&b, &b, &secp256k1.prime);
bn_mod(&b, &secp256k1.prime);
ck_assert_int_eq(bn_is_equal(&a, &b), 1);
}
}
END_TEST
@ -1102,12 +1171,16 @@ START_TEST(test_bignum_divmod) {
uint32_t r;
int i;
bignum256 a = {{0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}};
bignum256 a;
uint32_t ar[] = {15, 14, 55, 29, 44, 24, 53, 49, 18, 55, 2, 28, 5, 4, 12,
43, 18, 37, 28, 14, 30, 46, 12, 11, 17, 10, 10, 13, 24, 45,
4, 33, 44, 42, 2, 46, 34, 43, 45, 28, 21, 18, 13, 17};
bn_read_be(
fromhex(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
&a);
i = 0;
while (!bn_is_zero(&a) && i < 44) {
bn_divmod58(&a, &r);
@ -1116,12 +1189,15 @@ START_TEST(test_bignum_divmod) {
}
ck_assert_int_eq(i, 44);
bignum256 b = {{0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}};
bignum256 b;
uint32_t br[] = {935, 639, 129, 913, 7, 584, 457, 39, 564,
640, 665, 984, 269, 853, 907, 687, 8, 985,
570, 423, 195, 316, 237, 89, 792, 115};
bn_read_be(
fromhex(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
&b);
i = 0;
while (!bn_is_zero(&b) && i < 26) {
bn_divmod1000(&b, &r);
@ -5904,7 +5980,8 @@ static void test_codepoints_curve(const ecdsa_curve *curve) {
for (i = 0; i < 64; i++) {
for (j = 0; j < 8; j++) {
bn_zero(&a);
a.val[(4 * i) / 30] = (uint32_t)(2 * j + 1) << (4 * i % 30);
a.val[(4 * i) / BN_BITS_PER_LIMB] = (uint32_t)(2 * j + 1)
<< (4 * i % BN_BITS_PER_LIMB);
bn_normalize(&a);
// note that this is not a trivial test. We add 64 curve
// points in the table to get that particular curve point.
@ -8670,6 +8747,7 @@ Suite *test_suite(void) {
tcase_add_test(tc, test_bignum_is_less);
tcase_add_test(tc, test_bignum_format);
tcase_add_test(tc, test_bignum_format_uint64);
tcase_add_test(tc, test_bignum_sqrt);
suite_add_tcase(s, tc);
tc = tcase_create("base32");

View File

@ -80,14 +80,29 @@ random_iters = int(os.environ.get("ITERS", 1))
DIR = os.path.abspath(os.path.dirname(__file__))
lib = c.cdll.LoadLibrary(os.path.join(DIR, "libtrezor-crypto.so"))
BIGNUM = c.c_uint32 * 9
class curve_info(c.Structure):
_fields_ = [("bip32_name", c.c_char_p), ("params", c.c_void_p)]
lib.get_curve_by_name.restype = c.POINTER(curve_info)
class curve_point(c.Structure):
_fields_ = [("x", BIGNUM), ("y", BIGNUM)]
BIGNUM = c.c_uint32 * 9
class ecdsa_curve(c.Structure):
_fields_ = [
("prime", BIGNUM),
("G", curve_point),
("order", BIGNUM),
("order_half", BIGNUM),
("a", c.c_int),
("b", BIGNUM),
]
lib.get_curve_by_name.restype = c.POINTER(curve_info)
class Random(random.Random):
@ -106,15 +121,15 @@ def int2bn(x, bn_type=BIGNUM):
b = bn_type()
b._int = x
for i in range(len(b)):
b[i] = x % (1 << 30)
x = x >> 30
b[i] = x % (1 << 29)
x = x >> 29
return b
def bn2int(b):
x = 0
for i in range(len(b)):
x += b[i] << (30 * i)
x += b[i] << (29 * i)
return x
@ -130,7 +145,7 @@ def curve(request):
curve_ptr = lib.get_curve_by_name(bytes(name, "ascii")).contents.params
assert curve_ptr, "curve {} not found".format(name)
curve_obj = curves[name]
curve_obj.ptr = c.c_void_p(curve_ptr)
curve_obj.ptr = c.cast(curve_ptr, c.POINTER(ecdsa_curve))
curve_obj.p = curve_obj.curve.p() # shorthand
return curve_obj
@ -148,176 +163,6 @@ def point(request):
return curve_obj
def test_inverse(curve, r):
x = r.randrange(1, curve.p)
y = int2bn(x)
lib.bn_inverse(y, int2bn(curve.p))
y = bn2int(y)
y_ = ecdsa.numbertheory.inverse_mod(x, curve.p)
assert y == y_
def test_is_less(curve, r):
x = r.randrange(0, curve.p)
y = r.randrange(0, curve.p)
x_ = int2bn(x)
y_ = int2bn(y)
res = lib.bn_is_less(x_, y_)
assert res == (x < y)
res = lib.bn_is_less(y_, x_)
assert res == (y < x)
def test_is_equal(curve, r):
x = r.randrange(0, curve.p)
y = r.randrange(0, curve.p)
x_ = int2bn(x)
y_ = int2bn(y)
assert lib.bn_is_equal(x_, y_) == (x == y)
assert lib.bn_is_equal(x_, x_) == 1
assert lib.bn_is_equal(y_, y_) == 1
def test_is_zero(curve, r):
x = r.randrange(0, curve.p)
assert lib.bn_is_zero(int2bn(x)) == (not x)
def test_simple_comparisons():
assert lib.bn_is_zero(int2bn(0)) == 1
assert lib.bn_is_zero(int2bn(1)) == 0
assert lib.bn_is_less(int2bn(0), int2bn(0)) == 0
assert lib.bn_is_less(int2bn(1), int2bn(0)) == 0
assert lib.bn_is_less(int2bn(0), int2bn(1)) == 1
assert lib.bn_is_equal(int2bn(0), int2bn(0)) == 1
assert lib.bn_is_equal(int2bn(1), int2bn(0)) == 0
assert lib.bn_is_equal(int2bn(0), int2bn(1)) == 0
def test_mult_half(curve, r):
x = r.randrange(0, 2 * curve.p)
y = int2bn(x)
lib.bn_mult_half(y, int2bn(curve.p))
y = bn2int(y)
if y >= curve.p:
y -= curve.p
half = ecdsa.numbertheory.inverse_mod(2, curve.p)
assert y == (x * half) % curve.p
def test_subtractmod(curve, r):
x = r.randrange(0, 2 ** 256)
y = r.randrange(0, 2 ** 256)
z = int2bn(0)
lib.bn_subtractmod(int2bn(x), int2bn(y), z, int2bn(curve.p))
z = bn2int(z)
z_ = x + 2 * curve.p - y
assert z == z_
def test_subtract2(r):
x = r.randrange(0, 2 ** 256)
y = r.randrange(0, 2 ** 256)
x, y = max(x, y), min(x, y)
z = int2bn(0)
lib.bn_subtract(int2bn(x), int2bn(y), z)
z = bn2int(z)
z_ = x - y
assert z == z_
def test_add(curve, r):
x = r.randrange(0, 2 ** 256)
y = r.randrange(0, 2 ** 256)
z_ = x + y
z = int2bn(x)
lib.bn_add(z, int2bn(y))
z = bn2int(z)
assert z == z_
def test_addmod(curve, r):
x = r.randrange(0, 2 ** 256)
y = r.randrange(0, 2 ** 256)
z_ = (x + y) % curve.p
z = int2bn(x)
lib.bn_addmod(z, int2bn(y), int2bn(curve.p))
z = bn2int(z)
if z >= curve.p:
z = z - curve.p
assert z == z_
def test_multiply(curve, r):
k = r.randrange(0, 2 * curve.p)
x = r.randrange(0, 2 * curve.p)
z = (k * x) % curve.p
k = int2bn(k)
z_ = int2bn(x)
p_ = int2bn(curve.p)
lib.bn_multiply(k, z_, p_)
z_ = bn2int(z_)
assert z_ < 2 * curve.p
if z_ >= curve.p:
z_ = z_ - curve.p
assert z_ == z
def test_multiply1(curve, r):
k = r.randrange(0, 2 * curve.p)
x = r.randrange(0, 2 * curve.p)
kx = k * x
res = int2bn(0, bn_type=(c.c_uint32 * 18))
lib.bn_multiply_long(int2bn(k), int2bn(x), res)
res = bn2int(res)
assert res == kx
def test_multiply2(curve, r):
x = int2bn(0)
s = r.randrange(0, 2 ** 526)
res = int2bn(s, bn_type=(c.c_uint32 * 18))
prime = int2bn(curve.p)
lib.bn_multiply_reduce(x, res, prime)
x = bn2int(x) % curve.p
x_ = s % curve.p
assert x == x_
def test_fast_mod(curve, r):
x = r.randrange(0, 128 * curve.p)
y = int2bn(x)
lib.bn_fast_mod(y, int2bn(curve.p))
y = bn2int(y)
assert y < 2 * curve.p
if y >= curve.p:
y -= curve.p
assert x % curve.p == y
def test_mod(curve, r):
x = r.randrange(0, 2 * curve.p)
y = int2bn(x)
lib.bn_mod(y, int2bn(curve.p))
assert bn2int(y) == x % curve.p
def test_mod_specific(curve):
p = curve.p
for x in [0, 1, 2, p - 2, p - 1, p, p + 1, p + 2, 2 * p - 2, 2 * p - 1]:
y = int2bn(x)
lib.bn_mod(y, int2bn(curve.p))
assert bn2int(y) == x % p
POINT = BIGNUM * 2
@ -340,6 +185,16 @@ def from_JACOBIAN(p):
return (bn2int(p[0]), bn2int(p[1]), bn2int(p[2]))
def test_curve_parameters(curve):
assert curve.curve.p() == bn2int(curve.ptr.contents.prime)
assert curve.generator.x() == bn2int(curve.ptr.contents.G.x)
assert curve.generator.y() == bn2int(curve.ptr.contents.G.y)
assert curve.order == bn2int(curve.ptr.contents.order)
assert curve.order // 2 == bn2int(curve.ptr.contents.order_half)
assert curve.curve.a() == curve.ptr.contents.a
assert curve.curve.b() == bn2int(curve.ptr.contents.b)
def test_point_multiply(curve, r):
p = r.randpoint(curve)
k = r.randrange(0, 2 ** 256)
@ -385,15 +240,6 @@ def test_point_to_jacobian(curve, r):
assert q == (p.x(), p.y())
def test_cond_negate(curve, r):
x = r.randrange(0, curve.p)
a = int2bn(x)
lib.conditional_negate(0, a, int2bn(curve.p))
assert bn2int(a) == x
lib.conditional_negate(-1, a, int2bn(curve.p))
assert bn2int(a) == 2 * curve.p - x
def test_jacobian_add(curve, r):
p1 = r.randpoint(curve)
p2 = r.randpoint(curve)

View File

@ -39,7 +39,8 @@ int main(int argc, char **argv) {
curve_point checkresult;
bignum256 a;
bn_zero(&a);
a.val[(4 * i) / 30] = ((uint32_t)2 * j + 1) << ((4 * i) % 30);
a.val[(4 * i) / BN_BITS_PER_LIMB] = ((uint32_t)2 * j + 1)
<< ((4 * i) % BN_BITS_PER_LIMB);
bn_normalize(&a);
point_multiply(curve, &a, &curve->G, &checkresult);
assert(point_is_equal(&checkresult, &ng));