Merge pull request #76

7935930 Add unit tests for scalars. (Pieter Wuille)
eca6cdb Switch scalar to use get/set 32-byte arrays (Pieter Wuille)
This commit is contained in:
Pieter Wuille 2014-10-30 06:08:30 -07:00
commit 9c698f16d6
No known key found for this signature in database
GPG Key ID: 57896D2FF8F0B657
6 changed files with 309 additions and 28 deletions

View File

@ -159,7 +159,7 @@ int static secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_
int overflow = 0;
secp256k1_scalar_t sigr;
secp256k1_scalar_init(&sigr);
secp256k1_scalar_set_bin(&sigr, b, 32, &overflow);
secp256k1_scalar_set_b32(&sigr, b, &overflow);
if (recid)
*recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
secp256k1_scalar_t n;

View File

@ -73,7 +73,10 @@ int static secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned
if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1])
return 0;
int overflow = 0;
secp256k1_scalar_set_bin(key, privkey+2, privkey[1], &overflow);
unsigned char c[32] = {0};
memcpy(c + 32 - privkey[1], privkey + 2, privkey[1]);
secp256k1_scalar_set_b32(key, c, &overflow);
memset(c, 0, 32);
return !overflow;
}
@ -99,7 +102,7 @@ int static secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privke
};
unsigned char *ptr = privkey;
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
secp256k1_scalar_get_bin(ptr, 32, key); ptr += 32;
secp256k1_scalar_get_b32(ptr, key); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
int pubkeylen = 0;
secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 1); ptr += pubkeylen;
@ -123,7 +126,7 @@ int static secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privke
};
unsigned char *ptr = privkey;
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
secp256k1_scalar_get_bin(ptr, 32, key); ptr += 32;
secp256k1_scalar_get_b32(ptr, key); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
int pubkeylen = 0;
secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 0); ptr += pubkeylen;

View File

@ -25,10 +25,10 @@ void static secp256k1_scalar_free(secp256k1_scalar_t *r);
int static secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, int offset, int count);
/** Set a scalar from a big endian byte array. */
void static secp256k1_scalar_set_bin(secp256k1_scalar_t *r, const unsigned char *bin, int len, int *overflow);
void static secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *bin, int *overflow);
/** Convert a scalar to a byte array. */
void static secp256k1_scalar_get_bin(unsigned char *bin, int len, const secp256k1_scalar_t* a);
void static secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a);
/** Add two scalars together (modulo the group order). */
void static secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
@ -45,6 +45,9 @@ void static secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scala
/** Check whether a scalar equals zero. */
int static secp256k1_scalar_is_zero(const secp256k1_scalar_t *a);
/** Check whether a scalar equals one. */
int static secp256k1_scalar_is_one(const secp256k1_scalar_t *a);
/** Check whether a scalar is higher than the group order divided by 2. */
int static secp256k1_scalar_is_high(const secp256k1_scalar_t *a);

View File

@ -27,16 +27,16 @@ int static secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, int offset, in
return secp256k1_num_get_bits(&a->n, offset, count);
}
void static secp256k1_scalar_set_bin(secp256k1_scalar_t *r, const unsigned char *bin, int len, int *overflow) {
secp256k1_num_set_bin(&r->n, bin, len);
void static secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *bin, int *overflow) {
secp256k1_num_set_bin(&r->n, bin, 32);
if (overflow) {
*overflow = secp256k1_num_cmp(&r->n, &secp256k1_ge_consts->order) >= 0;
}
secp256k1_num_mod(&r->n, &secp256k1_ge_consts->order);
}
void static secp256k1_scalar_get_bin(unsigned char *bin, int len, const secp256k1_scalar_t* a) {
secp256k1_num_get_bin(bin, len, &a->n);
void static secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) {
secp256k1_num_get_bin(bin, 32, &a->n);
}
void static secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
@ -54,12 +54,17 @@ void static secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal
void static secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) {
secp256k1_num_sub(&r->n, &secp256k1_ge_consts->order, &a->n);
secp256k1_num_mod(&r->n, &secp256k1_ge_consts->order);
}
int static secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) {
return secp256k1_num_is_zero(&a->n);
}
int static secp256k1_scalar_is_one(const secp256k1_scalar_t *a) {
return secp256k1_num_bits(&a->n) == 1;
}
int static secp256k1_scalar_is_high(const secp256k1_scalar_t *a) {
return secp256k1_num_cmp(&a->n, &secp256k1_ge_consts->half_order) > 0;
}

View File

@ -80,10 +80,15 @@ int secp256k1_ecdsa_sign(const unsigned char *message, int messagelen, unsigned
secp256k1_scalar_init(&sec);
secp256k1_scalar_init(&non);
secp256k1_scalar_init(&msg);
secp256k1_scalar_set_bin(&sec, seckey, 32, NULL);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
int overflow = 0;
secp256k1_scalar_set_bin(&non, nonce, 32, &overflow);
secp256k1_scalar_set_bin(&msg, message, messagelen, NULL);
secp256k1_scalar_set_b32(&non, nonce, &overflow);
{
unsigned char c[32] = {0};
memcpy(c + 32 - messagelen, message, messagelen);
secp256k1_scalar_set_b32(&msg, c, NULL);
memset(c, 0, 32);
}
int ret = !secp256k1_scalar_is_zero(&non) && !overflow;
secp256k1_ecdsa_sig_t sig;
secp256k1_ecdsa_sig_init(&sig);
@ -115,10 +120,15 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *message, int messagelen, u
secp256k1_scalar_init(&sec);
secp256k1_scalar_init(&non);
secp256k1_scalar_init(&msg);
secp256k1_scalar_set_bin(&sec, seckey, 32, NULL);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
int overflow = 0;
secp256k1_scalar_set_bin(&non, nonce, 32, &overflow);
secp256k1_scalar_set_bin(&msg, message, messagelen, NULL);
secp256k1_scalar_set_b32(&non, nonce, &overflow);
{
unsigned char c[32] = {0};
memcpy(c + 32 - messagelen, message, messagelen);
secp256k1_scalar_set_b32(&msg, c, NULL);
memset(c, 0, 32);
}
int ret = !secp256k1_scalar_is_zero(&non) && !overflow;
secp256k1_ecdsa_sig_t sig;
secp256k1_ecdsa_sig_init(&sig);
@ -173,7 +183,7 @@ int secp256k1_ec_seckey_verify(const unsigned char *seckey) {
secp256k1_scalar_t sec;
secp256k1_scalar_init(&sec);
int overflow;
secp256k1_scalar_set_bin(&sec, seckey, 32, &overflow);
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
int ret = !secp256k1_scalar_is_zero(&sec) && !overflow;
secp256k1_scalar_clear(&sec);
secp256k1_scalar_free(&sec);
@ -195,7 +205,7 @@ int secp256k1_ec_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsi
secp256k1_scalar_t sec;
secp256k1_scalar_init(&sec);
secp256k1_scalar_set_bin(&sec, seckey, 32, NULL);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
secp256k1_gej_t pj;
secp256k1_ecmult_gen(&pj, &sec);
secp256k1_scalar_clear(&sec);
@ -224,14 +234,14 @@ int secp256k1_ec_privkey_tweak_add(unsigned char *seckey, const unsigned char *t
secp256k1_scalar_t term;
secp256k1_scalar_init(&term);
int overflow = 0;
secp256k1_scalar_set_bin(&term, tweak, 32, &overflow);
secp256k1_scalar_set_b32(&term, tweak, &overflow);
secp256k1_scalar_t sec;
secp256k1_scalar_init(&sec);
secp256k1_scalar_set_bin(&sec, seckey, 32, NULL);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
int ret = secp256k1_eckey_privkey_tweak_add(&sec, &term) && !overflow;
if (ret) {
secp256k1_scalar_get_bin(seckey, 32, &sec);
secp256k1_scalar_get_b32(seckey, &sec);
}
secp256k1_scalar_clear(&sec);
@ -271,13 +281,13 @@ int secp256k1_ec_privkey_tweak_mul(unsigned char *seckey, const unsigned char *t
secp256k1_scalar_t factor;
secp256k1_scalar_init(&factor);
int overflow = 0;
secp256k1_scalar_set_bin(&factor, tweak, 32, &overflow);
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
secp256k1_scalar_t sec;
secp256k1_scalar_init(&sec);
secp256k1_scalar_set_bin(&sec, seckey, 32, NULL);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
int ret = secp256k1_eckey_privkey_tweak_mul(&sec, &factor) && !overflow;
if (ret) {
secp256k1_scalar_get_bin(seckey, 32, &sec);
secp256k1_scalar_get_b32(seckey, &sec);
}
secp256k1_scalar_clear(&sec);
@ -317,7 +327,7 @@ int secp256k1_ec_privkey_export(const unsigned char *seckey, unsigned char *priv
secp256k1_scalar_t key;
secp256k1_scalar_init(&key);
secp256k1_scalar_set_bin(&key, seckey, 32, NULL);
secp256k1_scalar_set_b32(&key, seckey, NULL);
int ret = secp256k1_eckey_privkey_serialize(privkey, privkeylen, &key, compressed);
secp256k1_scalar_clear(&key);
secp256k1_scalar_free(&key);
@ -332,7 +342,7 @@ int secp256k1_ec_privkey_import(unsigned char *seckey, const unsigned char *priv
secp256k1_scalar_init(&key);
int ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen);
if (ret)
secp256k1_scalar_get_bin(seckey, 32, &key);
secp256k1_scalar_get_b32(seckey, &key);
secp256k1_scalar_clear(&key);
secp256k1_scalar_free(&key);
return ret;

View File

@ -46,7 +46,7 @@ void random_scalar_order_test(secp256k1_scalar_t *num) {
unsigned char b32[32];
secp256k1_rand256_test(b32);
int overflow = 0;
secp256k1_scalar_set_bin(num, b32, 32, &overflow);
secp256k1_scalar_set_b32(num, b32, &overflow);
if (overflow || secp256k1_scalar_is_zero(num))
continue;
break;
@ -221,6 +221,263 @@ void run_num_smalltests() {
run_num_int();
}
/***** SCALAR TESTS *****/
int secp256k1_scalar_eq(const secp256k1_scalar_t *s1, const secp256k1_scalar_t *s2) {
secp256k1_scalar_t t;
secp256k1_scalar_init(&t);
secp256k1_scalar_negate(&t, s2);
secp256k1_scalar_add(&t, &t, s1);
int ret = secp256k1_scalar_is_zero(&t);
secp256k1_scalar_free(&t);
return ret;
}
void scalar_test(void) {
unsigned char c[32];
// Set 's' to a random scalar, with value 'snum'.
secp256k1_rand256_test(c);
secp256k1_scalar_t s;
secp256k1_scalar_init(&s);
secp256k1_scalar_set_b32(&s, c, NULL);
secp256k1_num_t snum;
secp256k1_num_init(&snum);
secp256k1_num_set_bin(&snum, c, 32);
secp256k1_num_mod(&snum, &secp256k1_ge_consts->order);
// Set 's1' to a random scalar, with value 's1num'.
secp256k1_rand256_test(c);
secp256k1_scalar_t s1;
secp256k1_scalar_init(&s1);
secp256k1_scalar_set_b32(&s1, c, NULL);
secp256k1_num_t s1num;
secp256k1_num_init(&s1num);
secp256k1_num_set_bin(&s1num, c, 32);
secp256k1_num_mod(&s1num, &secp256k1_ge_consts->order);
// Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'.
secp256k1_rand256_test(c);
secp256k1_scalar_t s2;
secp256k1_scalar_init(&s2);
int overflow = 0;
secp256k1_scalar_set_b32(&s2, c, &overflow);
secp256k1_num_t s2num;
secp256k1_num_init(&s2num);
secp256k1_num_set_bin(&s2num, c, 32);
secp256k1_num_mod(&s2num, &secp256k1_ge_consts->order);
{
// Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it.
secp256k1_num_t n, t, m;
secp256k1_num_init(&n);
secp256k1_num_init(&t);
secp256k1_num_init(&m);
secp256k1_num_set_int(&n, 0);
secp256k1_num_set_int(&m, 16);
for (int i = 0; i < 256; i += 4) {
secp256k1_num_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4));
secp256k1_num_mul(&n, &n, &m);
secp256k1_num_add(&n, &n, &t);
}
CHECK(secp256k1_num_eq(&n, &snum));
secp256k1_num_free(&m);
secp256k1_num_free(&t);
secp256k1_num_free(&n);
}
{
// Test that get_b32 returns the same as get_bin on the number.
unsigned char r1[32];
secp256k1_scalar_get_b32(r1, &s2);
unsigned char r2[32];
secp256k1_num_get_bin(r2, 32, &s2num);
CHECK(memcmp(r1, r2, 32) == 0);
// If no overflow occurred when assigning, it should also be equal to the original byte array.
CHECK((memcmp(r1, c, 32) == 0) == (overflow == 0));
}
{
// Test that adding the scalars together is equal to adding their numbers together modulo the order.
secp256k1_num_t rnum;
secp256k1_num_init(&rnum);
secp256k1_num_add(&rnum, &snum, &s2num);
secp256k1_num_mod(&rnum, &secp256k1_ge_consts->order);
secp256k1_scalar_t r;
secp256k1_scalar_init(&r);
secp256k1_scalar_add(&r, &s, &s2);
secp256k1_num_t r2num;
secp256k1_num_init(&r2num);
secp256k1_scalar_get_num(&r2num, &r);
CHECK(secp256k1_num_eq(&rnum, &r2num));
secp256k1_num_free(&r2num);
secp256k1_num_free(&rnum);
secp256k1_scalar_free(&r);
}
{
// Test that multipying the scalars is equal to multiplying their numbers modulo the order.
secp256k1_num_t rnum;
secp256k1_num_init(&rnum);
secp256k1_num_mul(&rnum, &snum, &s2num);
secp256k1_num_mod(&rnum, &secp256k1_ge_consts->order);
secp256k1_scalar_t r;
secp256k1_scalar_init(&r);
secp256k1_scalar_mul(&r, &s, &s2);
secp256k1_num_t r2num;
secp256k1_num_init(&r2num);
secp256k1_scalar_get_num(&r2num, &r);
CHECK(secp256k1_num_eq(&rnum, &r2num));
// The result can only be zero if at least one of the factors was zero.
CHECK(secp256k1_scalar_is_zero(&r) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_zero(&s2)));
// The results can only be equal to one of the factors if that factor was zero, or the other factor was one.
CHECK(secp256k1_num_eq(&rnum, &snum) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_one(&s2)));
CHECK(secp256k1_num_eq(&rnum, &s2num) == (secp256k1_scalar_is_zero(&s2) || secp256k1_scalar_is_one(&s)));
secp256k1_num_free(&r2num);
secp256k1_num_free(&rnum);
secp256k1_scalar_free(&r);
}
{
// Check that comparison with zero matches comparison with zero on the number.
CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s));
// Check that comparison with the half order is equal to testing for high scalar.
CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &secp256k1_ge_consts->half_order) > 0));
secp256k1_scalar_t neg;
secp256k1_scalar_init(&neg);
secp256k1_scalar_negate(&neg, &s);
secp256k1_num_t negnum;
secp256k1_num_init(&negnum);
secp256k1_num_sub(&negnum, &secp256k1_ge_consts->order, &snum);
secp256k1_num_mod(&negnum, &secp256k1_ge_consts->order);
// Check that comparison with the half order is equal to testing for high scalar after negation.
CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &secp256k1_ge_consts->half_order) > 0));
// Negating should change the high property, unless the value was already zero.
CHECK((secp256k1_scalar_is_high(&s) == secp256k1_scalar_is_high(&neg)) == secp256k1_scalar_is_zero(&s));
secp256k1_num_t negnum2;
secp256k1_num_init(&negnum2);
secp256k1_scalar_get_num(&negnum2, &neg);
// Negating a scalar should be equal to (order - n) mod order on the number.
CHECK(secp256k1_num_eq(&negnum, &negnum2));
secp256k1_scalar_add(&neg, &neg, &s);
// Adding a number to its negation should result in zero.
CHECK(secp256k1_scalar_is_zero(&neg));
secp256k1_scalar_negate(&neg, &neg);
// Negating zero should still result in zero.
CHECK(secp256k1_scalar_is_zero(&neg));
secp256k1_num_free(&negnum);
secp256k1_num_free(&negnum2);
secp256k1_scalar_free(&neg);
}
{
// Test that scalar inverses are equal to the inverse of their number modulo the order.
if (!secp256k1_scalar_is_zero(&s)) {
secp256k1_scalar_t inv;
secp256k1_scalar_init(&inv);
secp256k1_scalar_inverse(&inv, &s);
secp256k1_num_t invnum;
secp256k1_num_init(&invnum);
secp256k1_num_mod_inverse(&invnum, &snum, &secp256k1_ge_consts->order);
secp256k1_num_t invnum2;
secp256k1_num_init(&invnum2);
secp256k1_scalar_get_num(&invnum2, &inv);
CHECK(secp256k1_num_eq(&invnum, &invnum2));
secp256k1_scalar_mul(&inv, &inv, &s);
// Multiplying a scalar with its inverse must result in one.
CHECK(secp256k1_scalar_is_one(&inv));
secp256k1_scalar_inverse(&inv, &inv);
// Inverting one must result in one.
CHECK(secp256k1_scalar_is_one(&inv));
secp256k1_num_free(&invnum);
secp256k1_num_free(&invnum2);
secp256k1_scalar_free(&inv);
}
}
{
// Test commutativity of add.
secp256k1_scalar_t r1, r2;
secp256k1_scalar_init(&r1);
secp256k1_scalar_init(&r2);
secp256k1_scalar_add(&r1, &s1, &s2);
secp256k1_scalar_add(&r2, &s2, &s1);
CHECK(secp256k1_scalar_eq(&r1, &r2));
secp256k1_scalar_free(&r1);
secp256k1_scalar_free(&r2);
}
{
// Test commutativity of mul.
secp256k1_scalar_t r1, r2;
secp256k1_scalar_init(&r1);
secp256k1_scalar_init(&r2);
secp256k1_scalar_mul(&r1, &s1, &s2);
secp256k1_scalar_mul(&r2, &s2, &s1);
CHECK(secp256k1_scalar_eq(&r1, &r2));
secp256k1_scalar_free(&r1);
secp256k1_scalar_free(&r2);
}
{
// Test associativity of add.
secp256k1_scalar_t r1, r2;
secp256k1_scalar_init(&r1);
secp256k1_scalar_init(&r2);
secp256k1_scalar_add(&r1, &s1, &s2);
secp256k1_scalar_add(&r1, &r1, &s);
secp256k1_scalar_add(&r2, &s2, &s);
secp256k1_scalar_add(&r2, &s1, &r2);
CHECK(secp256k1_scalar_eq(&r1, &r2));
secp256k1_scalar_free(&r1);
secp256k1_scalar_free(&r2);
}
{
// Test associativity of mul.
secp256k1_scalar_t r1, r2;
secp256k1_scalar_init(&r1);
secp256k1_scalar_init(&r2);
secp256k1_scalar_mul(&r1, &s1, &s2);
secp256k1_scalar_mul(&r1, &r1, &s);
secp256k1_scalar_mul(&r2, &s2, &s);
secp256k1_scalar_mul(&r2, &s1, &r2);
CHECK(secp256k1_scalar_eq(&r1, &r2));
secp256k1_scalar_free(&r1);
secp256k1_scalar_free(&r2);
}
{
// Test distributitivity of mul over add.
secp256k1_scalar_t r1, r2, t;
secp256k1_scalar_init(&r1);
secp256k1_scalar_init(&r2);
secp256k1_scalar_init(&t);
secp256k1_scalar_add(&r1, &s1, &s2);
secp256k1_scalar_mul(&r1, &r1, &s);
secp256k1_scalar_mul(&r2, &s1, &s);
secp256k1_scalar_mul(&t, &s2, &s);
secp256k1_scalar_add(&r2, &r2, &t);
CHECK(secp256k1_scalar_eq(&r1, &r2));
secp256k1_scalar_free(&r1);
secp256k1_scalar_free(&r2);
secp256k1_scalar_free(&t);
}
secp256k1_num_free(&snum);
secp256k1_scalar_free(&s);
secp256k1_num_free(&s1num);
secp256k1_scalar_free(&s1);
secp256k1_num_free(&s2num);
secp256k1_scalar_free(&s2);
}
void run_scalar_tests(void) {
for (int i = 0; i < 128 * count; i++) {
scalar_test();
}
}
/***** FIELD TESTS *****/
void random_fe(secp256k1_fe_t *x) {
@ -677,7 +934,7 @@ void test_ecdsa_openssl() {
secp256k1_scalar_init(&msg);
unsigned char message[32];
secp256k1_rand256_test(message);
secp256k1_scalar_set_bin(&msg, message, 32, NULL);
secp256k1_scalar_set_b32(&msg, message, NULL);
secp256k1_scalar_init(&key);
random_scalar_order_test(&key);
secp256k1_gej_t qj;
@ -746,6 +1003,9 @@ int main(int argc, char **argv) {
// num tests
run_num_smalltests();
// scalar tests
run_scalar_tests();
// field tests
run_field_inv();
run_field_inv_var();