aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Coleman <coleman.ian@gmail.com>2016-08-23 10:31:39 +1000
committerIan Coleman <coleman.ian@gmail.com>2016-08-23 10:31:39 +1000
commitefe41586705d3eba480da31bb1002c4e54e73ef0 (patch)
treef071e764935ce06c165fdc014ed29172271c3cef
parent563e401a4f3880da88bfc69cf51be5a1becd4c66 (diff)
downloadBIP39-efe41586705d3eba480da31bb1002c4e54e73ef0.tar.gz
BIP39-efe41586705d3eba480da31bb1002c4e54e73ef0.tar.zst
BIP39-efe41586705d3eba480da31bb1002c4e54e73ef0.zip
BIP32 Root Key can be specified by user
-rw-r--r--bip39-standalone.html87
-rw-r--r--src/index.html2
-rw-r--r--src/js/index.js85
3 files changed, 150 insertions, 24 deletions
diff --git a/bip39-standalone.html b/bip39-standalone.html
index b1fe90e..9d0de5e 100644
--- a/bip39-standalone.html
+++ b/bip39-standalone.html
@@ -109,7 +109,7 @@
109 <div class="form-group"> 109 <div class="form-group">
110 <label for="root-key" class="col-sm-2 control-label">BIP32 Root Key</label> 110 <label for="root-key" class="col-sm-2 control-label">BIP32 Root Key</label>
111 <div class="col-sm-10"> 111 <div class="col-sm-10">
112 <textarea id="root-key" class="root-key form-control" readonly="readonly"></textarea> 112 <textarea id="root-key" class="root-key form-control"></textarea>
113 </div> 113 </div>
114 </div> 114 </div>
115 </form> 115 </form>
@@ -14830,6 +14830,7 @@ var Mnemonic = function(language) {
14830 var showPrivKey = true; 14830 var showPrivKey = true;
14831 14831
14832 var phraseChangeTimeoutEvent = null; 14832 var phraseChangeTimeoutEvent = null;
14833 var rootKeyChangedTimeoutEvent = null;
14833 14834
14834 var DOM = {}; 14835 var DOM = {};
14835 DOM.network = $(".network"); 14836 DOM.network = $(".network");
@@ -14868,12 +14869,13 @@ var Mnemonic = function(language) {
14868 DOM.passphrase.on("input", delayedPhraseChanged); 14869 DOM.passphrase.on("input", delayedPhraseChanged);
14869 DOM.generate.on("click", generateClicked); 14870 DOM.generate.on("click", generateClicked);
14870 DOM.more.on("click", showMore); 14871 DOM.more.on("click", showMore);
14871 DOM.bip32path.on("input", delayedPhraseChanged); 14872 DOM.rootKey.on("input", delayedRootKeyChanged);
14872 DOM.bip44purpose.on("input", delayedPhraseChanged); 14873 DOM.bip32path.on("input", calcForDerivationPath);
14873 DOM.bip44coin.on("input", delayedPhraseChanged); 14874 DOM.bip44purpose.on("input", calcForDerivationPath);
14874 DOM.bip44account.on("input", delayedPhraseChanged); 14875 DOM.bip44coin.on("input", calcForDerivationPath);
14875 DOM.bip44change.on("input", delayedPhraseChanged); 14876 DOM.bip44account.on("input", calcForDerivationPath);
14876 DOM.tab.on("click", delayedPhraseChanged); 14877 DOM.bip44change.on("input", calcForDerivationPath);
14878 DOM.tab.on("shown.bs.tab", calcForDerivationPath);
14877 DOM.indexToggle.on("click", toggleIndexes); 14879 DOM.indexToggle.on("click", toggleIndexes);
14878 DOM.addressToggle.on("click", toggleAddresses); 14880 DOM.addressToggle.on("click", toggleAddresses);
14879 DOM.privateKeyToggle.on("click", togglePrivateKeys); 14881 DOM.privateKeyToggle.on("click", togglePrivateKeys);
@@ -14888,7 +14890,7 @@ var Mnemonic = function(language) {
14888 function networkChanged(e) { 14890 function networkChanged(e) {
14889 var network = e.target.value; 14891 var network = e.target.value;
14890 networks[network].onSelect(); 14892 networks[network].onSelect();
14891 delayedPhraseChanged(); 14893 displayBip32Info();
14892 } 14894 }
14893 14895
14894 function delayedPhraseChanged() { 14896 function delayedPhraseChanged() {
@@ -14905,12 +14907,57 @@ var Mnemonic = function(language) {
14905 hideValidationError(); 14907 hideValidationError();
14906 // Get the mnemonic phrase 14908 // Get the mnemonic phrase
14907 var phrase = DOM.phrase.val(); 14909 var phrase = DOM.phrase.val();
14908 var passphrase = DOM.passphrase.val();
14909 var errorText = findPhraseErrors(phrase); 14910 var errorText = findPhraseErrors(phrase);
14910 if (errorText) { 14911 if (errorText) {
14911 showValidationError(errorText); 14912 showValidationError(errorText);
14912 return; 14913 return;
14913 } 14914 }
14915 // Calculate and display
14916 var passphrase = DOM.passphrase.val();
14917 calcBip32RootKeyFromSeed(phrase, passphrase);
14918 calcForDerivationPath();
14919 hidePending();
14920 }
14921
14922 function delayedRootKeyChanged() {
14923 // Warn if there is an existing mnemonic or passphrase.
14924 if (DOM.phrase.val().length > 0 || DOM.passphrase.val().length > 0) {
14925 if (!confirm("This will clear existing mnemonic and passphrase")) {
14926 DOM.rootKey.val(bip32RootKey);
14927 return
14928 }
14929 }
14930 hideValidationError();
14931 showPending();
14932 // Clear existing mnemonic and passphrase
14933 DOM.phrase.val("");
14934 DOM.passphrase.val("");
14935 seed = null;
14936 if (rootKeyChangedTimeoutEvent != null) {
14937 clearTimeout(rootKeyChangedTimeoutEvent);
14938 }
14939 rootKeyChangedTimeoutEvent = setTimeout(rootKeyChanged, 400);
14940 }
14941
14942 function rootKeyChanged() {
14943 showPending();
14944 hideValidationError();
14945 // Validate the root key TODO
14946 var rootKeyBase58 = DOM.rootKey.val();
14947 var errorText = validateRootKey(rootKeyBase58);
14948 if (errorText) {
14949 showValidationError(errorText);
14950 return;
14951 }
14952 // Calculate and display
14953 calcBip32RootKeyFromBase58(rootKeyBase58);
14954 calcForDerivationPath();
14955 hidePending();
14956 }
14957
14958 function calcForDerivationPath() {
14959 showPending();
14960 hideValidationError();
14914 // Get the derivation path 14961 // Get the derivation path
14915 var derivationPath = getDerivationPath(); 14962 var derivationPath = getDerivationPath();
14916 var errorText = findDerivationPathErrors(derivationPath); 14963 var errorText = findDerivationPathErrors(derivationPath);
@@ -14918,8 +14965,7 @@ var Mnemonic = function(language) {
14918 showValidationError(errorText); 14965 showValidationError(errorText);
14919 return; 14966 return;
14920 } 14967 }
14921 // Calculate and display 14968 calcBip32ExtendedKey(derivationPath);
14922 calcBip32Seed(phrase, passphrase, derivationPath);
14923 displayBip32Info(); 14969 displayBip32Info();
14924 hidePending(); 14970 hidePending();
14925 } 14971 }
@@ -14966,9 +15012,16 @@ var Mnemonic = function(language) {
14966 return words; 15012 return words;
14967 } 15013 }
14968 15014
14969 function calcBip32Seed(phrase, passphrase, path) { 15015 function calcBip32RootKeyFromSeed(phrase, passphrase) {
14970 seed = mnemonic.toSeed(phrase, passphrase); 15016 seed = mnemonic.toSeed(phrase, passphrase);
14971 bip32RootKey = bitcoin.HDNode.fromSeedHex(seed, network); 15017 bip32RootKey = bitcoin.HDNode.fromSeedHex(seed, network);
15018 }
15019
15020 function calcBip32RootKeyFromBase58(rootKeyBase58) {
15021 bip32RootKey = bitcoin.HDNode.fromBase58(rootKeyBase58);
15022 }
15023
15024 function calcBip32ExtendedKey(path) {
14972 bip32ExtendedKey = bip32RootKey; 15025 bip32ExtendedKey = bip32RootKey;
14973 // Derive the key from the path 15026 // Derive the key from the path
14974 var pathBits = path.split("/"); 15027 var pathBits = path.split("/");
@@ -15031,6 +15084,16 @@ var Mnemonic = function(language) {
15031 return false; 15084 return false;
15032 } 15085 }
15033 15086
15087 function validateRootKey(rootKeyBase58) {
15088 try {
15089 bitcoin.HDNode.fromBase58(rootKeyBase58);
15090 }
15091 catch (e) {
15092 return "Invalid root key";
15093 }
15094 return "";
15095 }
15096
15034 function getDerivationPath() { 15097 function getDerivationPath() {
15035 if (DOM.bip44tab.hasClass("active")) { 15098 if (DOM.bip44tab.hasClass("active")) {
15036 var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44); 15099 var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44);
diff --git a/src/index.html b/src/index.html
index 6708675..fcdf109 100644
--- a/src/index.html
+++ b/src/index.html
@@ -105,7 +105,7 @@
105 <div class="form-group"> 105 <div class="form-group">
106 <label for="root-key" class="col-sm-2 control-label">BIP32 Root Key</label> 106 <label for="root-key" class="col-sm-2 control-label">BIP32 Root Key</label>
107 <div class="col-sm-10"> 107 <div class="col-sm-10">
108 <textarea id="root-key" class="root-key form-control" readonly="readonly"></textarea> 108 <textarea id="root-key" class="root-key form-control"></textarea>
109 </div> 109 </div>
110 </div> 110 </div>
111 </form> 111 </form>
diff --git a/src/js/index.js b/src/js/index.js
index f3582b0..88e891c 100644
--- a/src/js/index.js
+++ b/src/js/index.js
@@ -12,6 +12,7 @@
12 var showPrivKey = true; 12 var showPrivKey = true;
13 13
14 var phraseChangeTimeoutEvent = null; 14 var phraseChangeTimeoutEvent = null;
15 var rootKeyChangedTimeoutEvent = null;
15 16
16 var DOM = {}; 17 var DOM = {};
17 DOM.network = $(".network"); 18 DOM.network = $(".network");
@@ -50,12 +51,13 @@
50 DOM.passphrase.on("input", delayedPhraseChanged); 51 DOM.passphrase.on("input", delayedPhraseChanged);
51 DOM.generate.on("click", generateClicked); 52 DOM.generate.on("click", generateClicked);
52 DOM.more.on("click", showMore); 53 DOM.more.on("click", showMore);
53 DOM.bip32path.on("input", delayedPhraseChanged); 54 DOM.rootKey.on("input", delayedRootKeyChanged);
54 DOM.bip44purpose.on("input", delayedPhraseChanged); 55 DOM.bip32path.on("input", calcForDerivationPath);
55 DOM.bip44coin.on("input", delayedPhraseChanged); 56 DOM.bip44purpose.on("input", calcForDerivationPath);
56 DOM.bip44account.on("input", delayedPhraseChanged); 57 DOM.bip44coin.on("input", calcForDerivationPath);
57 DOM.bip44change.on("input", delayedPhraseChanged); 58 DOM.bip44account.on("input", calcForDerivationPath);
58 DOM.tab.on("click", delayedPhraseChanged); 59 DOM.bip44change.on("input", calcForDerivationPath);
60 DOM.tab.on("shown.bs.tab", calcForDerivationPath);
59 DOM.indexToggle.on("click", toggleIndexes); 61 DOM.indexToggle.on("click", toggleIndexes);
60 DOM.addressToggle.on("click", toggleAddresses); 62 DOM.addressToggle.on("click", toggleAddresses);
61 DOM.privateKeyToggle.on("click", togglePrivateKeys); 63 DOM.privateKeyToggle.on("click", togglePrivateKeys);
@@ -70,7 +72,7 @@
70 function networkChanged(e) { 72 function networkChanged(e) {
71 var network = e.target.value; 73 var network = e.target.value;
72 networks[network].onSelect(); 74 networks[network].onSelect();
73 delayedPhraseChanged(); 75 displayBip32Info();
74 } 76 }
75 77
76 function delayedPhraseChanged() { 78 function delayedPhraseChanged() {
@@ -87,12 +89,57 @@
87 hideValidationError(); 89 hideValidationError();
88 // Get the mnemonic phrase 90 // Get the mnemonic phrase
89 var phrase = DOM.phrase.val(); 91 var phrase = DOM.phrase.val();
90 var passphrase = DOM.passphrase.val();
91 var errorText = findPhraseErrors(phrase); 92 var errorText = findPhraseErrors(phrase);
92 if (errorText) { 93 if (errorText) {
93 showValidationError(errorText); 94 showValidationError(errorText);
94 return; 95 return;
95 } 96 }
97 // Calculate and display
98 var passphrase = DOM.passphrase.val();
99 calcBip32RootKeyFromSeed(phrase, passphrase);
100 calcForDerivationPath();
101 hidePending();
102 }
103
104 function delayedRootKeyChanged() {
105 // Warn if there is an existing mnemonic or passphrase.
106 if (DOM.phrase.val().length > 0 || DOM.passphrase.val().length > 0) {
107 if (!confirm("This will clear existing mnemonic and passphrase")) {
108 DOM.rootKey.val(bip32RootKey);
109 return
110 }
111 }
112 hideValidationError();
113 showPending();
114 // Clear existing mnemonic and passphrase
115 DOM.phrase.val("");
116 DOM.passphrase.val("");
117 seed = null;
118 if (rootKeyChangedTimeoutEvent != null) {
119 clearTimeout(rootKeyChangedTimeoutEvent);
120 }
121 rootKeyChangedTimeoutEvent = setTimeout(rootKeyChanged, 400);
122 }
123
124 function rootKeyChanged() {
125 showPending();
126 hideValidationError();
127 // Validate the root key TODO
128 var rootKeyBase58 = DOM.rootKey.val();
129 var errorText = validateRootKey(rootKeyBase58);
130 if (errorText) {
131 showValidationError(errorText);
132 return;
133 }
134 // Calculate and display
135 calcBip32RootKeyFromBase58(rootKeyBase58);
136 calcForDerivationPath();
137 hidePending();
138 }
139
140 function calcForDerivationPath() {
141 showPending();
142 hideValidationError();
96 // Get the derivation path 143 // Get the derivation path
97 var derivationPath = getDerivationPath(); 144 var derivationPath = getDerivationPath();
98 var errorText = findDerivationPathErrors(derivationPath); 145 var errorText = findDerivationPathErrors(derivationPath);
@@ -100,8 +147,7 @@
100 showValidationError(errorText); 147 showValidationError(errorText);
101 return; 148 return;
102 } 149 }
103 // Calculate and display 150 calcBip32ExtendedKey(derivationPath);
104 calcBip32Seed(phrase, passphrase, derivationPath);
105 displayBip32Info(); 151 displayBip32Info();
106 hidePending(); 152 hidePending();
107 } 153 }
@@ -148,9 +194,16 @@
148 return words; 194 return words;
149 } 195 }
150 196
151 function calcBip32Seed(phrase, passphrase, path) { 197 function calcBip32RootKeyFromSeed(phrase, passphrase) {
152 seed = mnemonic.toSeed(phrase, passphrase); 198 seed = mnemonic.toSeed(phrase, passphrase);
153 bip32RootKey = bitcoin.HDNode.fromSeedHex(seed, network); 199 bip32RootKey = bitcoin.HDNode.fromSeedHex(seed, network);
200 }
201
202 function calcBip32RootKeyFromBase58(rootKeyBase58) {
203 bip32RootKey = bitcoin.HDNode.fromBase58(rootKeyBase58);
204 }
205
206 function calcBip32ExtendedKey(path) {
154 bip32ExtendedKey = bip32RootKey; 207 bip32ExtendedKey = bip32RootKey;
155 // Derive the key from the path 208 // Derive the key from the path
156 var pathBits = path.split("/"); 209 var pathBits = path.split("/");
@@ -213,6 +266,16 @@
213 return false; 266 return false;
214 } 267 }
215 268
269 function validateRootKey(rootKeyBase58) {
270 try {
271 bitcoin.HDNode.fromBase58(rootKeyBase58);
272 }
273 catch (e) {
274 return "Invalid root key";
275 }
276 return "";
277 }
278
216 function getDerivationPath() { 279 function getDerivationPath() {
217 if (DOM.bip44tab.hasClass("active")) { 280 if (DOM.bip44tab.hasClass("active")) {
218 var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44); 281 var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44);