MCPcopy Create free account
hub / github.com/bitcoin/bitcoin / DescriptorChecksum

Function DescriptorChecksum

src/script/descriptor.cpp:122–167  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

120}
121
122std::string DescriptorChecksum(const std::span<const char>& span)
123{
124 /** A character set designed such that:
125 * - The most common 'unprotected' descriptor characters (hex, keypaths) are in the first group of 32.
126 * - Case errors cause an offset that's a multiple of 32.
127 * - As many alphabetic characters are in the same group (while following the above restrictions).
128 *
129 * If p(x) gives the position of a character c in this character set, every group of 3 characters
130 * (a,b,c) is encoded as the 4 symbols (p(a) & 31, p(b) & 31, p(c) & 31, (p(a) / 32) + 3 * (p(b) / 32) + 9 * (p(c) / 32).
131 * This means that changes that only affect the lower 5 bits of the position, or only the higher 2 bits, will just
132 * affect a single symbol.
133 *
134 * As a result, within-group-of-32 errors count as 1 symbol, as do cross-group errors that don't affect
135 * the position within the groups.
136 */
137 static const std::string INPUT_CHARSET =
138 "0123456789()[],'/*abcdefgh@:$%{}"
139 "IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~"
140 "ijklmnopqrstuvwxyzABCDEFGH`#\"\\ ";
141
142 /** The character set for the checksum itself (same as bech32). */
143 static const std::string CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
144
145 uint64_t c = 1;
146 int cls = 0;
147 int clscount = 0;
148 for (auto ch : span) {
149 auto pos = INPUT_CHARSET.find(ch);
150 if (pos == std::string::npos) return "";
151 c = PolyMod(c, pos & 31); // Emit a symbol for the position inside the group, for every character.
152 cls = cls * 3 + (pos >> 5); // Accumulate the group numbers
153 if (++clscount == 3) {
154 // Emit an extra symbol representing the group numbers, for every 3 characters.
155 c = PolyMod(c, cls);
156 cls = 0;
157 clscount = 0;
158 }
159 }
160 if (clscount > 0) c = PolyMod(c, cls);
161 for (int j = 0; j < 8; ++j) c = PolyMod(c, 0); // Shift further to determine the checksum.
162 c ^= 1; // Prevent appending zeroes from not affecting the checksum.
163
164 std::string ret(8, ' ');
165 for (int j = 0; j < 8; ++j) ret[j] = CHECKSUM_CHARSET[(c >> (5 * (7 - j))) & 31];
166 return ret;
167}
168
169std::string AddChecksum(const std::string& str) { return str + "#" + DescriptorChecksum(str); }
170

Callers 2

AddChecksumFunction · 0.85
CheckChecksumFunction · 0.85

Calls 2

findMethod · 0.80
PolyModFunction · 0.70

Tested by

no test coverage detected