Monero
Loading...
Searching...
No Matches
base58.cpp
Go to the documentation of this file.
1// Copyright (c) 2014-2022, The Monero Project
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without modification, are
6// permitted provided that the following conditions are met:
7//
8// 1. Redistributions of source code must retain the above copyright notice, this list of
9// conditions and the following disclaimer.
10//
11// 2. Redistributions in binary form must reproduce the above copyright notice, this list
12// of conditions and the following disclaimer in the documentation and/or other
13// materials provided with the distribution.
14//
15// 3. Neither the name of the copyright holder nor the names of its contributors may be
16// used to endorse or promote products derived from this software without specific
17// prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
30
31#include "base58.h"
32
33#include <assert.h>
34#include <string>
35#include <vector>
36
37#include "crypto/hash.h"
38#include "int-util.h"
39#include "varint.h"
40
41namespace tools
42{
43 namespace base58
44 {
45 namespace
46 {
47 const char alphabet[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
48 const size_t alphabet_size = sizeof(alphabet) - 1;
49 const size_t encoded_block_sizes[] = {0, 2, 3, 5, 6, 7, 9, 10, 11};
50 const size_t full_block_size = sizeof(encoded_block_sizes) / sizeof(encoded_block_sizes[0]) - 1;
51 const size_t full_encoded_block_size = encoded_block_sizes[full_block_size];
52 const size_t addr_checksum_size = 4;
53
54 struct reverse_alphabet
55 {
56 reverse_alphabet()
57 {
58 m_data.resize(alphabet[alphabet_size - 1] - alphabet[0] + 1, -1);
59
60 for (size_t i = 0; i < alphabet_size; ++i)
61 {
62 size_t idx = static_cast<size_t>(alphabet[i] - alphabet[0]);
63 m_data[idx] = static_cast<int8_t>(i);
64 }
65 }
66
67 int operator()(char letter) const
68 {
69 size_t idx = static_cast<size_t>(letter - alphabet[0]);
70 return idx < m_data.size() ? m_data[idx] : -1;
71 }
72
73 static reverse_alphabet instance;
74
75 private:
76 std::vector<int8_t> m_data;
77 };
78
79 reverse_alphabet reverse_alphabet::instance;
80
81 struct decoded_block_sizes
82 {
83 decoded_block_sizes()
84 {
85 m_data.resize(encoded_block_sizes[full_block_size] + 1, -1);
86 for (size_t i = 0; i <= full_block_size; ++i)
87 {
88 m_data[encoded_block_sizes[i]] = static_cast<int>(i);
89 }
90 }
91
92 int operator()(size_t encoded_block_size) const
93 {
94 assert(encoded_block_size <= full_encoded_block_size);
95 return m_data[encoded_block_size];
96 }
97
98 static decoded_block_sizes instance;
99
100 private:
101 std::vector<int> m_data;
102 };
103
104 decoded_block_sizes decoded_block_sizes::instance;
105
106 uint64_t uint_8be_to_64(const uint8_t* data, size_t size)
107 {
108 assert(1 <= size && size <= sizeof(uint64_t));
109
110 uint64_t res = 0;
111 memcpy(reinterpret_cast<uint8_t*>(&res) + sizeof(uint64_t) - size, data, size);
112 return SWAP64BE(res);
113 }
114
115 void uint_64_to_8be(uint64_t num, size_t size, uint8_t* data)
116 {
117 assert(1 <= size && size <= sizeof(uint64_t));
118
119 uint64_t num_be = SWAP64BE(num);
120 memcpy(data, reinterpret_cast<uint8_t*>(&num_be) + sizeof(uint64_t) - size, size);
121 }
122
123 void encode_block(const char* block, size_t size, char* res)
124 {
125 assert(1 <= size && size <= full_block_size);
126
127 uint64_t num = uint_8be_to_64(reinterpret_cast<const uint8_t*>(block), size);
128 int i = static_cast<int>(encoded_block_sizes[size]) - 1;
129 while (0 < num)
130 {
131 uint64_t remainder = num % alphabet_size;
132 num /= alphabet_size;
133 res[i] = alphabet[remainder];
134 --i;
135 }
136 }
137
138 bool decode_block(const char* block, size_t size, char* res)
139 {
140 assert(1 <= size && size <= full_encoded_block_size);
141
142 int res_size = decoded_block_sizes::instance(size);
143 if (res_size <= 0)
144 return false; // Invalid block size
145
146 uint64_t res_num = 0;
147 uint64_t order = 1;
148 for (size_t i = size - 1; i < size; --i)
149 {
150 int digit = reverse_alphabet::instance(block[i]);
151 if (digit < 0)
152 return false; // Invalid symbol
153
154 uint64_t product_hi;
155 uint64_t tmp = res_num + mul128(order, digit, &product_hi);
156 if (tmp < res_num || 0 != product_hi)
157 return false; // Overflow
158
159 res_num = tmp;
160 order *= alphabet_size; // Never overflows, 58^10 < 2^64
161 }
162
163 if (static_cast<size_t>(res_size) < full_block_size && (UINT64_C(1) << (8 * res_size)) <= res_num)
164 return false; // Overflow
165
166 uint_64_to_8be(res_num, res_size, reinterpret_cast<uint8_t*>(res));
167
168 return true;
169 }
170 }
171
172 std::string encode(const std::string& data)
173 {
174 if (data.empty())
175 return std::string();
176
177 size_t full_block_count = data.size() / full_block_size;
178 size_t last_block_size = data.size() % full_block_size;
179 size_t res_size = full_block_count * full_encoded_block_size + encoded_block_sizes[last_block_size];
180
181 std::string res(res_size, alphabet[0]);
182 for (size_t i = 0; i < full_block_count; ++i)
183 {
184 encode_block(data.data() + i * full_block_size, full_block_size, &res[i * full_encoded_block_size]);
185 }
186
187 if (0 < last_block_size)
188 {
189 encode_block(data.data() + full_block_count * full_block_size, last_block_size, &res[full_block_count * full_encoded_block_size]);
190 }
191
192 return res;
193 }
194
195 bool decode(const std::string& enc, std::string& data)
196 {
197 if (enc.empty())
198 {
199 data.clear();
200 return true;
201 }
202
203 size_t full_block_count = enc.size() / full_encoded_block_size;
204 size_t last_block_size = enc.size() % full_encoded_block_size;
205 int last_block_decoded_size = decoded_block_sizes::instance(last_block_size);
206 if (last_block_decoded_size < 0)
207 return false; // Invalid enc length
208 size_t data_size = full_block_count * full_block_size + last_block_decoded_size;
209
210 data.resize(data_size, 0);
211 for (size_t i = 0; i < full_block_count; ++i)
212 {
213 if (!decode_block(enc.data() + i * full_encoded_block_size, full_encoded_block_size, &data[i * full_block_size]))
214 return false;
215 }
216
217 if (0 < last_block_size)
218 {
219 if (!decode_block(enc.data() + full_block_count * full_encoded_block_size, last_block_size,
220 &data[full_block_count * full_block_size]))
221 return false;
222 }
223
224 return true;
225 }
226
227 std::string encode_addr(uint64_t tag, const std::string& data)
228 {
229 std::string buf = get_varint_data(tag);
230 buf += data;
231 crypto::hash hash = crypto::cn_fast_hash(buf.data(), buf.size());
232 const char* hash_data = reinterpret_cast<const char*>(&hash);
233 buf.append(hash_data, addr_checksum_size);
234 return encode(buf);
235 }
236
237 bool decode_addr(const std::string &addr, uint64_t& tag, std::string& data)
238 {
239 std::string addr_data;
240 bool r = decode(addr, addr_data);
241 if (!r) return false;
242 if (addr_data.size() <= addr_checksum_size) return false;
243
244 std::string checksum(addr_checksum_size, '\0');
245 checksum = addr_data.substr(addr_data.size() - addr_checksum_size);
246
247 addr_data.resize(addr_data.size() - addr_checksum_size);
248 crypto::hash hash = crypto::cn_fast_hash(addr_data.data(), addr_data.size());
249 std::string expected_checksum(reinterpret_cast<const char*>(&hash), addr_checksum_size);
250 if (expected_checksum != checksum) return false;
251
252 int read = tools::read_varint(addr_data.begin(), addr_data.end(), tag);
253 if (read <= 0) return false;
254
255 data = addr_data.substr(read);
256 return true;
257 }
258 }
259}
static const unsigned long long order[16]
Definition sc25519_from32bytes.c:8
struct block_ block
void * memcpy(void *a, const void *b, size_t c)
Definition glibc_compat.cpp:16
const char * res
Definition hmac_keccak.cpp:42
#define SWAP64BE
Definition int-util.h:286
static uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi)
Definition int-util.h:82
void cn_fast_hash(const void *data, size_t length, char *hash)
POD_CLASS hash
Definition hash.h:49
Definition base58.cpp:44
bool decode(const std::string &enc, std::string &data)
Definition base58.cpp:195
std::string encode_addr(uint64_t tag, const std::string &data)
Definition base58.cpp:227
std::string encode(const std::string &data)
Definition base58.cpp:172
bool decode_addr(const std::string &addr, uint64_t &tag, std::string &data)
Definition base58.cpp:237
Various Tools.
Definition apply_permutation.h:40
std::enable_if< std::is_integral< T >::value &&std::is_unsigned< T >::value &&0<=bits &&bits<=std::numeric_limits< T >::digits, int >::type read_varint(InputIt &&first, InputIt &&last, T &write)
reads in the varint that is pointed to by InputIt into write
Definition varint.h:94
std::string get_varint_data(const T &v)
Returns the string that represents the varint.
Definition varint.h:84
const char * buf
Definition slow_memmem.cpp:73
#define UINT64_C(val)
Definition stdint.h:284
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
signed char int8_t
Definition stdint.h:121
const char * tag
Definition testobsdrdr.c:19
std::string data
Definition base58.cpp:37
provides the implementation of varint's