| | #include "../../unity/unity.h" |
| | #include <stdlib.h> |
| | #include <string.h> |
| | #include <stdint.h> |
| | #include <stdbool.h> |
| | #include <gmp.h> |
| |
|
| | |
| | |
| |
|
| | void setUp(void) { |
| | |
| | } |
| |
|
| | void tearDown(void) { |
| | |
| | } |
| |
|
| | |
| | |
| | static char *alphabet_to_gmp_digits(const char *alphabet, size_t *out_len) |
| | { |
| | if (!alphabet) return NULL; |
| | size_t n = strlen(alphabet); |
| | char *digits = (char *)malloc(n + 1); |
| | TEST_ASSERT_NOT_NULL(digits); |
| | for (size_t i = 0; i < n; i++) { |
| | signed char m = base58_to_gmp[(unsigned char)alphabet[i]]; |
| | TEST_ASSERT_MESSAGE(m != -1, "Invalid Base58 alphabet character in test input"); |
| | digits[i] = (char)m; |
| | } |
| | digits[n] = '\0'; |
| | if (out_len) *out_len = n; |
| | return digits; |
| | } |
| |
|
| | |
| | |
| | |
| | static char *bytes_to_gmp58_digits(const unsigned char *data, size_t len, size_t *digits_len) |
| | { |
| | size_t ones = 0; |
| | while (ones < len && data[ones] == 0) ones++; |
| |
|
| | if (len - ones == 0) { |
| | |
| | char *digits = (char *)malloc(ones + 1); |
| | TEST_ASSERT_NOT_NULL(digits); |
| | memset(digits, '0', ones); |
| | digits[ones] = '\0'; |
| | if (digits_len) *digits_len = ones; |
| | return digits; |
| | } |
| |
|
| | mpz_t num; |
| | mpz_init(num); |
| | mpz_import(num, len - ones, 1, 1, 0, 0, data + ones); |
| |
|
| | |
| | size_t cap = ones + mpz_sizeinbase(num, 58) + 2; |
| | char *digits = (char *)malloc(cap); |
| | TEST_ASSERT_NOT_NULL(digits); |
| | memset(digits, '0', ones); |
| | char *p = digits + ones; |
| | char *ret = mpz_get_str(p, 58, num); |
| | TEST_ASSERT_EQUAL_PTR(p, ret); |
| | size_t tail_len = strlen(p); |
| | if (digits_len) *digits_len = ones + tail_len; |
| | mpz_clear(num); |
| | return digits; |
| | } |
| |
|
| | |
| | void test_base58_decode_empty(void) |
| | { |
| | char outbuf[1]; |
| | idx_t outlen = 0; |
| | bool ok = base58_decode("", 0, outbuf, &outlen); |
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_UINT64(0, (unsigned long long)outlen); |
| | } |
| |
|
| | |
| | void test_base58_decode_only_ones_single(void) |
| | { |
| | size_t inlen = 0; |
| | char *gmp = alphabet_to_gmp_digits("1", &inlen); |
| | TEST_ASSERT_EQUAL_size_t(1, inlen); |
| |
|
| | unsigned char outbuf[4] = {0xAA, 0xAA, 0xAA, 0xAA}; |
| | idx_t outlen = (idx_t)inlen; |
| | bool ok = base58_decode(gmp, inlen, (char *)outbuf, &outlen); |
| | free(gmp); |
| |
|
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_UINT64(1, (unsigned long long)outlen); |
| | TEST_ASSERT_EQUAL_UINT8(0x00, outbuf[0]); |
| | } |
| |
|
| | |
| | void test_base58_decode_ones_plus_digit(void) |
| | { |
| | size_t inlen = 0; |
| | char *gmp = alphabet_to_gmp_digits("1112", &inlen); |
| |
|
| | unsigned char outbuf[16]; |
| | memset(outbuf, 0xCC, sizeof(outbuf)); |
| | idx_t outlen = (idx_t)inlen; |
| | bool ok = base58_decode(gmp, inlen, (char *)outbuf, &outlen); |
| | free(gmp); |
| |
|
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_UINT64(4, (unsigned long long)outlen); |
| | TEST_ASSERT_EQUAL_UINT8(0x00, outbuf[0]); |
| | TEST_ASSERT_EQUAL_UINT8(0x00, outbuf[1]); |
| | TEST_ASSERT_EQUAL_UINT8(0x00, outbuf[2]); |
| | TEST_ASSERT_EQUAL_UINT8(0x01, outbuf[3]); |
| | } |
| |
|
| | |
| | void test_base58_decode_roundtrip_small(void) |
| | { |
| | unsigned char input[] = { 0x01, 0x02, 0xFF }; |
| | size_t digits_len = 0; |
| | char *digits = bytes_to_gmp58_digits(input, sizeof(input), &digits_len); |
| |
|
| | |
| | size_t outcap = digits_len + 8; |
| | unsigned char *outbuf = (unsigned char *)malloc(outcap); |
| | TEST_ASSERT_NOT_NULL(outbuf); |
| | idx_t outlen = (idx_t)outcap; |
| |
|
| | bool ok = base58_decode(digits, digits_len, (char *)outbuf, &outlen); |
| |
|
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_UINT64(sizeof(input), (unsigned long long)outlen); |
| | TEST_ASSERT_EQUAL_UINT8_ARRAY(input, outbuf, sizeof(input)); |
| |
|
| | free(digits); |
| | free(outbuf); |
| | } |
| |
|
| | |
| | void test_base58_decode_roundtrip_leading_zeros(void) |
| | { |
| | unsigned char input[] = { 0x00, 0x00, 0x00, 0x01, 0x23, 0x45 }; |
| | size_t digits_len = 0; |
| | char *digits = bytes_to_gmp58_digits(input, sizeof(input), &digits_len); |
| |
|
| | unsigned char *outbuf = (unsigned char *)malloc(digits_len + 16); |
| | TEST_ASSERT_NOT_NULL(outbuf); |
| | idx_t outlen = (idx_t)(digits_len + 16); |
| |
|
| | bool ok = base58_decode(digits, digits_len, (char *)outbuf, &outlen); |
| |
|
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_UINT64(sizeof(input), (unsigned long long)outlen); |
| | TEST_ASSERT_EQUAL_UINT8_ARRAY(input, outbuf, sizeof(input)); |
| |
|
| | free(digits); |
| | free(outbuf); |
| | } |
| |
|
| | |
| | void test_base58_decode_invalid_digit(void) |
| | { |
| | const char *digits = "0z"; |
| | unsigned char outbuf[8] = {0}; |
| | idx_t outlen = 2; |
| |
|
| | bool ok = base58_decode(digits, 2, (char *)outbuf, &outlen); |
| |
|
| | TEST_ASSERT_FALSE(ok); |
| | TEST_ASSERT_EQUAL_UINT64(0, (unsigned long long)outlen); |
| | } |
| |
|
| | |
| | void test_base58_decode_large_outbuf(void) |
| | { |
| | size_t inlen = 0; |
| | char *gmp = alphabet_to_gmp_digits("1112", &inlen); |
| |
|
| | unsigned char outbuf[32]; |
| | idx_t outlen = 10; |
| |
|
| | bool ok = base58_decode(gmp, inlen, (char *)outbuf, &outlen); |
| | free(gmp); |
| |
|
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_UINT64(4, (unsigned long long)outlen); |
| | TEST_ASSERT_EQUAL_UINT8(0x00, outbuf[0]); |
| | TEST_ASSERT_EQUAL_UINT8(0x00, outbuf[1]); |
| | TEST_ASSERT_EQUAL_UINT8(0x00, outbuf[2]); |
| | TEST_ASSERT_EQUAL_UINT8(0x01, outbuf[3]); |
| | } |
| |
|
| | int main(void) |
| | { |
| | UNITY_BEGIN(); |
| | RUN_TEST(test_base58_decode_empty); |
| | RUN_TEST(test_base58_decode_only_ones_single); |
| | RUN_TEST(test_base58_decode_ones_plus_digit); |
| | RUN_TEST(test_base58_decode_roundtrip_small); |
| | RUN_TEST(test_base58_decode_roundtrip_leading_zeros); |
| | RUN_TEST(test_base58_decode_invalid_digit); |
| | RUN_TEST(test_base58_decode_large_outbuf); |
| | return UNITY_END(); |
| | } |