11typedef std::vector<uint8_t> data;
13constexpr size_t CHECKSUM_SIZE = 8;
18const char *CHARSET =
"qpzry9x8gf2tvdw0s3jn54khce6mua7l";
23const int8_t CHARSET_REV[128] = {
24 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7,
27 5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22,
28 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1,
29 -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0,
30 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1};
37uint64_t PolyMod(
const data &v) {
100 c = ((c & 0x07ffffffff) << 5) ^ d;
149inline uint8_t LowerCase(uint8_t c) {
157data ExpandPrefix(
const std::string &
prefix) {
159 ret.resize(
prefix.size() + 1);
160 for (
size_t i = 0; i <
prefix.size(); ++i) {
161 ret[i] =
prefix[i] & 0x1f;
171bool VerifyChecksum(
const std::string &
prefix,
const data &payload) {
172 return PolyMod(
Cat(ExpandPrefix(
prefix), payload)) == 0;
178data CreateChecksum(
const std::string &
prefix,
const data &payload) {
179 data enc =
Cat(ExpandPrefix(
prefix), payload);
181 enc.resize(enc.size() + CHECKSUM_SIZE);
183 uint64_t mod = PolyMod(enc);
184 data ret(CHECKSUM_SIZE);
185 for (
size_t i = 0; i < CHECKSUM_SIZE; ++i) {
187 ret[i] = (mod >> (5 * (7 - i))) & 0x1f;
201 data checksum = CreateChecksum(
prefix, payload);
202 data combined =
Cat(payload, checksum);
203 std::string ret =
prefix +
':';
205 ret.reserve(ret.size() + combined.size());
206 for (uint8_t c : combined) {
216std::pair<std::string, data>
Decode(
const std::string &str,
217 const std::string &default_prefix) {
219 bool lower =
false, upper =
false, hasNumber =
false;
220 size_t prefixSize = 0;
221 for (
size_t i = 0; i < str.size(); ++i) {
223 if (c >=
'a' && c <=
'z') {
228 if (c >=
'A' && c <=
'Z') {
233 if (c >=
'0' && c <=
'9') {
242 if (hasNumber || i == 0 || prefixSize != 0) {
255 if (upper && lower) {
261 if (prefixSize == 0) {
264 prefix.reserve(prefixSize);
265 for (
size_t i = 0; i < prefixSize; ++i) {
266 prefix += LowerCase(str[i]);
274 const size_t valuesSize = str.size() - prefixSize;
275 if (valuesSize < CHECKSUM_SIZE) {
279 data values(valuesSize);
280 for (
size_t i = 0; i < valuesSize; ++i) {
281 uint8_t c = str[i + prefixSize];
283 if (c > 127 || CHARSET_REV[c] == -1) {
287 values[i] = CHARSET_REV[c];
291 if (!VerifyChecksum(
prefix, values)) {
295 return {std::move(
prefix),
296 data(values.begin(), values.end() - CHECKSUM_SIZE)};
std::pair< std::string, data > Decode(const std::string &str, const std::string &default_prefix)
Decode a cashaddr string.
std::string Encode(const std::string &prefix, const data &payload)
Encode a cashaddr string.
V Cat(V v1, V &&v2)
Concatenate two vectors, moving elements.