Compare commits

..

30 Commits
0.3.2 ... 0.3.4

Author SHA1 Message Date
Ian Coleman
fca07769eb Release v0.3.4 2018-03-12 11:48:10 +11:00
Ian Coleman
5028988195 Use correct BIP44 value for Denarius of 116, not 0
See https://github.com/satoshilabs/slips/blob/master/slip-0044.md
2018-03-12 11:41:35 +11:00
Ian Coleman
139becaf2c Add Korean language 2018-03-12 11:31:41 +11:00
Ian Coleman
0514c20b81 Update jsbip39.js to latest version 2018-03-12 11:31:41 +11:00
Ian Coleman
f8ca25c338 Add spacing every 11 bits to the checksum 2018-03-12 11:31:41 +11:00
Ian Coleman
548d94994b Warn that entropy values should exclude checksum 2018-03-12 11:31:41 +11:00
Ian Coleman
09d63290a4 Show the checksum value in the entropy details 2018-03-12 11:31:41 +11:00
Ian Coleman
d6cade868f Add spaces every 11 bits to raw binary of entropy
This makes it easier to see that the checksum is missing from the end of
the entropy.
2018-03-12 11:31:41 +11:00
Ian Coleman
048721a6ff Add test for blackcoin 2018-03-12 11:31:41 +11:00
Ian Coleman
892ce76fed Order blackcoin alphabetically in coin list 2018-03-12 11:31:41 +11:00
iancoleman
aaa82c097f Merge pull request #172 from carsenk/master
Add Denarius (DNR) Support
2018-03-12 11:21:17 +11:00
iancoleman
05311e7f54 Merge pull request #163 from janko33bd/blackcoin
Add Blackcoin please
2018-03-12 09:23:17 +11:00
carsenk
40209fd898 Add DNR Support 2018-03-06 01:11:55 -07:00
janko33bd
e5520bb859 typo 2018-02-07 19:27:35 +01:00
janko33bd
e1d0cf4f72 update index.js with correct BIP44 reg. number 2018-02-07 19:26:26 +01:00
janko33bd
e82a142872 make bitcoinjs-extensions black 2018-02-07 19:20:54 +01:00
Ian Coleman
fcc7d12109 Release v0.3.3 2018-02-06 10:36:38 +11:00
Ian Coleman
5dfe77e4a3 Fix tests which generate more rows 2018-02-06 10:33:21 +11:00
Ian Coleman
e21e32da31 Add BIP38 test 2018-02-06 10:14:22 +11:00
Ian Coleman
ba678b1147 Allow initial number of rows to be set by user 2018-02-06 09:57:28 +11:00
Ian Coleman
0b39e9dca7 Add BIP38 interface elements 2018-02-06 09:57:23 +11:00
Ian Coleman
cc61ec30c5 Encrypt private keys with BIP38
with fakes for missing UI elements
2018-02-06 09:43:13 +11:00
Ian Coleman
0f0a888e13 Add bitcoinjs-bip38-2.0.2 library
Created using browserify:
git clone https://github.com/bitcoinjs/bip38.git
git checkout v2.0.2
npm install
npm run unit
browserify index.js --standalone bitcoinjs-bip38 > bitcoinjs-bip38-2.0.2.js
2018-02-06 09:42:10 +11:00
Ian Coleman
2ef27fb80b Remove commented-out lines of code from test 2018-01-16 10:37:37 +11:00
Ian Coleman
423fb969c6 Test AXE network 2018-01-16 10:34:42 +11:00
Ian Coleman
9fae1ffbcc Increase allowed rendering time tests
Firefox was only generating 15 of 20 rows in the address table
2018-01-16 10:33:08 +11:00
Ian Coleman
78db37f663 LeftPad ethereum private keys with zeros if needed 2018-01-16 10:33:08 +11:00
iancoleman
28e1cd455c Merge pull request #154 from AXErunners/master
Add AXE
2018-01-16 09:05:18 +11:00
-k
47debf07ed AXE support
prefix fixed
2018-01-07 00:55:48 -05:00
-k
cfc0c4d743 AXE support 2018-01-06 23:57:11 -05:00
10 changed files with 60371 additions and 50 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,19 @@
# 0.3.4
* Add BlackCoin
* Add Denarius
* Raw entropy shows groupings with space every 11 bits
* Checksum shown in entropy details
* Warn that entropy values should exclude checksum
* Add Korean language
# 0.3.3
* Add AXE network
* Ethereum private key generation bugfix
* Add BIP38 support
* Allow initial number of rows to be set by the user
# 0.3.2
* Add Onixcoin

View File

@@ -15,7 +15,7 @@
<div class="container">
<h1 class="text-center">Mnemonic Code Converter</h1>
<p class="version">v0.3.2</p>
<p class="version">v0.3.4</p>
<hr>
<div class="row">
<div class="col-md-12">
@@ -94,6 +94,8 @@
<div class="filtered col-sm-9 form-control-static"></div>
<label class="col-sm-3 control-label">Raw Binary</label>
<div class="binary col-sm-9 form-control-static"></div>
<label class="col-sm-3 control-label">Binary Checksum</label>
<div class="checksum col-sm-9 form-control-static">&nbsp;</div>
<label class="col-sm-3 control-label">Word Indexes</label>
<div class="word-indexes col-sm-9 form-control-static">&nbsp;</div>
<label class="col-sm-3 control-label">Mnemonic Length</label>
@@ -141,6 +143,7 @@
<a href="#chinese_traditional" title="Chinese (Traditional)">中文(繁體)</a>
<a href="#french" title="French">Français</a>
<a href="#italian" title="Italian">Italiano</a>
<a href="#korean" title="Korean">한국어</a>
</div>
</div>
</div>
@@ -603,6 +606,16 @@
</label>
</div>
</div>
<div class="col-md-12">
<div class="checkbox">
<label>
<input type="checkbox" class="use-bip38">
<span>Encrypt private keys using BIP38 and this password:</span>
</label>
<input class="bip38-password">
<span>Enabling BIP38 means each key will take take several minutes to generate.</span>
</div>
</div>
<ul class="addresses-type nav nav-tabs" role="tablist">
<li id="table-tab" class="active">
<a href="#table" role="tab" data-toggle="tab">Table</a>
@@ -703,6 +716,9 @@
<span>Be careful - it can be easy to make mistakes if you don't know what you're doing.</span>
</p>
<h3 id="entropy-notes">Entropy</h3>
<p>
<span>Entropy values should not include the BIP39 checksum. This is automatically added by the tool.</span>
</p>
<p>
<span>
Entropy values must be sourced from a
@@ -873,6 +889,7 @@
<script src="js/kjua-0.1.1.min.js"></script>
<script src="js/bitcoinjs-3.3.0.js"></script>
<script src="js/bitcoinjs-extensions.js"></script>
<script src="js/bitcoinjs-bip38-2.0.2.js"></script>
<script src="js/segwit-parameters.js"></script>
<script src="js/ethereumjs-util.js"></script>
<script src="js/ripple-util.js"></script>
@@ -884,6 +901,7 @@
<script src="js/wordlist_chinese_traditional.js"></script>
<script src="js/wordlist_french.js"></script>
<script src="js/wordlist_italian.js"></script>
<script src="js/wordlist_korean.js"></script>
<script src="js/jsbip39.js"></script>
<script src="js/biginteger.js"></script>
<script src="js/zxcvbn.js"></script>

File diff suppressed because it is too large Load Diff

View File

@@ -108,6 +108,17 @@ bitcoinjs.bitcoin.networks.peercoin = {
wif: 0xb7
};
bitcoinjs.bitcoin.networks.axe = {
messagePrefix: 'unused',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4
},
pubKeyHash: 0x4B,
scriptHash: 0xCB, // TODO set this correctly
wif: 0xCB
};
bitcoinjs.bitcoin.networks.slimcoin = {
messagePrefix: 'unused',
bip32: {
@@ -141,6 +152,17 @@ bitcoinjs.bitcoin.networks.dogecoin = {
wif: 0x9e
};
bitcoinjs.bitcoin.networks.denarius = {
messagePrefix: '\x19Denarius Signed Message:\n',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4
},
pubKeyHash: 0x1e,
scriptHash: 0x5a,
wif: 0x9e
};
bitcoinjs.bitcoin.networks.viacoin = {
messagePrefix: '\x18Viacoin Signed Message:\n',
bip32: {
@@ -317,3 +339,14 @@ bitcoinjs.bitcoin.networks.komodo = {
scriptHash: 0x55,
wif: 0xbc
};
bitcoinjs.bitcoin.networks.blackcoin = {
messagePrefix: '\x18BlackCoin Signed Message:\n',
bip32: {
public: 0x02CFBEDE,
private: 0x02CFBF60
},
pubKeyHash: 0x19,
scriptHash: 0x55,
wif: 0x99
};

View File

@@ -38,6 +38,7 @@
DOM.entropyWordCount = DOM.entropyContainer.find(".word-count");
DOM.entropyBinary = DOM.entropyContainer.find(".binary");
DOM.entropyWordIndexes = DOM.entropyContainer.find(".word-indexes");
DOM.entropyChecksum = DOM.entropyContainer.find(".checksum");
DOM.entropyMnemonicLength = DOM.entropyContainer.find(".mnemonic-length");
DOM.entropyFilterWarning = DOM.entropyContainer.find(".filter-warning");
DOM.phrase = $(".phrase");
@@ -90,6 +91,8 @@
DOM.hardenedAddresses = $(".hardened-addresses");
DOM.useBitpayAddressesContainer = $(".use-bitpay-addresses-container");
DOM.useBitpayAddresses = $(".use-bitpay-addresses");
DOM.useBip38 = $(".use-bip38");
DOM.bip38Password = $(".bip38-password");
DOM.addresses = $(".addresses");
DOM.csvTab = $("#csv-tab a");
DOM.csv = $(".csv");
@@ -133,6 +136,8 @@
DOM.bip141semantics.on("change", tabChanged);
DOM.tab.on("shown.bs.tab", tabChanged);
DOM.hardenedAddresses.on("change", calcForDerivationPath);
DOM.useBip38.on("change", calcForDerivationPath);
DOM.bip38Password.on("change", calcForDerivationPath);
DOM.indexToggle.on("click", toggleIndexes);
DOM.addressToggle.on("click", toggleAddresses);
DOM.publicKeyToggle.on("click", togglePublicKeys);
@@ -723,7 +728,8 @@
DOM.extendedPubKey.val(extendedPubKey);
// Display the addresses and privkeys
clearAddressesList();
displayAddresses(0, 20);
var initialAddressCount = parseInt(DOM.rowsToAdd.val());
displayAddresses(0, initialAddressCount);
}
function displayAddresses(start, total) {
@@ -766,6 +772,8 @@
var self = this;
this.shouldGenerate = true;
var useHardenedAddresses = DOM.hardenedAddresses.prop("checked");
var useBip38 = DOM.useBip38.prop("checked");
var bip38password = DOM.bip38Password.val();
var isSegwit = segwitSelected();
var segwitAvailable = networkHasSegwit();
var isP2wpkh = p2wpkhSelected();
@@ -780,6 +788,7 @@
if (!self.shouldGenerate) {
return;
}
// derive HDkey for this row of the table
var key = "NA";
if (useHardenedAddresses) {
key = bip32ExtendedKey.deriveHardened(index);
@@ -787,19 +796,36 @@
else {
key = bip32ExtendedKey.derive(index);
}
var address = key.getAddress().toString();
var privkey = "NA";
if (!key.isNeutered()) {
privkey = key.keyPair.toWIF(network);
// bip38 requires uncompressed keys
// see https://github.com/iancoleman/bip39/issues/140#issuecomment-352164035
var keyPair = key.keyPair;
var useUncompressed = useBip38;
if (useUncompressed) {
keyPair = new bitcoinjs.bitcoin.ECPair(keyPair.d, null, { compressed: false });
}
var pubkey = key.getPublicKeyBuffer().toString('hex');
// get address
var address = keyPair.getAddress().toString();
// get privkey
var hasPrivkey = !key.isNeutered();
var privkey = "NA";
if (hasPrivkey) {
privkey = keyPair.toWIF(network);
// BIP38 encode private key if required
if (useBip38) {
privkey = bitcoinjsBip38.encrypt(keyPair.d.toBuffer(), false, bip38password, function(p) {
console.log("Progressed " + p.percent.toFixed(1) + "% for index " + index);
});
}
}
// get pubkey
var pubkey = keyPair.getPublicKeyBuffer().toString('hex');
var indexText = getDerivationPath() + "/" + index;
if (useHardenedAddresses) {
indexText = indexText + "'";
}
// Ethereum values are different
if (networks[DOM.network.val()].name == "ETH - Ethereum") {
var privKeyBuffer = key.keyPair.d.toBuffer();
var privKeyBuffer = keyPair.d.toBuffer(32);
privkey = privKeyBuffer.toString('hex');
var addressBuffer = ethUtil.privateToAddress(privKeyBuffer);
var hexAddress = addressBuffer.toString('hex');
@@ -1116,7 +1142,7 @@
function wordArrayToPhrase(words) {
var phrase = words.join(" ");
var language = getLanguageFromPhrase(phrase);
if (language == "japanese") {
if (language == "japanese" || language == "korean") {
phrase = words.join("\u3000");
}
return phrase;
@@ -1170,6 +1196,8 @@
DOM.phrase.val(phrase);
// Show the word indexes
showWordIndexes();
// Show the checksum
showChecksum();
}
function clearEntropyFeedback() {
@@ -1200,13 +1228,14 @@
var entropyTypeStr = getEntropyTypeStr(entropy);
var wordCount = Math.floor(numberOfBits / 32) * 3;
var bitsPerEvent = entropy.bitsPerEvent.toFixed(2);
var spacedBinaryStr = addSpacesEveryElevenBits(entropy.binaryStr);
DOM.entropyFiltered.html(entropy.cleanHtml);
DOM.entropyType.text(entropyTypeStr);
DOM.entropyCrackTime.text(timeToCrack);
DOM.entropyEventCount.text(entropy.base.ints.length);
DOM.entropyBits.text(numberOfBits);
DOM.entropyWordCount.text(wordCount);
DOM.entropyBinary.text(entropy.binaryStr);
DOM.entropyBinary.text(spacedBinaryStr);
DOM.entropyBitsPerEvent.text(bitsPerEvent);
// detect and warn of filtering
var rawNoSpaces = DOM.entropy.val().replace(/\s/g, "");
@@ -1431,6 +1460,35 @@
DOM.entropyWordIndexes.text(wordIndexesStr);
}
function showChecksum() {
var phrase = DOM.phrase.val();
var words = phraseToWordArray(phrase);
var checksumBitlength = words.length / 3;
var checksum = "";
var binaryStr = "";
var language = getLanguage();
for (var i=words.length-1; i>=0; i--) {
var word = words[i];
var wordIndex = WORDLISTS[language].indexOf(word);
var wordBinary = wordIndex.toString(2);
while (wordBinary.length < 11) {
wordBinary = "0" + wordBinary;
}
var binaryStr = wordBinary + binaryStr;
if (binaryStr.length >= checksumBitlength) {
var start = binaryStr.length - checksumBitlength;
var end = binaryStr.length;
checksum = binaryStr.substring(start, end);
// add spaces so the last group is 11 bits, not the first
checksum = checksum.split("").reverse().join("")
checksum = addSpacesEveryElevenBits(checksum);
checksum = checksum.split("").reverse().join("")
break;
}
}
DOM.entropyChecksum.text(checksum);
}
function updateCsv() {
var tableCsv = "path,address,public key,private key\n";
var rows = DOM.addresses.find("tr");
@@ -1451,7 +1509,19 @@
DOM.csv.val(tableCsv);
}
function addSpacesEveryElevenBits(binaryStr) {
return binaryStr.match(/.{1,11}/g).join(" ");
}
var networks = [
{
name: "AXE - Axe",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.axe;
setHdCoin(0);
},
},
{
name: "BCH - Bitcoin Cash",
segwitAvailable: false,
@@ -1461,6 +1531,14 @@
setHdCoin(145);
},
},
{
name: "BLK - BlackCoin",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.blackcoin;
setHdCoin(10);
},
},
{
name: "BTC - Bitcoin",
segwitAvailable: true,
@@ -1517,6 +1595,14 @@
setHdCoin(1);
},
},
{
name: "DNR - Denarius",
segwitAvailable: false,
onSelect: function() {
network = bitcoinjs.bitcoin.networks.denarius;
setHdCoin(116);
},
},
{
name: "DOGE - Dogecoin",
segwitAvailable: false,
@@ -1701,7 +1787,7 @@
network = bitcoinjs.bitcoin.networks.bitcoin;
setHdCoin(144);
},
}
},
]
var clients = [

View File

@@ -149,21 +149,14 @@ var Mnemonic = function(language) {
// Set space correctly depending on the language
// see https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md#japanese
var space = " ";
if (language == "japanese") {
if (language == "japanese" || language == "korean") {
space = "\u3000"; // ideographic space
}
return words.join(space);
}
self.normalizeString = function(str) {
if (typeof str.normalize == "function") {
return str.normalize("NFKD");
}
else {
// TODO decide how to handle this in the future.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
return str;
}
return str.normalize("NFKD");
}
function byteArrayToWordArray(data) {

View File

@@ -1,3 +1,6 @@
// Polyfill for NFKD normalization
// See https://github.com/walling/unorm
(function (root) {
"use strict";

2051
src/js/wordlist_korean.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -30,9 +30,10 @@ var until = webdriver.until;
var newDriver = null;
var driver = null;
// Delays in ms
var generateDelay = 1000;
var generateDelay = 1500;
var feedbackDelay = 500;
var entropyFeedbackDelay = 500;
var bip38delay = 15000;
// url uses file:// scheme
var path = require('path')
@@ -422,6 +423,13 @@ it('Allows selection of dogecoin', function(done) {
};
testNetwork(done, params);
});
it('Allows selection of denarius', function(done) {
var params = {
selectText: "DNR - Denarius",
firstAddress: "DFdFMVUMzU9xX88EywXvAGwjiwpxyh9vKb",
};
testNetwork(done, params);
});
it('Allows selection of shadowcash', function(done) {
var params = {
selectText: "SDC - ShadowCash",
@@ -605,6 +613,20 @@ it('Allows selection of monacoin', function(done) {
};
testNetwork(done, params);
});
it('Allows selection of AXE', function(done) {
var params = {
selectText: "AXE - Axe",
firstAddress: "XQ4HLxUVS3egk5ff1o9e2vJFJKSSsUH3B7",
};
testNetwork(done, params);
});
it('Allows selection of BlackCoin', function(done) {
var params = {
selectText: "BLK - BlackCoin",
firstAddress: "B5MznAKwj7uQ42vDz3w4onhBXPcqhTwJ9z",
};
testNetwork(done, params);
});
// BIP39 seed is set from phrase
it('Sets the bip39 seed from the prhase', function(done) {
@@ -933,13 +955,13 @@ it('Can generate more rows in the table', function(done) {
// A custom number of additional addresses can be generated
it('Can generate more rows in the table', function(done) {
driver.findElement(By.css('.rows-to-add'))
.clear();
driver.findElement(By.css('.rows-to-add'))
.sendKeys('1');
driver.findElement(By.css('.phrase'))
.sendKeys('abandon abandon ability');
driver.sleep(generateDelay).then(function() {
driver.findElement(By.css('.rows-to-add'))
.clear();
driver.findElement(By.css('.rows-to-add'))
.sendKeys('1');
driver.findElement(By.css('.more'))
.click();
driver.sleep(generateDelay).then(function() {
@@ -2159,10 +2181,11 @@ it('Can change details while old addresses are still being generated', function(
driver.findElement(By.css('.phrase'))
.sendKeys("abandon abandon ability");
driver.sleep(generateDelay).then(function() {
// generate more addresses
driver.findElement(By.css('.more'))
.click();
// change tabs which should cancel the previous generating
driver.findElement(By.css('.rows-to-add'))
.clear();
driver.findElement(By.css('.rows-to-add'))
.sendKeys('20');
driver.findElement(By.css('#bip32-tab a'))
.click()
driver.sleep(generateDelay).then(function() {
@@ -2175,7 +2198,7 @@ it('Can change details while old addresses are still being generated', function(
});
});
});
});
}, generateDelay + 5000);
// Github issue 49
// padding for binary should give length with multiple of 256
@@ -2850,4 +2873,85 @@ it('Can display the table as csv', function(done) {
});
});
it('LeftPads ethereum keys that are less than 32 bytes', function(done) {
// see https://github.com/iancoleman/bip39/issues/155
selectNetwork("ETH - Ethereum");
driver.findElement(By.css('#bip32-tab a'))
.click()
driver.findElement(By.css('#bip32-path'))
.clear();
driver.findElement(By.css('#bip32-path'))
.sendKeys("m/44'/60'/0'");
driver.findElement(By.css('.phrase'))
.sendKeys('scout sort custom elite radar rare vivid thing trophy gesture cover snake change narrow kite list nation sustain buffalo erode open balance system young');
driver.sleep(generateDelay).then(function() {
getFirstAddress(function(address) {
expect(address).toBe("0x8943E785B4a5714FC87a3aFAad1eB1FeB602B118");
done();
});
});
});
it('Can encrypt private keys using BIP38', function(done) {
// see https://github.com/iancoleman/bip39/issues/140
driver.executeScript(function() {
$(".use-bip38").prop("checked", true);
});
driver.findElement(By.css('.bip38-password'))
.sendKeys('bip38password');
driver.findElement(By.css('.rows-to-add'))
.clear();
driver.findElement(By.css('.rows-to-add'))
.sendKeys('1');
driver.findElement(By.css('.phrase'))
.sendKeys('abandon abandon ability');
driver.sleep(bip38delay).then(function() {
// address
getFirstRowValue(function(address) {
expect(address).toBe("1NCvSdumA3ngMM9c4aqU56AM6rqXddfuXB");
// pubkey
getFirstRowValue(function(pubkey) {
expect(pubkey).toBe("043f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3884a74447ea901729b1e73a999b7520e7cb55b4120e6432c64153ccab8a848e1");
// privkey
getFirstRowValue(function(privkey) {
expect(privkey).toBe("6PRNRiFnj1RoR3sXhymdCvoZCgnUHQpfupNdKkFbWJkwWQEKesWt1EDMDM");
done();
}, ".privkey");
}, ".pubkey");
}, ".address");
});
}, bip38delay + 5000);
it('Shows the checksum for the entropy', function(done) {
driver.findElement(By.css('.use-entropy'))
.click();
driver.findElement(By.css('.entropy'))
.sendKeys("00000000000000000000000000000000");
driver.sleep(generateDelay).then(function() {
driver.findElement(By.css('.checksum'))
.getText()
.then(function(text) {
expect(text).toBe("1");
done();
});
});
});
it('Shows the checksum for the entropy with the correct groupings', function(done) {
driver.findElement(By.css('.use-entropy'))
.click();
// create a checksum of 20 bits, which spans multiple words
driver.findElement(By.css('.entropy'))
.sendKeys("F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
driver.sleep(generateDelay).then(function() {
driver.findElement(By.css('.checksum'))
.getText()
.then(function(text) {
// first group is 9 bits, second group is 11
expect(text).toBe("011010111 01110000110");
done();
});
});
});
});