From 79359302fbc8d870a484882f2995e3c0dad4a2eb Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 29 Oct 2014 00:35:38 -0700 Subject: [PATCH] Add unit tests for scalars. Also add a secp256k1_scalar_is_one function. --- src/scalar.h | 3 + src/scalar_impl.h | 5 + src/tests.c | 260 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+) diff --git a/src/scalar.h b/src/scalar.h index 738b3fe..a7dde37 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -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); diff --git a/src/scalar_impl.h b/src/scalar_impl.h index 64c9266..03b2891 100644 --- a/src/scalar_impl.h +++ b/src/scalar_impl.h @@ -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; } diff --git a/src/tests.c b/src/tests.c index 684b331..57afcf8 100644 --- a/src/tests.c +++ b/src/tests.c @@ -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) { @@ -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();