diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/index.html | 41 | ||||
-rw-r--r-- | src/js/bitcoinjs-extensions.js | 33 | ||||
-rw-r--r-- | src/js/index.js | 88 | ||||
-rw-r--r-- | src/js/segwit-parameters.js | 58 |
4 files changed, 158 insertions, 62 deletions
diff --git a/src/index.html b/src/index.html index b638b26..0126bef 100644 --- a/src/index.html +++ b/src/index.html | |||
@@ -301,6 +301,9 @@ | |||
301 | <li id="bip49-tab"> | 301 | <li id="bip49-tab"> |
302 | <a href="#bip49" role="tab" data-toggle="tab">BIP49</a> | 302 | <a href="#bip49" role="tab" data-toggle="tab">BIP49</a> |
303 | </li> | 303 | </li> |
304 | <li id="bip141-tab"> | ||
305 | <a href="#bip141" role="tab" data-toggle="tab">BIP141</a> | ||
306 | </li> | ||
304 | </ul> | 307 | </ul> |
305 | <div class="derivation-type tab-content"> | 308 | <div class="derivation-type tab-content"> |
306 | <div id="bip44" class="tab-pane active"> | 309 | <div id="bip44" class="tab-pane active"> |
@@ -544,6 +547,43 @@ | |||
544 | </div> | 547 | </div> |
545 | </form> | 548 | </form> |
546 | </div> | 549 | </div> |
550 | <div id="bip141" class="tab-pane"> | ||
551 | <form class="form-horizontal" role="form"> | ||
552 | <br> | ||
553 | <div class="unavailable hidden"> | ||
554 | <div class="form-group"> | ||
555 | <div class="col-sm-2"></div> | ||
556 | <div class="col-sm-10"> | ||
557 | <p>BIP141 is unavailable for this coin.</p> | ||
558 | </div> | ||
559 | </div> | ||
560 | </div> | ||
561 | <div class="available"> | ||
562 | <div class="col-sm-2"></div> | ||
563 | <div class="col-sm-10"> | ||
564 | <p> | ||
565 | For more info see the | ||
566 | <a href="https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki" target="_blank">BIP141 spec</a> | ||
567 | </p> | ||
568 | </div> | ||
569 | <div class="form-group"> | ||
570 | <label for="bip141-path" class="col-sm-2 control-label">BIP32 Derivation Path</label> | ||
571 | <div class="col-sm-10"> | ||
572 | <input id="bip141-path" type="text" class="bip141-path form-control" value="m/0"> | ||
573 | </div> | ||
574 | </div> | ||
575 | <div class="form-group"> | ||
576 | <label class="col-sm-2 control-label">Script Semantics</label> | ||
577 | <div class="col-sm-10"> | ||
578 | <select class="form-control bip141-semantics"> | ||
579 | <option value="p2wpkh">P2WPKH</option> | ||
580 | <option value="p2wpkh-p2sh" selected>P2WPKH nested in P2SH</option> | ||
581 | </select> | ||
582 | </div> | ||
583 | </div> | ||
584 | </div> | ||
585 | </form> | ||
586 | </div> | ||
547 | </div> | 587 | </div> |
548 | <form class="form-horizontal" role="form"> | 588 | <form class="form-horizontal" role="form"> |
549 | <div class="form-group"> | 589 | <div class="form-group"> |
@@ -830,6 +870,7 @@ | |||
830 | <script src="js/jquery.qrcode.min.js"></script> | 870 | <script src="js/jquery.qrcode.min.js"></script> |
831 | <script src="js/bitcoinjs-3.3.0.js"></script> | 871 | <script src="js/bitcoinjs-3.3.0.js"></script> |
832 | <script src="js/bitcoinjs-extensions.js"></script> | 872 | <script src="js/bitcoinjs-extensions.js"></script> |
873 | <script src="js/segwit-parameters.js"></script> | ||
833 | <script src="js/ethereumjs-util.js"></script> | 874 | <script src="js/ethereumjs-util.js"></script> |
834 | <script src="js/ripple-util.js"></script> | 875 | <script src="js/ripple-util.js"></script> |
835 | <script src="js/sjcl-bip39.js"></script> | 876 | <script src="js/sjcl-bip39.js"></script> |
diff --git a/src/js/bitcoinjs-extensions.js b/src/js/bitcoinjs-extensions.js index 63f7c6e..1509a6c 100644 --- a/src/js/bitcoinjs-extensions.js +++ b/src/js/bitcoinjs-extensions.js | |||
@@ -284,39 +284,6 @@ bitcoinjs.bitcoin.networks.monacoin = { | |||
284 | wif: 0xb0 | 284 | wif: 0xb0 |
285 | }; | 285 | }; |
286 | 286 | ||
287 | bitcoinjs.bitcoin.networks.bitcoinBip49 = { | ||
288 | messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
289 | bip32: { | ||
290 | public: 0x049d7cb2, | ||
291 | private: 0x049d7878 | ||
292 | }, | ||
293 | pubKeyHash: 0x00, | ||
294 | scriptHash: 0x05, | ||
295 | wif: 0x80 | ||
296 | }; | ||
297 | |||
298 | bitcoinjs.bitcoin.networks.testnetBip49 = { | ||
299 | messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
300 | bip32: { | ||
301 | public: 0x044a5262, | ||
302 | private: 0x044a4e28 | ||
303 | }, | ||
304 | pubKeyHash: 0x6f, | ||
305 | scriptHash: 0xc4, | ||
306 | wif: 0xef | ||
307 | }; | ||
308 | |||
309 | bitcoinjs.bitcoin.networks.litecoinBip49 = { | ||
310 | messagePrefix: '\x19Litecoin Signed Message:\n', | ||
311 | bip32: { | ||
312 | public: 0x01b26ef6, | ||
313 | private: 0x01b26792 | ||
314 | }, | ||
315 | pubKeyHash: 0x30, | ||
316 | scriptHash: 0x32, | ||
317 | wif: 0xb0 | ||
318 | }; | ||
319 | |||
320 | bitcoinjs.bitcoin.networks.litecoinXprv = { | 287 | bitcoinjs.bitcoin.networks.litecoinXprv = { |
321 | messagePrefix: '\x19Litecoin Signed Message:\n', | 288 | messagePrefix: '\x19Litecoin Signed Message:\n', |
322 | bip32: { | 289 | bip32: { |
diff --git a/src/js/index.js b/src/js/index.js index b88e9d7..261a6d1 100644 --- a/src/js/index.js +++ b/src/js/index.js | |||
@@ -52,6 +52,7 @@ | |||
52 | DOM.bip32tab = $("#bip32-tab"); | 52 | DOM.bip32tab = $("#bip32-tab"); |
53 | DOM.bip44tab = $("#bip44-tab"); | 53 | DOM.bip44tab = $("#bip44-tab"); |
54 | DOM.bip49tab = $("#bip49-tab"); | 54 | DOM.bip49tab = $("#bip49-tab"); |
55 | DOM.bip141tab = $("#bip141-tab"); | ||
55 | DOM.bip32panel = $("#bip32"); | 56 | DOM.bip32panel = $("#bip32"); |
56 | DOM.bip44panel = $("#bip44"); | 57 | DOM.bip44panel = $("#bip44"); |
57 | DOM.bip49panel = $("#bip49"); | 58 | DOM.bip49panel = $("#bip49"); |
@@ -72,6 +73,10 @@ | |||
72 | DOM.bip49accountXprv = $("#bip49 .account-xprv"); | 73 | DOM.bip49accountXprv = $("#bip49 .account-xprv"); |
73 | DOM.bip49accountXpub = $("#bip49 .account-xpub"); | 74 | DOM.bip49accountXpub = $("#bip49 .account-xpub"); |
74 | DOM.bip49change = $("#bip49 .change"); | 75 | DOM.bip49change = $("#bip49 .change"); |
76 | DOM.bip141unavailable = $("#bip141 .unavailable"); | ||
77 | DOM.bip141available = $("#bip141 .available"); | ||
78 | DOM.bip141path = $("#bip141-path"); | ||
79 | DOM.bip141semantics = $(".bip141-semantics"); | ||
75 | DOM.generatedStrength = $(".generate-container .strength"); | 80 | DOM.generatedStrength = $(".generate-container .strength"); |
76 | DOM.hardenedAddresses = $(".hardened-addresses"); | 81 | DOM.hardenedAddresses = $(".hardened-addresses"); |
77 | DOM.useBitpayAddressesContainer = $(".use-bitpay-addresses-container"); | 82 | DOM.useBitpayAddressesContainer = $(".use-bitpay-addresses-container"); |
@@ -111,6 +116,8 @@ | |||
111 | DOM.bip44change.on("input", calcForDerivationPath); | 116 | DOM.bip44change.on("input", calcForDerivationPath); |
112 | DOM.bip49account.on("input", calcForDerivationPath); | 117 | DOM.bip49account.on("input", calcForDerivationPath); |
113 | DOM.bip49change.on("input", calcForDerivationPath); | 118 | DOM.bip49change.on("input", calcForDerivationPath); |
119 | DOM.bip141path.on("input", calcForDerivationPath); | ||
120 | DOM.bip141semantics.on("change", tabChanged); | ||
114 | DOM.tab.on("shown.bs.tab", tabChanged); | 121 | DOM.tab.on("shown.bs.tab", tabChanged); |
115 | DOM.hardenedAddresses.on("change", calcForDerivationPath); | 122 | DOM.hardenedAddresses.on("change", calcForDerivationPath); |
116 | DOM.indexToggle.on("click", toggleIndexes); | 123 | DOM.indexToggle.on("click", toggleIndexes); |
@@ -138,6 +145,7 @@ | |||
138 | var network = networks[networkIndex]; | 145 | var network = networks[networkIndex]; |
139 | network.onSelect(); | 146 | network.onSelect(); |
140 | if (network.segwitAvailable) { | 147 | if (network.segwitAvailable) { |
148 | adjustNetworkForSegwit(); | ||
141 | showSegwitAvailable(); | 149 | showSegwitAvailable(); |
142 | } | 150 | } |
143 | else { | 151 | else { |
@@ -343,7 +351,7 @@ | |||
343 | if (bip44TabSelected()) { | 351 | if (bip44TabSelected()) { |
344 | displayBip44Info(); | 352 | displayBip44Info(); |
345 | } | 353 | } |
346 | if (bip49TabSelected()) { | 354 | else if (bip49TabSelected()) { |
347 | displayBip49Info(); | 355 | displayBip49Info(); |
348 | } | 356 | } |
349 | displayBip32Info(); | 357 | displayBip32Info(); |
@@ -523,7 +531,7 @@ | |||
523 | console.log("Using derivation path from BIP44 tab: " + derivationPath); | 531 | console.log("Using derivation path from BIP44 tab: " + derivationPath); |
524 | return derivationPath; | 532 | return derivationPath; |
525 | } | 533 | } |
526 | if (bip49TabSelected()) { | 534 | else if (bip49TabSelected()) { |
527 | var purpose = parseIntNoNaN(DOM.bip49purpose.val(), 49); | 535 | var purpose = parseIntNoNaN(DOM.bip49purpose.val(), 49); |
528 | var coin = parseIntNoNaN(DOM.bip49coin.val(), 0); | 536 | var coin = parseIntNoNaN(DOM.bip49coin.val(), 0); |
529 | var account = parseIntNoNaN(DOM.bip49account.val(), 0); | 537 | var account = parseIntNoNaN(DOM.bip49account.val(), 0); |
@@ -543,6 +551,11 @@ | |||
543 | console.log("Using derivation path from BIP32 tab: " + derivationPath); | 551 | console.log("Using derivation path from BIP32 tab: " + derivationPath); |
544 | return derivationPath; | 552 | return derivationPath; |
545 | } | 553 | } |
554 | else if (bip141TabSelected()) { | ||
555 | var derivationPath = DOM.bip141path.val(); | ||
556 | console.log("Using derivation path from BIP141 tab: " + derivationPath); | ||
557 | return derivationPath; | ||
558 | } | ||
546 | else { | 559 | else { |
547 | console.log("Unknown derivation path"); | 560 | console.log("Unknown derivation path"); |
548 | } | 561 | } |
@@ -673,7 +686,16 @@ | |||
673 | } | 686 | } |
674 | 687 | ||
675 | function segwitSelected() { | 688 | function segwitSelected() { |
676 | return bip49TabSelected(); | 689 | return bip49TabSelected() || bip141TabSelected(); |
690 | } | ||
691 | |||
692 | function p2wpkhSelected() { | ||
693 | return bip141TabSelected() && DOM.bip141semantics.val() == "p2wpkh"; | ||
694 | } | ||
695 | |||
696 | function p2wpkhInP2shSelected() { | ||
697 | return bip49TabSelected() || | ||
698 | (bip141TabSelected() && DOM.bip141semantics.val() == "p2wpkh-p2sh"); | ||
677 | } | 699 | } |
678 | 700 | ||
679 | function TableRow(index, isLast) { | 701 | function TableRow(index, isLast) { |
@@ -683,6 +705,8 @@ | |||
683 | var useHardenedAddresses = DOM.hardenedAddresses.prop("checked"); | 705 | var useHardenedAddresses = DOM.hardenedAddresses.prop("checked"); |
684 | var isSegwit = segwitSelected(); | 706 | var isSegwit = segwitSelected(); |
685 | var segwitAvailable = networkHasSegwit(); | 707 | var segwitAvailable = networkHasSegwit(); |
708 | var isP2wpkh = p2wpkhSelected(); | ||
709 | var isP2wpkhInP2sh = p2wpkhInP2shSelected(); | ||
686 | 710 | ||
687 | function init() { | 711 | function init() { |
688 | calculateValues(); | 712 | calculateValues(); |
@@ -731,11 +755,18 @@ | |||
731 | if (!segwitAvailable) { | 755 | if (!segwitAvailable) { |
732 | return; | 756 | return; |
733 | } | 757 | } |
734 | var keyhash = bitcoinjs.bitcoin.crypto.hash160(key.getPublicKeyBuffer()); | 758 | if (isP2wpkh) { |
735 | var scriptsig = bitcoinjs.bitcoin.script.witnessPubKeyHash.output.encode(keyhash); | 759 | var keyhash = bitcoinjs.bitcoin.crypto.hash160(key.getPublicKeyBuffer()); |
736 | var addressbytes = bitcoinjs.bitcoin.crypto.hash160(scriptsig); | 760 | var scriptpubkey = bitcoinjs.bitcoin.script.witnessPubKeyHash.output.encode(keyhash); |
737 | var scriptpubkey = bitcoinjs.bitcoin.script.scriptHash.output.encode(addressbytes); | 761 | address = bitcoinjs.bitcoin.address.fromOutputScript(scriptpubkey, network) |
738 | address = bitcoinjs.bitcoin.address.fromOutputScript(scriptpubkey, network) | 762 | } |
763 | else if (isP2wpkhInP2sh) { | ||
764 | var keyhash = bitcoinjs.bitcoin.crypto.hash160(key.getPublicKeyBuffer()); | ||
765 | var scriptsig = bitcoinjs.bitcoin.script.witnessPubKeyHash.output.encode(keyhash); | ||
766 | var addressbytes = bitcoinjs.bitcoin.crypto.hash160(scriptsig); | ||
767 | var scriptpubkey = bitcoinjs.bitcoin.script.scriptHash.output.encode(addressbytes); | ||
768 | address = bitcoinjs.bitcoin.address.fromOutputScript(scriptpubkey, network) | ||
769 | } | ||
739 | } | 770 | } |
740 | addAddressToList(indexText, address, pubkey, privkey); | 771 | addAddressToList(indexText, address, pubkey, privkey); |
741 | if (isLast) { | 772 | if (isLast) { |
@@ -1233,6 +1264,10 @@ | |||
1233 | return DOM.bip49tab.hasClass("active"); | 1264 | return DOM.bip49tab.hasClass("active"); |
1234 | } | 1265 | } |
1235 | 1266 | ||
1267 | function bip141TabSelected() { | ||
1268 | return DOM.bip141tab.hasClass("active"); | ||
1269 | } | ||
1270 | |||
1236 | function setHdCoin(coinValue) { | 1271 | function setHdCoin(coinValue) { |
1237 | DOM.bip44coin.val(coinValue); | 1272 | DOM.bip44coin.val(coinValue); |
1238 | DOM.bip49coin.val(coinValue); | 1273 | DOM.bip49coin.val(coinValue); |
@@ -1241,11 +1276,15 @@ | |||
1241 | function showSegwitAvailable() { | 1276 | function showSegwitAvailable() { |
1242 | DOM.bip49unavailable.addClass("hidden"); | 1277 | DOM.bip49unavailable.addClass("hidden"); |
1243 | DOM.bip49available.removeClass("hidden"); | 1278 | DOM.bip49available.removeClass("hidden"); |
1279 | DOM.bip141unavailable.addClass("hidden"); | ||
1280 | DOM.bip141available.removeClass("hidden"); | ||
1244 | } | 1281 | } |
1245 | 1282 | ||
1246 | function showSegwitUnavailable() { | 1283 | function showSegwitUnavailable() { |
1247 | DOM.bip49available.addClass("hidden"); | 1284 | DOM.bip49available.addClass("hidden"); |
1248 | DOM.bip49unavailable.removeClass("hidden"); | 1285 | DOM.bip49unavailable.removeClass("hidden"); |
1286 | DOM.bip141available.addClass("hidden"); | ||
1287 | DOM.bip141unavailable.removeClass("hidden"); | ||
1249 | } | 1288 | } |
1250 | 1289 | ||
1251 | function useBitpayAddresses() { | 1290 | function useBitpayAddresses() { |
@@ -1266,27 +1305,18 @@ | |||
1266 | // to avoid accidentally importing BIP49 xpub to BIP44 watch only | 1305 | // to avoid accidentally importing BIP49 xpub to BIP44 watch only |
1267 | // wallet. | 1306 | // wallet. |
1268 | // See https://github.com/iancoleman/bip39/issues/125 | 1307 | // See https://github.com/iancoleman/bip39/issues/125 |
1269 | if (segwitSelected()) { | 1308 | var segwitNetworks = null; |
1270 | if (network == bitcoinjs.bitcoin.networks.bitcoin) { | 1309 | // if a segwit network is alread selected, need to use base network to |
1271 | network = bitcoinjs.bitcoin.networks.bitcoinBip49; | 1310 | // look up new parameters |
1272 | } | 1311 | if ("baseNetwork" in network) { |
1273 | else if (network == bitcoinjs.bitcoin.networks.testnet) { | 1312 | network = bitcoinjs.bitcoin.networks[network.baseNetwork]; |
1274 | network = bitcoinjs.bitcoin.networks.testnetBip49; | 1313 | } |
1275 | } | 1314 | // choose the right segwit params |
1276 | else if (network == bitcoinjs.bitcoin.networks.litecoin) { | 1315 | if (p2wpkhSelected() && "p2wpkh" in network) { |
1277 | network = bitcoinjs.bitcoin.networks.litecoinBip49; | 1316 | network = network.p2wpkh; |
1278 | } | 1317 | } |
1279 | } | 1318 | else if (p2wpkhInP2shSelected() && "p2wpkhInP2sh" in network) { |
1280 | else { | 1319 | network = network.p2wpkhInP2sh; |
1281 | if (network == bitcoinjs.bitcoin.networks.bitcoinBip49) { | ||
1282 | network = bitcoinjs.bitcoin.networks.bitcoin; | ||
1283 | } | ||
1284 | else if (network == bitcoinjs.bitcoin.networks.testnetBip49) { | ||
1285 | network = bitcoinjs.bitcoin.networks.testnet; | ||
1286 | } | ||
1287 | else if (network == bitcoinjs.bitcoin.networks.litecoinBip49) { | ||
1288 | network = bitcoinjs.bitcoin.networks.litecoin; | ||
1289 | } | ||
1290 | } | 1320 | } |
1291 | } | 1321 | } |
1292 | 1322 | ||
diff --git a/src/js/segwit-parameters.js b/src/js/segwit-parameters.js new file mode 100644 index 0000000..38cf9e0 --- /dev/null +++ b/src/js/segwit-parameters.js | |||
@@ -0,0 +1,58 @@ | |||
1 | (function() { | ||
2 | |||
3 | // p2wpkh | ||
4 | |||
5 | bitcoinjs.bitcoin.networks.bitcoin.p2wpkh = { | ||
6 | baseNetwork: "bitcoin", | ||
7 | messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
8 | bech32: 'bc', | ||
9 | bip32: { | ||
10 | public: 0x04b24746, | ||
11 | private: 0x04b2430c | ||
12 | }, | ||
13 | pubKeyHash: 0x00, | ||
14 | scriptHash: 0x05, | ||
15 | wif: 0x80 | ||
16 | }; | ||
17 | |||
18 | // p2wpkh in p2sh | ||
19 | |||
20 | bitcoinjs.bitcoin.networks.bitcoin.p2wpkhInP2sh = { | ||
21 | baseNetwork: "bitcoin", | ||
22 | messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
23 | bech32: 'bc', | ||
24 | bip32: { | ||
25 | public: 0x049d7cb2, | ||
26 | private: 0x049d7878 | ||
27 | }, | ||
28 | pubKeyHash: 0x00, | ||
29 | scriptHash: 0x05, | ||
30 | wif: 0x80 | ||
31 | }; | ||
32 | |||
33 | bitcoinjs.bitcoin.networks.testnet.p2wpkhInP2sh = { | ||
34 | baseNetwork: "testnet", | ||
35 | messagePrefix: '\x18Bitcoin Signed Message:\n', | ||
36 | bech32: 'tb', | ||
37 | bip32: { | ||
38 | public: 0x044a5262, | ||
39 | private: 0x044a4e28 | ||
40 | }, | ||
41 | pubKeyHash: 0x6f, | ||
42 | scriptHash: 0xc4, | ||
43 | wif: 0xef | ||
44 | }; | ||
45 | |||
46 | bitcoinjs.bitcoin.networks.litecoin.p2wpkhInP2sh = { | ||
47 | baseNetwork: "litecoin", | ||
48 | messagePrefix: '\x19Litecoin Signed Message:\n', | ||
49 | bip32: { | ||
50 | public: 0x01b26ef6, | ||
51 | private: 0x01b26792 | ||
52 | }, | ||
53 | pubKeyHash: 0x30, | ||
54 | scriptHash: 0x32, | ||
55 | wif: 0xb0 | ||
56 | }; | ||
57 | |||
58 | })(); | ||