File size: 4,188 Bytes
78d2150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "../../unity/unity.h"
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>

/* The test file is included into the same translation unit as the
   basenc implementation, so we can access internal symbols directly. */

void setUp(void) {
  /* Ensure base58_encode uses the correct length function. */
  base_length = base58_length;
}

void tearDown(void) {
  /* nothing */
}

static void check_encode(const unsigned char *data, size_t data_len,
                         const char *expected)
{
  idx_t cap = base58_length((idx_t)data_len);
  char *out = (char *)malloc((size_t)cap);
  TEST_ASSERT_NOT_NULL(out);
  memset(out, 0xAA, (size_t)cap);

  idx_t outlen = cap;
  base58_encode((const char *)data, data_len, out, &outlen);

  size_t exp_len = strlen(expected);
  TEST_ASSERT_EQUAL_UINT64(exp_len, (uint64_t)outlen);
  if (exp_len > 0)
    TEST_ASSERT_EQUAL_INT(0, memcmp(out, expected, exp_len));
  /* Ensure no bytes beyond returned length were modified. */
  for (idx_t i = outlen; i < cap; i++)
    TEST_ASSERT_EQUAL_HEX8(0xAA, (unsigned char)out[i]);

  free(out);
}

static size_t count_leading_zero_bytes(const unsigned char *p, size_t n)
{
  size_t i = 0;
  while (i < n && p[i] == 0x00) i++;
  return i;
}

static void test_base58_encode_empty(void)
{
  check_encode(NULL, 0, "");
}

static void test_base58_encode_only_zeros(void)
{
  /* 1 to 4 leading zeros */
  unsigned char z1[] = {0x00};
  unsigned char z2[] = {0x00, 0x00};
  unsigned char z3[] = {0x00, 0x00, 0x00};
  unsigned char z4[] = {0x00, 0x00, 0x00, 0x00};

  check_encode(z1, sizeof z1, "1");
  check_encode(z2, sizeof z2, "11");
  check_encode(z3, sizeof z3, "111");
  check_encode(z4, sizeof z4, "1111");
}

static void test_base58_encode_single_bytes(void)
{
  unsigned char v1[] = {0x01};      /* value 1 -> "2" */
  unsigned char vff[] = {0xFF};     /* value 255 -> "5Q" */

  check_encode(v1, sizeof v1, "2");
  check_encode(vff, sizeof vff, "5Q");
}

static void test_base58_encode_prefix_zeros_then_value(void)
{
  unsigned char a[] = {0x00, 0x01};      /* 0x00,1 => "12" */
  unsigned char b[] = {0x00, 0x00, 0xFF};/* two zeros then 255 => "115Q" */

  check_encode(a, sizeof a, "12");
  check_encode(b, sizeof b, "115Q");
}

static void test_base58_encode_small_multibyte_examples(void)
{
  /* 0x0100 = 256 => base58 digits 4,24 => "5R" */
  unsigned char v256[] = {0x01, 0x00};
  check_encode(v256, sizeof v256, "5R");

  /* 0x01 0x02 0x03 = 66051 => digits 19,36,47 => "Ldp" */
  unsigned char v123[] = {0x01, 0x02, 0x03};
  check_encode(v123, sizeof v123, "Ldp");
}

static bool is_forbidden_base58_char(char c)
{
  /* Base58 alphabet excludes these visually ambiguous characters */
  return (c == '0' || c == 'O' || c == 'I' || c == 'l');
}

static void test_base58_encode_long_input_properties(void)
{
  /* Create a non-zero-leading buffer: 0x01, 0x02, ..., 0xFF, 0x00, 0x01 */
  size_t n = 300;
  unsigned char *buf = (unsigned char *)malloc(n);
  TEST_ASSERT_NOT_NULL(buf);
  for (size_t i = 0; i < n; i++)
    buf[i] = (unsigned char)((i + 1) & 0xFF);
  buf[0] = 0x01; /* ensure no leading zero */

  idx_t cap = base58_length((idx_t)n);
  char *out = (char *)malloc((size_t)cap);
  TEST_ASSERT_NOT_NULL(out);
  memset(out, 0xAA, (size_t)cap);

  idx_t outlen = cap;
  base58_encode((const char *)buf, n, out, &outlen);

  TEST_ASSERT_TRUE(outlen > 0);
  /* Since first byte != 0x00, output must not start with '1' (value 0 digit). */
  TEST_ASSERT_NOT_EQUAL('1', out[0]);

  /* Check that no forbidden characters appear in output. */
  for (idx_t i = 0; i < outlen; i++)
    TEST_ASSERT_FALSE(is_forbidden_base58_char(out[i]));

  /* Ensure no writes past returned length. */
  for (idx_t i = outlen; i < cap; i++)
    TEST_ASSERT_EQUAL_HEX8(0xAA, (unsigned char)out[i]);

  free(out);
  free(buf);
}

int main(void)
{
  UNITY_BEGIN();
  RUN_TEST(test_base58_encode_empty);
  RUN_TEST(test_base58_encode_only_zeros);
  RUN_TEST(test_base58_encode_single_bytes);
  RUN_TEST(test_base58_encode_prefix_zeros_then_value);
  RUN_TEST(test_base58_encode_small_multibyte_examples);
  RUN_TEST(test_base58_encode_long_input_properties);
  return UNITY_END();
}