16 typedef std::vector<uint8_t> data;
19 const char* CHARSET =
"qpzry9x8gf2tvdw0s3jn54khce6mua7l";
22 const int8_t CHARSET_REV[128] = {
23 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
24 -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,
26 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
27 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
28 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
29 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
30 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
34 uint32_t EncodingConstant(
Encoding encoding) {
42 uint32_t PolyMod(
const data& v)
70 for (
const auto v_i : v) {
89 c = ((c & 0x1ffffff) << 5) ^ v_i;
92 if (c0 & 1) c ^= 0x3b6a57b2;
93 if (c0 & 2) c ^= 0x26508e6d;
94 if (c0 & 4) c ^= 0x1ea119fa;
95 if (c0 & 8) c ^= 0x3d4233dd;
96 if (c0 & 16) c ^= 0x2a1462b3;
102 inline unsigned char LowerCase(
unsigned char c)
104 return (c >=
'A' && c <=
'Z') ? (c -
'A') +
'a' : c;
108 data ExpandHRP(
const std::string& hrp)
111 ret.reserve(hrp.size() + 90);
112 ret.resize(hrp.size() * 2 + 1);
113 for (
size_t i = 0; i < hrp.size(); ++i) {
114 unsigned char c = hrp[i];
116 ret[i + hrp.size() + 1] = c & 0x1f;
123 Encoding VerifyChecksum(
const std::string& hrp,
const data& values)
129 const uint32_t check = PolyMod(
Cat(ExpandHRP(hrp), values));
136 data CreateChecksum(
Encoding encoding,
const std::string& hrp,
const data& values)
138 data enc =
Cat(ExpandHRP(hrp), values);
139 enc.resize(enc.size() + 6);
140 uint32_t mod = PolyMod(enc) ^ EncodingConstant(encoding);
142 for (
size_t i = 0; i < 6; ++i) {
144 ret[i] = (mod >> (5 * (5 - i))) & 31;
152 std::string
Encode(
Encoding encoding,
const std::string& hrp,
const data& values) {
156 for (
const char& c : hrp)
assert(c < 'A' || c >
'Z');
157 data checksum = CreateChecksum(encoding, hrp, values);
158 data combined =
Cat(values, checksum);
159 std::string ret = hrp +
'1';
160 ret.reserve(ret.size() + combined.size());
161 for (
const auto c : combined) {
169 bool lower =
false, upper =
false;
170 for (
size_t i = 0; i < str.size(); ++i) {
171 unsigned char c = str[i];
172 if (c >=
'a' && c <=
'z') lower =
true;
173 else if (c >=
'A' && c <=
'Z') upper =
true;
174 else if (c < 33 || c > 126)
return {};
176 if (lower && upper)
return {};
177 size_t pos = str.rfind(
'1');
178 if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
181 data values(str.size() - 1 - pos);
182 for (
size_t i = 0; i < str.size() - 1 - pos; ++i) {
183 unsigned char c = str[i + pos + 1];
184 int8_t rev = CHARSET_REV[c];
192 for (
size_t i = 0; i < pos; ++i) {
193 hrp += LowerCase(str[i]);
195 Encoding result = VerifyChecksum(hrp, values);
197 return {result, std::move(hrp), data(values.begin(), values.end() - 6)};
Bech32 encoding as defined in BIP173.
std::string Encode(Encoding encoding, const std::string &hrp, const data &values)
Encode a Bech32 or Bech32m string.
Bech32m encoding as defined in BIP350.
DecodeResult Decode(const std::string &str)
Decode a Bech32 or Bech32m string.
V Cat(V v1, V &&v2)
Concatenate two vectors, moving elements.