13 typedef std::vector<uint8_t> data;
16 const char* CHARSET =
"qpzry9x8gf2tvdw0s3jn54khce6mua7l";
19 const int8_t CHARSET_REV[128] = {
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
24 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
25 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
26 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
27 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
33 uint32_t PolyMod(
const data& v)
61 for (
const auto v_i : v) {
80 c = ((c & 0x1ffffff) << 5) ^ v_i;
83 if (c0 & 1) c ^= 0x3b6a57b2;
84 if (c0 & 2) c ^= 0x26508e6d;
85 if (c0 & 4) c ^= 0x1ea119fa;
86 if (c0 & 8) c ^= 0x3d4233dd;
87 if (c0 & 16) c ^= 0x2a1462b3;
93 inline unsigned char LowerCase(
unsigned char c)
95 return (c >=
'A' && c <=
'Z') ? (c -
'A') +
'a' : c;
99 data ExpandHRP(
const std::string& hrp)
102 ret.reserve(hrp.size() + 90);
103 ret.resize(hrp.size() * 2 + 1);
104 for (
size_t i = 0; i < hrp.size(); ++i) {
105 unsigned char c = hrp[i];
107 ret[i + hrp.size() + 1] = c & 0x1f;
114 bool VerifyChecksum(
const std::string& hrp,
const data& values)
120 return PolyMod(
Cat(ExpandHRP(hrp), values)) == 1;
124 data CreateChecksum(
const std::string& hrp,
const data& values)
126 data enc =
Cat(ExpandHRP(hrp), values);
127 enc.resize(enc.size() + 6);
128 uint32_t mod = PolyMod(enc) ^ 1;
130 for (
size_t i = 0; i < 6; ++i) {
132 ret[i] = (mod >> (5 * (5 - i))) & 31;
143 std::string
Encode(
const std::string& hrp,
const data& values) {
147 for (
const char& c : hrp)
assert(c < 'A' || c >
'Z');
148 data checksum = CreateChecksum(hrp, values);
149 data combined =
Cat(values, checksum);
150 std::string ret = hrp +
'1';
151 ret.reserve(ret.size() + combined.size());
152 for (
const auto c : combined) {
159 std::pair<std::string, data>
Decode(
const std::string& str) {
160 bool lower =
false, upper =
false;
161 for (
size_t i = 0; i < str.size(); ++i) {
162 unsigned char c = str[i];
163 if (c >=
'a' && c <=
'z') lower =
true;
164 else if (c >=
'A' && c <=
'Z') upper =
true;
165 else if (c < 33 || c > 126)
return {};
167 if (lower && upper)
return {};
168 size_t pos = str.rfind(
'1');
169 if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
172 data values(str.size() - 1 - pos);
173 for (
size_t i = 0; i < str.size() - 1 - pos; ++i) {
174 unsigned char c = str[i + pos + 1];
175 int8_t rev = CHARSET_REV[c];
183 for (
size_t i = 0; i < pos; ++i) {
184 hrp += LowerCase(str[i]);
186 if (!VerifyChecksum(hrp, values)) {
189 return {hrp, data(values.begin(), values.end() - 6)};
std::pair< std::string, data > Decode(const std::string &str)
Decode a Bech32 string.
std::string Encode(const std::string &hrp, const data &values)
Encode a Bech32 string.
V Cat(V v1, V &&v2)
Concatenate two vectors, moving elements.