|
|
#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(); |
|
|
} |