From 56fe27b77d69ef9eddf77c804f054571e1c1f340 Mon Sep 17 00:00:00 2001 From: tripathyr Date: Tue, 8 Aug 2023 15:45:55 +0530 Subject: [PATCH 1/6] Adding Taproot Validation This adds two new objects in main score bech32, and segwit_addr, and provide a set of functions to validate and extract information from Taproot addresses --- scripts/lib.js | 253 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/scripts/lib.js b/scripts/lib.js index e383403..974342f 100644 --- a/scripts/lib.js +++ b/scripts/lib.js @@ -9213,6 +9213,257 @@ })(); + /* Peter Wuille Taproot Address Validation Functions */ + + // Copyright (c) 2017, 2021 Pieter Wuille + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in + // all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + // THE SOFTWARE. + + + + var bech32={}; + var segwit_addr = {}; + + (function(){ + + var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; + var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; + + const encodings = { + BECH32: "bech32", + BECH32M: "bech32m", + }; + + + function getEncodingConst (enc) { + if (enc == bech32.encodings.BECH32) { + return 1; + } else if (enc == bech32.encodings.BECH32M) { + return 0x2bc830a3; + } else { + return null; + } + } + + function polymod (values) { + var chk = 1; + for (var p = 0; p < values.length; ++p) { + var top = chk >> 25; + chk = (chk & 0x1ffffff) << 5 ^ values[p]; + for (var i = 0; i < 5; ++i) { + if ((top >> i) & 1) { + chk ^= GENERATOR[i]; + } + } + } + return chk; + } + + function hrpExpand (hrp) { + var ret = []; + var p; + for (p = 0; p < hrp.length; ++p) { + ret.push(hrp.charCodeAt(p) >> 5); + } + ret.push(0); + for (p = 0; p < hrp.length; ++p) { + ret.push(hrp.charCodeAt(p) & 31); + } + return ret; + } + + function verifyChecksum (hrp, data, enc) { + return polymod(hrpExpand(hrp).concat(data)) === getEncodingConst(enc); + } + + function createChecksum (hrp, data, enc) { + var values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]); + var mod = polymod(values) ^ getEncodingConst(enc); + var ret = []; + for (var p = 0; p < 6; ++p) { + ret.push((mod >> 5 * (5 - p)) & 31); + } + return ret; + } + + function bech32_encode (hrp, data, enc) { + var combined = data.concat(createChecksum(hrp, data, enc)); + var ret = hrp + '1'; + for (var p = 0; p < combined.length; ++p) { + ret += CHARSET.charAt(combined[p]); + } + return ret; + } + + function bech32_decode (bechString, enc) { + var p; + var has_lower = false; + var has_upper = false; + for (p = 0; p < bechString.length; ++p) { + if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) { + return null; + } + if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) { + has_lower = true; + } + if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) { + has_upper = true; + } + } + if (has_lower && has_upper) { + return null; + } + bechString = bechString.toLowerCase(); + var pos = bechString.lastIndexOf('1'); + if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) { + return null; + } + var hrp = bechString.substring(0, pos); + var data = []; + for (p = pos + 1; p < bechString.length; ++p) { + var d = CHARSET.indexOf(bechString.charAt(p)); + if (d === -1) { + return null; + } + data.push(d); + } + if (!verifyChecksum(hrp, data, enc)) { + return null; + } + return {hrp: hrp, data: data.slice(0, data.length - 6)}; + } + + bech32.encodings = encodings; + bech32.encode = bech32_encode; + bech32.decode = bech32_decode; + + // SIPA SEGWIT_ADDR.JS + + // Copyright (c) 2017, 2021 Pieter Wuille + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in + // all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + // THE SOFTWARE. + + + + + + function convertbits (data, frombits, tobits, pad) { + var acc = 0; + var bits = 0; + var ret = []; + var maxv = (1 << tobits) - 1; + for (var p = 0; p < data.length; ++p) { + var value = data[p]; + if (value < 0 || (value >> frombits) !== 0) { + return null; + } + acc = (acc << frombits) | value; + bits += frombits; + while (bits >= tobits) { + bits -= tobits; + ret.push((acc >> bits) & maxv); + } + } + if (pad) { + if (bits > 0) { + ret.push((acc << (tobits - bits)) & maxv); + } + } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) { + return null; + } + return ret; + } + + segwit_addr.convertbits = convertbits; + + function segwit_addr_decode (hrp, addr) { + var bech32m = false; + var dec = bech32.decode(addr, bech32.encodings.BECH32); + if (dec === null) { + dec = bech32.decode(addr, bech32.encodings.BECH32M); + bech32m = true; + } + if (dec === null || dec.hrp !== hrp || dec.data.length < 1 || dec.data[0] > 16) { + return null; + } + var res = convertbits(dec.data.slice(1), 5, 8, false); + if (res === null || res.length < 2 || res.length > 40) { + return null; + } + if (dec.data[0] === 0 && res.length !== 20 && res.length !== 32) { + return null; + } + if (dec.data[0] === 0 && bech32m) { + return null; + } + if (dec.data[0] !== 0 && !bech32m) { + return null; + } + return {version: dec.data[0], program: res}; + } + + segwit_addr.decode = segwit_addr_decode; + + function segwit_addr_encode (hrp, version, program) { + var enc = bech32.encodings.BECH32; + if (version > 0) { + enc = bech32.encodings.BECH32M; + } + var ret = bech32.encode(hrp, [version].concat(convertbits(program, 8, 5, true)), enc); + if (segwit_addr_decode(hrp, ret) === null) { + return null; + } + return ret; + } + + segwit_addr.encode = segwit_addr_encode; + + + function isTaprootAddress(address) { + try { + const taprootDecoded = segwit_addr.decode("bc", address); + return taprootDecoded !== null && taprootDecoded.version === 1; + } catch (error) { + return false; + } + } + + segwit_addr.isTaprootAddress = isTaprootAddress; + +} )(); + //secrets.js (function () { //Shamir Secret Share by Alexander Stetsyuk - released under MIT License @@ -9972,4 +10223,4 @@ } })(); -})(typeof global !== "undefined" ? global : window); \ No newline at end of file +})(typeof global !== "undefined" ? global : window); From 6c2c53e47c16912456474d377b05b94bfc1fb86c Mon Sep 17 00:00:00 2001 From: tripathyr Date: Tue, 8 Aug 2023 15:58:56 +0530 Subject: [PATCH 2/6] Fixing variable scope issue in Taproot validation Created GLOBAL.bech32 and GLOBAL.segwit_addr to expose these functions --- scripts/lib.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/lib.js b/scripts/lib.js index 974342f..6781c0f 100644 --- a/scripts/lib.js +++ b/scripts/lib.js @@ -9237,11 +9237,13 @@ - var bech32={}; - var segwit_addr = {}; + (function(){ + var bech32 = GLOBAL.bech32 = {}; + var segwit_addr = GLOBAL.segwit_addr = {}; + var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; From adca3623fd7a4f537060b6aa2d11c25cc257eda9 Mon Sep 17 00:00:00 2001 From: tripathyr Date: Tue, 8 Aug 2023 16:25:35 +0530 Subject: [PATCH 3/6] Position change of Taproot functions --- scripts/lib.js | 504 ++++++++++++++++++++++++------------------------- 1 file changed, 251 insertions(+), 253 deletions(-) diff --git a/scripts/lib.js b/scripts/lib.js index 6781c0f..040ae1e 100644 --- a/scripts/lib.js +++ b/scripts/lib.js @@ -6614,6 +6614,257 @@ }; })(); + /* Peter Wuille Taproot Address Validation Functions */ + + // Copyright (c) 2017, 2021 Pieter Wuille + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in + // all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + // THE SOFTWARE. + + (function(){ + + var bech32 = GLOBAL.bech32 = {}; + var segwit_addr = GLOBAL.segwit_addr = {}; + + var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; + var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; + + const encodings = { + BECH32: "bech32", + BECH32M: "bech32m", + }; + + + function getEncodingConst (enc) { + if (enc == bech32.encodings.BECH32) { + return 1; + } else if (enc == bech32.encodings.BECH32M) { + return 0x2bc830a3; + } else { + return null; + } + } + + function polymod (values) { + var chk = 1; + for (var p = 0; p < values.length; ++p) { + var top = chk >> 25; + chk = (chk & 0x1ffffff) << 5 ^ values[p]; + for (var i = 0; i < 5; ++i) { + if ((top >> i) & 1) { + chk ^= GENERATOR[i]; + } + } + } + return chk; + } + + function hrpExpand (hrp) { + var ret = []; + var p; + for (p = 0; p < hrp.length; ++p) { + ret.push(hrp.charCodeAt(p) >> 5); + } + ret.push(0); + for (p = 0; p < hrp.length; ++p) { + ret.push(hrp.charCodeAt(p) & 31); + } + return ret; + } + + function verifyChecksum (hrp, data, enc) { + return polymod(hrpExpand(hrp).concat(data)) === getEncodingConst(enc); + } + + function createChecksum (hrp, data, enc) { + var values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]); + var mod = polymod(values) ^ getEncodingConst(enc); + var ret = []; + for (var p = 0; p < 6; ++p) { + ret.push((mod >> 5 * (5 - p)) & 31); + } + return ret; + } + + function bech32_encode (hrp, data, enc) { + var combined = data.concat(createChecksum(hrp, data, enc)); + var ret = hrp + '1'; + for (var p = 0; p < combined.length; ++p) { + ret += CHARSET.charAt(combined[p]); + } + return ret; + } + + function bech32_decode (bechString, enc) { + var p; + var has_lower = false; + var has_upper = false; + for (p = 0; p < bechString.length; ++p) { + if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) { + return null; + } + if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) { + has_lower = true; + } + if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) { + has_upper = true; + } + } + if (has_lower && has_upper) { + return null; + } + bechString = bechString.toLowerCase(); + var pos = bechString.lastIndexOf('1'); + if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) { + return null; + } + var hrp = bechString.substring(0, pos); + var data = []; + for (p = pos + 1; p < bechString.length; ++p) { + var d = CHARSET.indexOf(bechString.charAt(p)); + if (d === -1) { + return null; + } + data.push(d); + } + if (!verifyChecksum(hrp, data, enc)) { + return null; + } + return {hrp: hrp, data: data.slice(0, data.length - 6)}; + } + + bech32.encodings = encodings; + bech32.encode = bech32_encode; + bech32.decode = bech32_decode; + + // SIPA SEGWIT_ADDR.JS + + // Copyright (c) 2017, 2021 Pieter Wuille + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in + // all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + // THE SOFTWARE. + + + + + + function convertbits (data, frombits, tobits, pad) { + var acc = 0; + var bits = 0; + var ret = []; + var maxv = (1 << tobits) - 1; + for (var p = 0; p < data.length; ++p) { + var value = data[p]; + if (value < 0 || (value >> frombits) !== 0) { + return null; + } + acc = (acc << frombits) | value; + bits += frombits; + while (bits >= tobits) { + bits -= tobits; + ret.push((acc >> bits) & maxv); + } + } + if (pad) { + if (bits > 0) { + ret.push((acc << (tobits - bits)) & maxv); + } + } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) { + return null; + } + return ret; + } + + segwit_addr.convertbits = convertbits; + + function segwit_addr_decode (hrp, addr) { + var bech32m = false; + var dec = bech32.decode(addr, bech32.encodings.BECH32); + if (dec === null) { + dec = bech32.decode(addr, bech32.encodings.BECH32M); + bech32m = true; + } + if (dec === null || dec.hrp !== hrp || dec.data.length < 1 || dec.data[0] > 16) { + return null; + } + var res = convertbits(dec.data.slice(1), 5, 8, false); + if (res === null || res.length < 2 || res.length > 40) { + return null; + } + if (dec.data[0] === 0 && res.length !== 20 && res.length !== 32) { + return null; + } + if (dec.data[0] === 0 && bech32m) { + return null; + } + if (dec.data[0] !== 0 && !bech32m) { + return null; + } + return {version: dec.data[0], program: res}; + } + + segwit_addr.decode = segwit_addr_decode; + + function segwit_addr_encode (hrp, version, program) { + var enc = bech32.encodings.BECH32; + if (version > 0) { + enc = bech32.encodings.BECH32M; + } + var ret = bech32.encode(hrp, [version].concat(convertbits(program, 8, 5, true)), enc); + if (segwit_addr_decode(hrp, ret) === null) { + return null; + } + return ret; + } + + segwit_addr.encode = segwit_addr_encode; + + + function isTaprootAddress(address) { + try { + const taprootDecoded = segwit_addr.decode("bc", address); + return taprootDecoded !== null && taprootDecoded.version === 1; + } catch (error) { + return false; + } + } + + segwit_addr.isTaprootAddress = isTaprootAddress; + +} )(); + + + //coin.js (function () { /* @@ -9213,259 +9464,6 @@ })(); - /* Peter Wuille Taproot Address Validation Functions */ - - // Copyright (c) 2017, 2021 Pieter Wuille - // - // Permission is hereby granted, free of charge, to any person obtaining a copy - // of this software and associated documentation files (the "Software"), to deal - // in the Software without restriction, including without limitation the rights - // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - // copies of the Software, and to permit persons to whom the Software is - // furnished to do so, subject to the following conditions: - // - // The above copyright notice and this permission notice shall be included in - // all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - // THE SOFTWARE. - - - - - - (function(){ - - var bech32 = GLOBAL.bech32 = {}; - var segwit_addr = GLOBAL.segwit_addr = {}; - - var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; - var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; - - const encodings = { - BECH32: "bech32", - BECH32M: "bech32m", - }; - - - function getEncodingConst (enc) { - if (enc == bech32.encodings.BECH32) { - return 1; - } else if (enc == bech32.encodings.BECH32M) { - return 0x2bc830a3; - } else { - return null; - } - } - - function polymod (values) { - var chk = 1; - for (var p = 0; p < values.length; ++p) { - var top = chk >> 25; - chk = (chk & 0x1ffffff) << 5 ^ values[p]; - for (var i = 0; i < 5; ++i) { - if ((top >> i) & 1) { - chk ^= GENERATOR[i]; - } - } - } - return chk; - } - - function hrpExpand (hrp) { - var ret = []; - var p; - for (p = 0; p < hrp.length; ++p) { - ret.push(hrp.charCodeAt(p) >> 5); - } - ret.push(0); - for (p = 0; p < hrp.length; ++p) { - ret.push(hrp.charCodeAt(p) & 31); - } - return ret; - } - - function verifyChecksum (hrp, data, enc) { - return polymod(hrpExpand(hrp).concat(data)) === getEncodingConst(enc); - } - - function createChecksum (hrp, data, enc) { - var values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]); - var mod = polymod(values) ^ getEncodingConst(enc); - var ret = []; - for (var p = 0; p < 6; ++p) { - ret.push((mod >> 5 * (5 - p)) & 31); - } - return ret; - } - - function bech32_encode (hrp, data, enc) { - var combined = data.concat(createChecksum(hrp, data, enc)); - var ret = hrp + '1'; - for (var p = 0; p < combined.length; ++p) { - ret += CHARSET.charAt(combined[p]); - } - return ret; - } - - function bech32_decode (bechString, enc) { - var p; - var has_lower = false; - var has_upper = false; - for (p = 0; p < bechString.length; ++p) { - if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) { - return null; - } - if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) { - has_lower = true; - } - if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) { - has_upper = true; - } - } - if (has_lower && has_upper) { - return null; - } - bechString = bechString.toLowerCase(); - var pos = bechString.lastIndexOf('1'); - if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) { - return null; - } - var hrp = bechString.substring(0, pos); - var data = []; - for (p = pos + 1; p < bechString.length; ++p) { - var d = CHARSET.indexOf(bechString.charAt(p)); - if (d === -1) { - return null; - } - data.push(d); - } - if (!verifyChecksum(hrp, data, enc)) { - return null; - } - return {hrp: hrp, data: data.slice(0, data.length - 6)}; - } - - bech32.encodings = encodings; - bech32.encode = bech32_encode; - bech32.decode = bech32_decode; - - // SIPA SEGWIT_ADDR.JS - - // Copyright (c) 2017, 2021 Pieter Wuille - // - // Permission is hereby granted, free of charge, to any person obtaining a copy - // of this software and associated documentation files (the "Software"), to deal - // in the Software without restriction, including without limitation the rights - // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - // copies of the Software, and to permit persons to whom the Software is - // furnished to do so, subject to the following conditions: - // - // The above copyright notice and this permission notice shall be included in - // all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - // THE SOFTWARE. - - - - - - function convertbits (data, frombits, tobits, pad) { - var acc = 0; - var bits = 0; - var ret = []; - var maxv = (1 << tobits) - 1; - for (var p = 0; p < data.length; ++p) { - var value = data[p]; - if (value < 0 || (value >> frombits) !== 0) { - return null; - } - acc = (acc << frombits) | value; - bits += frombits; - while (bits >= tobits) { - bits -= tobits; - ret.push((acc >> bits) & maxv); - } - } - if (pad) { - if (bits > 0) { - ret.push((acc << (tobits - bits)) & maxv); - } - } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) { - return null; - } - return ret; - } - - segwit_addr.convertbits = convertbits; - - function segwit_addr_decode (hrp, addr) { - var bech32m = false; - var dec = bech32.decode(addr, bech32.encodings.BECH32); - if (dec === null) { - dec = bech32.decode(addr, bech32.encodings.BECH32M); - bech32m = true; - } - if (dec === null || dec.hrp !== hrp || dec.data.length < 1 || dec.data[0] > 16) { - return null; - } - var res = convertbits(dec.data.slice(1), 5, 8, false); - if (res === null || res.length < 2 || res.length > 40) { - return null; - } - if (dec.data[0] === 0 && res.length !== 20 && res.length !== 32) { - return null; - } - if (dec.data[0] === 0 && bech32m) { - return null; - } - if (dec.data[0] !== 0 && !bech32m) { - return null; - } - return {version: dec.data[0], program: res}; - } - - segwit_addr.decode = segwit_addr_decode; - - function segwit_addr_encode (hrp, version, program) { - var enc = bech32.encodings.BECH32; - if (version > 0) { - enc = bech32.encodings.BECH32M; - } - var ret = bech32.encode(hrp, [version].concat(convertbits(program, 8, 5, true)), enc); - if (segwit_addr_decode(hrp, ret) === null) { - return null; - } - return ret; - } - - segwit_addr.encode = segwit_addr_encode; - - - function isTaprootAddress(address) { - try { - const taprootDecoded = segwit_addr.decode("bc", address); - return taprootDecoded !== null && taprootDecoded.version === 1; - } catch (error) { - return false; - } - } - - segwit_addr.isTaprootAddress = isTaprootAddress; - -} )(); - //secrets.js (function () { //Shamir Secret Share by Alexander Stetsyuk - released under MIT License From 1a74ca0f4dd297d5064628db8c5efb82eb7b9728 Mon Sep 17 00:00:00 2001 From: tripathyr Date: Tue, 8 Aug 2023 16:47:06 +0530 Subject: [PATCH 4/6] Taproot Address Decoding Added --- scripts/lib.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/lib.js b/scripts/lib.js index 040ae1e..7823282 100644 --- a/scripts/lib.js +++ b/scripts/lib.js @@ -7226,6 +7226,15 @@ /* decode or validate an address and return the hash */ coinjs.addressDecode = function (addr) { try { + //Addition of Taproot check before other checks + if (segwit_addr.isTaprootAddress(addr)){ + var data = segwit_addr.decode("bc",addr); + data.type = "bech32m"; + data.outstring = "5120" + Crypto.util.bytesToHex(data.program); + return data; + } + + //Resuming regular checks var bytes = coinjs.base58decode(addr); var front = bytes.slice(0, bytes.length - 4); var back = bytes.slice(bytes.length - 4); From b7d102ec1282fd4d73b5f65d4cacef6880be3680 Mon Sep 17 00:00:00 2001 From: tripathyr Date: Tue, 8 Aug 2023 18:32:09 +0530 Subject: [PATCH 5/6] Taproot Outputs spend capacity --- scripts/btcOperator.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/btcOperator.js b/scripts/btcOperator.js index 2abb80f..0d54c23 100644 --- a/scripts/btcOperator.js +++ b/scripts/btcOperator.js @@ -92,6 +92,9 @@ }, bech32Address: { value: key => coinjs.bech32Address(btcOperator.pubkey(key)).address + }, + bech32mAddress: { + value: key => segwit_addr.encode("bc",1,key) } }); @@ -107,6 +110,8 @@ return btcOperator.segwitAddress(key) === addr; case "bech32": return btcOperator.bech32Address(key) === addr; + case "bech32m": + return btcOperator.bech32mAddress(key) === addr; // Key is a byte array of 32 bytes default: return null; } @@ -116,7 +121,7 @@ if (!addr) return undefined; let type = coinjs.addressDecode(addr).type; - if (["standard", "multisig", "bech32", "multisigBech32"].includes(type)) + if (["standard", "multisig", "bech32", "multisigBech32","bech32m"].includes(type)) return type; else return false; @@ -281,6 +286,7 @@ BECH32_OUTPUT_SIZE = 23, BECH32_MULTISIG_OUTPUT_SIZE = 34, SEGWIT_OUTPUT_SIZE = 23; + BECH32M_OUTPUT_SIZE = 35; // Check this later function _redeemScript(addr, key) { let decode = coinjs.addressDecode(addr); @@ -291,6 +297,8 @@ return key ? coinjs.segwitAddress(btcOperator.pubkey(key)).redeemscript : null; case "bech32": return decode.redeemscript; + case "bech32m": + return decode.outstring; //Maybe the redeemscript will come when input processing happens for bech32m default: return null; } @@ -328,6 +336,8 @@ return BASE_OUTPUT_SIZE + BECH32_MULTISIG_OUTPUT_SIZE; case "multisig": return BASE_OUTPUT_SIZE + SEGWIT_OUTPUT_SIZE; + case "bech32m": + return BASE_OUTPUT_SIZE + BECH32M_OUTPUT_SIZE; default: return null; } From 538075877501a4b11f90c0c52a1a855320eaa45a Mon Sep 17 00:00:00 2001 From: tripathyr Date: Tue, 8 Aug 2023 18:33:47 +0530 Subject: [PATCH 6/6] SpendScript Taproot output enhancement --- scripts/lib.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/lib.js b/scripts/lib.js index 7823282..042c730 100644 --- a/scripts/lib.js +++ b/scripts/lib.js @@ -7965,6 +7965,13 @@ r.spendToScript = function (address) { var addr = coinjs.addressDecode(address); var s = coinjs.script(); + + //Adding Taproot output writing + if (addr.type == "bech32m") { + s.writeBytes(Crypto.util.hexToBytes(addr.outstring)); + return s; + } + if (addr.type == "bech32" || addr.type == "multisigBech32") { s.writeOp(0); s.writeBytes(Crypto.util.hexToBytes(addr.redeemscript));