1
// Copyright © 2014-2018 The Bitcoin Core developers
2
// Copyright © 2017-2020 Trust Wallet.
3
//
4
// This file is part of Trust. The full Trust copyright notice, including
5
// terms governing use, modification, and redistribution, is contained in the
6
// file LICENSE at the root of the source code distribution tree.
7

8
#include "Base58.h"
9

10
#include "Hash.h"
11

12
#include <algorithm>
13
#include <cctype>
14
#include <cassert>
15

16
using namespace TW;
17

18
// clang-format off
19

20
static const std::array<char, 58> bitcoinDigits = {
21
    '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
22
    'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
23
    'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm',
24
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
25
};
26

27
static const std::array<signed char, 128> bitcoinCharacterMap = {
28
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
29
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
30
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
31
	-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
32
	-1, 9,10,11,12,13,14,15,16,-1,17,18,19,20,21,-1,
33
	22,23,24,25,26,27,28,29,30,31,32,-1,-1,-1,-1,-1,
34
	-1,33,34,35,36,37,38,39,40,41,42,43,-1,44,45,46,
35
	47,48,49,50,51,52,53,54,55,56,57,-1,-1,-1,-1,-1,
36
};
37

38
static const std::array<char, 58> rippleDigits = {
39
    'r', 'p', 's', 'h', 'n', 'a', 'f', '3', '9', 'w', 'B', 'U', 'D', 'N', 'E',
40
    'G', 'H', 'J', 'K', 'L', 'M', '4', 'P', 'Q', 'R', 'S', 'T', '7', 'V', 'W',
41
    'X', 'Y', 'Z', '2', 'b', 'c', 'd', 'e', 'C', 'g', '6', '5', 'j', 'k', 'm',
42
    '8', 'o', 'F', 'q', 'i', '1', 't', 'u', 'v', 'A', 'x', 'y', 'z'
43
};
44

45
static const std::array<signed char, 128> rippleCharacterMap = {
46
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
47
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
48
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
49
    -1,50,33,7,21,41,40,27,45,8,-1,-1,-1,-1,-1,-1,
50
    -1,54,10,38,12,14,47,15,16,-1,17,18,19,20,13,-1,
51
    22,23,24,25,26,11,28,29,30,31,32,-1,-1,-1,-1,-1,
52
    -1,5,34,35,36,37,6,39,3,49,42,43,-1,44,4,46,
53
    1,48,0,2,51,52,53,9,55,56,57,-1,-1,-1,-1,-1,
54
};
55

56
// clang-format on
57

58 1
Base58 Base58::bitcoin = Base58(bitcoinDigits, bitcoinCharacterMap);
59

60 1
Base58 Base58::ripple = Base58(rippleDigits, rippleCharacterMap);
61

62 1
Data Base58::decodeCheck(const char* begin, const char* end, Hash::Hasher hasher) const {
63 1
    auto result = decode(begin, end);
64 1
    if (result.size() < 4) {
65 1
        return {};
66
    }
67

68
    // re-calculate the checksum, ensure it matches the included 4-byte checksum
69 1
    auto hash = hasher(result.data(), result.size() - 4);
70 1
    if (!std::equal(hash.begin(), hash.begin() + 4, result.end() - 4)) {
71 1
        return {};
72
    }
73

74 1
    return Data(result.begin(), result.end() - 4);
75
}
76

77 1
Data Base58::decode(const char* begin, const char* end) const {
78 1
    auto it = begin;
79

80
    // Skip leading spaces.
81 1
    it = std::find_if_not(it, end, std::isspace);
82

83
    // Skip and count leading zeros.
84 1
    std::size_t zeroes = 0;
85 1
    std::size_t length = 0;
86 1
    while (it != end && *it == digits[0]) {
87 1
        zeroes += 1;
88 1
        it += 1;
89
    }
90

91
    // Allocate enough space in big-endian base256 representation.
92 1
    std::size_t base258Size = (end - it) * 733 / 1000 + 1; // log(58) / log(256), rounded up.
93 1
    Data b256(base258Size);
94

95
    // Process the characters.
96 1
    while (it != end && !std::isspace(*it)) {
97 1
        if (static_cast<unsigned char>(*it) >= 128) {
98
            // Invalid b58 character
99 0
            return {};
100
        }
101

102
        // Decode base58 character
103 1
        int carry = characterMap[static_cast<unsigned char>(*it)];
104 1
        if (carry == -1) {
105
            // Invalid b58 character
106 1
            return {};
107
        }
108

109 1
        std::size_t i = 0;
110 1
        for (auto b256it = b256.rbegin(); (carry != 0 || i < length) && (b256it != b256.rend());
111 1
             ++b256it, ++i) {
112 1
            carry += 58 * (*b256it);
113 1
            *b256it = static_cast<uint8_t>(carry % 256);
114 1
            carry /= 256;
115
        }
116 1
        assert(carry == 0);
117 1
        length = i;
118 1
        it += 1;
119
    }
120

121
    // Skip trailing spaces.
122 1
    it = std::find_if_not(it, end, std::isspace);
123 1
    if (it != end) {
124
        // Extra charaters at the end
125 0
        return {};
126
    }
127

128
    // Skip leading zeroes in b256.
129 1
    auto b256it = b256.begin() + (base258Size - length);
130 1
    while (b256it != b256.end() && *b256it == 0) {
131 0
        b256it++;
132
    }
133

134
    // Copy result into output vector.
135 1
    Data result;
136 1
    result.reserve(zeroes + (b256.end() - b256it));
137 1
    result.assign(zeroes, 0x00);
138 1
    std::copy(b256it, b256.end(), std::back_inserter(result));
139

140 1
    return result;
141
}
142

143 1
std::string Base58::encodeCheck(const byte* begin, const byte* end, Hash::Hasher hasher) const {
144
    // add 4-byte hash check to the end
145 1
    Data dataWithCheck(begin, end);
146 1
    auto hash = hasher(begin, end - begin);
147 1
    dataWithCheck.insert(dataWithCheck.end(), hash.begin(), hash.begin() + 4);
148 1
    return encode(dataWithCheck);
149
}
150

151 1
std::string Base58::encode(const byte* begin, const byte* end) const {
152
    // Skip & count leading zeroes.
153 1
    int zeroes = 0;
154 1
    int length = 0;
155 1
    while (begin != end && *begin == 0) {
156 1
        begin += 1;
157 1
        zeroes += 1;
158
    }
159

160
    // Allocate enough space in big-endian base58 representation.
161 1
    auto base58Size = (end - begin) * 138 / 100 + 1; // log(256) / log(58), rounded up.
162 1
    Data b58(base58Size);
163

164 1
    while (begin != end) {
165 1
        int carry = *begin;
166 1
        int i = 0;
167
        // Apply "b58 = b58 * 256 + ch".
168 1
        for (auto b58it = b58.rbegin(); (carry != 0 || i < length) && (b58it != b58.rend());
169 1
             b58it++, i++) {
170 1
            carry += 256 * (*b58it);
171 1
            *b58it = carry % 58;
172 1
            carry /= 58;
173
        }
174

175 1
        assert(carry == 0);
176 1
        length = i;
177 1
        begin += 1;
178
    }
179

180
    // Skip leading zeroes in base58 result.
181 1
    auto it = b58.begin() + (base58Size - length);
182 1
    while (it != b58.end() && *it == 0) {
183 0
        it++;
184
    }
185

186
    // Translate the result into a string.
187 1
    std::string str;
188 1
    str.reserve(zeroes + (b58.end() - it));
189 1
    str.assign(zeroes, digits[0]);
190 1
    while (it != b58.end()) {
191 1
        str += digits[*it];
192 1
        it += 1;
193
    }
194 1
    return str;
195
}

Read our documentation on viewing source code .

Loading