Initial from bip32.github.io

This commit is contained in:
Thibaud
2024-08-21 09:55:33 +02:00
commit 73bc8bbfea
26 changed files with 5011 additions and 0 deletions

1
CNAME Normal file
View File

@@ -0,0 +1 @@
bip32.org

1
LICENSE Normal file
View File

@@ -0,0 +1 @@
This work is public domain.

9
README Normal file
View File

@@ -0,0 +1,9 @@
JavaScript Client-Side BIP0032 generator
http://github.com/sarchar/brainwallet.github.com/tree/bip32
- Web Worker hashes 50,000 rounds to protect passphrases
- Several Crypto-coins supported
- Bitcoin Cash support urtilizes https://github.com/bitcoincashjs/cashaddrjs
- Inline QR code for private keys makes sweeping easier

7
css/bootstrap-theme.min.css vendored Normal file

File diff suppressed because one or more lines are too long

7
css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

34
css/brainwallet.css Normal file
View File

@@ -0,0 +1,34 @@
body {
padding-top: 72px;
padding-bottom: 32px;
}
.form-control[disabled], .form-control[readonly] { cursor: auto; }
hidden {
display: none;
}
.col-lg-2 {
width: 18%;
}
.col-lg-offset-2 {
margin-left: 18%;
}
.col-lg-10 {
width: 82%;
}
.col-lg-10-inner {
width: 80.5%;
}
.progress .progress-bar {
-webkit-transition: none;
-moz-transition: none;
-ms-transition: none;
-o-transition: none;
transition: none;
}?

290
index.html Normal file
View File

@@ -0,0 +1,290 @@
<!DOCTYPE html>
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>BIP32 - JavaScript Deterministic Wallets</title>
<meta content="Client-side Bitcoin and other cryptocurrency address and deterministic wallets generator" name="description"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
<meta content="bitcoin address generator" name="description" />
<meta content="brainwallet" name="author" />
<link href="css/bootstrap.min.css" rel="stylesheet" />
<link href="css/bootstrap-theme.min.css" rel="stylesheet" />
<link href="css/brainwallet.css" rel="stylesheet" />
<link href="favicon.ico" rel="shortcut icon" />
<script src="js/jquery.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/bitcoinjs-min.js"></script>
<script src="js/sha512.js"></script>
<script src="js/modsqrt.js"></script>
<script src="js/qrcode.js"></script>
<script src="js/rfc1751.js"></script>
<script src="js/mnemonic.js"></script>
<script src="js/armory.js"></script>
<script src="js/bip32.js"></script>
<script src="js/cashaddrjs-0.2.8.min.js"></script>
<script src="js/electrum.js"></script>
<script src="js/tx.js"></script>
<script src="js/bitcoinsig.js"></script>
<script src="js/brainwallet.js"></script>
</head>
<body onclick="rng_seed_time();" onkeypress="rng_seed_time();">
<header class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-target=".bs-navbar-collapse" data-toggle="collapse" type="button"><span class="sr-only">Toggle navigation</span> <span class="icon-bar">&nbsp;</span> <span class="icon-bar">&nbsp;</span> <span class="icon-bar">&nbsp;</span></button> <a class="navbar-brand" href="/">BIP32 Generator (Alpha!)</a>
</div>
<nav class="collapse navbar-collapse bs-navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a data-toggle="tab" href="#bip32" id="tab-bip32">Home</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown" id="crCurrency">
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="crSelect"><span id="crName">Bitcoin Mainnet</span>&nbsp;<b class="caret">&nbsp;</b></a>
<ul class="dropdown-menu">
<li><a href="http://blockchain.info/address/" id="btc_main">Bitcoin Mainnet</a></li>
<li><a href="http://blockexplorer.com/testnet/address/" id="btc_test">Bitcoin Testnet</a></li>
<li><a href="https://blockchair.com/bitcoin-cash/address/" id="bch_main">Bitcoin Cash Mainnet</a></li>
<li><a href="" id="bch_test">Bitcoin Cash Testnet</a></li>
<li><a href="http://block-explorer.com/address/" id="ltc_main">Litecoin Mainnet</a></li>
<li><a href="#" id="ltc_test">Litecoin Testnet</a></li>
<li><a href="http://dogechain.info/address/" id="doge_main">Dogecoin Mainnet</a></li>
<li><a href="#" id="doge_test">Dogecoin Testnet</a></li>
<li><a href="https://chainz.cryptoid.info/jbs/" id="jbs_main">Jumbucks Mainnet</a></li>
<!-- Unsupported right now
<li><a href="http://explorer.litecoin.net/address/" title="0x30">LTC</a></li>
<li><a href="http://explorer.dot-bit.org/a/" title="0x34">NMC</a></li>
<li><a href="http://ppc.cryptocoinexplorer.com/address/" title="0x37">PPC</a></li>
<li><a href="http://d.evco.in/abe/address/" title="0x8A">IXC</a></li>
<li><a href="http://nvc.cryptocoinexplorer.com/address/" title="0x08">NVC</a></li>
<li><a href="http://trc.cryptocoinexplorer.com/address/" title="0x00">TRC</a></li>
<li><a href="http://ftc.cryptocoinexplorer.com/address/" title="0x0E">FTC</a></li>
-->
</ul></li>
</ul>
</nav>
</div>
</header>
<div class="container">
<div class="tab-content">
<!-- BIP32 -->
<div class="tab-pane fade in active" id="bip32">
<form action="/" class="form-horizontal" method="get">
<fieldset>
<legend>BIP32 Deterministic Key Generator</legend>
<div class="form-group">
<label class="col-lg-2 control-label" for="from_pass">Derive From</label>
<div class="col-lg-10">
<div class="btn-group" data-toggle="buttons" id="gen_from">
<label class="btn btn-default active" title="Single SHA256"><input id="from_pass" name="gen_from" type="radio" />Passphrase</label>
<label class="btn btn-default" title="Base58-encoded"><input id="from_key" name="gen_from" type="radio" />BIP32 Key</label>
</div>
&nbsp;&nbsp;<span class="help-inline" id="gen_from_msg"></span>
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="bip32_source_passphrase">Passphrase</label>
<div class="col-lg-10">
<div class="row">
<div class="col-lg-12">
<div class="input-group">
<input class="form-control" id="bip32_source_passphrase" type="password" />
<div class="input-group-addon" style="height: 34px;">
<input type="checkbox" id="checkbox_show_passphrase" /> Show Passphrase
</div>
</div>
</div>
</div>
<p />
<div class="row" >
<div class="col-lg-12">
<div class="progress progress-striped" id="bip32_hashing_style" style="margin-bottom: 10px;">
<div class="progress-bar" style="width: 0%;" id="bip32_hashing_progress_bar">
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<input class="btn btn-default" title="Cancel" type="button" value="Cancel slow hash and use weak hash instead" id="cancel_hash_worker" />
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="bip32_source_key">BIP32 Extended Key</label>
<div class="col-lg-10">
<div class="row">
<div class="col-lg-12">
<input class="form-control" id="bip32_source_key" type="text" />
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="bip32_key_info">Key Info</label>
<div class="col-lg-10">
<div class="row">
<div class="col-lg-12">
<label class="control-label" id="bip32_key_info_title">title</label>
</div>
</div>
<br />
<div class="row">
<div class="form-group">
<div class="col-lg-2 control-label">Version</div>
<div class="col-lg-10 col-lg-10-inner">
<input class="form-control" id="bip32_key_info_version" disabled />
</div>
</div>
</div>
<div class="row">
<div class="form-group">
<div class="col-lg-2 control-label">Depth</div>
<div class="col-lg-10 col-lg-10-inner">
<input class="form-control" id="bip32_key_info_depth" disabled />
</div>
</div>
</div>
<div class="row">
<div class="form-group">
<div class="col-lg-2 control-label">Parent Fingerprint</div>
<div class="col-lg-10 col-lg-10-inner">
<input class="form-control" id="bip32_key_info_parent_fingerprint" disabled />
</div>
</div>
</div>
<div class="row">
<div class="form-group">
<div class="col-lg-2 control-label">Child Index</div>
<div class="col-lg-10 col-lg-10-inner">
<input class="form-control" id="bip32_key_info_child_index" disabled />
</div>
</div>
</div>
<div class="row">
<div class="form-group">
<div class="col-lg-2 control-label">Chain Code</div>
<div class="col-lg-10 col-lg-10-inner">
<input class="form-control" id="bip32_key_info_chain_code" disabled />
</div>
</div>
</div>
<div class="row">
<div class="form-group">
<div class="col-lg-2 control-label">Key</div>
<div class="col-lg-10 col-lg-10-inner">
<input class="form-control" id="bip32_key_info_key" disabled />
</div>
</div>
</div>
</div>
</div>
<div class="form-group" id="extpubkeys_from_group">
<label class="col-lg-2 control-label" for="bip32_derivation_path">Derivation Path</label>
<div class="col-lg-10">
<select class="form-control" id="bip32_derivation_path">
<option value="m">Info: m</option>
<option value="m/i">Simple: m/i</option>
<option value="m/k'/0" selected>External account (master): m/k'/0</option>
<option value="m/k'/0/i">External account i'th keypair: m/k'/0/i</option>
<option value="m/k'/1">Internal account (master): m/k'/1</option>
<option value="m/k'/1/i">Internal account i'th keypair: m/k'/1/i</option>
<option value="custom">Custom</option>
</select>
</div>
</div>
<div class="form-group" id="custom_group">
<label class="col-lg-2 control-label" for="bip32_custom_path">Custom Path</label>
<div class="col-lg-10">
<div class="input-group">
<input class="form-control" id="bip32_custom_path" type="text" placeholder="m/i" />
</div>
</div>
</div>
<div class="form-group" id="account_group">
<label class="col-lg-2 control-label" for="account_index">Account (k)</label>
<div class="col-lg-10">
<input class="form-control" id="account_index" maxlength="10" type="text" value="0" />
</div>
</div>
<div class="form-group" id="child_group">
<label class="col-lg-2 control-label" for="keypair_index">Keypair Index (i)</label>
<div class="col-lg-10">
<input class="form-control" id="keypair_index" maxlength="10" type="text" value="0" />
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="derived_private_key">Derived Private Key</label>
<div class="col-lg-10">
<input class="form-control" id="derived_private_key" readonly="readonly" type="text" />
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="derived_private_key_wif">Private Key (WIF)</label>
<div class="col-lg-10">
<input class="form-control" id="derived_private_key_wif" readonly="readonly" type="text" />
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="genKeyQR">Private Key QR Code</label>
<div class="col-lg-10">
<a id="revealKeyQR" class="form-control" style="cursor: pointer;">Click to show Private Key QR Code</a>
<a id="genKeyURL" title=""><span id="genKeyQR"></span></a>
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="derived_public_key">Derived Public Key</label>
<div class="col-lg-10">
<input class="form-control" id="derived_public_key" readonly="readonly" type="text" />
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="derived_public_key_hex">Public Key (Hex)</label>
<div class="col-lg-10">
<input class="form-control" id="derived_public_key_hex" readonly="readonly" type="text" />
</div>
</div>
<div id="cashaddr_group">
<div class="form-group">
<label class="col-lg-2 control-label" for="cashaddr">CashAddr</label>
<div class="col-lg-10">
<input class="form-control" id="cashaddr" readonly="readonly" type="text" />
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="genCashAddrQR">CashAddr QR Code</label>
<div class="col-lg-10">
<a href="#" id="genCashAddrURL" target="_blank" title="Click to view address history (external link)"><span id="genCashAddrQR"></span></a>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="addr" id="addrlabel">Address</label>
<div class="col-lg-10">
<input class="form-control" id="addr" readonly="readonly" type="text" />
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="genAddrQR" id="qraddrlabel">Address QR Code</label>
<div class="col-lg-10">
<a href="#" id="genAddrURL" target="_blank" title="Click to view address history (external link)"><span id="genAddrQR"></span></a>
</div>
</div>
</fieldset>
</form>
</div>
<hr />
<footer>
<p>
This work of art is public domain.<br>Donations welcome at <a href="bitcoin:1NXvAo6tDoSxAqsrcNQ5PPJJM87gR4dHr7">1NXvAo6tDoSxAqsrcNQ5PPJJM87gR4dHr7</a>.
<span class="pull-right">Powered by <a href="http://pages.github.com">GitHub Pages</a> &nbsp;
<a href="https://github.com/bip32/bip32.github.io">GitHub Repository</a> &nbsp;
<a href="https://github.com/bip32/bip32.github.io/archive/master.zip">Download ZIP</a>
</span>
</p>
</footer>
</div>
</div>
</body>
</html>

286
js/armory.js Normal file
View File

@@ -0,0 +1,286 @@
/*
armory.js : Armory deterministic wallet implementation (public domain)
*/
function armory_extend_chain(pubKey, chainCode, privKey, fromPrivKey) {
var chainXor = Crypto.SHA256(Crypto.SHA256(pubKey, {asBytes: true}), {asBytes: true});
for (var i = 0; i < 32; i++)
chainXor[i] ^= chainCode[i];
var curve = getSECCurveByName("secp256k1");
var secexp = null;
var pt;
var A;
if (fromPrivKey) {
A = BigInteger.fromByteArrayUnsigned(chainXor);
var B = BigInteger.fromByteArrayUnsigned(privKey);
var C = curve.getN();
secexp = (A.multiply(B)).mod(C);
pt = curve.getG().multiply(secexp);
} else {
A = BigInteger.fromByteArrayUnsigned(chainXor);
pt = ECPointFp.decodeFrom(curve.getCurve(), pubKey).multiply(A);
}
var newPriv = secexp ? secexp.toByteArrayUnsigned() : [];
var newPub = pt.getEncoded();
var h160 = Bitcoin.Util.sha256ripe160(newPub);
var addr = new Bitcoin.Address(h160);
var sec = secexp ? new Bitcoin.Address(newPriv) : '';
if (secexp)
sec.version = 128;
return [addr.toString(), sec.toString(), newPub, newPriv];
}
var armory_f = '0123456789abcdef';
var armory_t = 'asdfghjkwertuion';
function armory_map(str, from, to) {
var res = '';
for (var i = 0; i < str.length; i++)
res += from.charAt(to.indexOf(str.charAt(i)));
return res;
}
function armory_encode_keys(privKey, chainCode) {
var key = privKey.concat(chainCode);
var res = [];
var str, code;
for (var i = 0; i < 4; i++) {
var bytes = key.slice(i * 16, i * 16 + 16);
var cs = Crypto.SHA256(Crypto.SHA256(bytes, {asBytes: true}), {asBytes: true});
str = Crypto.util.bytesToHex(bytes.concat(cs.slice(0,2)));
code = armory_map(str, armory_t, armory_f);
var arr = [];
for (var j = 0; j < 9; j++)
arr.push(code.substr(j*4, 4));
code = arr.join(' ');
res.push(code);
}
str = res.join('\n');
return str;
}
function armory_decode_keys(data) {
var keys = data.split('\n');
var lines = [];
for (var i = 0; i < keys.length; i++) {
var k = keys[i].replace(' ','');
var raw = Crypto.util.hexToBytes(armory_map(k, armory_f, armory_t));
data = raw.slice(0, 16);
lines.push(data);
}
try {
var privKey = lines[0].concat(lines[1]);
var chainCode = lines[2].concat(lines[3]);
return [privKey, chainCode];
} catch (errr) {
return null;
}
}
function armory_get_pubkey(privKey) {
var curve = getSECCurveByName("secp256k1");
var secexp = BigInteger.fromByteArrayUnsigned(privKey);
var pt = curve.getG().multiply(secexp);
return pt.getEncoded();
}
function armory_get_wallet_uid(pubKey) {
var h160 = Bitcoin.Util.sha256ripe160(pubKey);
var id = [0].concat(h160.slice(0,5)).reverse();
return Bitcoin.Base58.encode(id);
}
var Armory = new function () {
var pubKey;
var privKey;
var chainCode;
var range;
var counter;
var timeout;
var onSuccess;
var onUpdate;
function calcAddr() {
var r = armory_extend_chain(pubKey, chainCode, privKey, true);
onUpdate(r);
pubKey = r[2];
privKey = r[3];
counter++;
if (counter < range) {
timeout = setTimeout(calcAddr, 0);
} else {
if (onSuccess)
onSuccess();
}
}
this.gen = function(seed, _range, update, success) {
var keys = armory_decode_keys(seed);
if (keys == null)
return null;
privKey = keys[0];
chainCode = keys[1];
pubKey = armory_get_pubkey(privKey);
range = _range;
counter = 0;
onUpdate = update;
onSuccess = success;
clearTimeout(timeout);
calcAddr();
return armory_get_wallet_uid(pubKey);
};
this.stop = function () {
clearTimeout(timeout);
};
return this;
};
function armory_trim(str)
{
str = str.replace(/^\s+|\s+$/g, '');
str = str.replace(/^"+|"+$/g, '');
return str;
}
function armory_fmt(str, quote)
{
var chunks = str.match(/.{1,50}/g);
var span = '\n ';
span = quote ? '"'+span+'"':span;
var res = chunks.join(span);
return quote ? '"'+res+'"' : res;
}
function armory_sign_message(private_key, address, message, compressed, addrtype)
{
message = message.replace(/\r|\n/g, ' ');
message = message.replace(/\"/g, '\'');
var digest = 'Bitcoin Signed Message:\n' +message;
var hash = Crypto.SHA256(Crypto.SHA256(digest, {asBytes: true}), {asBytes: true});
var sig = private_key.sign(hash);
var obj = Bitcoin.ECDSA.parseSig(sig);
var sigHex = Crypto.util.bytesToHex(integerToBytes(obj.r, 32))+Crypto.util.bytesToHex(integerToBytes(obj.s, 32));
var pubHex = Crypto.util.bytesToHex(private_key.pub);
return '-----BEGIN-SIGNATURE-BLOCK-------------------------------------'
+'\nAddress: '+address
+'\nMessage: '+armory_fmt(message,true)
+'\nPublicKey: '+armory_fmt(pubHex)
+'\nSignature: '+armory_fmt(sigHex)
+'\n-----END-SIGNATURE-BLOCK---------------------------------------';
}
function armory_split_message(str)
{
var a = str.split('\n');
var pre = true;
var fields = ["Address","Message","PublicKey","Signature"];
var values = {};
var key = null;
for (i in a)
{
var s = a[i];
if (pre && s.indexOf('-----BEGIN-SIGNATURE-BLOCK')==0)
pre = false;
if (!pre)
{
if (s.indexOf('-----END-SIGNATURE-BLOCK')==0)
break;
for (j in fields)
{
var k = fields[j];
if (s.indexOf(k+':')==0)
{
key = k;
values[key]=''
s = s.split(':')[1];
break;
}
}
if (key)
values[key]+=armory_trim(s);
}
}
return values;
}
function armory_verify_message(values)
{
var adr = values['Address'];
var msg = values['Message'];
var pub = values['PublicKey'];
var sig = values['Signature'];
var digest = 'Bitcoin Signed Message:\n' +msg;
var hash = Crypto.SHA256(Crypto.SHA256(digest, {asBytes: true}), {asBytes: true});
var sig = [27].concat(Crypto.util.hexToBytes(sig));
sig = Bitcoin.ECDSA.parseSigCompact(sig);
var res = false;
for (var i=0; i<4; i++)
{
sig.i = i;
try {
var pubKey = Bitcoin.ECDSA.recoverPubKey(sig.r, sig.s, hash, sig.i);
} catch(err) {
return false;
}
var expectedAddress = pubKey.getBitcoinAddress().toString();
if (expectedAddress==adr)
{
res = adr;
break;
}
}
return res;
}
// command-line tests
if (typeof require != 'undefined' && require.main === module) {
window=global,navigator=Bitcoin={};eval(require('fs').readFileSync('./bitcoinjs-min.js')+'');
var s = [
'-----BEGIN-SIGNATURE-BLOCK-------------------------------------',
'Address: 1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T',
'Message: "This is an example of a signed message."',
'PublicKey: 0478d430274f8c5ec1321338151e9f27f4c676a008bdf8638d',
' 07c0b6be9ab35c71a1518063243acd4dfe96b66e3f2ec8013c',
' 8e072cd09b3834a19f81f659cc3455',
'Signature: ad2e12415efc3509c261daee79eb31ae5a1dffd89045222d15',
' b73740866649b119d2415d02917164e80d5c20a7820c768d15',
' 2be377ea19a7f4f645227d9d2902',
'-----END-SIGNATURE-BLOCK---------------------------------------'
].join('\n');
console.log('verified to: ' + armory_verify_message(armory_split_message(s)));
var codes = [
'atuw tnde sghh utho sudi ekgk ohoj odwd ojhw',
'ueis hnrt fsht fjes gsgg gswg eutd duus ftfs',
'jgjs fghg waug hjah faaw tksn gwig hrrr tdot',
'kjuu oeuj kdun adst gfug howu jjes fndd fref'
].join('\n');
Armory.gen(codes, 5, function(r) { console.log(r[0]); } );
}

386
js/bip32.js Normal file
View File

@@ -0,0 +1,386 @@
var BITCOIN_MAINNET_PUBLIC = 0x0488b21e;
var BITCOIN_MAINNET_PRIVATE = 0x0488ade4;
var BITCOIN_TESTNET_PUBLIC = 0x043587cf;
var BITCOIN_TESTNET_PRIVATE = 0x04358394;
var BITCOIN_CASH_MAINNET_PUBLIC = 0x02cfc6c2; // I'm starting to wonder if having a different version for each coin is a bad idea
var BITCOIN_CASH_MAINNET_PRIVATE = 0x02cfbf5d; // Perhaps it would be better to consistently use Bitcoin's versions (xprv/xpub) and follow
var BITCOIN_CASH_TESTNET_PUBLIC = 0x02d5830e; // BIP44. That may be a change for the future. Technically, all these version codes do anyway
var BITCOIN_CASH_TESTNET_PRIVATE = 0x02d57ba9; // is to make sure you're using the right bip32 chain on the right coin. The underlying private key
var DOGECOIN_MAINNET_PUBLIC = 0x02facafd; // and chain code are the same regardless of version.
var DOGECOIN_MAINNET_PRIVATE = 0x02fac398;
var DOGECOIN_TESTNET_PUBLIC = 0x0432a9a8;
var DOGECOIN_TESTNET_PRIVATE = 0x0432a243;
var JUMBUCKS_MAINNET_PUBLIC = 0x037a689a;
var JUMBUCKS_MAINNET_PRIVATE = 0x037a6460;
var LITECOIN_MAINNET_PUBLIC = 0x019da462;
var LITECOIN_MAINNET_PRIVATE = 0x019d9cfe;
var LITECOIN_TESTNET_PUBLIC = 0x0436f6e1;
var LITECOIN_TESTNET_PRIVATE = 0x0436ef7d;
var BIP32 = function(bytes) {
// decode base58
if( typeof bytes === "string" ) {
var decoded = Bitcoin.Base58.decode(bytes);
if( decoded.length != 82 ) throw new Error("Not enough data");
var checksum = decoded.slice(78, 82);
bytes = decoded.slice(0, 78);
var hash = Crypto.SHA256( Crypto.SHA256( bytes, { asBytes: true } ), { asBytes: true } );
if( hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3] ) {
throw new Error("Invalid checksum");
}
}
if( bytes !== undefined )
this.init_from_bytes(bytes);
}
BIP32.prototype.init_from_bytes = function(bytes) {
// Both pub and private extended keys are 78 bytes
if( bytes.length != 78 ) throw new Error("not enough data");
this.version = u32(bytes.slice(0, 4));
this.depth = u8 (bytes.slice(4, 5));
this.parent_fingerprint = bytes.slice(5, 9);
this.child_index = u32(bytes.slice(9, 13));
this.chain_code = bytes.slice(13, 45);
var key_bytes = bytes.slice(45, 78);
var is_private =
(this.version == BITCOIN_MAINNET_PRIVATE ||
this.version == BITCOIN_TESTNET_PRIVATE ||
this.version == BITCOIN_CASH_MAINNET_PRIVATE ||
this.version == BITCOIN_CASH_TESTNET_PRIVATE ||
this.version == DOGECOIN_MAINNET_PRIVATE ||
this.version == DOGECOIN_TESTNET_PRIVATE ||
this.version == JUMBUCKS_MAINNET_PRIVATE ||
this.version == LITECOIN_MAINNET_PRIVATE ||
this.version == LITECOIN_TESTNET_PRIVATE );
var is_public =
(this.version == BITCOIN_MAINNET_PUBLIC ||
this.version == BITCOIN_TESTNET_PUBLIC ||
this.version == BITCOIN_CASH_MAINNET_PUBLIC ||
this.version == BITCOIN_CASH_TESTNET_PUBLIC ||
this.version == DOGECOIN_MAINNET_PUBLIC ||
this.version == DOGECOIN_TESTNET_PUBLIC ||
this.version == JUMBUCKS_MAINNET_PUBLIC ||
this.version == LITECOIN_MAINNET_PUBLIC ||
this.version == LITECOIN_TESTNET_PUBLIC );
if( is_private && key_bytes[0] == 0 ) {
this.eckey = new Bitcoin.ECKey(key_bytes.slice(1, 33));
this.eckey.setCompressed(true);
var ecparams = getSECCurveByName("secp256k1");
var pt = ecparams.getG().multiply(this.eckey.priv);
this.eckey.pub = pt;
this.eckey.pubKeyHash = Bitcoin.Util.sha256ripe160(this.eckey.pub.getEncoded(true));
this.has_private_key = true;
} else if( is_public && (key_bytes[0] == 0x02 || key_bytes[0] == 0x03) ) {
this.eckey = new Bitcoin.ECKey();
this.eckey.pub = decompress_pubkey(key_bytes);
this.eckey.pubKeyHash = Bitcoin.Util.sha256ripe160(this.eckey.pub.getEncoded(true));
this.eckey.setCompressed(true);
this.has_private_key = false;
} else {
throw new Error("Invalid key");
}
this.build_extended_public_key();
this.build_extended_private_key();
}
BIP32.prototype.build_extended_public_key = function() {
this.extended_public_key = [];
var v = null;
switch(this.version) {
case BITCOIN_MAINNET_PUBLIC:
case BITCOIN_MAINNET_PRIVATE:
v = BITCOIN_MAINNET_PUBLIC;
break;
case BITCOIN_TESTNET_PUBLIC:
case BITCOIN_TESTNET_PRIVATE:
v = BITCOIN_TESTNET_PUBLIC;
break;
case BITCOIN_CASH_MAINNET_PUBLIC:
case BITCOIN_CASH_MAINNET_PRIVATE:
v = BITCOIN_CASH_MAINNET_PUBLIC;
break;
case BITCOIN_CASH_TESTNET_PUBLIC:
case BITCOIN_CASH_TESTNET_PRIVATE:
v = BITCOIN_CASH_TESTNET_PUBLIC;
break;
case DOGECOIN_MAINNET_PUBLIC:
case DOGECOIN_MAINNET_PRIVATE:
v = DOGECOIN_MAINNET_PUBLIC;
break;
case DOGECOIN_TESTNET_PUBLIC:
case DOGECOIN_TESTNET_PRIVATE:
v = DOGECOIN_TESTNET_PUBLIC;
break;
case JUMBUCKS_MAINNET_PUBLIC:
case JUMBUCKS_MAINNET_PRIVATE:
v = JUMBUCKS_MAINNET_PUBLIC;
break;
case LITECOIN_MAINNET_PUBLIC:
case LITECOIN_MAINNET_PRIVATE:
v = LITECOIN_MAINNET_PUBLIC;
break;
case LITECOIN_TESTNET_PUBLIC:
case LITECOIN_TESTNET_PRIVATE:
v = LITECOIN_TESTNET_PUBLIC;
break;
default:
throw new Error("Unknown version");
}
// Version
this.extended_public_key.push(v >> 24);
this.extended_public_key.push((v >> 16) & 0xff);
this.extended_public_key.push((v >> 8) & 0xff);
this.extended_public_key.push(v & 0xff);
// Depth
this.extended_public_key.push(this.depth);
// Parent fingerprint
this.extended_public_key = this.extended_public_key.concat(this.parent_fingerprint);
// Child index
this.extended_public_key.push(this.child_index >>> 24);
this.extended_public_key.push((this.child_index >>> 16) & 0xff);
this.extended_public_key.push((this.child_index >>> 8) & 0xff);
this.extended_public_key.push(this.child_index & 0xff);
// Chain code
this.extended_public_key = this.extended_public_key.concat(this.chain_code);
// Public key
this.extended_public_key = this.extended_public_key.concat(this.eckey.pub.getEncoded(true));
}
BIP32.prototype.extended_public_key_string = function(format) {
if( format === undefined || format === "base58" ) {
var hash = Crypto.SHA256( Crypto.SHA256( this.extended_public_key, { asBytes: true } ), { asBytes: true } );
var checksum = hash.slice(0, 4);
var data = this.extended_public_key.concat(checksum);
return Bitcoin.Base58.encode(data);
} else if( format === "hex" ) {
return Crypto.util.bytesToHex(this.extended_public_key);
} else {
throw new Error("bad format");
}
}
BIP32.prototype.build_extended_private_key = function() {
if( !this.has_private_key ) return;
this.extended_private_key = [];
var v = this.version;
// Version
this.extended_private_key.push(v >> 24);
this.extended_private_key.push((v >> 16) & 0xff);
this.extended_private_key.push((v >> 8) & 0xff);
this.extended_private_key.push(v & 0xff);
// Depth
this.extended_private_key.push(this.depth);
// Parent fingerprint
this.extended_private_key = this.extended_private_key.concat(this.parent_fingerprint);
// Child index
this.extended_private_key.push(this.child_index >>> 24);
this.extended_private_key.push((this.child_index >>> 16) & 0xff);
this.extended_private_key.push((this.child_index >>> 8) & 0xff);
this.extended_private_key.push(this.child_index & 0xff);
// Chain code
this.extended_private_key = this.extended_private_key.concat(this.chain_code);
// Private key
this.extended_private_key.push(0);
var k = this.eckey.priv.toByteArrayUnsigned();
while (k.length < 32) {
k.unshift(0);
}
this.extended_private_key = this.extended_private_key.concat(k);
}
BIP32.prototype.extended_private_key_string = function(format) {
if( format === undefined || format === "base58" ) {
var hash = Crypto.SHA256( Crypto.SHA256( this.extended_private_key, { asBytes: true } ), { asBytes: true } );
var checksum = hash.slice(0, 4);
var data = this.extended_private_key.concat(checksum);
return Bitcoin.Base58.encode(data);
} else if( format === "hex" ) {
return Crypto.util.bytesToHex(this.extended_private_key);
} else {
throw new Error("bad format");
}
}
BIP32.prototype.derive = function(path) {
var e = path.split('/');
// Special cases:
if( path == 'm' || path == 'M' || path == 'm\'' || path == 'M\'' ) return this;
var bip32 = this;
for( var i in e ) {
var c = e[i];
if( i == 0 ) {
if( c != 'm' ) throw new Error("invalid path");
continue;
}
var use_private = (c.length > 1) && (c[c.length-1] == '\'');
var child_index = parseInt(use_private ? c.slice(0, c.length - 1) : c) & 0x7fffffff;
if( use_private )
child_index += 0x80000000;
bip32 = bip32.derive_child(child_index);
}
return bip32;
}
BIP32.prototype.derive_child = function(i) {
var ib = [];
ib.push( (i >> 24) & 0xff );
ib.push( (i >> 16) & 0xff );
ib.push( (i >> 8) & 0xff );
ib.push( i & 0xff );
var use_private = (i & 0x80000000) != 0;
var ecparams = getSECCurveByName("secp256k1");
var is_private =
(this.version == BITCOIN_MAINNET_PRIVATE ||
this.version == BITCOIN_TESTNET_PRIVATE ||
this.version == BITCOIN_CASH_MAINNET_PRIVATE ||
this.version == BITCOIN_CASH_TESTNET_PRIVATE ||
this.version == DOGECOIN_MAINNET_PRIVATE ||
this.version == DOGECOIN_TESTNET_PRIVATE ||
this.version == JUMBUCKS_MAINNET_PRIVATE ||
this.version == LITECOIN_MAINNET_PRIVATE ||
this.version == LITECOIN_TESTNET_PRIVATE );
if( use_private && (!this.has_private_key || !is_private) ) throw new Error("Cannot do private key derivation without private key");
var ret = null;
if( this.has_private_key ) {
var data = null;
if( use_private ) {
var k = this.eckey.priv.toByteArrayUnsigned();
while (k.length < 32) {
k.unshift(0);
}
data = [0].concat(k).concat(ib);
} else {
data = this.eckey.pub.getEncoded(true).concat(ib);
}
var j = new jsSHA(Crypto.util.bytesToHex(data), 'HEX');
var hash = j.getHMAC(Crypto.util.bytesToHex(this.chain_code), "HEX", "SHA-512", "HEX");
var il = new BigInteger(hash.slice(0, 64), 16);
var ir = Crypto.util.hexToBytes(hash.slice(64, 128));
// ki = IL + kpar (mod n).
var curve = ecparams.getCurve();
var k = il.add(this.eckey.priv).mod(ecparams.getN());
ret = new BIP32();
ret.chain_code = ir;
ret.eckey = new Bitcoin.ECKey(k.toByteArrayUnsigned());
ret.eckey.pub = ret.eckey.getPubPoint();
ret.has_private_key = true;
} else {
var data = this.eckey.pub.getEncoded(true).concat(ib);
var j = new jsSHA(Crypto.util.bytesToHex(data), 'HEX');
var hash = j.getHMAC(Crypto.util.bytesToHex(this.chain_code), "HEX", "SHA-512", "HEX");
var il = new BigInteger(hash.slice(0, 64), 16);
var ir = Crypto.util.hexToBytes(hash.slice(64, 128));
// Ki = (IL + kpar)*G = IL*G + Kpar
var k = ecparams.getG().multiply(il).add(this.eckey.pub);
ret = new BIP32();
ret.chain_code = ir;
ret.eckey = new Bitcoin.ECKey();
ret.eckey.pub = k;
ret.has_private_key = false;
}
ret.child_index = i;
ret.parent_fingerprint = this.eckey.pubKeyHash.slice(0,4);
ret.version = this.version;
ret.depth = this.depth + 1;
ret.eckey.setCompressed(true);
ret.eckey.pubKeyHash = Bitcoin.Util.sha256ripe160(ret.eckey.pub.getEncoded(true));
ret.build_extended_public_key();
ret.build_extended_private_key();
return ret;
}
function uint(f, size) {
if (f.length < size)
throw new Error("not enough data");
var n = 0;
for (var i = 0; i < size; i++) {
n *= 256;
n += f[i];
}
return n;
}
function u8(f) { return uint(f,1); }
function u16(f) { return uint(f,2); }
function u32(f) { return uint(f,4); }
function u64(f) { return uint(f,8); }
function decompress_pubkey(key_bytes) {
var y_bit = u8(key_bytes.slice(0, 1)) & 0x01;
var ecparams = getSECCurveByName("secp256k1");
// build X
var x = BigInteger.ZERO.clone();
x.fromString(Crypto.util.bytesToHex(key_bytes.slice(1, 33)), 16);
// get curve
var curve = ecparams.getCurve();
var a = curve.getA().toBigInteger();
var b = curve.getB().toBigInteger();
var p = curve.getQ();
// compute y^2 = x^3 + a*x + b
var tmp = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
// compute modular square root of y (mod p)
var y = tmp.modSqrt(p);
// flip sign if we need to
if( (y[0] & 0x01) != y_bit ) {
y = y.multiply(new BigInteger("-1")).mod(p);
}
return new ECPointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y));
}

28
js/bitcoinjs-min.js vendored Normal file

File diff suppressed because one or more lines are too long

121
js/bitcoinsig.js Normal file
View File

@@ -0,0 +1,121 @@
/*
bitcoinsig.js - sign and verify messages with bitcoin address (public domain)
*/
function msg_numToVarInt(i) {
if (i < 0xfd) {
return [i];
} else if (i <= 0xffff) {
// can't use numToVarInt from bitcoinjs, BitcoinQT wants big endian here (!)
return [0xfd, i & 255, i >>> 8];
} else {
throw ("message too large");
}
}
function msg_bytes(message) {
var b = Crypto.charenc.UTF8.stringToBytes(message);
return msg_numToVarInt(b.length).concat(b);
}
function msg_digest(message) {
var b = msg_bytes("Bitcoin Signed Message:\n").concat(msg_bytes(message));
return Crypto.SHA256(Crypto.SHA256(b, {asBytes:true}), {asBytes:true});
}
function verify_message(signature, message, addrtype) {
try {
var sig = Crypto.util.base64ToBytes(signature);
} catch(err) {
return false;
}
if (sig.length != 65)
return false;
// extract r,s from signature
var r = BigInteger.fromByteArrayUnsigned(sig.slice(1,1+32));
var s = BigInteger.fromByteArrayUnsigned(sig.slice(33,33+32));
// get recid
var compressed = false;
var nV = sig[0];
if (nV < 27 || nV >= 35)
return false;
if (nV >= 31) {
compressed = true;
nV -= 4;
}
var recid = BigInteger.valueOf(nV - 27);
var ecparams = getSECCurveByName("secp256k1");
var curve = ecparams.getCurve();
var a = curve.getA().toBigInteger();
var b = curve.getB().toBigInteger();
var p = curve.getQ();
var G = ecparams.getG();
var order = ecparams.getN();
var x = r.add(order.multiply(recid.divide(BigInteger.valueOf(2))));
var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
var beta = alpha.modPow(p.add(BigInteger.ONE).divide(BigInteger.valueOf(4)), p);
var y = beta.subtract(recid).isEven() ? beta : p.subtract(beta);
var R = new ECPointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y));
var e = BigInteger.fromByteArrayUnsigned(msg_digest(message));
var minus_e = e.negate().mod(order);
var inv_r = r.modInverse(order);
var Q = (R.multiply(s).add(G.multiply(minus_e))).multiply(inv_r);
var public_key = Q.getEncoded(compressed);
var addr = new Bitcoin.Address(Bitcoin.Util.sha256ripe160(public_key));
addr.version = addrtype ? addrtype : 0;
return addr.toString();
}
function sign_message(private_key, message, compressed, addrtype) {
if (!private_key)
return false;
var signature = private_key.sign(msg_digest(message));
var address = new Bitcoin.Address(private_key.getPubKeyHash());
address.version = addrtype ? addrtype : 0;
//convert ASN.1-serialized signature to bitcoin-qt format
var obj = Bitcoin.ECDSA.parseSig(signature);
var sequence = [0];
sequence = sequence.concat(obj.r.toByteArrayUnsigned());
sequence = sequence.concat(obj.s.toByteArrayUnsigned());
for (var i = 0; i < 4; i++) {
var nV = 27 + i;
if (compressed)
nV += 4;
sequence[0] = nV;
var sig = Crypto.util.bytesToBase64(sequence);
if (verify_message(sig, message, addrtype) == address)
return sig;
}
return false;
}
function bitcoinsig_test() {
var k = '5JeWZ1z6sRcLTJXdQEDdB986E6XfLAkj9CgNE4EHzr5GmjrVFpf';
var a = '17mDAmveV5wBwxajBsY7g1trbMW1DVWcgL';
var s = 'HDiv4Oe9SjM1FFVbKk4m3N34efYiRgkQGGoEm564ldYt44jHVTuX23+WnihNMi4vujvpUs1M529P3kftjDezn9E=';
var m = 'test message';
payload = Bitcoin.Base58.decode(k);
secret = payload.slice(1, 33);
compressed = payload.length == 38;
console.log(verify_message(s, m));
sig = sign_message(new Bitcoin.ECKey(secret), m, compressed);
console.log(verify_message(sig, m));
}
if (typeof require != 'undefined' && require.main === module) {
window = global; navigator = {}; Bitcoin = {};
eval(require('fs').readFileSync('./bitcoinjs-min.js')+'');
eval(require('path').basename(module.filename,'.js')+'_test()');
}

7
js/bootstrap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

645
js/brainwallet.js Normal file
View File

@@ -0,0 +1,645 @@
(function($){
var bip32_source_key = null;
var bip32_derivation_path = null;
var gen_from = "pass";
var hash_worker = null;
var hash_worker_working = false;
var bip32_passphrase_hash = null;
var TIMEOUT = 600;
var timeout = null;
var coin = "btc_main";
var COINS = {
btc_main: {
name: "Bitcoin",
network: "Mainnet",
prefix: 0,
private_prefix: 0+0x80,
bip32_public: BITCOIN_MAINNET_PUBLIC,
bip32_private: BITCOIN_MAINNET_PRIVATE
},
btc_test: {
name: "Bitcoin",
network: "Testnet",
prefix: 0x6f,
private_prefix: 0x6f+0x80,
bip32_public: BITCOIN_TESTNET_PUBLIC,
bip32_private: BITCOIN_TESTNET_PRIVATE
},
bch_main: {
name: "Bitcoin Cash",
network: "Mainnet",
prefix: 0,
private_prefix: 0+0x80,
bip32_public: BITCOIN_CASH_MAINNET_PUBLIC,
bip32_private: BITCOIN_CASH_MAINNET_PRIVATE
},
bch_test: {
name: "Bitcoin Cash",
network: "Testnet",
prefix: 0x6f,
private_prefix: 0x6f+0x80,
bip32_public: BITCOIN_CASH_TESTNET_PUBLIC,
bip32_private: BITCOIN_CASH_TESTNET_PRIVATE
},
doge_main: {
name: "Dogecoin",
network: "Mainnet",
prefix: 0x1e,
private_prefix: 0x1e+0x80,
bip32_public: DOGECOIN_MAINNET_PUBLIC,
bip32_private: DOGECOIN_MAINNET_PRIVATE
},
doge_test: {
name: "Dogecoin",
network: "Testnet",
prefix: 0x71,
private_prefix: 0x71+0x80,
bip32_public: DOGECOIN_TESTNET_PUBLIC,
bip32_private: DOGECOIN_TESTNET_PRIVATE
},
jbs_main: {
name: "Jumbucks",
network: "Mainnet",
prefix: 0x2b,
private_prefix: 0x2b+0x80,
bip32_public: JUMBUCKS_MAINNET_PUBLIC,
bip32_private: JUMBUCKS_MAINNET_PRIVATE
},
ltc_main: {
name: "Litecoin",
network: "Mainnet",
prefix: 0x30,
private_prefix: 0x30+0x80,
bip32_public: LITECOIN_MAINNET_PUBLIC,
bip32_private: LITECOIN_MAINNET_PRIVATE
},
ltc_test: {
name: "Litecoin",
network: "Testnet",
prefix: 0x6f,
private_prefix: 0x6f+0x80,
bip32_public: LITECOIN_TESTNET_PUBLIC,
bip32_private: LITECOIN_TESTNET_PRIVATE
}
};
var ADDRESS_URL_PREFIX = 'http://blockchain.info/address/'
var acknowledged_bch_is_experimental = false;
function pad(str, len, ch) {
padding = '';
for (var i = 0; i < len - str.length; i++) {
padding += ch;
}
return padding + str;
}
function setWarningState(field, err, msg) {
var group = field.closest('.form-group');
if (err) {
group.removeClass('has-error').addClass('has-warning');
group.attr('title', msg);
} else {
group.removeClass('has-warning').removeClass('has-error');
group.attr('title', '');
}
}
function setErrorState(field, err, msg) {
var group = field.closest('.form-group');
if (err) {
group.removeClass('has-warning').addClass('has-error');
group.attr('title',msg);
} else {
group.removeClass('has-warning').removeClass('has-error');
group.attr('title','');
}
}
function pad2(s) {
if(s.length == 1) return '0' + s;
return s;
}
function pad8(s) {
while(s.length < 8) s = '0' + s;
return s;
}
function byteArrayToHexString(a) {
var s = '';
for( var i in a ) {
s = s + pad2(a[i].toString(16));
}
return s;
}
// --- bip32 ---
function onUpdateGenFrom() {
gen_from = $(this).attr('id').substring(5);
updateGenFrom();
}
function updateGenFrom() {
if( gen_from == 'pass' ) {
$("#bip32_source_passphrase").attr('readonly', false);
$("#bip32_source_key").attr('readonly', true);
$("#gen_from_msg").html("Your passphrase is hashed using 50,000 rounds of HMAC-SHA256");
} else {
setErrorState($("#bip32_source_passphrase"), false);
$("#bip32_source_passphrase").attr('readonly', true);
$("#bip32_source_key").attr('readonly', false);
stop_hash_worker();
$("#cancel_hash_worker").attr('disabled', true);
$("#gen_from_msg").html("You can manually enter an Extended Private or Public key");
}
}
function onUpdateSourcePassphrase() {
clearTimeout(timeout);
timeout = setTimeout(updateSourcePassphrase, TIMEOUT);
setWarningState($("#bip32_source_passphrase"), false);
}
function onShowPassphraseChanged() {
if($(this).is(":checked")) {
$("#bip32_source_passphrase").attr('type', 'text');
} else {
$("#bip32_source_passphrase").attr('type', 'password');
}
}
function onCancelHashWorkerClicked() {
stop_hash_worker();
var passphrase = $("#bip32_source_passphrase").val();
bip32_passphrase_hash = Crypto.util.bytesToHex(Crypto.SHA256(passphrase, { asBytes: true }));
updatePassphraseHash();
setWarningState($("#bip32_source_passphrase"), true, "The passphrase was hashed using a single SHA-256 and should be considered WEAK and INSECURE");
}
function updateSourcePassphrase() {
var passphrase = $("#bip32_source_passphrase").val();
if( typeof(Worker) === undefined ) {
setErrorState($("#bip32_source_passphrase"), true, "Your browser doesn't support Web Workers");
} else {
setErrorState($("#bip32_source_passphrase"), false);
}
try {
start_hash_worker(passphrase);
} catch (err) {
setErrorState($("#bip32_source_passphrase"), true, "Your browser doesn't support Web Workers: " + err.toString());
alert("It appears your browser cannot load or execute web workers. If you are running locally using Chrome, run with the --allow-file-access-from-files option or use a HTTP server such as Python (python3 -m http.server)");
}
}
function updatePassphraseHash() {
var hasher = new jsSHA(bip32_passphrase_hash, 'HEX');
var I = hasher.getHMAC("Bitcoin seed", "TEXT", "SHA-512", "HEX");
var il = Crypto.util.hexToBytes(I.slice(0, 64));
var ir = Crypto.util.hexToBytes(I.slice(64, 128));
var gen_bip32 = new BIP32();
try {
gen_bip32.eckey = new Bitcoin.ECKey(il);
gen_bip32.eckey.pub = gen_bip32.eckey.getPubPoint();
gen_bip32.eckey.setCompressed(true);
gen_bip32.eckey.pubKeyHash = Bitcoin.Util.sha256ripe160(gen_bip32.eckey.pub.getEncoded(true));
gen_bip32.has_private_key = true;
gen_bip32.chain_code = ir;
gen_bip32.child_index = 0;
gen_bip32.parent_fingerprint = Bitcoin.Util.hexToBytes("00000000");
gen_bip32.version = COINS[coin].bip32_private;
gen_bip32.depth = 0;
gen_bip32.build_extended_public_key();
gen_bip32.build_extended_private_key();
} catch (err) {
setErrorState($('#bip32_source_passphrase'), true, '' + err);
return;
}
setErrorState($('#bip32_source_passphrase'), false);
$("#bip32_source_key").val(gen_bip32.extended_private_key_string("base58"));
updateSourceKey();
}
function isMasterKey(k) {
return k.child_index == 0 && k.depth == 0 &&
( k.parent_fingerprint[0] == 0 && k.parent_fingerprint[1] == 0 && k.parent_fingerprint[2] == 0 && k.parent_fingerprint[3] == 0 );
}
function onUpdateSourceKey() {
clearTimeout(timeout);
timeout = setTimeout(updateSourceKey, TIMEOUT);
}
function updateSourceKey() {
$("#bip32_key_info_title").html('');
$("#bip32_key_info_version").val('');
$("#bip32_key_info_depth").val('');
$("#bip32_key_info_parent_fingerprint").val('');
$("#bip32_key_info_child_index").val('');
$("#bip32_key_info_chain_code").val('');
$("#bip32_key_info_key").val('');
setErrorState($('#bip32_source_key'), false);
try {
var source_key_str = $("#bip32_source_key").val();
if(source_key_str.length == 0) return;
bip32_source_key = new BIP32(source_key_str);
} catch(err) {
bip32_source_key = null;
setErrorState($('#bip32_source_key'), true, 'Invalid key: ' + err.toString());
return;
}
var coin = getCoinFromKey(bip32_source_key);
if(coin.name == "Bitcoin Cash" && !acknowledged_bch_is_experimental) {
alert("Warning!\n\nBitcoin Cash support is NEW and EXPERIMENTAL. Use at your own risk!\n\nPlease verify your addresses with other services before using!");
acknowledged_bch_is_experimental = true;
}
for(var coin_name in COINS) {
if(coin.bip32_private == COINS[coin_name].bip32_private) {
$('#crName').text($("#" + coin_name).text());
break;
}
}
//console.log(bip32_source_key);
updateSourceKeyInfo();
updateDerivationPath();
}
function getCoinFromKey(k) {
for(var coin_name in COINS) {
var c = COINS[coin_name];
if(k.version == c.bip32_public || k.version == c.bip32_private) {
return c;
}
}
return null;
}
function updateSourceKeyInfo() {
var key_coin = getCoinFromKey(bip32_source_key);
if( isMasterKey(bip32_source_key) ) {
if( bip32_source_key.has_private_key ) {
$("#bip32_key_info_title").html("<b>" + key_coin.name + " Master Private Key</b>");
} else {
$("#bip32_key_info_title").html("<b>" + key_coin.name + " Master Public Key</b>");
}
} else {
if( bip32_source_key.has_private_key ) {
$("#bip32_key_info_title").html("<b>" + key_coin.name + " Derived Private Key</b>");
} else {
$("#bip32_key_info_title").html("<b>" + key_coin.name + " Derived Public Key</b>");
}
}
var v = '' + pad8(bip32_source_key.version.toString(16));
if( bip32_source_key.has_private_key ) v = v + " (" + key_coin.name + " " + key_coin.network + " private key)";
else v = v + " (" + key_coin.name + " " + key_coin.network + " public key)";
$("#bip32_key_info_version").val(v);
$("#bip32_key_info_depth").val('' + bip32_source_key.depth);
$("#bip32_key_info_parent_fingerprint").val('' + pad2(bip32_source_key.parent_fingerprint[0].toString(16)) +
pad2(bip32_source_key.parent_fingerprint[1].toString(16)) +
pad2(bip32_source_key.parent_fingerprint[2].toString(16)) +
pad2(bip32_source_key.parent_fingerprint[3].toString(16)));
$("#bip32_key_info_child_index").val(bip32_source_key.child_index);
$("#bip32_key_info_chain_code").val('' + byteArrayToHexString(bip32_source_key.chain_code));
if( bip32_source_key.has_private_key ) {
var bytes = [key_coin.private_prefix].concat(bip32_source_key.eckey.priv.toByteArrayUnsigned()).concat([1]);
var checksum = Crypto.SHA256(Crypto.SHA256(bytes, {asBytes: true}), {asBytes: true}).slice(0, 4);
$("#bip32_key_info_key").val(Bitcoin.Base58.encode(bytes.concat(checksum)));
} else {
var bytes = Crypto.util.bytesToHex(bip32_source_key.eckey.pub.getEncoded(true));
$("#bip32_key_info_key").val(bytes);
}
return;
}
function onUpdateDerivationPath() {
updateDerivationPath();
}
function onUpdateCustomPath() {
clearTimeout(timeout);
timeout = setTimeout(updateDerivationPath, TIMEOUT);
}
function onAccountIndexChanged() {
clearTimeout(timeout);
timeout = setTimeout(updateDerivationPath, TIMEOUT);
}
function onKeypairIndexChanged() {
clearTimeout(timeout);
timeout = setTimeout(updateDerivationPath, TIMEOUT);
}
function updateDerivationPath() {
bip32_derivation_path = $("#bip32_derivation_path :selected").val();
if( bip32_derivation_path == "custom" ) {
$("#custom_group").show();
bip32_derivation_path = $("#bip32_custom_path").val();
} else {
$("#custom_group").hide();
}
if( bip32_derivation_path.indexOf('/k/') >= 0 || bip32_derivation_path.indexOf('/k\'/') >= 0 ) {
$("#account_group").show();
} else {
$("#account_group").hide();
}
if( bip32_derivation_path.indexOf('/i/') >= 0 ||
bip32_derivation_path.indexOf('/i\'/') >= 0 ||
bip32_derivation_path.slice(bip32_derivation_path.length-2) == "/i" ||
bip32_derivation_path.slice(bip32_derivation_path.length-3) == "/i'" ) {
$("#child_group").show();
} else {
$("#child_group").hide();
}
updateResult();
}
function updateResult() {
var p = '' + bip32_derivation_path;
var k = parseInt($("#account_index").val());
var i = parseInt($("#keypair_index").val());
p = p.replace('i', i).replace('k', k);
setErrorState($('#bip32_derivation_path'), false);
$("#derived_private_key").val('');
$("#derived_public_key").val('');
$("#derived_private_key_wif").val('');
$("#derived_public_key_hex").val('');
$("#addr").val('');
$("#cashaddr").val('');
$("#genKeyQR").html('');
$("#genKeyURL").hide();
$("#revealKeyQR").show();
$("#genAddrQR").html('');
$("#genCashAddrQR").html('');
try {
if(bip32_source_key == null) {
// if this is the case then there's an error state set on the source key
return;
}
console.log("Deriving: " + p);
var result = bip32_source_key.derive(p);
} catch (err) {
setErrorState($('#bip32_derivation_path'), true, 'Error deriving key: ' + err.toString());
return;
}
var key_coin = getCoinFromKey(result);
if( result.has_private_key ) {
$("#derived_private_key").val(result.extended_private_key_string("base58"));
var privkeyBytes = result.eckey.priv.toByteArrayUnsigned();
while (privkeyBytes.length < 32) {
privkeyBytes.unshift(0);
};
var bytes = [key_coin.private_prefix].concat(privkeyBytes).concat([1]);
var checksum = Crypto.SHA256(Crypto.SHA256(bytes, {asBytes: true}), {asBytes: true}).slice(0, 4);
$("#derived_private_key_wif").val(Bitcoin.Base58.encode(bytes.concat(checksum)))
} else {
$("#derived_private_key").val("No private key available");
$("#derived_private_key_wif").val("No private key available");
}
$("#derived_public_key").val(result.extended_public_key_string("base58"));
$("#derived_public_key_hex").val(Crypto.util.bytesToHex(result.eckey.pub.getEncoded(true)));
var hash160 = result.eckey.pubKeyHash;
var addr = new Bitcoin.Address(hash160);
addr.version = key_coin.prefix;
$("#addr").val(addr.toString());
var qrCode = qrcode(3, 'M');
var text = $('#addr').val();
text = text.replace(/^[\s\u3000]+|[\s\u3000]+$/g, '');
qrCode.addData(text);
qrCode.make();
$('#genAddrQR').html(qrCode.createImgTag(4));
$('#genAddrURL').attr('href', ADDRESS_URL_PREFIX+text);
$('#genAddrURL').attr('title', text);
if(key_coin.name == "Bitcoin Cash") {
var bch_addr;
if(key_coin.bip32_private == BITCOIN_CASH_TESTNET_PRIVATE) {
bch_addr = cashaddr.encode("bchtest", "P2PKH", new Uint8Array(result.eckey.pubKeyHash));
} else {
bch_addr = cashaddr.encode("bitcoincash", "P2PKH", new Uint8Array(result.eckey.pubKeyHash));
}
$("#cashaddr").val(bch_addr);
$("#addrlabel").text("Legacy Address");
$("#qraddrlabel").text("Legacy Address QR Code");
qrCode = qrcode(4, 'M');
qrCode.addData(bch_addr);
qrCode.make();
$('#genCashAddrQR').html(qrCode.createImgTag(4));
$('#genCashAddrURL').attr('href', ADDRESS_URL_PREFIX+bch_addr);
$('#genCashAddrURL').attr('title', bch_addr);
$("#cashaddr_group").show();
} else {
$("#addrlabel").text("Address");
$("#qraddrlabel").text("Address QR Code");
$("#cashaddr_group").hide();
}
}
function onInput(id, func) {
$(id).bind("input keyup keydown keypress change blur", function() {
if ($(this).val() != jQuery.data(this, "lastvalue")) {
func();
}
jQuery.data(this, "lastvalue", $(this).val());
});
$(id).bind("focus", function() {
jQuery.data(this, "lastvalue", $(this).val());
});
}
function crChange(e)
{
var key_coin = getCoinFromKey(bip32_source_key);
e.preventDefault();
coin = $(this).attr("id");
ADDRESS_URL_PREFIX = $(this).attr('href');
$('#crName').text($(this).text());
$('#crSelect').dropdown('toggle');
if((coin == "bch_main" || coin == "bch_test") && !acknowledged_bch_is_experimental) {
alert("Warning!\n\nBitcoin Cash support is NEW and EXPERIMENTAL.\n\nPlease verify your addresses with other services before using!");
acknowledged_bch_is_experimental = true;
}
if( gen_from == 'pass' && bip32_source_key === null ) {
updateSourcePassphrase();
} else if( bip32_source_key !== null ) {
if( coin != key_coin ) { // key is changing to another realm..
var is_private = (bip32_source_key.version == key_coin.bip32_private);
var is_public = (bip32_source_key.version == key_coin.bip32_public);
if( is_public ) {
bip32_source_key.version = COINS[coin].bip32_public;
bip32_source_key.build_extended_public_key();
$("#bip32_source_key").val(bip32_source_key.extended_public_key_string("base58"));
} else if( is_private ) {
bip32_source_key.version = COINS[coin].bip32_private;
bip32_source_key.build_extended_public_key();
bip32_source_key.build_extended_private_key();
$("#bip32_source_key").val(bip32_source_key.extended_private_key_string("base58"));
}
}
updateSourceKey();
}
return false;
}
// -- web worker for hashing passphrase --
function hash_worker_message(e) {
// ignore the hash worker
if(!hash_worker_working) return;
var m = e.data;
switch(m.cmd) {
case 'progress':
$("#bip32_hashing_progress_bar").width('' + m.progress + "%");
break;
case 'done':
$("#bip32_hashing_progress_bar").width('100%');
$("#bip32_hashing_style").removeClass("active");
$("#cancel_hash_worker").attr('disabled', true);
hash_worker_working = false;
bip32_passphrase_hash = m.result;
updatePassphraseHash();
break;
}
console.log(m);
}
function start_hash_worker(passphrase) {
if( hash_worker === null ) {
hash_worker = new Worker("js/hash_worker.js");
hash_worker.addEventListener('message', hash_worker_message, false);
}
bip32_passphrase_hash = null;
bip32_source_key = null;
$("#bip32_source_key").val('');
updateSourceKey();
updateResult();
$("#bip32_hashing_progress_bar").css('width', '0%');
$("#bip32_hashing_style").addClass("active");
hash_worker_working = true;
$("#cancel_hash_worker").attr('disabled', false);
hash_worker.postMessage({"cmd": "start", "bip32_source_passphrase": passphrase});
}
function stop_hash_worker() {
$("#cancel_hash_worker").attr('disabled', true);
hash_worker_working = false;
$("#bip32_hashing_progress_bar").css("width", "0%");
if( hash_worker != null ) {
hash_worker.postMessage({"cmd": "stop"});
}
}
function revealKeyQRClicked() {
$("#revealKeyQR").hide();
qrCode = qrcode(5, 'Q');
qrCode.addData($("#derived_private_key_wif").val());
qrCode.make();
$('#genKeyQR').html(qrCode.createImgTag(4));
$('#genKeyURL').attr('title','Click again to hide');
$('#genKeyURL').show();
}
function hideKeyQRClicked() {
$('#genKeyURL').hide();
$("#revealKeyQR").show();
}
$(document).ready( function() {
if (window.location.hash)
$('#tab-' + window.location.hash.substr(1).split('?')[0]).tab('show');
$('a[data-toggle="tab"]').on('click', function (e) {
window.location.hash = $(this).attr('href');
});
// bip32
$('#gen_from label input').on('change', onUpdateGenFrom );
updateGenFrom();
$("#bip32_source_passphrase").val("crazy horse battery staple");
$("#bip32_source_key").val("xprv9s21ZrQH143K2JF8RafpqtKiTbsbaxEeUaMnNHsm5o6wCW3z8ySyH4UxFVSfZ8n7ESu7fgir8imbZKLYVBxFPND1pniTZ81vKfd45EHKX73");
onInput("#bip32_source_passphrase", onUpdateSourcePassphrase);
$("#checkbox_show_passphrase").on('change', onShowPassphraseChanged );
$("#cancel_hash_worker").on('click', onCancelHashWorkerClicked);
onInput("#bip32_source_key", onUpdateSourceKey);
$("#bip32_hashing_progress_bar").width('100%');
$("#cancel_hash_worker").attr('disabled', true);
updateSourceKey();
$('#bip32_derivation_path').on('change', onUpdateDerivationPath);
onInput("#bip32_custom_path", onUpdateCustomPath);
onInput("#account_index", onAccountIndexChanged);
onInput("#keypair_index", onKeypairIndexChanged);
updateDerivationPath();
// currency select
$('#crCurrency ul li a').on('click', crChange);
$('#genKeyURL').hide();
$("#revealKeyQR").on('click', revealKeyQRClicked);
$('#genKeyURL').on('click', hideKeyQRClicked);
});
})(jQuery);

8
js/cashaddrjs-0.2.8.min.js vendored Normal file

File diff suppressed because one or more lines are too long

7
js/crypto-min.js vendored Normal file
View File

@@ -0,0 +1,7 @@
/*
* Crypto-JS v2.0.0
* http://code.google.com/p/crypto-js/
* Copyright (c) 2009, Jeff Mott. All rights reserved.
* http://code.google.com/p/crypto-js/wiki/License
*/
(function(){var c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var d=Crypto={};var a=d.util={rotl:function(h,g){return(h<<g)|(h>>>(32-g))},rotr:function(h,g){return(h<<(32-g))|(h>>>g)},endian:function(h){if(h.constructor==Number){return a.rotl(h,8)&16711935|a.rotl(h,24)&4278255360}for(var g=0;g<h.length;g++){h[g]=a.endian(h[g])}return h},randomBytes:function(h){for(var g=[];h>0;h--){g.push(Math.floor(Math.random()*256))}return g},bytesToWords:function(h){for(var k=[],j=0,g=0;j<h.length;j++,g+=8){k[g>>>5]|=h[j]<<(24-g%32)}return k},wordsToBytes:function(i){for(var h=[],g=0;g<i.length*32;g+=8){h.push((i[g>>>5]>>>(24-g%32))&255)}return h},bytesToHex:function(g){for(var j=[],h=0;h<g.length;h++){j.push((g[h]>>>4).toString(16));j.push((g[h]&15).toString(16))}return j.join("")},hexToBytes:function(h){for(var g=[],i=0;i<h.length;i+=2){g.push(parseInt(h.substr(i,2),16))}return g},bytesToBase64:function(h){if(typeof btoa=="function"){return btoa(e.bytesToString(h))}for(var g=[],l=0;l<h.length;l+=3){var m=(h[l]<<16)|(h[l+1]<<8)|h[l+2];for(var k=0;k<4;k++){if(l*8+k*6<=h.length*8){g.push(c.charAt((m>>>6*(3-k))&63))}else{g.push("=")}}}return g.join("")},base64ToBytes:function(h){if(typeof atob=="function"){return e.stringToBytes(atob(h))}h=h.replace(/[^A-Z0-9+\/]/ig,"");for(var g=[],j=0,k=0;j<h.length;k=++j%4){if(k==0){continue}g.push(((c.indexOf(h.charAt(j-1))&(Math.pow(2,-2*k+8)-1))<<(k*2))|(c.indexOf(h.charAt(j))>>>(6-k*2)))}return g}};d.mode={};var b=d.charenc={};var f=b.UTF8={stringToBytes:function(g){return e.stringToBytes(unescape(encodeURIComponent(g)))},bytesToString:function(g){return decodeURIComponent(escape(e.bytesToString(g)))}};var e=b.Binary={stringToBytes:function(j){for(var g=[],h=0;h<j.length;h++){g.push(j.charCodeAt(h))}return g},bytesToString:function(g){for(var j=[],h=0;h<g.length;h++){j.push(String.fromCharCode(g[h]))}return j.join("")}}})();

129
js/electrum.js Normal file
View File

@@ -0,0 +1,129 @@
/*
electrum.js : Electrum deterministic wallet implementation (public domain)
*/
function electrum_extend_chain(pubKey, privKey, n, forChange, fromPrivKey) {
var curve = getSECCurveByName("secp256k1");
var mode = forChange ? 1 : 0;
var mpk = pubKey.slice(1);
var bytes = Crypto.charenc.UTF8.stringToBytes(n + ':' + mode + ':').concat(mpk);
var sequence = Crypto.SHA256(Crypto.SHA256(bytes, {asBytes: true}), {asBytes: true});
var secexp = null;
var pt = ECPointFp.decodeFrom(curve.getCurve(), pubKey);
var A;
if (fromPrivKey) {
A = BigInteger.fromByteArrayUnsigned(sequence);
var B = BigInteger.fromByteArrayUnsigned(privKey);
var C = curve.getN();
secexp = A.add(B).mod(C);
pt = pt.add(curve.getG().multiply(A));
} else {
A = BigInteger.fromByteArrayUnsigned(sequence);
pt = pt.add(curve.getG().multiply(A));
}
var newPriv = secexp ? secexp.toByteArrayUnsigned(): [];
for(;newPriv.length<32;) newPriv.unshift(0x00);
var newPub = pt.getEncoded();
var h160 = Bitcoin.Util.sha256ripe160(newPub);
var addr = new Bitcoin.Address(h160);
var sec = secexp ? new Bitcoin.Address(newPriv) : '';
if (secexp)
sec.version = 128;
return [addr.toString(), sec.toString(), newPub, newPriv];
}
function electrum_get_pubkey(privKey) {
var curve = getSECCurveByName("secp256k1");
var secexp = BigInteger.fromByteArrayUnsigned(privKey);
var pt = curve.getG().multiply(secexp);
return pt.getEncoded();
}
var Electrum = new function () {
var seedRounds = 100000;
var seed;
var oldseed;
var pubKey;
var privKey;
var rounds;
var range;
var counter;
var timeout;
var onUpdate;
var onSuccess;
var addChange;
function calcSeed() {
if (rounds < seedRounds) {
var portion = seedRounds / 100;
onUpdate(rounds * 100 / seedRounds, seed);
for (var i = 0; i < portion; i++)
seed = Crypto.SHA256(seed.concat(oldseed), {asBytes: true});
rounds += portion;
if (rounds < seedRounds) {
timeout = setTimeout(calcSeed, 0);
} else {
privKey = seed;
pubKey = electrum_get_pubkey(privKey);
onSuccess(privKey);
}
}
}
function calcAddr() {
var r = electrum_extend_chain(pubKey, privKey, counter % range, counter >= range, true);
onUpdate(r);
counter++;
if (counter >= range+addChange) {
if (onSuccess)
onSuccess();
} else {
timeout = setTimeout(calcAddr, 0);
}
}
this.init = function(_seed, update, success) {
seed = Crypto.charenc.UTF8.stringToBytes(_seed);
oldseed = seed.slice(0);
rounds = 0;
onUpdate = update;
onSuccess = success;
clearTimeout(timeout);
calcSeed();
};
this.gen = function(_range, update, success, useChange) {
addChange = useChange;
range = _range;
counter = 0;
onUpdate = update;
onSuccess = success;
clearTimeout(timeout);
calcAddr();
};
this.stop = function () {
clearTimeout(timeout);
};
return this;
};
function electrum_test() {
Electrum.init('12345678', function(r) {console.log(r);},
function() {Electrum.gen(5, function(r) {console.log(r);});});
/*
1DLHQhEuLftmAMTiYhw4DvVWhFQ9hnbXio
1HvoaBYqebPqFaS7GEZzywTaiTrS8cSaCF
1KMtsVJdde66kjgaK5dcte3TiWfFBF2bC7
159zjjZB3TadPXE3oeei5MfxTCYu5bqDCd
1H4uQ5i3MWSiUdHLJiPop9HWw2fe96CrLR
1EkX2PAY21FuqsKVirZS6wkLkSwbbE4EFD
*/
}

66
js/hash_worker.js Normal file
View File

@@ -0,0 +1,66 @@
importScripts("crypto-min.js");
importScripts("sha256.js");
(function() {
var state = 'stopped';
var bip32_source_passphrase = null;
var last = null;
var index = 0;
var COUNT = 50000;
var STEP = 500;
function message_handler(e) {
var m = e.data;
switch (m.cmd) {
case 'start':
last = Crypto.util.hexToBytes("0000000000000000000000000000000000000000000000000000000000000000"); // 256-bit 0
bip32_source_passphrase = m.bip32_source_passphrase;
state = 'start';
break;
case 'stop':
state = 'stopped';
break;
default:
break;
};
}
self.addEventListener('message', message_handler, false);
function main() {
var loop = 0;
for(var loop = 0; loop < 100; loop++) {
switch(state) {
case 'stopped':
setTimeout(main, 1000);
return;
case 'start':
self.postMessage({'cmd': 'progress', 'progress': 0});
index = 0;
state = 'hashing';
// fall through
case 'hashing':
var hasher = new jsSHA(Crypto.util.bytesToHex(last), 'HEX');
last = Crypto.util.hexToBytes(hasher.getHMAC(bip32_source_passphrase, "TEXT", "SHA-256", "HEX"));
index += 1;
if( index >= COUNT ) {
self.postMessage({'cmd': 'done', 'result': Crypto.util.bytesToHex(last)});
state = 'stopped';
} else if( (index % STEP) == 0 ) {
self.postMessage({'cmd': 'progress', 'progress': Math.floor((100 * index / COUNT) + 0.5)});
}
break;
default:
break;
}
}
// we use this style of run-some, wait-some to allow the browser to parse messages,
// allowing us to restart/stop mid-hash
setTimeout(main, 0);
}
main();
})();

33
js/htmlpost.xml Normal file
View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<table xmlns="http://query.yahooapis.com/v1/schema/table.xsd">
<meta>
<author>brainwallet</author>
<description>POST method for YQL</description>
<sampleQuery><![CDATA[
select * from {table} where url='http://example.com'
and postdata="foo=foo&bar=bar" and xpath="//p"]]></sampleQuery>
<documentationURL></documentationURL>
</meta>
<bindings>
<select itemPath="" produces="XML">
<urls>
<url>{url}</url>
</urls>
<inputs>
<key id="url" type="xs:string" required="true" paramType="variable"/>
<key id="postdata" type="xs:string" required="true" paramType="variable"/>
<key id="xpath" type="xs:string" required="true" paramType="variable"/>
</inputs>
<execute>
<![CDATA[
var myRequest = y.rest(url);
var data = myRequest.accept('text/html').
contentType("application/x-www-form-urlencoded").
post(postdata).response;
var xdata = y.xpath(data,xpath);
response.object = <postresult>{xdata}</postresult>;
]]>
</execute>
</select>
</bindings>
</table>

6
js/jquery.js vendored Normal file

File diff suppressed because one or more lines are too long

255
js/mnemonic.js Normal file
View File

@@ -0,0 +1,255 @@
/*
mnemonic.js : Converts between 4-byte aligned strings and a human-readable
sequence of words. Uses 1626 common words taken from wikipedia article:
http://en.wiktionary.org/wiki/Wiktionary:Frequency_lists/Contemporary_poetry
Originally written in python special for Electrum (lightweight Bitcoin client).
This version has been reimplemented in javascript and placed in public domain.
*/
function mn_encode(str) {
var out = [];
var n = mn_words.length;
for (var i = 0; i < str.length; i += 8) {
var x = parseInt(str.substr(i, 8), 16);
var w1 = (x % n);
var w2 = (Math.floor(x/n) + w1) % n;
var w3 = (Math.floor(Math.floor(x/n)/n) + w2) % n;
out = out.concat([mn_words[w1], mn_words[w2], mn_words[w3]]);
}
return out.join(' ');
}
function mn_mod(a, b) {
return a < 0 ? b + a : a % b;
}
function mn_decode(str) {
var out = '';
var n = mn_words.length;
var wlist = str.split(' ');
for (var i = 0; i < wlist.length; i += 3) {
var w1 = mn_words.indexOf(wlist[i]);
var w2 = (mn_words.indexOf(wlist[i+1])) % n;
var w3 = (mn_words.indexOf(wlist[i+2])) % n;
var x = w1 + n * mn_mod((w2 - w1), n) + n * n * mn_mod((w3 - w2), n);
out += ('0000000' + x.toString(16)).slice(-8);
}
return out;
}
var mn_words = [
"like", "just", "love", "know", "never", "want", "time", "out", "there",
"make", "look", "eye", "down", "only", "think", "heart", "back", "then",
"into", "about", "more", "away", "still", "them", "take", "thing", "even",
"through", "long", "always", "world", "too", "friend", "tell", "try",
"hand", "thought", "over", "here", "other", "need", "smile", "again",
"much", "cry", "been", "night", "ever", "little", "said", "end", "some",
"those", "around", "mind", "people", "girl", "leave", "dream", "left",
"turn", "myself", "give", "nothing", "really", "off", "before",
"something", "find", "walk", "wish", "good", "once", "place", "ask",
"stop", "keep", "watch", "seem", "everything", "wait", "got", "yet",
"made", "remember", "start", "alone", "run", "hope", "maybe", "believe",
"body", "hate", "after", "close", "talk", "stand", "own", "each", "hurt",
"help", "home", "god", "soul", "new", "many", "two", "inside", "should",
"true", "first", "fear", "mean", "better", "play", "another", "gone",
"change", "use", "wonder", "someone", "hair", "cold", "open", "best",
"any", "behind", "happen", "water", "dark", "laugh", "stay", "forever",
"name", "work", "show", "sky", "break", "came", "deep", "door", "put",
"black", "together", "upon", "happy", "such", "great", "white", "matter",
"fill", "past", "please", "burn", "cause", "enough", "touch", "moment",
"soon", "voice", "scream", "anything", "stare", "sound", "red", "everyone",
"hide", "kiss", "truth", "death", "beautiful", "mine", "blood", "broken",
"very", "pass", "next", "forget", "tree", "wrong", "air", "mother",
"understand", "lip", "hit", "wall", "memory", "sleep", "free", "high",
"realize", "school", "might", "skin", "sweet", "perfect", "blue", "kill",
"breath", "dance", "against", "fly", "between", "grow", "strong", "under",
"listen", "bring", "sometimes", "speak", "pull", "person", "become",
"family", "begin", "ground", "real", "small", "father", "sure", "feet",
"rest", "young", "finally", "land", "across", "today", "different", "guy",
"line", "fire", "reason", "reach", "second", "slowly", "write", "eat",
"smell", "mouth", "step", "learn", "three", "floor", "promise", "breathe",
"darkness", "push", "earth", "guess", "save", "song", "above", "along",
"both", "color", "house", "almost", "sorry", "anymore", "brother", "okay",
"dear", "game", "fade", "already", "apart", "warm", "beauty", "heard",
"notice", "question", "shine", "began", "piece", "whole", "shadow",
"secret", "street", "within", "finger", "point", "morning", "whisper",
"child", "moon", "green", "story", "glass", "kid", "silence", "since",
"soft", "yourself", "empty", "shall", "angel", "answer", "baby", "bright",
"dad", "path", "worry", "hour", "drop", "follow", "power", "war", "half",
"flow", "heaven", "act", "chance", "fact", "least", "tired", "children",
"near", "quite", "afraid", "rise", "sea", "taste", "window", "cover",
"nice", "trust", "lot", "sad", "cool", "force", "peace", "return", "blind",
"easy", "ready", "roll", "rose", "drive", "held", "music", "beneath",
"hang", "mom", "paint", "emotion", "quiet", "clear", "cloud", "few",
"pretty", "bird", "outside", "paper", "picture", "front", "rock", "simple",
"anyone", "meant", "reality", "road", "sense", "waste", "bit", "leaf",
"thank", "happiness", "meet", "men", "smoke", "truly", "decide", "self",
"age", "book", "form", "alive", "carry", "escape", "damn", "instead",
"able", "ice", "minute", "throw", "catch", "leg", "ring", "course",
"goodbye", "lead", "poem", "sick", "corner", "desire", "known", "problem",
"remind", "shoulder", "suppose", "toward", "wave", "drink", "jump",
"woman", "pretend", "sister", "week", "human", "joy", "crack", "grey",
"pray", "surprise", "dry", "knee", "less", "search", "bleed", "caught",
"clean", "embrace", "future", "king", "son", "sorrow", "chest", "hug",
"remain", "sat", "worth", "blow", "daddy", "final", "parent", "tight",
"also", "create", "lonely", "safe", "cross", "dress", "evil", "silent",
"bone", "fate", "perhaps", "anger", "class", "scar", "snow", "tiny",
"tonight", "continue", "control", "dog", "edge", "mirror", "month",
"suddenly", "comfort", "given", "loud", "quickly", "gaze", "plan", "rush",
"stone", "town", "battle", "ignore", "spirit", "stood", "stupid", "yours",
"brown", "build", "dust", "hey", "kept", "pay", "phone", "twist",
"although", "ball", "beyond", "hidden", "nose", "taken", "fail", "float",
"pure", "somehow", "wash", "wrap", "angry", "cheek", "creature",
"forgotten", "heat", "rip", "single", "space", "special", "weak",
"whatever", "yell", "anyway", "blame", "job", "choose", "country", "curse",
"drift", "echo", "figure", "grew", "laughter", "neck", "suffer", "worse",
"yeah", "disappear", "foot", "forward", "knife", "mess", "somewhere",
"stomach", "storm", "beg", "idea", "lift", "offer", "breeze", "field",
"five", "often", "simply", "stuck", "win", "allow", "confuse", "enjoy",
"except", "flower", "seek", "strength", "calm", "grin", "gun", "heavy",
"hill", "large", "ocean", "shoe", "sigh", "straight", "summer", "tongue",
"accept", "crazy", "everyday", "exist", "grass", "mistake", "sent", "shut",
"surround", "table", "ache", "brain", "destroy", "heal", "nature", "shout",
"sign", "stain", "choice", "doubt", "glance", "glow", "mountain", "queen",
"stranger", "throat", "tomorrow", "city", "either", "fish", "flame",
"rather", "shape", "spin", "spread", "ash", "distance", "finish", "image",
"imagine", "important", "nobody", "shatter", "warmth", "became", "feed",
"flesh", "funny", "lust", "shirt", "trouble", "yellow", "attention",
"bare", "bite", "money", "protect", "amaze", "appear", "born", "choke",
"completely", "daughter", "fresh", "friendship", "gentle", "probably",
"six", "deserve", "expect", "grab", "middle", "nightmare", "river",
"thousand", "weight", "worst", "wound", "barely", "bottle", "cream",
"regret", "relationship", "stick", "test", "crush", "endless", "fault",
"itself", "rule", "spill", "art", "circle", "join", "kick", "mask",
"master", "passion", "quick", "raise", "smooth", "unless", "wander",
"actually", "broke", "chair", "deal", "favorite", "gift", "note", "number",
"sweat", "box", "chill", "clothes", "lady", "mark", "park", "poor",
"sadness", "tie", "animal", "belong", "brush", "consume", "dawn", "forest",
"innocent", "pen", "pride", "stream", "thick", "clay", "complete", "count",
"draw", "faith", "press", "silver", "struggle", "surface", "taught",
"teach", "wet", "bless", "chase", "climb", "enter", "letter", "melt",
"metal", "movie", "stretch", "swing", "vision", "wife", "beside", "crash",
"forgot", "guide", "haunt", "joke", "knock", "plant", "pour", "prove",
"reveal", "steal", "stuff", "trip", "wood", "wrist", "bother", "bottom",
"crawl", "crowd", "fix", "forgive", "frown", "grace", "loose", "lucky",
"party", "release", "surely", "survive", "teacher", "gently", "grip",
"speed", "suicide", "travel", "treat", "vein", "written", "cage", "chain",
"conversation", "date", "enemy", "however", "interest", "million", "page",
"pink", "proud", "sway", "themselves", "winter", "church", "cruel", "cup",
"demon", "experience", "freedom", "pair", "pop", "purpose", "respect",
"shoot", "softly", "state", "strange", "bar", "birth", "curl", "dirt",
"excuse", "lord", "lovely", "monster", "order", "pack", "pants", "pool",
"scene", "seven", "shame", "slide", "ugly", "among", "blade", "blonde",
"closet", "creek", "deny", "drug", "eternity", "gain", "grade", "handle",
"key", "linger", "pale", "prepare", "swallow", "swim", "tremble", "wheel",
"won", "cast", "cigarette", "claim", "college", "direction", "dirty",
"gather", "ghost", "hundred", "loss", "lung", "orange", "present", "swear",
"swirl", "twice", "wild", "bitter", "blanket", "doctor", "everywhere",
"flash", "grown", "knowledge", "numb", "pressure", "radio", "repeat",
"ruin", "spend", "unknown", "buy", "clock", "devil", "early", "false",
"fantasy", "pound", "precious", "refuse", "sheet", "teeth", "welcome",
"add", "ahead", "block", "bury", "caress", "content", "depth", "despite",
"distant", "marry", "purple", "threw", "whenever", "bomb", "dull",
"easily", "grasp", "hospital", "innocence", "normal", "receive", "reply",
"rhyme", "shade", "someday", "sword", "toe", "visit", "asleep", "bought",
"center", "consider", "flat", "hero", "history", "ink", "insane", "muscle",
"mystery", "pocket", "reflection", "shove", "silently", "smart", "soldier",
"spot", "stress", "train", "type", "view", "whether", "bus", "energy",
"explain", "holy", "hunger", "inch", "magic", "mix", "noise", "nowhere",
"prayer", "presence", "shock", "snap", "spider", "study", "thunder",
"trail", "admit", "agree", "bag", "bang", "bound", "butterfly", "cute",
"exactly", "explode", "familiar", "fold", "further", "pierce", "reflect",
"scent", "selfish", "sharp", "sink", "spring", "stumble", "universe",
"weep", "women", "wonderful", "action", "ancient", "attempt", "avoid",
"birthday", "branch", "chocolate", "core", "depress", "drunk",
"especially", "focus", "fruit", "honest", "match", "palm", "perfectly",
"pillow", "pity", "poison", "roar", "shift", "slightly", "thump", "truck",
"tune", "twenty", "unable", "wipe", "wrote", "coat", "constant", "dinner",
"drove", "egg", "eternal", "flight", "flood", "frame", "freak", "gasp",
"glad", "hollow", "motion", "peer", "plastic", "root", "screen", "season",
"sting", "strike", "team", "unlike", "victim", "volume", "warn", "weird",
"attack", "await", "awake", "built", "charm", "crave", "despair", "fought",
"grant", "grief", "horse", "limit", "message", "ripple", "sanity",
"scatter", "serve", "split", "string", "trick", "annoy", "blur", "boat",
"brave", "clearly", "cling", "connect", "fist", "forth", "imagination",
"iron", "jock", "judge", "lesson", "milk", "misery", "nail", "naked",
"ourselves", "poet", "possible", "princess", "sail", "size", "snake",
"society", "stroke", "torture", "toss", "trace", "wise", "bloom", "bullet",
"cell", "check", "cost", "darling", "during", "footstep", "fragile",
"hallway", "hardly", "horizon", "invisible", "journey", "midnight", "mud",
"nod", "pause", "relax", "shiver", "sudden", "value", "youth", "abuse",
"admire", "blink", "breast", "bruise", "constantly", "couple", "creep",
"curve", "difference", "dumb", "emptiness", "gotta", "honor", "plain",
"planet", "recall", "rub", "ship", "slam", "soar", "somebody", "tightly",
"weather", "adore", "approach", "bond", "bread", "burst", "candle",
"coffee", "cousin", "crime", "desert", "flutter", "frozen", "grand",
"heel", "hello", "language", "level", "movement", "pleasure", "powerful",
"random", "rhythm", "settle", "silly", "slap", "sort", "spoken", "steel",
"threaten", "tumble", "upset", "aside", "awkward", "bee", "blank", "board",
"button", "card", "carefully", "complain", "crap", "deeply", "discover",
"drag", "dread", "effort", "entire", "fairy", "giant", "gotten", "greet",
"illusion", "jeans", "leap", "liquid", "march", "mend", "nervous", "nine",
"replace", "rope", "spine", "stole", "terror", "accident", "apple",
"balance", "boom", "childhood", "collect", "demand", "depression",
"eventually", "faint", "glare", "goal", "group", "honey", "kitchen",
"laid", "limb", "machine", "mere", "mold", "murder", "nerve", "painful",
"poetry", "prince", "rabbit", "shelter", "shore", "shower", "soothe",
"stair", "steady", "sunlight", "tangle", "tease", "treasure", "uncle",
"begun", "bliss", "canvas", "cheer", "claw", "clutch", "commit", "crimson",
"crystal", "delight", "doll", "existence", "express", "fog", "football",
"gay", "goose", "guard", "hatred", "illuminate", "mass", "math", "mourn",
"rich", "rough", "skip", "stir", "student", "style", "support", "thorn",
"tough", "yard", "yearn", "yesterday", "advice", "appreciate", "autumn",
"bank", "beam", "bowl", "capture", "carve", "collapse", "confusion",
"creation", "dove", "feather", "girlfriend", "glory", "government",
"harsh", "hop", "inner", "loser", "moonlight", "neighbor", "neither",
"peach", "pig", "praise", "screw", "shield", "shimmer", "sneak", "stab",
"subject", "throughout", "thrown", "tower", "twirl", "wow", "army",
"arrive", "bathroom", "bump", "cease", "cookie", "couch", "courage", "dim",
"guilt", "howl", "hum", "husband", "insult", "led", "lunch", "mock",
"mostly", "natural", "nearly", "needle", "nerd", "peaceful", "perfection",
"pile", "price", "remove", "roam", "sanctuary", "serious", "shiny",
"shook", "sob", "stolen", "tap", "vain", "void", "warrior", "wrinkle",
"affection", "apologize", "blossom", "bounce", "bridge", "cheap",
"crumble", "decision", "descend", "desperately", "dig", "dot", "flip",
"frighten", "heartbeat", "huge", "lazy", "lick", "odd", "opinion",
"process", "puzzle", "quietly", "retreat", "score", "sentence", "separate",
"situation", "skill", "soak", "square", "stray", "taint", "task", "tide",
"underneath", "veil", "whistle", "anywhere", "bedroom", "bid", "bloody",
"burden", "careful", "compare", "concern", "curtain", "decay", "defeat",
"describe", "double", "dreamer", "driver", "dwell", "evening", "flare",
"flicker", "grandma", "guitar", "harm", "horrible", "hungry", "indeed",
"lace", "melody", "monkey", "nation", "object", "obviously", "rainbow",
"salt", "scratch", "shown", "shy", "stage", "stun", "third", "tickle",
"useless", "weakness", "worship", "worthless", "afternoon", "beard",
"boyfriend", "bubble", "busy", "certain", "chin", "concrete", "desk",
"diamond", "doom", "drawn", "due", "felicity", "freeze", "frost", "garden",
"glide", "harmony", "hopefully", "hunt", "jealous", "lightning", "mama",
"mercy", "peel", "physical", "position", "pulse", "punch", "quit", "rant",
"respond", "salty", "sane", "satisfy", "savior", "sheep", "slept",
"social", "sport", "tuck", "utter", "valley", "wolf", "aim", "alas",
"alter", "arrow", "awaken", "beaten", "belief", "brand", "ceiling",
"cheese", "clue", "confidence", "connection", "daily", "disguise", "eager",
"erase", "essence", "everytime", "expression", "fan", "flag", "flirt",
"foul", "fur", "giggle", "glorious", "ignorance", "law", "lifeless",
"measure", "mighty", "muse", "north", "opposite", "paradise", "patience",
"patient", "pencil", "petal", "plate", "ponder", "possibly", "practice",
"slice", "spell", "stock", "strife", "strip", "suffocate", "suit",
"tender", "tool", "trade", "velvet", "verse", "waist", "witch", "aunt",
"bench", "bold", "cap", "certainly", "click", "companion", "creator",
"dart", "delicate", "determine", "dish", "dragon", "drama", "drum", "dude",
"everybody", "feast", "forehead", "former", "fright", "fully", "gas",
"hook", "hurl", "invite", "juice", "manage", "moral", "possess", "raw",
"rebel", "royal", "scale", "scary", "several", "slight", "stubborn",
"swell", "talent", "tea", "terrible", "thread", "torment", "trickle",
"usually", "vast", "violence", "weave", "acid", "agony", "ashamed", "awe",
"belly", "blend", "blush", "character", "cheat", "common", "company",
"coward", "creak", "danger", "deadly", "defense", "define", "depend",
"desperate", "destination", "dew", "duck", "dusty", "embarrass", "engine",
"example", "explore", "foe", "freely", "frustrate", "generation", "glove",
"guilty", "health", "hurry", "idiot", "impossible", "inhale", "jaw",
"kingdom", "mention", "mist", "moan", "mumble", "mutter", "observe", "ode",
"pathetic", "pattern", "pie", "prefer", "puff", "rape", "rare", "revenge",
"rude", "scrape", "spiral", "squeeze", "strain", "sunset", "suspend",
"sympathy", "thigh", "throne", "total", "unseen", "weapon", "weary"
];

139
js/modsqrt.js Normal file
View File

@@ -0,0 +1,139 @@
/*
* ModSqrt borrowed and translated from http://eli.thegreenplace.net/2009/03/07/computing-modular-square-roots-in-python/
*/
function LegendreSymbol(a, p) {
var r = a.modPow(p.subtract(BigInteger.ONE).divide(new BigInteger("2")), p);
if( r.equals(p.subtract(BigInteger.ONE)) ) return new BigInteger("-1");
return r;
}
/* return `ret' such that ret^2 = this (mod p) */
function bnModSqrt(p) {
var TWO = new BigInteger("2");
var NEG_ONE = new BigInteger("-1");
if( !(LegendreSymbol(this, p).equals(BigInteger.ONE)) )
return BigInteger.ZERO;
if( this.equals(BigInteger.ZERO) )
return BigInteger.ZERO;
if( p.equals(TWO) )
return p;
if( p.mod(new BigInteger("4")).equals(new BigInteger("3")) )
return this.modPow(p.add(BigInteger.ONE).divide(new BigInteger("4")), p);
var s = p.subtract(BigInteger.ONE);
var e = 0;
while( s.mod(TWO).equals(BigInteger.ZERO) ) {
s = s.divide(TWO);
e += 1;
}
// find some legendre symbol n|p = -1
var n = TWO;
while( !LegendreSymbol(n, p).equals(NEG_ONE) ) {
n = n.add(BigInteger.ONE);
}
console.log("LegendreSymbol found: " + n);
/*
* Here be dragons!
* Read the paper "Square roots from 1; 24, 51,
* 10 to Dan Shanks" by Ezra Brown for more
* information
*
* x is a guess of the square root that gets better
* with each iteration.
* b is the "fudge factor" - by how much we're off
* with the guess. The invariant x^2 = ab (mod p)
* is maintained throughout the loop.
* g is used for successive powers of n to update
* both a and b
* r is the exponent - decreases with each update
*/
var x = this.modPow(s.add(BigInteger.ONE).divide(TWO), p);
var b = this.modPow(s, p);
var g = n.modPow(s, p);
var r = e;
var q = BigInteger.ZERO.clone();
while(true) {
var t = b.clone();
var m = 0;
for( ; m < r; m += 1 ) {
if(t.equals(BigInteger.ONE))
break;
t = t.modPow(TWO, p);
}
if( m == 0 )
return x;
q.fromInt(r - m - 1);
var gs = g.modPow(TWO.pow(q), p);
g = gs.multiply(gs).mod(p);
x = x.multiply(gs).mod(p);
b = b.multiply(g).mod(p);
r = m;
}
}
BigInteger.prototype.modSqrt = bnModSqrt;
$(document).ready( function() {
return; // Comment out to run tests
var ecparams = getSECCurveByName("secp256k1");
console.log(ecparams);
var test_modsqrt = function(compressed_key_str, check_y_str) {
var key_bytes = Crypto.util.hexToBytes(compressed_key_str);
console.log(key_bytes);
var y_bit = u8(key_bytes.slice(0, 1)) & 0x01;
var x = BigInteger.ZERO.clone();
x.fromString(Crypto.util.bytesToHex(key_bytes.slice(1, 33)), 16);
console.log('x = ' + Crypto.util.bytesToHex(x.toByteArrayUnsigned()));
var curve = ecparams.getCurve();
var a = curve.getA().toBigInteger();
var b = curve.getB().toBigInteger();
var p = curve.getQ();
var tmp = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
console.log('tmp = ' + Crypto.util.bytesToHex(tmp.toByteArrayUnsigned()));
var y = tmp.modSqrt(p);
if( (y[0] & 0x01) != y_bit ) {
y = y.multiply(new BigInteger("-1")).mod(p);
}
console.log('y = ' + Crypto.util.bytesToHex(y.toByteArrayUnsigned()));
var check_y = BigInteger.ZERO.clone();
check_y.fromString(check_y_str, 16);
if( !y.equals(check_y) ) {
alert("Error in modSqrt");
}
}
// ECDSA private key (random number / secret exponent) = 863abb33f3e3305a78f56285c5aa42bcf85c2cdef2cface9346c65233da4e3e1
// ECDSA public key (uncompressed) = 04aeb681df5ac19e449a872b9e9347f1db5a0394d2ec5caf2a9c143f86e232b0d9eb0124240d225ed0ccfb2dfa9ad05d1e5e0c7941ee5c518b398145f202cb1d13
// ECDSA public key (compressed) = 03aeb681df5ac19e449a872b9e9347f1db5a0394d2ec5caf2a9c143f86e232b0d9
test_modsqrt('03aeb681df5ac19e449a872b9e9347f1db5a0394d2ec5caf2a9c143f86e232b0d9', 'eb0124240d225ed0ccfb2dfa9ad05d1e5e0c7941ee5c518b398145f202cb1d13');
// ECDSA private key (random number / secret exponent) = 7a26b3657dfa753a6a32962fde76e2d8202b3eaa1603270119ce4156472c4d20
// ECDSA public key (uncompressed) = 042ba95457d7274368a191d43cc379e357ba577d7a24262ae375cca78a2224f3f011a0fed69a15c28dea6f433255dc765403794c562a444015b996f7ac234141d8
// ECDSA public key (compressed) = 022ba95457d7274368a191d43cc379e357ba577d7a24262ae375cca78a2224f3f0
test_modsqrt('022ba95457d7274368a191d43cc379e357ba577d7a24262ae375cca78a2224f3f0', '11a0fed69a15c28dea6f433255dc765403794c562a444015b996f7ac234141d8');
});

1634
js/qrcode.js Normal file

File diff suppressed because it is too large Load Diff

348
js/rfc1751.js Normal file
View File

@@ -0,0 +1,348 @@
/*
rfc1751.js : Converts between 128-bit strings and a human-readable
sequence of words, as defined in RFC1751: "A Convention for
Human-Readable 128-bit Keys", by Daniel L. McDonald.
Ported from rfc1751.py / Python Cryptography Toolkit (public domain).
*/
var rfc1751_wordlist = [ "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD",
"AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN", "ANA",
"AND", "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK",
"ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", "AVE",
"AWE", "AWK", "AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM",
"BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN", "BET",
"BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB", "BOG", "BON", "BOO",
"BOP", "BOW", "BOY", "BUB", "BUD", "BUG", "BUM", "BUN", "BUS", "BUT",
"BUY", "BY", "BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT",
"CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW", "COY",
"CRY", "CUB", "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN",
"DAR", "DAY", "DEE", "DEL", "DEN", "DES", "DEW", "DID", "DIE", "DIG",
"DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB",
"DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG", "EGO",
"ELI", "ELK", "ELM", "ELY", "EM", "END", "EST", "ETC", "EVA", "EVE",
"EWE", "EYE", "FAD", "FAN", "FAR", "FAT", "FAY", "FED", "FEE", "FEW",
"FIB", "FIG", "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR",
"FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM", "GAP",
"GAS", "GAY", "GEE", "GEL", "GEM", "GET", "GIG", "GIL", "GIN", "GO",
"GOT", "GUM", "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", "HAD",
"HAL", "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM",
"HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS", "HIT",
"HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", "HOW", "HUB", "HUE",
"HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", "IF", "IKE", "ILL",
"INK", "INN", "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT",
"ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", "JAY", "JET",
"JIG", "JIM", "JO", "JOB", "JOE", "JOG", "JOT", "JOY", "JUG", "JUT",
"KAY", "KEG", "KEN", "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB",
"LAC", "LAD", "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE",
"LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP", "LIT",
"LO", "LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", "LUG",
"LYE", "MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", "MAT", "MAW",
"MAY", "ME", "MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT",
"MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD", "MUG",
"MUM", "MY", "NAB", "NAG", "NAN", "NAP", "NAT", "NAY", "NE", "NED",
"NEE", "NET", "NEW", "NIB", "NIL", "NIP", "NIT", "NO", "NOB", "NOD",
"NON", "NOR", "NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF",
"OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL",
"OK", "OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT",
"OUR", "OUT", "OVA", "OW", "OWE", "OWL", "OWN", "OX", "PA", "PAD",
"PAL", "PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG",
"PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN", "PIT",
"PLY", "PO", "POD", "POE", "POP", "POT", "POW", "PRO", "PRY", "PUB",
"PUG", "PUN", "PUP", "PUT", "QUO", "RAG", "RAM", "RAN", "RAP", "RAT",
"RAW", "RAY", "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM",
"RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB",
"RUE", "RUG", "RUM", "RUN", "RYE", "SAC", "SAD", "SAG", "SAL", "SAM",
"SAN", "SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", "SET",
"SEW", "SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY",
"SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", "SPA", "SPY",
"SUB", "SUD", "SUE", "SUM", "SUN", "SUP", "TAB", "TAD", "TAG", "TAN",
"TAP", "TAR", "TEA", "TED", "TEE", "TEN", "THE", "THY", "TIC", "TIE",
"TIM", "TIN", "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP",
"TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", "UN", "UP",
"US", "USE", "VAN", "VAT", "VET", "VIE", "WAD", "WAG", "WAR", "WAS",
"WAY", "WE", "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT",
"WOK", "WON", "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE",
"YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", "ABUT",
"ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS",
"ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA", "AIDE",
"AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", "ALIA",
"ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA", "AMEN",
"AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", "ANEW",
"ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", "AREA",
"ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS", "ATOM",
"AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", "AVOW",
"AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", "BAIL",
"BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM",
"BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE", "BARK",
"BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE", "BATH",
"BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", "BEAT",
"BEAU", "BECK", "BEEF", "BEEN", "BEER",
"BEET", "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN",
"BERT", "BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE",
"BIEN", "BILE", "BILK", "BILL", "BIND", "BING", "BIRD", "BITE",
"BITS", "BLAB", "BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT",
"BLOW", "BLUE", "BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK",
"BODE", "BODY", "BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT",
"BOMB", "BONA", "BOND", "BONE", "BONG", "BONN", "BONY", "BOOK",
"BOOM", "BOON", "BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS",
"BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN",
"BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD",
"BUFF", "BULB", "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG",
"BURL", "BURN", "BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST",
"BUSY", "BYTE", "CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF",
"CALL", "CALM", "CAME", "CANE", "CANT", "CARD", "CARE", "CARL",
"CARR", "CART", "CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL",
"CELL", "CENT", "CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF",
"CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG",
"CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY",
"CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA",
"COCK", "COCO", "CODA", "CODE", "CODY", "COED", "COIL", "COIN",
"COKE", "COLA", "COLD", "COLT", "COMA", "COMB", "COME", "COOK",
"COOL", "COON", "COOT", "CORD", "CORE", "CORK", "CORN", "COST",
"COVE", "COWL", "CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB",
"CROW", "CRUD", "CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY",
"CURB", "CURD", "CURE", "CURL", "CURT", "CUTS", "DADE", "DALE",
"DAME", "DANA", "DANE", "DANG", "DANK", "DARE", "DARK", "DARN",
"DART", "DASH", "DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS",
"DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED",
"DEEM", "DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK",
"DIAL", "DICE", "DIED", "DIET", "DIME", "DINE", "DING", "DINT",
"DIRE", "DIRT", "DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES",
"DOLE", "DOLL", "DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA",
"DOSE", "DOTE", "DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG",
"DRAM", "DRAW", "DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK",
"DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK",
"DUSK", "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST",
"EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT",
"EDNA", "EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT",
"EMMA", "ENDS", "ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED",
"FACE", "FACT", "FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL",
"FAME", "FANG", "FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT",
"FEED", "FEEL", "FEET", "FELL", "FELT", "FEND", "FERN", "FEST",
"FEUD", "FIEF", "FIGS", "FILE", "FILL", "FILM", "FIND", "FINE",
"FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE",
"FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW",
"FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM",
"FOGY", "FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL",
"FOOT", "FORD", "FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL",
"FOUR", "FOWL", "FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY",
"FROG", "FROM", "FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY",
"FUSE", "FUSS", "GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA",
"GALE", "GALL", "GALT", "GAME", "GANG", "GARB", "GARY", "GASH",
"GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE",
"GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT",
"GINA", "GIRD", "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN",
"GLIB", "GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD",
"GOAL", "GOAT", "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG",
"GOOD", "GOOF", "GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB",
"GRAD", "GRAY", "GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN",
"GRIT", "GROW", "GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH",
"GUST", "GWEN", "GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR",
"HALE", "HALF", "HALL", "HALO", "HALT", "HAND", "HANG", "HANK",
"HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", "HATE",
"HATH", "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR",
"HEAT", "HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL",
"HELM", "HERB", "HERD", "HERE", "HERO", "HERS", "HESS", "HEWN",
"HICK", "HIDE", "HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT",
"HIRE", "HISS", "HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE",
"HOLM", "HOLT", "HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK",
"HOOT", "HORN", "HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL",
"HOYT", "HUCK", "HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK",
"HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE",
"HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH",
"INTO", "IONS", "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE",
"ITCH", "ITEM", "IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE",
"JAVA", "JEAN", "JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL",
"JILT", "JIVE", "JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN",
"JOIN", "JOKE", "JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY",
"JUJU", "JUKE", "JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST",
"JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE", "KEEL",
"KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS", "KICK", "KILL",
"KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW",
"KNIT", "KNOB", "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD",
"KURT", "KYLE", "LACE", "LACK", "LACY", "LADY", "LAID", "LAIN",
"LAIR", "LAKE", "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD",
"LARK", "LASS", "LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS",
"LAYS", "LEAD", "LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER",
"LEFT", "LEND", "LENS", "LENT", "LEON", "LESK", "LESS", "LEST",
"LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU",
"LIFE", "LIFT", "LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB",
"LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST",
"LIVE", "LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE",
"LOIS", "LOLA", "LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD",
"LORE", "LOSE", "LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK",
"LUCY", "LUGE", "LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE",
"LURK", "LUSH", "LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE",
"MADE", "MAGI", "MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI",
"MALL", "MALT", "MANA", "MANN", "MANY", "MARC", "MARE", "MARK",
"MARS", "MART", "MARY", "MASH", "MASK", "MASS", "MAST", "MATE",
"MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK",
"MEET", "MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH",
"MESS", "MICE", "MIKE", "MILD", "MILE", "MILK", "MILL", "MILT",
"MIMI", "MIND", "MINE", "MINI", "MINK", "MINT", "MIRE", "MISS",
"MIST", "MITE", "MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD",
"MOLE", "MOLL", "MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON",
"MOOR", "MOOT", "MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH",
"MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK",
"MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL",
"NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR",
"NEAT", "NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS",
"NEST", "NEWS", "NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA",
"NINE", "NOAH", "NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON",
"NORM", "NOSE", "NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB",
"OATH", "OBEY", "OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY",
"OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE",
"ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS",
"OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY",
"OWNS", "QUAD", "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT",
"RAGE", "RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE",
"RASH", "RATE", "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR",
"RECK", "REED", "REEF", "REEK", "REEL", "REID", "REIN", "RENA",
"REND", "RENT", "REST", "RICE", "RICH", "RICK", "RIDE", "RIFT",
"RILL", "RIME", "RING", "RINK", "RISE", "RISK", "RITE", "ROAD",
"ROAM", "ROAR", "ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME",
"ROOD", "ROOF", "ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS",
"ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY",
"RUDE", "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE",
"RUSH", "RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE",
"SAID", "SAIL", "SALE", "SALK", "SALT", "SAME", "SAND", "SANE",
"SANG", "SANK", "SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR",
"SCAT", "SCOT", "SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK",
"SEEM", "SEEN", "SEES", "SELF", "SELL", "SEND", "SENT", "SETS",
"SEWN", "SHAG", "SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN",
"SHOD", "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE",
"SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE",
"SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW",
"SKID", "SKIM", "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY",
"SLED", "SLEW", "SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT",
"SLOW", "SLUG", "SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB",
"SNOW", "SNUB", "SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA",
"SOFT", "SOIL", "SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE",
"SORT", "SOUL", "SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR",
"STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN", "SUCH",
"SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF",
"SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM",
"TACK", "TACT", "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK",
"TASK", "TATE", "TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM",
"TEEN", "TEET", "TELL", "TEND", "TENT", "TERM", "TERN", "TESS",
"TEST", "THAN", "THAT", "THEE", "THEM", "THEN", "THEY", "THIN",
"THIS", "THUD", "THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER",
"TILE", "TILL", "TILT", "TIME", "TINA", "TINE", "TINT", "TINY",
"TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG",
"TONY", "TOOK", "TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR",
"TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG",
"TRIM", "TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE",
"TUCK", "TUFT", "TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK",
"TWIG", "TWIN", "TWIT", "ULAN", "UNIT", "URGE", "USED", "USER",
"USES", "UTAH", "VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST",
"VEAL", "VEDA", "VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY",
"VETO", "VICE", "VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE",
"WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK",
"WALL", "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", "WARM",
"WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY",
"WAYS", "WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR",
"WELD", "WELL", "WELT", "WENT", "WERE", "WERT", "WEST", "WHAM",
"WHAT", "WHEE", "WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE",
"WILD", "WILL", "WIND", "WINE", "WING", "WINK", "WINO", "WIRE",
"WISE", "WISH", "WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD",
"WORE", "WORK", "WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE",
"YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR",
"YELL", "YOGA", "YOKE" ];
var binary = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111',
'1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111'];
function _key2bin(key) {
res = ''
for (var i = 0; i < key.length; i++) {
res += binary[key[i] >> 4] + binary [key[i] & 0x0f];
}
return res;
}
function _extract(key, start, length) {
k = key.substring(start, start+length);
var acc = 0;
for (var i = 0; i < k.length; i++) {
acc = acc * 2 + k.charCodeAt(i) - 48;
}
return acc;
}
function key_to_english(key) {
//pad to 8 bytes
var padding = [];
for (var i = 0; i < (8 - (key.length % 8)) % 8; i++) {
padding.push(0);
}
key = padding.concat(key);
var english = [];
for (var index = 0; index < key.length; index += 8) {
var subkey = key.slice(index, index + 8);
//add parity
var skbin = _key2bin(subkey);
var p = 0;
for (var i = 0; i < 64; i += 2) {
p = p + _extract(skbin, i, 2);
}
subkey.push((p << 6) & 0xff);
skbin = _key2bin(subkey);
for (var i = 0; i < 64; i += 11) {
english.push(rfc1751_wordlist[_extract(skbin, i, 11)]);
}
}
return english.join(' ');
}
function english_to_key(str) {
var L = str.split(' ');
var key = [];
for (var index = 0; index < L.length; index += 6) {
var sublist = L.slice(index, index + 6);
var bits = 0;
var ch = [0,0,0,0,0,0,0,0,0];
for (var k = 0; k < sublist.length; k++) {
var word = sublist[k];
var idx = rfc1751_wordlist.indexOf(word);
var shift = (8 - (bits + 11) % 8) % 8;
var y = idx << shift;
var cl = y >> 16;
var cc = (y >> 8) & 0xff;
var cr = y & 0xff;
var t = Math.floor(bits / 8);
if (shift > 5) {
ch[t] = ch[t] | cl;
ch[t+1] = ch[t+1] | cc;
ch[t+2] = ch[t+2] | cr;
} else if (shift > -3) {
ch[t] = ch[t] | cc;
ch[t+1] = ch[t+1] | cr;
} else {
ch[t] = ch[t] | cr;
}
bits = bits + 11;
}
var subkey = ch.slice();
//check parity
var skbin = _key2bin(subkey);
var p = 0;
for (var i = 0; i < 64; i += 2) {
p = p + _extract(skbin, i, 2);
}
var cs0 = _extract(skbin, 64, 2);
var cs1 = p & 3;
if (cs0 != cs1) {
throw new Error("Parity error at " + word);
}
key = key.concat( subkey.slice(0,8) );
}
return key;
}

23
js/sha256.js Normal file
View File

@@ -0,0 +1,23 @@
/*
A JavaScript implementation of the SHA family of hashes, as
defined in FIPS PUB 180-2 as well as the corresponding HMAC implementation
as defined in FIPS PUB 198a
Copyright Brian Turek 2008-2013
Distributed under the BSD License
See http://caligatio.github.com/jsSHA/ for more information
Several functions taken from Paul Johnston
*/
(function(B){function r(a,c,b){var f=0,e=[0],g="",h=null,g=b||"UTF8";if("UTF8"!==g&&"UTF16"!==g)throw"encoding must be UTF8 or UTF16";if("HEX"===c){if(0!==a.length%2)throw"srcString of HEX type must be in byte increments";h=u(a);f=h.binLen;e=h.value}else if("ASCII"===c||"TEXT"===c)h=v(a,g),f=h.binLen,e=h.value;else if("B64"===c)h=w(a),f=h.binLen,e=h.value;else throw"inputFormat must be HEX, TEXT, ASCII, or B64";this.getHash=function(a,c,b,g){var h=null,d=e.slice(),l=f,m;3===arguments.length?"number"!==
typeof b&&(g=b,b=1):2===arguments.length&&(b=1);if(b!==parseInt(b,10)||1>b)throw"numRounds must a integer >= 1";switch(c){case "HEX":h=x;break;case "B64":h=y;break;default:throw"format must be HEX or B64";}if("SHA-224"===a)for(m=0;m<b;m++)d=q(d,l,a),l=224;else if("SHA-256"===a)for(m=0;m<b;m++)d=q(d,l,a),l=256;else throw"Chosen SHA variant is not supported";return h(d,z(g))};this.getHMAC=function(a,b,c,h,k){var d,l,m,n,A=[],s=[];d=null;switch(h){case "HEX":h=x;break;case "B64":h=y;break;default:throw"outputFormat must be HEX or B64";
}if("SHA-224"===c)l=64,n=224;else if("SHA-256"===c)l=64,n=256;else throw"Chosen SHA variant is not supported";if("HEX"===b)d=u(a),m=d.binLen,d=d.value;else if("ASCII"===b||"TEXT"===b)d=v(a,g),m=d.binLen,d=d.value;else if("B64"===b)d=w(a),m=d.binLen,d=d.value;else throw"inputFormat must be HEX, TEXT, ASCII, or B64";a=8*l;b=l/4-1;l<m/8?(d=q(d,m,c),d[b]&=4294967040):l>m/8&&(d[b]&=4294967040);for(l=0;l<=b;l+=1)A[l]=d[l]^909522486,s[l]=d[l]^1549556828;c=q(s.concat(q(A.concat(e),a+f,c)),a+n,c);return h(c,
z(k))}}function v(a,c){var b=[],f,e=[],g=0,h;if("UTF8"===c)for(h=0;h<a.length;h+=1)for(f=a.charCodeAt(h),e=[],2048<f?(e[0]=224|(f&61440)>>>12,e[1]=128|(f&4032)>>>6,e[2]=128|f&63):128<f?(e[0]=192|(f&1984)>>>6,e[1]=128|f&63):e[0]=f,f=0;f<e.length;f+=1)b[g>>>2]|=e[f]<<24-g%4*8,g+=1;else if("UTF16"===c)for(h=0;h<a.length;h+=1)b[g>>>2]|=a.charCodeAt(h)<<16-g%4*8,g+=2;return{value:b,binLen:8*g}}function u(a){var c=[],b=a.length,f,e;if(0!==b%2)throw"String of HEX type must be in byte increments";for(f=0;f<
b;f+=2){e=parseInt(a.substr(f,2),16);if(isNaN(e))throw"String of HEX type contains invalid characters";c[f>>>3]|=e<<24-f%8*4}return{value:c,binLen:4*b}}function w(a){var c=[],b=0,f,e,g,h,k;if(-1===a.search(/^[a-zA-Z0-9=+\/]+$/))throw"Invalid character in base-64 string";f=a.indexOf("=");a=a.replace(/\=/g,"");if(-1!==f&&f<a.length)throw"Invalid '=' found in base-64 string";for(e=0;e<a.length;e+=4){k=a.substr(e,4);for(g=h=0;g<k.length;g+=1)f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(k[g]),
h|=f<<18-6*g;for(g=0;g<k.length-1;g+=1)c[b>>2]|=(h>>>16-8*g&255)<<24-b%4*8,b+=1}return{value:c,binLen:8*b}}function x(a,c){var b="",f=4*a.length,e,g;for(e=0;e<f;e+=1)g=a[e>>>2]>>>8*(3-e%4),b+="0123456789abcdef".charAt(g>>>4&15)+"0123456789abcdef".charAt(g&15);return c.outputUpper?b.toUpperCase():b}function y(a,c){var b="",f=4*a.length,e,g,h;for(e=0;e<f;e+=3)for(h=(a[e>>>2]>>>8*(3-e%4)&255)<<16|(a[e+1>>>2]>>>8*(3-(e+1)%4)&255)<<8|a[e+2>>>2]>>>8*(3-(e+2)%4)&255,g=0;4>g;g+=1)b=8*e+6*g<=32*a.length?b+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(h>>>6*(3-g)&63):b+c.b64Pad;return b}function z(a){var c={outputUpper:!1,b64Pad:"="};try{a.hasOwnProperty("outputUpper")&&(c.outputUpper=a.outputUpper),a.hasOwnProperty("b64Pad")&&(c.b64Pad=a.b64Pad)}catch(b){}if("boolean"!==typeof c.outputUpper)throw"Invalid outputUpper formatting option";if("string"!==typeof c.b64Pad)throw"Invalid b64Pad formatting option";return c}function k(a,c){return a>>>c|a<<32-c}function I(a,c,b){return a&
c^~a&b}function J(a,c,b){return a&c^a&b^c&b}function K(a){return k(a,2)^k(a,13)^k(a,22)}function L(a){return k(a,6)^k(a,11)^k(a,25)}function M(a){return k(a,7)^k(a,18)^a>>>3}function N(a){return k(a,17)^k(a,19)^a>>>10}function O(a,c){var b=(a&65535)+(c&65535);return((a>>>16)+(c>>>16)+(b>>>16)&65535)<<16|b&65535}function P(a,c,b,f){var e=(a&65535)+(c&65535)+(b&65535)+(f&65535);return((a>>>16)+(c>>>16)+(b>>>16)+(f>>>16)+(e>>>16)&65535)<<16|e&65535}function Q(a,c,b,f,e){var g=(a&65535)+(c&65535)+(b&
65535)+(f&65535)+(e&65535);return((a>>>16)+(c>>>16)+(b>>>16)+(f>>>16)+(e>>>16)+(g>>>16)&65535)<<16|g&65535}function q(a,c,b){var f,e,g,h,k,q,r,C,u,d,l,m,n,A,s,p,v,w,x,y,z,D,E,F,G,t=[],H,B=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,
3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];d=[3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428];f=[1779033703,3144134277,1013904242,
2773480762,1359893119,2600822924,528734635,1541459225];if("SHA-224"===b||"SHA-256"===b)l=64,A=16,s=1,G=Number,p=O,v=P,w=Q,x=M,y=N,z=K,D=L,F=J,E=I,d="SHA-224"===b?d:f;else throw"Unexpected error in SHA-2 implementation";a[c>>>5]|=128<<24-c%32;a[(c+65>>>9<<4)+15]=c;H=a.length;for(m=0;m<H;m+=A){c=d[0];f=d[1];e=d[2];g=d[3];h=d[4];k=d[5];q=d[6];r=d[7];for(n=0;n<l;n+=1)t[n]=16>n?new G(a[n*s+m],a[n*s+m+1]):v(y(t[n-2]),t[n-7],x(t[n-15]),t[n-16]),C=w(r,D(h),E(h,k,q),B[n],t[n]),u=p(z(c),F(c,f,e)),r=q,q=k,k=
h,h=p(g,C),g=e,e=f,f=c,c=p(C,u);d[0]=p(c,d[0]);d[1]=p(f,d[1]);d[2]=p(e,d[2]);d[3]=p(g,d[3]);d[4]=p(h,d[4]);d[5]=p(k,d[5]);d[6]=p(q,d[6]);d[7]=p(r,d[7])}if("SHA-224"===b)a=[d[0],d[1],d[2],d[3],d[4],d[5],d[6]];else if("SHA-256"===b)a=d;else throw"Unexpected error in SHA-2 implementation";return a}"function"===typeof define&&typeof define.amd?define(function(){return r}):"undefined"!==typeof exports?"undefined"!==typeof module&&module.exports?module.exports=exports=r:exports=r:B.jsSHA=r})(this);

32
js/sha512.js Normal file
View File

@@ -0,0 +1,32 @@
(function() {/*
A JavaScript implementation of the SHA family of hashes, as defined in FIPS
PUB 180-2 as well as the corresponding HMAC implementation as defined in
FIPS PUB 198a
Copyright Brian Turek 2008-2012
Distributed under the BSD License
See http://caligatio.github.com/jsSHA/ for more information
Several functions taken from Paul Johnson
*/
function n(a){throw a;}var q=null;function s(a,b){this.a=a;this.b=b}function u(a,b){var d=[],h=(1<<b)-1,f=a.length*b,g;for(g=0;g<f;g+=b)d[g>>>5]|=(a.charCodeAt(g/b)&h)<<32-b-g%32;return{value:d,binLen:f}}function x(a){var b=[],d=a.length,h,f;0!==d%2&&n("String of HEX type must be in byte increments");for(h=0;h<d;h+=2)f=parseInt(a.substr(h,2),16),isNaN(f)&&n("String of HEX type contains invalid characters"),b[h>>>3]|=f<<24-4*(h%8);return{value:b,binLen:4*d}}
function B(a){var b=[],d=0,h,f,g,k,m;-1===a.search(/^[a-zA-Z0-9=+\/]+$/)&&n("Invalid character in base-64 string");h=a.indexOf("=");a=a.replace(/\=/g,"");-1!==h&&h<a.length&&n("Invalid '=' found in base-64 string");for(f=0;f<a.length;f+=4){m=a.substr(f,4);for(g=k=0;g<m.length;g+=1)h="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(m[g]),k|=h<<18-6*g;for(g=0;g<m.length-1;g+=1)b[d>>2]|=(k>>>16-8*g&255)<<24-8*(d%4),d+=1}return{value:b,binLen:8*d}}
function E(a,b){var d="",h=4*a.length,f,g;for(f=0;f<h;f+=1)g=a[f>>>2]>>>8*(3-f%4),d+="0123456789abcdef".charAt(g>>>4&15)+"0123456789abcdef".charAt(g&15);return b.outputUpper?d.toUpperCase():d}
function F(a,b){var d="",h=4*a.length,f,g,k;for(f=0;f<h;f+=3){k=(a[f>>>2]>>>8*(3-f%4)&255)<<16|(a[f+1>>>2]>>>8*(3-(f+1)%4)&255)<<8|a[f+2>>>2]>>>8*(3-(f+2)%4)&255;for(g=0;4>g;g+=1)d=8*f+6*g<=32*a.length?d+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(k>>>6*(3-g)&63):d+b.b64Pad}return d}
function G(a){var b={outputUpper:!1,b64Pad:"="};try{a.hasOwnProperty("outputUpper")&&(b.outputUpper=a.outputUpper),a.hasOwnProperty("b64Pad")&&(b.b64Pad=a.b64Pad)}catch(d){}"boolean"!==typeof b.outputUpper&&n("Invalid outputUpper formatting option");"string"!==typeof b.b64Pad&&n("Invalid b64Pad formatting option");return b}
function H(a,b){var d=q,d=new s(a.a,a.b);return d=32>=b?new s(d.a>>>b|d.b<<32-b&4294967295,d.b>>>b|d.a<<32-b&4294967295):new s(d.b>>>b-32|d.a<<64-b&4294967295,d.a>>>b-32|d.b<<64-b&4294967295)}function I(a,b){var d=q;return d=32>=b?new s(a.a>>>b,a.b>>>b|a.a<<32-b&4294967295):new s(0,a.a>>>b-32)}function J(a,b,d){return new s(a.a&b.a^~a.a&d.a,a.b&b.b^~a.b&d.b)}function U(a,b,d){return new s(a.a&b.a^a.a&d.a^b.a&d.a,a.b&b.b^a.b&d.b^b.b&d.b)}
function V(a){var b=H(a,28),d=H(a,34);a=H(a,39);return new s(b.a^d.a^a.a,b.b^d.b^a.b)}function W(a){var b=H(a,14),d=H(a,18);a=H(a,41);return new s(b.a^d.a^a.a,b.b^d.b^a.b)}function X(a){var b=H(a,1),d=H(a,8);a=I(a,7);return new s(b.a^d.a^a.a,b.b^d.b^a.b)}function Y(a){var b=H(a,19),d=H(a,61);a=I(a,6);return new s(b.a^d.a^a.a,b.b^d.b^a.b)}
function Z(a,b){var d,h,f;d=(a.b&65535)+(b.b&65535);h=(a.b>>>16)+(b.b>>>16)+(d>>>16);f=(h&65535)<<16|d&65535;d=(a.a&65535)+(b.a&65535)+(h>>>16);h=(a.a>>>16)+(b.a>>>16)+(d>>>16);return new s((h&65535)<<16|d&65535,f)}
function aa(a,b,d,h){var f,g,k;f=(a.b&65535)+(b.b&65535)+(d.b&65535)+(h.b&65535);g=(a.b>>>16)+(b.b>>>16)+(d.b>>>16)+(h.b>>>16)+(f>>>16);k=(g&65535)<<16|f&65535;f=(a.a&65535)+(b.a&65535)+(d.a&65535)+(h.a&65535)+(g>>>16);g=(a.a>>>16)+(b.a>>>16)+(d.a>>>16)+(h.a>>>16)+(f>>>16);return new s((g&65535)<<16|f&65535,k)}
function ba(a,b,d,h,f){var g,k,m;g=(a.b&65535)+(b.b&65535)+(d.b&65535)+(h.b&65535)+(f.b&65535);k=(a.b>>>16)+(b.b>>>16)+(d.b>>>16)+(h.b>>>16)+(f.b>>>16)+(g>>>16);m=(k&65535)<<16|g&65535;g=(a.a&65535)+(b.a&65535)+(d.a&65535)+(h.a&65535)+(f.a&65535)+(k>>>16);k=(a.a>>>16)+(b.a>>>16)+(d.a>>>16)+(h.a>>>16)+(f.a>>>16)+(g>>>16);return new s((k&65535)<<16|g&65535,m)}
function $(a,b,d){var h,f,g,k,m,j,A,C,K,e,L,v,l,M,t,p,y,z,r,N,O,P,Q,R,c,S,w=[],T,D;"SHA-384"===d||"SHA-512"===d?(L=80,h=(b+128>>>10<<5)+31,M=32,t=2,c=s,p=Z,y=aa,z=ba,r=X,N=Y,O=V,P=W,R=U,Q=J,S=[new c(1116352408,3609767458),new c(1899447441,602891725),new c(3049323471,3964484399),new c(3921009573,2173295548),new c(961987163,4081628472),new c(1508970993,3053834265),new c(2453635748,2937671579),new c(2870763221,3664609560),new c(3624381080,2734883394),new c(310598401,1164996542),new c(607225278,1323610764),
new c(1426881987,3590304994),new c(1925078388,4068182383),new c(2162078206,991336113),new c(2614888103,633803317),new c(3248222580,3479774868),new c(3835390401,2666613458),new c(4022224774,944711139),new c(264347078,2341262773),new c(604807628,2007800933),new c(770255983,1495990901),new c(1249150122,1856431235),new c(1555081692,3175218132),new c(1996064986,2198950837),new c(2554220882,3999719339),new c(2821834349,766784016),new c(2952996808,2566594879),new c(3210313671,3203337956),new c(3336571891,
1034457026),new c(3584528711,2466948901),new c(113926993,3758326383),new c(338241895,168717936),new c(666307205,1188179964),new c(773529912,1546045734),new c(1294757372,1522805485),new c(1396182291,2643833823),new c(1695183700,2343527390),new c(1986661051,1014477480),new c(2177026350,1206759142),new c(2456956037,344077627),new c(2730485921,1290863460),new c(2820302411,3158454273),new c(3259730800,3505952657),new c(3345764771,106217008),new c(3516065817,3606008344),new c(3600352804,1432725776),new c(4094571909,
1467031594),new c(275423344,851169720),new c(430227734,3100823752),new c(506948616,1363258195),new c(659060556,3750685593),new c(883997877,3785050280),new c(958139571,3318307427),new c(1322822218,3812723403),new c(1537002063,2003034995),new c(1747873779,3602036899),new c(1955562222,1575990012),new c(2024104815,1125592928),new c(2227730452,2716904306),new c(2361852424,442776044),new c(2428436474,593698344),new c(2756734187,3733110249),new c(3204031479,2999351573),new c(3329325298,3815920427),new c(3391569614,
3928383900),new c(3515267271,566280711),new c(3940187606,3454069534),new c(4118630271,4000239992),new c(116418474,1914138554),new c(174292421,2731055270),new c(289380356,3203993006),new c(460393269,320620315),new c(685471733,587496836),new c(852142971,1086792851),new c(1017036298,365543100),new c(1126000580,2618297676),new c(1288033470,3409855158),new c(1501505948,4234509866),new c(1607167915,987167468),new c(1816402316,1246189591)],e="SHA-384"===d?[new c(3418070365,3238371032),new c(1654270250,914150663),
new c(2438529370,812702999),new c(355462360,4144912697),new c(1731405415,4290775857),new c(41048885895,1750603025),new c(3675008525,1694076839),new c(1203062813,3204075428)]:[new c(1779033703,4089235720),new c(3144134277,2227873595),new c(1013904242,4271175723),new c(2773480762,1595750129),new c(1359893119,2917565137),new c(2600822924,725511199),new c(528734635,4215389547),new c(1541459225,327033209)]):n("Unexpected error in SHA-2 implementation");a[b>>>5]|=128<<24-b%32;a[h]=b;T=a.length;for(v=0;v<
T;v+=M){b=e[0];h=e[1];f=e[2];g=e[3];k=e[4];m=e[5];j=e[6];A=e[7];for(l=0;l<L;l+=1)w[l]=16>l?new c(a[l*t+v],a[l*t+v+1]):y(N(w[l-2]),w[l-7],r(w[l-15]),w[l-16]),C=z(A,P(k),Q(k,m,j),S[l],w[l]),K=p(O(b),R(b,h,f)),A=j,j=m,m=k,k=p(g,C),g=f,f=h,h=b,b=p(C,K);e[0]=p(b,e[0]);e[1]=p(h,e[1]);e[2]=p(f,e[2]);e[3]=p(g,e[3]);e[4]=p(k,e[4]);e[5]=p(m,e[5]);e[6]=p(j,e[6]);e[7]=p(A,e[7])}"SHA-384"===d?D=[e[0].a,e[0].b,e[1].a,e[1].b,e[2].a,e[2].b,e[3].a,e[3].b,e[4].a,e[4].b,e[5].a,e[5].b]:"SHA-512"===d?D=[e[0].a,e[0].b,
e[1].a,e[1].b,e[2].a,e[2].b,e[3].a,e[3].b,e[4].a,e[4].b,e[5].a,e[5].b,e[6].a,e[6].b,e[7].a,e[7].b]:n("Unexpected error in SHA-2 implementation");return D}
window.jsSHA=function(a,b,d){var h=q,f=q,g=0,k=[0],m=0,j=q,m="undefined"!==typeof d?d:8;8===m||16===m||n("charSize must be 8 or 16");"HEX"===b?(0!==a.length%2&&n("srcString of HEX type must be in byte increments"),j=x(a),g=j.binLen,k=j.value):"ASCII"===b||"TEXT"===b?(j=u(a,m),g=j.binLen,k=j.value):"B64"===b?(j=B(a),g=j.binLen,k=j.value):n("inputFormat must be HEX, TEXT, ASCII, or B64");this.getHash=function(a,b,d){var e=q,m=k.slice(),j="";switch(b){case "HEX":e=E;break;case "B64":e=F;break;default:n("format must be HEX or B64")}"SHA-384"===
a?(q===h&&(h=$(m,g,a)),j=e(h,G(d))):"SHA-512"===a?(q===f&&(f=$(m,g,a)),j=e(f,G(d))):n("Chosen SHA variant is not supported");return j};this.getHMAC=function(a,b,d,e,f){var h,l,j,t,p,y=[],z=[],r=q;switch(e){case "HEX":h=E;break;case "B64":h=F;break;default:n("outputFormat must be HEX or B64")}"SHA-384"===d?(j=128,p=384):"SHA-512"===d?(j=128,p=512):n("Chosen SHA variant is not supported");"HEX"===b?(r=x(a),t=r.binLen,l=r.value):"ASCII"===b||"TEXT"===b?(r=u(a,m),t=r.binLen,l=r.value):"B64"===b?(r=B(a),
t=r.binLen,l=r.value):n("inputFormat must be HEX, TEXT, ASCII, or B64");a=8*j;b=j/4-1;j<t/8?(l=$(l,t,d),l[b]&=4294967040):j>t/8&&(l[b]&=4294967040);for(j=0;j<=b;j+=1)y[j]=l[j]^909522486,z[j]=l[j]^1549556828;d=$(z.concat($(y.concat(k),a+g,d)),a+p,d);return h(d,G(f))}};})();

509
js/tx.js Normal file
View File

@@ -0,0 +1,509 @@
/*
tx.js - Bitcoin transactions for JavaScript (public domain)
Obtaining inputs:
1) http://blockchain.info/unspent?address=<address>
2) http://blockexplorer.com/q/mytransactions/<address>
Sending transactions:
1) http://bitsend.rowit.co.uk
2) http://www.blockchain.info/pushtx
*/
var TX = new function () {
var inputs = [];
var outputs = [];
var eckeys = null;
var balance = 0;
var redemption_script = null;
this.init = function(_eckeys, _redemption_script) {
outputs = [];
eckeys = _eckeys;
redemption_script = _redemption_script;
}
this.addOutput = function(addr, fval) {
outputs.push({address: addr, value: fval});
}
this.removeOutputs = function() {
outputs = [];
}
this.getBalance = function() {
return balance;
}
this.getFee = function(sendTx) {
var out = BigInteger.ZERO;
for (var i in outputs) {
var fval = outputs[i].value;
value = new BigInteger('' + Math.round(fval*1e8), 10);
out = out.add(value);
}
return balance.subtract(out);
}
this.parseInputs = function(text, address) {
try {
var res = tx_parseBCI(text, address);
} catch(err) {
var res = parseTxs(text, address);
}
balance = res.balance;
inputs = res.unspenttxs;
}
this.rebuild = function(sendTx, resign) {
if (!resign)
sendTx = new Bitcoin.Transaction();
var selectedOuts = [];
for (var hash in inputs) {
if (!inputs.hasOwnProperty(hash))
continue;
for (var index in inputs[hash]) {
if (!inputs[hash].hasOwnProperty(index))
continue;
var script = parseScript(inputs[hash][index].script);
var b64hash = Crypto.util.bytesToBase64(Crypto.util.hexToBytes(hash));
var txin = new Bitcoin.TransactionIn({outpoint: {hash: b64hash, index: index}, script: script, sequence: 4294967295});
selectedOuts.push(txin);
if (!resign)
sendTx.addInput(txin);
}
}
for (var i in outputs) {
var address = outputs[i].address;
var fval = outputs[i].value;
var value = new BigInteger('' + Math.round(fval * 1e8), 10);
if (!resign)
sendTx.addOutput(new Bitcoin.Address(address), value);
}
var hashType = 1; // SIGHASH_ALL
for (var i = 0; i < sendTx.ins.length; i++) {
var connectedScript = selectedOuts[i].script;
var hash = sendTx.hashTransactionForSignature(redemption_script, i, hashType);
var script = new Bitcoin.Script();
// No idea why this remains in Bitcoin code...
script.writeOp(0);
for (var j = 0; j < eckeys.length; j++ ) {
var signature = eckeys[j].sign(hash);
signature.push(parseInt(hashType, 10));
script.writeBytes(signature);
}
script.writeBytes(redemption_script.buffer);
sendTx.ins[i].script = script;
}
return sendTx;
};
this.construct = function() {
return this.rebuild(null, false);
}
this.resign = function(sendTx) {
return this.rebuild(sendTx, true);
}
function uint(f, size) {
if (f.length < size)
return 0;
var bytes = f.slice(0, size);
var pos = 1;
var n = 0;
for (var i = 0; i < size; i++) {
var b = f.shift();
n += b * pos;
pos *= 256;
}
return size <= 4 ? n : bytes;
}
function u8(f) { return uint(f,1); }
function u16(f) { return uint(f,2); }
function u32(f) { return uint(f,4); }
function u64(f) { return uint(f,8); }
function errv(val) {
return (val instanceof BigInteger || val > 0xffff);
}
function readBuffer(f, size) {
var res = f.slice(0, size);
for (var i = 0; i < size; i++) f.shift();
return res;
}
function readString(f) {
var len = readVarInt(f);
if (errv(len)) return [];
return readBuffer(f, len);
}
function readVarInt(f) {
var t = u8(f);
if (t == 0xfd) return u16(f); else
if (t == 0xfe) return u32(f); else
if (t == 0xff) return u64(f); else
return t;
}
this.deserialize = function(bytes) {
var sendTx = new Bitcoin.Transaction();
var f = bytes.slice(0);
var tx_ver = u32(f);
var vin_sz = readVarInt(f);
if (errv(vin_sz))
return null;
for (var i = 0; i < vin_sz; i++) {
var op = readBuffer(f, 32);
var n = u32(f);
var script = readString(f);
var seq = u32(f);
var txin = new Bitcoin.TransactionIn({
outpoint: {
hash: Crypto.util.bytesToBase64(op),
index: n
},
script: new Bitcoin.Script(script),
sequence: seq
});
sendTx.addInput(txin);
}
var vout_sz = readVarInt(f);
if (errv(vout_sz))
return null;
for (var i = 0; i < vout_sz; i++) {
var value = u64(f);
var script = readString(f);
var txout = new Bitcoin.TransactionOut({
value: value,
script: new Bitcoin.Script(script)
});
sendTx.addOutput(txout);
}
var lock_time = u32(f);
sendTx.lock_time = lock_time;
return sendTx;
};
this.toBBE = function(sendTx) {
//serialize to Bitcoin Block Explorer format
var buf = sendTx.serialize();
var hash = Crypto.SHA256(Crypto.SHA256(buf, {asBytes: true}), {asBytes: true});
var r = {};
r['hash'] = Crypto.util.bytesToHex(hash.reverse());
r['ver'] = sendTx.version;
r['vin_sz'] = sendTx.ins.length;
r['vout_sz'] = sendTx.outs.length;
r['lock_time'] = sendTx.lock_time;
r['size'] = buf.length;
r['in'] = []
r['out'] = []
for (var i = 0; i < sendTx.ins.length; i++) {
var txin = sendTx.ins[i];
var hash = Crypto.util.base64ToBytes(txin.outpoint.hash);
var n = txin.outpoint.index;
var prev_out = {'hash': Crypto.util.bytesToHex(hash.reverse()), 'n': n};
var seq = txin.sequence;
if (n == 4294967295) {
var cb = Crypto.util.bytesToHex(txin.script.buffer);
r['in'].push({'prev_out': prev_out, 'coinbase' : cb, 'sequence':seq});
} else {
var ss = dumpScript(txin.script);
r['in'].push({'prev_out': prev_out, 'scriptSig' : ss, 'sequence':seq});
}
}
for (var i = 0; i < sendTx.outs.length; i++) {
var txout = sendTx.outs[i];
var bytes = txout.value.slice(0);
var fval = parseFloat(Bitcoin.Util.formatValue(bytes.reverse()));
var value = fval.toFixed(8);
var spk = dumpScript(txout.script);
r['out'].push({'value' : value, 'scriptPubKey': spk});
}
return JSON.stringify(r, null, 4);
};
this.fromBBE = function(text) {
//deserialize from Bitcoin Block Explorer format
var sendTx = new Bitcoin.Transaction();
var r = JSON.parse(text);
if (!r)
return sendTx;
var tx_ver = r['ver'];
var vin_sz = r['vin_sz'];
for (var i = 0; i < vin_sz; i++) {
var txi = r['in'][i];
var hash = Crypto.util.hexToBytes(txi['prev_out']['hash']);
var n = txi['prev_out']['n'];
if (txi['coinbase'])
var script = Crypto.util.hexToBytes(txi['coinbase']);
else
var script = parseScript(txi['scriptSig']);
var seq = txi['sequence'] === undefined ? 4294967295 : txi['sequence'];
var txin = new Bitcoin.TransactionIn({
outpoint: {
hash: Crypto.util.bytesToBase64(hash.reverse()),
index: n
},
script: new Bitcoin.Script(script),
sequence: seq
});
sendTx.addInput(txin);
}
var vout_sz = r['vout_sz'];
TX.removeOutputs();
for (var i = 0; i < vout_sz; i++) {
var txo = r['out'][i];
var fval = parseFloat(txo['value']);
var value = new BigInteger('' + Math.round(fval * 1e8), 10);
var script = parseScript(txo['scriptPubKey']);
if (value instanceof BigInteger) {
value = value.toByteArrayUnsigned().reverse();
while (value.length < 8) value.push(0);
}
var txout = new Bitcoin.TransactionOut({
value: value,
script: new Bitcoin.Script(script)
});
sendTx.addOutput(txout);
TX.addOutput(txo,fval);
}
sendTx.lock_time = r['lock_time'];
return sendTx;
};
return this;
};
function dumpScript(script) {
var out = [];
for (var i = 0; i < script.chunks.length; i++) {
var chunk = script.chunks[i];
var op = new Bitcoin.Opcode(chunk);
typeof chunk == 'number' ? out.push(op.toString()) :
out.push(Crypto.util.bytesToHex(chunk));
}
return out.join(' ');
}
// blockchain.info parser (adapted)
// uses http://blockchain.info/unspent?address=<address>
function tx_parseBCI(data, address) {
var r = JSON.parse(data);
var txs = r.unspent_outputs;
if (!txs)
throw 'Not a BCI format';
delete unspenttxs;
var unspenttxs = {};
var balance = BigInteger.ZERO;
for (var i in txs) {
var o = txs[i];
var lilendHash = o.tx_hash;
//convert script back to BBE-compatible text
var script = dumpScript( new Bitcoin.Script(Crypto.util.hexToBytes(o.script)) );
var value = new BigInteger('' + o.value, 10);
if (!(lilendHash in unspenttxs))
unspenttxs[lilendHash] = {};
unspenttxs[lilendHash][o.tx_output_n] = {amount: value, script: script};
balance = balance.add(value);
}
return {balance:balance, unspenttxs:unspenttxs};
}
// blockexplorer parser (by BTCurious)
// uses http://blockexplorer.com/q/mytransactions/<address>
// --->8---
function parseTxs(data, address) {
var address = address.toString();
var tmp = JSON.parse(data);
var txs = [];
for (var a in tmp) {
if (!tmp.hasOwnProperty(a))
continue;
txs.push(tmp[a]);
}
// Sort chronologically
txs.sort(function(a,b) {
if (a.time > b.time) return 1;
else if (a.time < b.time) return -1;
return 0;
})
delete unspenttxs;
var unspenttxs = {}; // { "<hash>": { <output index>: { amount:<amount>, script:<script> }}}
var balance = BigInteger.ZERO;
// Enumerate the transactions
for (var a in txs) {
if (!txs.hasOwnProperty(a))
continue;
var tx = txs[a];
if (tx.ver != 1) throw "Unknown version found. Expected version 1, found version " + tx.ver;
// Enumerate inputs
for (var b in tx.in ) {
if (!tx.in.hasOwnProperty(b))
continue;
var input = tx.in[b];
var p = input.prev_out;
var lilendHash = endian(p.hash)
// if this came from a transaction to our address...
if (lilendHash in unspenttxs) {
unspenttx = unspenttxs[lilendHash];
// remove from unspent transactions, and deduce the amount from the balance
balance = balance.subtract(unspenttx[p.n].amount);
delete unspenttx[p.n]
if (isEmpty(unspenttx)) {
delete unspenttxs[lilendHash]
}
}
}
// Enumerate outputs
var i = 0;
for (var b in tx.out) {
if (!tx.out.hasOwnProperty(b))
continue;
var output = tx.out[b];
// if this was sent to our address...
if (output.address == address) {
// remember the transaction, index, amount, and script, and add the amount to the wallet balance
var value = btcstr2bignum(output.value);
var lilendHash = endian(tx.hash)
if (!(lilendHash in unspenttxs))
unspenttxs[lilendHash] = {};
unspenttxs[lilendHash][i] = {amount: value, script: output.scriptPubKey};
balance = balance.add(value);
}
i = i + 1;
}
}
return {balance:balance, unspenttxs:unspenttxs};
}
function isEmpty(ob) {
for(var i in ob){ if(ob.hasOwnProperty(i)){return false;}}
return true;
}
function endian(string) {
var out = []
for(var i = string.length; i > 0; i-=2) {
out.push(string.substring(i-2,i));
}
return out.join("");
}
function btcstr2bignum(btc) {
var i = btc.indexOf('.');
var value = new BigInteger(btc.replace(/\./,''));
var diff = 9 - (btc.length - i);
if (i == -1) {
var mul = "100000000";
} else if (diff < 0) {
return value.divide(new BigInteger(Math.pow(10,-1*diff).toString()));
} else {
var mul = Math.pow(10,diff).toString();
}
return value.multiply(new BigInteger(mul));
}
function parseScript(script) {
var newScript = new Bitcoin.Script();
var s = script.split(" ");
for (var i in s) {
if (Bitcoin.Opcode.map.hasOwnProperty(s[i])){
newScript.writeOp(Bitcoin.Opcode.map[s[i]]);
} else {
newScript.writeBytes(Crypto.util.hexToBytes(s[i]));
}
}
return newScript;
}
// --->8---
// Some cross-domain magic (to bypass Access-Control-Allow-Origin)
function tx_fetch(url, onSuccess, onError, postdata) {
var useYQL = true;
if (useYQL) {
var q = 'select * from html where url="'+url+'"';
if (postdata) {
q = 'use "http://brainwallet.github.com/js/htmlpost.xml" as htmlpost; ';
q += 'select * from htmlpost where url="' + url + '" ';
q += 'and postdata="' + postdata + '" and xpath="//p"';
}
url = 'https://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent(q);
}
$.ajax({
url: url,
success: function(res) {
onSuccess(useYQL ? $(res).find('results').text() : res.responseText);
},
error:function (xhr, opt, err) {
if (onError)
onError(err);
}
});
}
var tx_dest = '1Ce8WxgwjarzLtV6zkUGgdwmAe5yjHoPXX';
var tx_sec = '5KdttCmkLPPLN4oDet53FBdPxp4N1DWoGCiigd3ES9Wuknhm8uT';
var tx_addr = '32c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX';
var tx_unspent = '{"unspent_outputs":[{"tx_hash":"7a06ea98cd40ba2e3288262b28638cec5337c1456aaf5eedc8e9e5a20f062bdf","tx_index":5,"tx_output_n": 0,"script":"4104184f32b212815c6e522e66686324030ff7e5bf08efb21f8b00614fb7690e19131dd31304c54f37baa40db231c918106bb9fd43373e37ae31a0befc6ecaefb867ac","value": 5000000000,"value_hex": "012a05f200","confirmations":177254}]}';
function tx_test() {
//TODO
//var secret = Bitcoin.Base58.decode(tx_sec).slice(1, 33);
//var eckey = new Bitcoin.ECKey(secret);
//TX.init(eckey);
//TX.parseInputs(tx_unspent, tx_addr);
//TX.addOutput(tx_dest, 50.0);
//var sendTx = TX.construct();
//console.log(TX.toBBE(sendTx));
//console.log(Crypto.util.bytesToHex(sendTx.serialize()));
}