Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
251}252return SYNDROME_CONSTS;253}254constexpr std::array<uint32_t, 25> SYNDROME_CONSTS = GenerateSyndromeConstants();256/**257* Syndrome returns the three values s_997, s_998, and s_999 described above,258* packed into a 30-bit integer, where each group of 10 bits encodes one value.259*/260uint32_t Syndrome(const uint32_t residue) {261// low is the first 5 bits, corresponding to the r6 in the residue262// (the constant term of the polynomial).263uint32_t low = residue & 0x1f;265// We begin by setting s_j = low = r6 for all three values of j, because these are unconditional.266uint32_t result = low ^ (low << 10) ^ (low << 20);268// Then for each following bit, we add the corresponding precomputed constant if the bit is 1.269// For example, 0x31edd3c4 is 1100011110 1101110100 1111000100 when unpacked in groups of 10270// bits, corresponding exactly to a^999 || a^998 || a^997 (matching the corresponding values in271// GF1024_EXP above). In this way, we compute all three values of s_j for j in (997, 998, 999)272// simultaneously. Recall that XOR corresponds to addition in a characteristic 2 field.273for (int i = 0; i < 25; ++i) {274result ^= ((residue >> (5+i)) & 1 ? SYNDROME_CONSTS.at(i) : 0);275}276return result;277}279/** Convert to lower case. */280inline unsigned char LowerCase(unsigned char c)281{282return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;283}285/** Return indices of invalid characters in a Bech32 string. */286bool CheckCharacters(const std::string& str, std::vector<int>& errors)287{288bool lower = false, upper = false;289for (size_t i = 0; i < str.size(); ++i) {290unsigned char c{(unsigned char)(str[i])};291if (c >= 'a' && c <= 'z') {292if (upper) {293errors.push_back(i);294} else {295lower = true;296}297} else if (c >= 'A' && c <= 'Z') {298if (lower) {299errors.push_back(i);300} else {301upper = true;302}303} else if (c < 33 || c > 126) {304errors.push_back(i);305}306}307return errors.empty();308}310std::vector<unsigned char> PreparePolynomialCoefficients(const std::string& hrp, const data& values)311{312data ret;313ret.reserve(hrp.size() + 1 + hrp.size() + values.size() + CHECKSUM_SIZE);315/** Expand a HRP for use in checksum computation. */316for (size_t i = 0; i < hrp.size(); ++i) ret.push_back(hrp[i] >> 5);317ret.push_back(0);318for (size_t i = 0; i < hrp.size(); ++i) ret.push_back(hrp[i] & 0x1f);320ret.insert(ret.end(), values.begin(), values.end());322return ret;323}325/** Verify a checksum. */326Encoding VerifyChecksum(const std::string& hrp, const data& values)327{328// PolyMod computes what value to xor into the final values to make the checksum 0. However,329// if we required that the checksum was 0, it would be the case that appending a 0 to a valid330// list of values would result in a new valid list. For that reason, Bech32 requires the331// resulting checksum to be 1 instead. In Bech32m, this constant was amended. See332// https://gist.github.com/sipa/14c248c288c3880a3b191f978a34508e for details.333auto enc = PreparePolynomialCoefficients(hrp, values);334const uint32_t check = PolyMod(enc);335if (check == EncodingConstant(Encoding::BECH32)) return Encoding::BECH32;336if (check == EncodingConstant(Encoding::BECH32M)) return Encoding::BECH32M;337return Encoding::INVALID;338}340/** Create a checksum. */341data CreateChecksum(Encoding encoding, const std::string& hrp, const data& values)342{343auto enc = PreparePolynomialCoefficients(hrp, values);344enc.insert(enc.end(), CHECKSUM_SIZE, 0x00);345uint32_t mod = PolyMod(enc) ^ EncodingConstant(encoding); // Determine what to XOR into those 6 zeroes.346data ret(CHECKSUM_SIZE);347for (size_t i = 0; i < CHECKSUM_SIZE; ++i) {348// Convert the 5-bit groups in mod to checksum values.349ret[i] = (mod >> (5 * (5 - i))) & 31;350}351return ret;352}354} // namespace356/** Encode a Bech32 or Bech32m string. */357std::string Encode(Encoding encoding, const std::string& hrp, const data& values) {358// First ensure that the HRP is all lowercase. BIP-173 and BIP350 require an encoder359// to return a lowercase Bech32/Bech32m string, but if given an uppercase HRP, the360// result will always be invalid.361for (const char& c : hrp) assert(c < 'A' || c > 'Z');363std::string ret;364ret.reserve(hrp.size() + 1 + values.size() + CHECKSUM_SIZE);365ret += hrp;366ret += SEPARATOR;367for (const uint8_t& i : values) ret += CHARSET[i];368for (const uint8_t& i : CreateChecksum(encoding, hrp, values)) ret += CHARSET[i];369return ret;370}372/** Decode a Bech32 or Bech32m string. */373DecodeResult Decode(const std::string& str, CharLimit limit) {374std::vector<int> errors;375if (!CheckCharacters(str, errors)) return {};376size_t pos = str.rfind(SEPARATOR);377if (str.size() > limit) return {};378if (pos == str.npos || pos == 0 || pos + CHECKSUM_SIZE >= str.size()) {379return {};380}381data values(str.size() - 1 - pos);382for (size_t i = 0; i < str.size() - 1 - pos; ++i) {383unsigned char c = str[i + pos + 1];384int8_t rev = CHARSET_REV[c];386if (rev == -1) {387return {};388}389values[i] = rev;390}391std::string hrp;392hrp.reserve(pos);393for (size_t i = 0; i < pos; ++i) {394hrp += LowerCase(str[i]);395}396Encoding result = VerifyChecksum(hrp, values);397if (result == Encoding::INVALID) return {};398return {result, std::move(hrp), data(values.begin(), values.end() - CHECKSUM_SIZE)};399}401/** Find index of an incorrect character in a Bech32 string. */402std::pair<std::string, std::vector<int>> LocateErrors(const std::string& str, CharLimit limit) {403std::vector<int> error_locations{};405if (str.size() > limit) {406error_locations.push_back(static_cast<int>(limit));407return std::make_pair("Bech32 string too long", std::move(error_locations));408}410if (!CheckCharacters(str, error_locations)){411return std::make_pair("Invalid character or mixed case", std::move(error_locations));412}414size_t pos = str.rfind(SEPARATOR);415if (pos == str.npos) {416return std::make_pair("Missing separator", std::vector<int>{});417}418if (pos == 0 || pos + CHECKSUM_SIZE >= str.size()) {419error_locations.push_back(pos);420return std::make_pair("Invalid separator position", std::move(error_locations));421}423std::string hrp;424hrp.reserve(pos);425for (size_t i = 0; i < pos; ++i) {426hrp += LowerCase(str[i]);427}429size_t length = str.size() - 1 - pos; // length of data part430data values(length);431for (size_t i = pos + 1; i < str.size(); ++i) {432unsigned char c = str[i];433int8_t rev = CHARSET_REV[c];434if (rev == -1) {435error_locations.push_back(i);436return std::make_pair("Invalid Base 32 character", std::move(error_locations));437}438values[i - pos - 1] = rev;439}441// We attempt error detection with both bech32 and bech32m, and choose the one with the fewest errors442// We can't simply use the segwit version, because that may be one of the errors443std::optional<Encoding> error_encoding;444for (Encoding encoding : {Encoding::BECH32, Encoding::BECH32M}) {445std::vector<int> possible_errors;446// Recall that (expanded hrp + values) is interpreted as a list of coefficients of a polynomial447// over GF(32). PolyMod computes the "remainder" of this polynomial modulo the generator G(x).448auto enc = PreparePolynomialCoefficients(hrp, values);449uint32_t residue = PolyMod(enc) ^ EncodingConstant(encoding);451// All valid codewords should be multiples of G(x), so this remainder (after XORing with the encoding452// constant) should be 0 - hence 0 indicates there are no errors present.453if (residue != 0) {454// If errors are present, our polynomial must be of the form C(x) + E(x) where C is the valid455// codeword (a multiple of G(x)), and E encodes the errors.456uint32_t syn = Syndrome(residue);458// Unpack the three 10-bit syndrome values459int s0 = syn & 0x3FF;460int s1 = (syn >> 10) & 0x3FF;461int s2 = syn >> 20;463// Get the discrete logs of these values in GF1024 for more efficient computation464int l_s0 = GF1024_LOG.at(s0);465int l_s1 = GF1024_LOG.at(s1);466int l_s2 = GF1024_LOG.at(s2);468// First, suppose there is only a single error. Then E(x) = e1*x^p1 for some position p1469// Then s0 = E((e)^997) = e1*(e)^(997*p1) and s1 = E((e)^998) = e1*(e)^(998*p1)470// Therefore s1/s0 = (e)^p1, and by the same logic, s2/s1 = (e)^p1 too.471// Hence, s1^2 == s0*s2, which is exactly the condition we check first:472if (l_s0 != -1 && l_s1 != -1 && l_s2 != -1 && (2 * l_s1 - l_s2 - l_s0 + 2046) % 1023 == 0) {473// Compute the error position p1 as l_s1 - l_s0 = p1 (mod 1023)474size_t p1 = (l_s1 - l_s0 + 1023) % 1023; // the +1023 ensures it is positive475// Now because s0 = e1*(e)^(997*p1), we get e1 = s0/((e)^(997*p1)). Remember that (e)^1023 = 1,476// so 1/((e)^997) = (e)^(1023-997).477int l_e1 = l_s0 + (1023 - 997) * p1;478// Finally, some sanity checks on the result:479// - The error position should be within the length of the data480// - e1 should be in GF(32), which implies that e1 = (e)^(33k) for some k (the 31 non-zero elements481// of GF(32) form an index 33 subgroup of the 1023 non-zero elements of GF(1024)).482if (p1 < length && !(l_e1 % 33)) {483// Polynomials run from highest power to lowest, so the index p1 is from the right.484// We don't return e1 because it is dangerous to suggest corrections to the user,485// the user should check the address themselves.486possible_errors.push_back(str.size() - p1 - 1);487}488// Otherwise, suppose there are two errors. Then E(x) = e1*x^p1 + e2*x^p2.489} else {490// For all possible first error positions p1491for (size_t p1 = 0; p1 < length; ++p1) {492// We have guessed p1, and want to solve for p2. Recall that E(x) = e1*x^p1 + e2*x^p2, so493// s0 = E((e)^997) = e1*(e)^(997^p1) + e2*(e)^(997*p2), and similar for s1 and s2.494//495// Consider s2 + s1*(e)^p1496// = 2e1*(e)^(999^p1) + e2*(e)^(999*p2) + e2*(e)^(998*p2)*(e)^p1497// = e2*(e)^(999*p2) + e2*(e)^(998*p2)*(e)^p1498// (Because we are working in characteristic 2.)499// = e2*(e)^(998*p2) ((e)^p2 + (e)^p1)500//