From 5c203fab6ac25fc76e2b805b7709d9b06ccdd995 Mon Sep 17 00:00:00 2001 From: Ian Coleman Date: Mon, 16 Dec 2019 13:08:28 +1100 Subject: [PATCH] Add P2WSH and P2WSH-P2SH for bitcoin and testnet Address generation still to come. --- src/index.html | 2 + src/js/index.js | 56 ++++++++++++++++++++++ src/js/segwit-parameters.js | 56 ++++++++++++++++++++++ tests/spec/tests.js | 96 +++++++++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+) diff --git a/src/index.html b/src/index.html index 36e238f..61fe022 100644 --- a/src/index.html +++ b/src/index.html @@ -509,6 +509,8 @@ diff --git a/src/js/index.js b/src/js/index.js index 0b34ade..db47412 100644 --- a/src/js/index.js +++ b/src/js/index.js @@ -539,6 +539,22 @@ } catch (e) {} } + // try parsing using p2wsh network params + if ("p2wsh" in n) { + try { + bip32RootKey = bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, n.p2wsh); + return; + } + catch (e) {} + } + // try parsing using p2wsh-in-p2sh network params + if ("p2wshInP2sh" in n) { + try { + bip32RootKey = bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, n.p2wshInP2sh); + return; + } + catch (e) {} + } } // try the network params as currently specified bip32RootKey = bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, network); @@ -681,6 +697,22 @@ } catch (e) {} } + // try parsing using p2wsh network params + if ("p2wsh" in n) { + try { + bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, n.p2wsh); + return ""; + } + catch (e) {} + } + // try parsing using p2wsh-in-p2sh network params + if ("p2wshInP2sh" in n) { + try { + bitcoinjs.bitcoin.HDNode.fromBase58(rootKeyBase58, n.p2wshInP2sh); + return ""; + } + catch (e) {} + } } // try the network params as currently specified try { @@ -968,6 +1000,14 @@ (bip141TabSelected() && DOM.bip141semantics.val() == "p2wpkh-p2sh"); } + function p2wshSelected() { + return bip141TabSelected() && DOM.bip141semantics.val() == "p2wsh"; + } + + function p2wshInP2shSelected() { + return (bip141TabSelected() && DOM.bip141semantics.val() == "p2wsh-p2sh"); + } + function TableRow(index, isLast) { var self = this; @@ -979,6 +1019,8 @@ var segwitAvailable = networkHasSegwit(); var isP2wpkh = p2wpkhSelected(); var isP2wpkhInP2sh = p2wpkhInP2shSelected(); + var isP2wsh = p2wshSelected(); + var isP2wshInP2sh = p2wshInP2shSelected(); function init() { calculateValues(); @@ -1109,6 +1151,14 @@ var scriptpubkey = bitcoinjs.bitcoin.script.scriptHash.output.encode(addressbytes); address = bitcoinjs.bitcoin.address.fromOutputScript(scriptpubkey, network) } + else if (isP2wsh) { + // TODO + address = ""; + } + else if (isP2wshInP2sh) { + // TODO + address = ""; + } } if ((networks[DOM.network.val()].name == "CRW - Crown")) { @@ -1794,6 +1844,12 @@ else if (p2wpkhInP2shSelected() && "p2wpkhInP2sh" in network) { network = network.p2wpkhInP2sh; } + else if (p2wshSelected() && "p2wsh" in network) { + network = network.p2wsh; + } + else if (p2wshInP2shSelected() && "p2wshInP2sh" in network) { + network = network.p2wshInP2sh; + } } function lastIndexInTable() { diff --git a/src/js/segwit-parameters.js b/src/js/segwit-parameters.js index de4d634..83d49da 100644 --- a/src/js/segwit-parameters.js +++ b/src/js/segwit-parameters.js @@ -56,6 +56,62 @@ bitcoinjs.bitcoin.networks.testnet.p2wpkhInP2sh = { wif: 0xef }; +// p2wsh + +bitcoinjs.bitcoin.networks.bitcoin.p2wsh = { + baseNetwork: "bitcoin", + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bc', + bip32: { + public: 0x02aa7ed3, + private: 0x02aa7a99 + }, + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80 +}; + +bitcoinjs.bitcoin.networks.testnet.p2wsh = { + baseNetwork: "testnet", + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'tb', + bip32: { + public: 0x02575483, + private: 0x02575048 + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef +}; + +// p2wsh in p2sh + +bitcoinjs.bitcoin.networks.bitcoin.p2wshInP2sh = { + baseNetwork: "bitcoin", + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bc', + bip32: { + public: 0x0295b43f, + private: 0x0295b005 + }, + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80 +}; + +bitcoinjs.bitcoin.networks.testnet.p2wshInP2sh = { + baseNetwork: "testnet", + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'tb', + bip32: { + public: 0x024289ef, + private: 0x024285b5 + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef +}; + bitcoinjs.bitcoin.networks.litecoin.p2wpkh = { baseNetwork: "litecoin", messagePrefix: '\x19Litecoin Signed Message:\n', diff --git a/tests/spec/tests.js b/tests/spec/tests.js index af8944c..fc71353 100644 --- a/tests/spec/tests.js +++ b/tests/spec/tests.js @@ -3694,6 +3694,102 @@ it('Can generate BIP141 addresses with P2WPKH-in-P2SH semanitcs', function(done) }); }); +it('Can generate BIP141 addresses with P2WSH semanitcs', function(done) { + driver.findElement(By.css('#bip141-tab a')) + .click(); + // Choose P2WSH + driver.executeScript(function() { + $(".bip141-semantics option[selected]").removeAttr("selected"); + $(".bip141-semantics option").filter(function(i,e) { + return $(e).html() == "P2WSH"; + }).prop("selected", true); + $(".bip141-semantics").trigger("change"); + }); + driver.findElement(By.css(".phrase")) + .sendKeys("abandon abandon ability"); + driver.sleep(generateDelay).then(function() { + driver.findElement(By.css("#root-key")) + .getAttribute("value") + .then(function(rootKey) { + expect(rootKey).toBe("ZprvAhadJRUYsNge9uHspaggavxU1BUQ8QwfT4Z9UGq5sKF2mSt1mVy8EckLAaoBdmLHyP5eYDJ3LxtmzMNnLg2MRFe7QN2ueF4NCH4s5PrCDR6"); + // TODO check first address + done(); + }) + }); +}); + +it('Can generate BIP141 addresses with P2WSH-in-P2SH semanitcs', function(done) { + driver.findElement(By.css('#bip141-tab a')) + .click(); + // Choose P2WSH-in-P2SH + driver.executeScript(function() { + $(".bip141-semantics option[selected]").removeAttr("selected"); + $(".bip141-semantics option").filter(function(i,e) { + return $(e).html() == "P2WSH nested in P2SH"; + }).prop("selected", true); + $(".bip141-semantics").trigger("change"); + }); + driver.findElement(By.css(".phrase")) + .sendKeys("abandon abandon ability"); + driver.sleep(generateDelay).then(function() { + driver.findElement(By.css("#root-key")) + .getAttribute("value") + .then(function(rootKey) { + expect(rootKey).toBe("YprvANkMzkodih9AJc6kzDu4NqrxqDKxBnxAXx2vgswCVJs9iM4nWqoZcZ6C9NqbdrgNZjxqnjhUtJYE74mDcycLd1xWY2LV4LEsvZ1DgqxuAKe"); + // TODO check first address + done(); + }) + }); +}); + +it('Uses Vprv for bitcoin testnet p2wsh', function(done) { + selectNetwork("BTC - Bitcoin Testnet"); + driver.findElement(By.css('#bip141-tab a')) + .click() + // Choose P2WSH + driver.executeScript(function() { + $(".bip141-semantics option[selected]").removeAttr("selected"); + $(".bip141-semantics option").filter(function(i,e) { + return $(e).html() == "P2WSH"; + }).prop("selected", true); + $(".bip141-semantics").trigger("change"); + }); + driver.findElement(By.css('.phrase')) + .sendKeys('abandon abandon ability'); + driver.sleep(generateDelay).then(function() { + driver.findElement(By.css('.root-key')) + .getAttribute("value") + .then(function(path) { + expect(path).toBe("Vprv16YtLrHXxePM5ja5hXQbiJs5JKDAc4WcaXo5rZcrVMU6bMhUg1oY7fpPku3i819gvMcHvq1h8aELDsyfCEs19vj1Q3iDHRrESWyJConkoT1"); + done(); + }) + }); +}); + +it('Uses Uprv for bitcoin testnet p2wsh-in-p2sh', function(done) { + selectNetwork("BTC - Bitcoin Testnet"); + driver.findElement(By.css('#bip141-tab a')) + .click() + // Choose P2WSH-in-P2SH + driver.executeScript(function() { + $(".bip141-semantics option[selected]").removeAttr("selected"); + $(".bip141-semantics option").filter(function(i,e) { + return $(e).html() == "P2WSH nested in P2SH"; + }).prop("selected", true); + $(".bip141-semantics").trigger("change"); + }); + driver.findElement(By.css('.phrase')) + .sendKeys('abandon abandon ability'); + driver.sleep(generateDelay).then(function() { + driver.findElement(By.css('.root-key')) + .getAttribute("value") + .then(function(path) { + expect(path).toBe("Uprv95RJn67y7xyEuRLHenkZYVUx9LkARJzAsVx3ZJMeyHMdVwosWD9K8JTe4Z1FeE4gwBVcnqKF3f82ZvJxkBxHS5E74fYnigxvqeke8ZV3Fp2"); + done(); + }) + }); +}); + it('Can generate BIP141 addresses with P2WPKH semanitcs', function(done) { // This result tested against bitcoinjs-lib test spec for segwit address // using the first private key of this mnemonic and default path m/0 -- 2.41.0