body {
padding-bottom: 32px;
}
+ .form-control[readonly] {
+ cursor: text;
+ }
.feedback-container {
position: fixed;
top: 0;
<hr>
<div class="row">
<div class="col-md-12">
- <h2>Phrase</h2>
+ <h2>Mnemonic</h2>
<form class="form-horizontal" role="form">
<div class="col-sm-2"></div>
<div class="col-sm-10">
+ <p>You can enter an existing BIP39 mnemonic, or generate a new random one. Typing your own twelve words will probably not work how you expect, since the words require a particular structure (the last word is a checksum)</p>
<p>For more info see the <a href="https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki" target="_blank">BIP39 spec</a></p>
</div>
<div class="form-group">
- <label for="phrase" class="col-sm-2 control-label">BIP39 Phrase</label>
+ <label for="phrase" class="col-sm-2 control-label">BIP39 Mnemonic</label>
<div class="col-sm-10">
<textarea id="phrase" class="phrase form-control"></textarea>
</div>
<div class="input-group">
<input type="number" class="strength form-control" id="strength" value="12">
<span class="input-group-btn">
- <button class="btn generate">Generate Random Phrase</button>
+ <button class="btn generate">Generate Random Mnemonic</button>
</span>
</div>
</div>
</div>
+ <div class="form-group">
+ <label for="passphrase" class="col-sm-2 control-label">BIP39 Passphrase (optional)</label>
+ <div class="col-sm-10">
+ <textarea id="passphrase" class="passphrase form-control"></textarea>
+ </div>
+ </div>
<div class="form-group">
<label for="root-key" class="col-sm-2 control-label">BIP32 Root Key</label>
<div class="col-sm-10">
- <textarea id="root-key" class="root-key form-control" disabled="disabled"></textarea>
+ <textarea id="root-key" class="root-key form-control" readonly="readonly"></textarea>
</div>
</div>
</form>
<div class="form-group">
<label for="bip44-path" class="col-sm-2 control-label">BIP32 Derivation Path</label>
<div class="col-sm-10">
- <input id="bip44-path" type="text" class="path form-control" value="m/44'/0'/0'/0" disabled="disabled">
+ <input id="bip44-path" type="text" class="path form-control" value="m/44'/0'/0'/0" readonly="readonly">
</div>
</div>
</form>
<div class="form-group">
<label for="extended-priv-key" class="col-sm-2 control-label">BIP32 Extended Key</label>
<div class="col-sm-10">
- <textarea id="extended-priv-key" class="extended-priv-key form-control" disabled="disabled"></textarea>
+ <textarea id="extended-priv-key" class="extended-priv-key form-control" readonly="readonly"></textarea>
</div>
</div>
<div class="form-group">
<label for="extended-pub-key" class="col-sm-2 control-label">BIP32 Extended Key (addresses only)</label>
<div class="col-sm-10">
- <textarea id="extended-pub-key" class="extended-pub-key form-control" disabled="disabled"></textarea>
+ <textarea id="extended-pub-key" class="extended-pub-key form-control" readonly="readonly"></textarea>
</div>
</div>
</form>
<hr>
- <div class="row">
- <div class="col-md-12">
- <h2>Derived Addresses</h2>
- <p>Note these addreses are derived from the <strong>BIP32 Extended Key</strong></p>
- <table class="table table-striped">
- <thead>
- <th>
- <div class="input-group">
- Index
- <button class="index-toggle">Toggle</button>
- </div>
- </th>
- <th>
- <div class="input-group">
- Address
- <button class="address-toggle">Toggle</button>
- </div>
- </th>
- <th>
- <div class="input-group">
- Private Key
- <button class="private-key-toggle">Toggle</button>
- </div>
- </th>
- </thead>
- <tbody class="addresses">
- <tr><td> </td><td> </td><td> </td></tr>
- <tr><td> </td><td> </td><td> </td></tr>
- <tr><td> </td><td> </td><td> </td></tr>
- <tr><td> </td><td> </td><td> </td></tr>
- <tr><td> </td><td> </td><td> </td></tr>
- </tbody>
- </table>
- </div>
- </div>
- <span>Show next </button>
- <input type="number" class="rows-to-add" value="20">
- <button class="more">Show</button>
-
- <hr>
-
- <div class="row">
- <div class="col-md-12">
- <h2>More info</h2>
- <h3>BIP39 <span class="small">Mnemonic code for generating deterministic keys</span></h3>
- <p>
- Read more at the
- <a href="https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki">official BIP39 spec</a>
- </p>
- <h3>BIP32 <span class="small">Hierarchical Deterministic Wallets</span></h3>
- <p>
- Read more at the
- <a href="https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki" target="_blank">official BIP32 spec</a>
- and see the demo at
- <a href="http://bip32.org/" target="_blank">bip32.org</a>
- </p>
- <h3>BIP44 <span class="small">Multi-Account Hierarchy for Deterministic Wallets</span></h3>
- <p>
- Read more at the
- <a href="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki" target="_blank">official BIP44 spec</a>
- </p>
- <h3>Private Keys</h3>
- <p>
- Use private keys at
- <a href="https://brainwallet.github.io/" target="_blank">brainwallet.org</a>,
- but be careful - it can be easy to make mistakes if you
- don't know what you're doing
- </p>
- </div>
- </div>
-
- <hr>
-
<div class="row">
<div class="col-md-12">
</div>
<div class="feedback-container">
- <div class="feedback"></div>
+ <div class="feedback">Loading...</div>
</div>
<script type="text/template" id="address-row-template">
self.toSeed = function(mnemonic, passphrase) {
passphrase = passphrase || '';
- mnemonic = normalizeString(mnemonic)
- passphrase = normalizeString(passphrase)
+ mnemonic = self.normalizeString(mnemonic)
+ passphrase = self.normalizeString(passphrase)
passphrase = "mnemonic" + passphrase;
//return PBKDF2(mnemonic, 'mnemonic' + passphrase, iterations=PBKDF2_ROUNDS, macmodule=hmac, digestmodule=hashlib.sha512).read(64)
return asmCrypto.PBKDF2_HMAC_SHA512.hex(mnemonic, passphrase, PBKDF2_ROUNDS, 512/8);
}
- function normalizeString(str) {
+ self.normalizeString = function(str) {
if (typeof str.normalize == "function") {
return str.normalize("NFKD");
}
var DOM = {};
DOM.phrase = $(".phrase");
+ DOM.passphrase = $(".passphrase");
DOM.generate = $(".generate");
DOM.rootKey = $(".root-key");
DOM.extendedPrivKey = $(".extended-priv-key");
function init() {
// Events
- DOM.phrase.on("keyup", delayedPhraseChanged);
+ DOM.phrase.on("input", delayedPhraseChanged);
+ DOM.passphrase.on("input", delayedPhraseChanged);
DOM.generate.on("click", generateClicked);
DOM.more.on("click", showMore);
- DOM.bip32path.on("keyup", bip32Changed);
- DOM.bip44purpose.on("keyup", bip44Changed);
- DOM.bip44coin.on("keyup", bip44Changed);
- DOM.bip44account.on("keyup", bip44Changed);
- DOM.bip44change.on("keyup", bip44Changed);
+ DOM.bip32path.on("input", bip32Changed);
+ DOM.bip44purpose.on("input", bip44Changed);
+ DOM.bip44coin.on("input", bip44Changed);
+ DOM.bip44account.on("input", bip44Changed);
+ DOM.bip44change.on("input", bip44Changed);
DOM.tab.on("click", tabClicked);
DOM.indexToggle.on("click", toggleIndexes);
DOM.addressToggle.on("click", toggleAddresses);
hideValidationError();
// Get the mnemonic phrase
var phrase = DOM.phrase.val();
+ var passphrase = DOM.passphrase.val();
var errorText = findPhraseErrors(phrase);
if (errorText) {
showValidationError(errorText);
return;
}
// Calculate and display
- calcBip32Seed(phrase, derivationPath);
+ calcBip32Seed(phrase, passphrase, derivationPath);
displayBip32Info();
hidePending();
}
return words;
}
- function calcBip32Seed(phrase, path) {
- var seed = mnemonic.toSeed(phrase);
- var seedHash = Bitcoin.crypto.sha256(seed).toString("hex");
- bip32RootKey = Bitcoin.HDNode.fromSeedHex(seedHash, network);
+ function calcBip32Seed(phrase, passphrase, path) {
+ var seed = mnemonic.toSeed(phrase, passphrase);
+ bip32RootKey = Bitcoin.HDNode.fromSeedHex(seed, network);
bip32ExtendedKey = bip32RootKey;
// Derive the key from the path
var pathBits = path.split("/");
function findPhraseErrors(phrase) {
// TODO make this right
// Preprocess the words
+ phrase = mnemonic.normalizeString(phrase);
var parts = phrase.split(" ");
var proper = [];
for (var i=0; i<parts.length; i++) {
var index = i+ start;
var key = bip32ExtendedKey.derive(index);
var address = key.getAddress().toString();
- var privkey = key.privKey.toWIF();
+ var privkey = key.privKey.toWIF(network);
addAddressToList(index, address, privkey);
}
}