Any projects which want to use Hush code from now on will need to be licensed as GPLv3 or we will send the lawyers: https://www.softwarefreedom.org/ Notably, Komodo (KMD) is licensed as GPLv2 and is no longer compatible to receive code changes, without causing legal issues. MIT projects, such as Zcash, also cannot pull in changes from the Hush Full Node without permission from The Hush Developers, which may in some circumstances grant an MIT license on a case-by-case basis.
196 lines
7.9 KiB
C++
196 lines
7.9 KiB
C++
// Copyright (c) 2017 Pieter Wuille
|
|
// Copyright (c) 2019-2020 The Hush developers
|
|
// Distributed under the GPLv3 software license, see the accompanying
|
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
|
|
#include "bech32.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
typedef std::vector<uint8_t> data;
|
|
|
|
/** The Bech32 character set for encoding. */
|
|
const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
|
|
/** The Bech32 character set for decoding. */
|
|
const int8_t CHARSET_REV[128] = {
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
|
|
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
|
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
|
|
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
|
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
|
|
};
|
|
|
|
/** Concatenate two byte arrays. */
|
|
data Cat(data x, const data& y)
|
|
{
|
|
x.insert(x.end(), y.begin(), y.end());
|
|
return x;
|
|
}
|
|
|
|
/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to
|
|
* make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
|
|
* bits correspond to earlier values. */
|
|
uint32_t PolyMod(const data& v)
|
|
{
|
|
// The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an
|
|
// implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) =
|
|
// 1*x^5 + v0*x^4 + v1*x^3 + v2*x^2 + v3*x + v4. The implicit 1 guarantees that
|
|
// [v0,v1,v2,...] has a distinct checksum from [0,v0,v1,v2,...].
|
|
|
|
// The output is a 30-bit integer whose 5-bit groups are the coefficients of the remainder of
|
|
// v(x) mod g(x), where g(x) is the Bech32 generator,
|
|
// x^6 + {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}. g(x) is chosen in such a way
|
|
// that the resulting code is a BCH code, guaranteeing detection of up to 3 errors within a
|
|
// window of 1023 characters. Among the various possible BCH codes, one was selected to in
|
|
// fact guarantee detection of up to 4 errors within a window of 89 characters.
|
|
|
|
// Note that the coefficients are elements of GF(32), here represented as decimal numbers
|
|
// between {}. In this finite field, addition is just XOR of the corresponding numbers. For
|
|
// example, {27} + {13} = {27 ^ 13} = {22}. Multiplication is more complicated, and requires
|
|
// treating the bits of values themselves as coefficients of a polynomial over a smaller field,
|
|
// GF(2), and multiplying those polynomials mod a^5 + a^3 + 1. For example, {5} * {26} =
|
|
// (a^2 + 1) * (a^4 + a^3 + a) = (a^4 + a^3 + a) * a^2 + (a^4 + a^3 + a) = a^6 + a^5 + a^4 + a
|
|
// = a^3 + 1 (mod a^5 + a^3 + 1) = {9}.
|
|
|
|
// During the course of the loop below, `c` contains the bitpacked coefficients of the
|
|
// polynomial constructed from just the values of v that were processed so far, mod g(x). In
|
|
// the above example, `c` initially corresponds to 1 mod (x), and after processing 2 inputs of
|
|
// v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value
|
|
// for `c`.
|
|
uint32_t c = 1;
|
|
for (auto v_i : v) {
|
|
// We want to update `c` to correspond to a polynomial with one extra term. If the initial
|
|
// value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to
|
|
// correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to
|
|
// process. Simplifying:
|
|
// c'(x) = (f(x) * x + v_i) mod g(x)
|
|
// ((f(x) mod g(x)) * x + v_i) mod g(x)
|
|
// (c(x) * x + v_i) mod g(x)
|
|
// If c(x) = c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5, we want to compute
|
|
// c'(x) = (c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5) * x + v_i mod g(x)
|
|
// = c0*x^6 + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i mod g(x)
|
|
// = c0*(x^6 mod g(x)) + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i
|
|
// If we call (x^6 mod g(x)) = k(x), this can be written as
|
|
// c'(x) = (c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i) + c0*k(x)
|
|
|
|
// First, determine the value of c0:
|
|
uint8_t c0 = c >> 25;
|
|
|
|
// Then compute c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i:
|
|
c = ((c & 0x1ffffff) << 5) ^ v_i;
|
|
|
|
// Finally, for each set bit n in c0, conditionally add {2^n}k(x):
|
|
if (c0 & 1) c ^= 0x3b6a57b2; // k(x) = {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}
|
|
if (c0 & 2) c ^= 0x26508e6d; // {2}k(x) = {19}x^5 + {5}x^4 + x^3 + {3}x^2 + {19}x + {13}
|
|
if (c0 & 4) c ^= 0x1ea119fa; // {4}k(x) = {15}x^5 + {10}x^4 + {2}x^3 + {6}x^2 + {15}x + {26}
|
|
if (c0 & 8) c ^= 0x3d4233dd; // {8}k(x) = {30}x^5 + {20}x^4 + {4}x^3 + {12}x^2 + {30}x + {29}
|
|
if (c0 & 16) c ^= 0x2a1462b3; // {16}k(x) = {21}x^5 + x^4 + {8}x^3 + {24}x^2 + {21}x + {19}
|
|
}
|
|
return c;
|
|
}
|
|
|
|
/** Convert to lower case. */
|
|
inline unsigned char LowerCase(unsigned char c)
|
|
{
|
|
return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;
|
|
}
|
|
|
|
/** Expand a HRP for use in checksum computation. */
|
|
data ExpandHRP(const std::string& hrp)
|
|
{
|
|
data ret;
|
|
ret.reserve(hrp.size() + 90);
|
|
ret.resize(hrp.size() * 2 + 1);
|
|
for (size_t i = 0; i < hrp.size(); ++i) {
|
|
unsigned char c = hrp[i];
|
|
ret[i] = c >> 5;
|
|
ret[i + hrp.size() + 1] = c & 0x1f;
|
|
}
|
|
ret[hrp.size()] = 0;
|
|
return ret;
|
|
}
|
|
|
|
/** Verify a checksum. */
|
|
bool VerifyChecksum(const std::string& hrp, const data& values)
|
|
{
|
|
// PolyMod computes what value to xor into the final values to make the checksum 0. However,
|
|
// if we required that the checksum was 0, it would be the case that appending a 0 to a valid
|
|
// list of values would result in a new valid list. For that reason, Bech32 requires the
|
|
// resulting checksum to be 1 instead.
|
|
return PolyMod(Cat(ExpandHRP(hrp), values)) == 1;
|
|
}
|
|
|
|
/** Create a checksum. */
|
|
data CreateChecksum(const std::string& hrp, const data& values)
|
|
{
|
|
data enc = Cat(ExpandHRP(hrp), values);
|
|
enc.resize(enc.size() + 6); // Append 6 zeroes
|
|
uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes.
|
|
data ret(6);
|
|
for (size_t i = 0; i < 6; ++i) {
|
|
// Convert the 5-bit groups in mod to checksum values.
|
|
ret[i] = (mod >> (5 * (5 - i))) & 31;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace bech32
|
|
{
|
|
|
|
/** Encode a Bech32 string. */
|
|
std::string Encode(const std::string& hrp, const data& values) {
|
|
data checksum = CreateChecksum(hrp, values);
|
|
data combined = Cat(values, checksum);
|
|
std::string ret = hrp + '1';
|
|
ret.reserve(ret.size() + combined.size());
|
|
for (auto c : combined) {
|
|
if (c >= 32) {
|
|
return "";
|
|
}
|
|
ret += CHARSET[c];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/** Decode a Bech32 string. */
|
|
std::pair<std::string, data> Decode(const std::string& str) {
|
|
bool lower = false, upper = false;
|
|
for (size_t i = 0; i < str.size(); ++i) {
|
|
unsigned char c = str[i];
|
|
if (c < 33 || c > 126) return {};
|
|
if (c >= 'a' && c <= 'z') lower = true;
|
|
if (c >= 'A' && c <= 'Z') upper = true;
|
|
}
|
|
if (lower && upper) return {};
|
|
size_t pos = str.rfind('1');
|
|
if (str.size() > 1023 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
|
|
return {};
|
|
}
|
|
data values(str.size() - 1 - pos);
|
|
for (size_t i = 0; i < str.size() - 1 - pos; ++i) {
|
|
unsigned char c = str[i + pos + 1];
|
|
int8_t rev = (c < 33 || c > 126) ? -1 : CHARSET_REV[c];
|
|
if (rev == -1) {
|
|
return {};
|
|
}
|
|
values[i] = rev;
|
|
}
|
|
std::string hrp;
|
|
for (size_t i = 0; i < pos; ++i) {
|
|
hrp += LowerCase(str[i]);
|
|
}
|
|
if (!VerifyChecksum(hrp, values)) {
|
|
return {};
|
|
}
|
|
return {hrp, data(values.begin(), values.end() - 6)};
|
|
}
|
|
|
|
} // namespace bech32
|