MCPcopy Create free account
hub / github.com/ElementsProject/elements / DescriptorChecksum

Function DescriptorChecksum

src/script/descriptor.cpp:96–141  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

94}
95
96std::string DescriptorChecksum(const Span<const char>& span)
97{
98 /** A character set designed such that:
99 * - The most common 'unprotected' descriptor characters (hex, keypaths) are in the first group of 32.
100 * - Case errors cause an offset that's a multiple of 32.
101 * - As many alphabetic characters are in the same group (while following the above restrictions).
102 *
103 * If p(x) gives the position of a character c in this character set, every group of 3 characters
104 * (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).
105 * This means that changes that only affect the lower 5 bits of the position, or only the higher 2 bits, will just
106 * affect a single symbol.
107 *
108 * As a result, within-group-of-32 errors count as 1 symbol, as do cross-group errors that don't affect
109 * the position within the groups.
110 */
111 static std::string INPUT_CHARSET =
112 "0123456789()[],'/*abcdefgh@:$%{}"
113 "IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~"
114 "ijklmnopqrstuvwxyzABCDEFGH`#\"\\ ";
115
116 /** The character set for the checksum itself (same as bech32). */
117 static std::string CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
118
119 uint64_t c = 1;
120 int cls = 0;
121 int clscount = 0;
122 for (auto ch : span) {
123 auto pos = INPUT_CHARSET.find(ch);
124 if (pos == std::string::npos) return "";
125 c = PolyMod(c, pos & 31); // Emit a symbol for the position inside the group, for every character.
126 cls = cls * 3 + (pos >> 5); // Accumulate the group numbers
127 if (++clscount == 3) {
128 // Emit an extra symbol representing the group numbers, for every 3 characters.
129 c = PolyMod(c, cls);
130 cls = 0;
131 clscount = 0;
132 }
133 }
134 if (clscount > 0) c = PolyMod(c, cls);
135 for (int j = 0; j < 8; ++j) c = PolyMod(c, 0); // Shift further to determine the checksum.
136 c ^= 1; // Prevent appending zeroes from not affecting the checksum.
137
138 std::string ret(8, ' ');
139 for (int j = 0; j < 8; ++j) ret[j] = CHECKSUM_CHARSET[(c >> (5 * (7 - j))) & 31];
140 return ret;
141}
142
143std::string AddChecksum(const std::string& str) { return str + "#" + DescriptorChecksum(str); }
144

Callers 2

AddChecksumFunction · 0.85
CheckChecksumFunction · 0.85

Calls 2

findMethod · 0.80
PolyModFunction · 0.70

Tested by

no test coverage detected