github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/www/resources/bech32.js (about) 1 // Copyright (c) 2017, 2021 Pieter Wuille 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; 22 var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; 23 24 const encodings = { 25 BECH32: "bech32", 26 BECH32M: "bech32m", 27 }; 28 function getEncodingConst (enc) { 29 if (enc == encodings.BECH32) { 30 return 1; 31 } else if (enc == encodings.BECH32M) { 32 return 0x2bc830a3; 33 } else { 34 return null; 35 } 36 } 37 38 function polymod (values) { 39 var chk = 1; 40 for (var p = 0; p < values.length; ++p) { 41 var top = chk >> 25; 42 chk = (chk & 0x1ffffff) << 5 ^ values[p]; 43 for (var i = 0; i < 5; ++i) { 44 if ((top >> i) & 1) { 45 chk ^= GENERATOR[i]; 46 } 47 } 48 } 49 return chk; 50 } 51 52 function hrpExpand (hrp) { 53 var ret = []; 54 var p; 55 for (p = 0; p < hrp.length; ++p) { 56 ret.push(hrp.charCodeAt(p) >> 5); 57 } 58 ret.push(0); 59 for (p = 0; p < hrp.length; ++p) { 60 ret.push(hrp.charCodeAt(p) & 31); 61 } 62 return ret; 63 } 64 65 function verifyChecksum (hrp, data, enc) { 66 return polymod(hrpExpand(hrp).concat(data)) === getEncodingConst(enc); 67 } 68 69 function createChecksum (hrp, data, enc) { 70 var values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]); 71 var mod = polymod(values) ^ getEncodingConst(enc); 72 var ret = []; 73 for (var p = 0; p < 6; ++p) { 74 ret.push((mod >> 5 * (5 - p)) & 31); 75 } 76 return ret; 77 } 78 79 function bech32_encode (hrp, data, enc) { 80 var combined = data.concat(createChecksum(hrp, data, enc)); 81 var ret = hrp + '1'; 82 for (var p = 0; p < combined.length; ++p) { 83 ret += CHARSET.charAt(combined[p]); 84 } 85 return ret; 86 } 87 88 function bech32_decode (bechString, enc) { 89 var p; 90 var has_lower = false; 91 var has_upper = false; 92 for (p = 0; p < bechString.length; ++p) { 93 if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) { 94 return null; 95 } 96 if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) { 97 has_lower = true; 98 } 99 if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) { 100 has_upper = true; 101 } 102 } 103 if (has_lower && has_upper) { 104 return null; 105 } 106 bechString = bechString.toLowerCase(); 107 var pos = bechString.lastIndexOf('1'); 108 if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) { 109 return null; 110 } 111 var hrp = bechString.substring(0, pos); 112 var data = []; 113 for (p = pos + 1; p < bechString.length; ++p) { 114 var d = CHARSET.indexOf(bechString.charAt(p)); 115 if (d === -1) { 116 return null; 117 } 118 data.push(d); 119 } 120 if (!verifyChecksum(hrp, data, enc)) { 121 return null; 122 } 123 return {hrp: hrp, data: data.slice(0, data.length - 6)}; 124 } 125 126 function convertbits (data, frombits, tobits, pad) { 127 var acc = 0; 128 var bits = 0; 129 var ret = []; 130 var maxv = (1 << tobits) - 1; 131 for (var p = 0; p < data.length; ++p) { 132 var value = data[p]; 133 if (value < 0 || (value >> frombits) !== 0) { 134 return null; 135 } 136 acc = (acc << frombits) | value; 137 bits += frombits; 138 while (bits >= tobits) { 139 bits -= tobits; 140 ret.push((acc >> bits) & maxv); 141 } 142 } 143 if (pad) { 144 if (bits > 0) { 145 ret.push((acc << (tobits - bits)) & maxv); 146 } 147 } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) { 148 return null; 149 } 150 return ret; 151 } 152 153 function sw_decode (hrp, addr) { 154 var bech32m = false; 155 var dec = bech32_decode(addr, encodings.BECH32); 156 if (dec === null) { 157 dec = bech32_decode(addr, encodings.BECH32M); 158 bech32m = true; 159 } 160 if (dec === null || dec.hrp !== hrp || dec.data.length < 1 || dec.data[0] > 16) { 161 return null; 162 } 163 var res = convertbits(dec.data.slice(1), 5, 8, false); 164 if (res === null || res.length < 2 || res.length > 40) { 165 return null; 166 } 167 if (dec.data[0] === 0 && res.length !== 20 && res.length !== 32) { 168 return null; 169 } 170 if (dec.data[0] === 0 && bech32m) { 171 return null; 172 } 173 if (dec.data[0] !== 0 && !bech32m) { 174 return null; 175 } 176 return {version: dec.data[0], program: res}; 177 } 178 179 function sw_encode (hrp, version, program) { 180 var enc = encodings.BECH32; 181 if (version > 0) { 182 enc = encodings.BECH32M; 183 } 184 var ret = bech32_encode(hrp, [version].concat(convertbits(program, 8, 5, true)), enc); 185 if (sw_decode(hrp, ret, enc) === null) { 186 return null; 187 } 188 return ret; 189 }