mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 12:28:09 +00:00
bignum: add bn_format
This commit is contained in:
parent
1ae459912f
commit
af01ef71fc
2
Makefile
2
Makefile
@ -53,7 +53,7 @@ OBJS = $(SRCS:.c=.o)
|
|||||||
TESTLIBS = $(shell pkg-config --libs check) -lrt -lpthread -lm
|
TESTLIBS = $(shell pkg-config --libs check) -lrt -lpthread -lm
|
||||||
TESTSSLLIBS = -lcrypto
|
TESTSSLLIBS = -lcrypto
|
||||||
|
|
||||||
all: tests test-openssl libtrezor-crypto.so test_speed tools
|
all: tests test-openssl test_speed tools libtrezor-crypto.so
|
||||||
|
|
||||||
%.o: %.c %.h options.h
|
%.o: %.c %.h options.h
|
||||||
$(CC) $(CFLAGS) -o $@ -c $<
|
$(CC) $(CFLAGS) -o $@ -c $<
|
||||||
|
52
bignum.c
52
bignum.c
@ -960,6 +960,58 @@ void bn_divmod1000(bignum256 *a, uint32_t *r)
|
|||||||
*r = rem;
|
*r = rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2^256 has 78 digits in decimal (+ 1 for decimal point, + 1 for leading zero, + 1 for trailing zero)
|
||||||
|
#define DIGITLEN (78 + 1 + 1 + 1)
|
||||||
|
|
||||||
|
int bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, int decimals, char *out, int outlen)
|
||||||
|
{
|
||||||
|
// convert bignum to characters
|
||||||
|
bignum256 val;
|
||||||
|
memcpy(&val, amnt, sizeof(bignum256));
|
||||||
|
char digits[DIGITLEN];
|
||||||
|
memset(digits, '0', DIGITLEN);
|
||||||
|
int pos = 1; // keep one trailing zero
|
||||||
|
for (int i = 0; i < 78 / 3; i++) {
|
||||||
|
uint32_t limb;
|
||||||
|
bn_divmod1000(&val, &limb);
|
||||||
|
if (pos == decimals + 1) { digits[DIGITLEN - 1 - pos] = '.'; pos++; }
|
||||||
|
digits[DIGITLEN - 1 - pos] = '0' + (limb % 10); pos++;
|
||||||
|
if (pos == decimals + 1) { digits[DIGITLEN - 1 - pos] = '.'; pos++; }
|
||||||
|
digits[DIGITLEN - 1 - pos] = '0' + ((limb / 10) % 10); pos++;
|
||||||
|
if (pos == decimals + 1) { digits[DIGITLEN - 1 - pos] = '.'; pos++; }
|
||||||
|
digits[DIGITLEN - 1 - pos] = '0' + ((limb / 100) % 10); pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop leading zeroes
|
||||||
|
int digitstart = 0;
|
||||||
|
while (digitstart < DIGITLEN - 1 && digits[digitstart] == '0' && digits[digitstart + 1] >= '0' && digits[digitstart + 1] <= '9') {
|
||||||
|
digitstart++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop trailing zeroes
|
||||||
|
int digitend = DIGITLEN - 1;
|
||||||
|
while (digitend > 0 && digits[digitend] == '0' && digits[digitend - 1] >= '0' && digits[digitend - 1] <= '9') {
|
||||||
|
digitend--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int digitslen = digitend - digitstart + 1;
|
||||||
|
int prefixlen = prefix != NULL ? strlen(prefix) : 0;
|
||||||
|
int suffixlen = suffix != NULL ? strlen(suffix) : 0;
|
||||||
|
|
||||||
|
// output buffer is too small
|
||||||
|
if (prefixlen + digitslen + suffixlen + 1 > outlen) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy result to output buffer
|
||||||
|
memcpy(out, prefix, prefixlen);
|
||||||
|
memcpy(out + prefixlen, digits + digitstart, digitslen);
|
||||||
|
memcpy(out + prefixlen + digitslen, suffix, suffixlen);
|
||||||
|
out[prefixlen + digitslen + suffixlen] = 0;
|
||||||
|
|
||||||
|
return prefixlen + digitslen + suffixlen;
|
||||||
|
}
|
||||||
|
|
||||||
#if USE_BN_PRINT
|
#if USE_BN_PRINT
|
||||||
void bn_print(const bignum256 *a)
|
void bn_print(const bignum256 *a)
|
||||||
{
|
{
|
||||||
|
2
bignum.h
2
bignum.h
@ -145,6 +145,8 @@ void bn_divmod58(bignum256 *a, uint32_t *r);
|
|||||||
|
|
||||||
void bn_divmod1000(bignum256 *a, uint32_t *r);
|
void bn_divmod1000(bignum256 *a, uint32_t *r);
|
||||||
|
|
||||||
|
int bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, int decimals, char *out, int outlen);
|
||||||
|
|
||||||
#if USE_BN_PRINT
|
#if USE_BN_PRINT
|
||||||
void bn_print(const bignum256 *a);
|
void bn_print(const bignum256 *a);
|
||||||
void bn_print_raw(const bignum256 *a);
|
void bn_print_raw(const bignum256 *a);
|
||||||
|
135
tests.c
135
tests.c
@ -353,6 +353,138 @@ START_TEST(test_bignum_is_less)
|
|||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_bignum_format) {
|
||||||
|
bignum256 a;
|
||||||
|
char buf[128];
|
||||||
|
int r;
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 3);
|
||||||
|
ck_assert_str_eq(buf, "0.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a);
|
||||||
|
r = bn_format(&a, "", "", 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 3);
|
||||||
|
ck_assert_str_eq(buf, "0.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a);
|
||||||
|
r = bn_format(&a, NULL, "SFFX", 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 3 + 4);
|
||||||
|
ck_assert_str_eq(buf, "0.0SFFX");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a);
|
||||||
|
r = bn_format(&a, "PRFX", NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 4 + 3);
|
||||||
|
ck_assert_str_eq(buf, "PRFX0.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a);
|
||||||
|
r = bn_format(&a, "PRFX", "SFFX", 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 4 + 3 + 4);
|
||||||
|
ck_assert_str_eq(buf, "PRFX0.0SFFX");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000000"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 18, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 3);
|
||||||
|
ck_assert_str_eq(buf, "0.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000001"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 3);
|
||||||
|
ck_assert_str_eq(buf, "1.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000002"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 3);
|
||||||
|
ck_assert_str_eq(buf, "2.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000005"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 3);
|
||||||
|
ck_assert_str_eq(buf, "5.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("000000000000000000000000000000000000000000000000000000000000000a"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 4);
|
||||||
|
ck_assert_str_eq(buf, "10.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000014"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 4);
|
||||||
|
ck_assert_str_eq(buf, "20.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000032"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 4);
|
||||||
|
ck_assert_str_eq(buf, "50.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000000064"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 5);
|
||||||
|
ck_assert_str_eq(buf, "100.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000000c8"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 5);
|
||||||
|
ck_assert_str_eq(buf, "200.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000001f4"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 5);
|
||||||
|
ck_assert_str_eq(buf, "500.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("00000000000000000000000000000000000000000000000000000000000003e8"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 6);
|
||||||
|
ck_assert_str_eq(buf, "1000.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("0000000000000000000000000000000000000000000000000000000000989680"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 7, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 3);
|
||||||
|
ck_assert_str_eq(buf, "1.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 0, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 80);
|
||||||
|
ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457584007913129639935.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 1, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 79);
|
||||||
|
ck_assert_str_eq(buf, "11579208923731619542357098500868790785326998466564056403945758400791312963993.5");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 2, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 79);
|
||||||
|
ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131296399.35");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 8, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 79);
|
||||||
|
ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131.29639935");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3bbb00"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 8, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 72);
|
||||||
|
ck_assert_str_eq(buf, "1157920892373161954235709850086879078532699846656405640394575840079131.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 18, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 79);
|
||||||
|
ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457.584007913129639935");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("fffffffffffffffffffffffffffffffffffffffffffffffff7e52fe5afe40000"), &a);
|
||||||
|
r = bn_format(&a, NULL, NULL, 18, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 62);
|
||||||
|
ck_assert_str_eq(buf, "115792089237316195423570985008687907853269984665640564039457.0");
|
||||||
|
|
||||||
|
bn_read_be(fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a);
|
||||||
|
r = bn_format(&a, "quite a long prefix", "even longer suffix", 60, buf, sizeof(buf));
|
||||||
|
ck_assert_int_eq(r, 116);
|
||||||
|
ck_assert_str_eq(buf, "quite a long prefix115792089237316195.423570985008687907853269984665640564039457584007913129639935even longer suffix");
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
// from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json
|
// from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json
|
||||||
START_TEST(test_base58)
|
START_TEST(test_base58)
|
||||||
{
|
{
|
||||||
@ -2960,6 +3092,7 @@ Suite *test_suite(void)
|
|||||||
tcase_add_test(tc, test_bignum_is_odd);
|
tcase_add_test(tc, test_bignum_is_odd);
|
||||||
tcase_add_test(tc, test_bignum_bitcount);
|
tcase_add_test(tc, test_bignum_bitcount);
|
||||||
tcase_add_test(tc, test_bignum_is_less);
|
tcase_add_test(tc, test_bignum_is_less);
|
||||||
|
tcase_add_test(tc, test_bignum_format);
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
tc = tcase_create("base58");
|
tc = tcase_create("base58");
|
||||||
@ -3107,7 +3240,7 @@ Suite *test_suite(void)
|
|||||||
tcase_add_test(tc, test_ethereum_pubkeyhash);
|
tcase_add_test(tc, test_ethereum_pubkeyhash);
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
tc = tcase_create("multibyte_addresse");
|
tc = tcase_create("multibyte_address");
|
||||||
tcase_add_test(tc, test_multibyte_address);
|
tcase_add_test(tc, test_multibyte_address);
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user