Initial from bip32.github.io
This commit is contained in:
9
README
Normal file
9
README
Normal 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
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
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
34
css/brainwallet.css
Normal 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
290
index.html
Normal 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"> </span> <span class="icon-bar"> </span> <span class="icon-bar"> </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> <b class="caret"> </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>
|
||||||
|
<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>
|
||||||
|
<a href="https://github.com/bip32/bip32.github.io">GitHub Repository</a>
|
||||||
|
<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
286
js/armory.js
Normal 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
386
js/bip32.js
Normal 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
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
121
js/bitcoinsig.js
Normal 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
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
645
js/brainwallet.js
Normal 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
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
7
js/crypto-min.js
vendored
Normal 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
129
js/electrum.js
Normal 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
66
js/hash_worker.js
Normal 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
33
js/htmlpost.xml
Normal 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
6
js/jquery.js
vendored
Normal file
File diff suppressed because one or more lines are too long
255
js/mnemonic.js
Normal file
255
js/mnemonic.js
Normal 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
139
js/modsqrt.js
Normal 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
1634
js/qrcode.js
Normal file
File diff suppressed because it is too large
Load Diff
348
js/rfc1751.js
Normal file
348
js/rfc1751.js
Normal 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
23
js/sha256.js
Normal 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
32
js/sha512.js
Normal 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
509
js/tx.js
Normal 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()));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user