From d890f4d859abb2bb64ecc59b93bea13fe7ec5642 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 22:48:06 +0100 Subject: [PATCH 01/12] tests: include bn_read_be --- tests.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests.c b/tests.c index 6dae737c8a..5666cb8e3c 100644 --- a/tests.c +++ b/tests.c @@ -83,6 +83,24 @@ char *tohex(const uint8_t *bin, size_t l) #define ck_assert_mem_eq(X, Y, L) _ck_assert_mem(X, Y, L, ==) #define ck_assert_mem_ne(X, Y, L) _ck_assert_mem(X, Y, L, !=) +START_TEST(test_bignum_read_be) +{ + bignum256 a; + uint8_t input[32]; + + memcpy(input, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); + + bn_read_be(input, &a); + + bignum256 b = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; + + for (int i = 0; i < 9; i++) { + ck_assert_int_eq(a.val[i], b.val[i]); + } +} +END_TEST + + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2327,6 +2345,10 @@ Suite *test_suite(void) Suite *s = suite_create("trezor-crypto"); TCase *tc; + tc = tcase_create("bignum"); + tcase_add_test(tc, test_bignum_read_be); + suite_add_tcase(s, tc); + tc = tcase_create("base58"); tcase_add_test(tc, test_base58); suite_add_tcase(s, tc); From 8eebfb1986938faf1d891414dcee771f2882ba9c Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 22:51:34 +0100 Subject: [PATCH 02/12] tests: add bn_write_be --- tests.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests.c b/tests.c index 5666cb8e3c..2fb0fb0376 100644 --- a/tests.c +++ b/tests.c @@ -100,6 +100,17 @@ 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 } }; + uint8_t tmp[32]; + + bn_write_be(&a, tmp); + + ck_assert_mem_eq(tmp, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) @@ -2347,6 +2358,7 @@ Suite *test_suite(void) tc = tcase_create("bignum"); tcase_add_test(tc, test_bignum_read_be); + tcase_add_test(tc, test_bignum_write_be); suite_add_tcase(s, tc); tc = tcase_create("base58"); From ec316b6afc21d2c327a163964b113107f7e45734 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 23:07:28 +0100 Subject: [PATCH 03/12] tests: add bn_is_equal --- tests.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests.c b/tests.c index 2fb0fb0376..fc1f83a63d 100644 --- a/tests.c +++ b/tests.c @@ -111,6 +111,17 @@ START_TEST(test_bignum_write_be) } END_TEST +START_TEST(test_bignum_equal) +{ + bignum256 a = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; + bignum256 b = { { 0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, 0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e } }; + bignum256 c = { { 0, } }; + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + ck_assert_int_eq(bn_is_equal(&c, &c), 1); + ck_assert_int_eq(bn_is_equal(&a, &c), 0); +} +END_TEST // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) @@ -2359,6 +2370,7 @@ Suite *test_suite(void) tc = tcase_create("bignum"); tcase_add_test(tc, test_bignum_read_be); tcase_add_test(tc, test_bignum_write_be); + tcase_add_test(tc, test_bignum_equal); suite_add_tcase(s, tc); tc = tcase_create("base58"); From 62a0db8c4e680eafcc48730131216002601f67c0 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 23:18:24 +0100 Subject: [PATCH 04/12] bignum: introduce read/write_le --- CONTRIBUTORS | 1 + bignum.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ bignum.h | 10 ++++++++++ tests.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 7e5175b016..b5fc5500a4 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -4,6 +4,7 @@ Jochen Hoenicke Dustin Laurence Ondrej Mikle Roman Zeyde +Alex Beregszaszi netanelkl Jan Pochyla Ondrej Mikle diff --git a/bignum.c b/bignum.c index 20e3718c3b..d2ebd63509 100644 --- a/bignum.c +++ b/bignum.c @@ -2,6 +2,7 @@ * Copyright (c) 2013-2014 Tomas Dzetkulic * Copyright (c) 2013-2014 Pavol Rusnak * Copyright (c) 2015 Jochen Hoenicke + * Copyright (c) 2016 Alex Beregszaszi * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), @@ -69,6 +70,22 @@ inline void write_be(uint8_t *data, uint32_t x) data[3] = x; } +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])); +} + +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; +} + // convert a raw bigendian 256 bit value into a normalized bignum. // out_number is partly reduced (since it fits in 256 bit). void bn_read_be(const uint8_t *in_number, bignum256 *out_number) @@ -104,6 +121,41 @@ void bn_write_be(const bignum256 *in_number, uint8_t *out_number) } } +// convert a raw little endian 256 bit value into a normalized bignum. +// out_number is partly reduced (since it fits in 256 bit). +void bn_read_le(const uint8_t *in_number, bignum256 *out_number) +{ + int i; + uint32_t temp = 0; + for (i = 0; i < 8; i++) { + // invariant: temp = (in_number % 2^(32i)) >> 30i + // get next limb = (in_number % 2^(32(i+1))) >> 32i + uint32_t limb = read_le(in_number + i * 4); + // temp = (in_number % 2^(32(i+1))) << 30i + temp |= limb << (2*i); + // store 30 bits into val[i] + out_number->val[i]= temp & 0x3FFFFFFF; + // prepare temp for next round + temp = limb >> (30 - 2*i); + } + out_number->val[8] = temp; +} + +// convert a normalized bignum to a raw little endian 256 bit number. +// in_number must be fully reduced. +void bn_write_le(const bignum256 *in_number, uint8_t *out_number) +{ + int i; + uint32_t temp = in_number->val[8] << 16; + for (i = 0; i < 8; i++) { + // invariant: temp = (in_number >> 30*(8-i)) << (16 + 2i) + uint32_t limb = in_number->val[7 - i]; + temp |= limb >> (14 - 2*i); + write_le(out_number + (7 - i) * 4, temp); + temp = limb << (18 + 2*i); + } +} + // sets a bignum to zero. void bn_zero(bignum256 *a) { diff --git a/bignum.h b/bignum.h index 4b51c5d42f..65bea7ba70 100644 --- a/bignum.h +++ b/bignum.h @@ -39,10 +39,20 @@ uint32_t read_be(const uint8_t *data); // write 4 big endian bytes void write_be(uint8_t *data, uint32_t x); +// read 4 little endian bytes into uint32 +uint32_t read_le(const uint8_t *data); + +// write 4 little endian bytes +void write_le(uint8_t *data, uint32_t 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_zero(bignum256 *a); int bn_is_zero(const bignum256 *a); diff --git a/tests.c b/tests.c index fc1f83a63d..f1e10ba2b0 100644 --- a/tests.c +++ b/tests.c @@ -123,6 +123,36 @@ START_TEST(test_bignum_equal) } END_TEST +START_TEST(test_bignum_read_le) +{ + bignum256 a; + bignum256 b; + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); + bn_read_le(fromhex("d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), &b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_write_le) +{ + bignum256 a; + bignum256 b; + uint8_t tmp[32]; + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); + bn_write_le(&a, tmp); + + bn_read_le(tmp, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + bn_read_be(fromhex("d58b6de8051f031eeca2c6d7fbe1b5d37c4314fe1068f96352dd0d8b85ce5ec5"), &a); + bn_read_be(tmp, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2371,6 +2401,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_read_be); tcase_add_test(tc, test_bignum_write_be); tcase_add_test(tc, test_bignum_equal); + tcase_add_test(tc, test_bignum_read_le); + tcase_add_test(tc, test_bignum_write_le); suite_add_tcase(s, tc); tc = tcase_create("base58"); From dd25a2ee5a93ab5804b08a826258181ab24e46a6 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 23:20:09 +0100 Subject: [PATCH 05/12] bignum: introduce copy --- bignum.c | 9 +++++++++ bignum.h | 2 ++ tests.c | 13 +++++++++++++ 3 files changed, 24 insertions(+) diff --git a/bignum.c b/bignum.c index d2ebd63509..a0364309bc 100644 --- a/bignum.c +++ b/bignum.c @@ -156,6 +156,15 @@ void bn_write_le(const bignum256 *in_number, uint8_t *out_number) } } +// copies number a to b +void bn_copy(bignum256 *a, bignum256 *b) +{ + int i; + for (i = 0; i < 9; i++) { + b->val[i] = a->val[i]; + } +} + // sets a bignum to zero. void bn_zero(bignum256 *a) { diff --git a/bignum.h b/bignum.h index 65bea7ba70..fd040c8dc6 100644 --- a/bignum.h +++ b/bignum.h @@ -53,6 +53,8 @@ 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_copy(bignum256 *a, bignum256 *b); + void bn_zero(bignum256 *a); int bn_is_zero(const bignum256 *a); diff --git a/tests.c b/tests.c index f1e10ba2b0..82d47ab8cb 100644 --- a/tests.c +++ b/tests.c @@ -153,6 +153,18 @@ START_TEST(test_bignum_write_le) } END_TEST +START_TEST(test_bignum_copy) +{ + bignum256 a; + bignum256 b; + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); + bn_copy(&a, &b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2403,6 +2415,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_equal); tcase_add_test(tc, test_bignum_read_le); tcase_add_test(tc, test_bignum_write_le); + tcase_add_test(tc, test_bignum_copy); suite_add_tcase(s, tc); tc = tcase_create("base58"); From 339d2f44a9c124de3e0a592928d90c8b4eb158fd Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Aug 2016 23:55:40 +0100 Subject: [PATCH 06/12] bignum: introduce is_even/is_odd --- bignum.h | 9 +++++++++ tests.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/bignum.h b/bignum.h index fd040c8dc6..863b05ccc8 100644 --- a/bignum.h +++ b/bignum.h @@ -1,6 +1,7 @@ /** * Copyright (c) 2013-2014 Tomas Dzetkulic * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2016 Alex Beregszaszi * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), @@ -59,6 +60,14 @@ void bn_zero(bignum256 *a); int bn_is_zero(const 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); diff --git a/tests.c b/tests.c index 82d47ab8cb..91acb59b46 100644 --- a/tests.c +++ b/tests.c @@ -165,6 +165,36 @@ START_TEST(test_bignum_copy) } END_TEST +START_TEST(test_bignum_is_even) +{ + bignum256 a; + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); + ck_assert_int_eq(bn_is_even(&a), 0); + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), &a); + ck_assert_int_eq(bn_is_even(&a), 1); + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), &a); + ck_assert_int_eq(bn_is_even(&a), 1); +} +END_TEST + +START_TEST(test_bignum_is_odd) +{ + bignum256 a; + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), &a); + ck_assert_int_eq(bn_is_odd(&a), 1); + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd2"), &a); + ck_assert_int_eq(bn_is_odd(&a), 0); + + bn_read_be(fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd0"), &a); + ck_assert_int_eq(bn_is_odd(&a), 0); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2416,6 +2446,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_read_le); tcase_add_test(tc, test_bignum_write_le); tcase_add_test(tc, test_bignum_copy); + tcase_add_test(tc, test_bignum_is_even); + tcase_add_test(tc, test_bignum_is_odd); suite_add_tcase(s, tc); tc = tcase_create("base58"); From d061139da986fa66d171dae555da58922d79a623 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 00:12:02 +0100 Subject: [PATCH 07/12] bignum: introduce load uint32/uint64 --- bignum.c | 26 ++++++++++++++++++++++++++ bignum.h | 4 ++++ tests.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/bignum.c b/bignum.c index a0364309bc..23db0d4773 100644 --- a/bignum.c +++ b/bignum.c @@ -156,6 +156,32 @@ void bn_write_le(const bignum256 *in_number, uint8_t *out_number) } } +void bn_load_uint32(uint32_t in_number, bignum256 *out_number) +{ + out_number->val[0] = in_number & 0x3FFFFFFF; + out_number->val[1] = in_number >> 30; + out_number->val[2] = 0; + out_number->val[3] = 0; + out_number->val[4] = 0; + out_number->val[5] = 0; + out_number->val[6] = 0; + out_number->val[7] = 0; + out_number->val[8] = 0; +} + +void bn_load_uint64(uint64_t in_number, bignum256 *out_number) +{ + out_number->val[0] = in_number & 0x3FFFFFFF; + out_number->val[1] = (in_number >>= 30) & 0x3FFFFFFF; + out_number->val[2] = in_number >>= 30; + out_number->val[3] = 0; + out_number->val[4] = 0; + out_number->val[5] = 0; + out_number->val[6] = 0; + out_number->val[7] = 0; + out_number->val[8] = 0; +} + // copies number a to b void bn_copy(bignum256 *a, bignum256 *b) { diff --git a/bignum.h b/bignum.h index 863b05ccc8..f7ee44d18c 100644 --- a/bignum.h +++ b/bignum.h @@ -54,6 +54,10 @@ 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_load_uint32(uint32_t in_number, bignum256 *out_number); + +void bn_load_uint64(uint64_t in_number, bignum256 *out_number); + void bn_copy(bignum256 *a, bignum256 *b); void bn_zero(bignum256 *a); diff --git a/tests.c b/tests.c index 91acb59b46..f61ee039e1 100644 --- a/tests.c +++ b/tests.c @@ -153,6 +153,56 @@ START_TEST(test_bignum_write_le) } END_TEST +START_TEST(test_bignum_load_uint32) +{ + bignum256 a; + bignum256 b; + + // lowest 30 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); + bn_load_uint32(0x3fffffff, &b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 31 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); + bn_load_uint32(0x40000000, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_load_uint64) +{ + bignum256 a; + bignum256 b; + + // lowest 30 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); + bn_load_uint64(0x3fffffff, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 31 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); + bn_load_uint64(0x40000000, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 33 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000100000000"), &a); + bn_load_uint64(0x100000000LL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // bit 61 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000002000000000000000"), &a); + bn_load_uint64(0x2000000000000000LL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); + + // all 64 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000ffffffffffffffff"), &a); + bn_load_uint64(0xffffffffffffffffLL, &b); + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + START_TEST(test_bignum_copy) { bignum256 a; @@ -2445,6 +2495,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_equal); tcase_add_test(tc, test_bignum_read_le); tcase_add_test(tc, test_bignum_write_le); + tcase_add_test(tc, test_bignum_load_uint32); + tcase_add_test(tc, test_bignum_load_uint64); tcase_add_test(tc, test_bignum_copy); tcase_add_test(tc, test_bignum_is_even); tcase_add_test(tc, test_bignum_is_odd); From 97454d9cbc81b81d36ecfbd3a4612bae0ee3acf2 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 01:06:47 +0100 Subject: [PATCH 08/12] bignum: use the compiler's built in memory copy for bn_copy --- bignum.c | 9 --------- bignum.h | 5 ++++- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/bignum.c b/bignum.c index 23db0d4773..7d756e84f5 100644 --- a/bignum.c +++ b/bignum.c @@ -182,15 +182,6 @@ void bn_load_uint64(uint64_t in_number, bignum256 *out_number) out_number->val[8] = 0; } -// copies number a to b -void bn_copy(bignum256 *a, bignum256 *b) -{ - int i; - for (i = 0; i < 9; i++) { - b->val[i] = a->val[i]; - } -} - // sets a bignum to zero. void bn_zero(bignum256 *a) { diff --git a/bignum.h b/bignum.h index f7ee44d18c..8a770064a2 100644 --- a/bignum.h +++ b/bignum.h @@ -58,7 +58,10 @@ void bn_load_uint32(uint32_t in_number, bignum256 *out_number); void bn_load_uint64(uint64_t in_number, bignum256 *out_number); -void bn_copy(bignum256 *a, bignum256 *b); +// copies number a to b +static inline void bn_copy(const bignum256 *a, bignum256 *b) { + *b = *a; +} void bn_zero(bignum256 *a); From 4eb2bd239c1a8e7285d49bff060b071d5fc2b6f9 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 11:54:55 +0100 Subject: [PATCH 09/12] tests: add bn_zero/bn_is_zero --- tests.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests.c b/tests.c index f61ee039e1..baefdbf966 100644 --- a/tests.c +++ b/tests.c @@ -123,6 +123,36 @@ START_TEST(test_bignum_equal) } END_TEST +START_TEST(test_bignum_zero) +{ + bignum256 a; + bignum256 b; + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + bn_zero(&b); + + ck_assert_int_eq(bn_is_equal(&a, &b), 1); +} +END_TEST + +START_TEST(test_bignum_is_zero) +{ + bignum256 a; + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a); + ck_assert_int_eq(bn_is_zero(&a), 1); + + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a); + ck_assert_int_eq(bn_is_zero(&a), 0); + + bn_read_be(fromhex("1000000000000000000000000000000000000000000000000000000000000000"), &a); + ck_assert_int_eq(bn_is_zero(&a), 0); + + bn_read_be(fromhex("f000000000000000000000000000000000000000000000000000000000000000"), &a); + ck_assert_int_eq(bn_is_zero(&a), 0); +} +END_TEST + START_TEST(test_bignum_read_le) { bignum256 a; @@ -2493,6 +2523,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_read_be); tcase_add_test(tc, test_bignum_write_be); tcase_add_test(tc, test_bignum_equal); + tcase_add_test(tc, test_bignum_zero); + tcase_add_test(tc, test_bignum_is_zero); tcase_add_test(tc, test_bignum_read_le); tcase_add_test(tc, test_bignum_write_le); tcase_add_test(tc, test_bignum_load_uint32); From 29e82018cde093848258f3643ee1775abe3d8985 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 12:14:01 +0100 Subject: [PATCH 10/12] bignum: rename bn_load_uint* to bn_read_uint* --- bignum.c | 4 ++-- bignum.h | 4 ++-- tests.c | 22 +++++++++++----------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/bignum.c b/bignum.c index 7d756e84f5..7548bd1d33 100644 --- a/bignum.c +++ b/bignum.c @@ -156,7 +156,7 @@ void bn_write_le(const bignum256 *in_number, uint8_t *out_number) } } -void bn_load_uint32(uint32_t in_number, bignum256 *out_number) +void bn_read_uint32(uint32_t in_number, bignum256 *out_number) { out_number->val[0] = in_number & 0x3FFFFFFF; out_number->val[1] = in_number >> 30; @@ -169,7 +169,7 @@ void bn_load_uint32(uint32_t in_number, bignum256 *out_number) out_number->val[8] = 0; } -void bn_load_uint64(uint64_t in_number, bignum256 *out_number) +void bn_read_uint64(uint64_t in_number, bignum256 *out_number) { out_number->val[0] = in_number & 0x3FFFFFFF; out_number->val[1] = (in_number >>= 30) & 0x3FFFFFFF; diff --git a/bignum.h b/bignum.h index 8a770064a2..377bf12744 100644 --- a/bignum.h +++ b/bignum.h @@ -54,9 +54,9 @@ 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_load_uint32(uint32_t in_number, bignum256 *out_number); +void bn_read_uint32(uint32_t in_number, bignum256 *out_number); -void bn_load_uint64(uint64_t in_number, bignum256 *out_number); +void bn_read_uint64(uint64_t in_number, bignum256 *out_number); // copies number a to b static inline void bn_copy(const bignum256 *a, bignum256 *b) { diff --git a/tests.c b/tests.c index baefdbf966..804969bbfe 100644 --- a/tests.c +++ b/tests.c @@ -183,52 +183,52 @@ START_TEST(test_bignum_write_le) } END_TEST -START_TEST(test_bignum_load_uint32) +START_TEST(test_bignum_read_uint32) { bignum256 a; bignum256 b; // lowest 30 bits set bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); - bn_load_uint32(0x3fffffff, &b); + bn_read_uint32(0x3fffffff, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); // bit 31 set bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); - bn_load_uint32(0x40000000, &b); + bn_read_uint32(0x40000000, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); } END_TEST -START_TEST(test_bignum_load_uint64) +START_TEST(test_bignum_read_uint64) { bignum256 a; bignum256 b; // lowest 30 bits set bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); - bn_load_uint64(0x3fffffff, &b); + bn_read_uint64(0x3fffffff, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); // bit 31 set bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); - bn_load_uint64(0x40000000, &b); + bn_read_uint64(0x40000000, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); // bit 33 set bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000100000000"), &a); - bn_load_uint64(0x100000000LL, &b); + bn_read_uint64(0x100000000LL, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); // bit 61 set bn_read_be(fromhex("0000000000000000000000000000000000000000000000002000000000000000"), &a); - bn_load_uint64(0x2000000000000000LL, &b); + bn_read_uint64(0x2000000000000000LL, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); // all 64 bits set bn_read_be(fromhex("000000000000000000000000000000000000000000000000ffffffffffffffff"), &a); - bn_load_uint64(0xffffffffffffffffLL, &b); + bn_read_uint64(0xffffffffffffffffLL, &b); ck_assert_int_eq(bn_is_equal(&a, &b), 1); } END_TEST @@ -2527,8 +2527,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_is_zero); tcase_add_test(tc, test_bignum_read_le); tcase_add_test(tc, test_bignum_write_le); - tcase_add_test(tc, test_bignum_load_uint32); - tcase_add_test(tc, test_bignum_load_uint64); + tcase_add_test(tc, test_bignum_read_uint32); + tcase_add_test(tc, test_bignum_read_uint64); tcase_add_test(tc, test_bignum_copy); tcase_add_test(tc, test_bignum_is_even); tcase_add_test(tc, test_bignum_is_odd); From 7956c2f2f133a90b3cccc7742c1fefac34805975 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 12:31:51 +0100 Subject: [PATCH 11/12] bignum: implement bitcount --- bignum.c | 13 +++++++++++++ bignum.h | 2 ++ tests.c | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/bignum.c b/bignum.c index 7548bd1d33..1bd65b605d 100644 --- a/bignum.c +++ b/bignum.c @@ -182,6 +182,19 @@ void bn_read_uint64(uint64_t in_number, bignum256 *out_number) out_number->val[8] = 0; } +// a must be normalized +int bn_bitcount(const bignum256 *a) +{ + int i; + for (i = 8; i >= 0; i--) { + int tmp = a->val[i]; + if (tmp != 0) { + return i * 30 + (32 - __builtin_clz(tmp)); + } + } + return 0; +} + // sets a bignum to zero. void bn_zero(bignum256 *a) { diff --git a/bignum.h b/bignum.h index 377bf12744..f0877c3e1b 100644 --- a/bignum.h +++ b/bignum.h @@ -63,6 +63,8 @@ static inline void bn_copy(const bignum256 *a, bignum256 *b) { *b = *a; } +int bn_bitcount(const bignum256 *a); + void bn_zero(bignum256 *a); int bn_is_zero(const bignum256 *a); diff --git a/tests.c b/tests.c index 804969bbfe..b9b87ffc38 100644 --- a/tests.c +++ b/tests.c @@ -275,6 +275,24 @@ START_TEST(test_bignum_is_odd) } END_TEST +START_TEST(test_bignum_bitcount) +{ + bignum256 a; + + bn_zero(&a); + ck_assert_int_eq(bn_bitcount(&a), 0); + + bn_read_uint32(0x3fffffff, &a); + ck_assert_int_eq(bn_bitcount(&a), 30); + + bn_read_uint32(0xffffffff, &a); + ck_assert_int_eq(bn_bitcount(&a), 32); + + bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); + ck_assert_int_eq(bn_bitcount(&a), 256); +} +END_TEST + // from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { @@ -2532,6 +2550,7 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_copy); tcase_add_test(tc, test_bignum_is_even); tcase_add_test(tc, test_bignum_is_odd); + tcase_add_test(tc, test_bignum_bitcount); suite_add_tcase(s, tc); tc = tcase_create("base58"); From 8581614d66aba51c6f4175eea5192553288037a6 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Aug 2016 12:41:54 +0100 Subject: [PATCH 12/12] bignum: introduce write uint32/uint64 --- bignum.h | 16 ++++++++++++++++ tests.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/bignum.h b/bignum.h index f0877c3e1b..2d7af3c38a 100644 --- a/bignum.h +++ b/bignum.h @@ -58,6 +58,22 @@ 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; diff --git a/tests.c b/tests.c index b9b87ffc38..45ef27aa0c 100644 --- a/tests.c +++ b/tests.c @@ -233,6 +233,46 @@ START_TEST(test_bignum_read_uint64) } END_TEST +START_TEST(test_bignum_write_uint32) +{ + bignum256 a; + + // lowest 30 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); + ck_assert_int_eq(bn_write_uint32(&a), 0x3fffffff); + + // bit 31 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); + ck_assert_int_eq(bn_write_uint32(&a), 0x40000000); +} +END_TEST + +START_TEST(test_bignum_write_uint64) +{ + bignum256 a; + + // lowest 30 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000003fffffff"), &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x3fffffff); + + // bit 31 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000040000000"), &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x40000000); + + // bit 33 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000100000000"), &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x100000000LL); + + // bit 61 set + bn_read_be(fromhex("0000000000000000000000000000000000000000000000002000000000000000"), &a); + ck_assert_int_eq(bn_write_uint64(&a), 0x2000000000000000LL); + + // all 64 bits set + bn_read_be(fromhex("000000000000000000000000000000000000000000000000ffffffffffffffff"), &a); + ck_assert_int_eq(bn_write_uint64(&a), 0xffffffffffffffffLL); +} +END_TEST + START_TEST(test_bignum_copy) { bignum256 a; @@ -2547,6 +2587,8 @@ Suite *test_suite(void) tcase_add_test(tc, test_bignum_write_le); tcase_add_test(tc, test_bignum_read_uint32); tcase_add_test(tc, test_bignum_read_uint64); + tcase_add_test(tc, test_bignum_write_uint32); + tcase_add_test(tc, test_bignum_write_uint64); tcase_add_test(tc, test_bignum_copy); tcase_add_test(tc, test_bignum_is_even); tcase_add_test(tc, test_bignum_is_odd);