mirror of
https://github.com/OneKeyHQ/bip39.git
synced 2026-04-05 18:43:47 +00:00
Move from private repo
This commit is contained in:
22946
bip39-standalone.html
Normal file
22946
bip39-standalone.html
Normal file
File diff suppressed because one or more lines are too long
27
readme.md
Normal file
27
readme.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# BIP39 Tool
|
||||
|
||||
A tool for converting BIP39 mnemonic phrases to addresses and private keys.
|
||||
|
||||
## Online Version
|
||||
|
||||
Coming soon
|
||||
|
||||
## Standalone offline version
|
||||
|
||||
Download `bip39-standalone.html`
|
||||
|
||||
Open the file in a browser by double clicking it.
|
||||
|
||||
## Usage
|
||||
|
||||
Enter your BIP39 phrase into the 'BIP39 Phrase' field, or press
|
||||
'Generate Random Phrase'
|
||||
|
||||
If required, set the derivation path, although the defaults are quite usable.
|
||||
|
||||
See the table for a list of addresses generated from the phrase.
|
||||
|
||||
Toggle columns to blank to easily copy/paste a single column of data, eg to
|
||||
import private keys into a wallet or supply someone with a list of addresses.
|
||||
|
||||
The BIP32 keys can be used at [bip32.org](https://bip32.org) if desired.
|
||||
257
src/index.html
Normal file
257
src/index.html
Normal file
@@ -0,0 +1,257 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="utf-8" />
|
||||
<title>BIP39 - Mnemonic Code</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
|
||||
<meta content="Mnemonic code for generating deterministic keys" name="description"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||
<meta content="bitcoin mnemonic converter" name="description" />
|
||||
<meta content="DC POS" name="author" />
|
||||
|
||||
<style>
|
||||
.feedback-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
z-index: 4;
|
||||
}
|
||||
.feedback {
|
||||
display: table;
|
||||
padding: 0.5em 1em;
|
||||
background-color: orange;
|
||||
margin: 0 auto;
|
||||
font-size: 2em;
|
||||
color: #444;
|
||||
border: 2px solid #555;
|
||||
border-top: 0;
|
||||
border-bottom-left-radius: 20px 20px;
|
||||
border-bottom-right-radius: 20px 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
||||
<h1 class="text-center">Mnemonic Code Converter</h1>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2>Phrase</h2>
|
||||
<form class="form-horizontal" role="form">
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-10">
|
||||
<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>
|
||||
<div class="col-sm-10">
|
||||
<textarea id="phrase" class="phrase form-control"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="strength" class="col-sm-2 control-label">Number of words</label>
|
||||
<div class="col-sm-10">
|
||||
<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>
|
||||
</span>
|
||||
</div>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2>Derivation Path</h2>
|
||||
<ul class="derivation-type nav nav-tabs" role="tablist">
|
||||
<li class="active">
|
||||
<a href="#bip44" role="tab" data-toggle="tab">BIP44</a></li>
|
||||
<li><a href="#bip32" role="tab" data-toggle="tab">BIP32</a></li>
|
||||
</ul>
|
||||
<div class="derivation-type tab-content">
|
||||
<div id="bip44" class="tab-pane active">
|
||||
<form class="form-horizontal" role="form">
|
||||
<br>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-10">
|
||||
<p>For more info see the <a href="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki" target="_blank">BIP44 spec</a></p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="purpose" class="col-sm-2 control-label">
|
||||
<a href="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#purpose" target="_blank">Purpose</a>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="purpose" type="text" class="purpose form-control" value="44">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="coin" class="col-sm-2 control-label">
|
||||
<a href="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#registered-coin-types" target="_blank">Coin</a>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="coin" type="text" class="coin form-control" value="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="account" class="col-sm-2 control-label">
|
||||
<a href="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account" target="_blank">Account</a>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="account" type="text" class="account form-control" value="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="change" class="col-sm-2 control-label">
|
||||
<a href="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#change" target="_blank">External / Internal</a>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="change" type="text" class="change form-control" value="0">
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="bip32" class="tab-pane">
|
||||
<form class="form-horizontal" role="form">
|
||||
<br>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-10">
|
||||
<p>For more info see the <a href="https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki" target="_blank">BIP32 spec</a></p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="bip32-path" class="col-sm-2 control-label">BIP32 Derivation Path</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="bip32-path" type="text" class="path form-control" value="m/0">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<form class="form-horizontal" role="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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="feedback-container">
|
||||
<div class="feedback"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/template" id="address-row-template">
|
||||
<tr>
|
||||
<td class="index"><span></span></td>
|
||||
<td class="address"><span></span></td>
|
||||
<td class="privkey"><span></span></td>
|
||||
</tr>
|
||||
</script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
||||
<script src="/js/bitcoinjs-1-0-0.js"></script>
|
||||
<script src="/js/asmcrypto.js"></script>
|
||||
<script src="/js/jsbip39.js"></script>
|
||||
<script src="/js/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
7467
src/js/asmcrypto.js
Normal file
7467
src/js/asmcrypto.js
Normal file
File diff suppressed because one or more lines are too long
14463
src/js/bitcoinjs-1-0-0.js
Normal file
14463
src/js/bitcoinjs-1-0-0.js
Normal file
File diff suppressed because it is too large
Load Diff
337
src/js/index.js
Normal file
337
src/js/index.js
Normal file
@@ -0,0 +1,337 @@
|
||||
(function() {
|
||||
|
||||
var mnemonic = new Mnemonic("english");
|
||||
var bip32RootKey = null;
|
||||
var bip32ExtendedKey = null;
|
||||
var network = Bitcoin.networks.bitcoin;
|
||||
var addressRowTemplate = $("#address-row-template");
|
||||
|
||||
var phraseChangeTimeoutEvent = null;
|
||||
|
||||
var DOM = {};
|
||||
DOM.phrase = $(".phrase");
|
||||
DOM.generate = $(".generate");
|
||||
DOM.rootKey = $(".root-key");
|
||||
DOM.extendedPrivKey = $(".extended-priv-key");
|
||||
DOM.extendedPubKey = $(".extended-pub-key");
|
||||
DOM.bip32path = $("#bip32-path");
|
||||
DOM.bip44path = $("#bip44-path");
|
||||
DOM.bip44purpose = $("#bip44 .purpose");
|
||||
DOM.bip44coin = $("#bip44 .coin");
|
||||
DOM.bip44account = $("#bip44 .account");
|
||||
DOM.bip44change = $("#bip44 .change");
|
||||
DOM.strength = $(".strength");
|
||||
DOM.addresses = $(".addresses");
|
||||
DOM.rowsToAdd = $(".rows-to-add");
|
||||
DOM.more = $(".more");
|
||||
DOM.feedback = $(".feedback");
|
||||
DOM.tab = $(".derivation-type a");
|
||||
DOM.indexToggle = $(".index-toggle");
|
||||
DOM.addressToggle = $(".address-toggle");
|
||||
DOM.privateKeyToggle = $(".private-key-toggle");
|
||||
|
||||
var derivationPath = DOM.bip44path.val();
|
||||
|
||||
function init() {
|
||||
// Events
|
||||
DOM.phrase.on("keyup", 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.tab.on("click", tabClicked);
|
||||
DOM.indexToggle.on("click", toggleIndexes);
|
||||
DOM.addressToggle.on("click", toggleAddresses);
|
||||
DOM.privateKeyToggle.on("click", togglePrivateKeys);
|
||||
disableForms();
|
||||
hidePending();
|
||||
hideValidationError();
|
||||
}
|
||||
|
||||
// Event handlers
|
||||
|
||||
function delayedPhraseChanged() {
|
||||
hideValidationError();
|
||||
showPending();
|
||||
if (phraseChangeTimeoutEvent != null) {
|
||||
clearTimeout(phraseChangeTimeoutEvent);
|
||||
}
|
||||
phraseChangeTimeoutEvent = setTimeout(phraseChanged, 400);
|
||||
}
|
||||
|
||||
function phraseChanged() {
|
||||
showPending();
|
||||
hideValidationError();
|
||||
// Get the mnemonic phrase
|
||||
var phrase = DOM.phrase.val();
|
||||
var errorText = findPhraseErrors(phrase);
|
||||
if (errorText) {
|
||||
showValidationError(errorText);
|
||||
return;
|
||||
}
|
||||
// Get the derivation path
|
||||
var errorText = findDerivationPathErrors();
|
||||
if (errorText) {
|
||||
showValidationError(errorText);
|
||||
return;
|
||||
}
|
||||
// Calculate and display
|
||||
calcBip32Seed(phrase, derivationPath);
|
||||
displayBip32Info();
|
||||
hidePending();
|
||||
}
|
||||
|
||||
function generateClicked() {
|
||||
clearDisplay();
|
||||
showPending();
|
||||
setTimeout(function() {
|
||||
var phrase = generateRandomPhrase();
|
||||
if (!phrase) {
|
||||
return;
|
||||
}
|
||||
phraseChanged();
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function tabClicked(e) {
|
||||
var activePath = $(e.target.getAttribute("href") + " .path");
|
||||
derivationPath = activePath.val();
|
||||
derivationChanged();
|
||||
}
|
||||
|
||||
function derivationChanged() {
|
||||
delayedPhraseChanged();
|
||||
}
|
||||
|
||||
function bip32Changed() {
|
||||
derivationPath = DOM.bip32path.val();
|
||||
derivationChanged();
|
||||
}
|
||||
|
||||
function bip44Changed() {
|
||||
setBip44DerivationPath();
|
||||
derivationPath = DOM.bip44path.val();
|
||||
derivationChanged();
|
||||
}
|
||||
|
||||
function toggleIndexes() {
|
||||
$("td.index span").toggleClass("invisible");
|
||||
}
|
||||
|
||||
function toggleAddresses() {
|
||||
$("td.address span").toggleClass("invisible");
|
||||
}
|
||||
|
||||
function togglePrivateKeys() {
|
||||
$("td.privkey span").toggleClass("invisible");
|
||||
}
|
||||
|
||||
// Private methods
|
||||
|
||||
function generateRandomPhrase() {
|
||||
if (!hasStrongRandom()) {
|
||||
var errorText = "This browser does not support strong randomness";
|
||||
showValidationError(errorText);
|
||||
return;
|
||||
}
|
||||
var numWords = parseInt(DOM.strength.val());
|
||||
// Check strength is an integer
|
||||
if (isNaN(numWords)) {
|
||||
DOM.strength.val("12");
|
||||
numWords = 12;
|
||||
}
|
||||
// Check strength is a multiple of 32, if not round it down
|
||||
if (numWords % 3 != 0) {
|
||||
numWords = Math.floor(numWords / 3) * 3;
|
||||
DOM.strength.val(numWords);
|
||||
}
|
||||
// Check strength is at least 32
|
||||
if (numWords == 0) {
|
||||
numWords = 3;
|
||||
DOM.strength.val(numWords);
|
||||
}
|
||||
var strength = numWords / 3 * 32;
|
||||
var words = mnemonic.generate(strength);
|
||||
DOM.phrase.val(words);
|
||||
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);
|
||||
bip32ExtendedKey = bip32RootKey;
|
||||
// Derive the key from the path
|
||||
var pathBits = path.split("/");
|
||||
for (var i=0; i<pathBits.length; i++) {
|
||||
var bit = pathBits[i];
|
||||
var index = parseInt(bit);
|
||||
if (isNaN(index)) {
|
||||
continue;
|
||||
}
|
||||
var hardened = bit[bit.length-1] == "'";
|
||||
if (hardened) {
|
||||
bip32ExtendedKey = bip32ExtendedKey.deriveHardened(index);
|
||||
}
|
||||
else {
|
||||
bip32ExtendedKey = bip32ExtendedKey.derive(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showValidationError(errorText) {
|
||||
DOM.feedback
|
||||
.text(errorText)
|
||||
.show();
|
||||
}
|
||||
|
||||
function hideValidationError() {
|
||||
DOM.feedback
|
||||
.text("")
|
||||
.hide();
|
||||
}
|
||||
|
||||
function findPhraseErrors(phrase) {
|
||||
// TODO make this right
|
||||
// Preprocess the words
|
||||
var parts = phrase.split(" ");
|
||||
var proper = [];
|
||||
for (var i=0; i<parts.length; i++) {
|
||||
var part = parts[i];
|
||||
if (part.length > 0) {
|
||||
// TODO check that lowercasing is always valid to do
|
||||
proper.push(part.toLowerCase());
|
||||
}
|
||||
}
|
||||
// TODO some levenstein on the words
|
||||
var properPhrase = proper.join(' ');
|
||||
// Check the words are valid
|
||||
var isValid = mnemonic.check(properPhrase);
|
||||
if (!isValid) {
|
||||
return "Invalid mnemonic";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function findDerivationPathErrors(path) {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
function displayBip32Info() {
|
||||
// Display the key
|
||||
var rootKey = bip32RootKey.toBase58();
|
||||
DOM.rootKey.val(rootKey);
|
||||
var extendedPrivKey = bip32ExtendedKey.toBase58();
|
||||
DOM.extendedPrivKey.val(extendedPrivKey);
|
||||
var extendedPubKey = bip32ExtendedKey.toBase58(false);
|
||||
DOM.extendedPubKey.val(extendedPubKey);
|
||||
// Display the addresses and privkeys
|
||||
clearAddressesList();
|
||||
displayAddresses(0, 20);
|
||||
}
|
||||
|
||||
function displayAddresses(start, total) {
|
||||
for (var i=0; i<total; i++) {
|
||||
var index = i+ start;
|
||||
var key = bip32ExtendedKey.derive(index);
|
||||
var address = key.getAddress().toString();
|
||||
var privkey = key.privKey.toWIF();
|
||||
addAddressToList(index, address, privkey);
|
||||
}
|
||||
}
|
||||
|
||||
function showMore() {
|
||||
var start = DOM.addresses.children().length;
|
||||
var rowsToAdd = parseInt(DOM.rowsToAdd.val());
|
||||
if (isNaN(rowsToAdd)) {
|
||||
rowsToAdd = 20;
|
||||
DOM.rowsToAdd.val("20");
|
||||
}
|
||||
if (rowsToAdd > 200) {
|
||||
var msg = "Generating " + rowsToAdd + " rows could take a while. ";
|
||||
msg += "Do you want to continue?";
|
||||
if (!confirm(msg)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
showPending();
|
||||
setTimeout(function() {
|
||||
displayAddresses(start, rowsToAdd);
|
||||
hidePending();
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function clearDisplay() {
|
||||
clearAddressesList();
|
||||
clearKey();
|
||||
hideValidationError();
|
||||
}
|
||||
|
||||
function clearAddressesList() {
|
||||
DOM.addresses.empty();
|
||||
}
|
||||
|
||||
function clearKey() {
|
||||
DOM.rootKey.val("");
|
||||
DOM.extendedPrivKey.val("");
|
||||
DOM.extendedPubKey.val("");
|
||||
}
|
||||
|
||||
function addAddressToList(index, address, privkey) {
|
||||
var row = $(addressRowTemplate.html());
|
||||
row.find(".index span").text(index);
|
||||
row.find(".address span").text(address);
|
||||
row.find(".privkey span").text(privkey);
|
||||
DOM.addresses.append(row);
|
||||
}
|
||||
|
||||
function hasStrongRandom() {
|
||||
return 'crypto' in window && window['crypto'] !== null;
|
||||
}
|
||||
|
||||
function disableForms() {
|
||||
$("form").on("submit", function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
function setBip44DerivationPath() {
|
||||
var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44);
|
||||
var coin = parseIntNoNaN(DOM.bip44coin.val(), 0);
|
||||
var account = parseIntNoNaN(DOM.bip44account.val(), 0);
|
||||
var change = parseIntNoNaN(DOM.bip44change.val(), 0);
|
||||
var path = "m/";
|
||||
path += purpose + "'/";
|
||||
path += coin + "'/";
|
||||
path += account + "'/";
|
||||
path += change;
|
||||
DOM.bip44path.val(path);
|
||||
}
|
||||
|
||||
function parseIntNoNaN(val, defaultVal) {
|
||||
var v = parseInt(val);
|
||||
if (isNaN(v)) {
|
||||
return defaultVal;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
function showPending() {
|
||||
DOM.feedback
|
||||
.text("Calculating...")
|
||||
.show();
|
||||
}
|
||||
|
||||
function hidePending() {
|
||||
DOM.feedback
|
||||
.text("")
|
||||
.hide();
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
})();
|
||||
386
src/js/jsbip39.js
Normal file
386
src/js/jsbip39.js
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Pavol Rusnak
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Javascript port from python by Ian Coleman
|
||||
*
|
||||
* Includes code from asmCrypto
|
||||
* https://github.com/tresorit/asmcrypto.js
|
||||
*/
|
||||
|
||||
var Mnemonic = function(language) {
|
||||
|
||||
var PBKDF2_ROUNDS = 2048;
|
||||
var RADIX = 2048;
|
||||
|
||||
var self = this;
|
||||
var wordlist = [];
|
||||
|
||||
function init() {
|
||||
wordlist = WORDLISTS[language];
|
||||
if (wordlist.length != RADIX) {
|
||||
err = 'Wordlist should contain ' + RADIX + ' words, but it contains ' + wordlist.length + ' words.';
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
self.generate = function(strength) {
|
||||
strength = strength || 128;
|
||||
var r = strength % 32;
|
||||
if (r > 0) {
|
||||
throw 'Strength should be divisible by 32, but it is not (' + r + ').';
|
||||
}
|
||||
var hasStrongCrypto = 'crypto' in window && window['crypto'] !== null;
|
||||
if (!hasStrongCrypto) {
|
||||
throw 'Mnemonic should be generated with strong randomness, but crypto.getRandomValues is unavailable';
|
||||
}
|
||||
var buffer = new Uint8Array(strength / 8);
|
||||
var data = crypto.getRandomValues(buffer);
|
||||
return self.toMnemonic(data);
|
||||
}
|
||||
|
||||
self.toMnemonic = function(data) {
|
||||
if (data.length % 4 > 0) {
|
||||
throw 'Data length in bits should be divisible by 32, but it is not (' + data.length + ' bytes = ' + data.length*8 + ' bits).'
|
||||
}
|
||||
|
||||
//h = hashlib.sha256(data).hexdigest()
|
||||
var uintArray = new Uint8Array(data);
|
||||
var h = asmCrypto.SHA256.bytes(uintArray);
|
||||
|
||||
// b is a binary string, eg '00111010101100...'
|
||||
//b = bin(int(binascii.hexlify(data), 16))[2:].zfill(len(data) * 8) + \
|
||||
// bin(int(h, 16))[2:].zfill(256)[:len(data) * 8 / 32]
|
||||
//
|
||||
// a = bin(int(binascii.hexlify(data), 16))[2:].zfill(len(data) * 8)
|
||||
// c = bin(int(h, 16))[2:].zfill(256)
|
||||
// d = c[:len(data) * 8 / 32]
|
||||
var a = byteArrayToBinaryString(data);
|
||||
var c = byteArrayToBinaryString(h);
|
||||
var d = c.substring(0, data.length * 8 / 32);
|
||||
// b = line1 + line2
|
||||
var b = a + d;
|
||||
|
||||
var result = [];
|
||||
var blen = b.length / 11;
|
||||
for (var i=0; i<blen; i++) {
|
||||
var idx = parseInt(b.substring(i * 11, (i + 1) * 11), 2);
|
||||
result.push(wordlist[idx]);
|
||||
}
|
||||
return result.join(' ');
|
||||
}
|
||||
|
||||
self.check = function(mnemonic) {
|
||||
var mnemonic = mnemonic.split(' ')
|
||||
if (mnemonic.length % 3 > 0) {
|
||||
return false
|
||||
}
|
||||
// idx = map(lambda x: bin(self.wordlist.index(x))[2:].zfill(11), mnemonic)
|
||||
var idx = [];
|
||||
for (var i=0; i<mnemonic.length; i++) {
|
||||
var word = mnemonic[i];
|
||||
var wordIndex = wordlist.indexOf(word);
|
||||
if (wordIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
var binaryIndex = zfill(wordIndex.toString(2), 11);
|
||||
idx.push(binaryIndex);
|
||||
}
|
||||
var b = idx.join('');
|
||||
var l = b.length;
|
||||
//d = b[:l / 33 * 32]
|
||||
//h = b[-l / 33:]
|
||||
var d = b.substring(0, l / 33 * 32);
|
||||
var h = b.substring(l - l / 33, l);
|
||||
//nd = binascii.unhexlify(hex(int(d, 2))[2:].rstrip('L').zfill(l / 33 * 8))
|
||||
//nh = bin(int(hashlib.sha256(nd).hexdigest(), 16))[2:].zfill(256)[:l / 33]
|
||||
var nd = binaryStringToByteArray(d);
|
||||
var ndHash = asmCrypto.SHA256.bytes(nd);
|
||||
var ndBstr = zfill(byteArrayToBinaryString(ndHash), 256);
|
||||
var nh = ndBstr.substring(0,l/33);
|
||||
return h == nh;
|
||||
}
|
||||
|
||||
self.toSeed = function(mnemonic, passphrase) {
|
||||
passphrase = passphrase || '';
|
||||
mnemonic = normalizeString(mnemonic)
|
||||
passphrase = 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) {
|
||||
if (typeof str.normalize == "function") {
|
||||
return str.normalize("NFKD");
|
||||
}
|
||||
else {
|
||||
// TODO find a library to do this
|
||||
// Not supported on firefox mobile
|
||||
console.warn("NFKD Normalization is unavailable");
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
function byteArrayToBinaryString(data) {
|
||||
var bin = "";
|
||||
for (var i=0; i<data.length; i++) {
|
||||
bin += zfill(data[i].toString(2), 8);
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
|
||||
function binaryStringToByteArray(str) {
|
||||
var arrayLen = str.length / 8;
|
||||
var array = new Uint8Array(arrayLen);
|
||||
for (var i=0; i<arrayLen; i++) {
|
||||
var valueStr = str.substring(0,8);
|
||||
var value = parseInt(valueStr, 2);
|
||||
array[i] = value;
|
||||
str = str.slice(8);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
// Pad a numeric string on the left with zero digits until the given width
|
||||
// is reached.
|
||||
// Note this differs to the python implementation because it does not
|
||||
// handle numbers starting with a sign.
|
||||
function zfill(source, length) {
|
||||
source = source.toString();
|
||||
while (source.length < length) {
|
||||
source = '0' + source;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
}
|
||||
|
||||
WORDLISTS = {
|
||||
"english": [
|
||||
"abandon","ability","able","about","above","absent","absorb","abstract","absurd","abuse",
|
||||
"access","accident","account","accuse","achieve","acid","acoustic","acquire","across","act",
|
||||
"action","actor","actress","actual","adapt","add","addict","address","adjust","admit",
|
||||
"adult","advance","advice","aerobic","affair","afford","afraid","again","age","agent",
|
||||
"agree","ahead","aim","air","airport","aisle","alarm","album","alcohol","alert",
|
||||
"alien","all","alley","allow","almost","alone","alpha","already","also","alter",
|
||||
"always","amateur","amazing","among","amount","amused","analyst","anchor","ancient","anger",
|
||||
"angle","angry","animal","ankle","announce","annual","another","answer","antenna","antique",
|
||||
"anxiety","any","apart","apology","appear","apple","approve","april","arch","arctic",
|
||||
"area","arena","argue","arm","armed","armor","army","around","arrange","arrest",
|
||||
"arrive","arrow","art","artefact","artist","artwork","ask","aspect","assault","asset",
|
||||
"assist","assume","asthma","athlete","atom","attack","attend","attitude","attract","auction",
|
||||
"audit","august","aunt","author","auto","autumn","average","avocado","avoid","awake",
|
||||
"aware","away","awesome","awful","awkward","axis","baby","bachelor","bacon","badge",
|
||||
"bag","balance","balcony","ball","bamboo","banana","banner","bar","barely","bargain",
|
||||
"barrel","base","basic","basket","battle","beach","bean","beauty","because","become",
|
||||
"beef","before","begin","behave","behind","believe","below","belt","bench","benefit",
|
||||
"best","betray","better","between","beyond","bicycle","bid","bike","bind","biology",
|
||||
"bird","birth","bitter","black","blade","blame","blanket","blast","bleak","bless",
|
||||
"blind","blood","blossom","blouse","blue","blur","blush","board","boat","body",
|
||||
"boil","bomb","bone","bonus","book","boost","border","boring","borrow","boss",
|
||||
"bottom","bounce","box","boy","bracket","brain","brand","brass","brave","bread",
|
||||
"breeze","brick","bridge","brief","bright","bring","brisk","broccoli","broken","bronze",
|
||||
"broom","brother","brown","brush","bubble","buddy","budget","buffalo","build","bulb",
|
||||
"bulk","bullet","bundle","bunker","burden","burger","burst","bus","business","busy",
|
||||
"butter","buyer","buzz","cabbage","cabin","cable","cactus","cage","cake","call",
|
||||
"calm","camera","camp","can","canal","cancel","candy","cannon","canoe","canvas",
|
||||
"canyon","capable","capital","captain","car","carbon","card","cargo","carpet","carry",
|
||||
"cart","case","cash","casino","castle","casual","cat","catalog","catch","category",
|
||||
"cattle","caught","cause","caution","cave","ceiling","celery","cement","census","century",
|
||||
"cereal","certain","chair","chalk","champion","change","chaos","chapter","charge","chase",
|
||||
"chat","cheap","check","cheese","chef","cherry","chest","chicken","chief","child",
|
||||
"chimney","choice","choose","chronic","chuckle","chunk","churn","cigar","cinnamon","circle",
|
||||
"citizen","city","civil","claim","clap","clarify","claw","clay","clean","clerk",
|
||||
"clever","click","client","cliff","climb","clinic","clip","clock","clog","close",
|
||||
"cloth","cloud","clown","club","clump","cluster","clutch","coach","coast","coconut",
|
||||
"code","coffee","coil","coin","collect","color","column","combine","come","comfort",
|
||||
"comic","common","company","concert","conduct","confirm","congress","connect","consider","control",
|
||||
"convince","cook","cool","copper","copy","coral","core","corn","correct","cost",
|
||||
"cotton","couch","country","couple","course","cousin","cover","coyote","crack","cradle",
|
||||
"craft","cram","crane","crash","crater","crawl","crazy","cream","credit","creek",
|
||||
"crew","cricket","crime","crisp","critic","crop","cross","crouch","crowd","crucial",
|
||||
"cruel","cruise","crumble","crunch","crush","cry","crystal","cube","culture","cup",
|
||||
"cupboard","curious","current","curtain","curve","cushion","custom","cute","cycle","dad",
|
||||
"damage","damp","dance","danger","daring","dash","daughter","dawn","day","deal",
|
||||
"debate","debris","decade","december","decide","decline","decorate","decrease","deer","defense",
|
||||
"define","defy","degree","delay","deliver","demand","demise","denial","dentist","deny",
|
||||
"depart","depend","deposit","depth","deputy","derive","describe","desert","design","desk",
|
||||
"despair","destroy","detail","detect","develop","device","devote","diagram","dial","diamond",
|
||||
"diary","dice","diesel","diet","differ","digital","dignity","dilemma","dinner","dinosaur",
|
||||
"direct","dirt","disagree","discover","disease","dish","dismiss","disorder","display","distance",
|
||||
"divert","divide","divorce","dizzy","doctor","document","dog","doll","dolphin","domain",
|
||||
"donate","donkey","donor","door","dose","double","dove","draft","dragon","drama",
|
||||
"drastic","draw","dream","dress","drift","drill","drink","drip","drive","drop",
|
||||
"drum","dry","duck","dumb","dune","during","dust","dutch","duty","dwarf",
|
||||
"dynamic","eager","eagle","early","earn","earth","easily","east","easy","echo",
|
||||
"ecology","economy","edge","edit","educate","effort","egg","eight","either","elbow",
|
||||
"elder","electric","elegant","element","elephant","elevator","elite","else","embark","embody",
|
||||
"embrace","emerge","emotion","employ","empower","empty","enable","enact","end","endless",
|
||||
"endorse","enemy","energy","enforce","engage","engine","enhance","enjoy","enlist","enough",
|
||||
"enrich","enroll","ensure","enter","entire","entry","envelope","episode","equal","equip",
|
||||
"era","erase","erode","erosion","error","erupt","escape","essay","essence","estate",
|
||||
"eternal","ethics","evidence","evil","evoke","evolve","exact","example","excess","exchange",
|
||||
"excite","exclude","excuse","execute","exercise","exhaust","exhibit","exile","exist","exit",
|
||||
"exotic","expand","expect","expire","explain","expose","express","extend","extra","eye",
|
||||
"eyebrow","fabric","face","faculty","fade","faint","faith","fall","false","fame",
|
||||
"family","famous","fan","fancy","fantasy","farm","fashion","fat","fatal","father",
|
||||
"fatigue","fault","favorite","feature","february","federal","fee","feed","feel","female",
|
||||
"fence","festival","fetch","fever","few","fiber","fiction","field","figure","file",
|
||||
"film","filter","final","find","fine","finger","finish","fire","firm","first",
|
||||
"fiscal","fish","fit","fitness","fix","flag","flame","flash","flat","flavor",
|
||||
"flee","flight","flip","float","flock","floor","flower","fluid","flush","fly",
|
||||
"foam","focus","fog","foil","fold","follow","food","foot","force","forest",
|
||||
"forget","fork","fortune","forum","forward","fossil","foster","found","fox","fragile",
|
||||
"frame","frequent","fresh","friend","fringe","frog","front","frost","frown","frozen",
|
||||
"fruit","fuel","fun","funny","furnace","fury","future","gadget","gain","galaxy",
|
||||
"gallery","game","gap","garage","garbage","garden","garlic","garment","gas","gasp",
|
||||
"gate","gather","gauge","gaze","general","genius","genre","gentle","genuine","gesture",
|
||||
"ghost","giant","gift","giggle","ginger","giraffe","girl","give","glad","glance",
|
||||
"glare","glass","glide","glimpse","globe","gloom","glory","glove","glow","glue",
|
||||
"goat","goddess","gold","good","goose","gorilla","gospel","gossip","govern","gown",
|
||||
"grab","grace","grain","grant","grape","grass","gravity","great","green","grid",
|
||||
"grief","grit","grocery","group","grow","grunt","guard","guess","guide","guilt",
|
||||
"guitar","gun","gym","habit","hair","half","hammer","hamster","hand","happy",
|
||||
"harbor","hard","harsh","harvest","hat","have","hawk","hazard","head","health",
|
||||
"heart","heavy","hedgehog","height","hello","helmet","help","hen","hero","hidden",
|
||||
"high","hill","hint","hip","hire","history","hobby","hockey","hold","hole",
|
||||
"holiday","hollow","home","honey","hood","hope","horn","horror","horse","hospital",
|
||||
"host","hotel","hour","hover","hub","huge","human","humble","humor","hundred",
|
||||
"hungry","hunt","hurdle","hurry","hurt","husband","hybrid","ice","icon","idea",
|
||||
"identify","idle","ignore","ill","illegal","illness","image","imitate","immense","immune",
|
||||
"impact","impose","improve","impulse","inch","include","income","increase","index","indicate",
|
||||
"indoor","industry","infant","inflict","inform","inhale","inherit","initial","inject","injury",
|
||||
"inmate","inner","innocent","input","inquiry","insane","insect","inside","inspire","install",
|
||||
"intact","interest","into","invest","invite","involve","iron","island","isolate","issue",
|
||||
"item","ivory","jacket","jaguar","jar","jazz","jealous","jeans","jelly","jewel",
|
||||
"job","join","joke","journey","joy","judge","juice","jump","jungle","junior",
|
||||
"junk","just","kangaroo","keen","keep","ketchup","key","kick","kid","kidney",
|
||||
"kind","kingdom","kiss","kit","kitchen","kite","kitten","kiwi","knee","knife",
|
||||
"knock","know","lab","label","labor","ladder","lady","lake","lamp","language",
|
||||
"laptop","large","later","latin","laugh","laundry","lava","law","lawn","lawsuit",
|
||||
"layer","lazy","leader","leaf","learn","leave","lecture","left","leg","legal",
|
||||
"legend","leisure","lemon","lend","length","lens","leopard","lesson","letter","level",
|
||||
"liar","liberty","library","license","life","lift","light","like","limb","limit",
|
||||
"link","lion","liquid","list","little","live","lizard","load","loan","lobster",
|
||||
"local","lock","logic","lonely","long","loop","lottery","loud","lounge","love",
|
||||
"loyal","lucky","luggage","lumber","lunar","lunch","luxury","lyrics","machine","mad",
|
||||
"magic","magnet","maid","mail","main","major","make","mammal","man","manage",
|
||||
"mandate","mango","mansion","manual","maple","marble","march","margin","marine","market",
|
||||
"marriage","mask","mass","master","match","material","math","matrix","matter","maximum",
|
||||
"maze","meadow","mean","measure","meat","mechanic","medal","media","melody","melt",
|
||||
"member","memory","mention","menu","mercy","merge","merit","merry","mesh","message",
|
||||
"metal","method","middle","midnight","milk","million","mimic","mind","minimum","minor",
|
||||
"minute","miracle","mirror","misery","miss","mistake","mix","mixed","mixture","mobile",
|
||||
"model","modify","mom","moment","monitor","monkey","monster","month","moon","moral",
|
||||
"more","morning","mosquito","mother","motion","motor","mountain","mouse","move","movie",
|
||||
"much","muffin","mule","multiply","muscle","museum","mushroom","music","must","mutual",
|
||||
"myself","mystery","myth","naive","name","napkin","narrow","nasty","nation","nature",
|
||||
"near","neck","need","negative","neglect","neither","nephew","nerve","nest","net",
|
||||
"network","neutral","never","news","next","nice","night","noble","noise","nominee",
|
||||
"noodle","normal","north","nose","notable","note","nothing","notice","novel","now",
|
||||
"nuclear","number","nurse","nut","oak","obey","object","oblige","obscure","observe",
|
||||
"obtain","obvious","occur","ocean","october","odor","off","offer","office","often",
|
||||
"oil","okay","old","olive","olympic","omit","once","one","onion","online",
|
||||
"only","open","opera","opinion","oppose","option","orange","orbit","orchard","order",
|
||||
"ordinary","organ","orient","original","orphan","ostrich","other","outdoor","outer","output",
|
||||
"outside","oval","oven","over","own","owner","oxygen","oyster","ozone","pact",
|
||||
"paddle","page","pair","palace","palm","panda","panel","panic","panther","paper",
|
||||
"parade","parent","park","parrot","party","pass","patch","path","patient","patrol",
|
||||
"pattern","pause","pave","payment","peace","peanut","pear","peasant","pelican","pen",
|
||||
"penalty","pencil","people","pepper","perfect","permit","person","pet","phone","photo",
|
||||
"phrase","physical","piano","picnic","picture","piece","pig","pigeon","pill","pilot",
|
||||
"pink","pioneer","pipe","pistol","pitch","pizza","place","planet","plastic","plate",
|
||||
"play","please","pledge","pluck","plug","plunge","poem","poet","point","polar",
|
||||
"pole","police","pond","pony","pool","popular","portion","position","possible","post",
|
||||
"potato","pottery","poverty","powder","power","practice","praise","predict","prefer","prepare",
|
||||
"present","pretty","prevent","price","pride","primary","print","priority","prison","private",
|
||||
"prize","problem","process","produce","profit","program","project","promote","proof","property",
|
||||
"prosper","protect","proud","provide","public","pudding","pull","pulp","pulse","pumpkin",
|
||||
"punch","pupil","puppy","purchase","purity","purpose","purse","push","put","puzzle",
|
||||
"pyramid","quality","quantum","quarter","question","quick","quit","quiz","quote","rabbit",
|
||||
"raccoon","race","rack","radar","radio","rail","rain","raise","rally","ramp",
|
||||
"ranch","random","range","rapid","rare","rate","rather","raven","raw","razor",
|
||||
"ready","real","reason","rebel","rebuild","recall","receive","recipe","record","recycle",
|
||||
"reduce","reflect","reform","refuse","region","regret","regular","reject","relax","release",
|
||||
"relief","rely","remain","remember","remind","remove","render","renew","rent","reopen",
|
||||
"repair","repeat","replace","report","require","rescue","resemble","resist","resource","response",
|
||||
"result","retire","retreat","return","reunion","reveal","review","reward","rhythm","rib",
|
||||
"ribbon","rice","rich","ride","ridge","rifle","right","rigid","ring","riot",
|
||||
"ripple","risk","ritual","rival","river","road","roast","robot","robust","rocket",
|
||||
"romance","roof","rookie","room","rose","rotate","rough","round","route","royal",
|
||||
"rubber","rude","rug","rule","run","runway","rural","sad","saddle","sadness",
|
||||
"safe","sail","salad","salmon","salon","salt","salute","same","sample","sand",
|
||||
"satisfy","satoshi","sauce","sausage","save","say","scale","scan","scare","scatter",
|
||||
"scene","scheme","school","science","scissors","scorpion","scout","scrap","screen","script",
|
||||
"scrub","sea","search","season","seat","second","secret","section","security","seed",
|
||||
"seek","segment","select","sell","seminar","senior","sense","sentence","series","service",
|
||||
"session","settle","setup","seven","shadow","shaft","shallow","share","shed","shell",
|
||||
"sheriff","shield","shift","shine","ship","shiver","shock","shoe","shoot","shop",
|
||||
"short","shoulder","shove","shrimp","shrug","shuffle","shy","sibling","sick","side",
|
||||
"siege","sight","sign","silent","silk","silly","silver","similar","simple","since",
|
||||
"sing","siren","sister","situate","six","size","skate","sketch","ski","skill",
|
||||
"skin","skirt","skull","slab","slam","sleep","slender","slice","slide","slight",
|
||||
"slim","slogan","slot","slow","slush","small","smart","smile","smoke","smooth",
|
||||
"snack","snake","snap","sniff","snow","soap","soccer","social","sock","soda",
|
||||
"soft","solar","soldier","solid","solution","solve","someone","song","soon","sorry",
|
||||
"sort","soul","sound","soup","source","south","space","spare","spatial","spawn",
|
||||
"speak","special","speed","spell","spend","sphere","spice","spider","spike","spin",
|
||||
"spirit","split","spoil","sponsor","spoon","sport","spot","spray","spread","spring",
|
||||
"spy","square","squeeze","squirrel","stable","stadium","staff","stage","stairs","stamp",
|
||||
"stand","start","state","stay","steak","steel","stem","step","stereo","stick",
|
||||
"still","sting","stock","stomach","stone","stool","story","stove","strategy","street",
|
||||
"strike","strong","struggle","student","stuff","stumble","style","subject","submit","subway",
|
||||
"success","such","sudden","suffer","sugar","suggest","suit","summer","sun","sunny",
|
||||
"sunset","super","supply","supreme","sure","surface","surge","surprise","surround","survey",
|
||||
"suspect","sustain","swallow","swamp","swap","swarm","swear","sweet","swift","swim",
|
||||
"swing","switch","sword","symbol","symptom","syrup","system","table","tackle","tag",
|
||||
"tail","talent","talk","tank","tape","target","task","taste","tattoo","taxi",
|
||||
"teach","team","tell","ten","tenant","tennis","tent","term","test","text",
|
||||
"thank","that","theme","then","theory","there","they","thing","this","thought",
|
||||
"three","thrive","throw","thumb","thunder","ticket","tide","tiger","tilt","timber",
|
||||
"time","tiny","tip","tired","tissue","title","toast","tobacco","today","toddler",
|
||||
"toe","together","toilet","token","tomato","tomorrow","tone","tongue","tonight","tool",
|
||||
"tooth","top","topic","topple","torch","tornado","tortoise","toss","total","tourist",
|
||||
"toward","tower","town","toy","track","trade","traffic","tragic","train","transfer",
|
||||
"trap","trash","travel","tray","treat","tree","trend","trial","tribe","trick",
|
||||
"trigger","trim","trip","trophy","trouble","truck","true","truly","trumpet","trust",
|
||||
"truth","try","tube","tuition","tumble","tuna","tunnel","turkey","turn","turtle",
|
||||
"twelve","twenty","twice","twin","twist","two","type","typical","ugly","umbrella",
|
||||
"unable","unaware","uncle","uncover","under","undo","unfair","unfold","unhappy","uniform",
|
||||
"unique","unit","universe","unknown","unlock","until","unusual","unveil","update","upgrade",
|
||||
"uphold","upon","upper","upset","urban","urge","usage","use","used","useful",
|
||||
"useless","usual","utility","vacant","vacuum","vague","valid","valley","valve","van",
|
||||
"vanish","vapor","various","vast","vault","vehicle","velvet","vendor","venture","venue",
|
||||
"verb","verify","version","very","vessel","veteran","viable","vibrant","vicious","victory",
|
||||
"video","view","village","vintage","violin","virtual","virus","visa","visit","visual",
|
||||
"vital","vivid","vocal","voice","void","volcano","volume","vote","voyage","wage",
|
||||
"wagon","wait","walk","wall","walnut","want","warfare","warm","warrior","wash",
|
||||
"wasp","waste","water","wave","way","wealth","weapon","wear","weasel","weather",
|
||||
"web","wedding","weekend","weird","welcome","west","wet","whale","what","wheat",
|
||||
"wheel","when","where","whip","whisper","wide","width","wife","wild","will",
|
||||
"win","window","wine","wing","wink","winner","winter","wire","wisdom","wise",
|
||||
"wish","witness","wolf","woman","wonder","wood","wool","word","work","world",
|
||||
"worry","worth","wrap","wreck","wrestle","wrist","write","wrong","yard","year",
|
||||
"yellow","you","young","youth","zebra","zero","zone","zoo"]
|
||||
};
|
||||
Reference in New Issue
Block a user