mirror of
https://github.com/ok2/coinbin.git
synced 2026-05-09 18:15:23 +02:00
first commit
This commit is contained in:
Vendored
+2002
File diff suppressed because it is too large
Load Diff
Vendored
+9
File diff suppressed because one or more lines are too long
+909
@@ -0,0 +1,909 @@
|
||||
/*
|
||||
Coinjs 0.01 beta by OutCast3k{at}gmail.com
|
||||
A bitcoin framework loosely based on bitcoinjs.
|
||||
|
||||
http://github.com/OutCast3k/coinjs or http://coinb.in/coinjs
|
||||
*/
|
||||
|
||||
(function () {
|
||||
|
||||
var coinjs = window.coinjs = function () { };
|
||||
|
||||
/* public vars */
|
||||
coinjs.pub = 0x00;
|
||||
coinjs.priv = 0x80;
|
||||
coinjs.multisig = 0x05;
|
||||
coinjs.compressed = false;
|
||||
|
||||
/* other vars */
|
||||
coinjs.developer = '1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg';
|
||||
|
||||
/* bit(coinb.in) api vars */
|
||||
coinjs.host = 'http://coinb.in/api/';
|
||||
coinjs.uid = '1';
|
||||
coinjs.key = '12345678901234567890123456789012';
|
||||
|
||||
/* start of address functions */
|
||||
|
||||
/* generate a private and public keypair, with address and WIF address */
|
||||
coinjs.newKeys = function(string){
|
||||
var privkey = (string) ? Crypto.SHA256(string) : this.newPrivkey();
|
||||
var pubkey = this.newPubkey(privkey);
|
||||
return {
|
||||
'privkey': privkey,
|
||||
'pubkey': pubkey,
|
||||
'address': this.pubkey2address(pubkey),
|
||||
'wif': this.privkey2wif(privkey),
|
||||
'compressed': this.compressed
|
||||
};
|
||||
}
|
||||
|
||||
/* generate a new random private key */
|
||||
coinjs.newPrivkey = function(){
|
||||
var randArr = new Uint8Array(32);
|
||||
window.crypto.getRandomValues(randArr);
|
||||
|
||||
var privateKeyBytes = [];
|
||||
for (var i = 0; i < randArr.length; ++i){
|
||||
privateKeyBytes[i] = randArr[i];
|
||||
}
|
||||
|
||||
return Crypto.util.bytesToHex(privateKeyBytes);
|
||||
}
|
||||
|
||||
/* generate a public key from a private key */
|
||||
coinjs.newPubkey = function(hash){
|
||||
var privateKeyBigInt = BigInteger.fromByteArrayUnsigned(Crypto.util.hexToBytes(hash));
|
||||
var curve = EllipticCurve.getSECCurveByName("secp256k1");
|
||||
|
||||
var curvePt = curve.getG().multiply(privateKeyBigInt);
|
||||
var x = curvePt.getX().toBigInteger();
|
||||
var y = curvePt.getY().toBigInteger();
|
||||
|
||||
var publicKeyBytes = EllipticCurve.integerToBytes(x, 32);
|
||||
publicKeyBytes = publicKeyBytes.concat(EllipticCurve.integerToBytes(y,32));
|
||||
publicKeyBytes.unshift(0x04);
|
||||
|
||||
if(coinjs.compressed==true){
|
||||
var publicKeyBytesCompressed = EllipticCurve.integerToBytes(x,32)
|
||||
if (y.isEven()){
|
||||
publicKeyBytesCompressed.unshift(0x02)
|
||||
} else {
|
||||
publicKeyBytesCompressed.unshift(0x03)
|
||||
}
|
||||
return Crypto.util.bytesToHex(publicKeyBytesCompressed);
|
||||
} else {
|
||||
return Crypto.util.bytesToHex(publicKeyBytes);
|
||||
}
|
||||
}
|
||||
|
||||
/* provide a public key and return address */
|
||||
coinjs.pubkey2address = function(h){
|
||||
var r = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(h), {asBytes: true}));
|
||||
r.unshift(coinjs.pub);
|
||||
var hash = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
|
||||
var checksum = hash.slice(0, 4);
|
||||
return coinjs.base58encode(r.concat(checksum));
|
||||
}
|
||||
|
||||
/* provide a scripthash and return address */
|
||||
coinjs.scripthash2address = function(h){
|
||||
var x = Crypto.util.hexToBytes(h);
|
||||
x.unshift(coinjs.pub);
|
||||
var r = x;
|
||||
r = Crypto.SHA256(Crypto.SHA256(r,{asBytes: true}),{asBytes: true});
|
||||
var checksum = r.slice(0,4);
|
||||
return coinjs.base58encode(x.concat(checksum));
|
||||
}
|
||||
|
||||
/* new multisig address, provide the pubkeys AND required signatures to release the funds */
|
||||
coinjs.pubkeys2MultisigAddress = function(pubkeys, required) {
|
||||
var s = coinjs.script();
|
||||
s.writeOp(81 + (required*1) - 1); //OP_1
|
||||
for (var i = 0; i < pubkeys.length; ++i) {
|
||||
s.writeBytes(Crypto.util.hexToBytes(pubkeys[i]));
|
||||
}
|
||||
s.writeOp(81 + pubkeys.length - 1); //OP_1
|
||||
s.writeOp(174); //OP_CHECKMULTISIG
|
||||
var x = ripemd160(Crypto.SHA256(s.buffer, {asBytes: true}), {asBytes: true});
|
||||
x.unshift(coinjs.multisig);
|
||||
var r = x;
|
||||
r = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
|
||||
var checksum = r.slice(0,4);
|
||||
var redeemScript = Crypto.util.bytesToHex(s.buffer);
|
||||
var address = coinjs.base58encode(x.concat(checksum));
|
||||
return {'address':address, 'redeemScript':redeemScript};
|
||||
}
|
||||
|
||||
/* provide a privkey and return an WIF */
|
||||
coinjs.privkey2wif = function(h){
|
||||
var r = Crypto.util.hexToBytes(h);
|
||||
|
||||
if(coinjs.compressed==true){
|
||||
r.push(0x01);
|
||||
}
|
||||
|
||||
r.unshift(coinjs.priv);
|
||||
var hash = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
|
||||
var checksum = hash.slice(0, 4);
|
||||
|
||||
return coinjs.base58encode(r.concat(checksum));
|
||||
}
|
||||
|
||||
/* convert a wif key back to a private key */
|
||||
coinjs.wif2privkey = function(wif){
|
||||
var compressed = false;
|
||||
var decode = coinjs.base58decode(wif);
|
||||
var key = decode.slice(0, decode.length-4);
|
||||
key = key.slice(1, key.length);
|
||||
if(key.length>=33 && key[key.length-1]==0x01){
|
||||
key = key.slice(0, key.length-1);
|
||||
compressed = true;
|
||||
}
|
||||
return {'privkey': Crypto.util.bytesToHex(key), 'compressed':compressed};
|
||||
}
|
||||
|
||||
/* convert a wif to a pubkey */
|
||||
coinjs.wif2pubkey = function(wif){
|
||||
var compressed = coinjs.compressed;
|
||||
var r = coinjs.wif2privkey(wif);
|
||||
coinjs.compressed = r['compressed'];
|
||||
var pubkey = coinjs.newPubkey(r['privkey']);
|
||||
coinjs.compressed = compressed;
|
||||
return {'pubkey':pubkey,'compressed':r['compressed']};
|
||||
}
|
||||
|
||||
/* convert a wif to a address */
|
||||
coinjs.wif2address = function(wif){
|
||||
var r = coinjs.wif2pubkey(wif);
|
||||
return {'address':coinjs.pubkey2address(r['pubkey']), 'compressed':r['compressed']};
|
||||
}
|
||||
|
||||
/* decode or validate an address and return the hash */
|
||||
coinjs.addressDecode = function(addr){
|
||||
try {
|
||||
var bytes = coinjs.base58decode(addr);
|
||||
var front = bytes.slice(0, bytes.length-4);
|
||||
var back = bytes.slice(bytes.length-4);
|
||||
var checksum = Crypto.SHA256(Crypto.SHA256(front, {asBytes: true}), {asBytes: true}).slice(0, 4);
|
||||
if (checksum+"" == back+"") {
|
||||
var o = front.slice(1);
|
||||
o.version = front[0];
|
||||
return o;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* retreive the balance from a given address */
|
||||
coinjs.addressBalance = function(address, callback){
|
||||
coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=addresses&request=bal&address='+address, callback, "GET");
|
||||
}
|
||||
|
||||
/* decompress an compressed public key */
|
||||
coinjs.pubkeydecompress = function(pubkey) {
|
||||
var curve = EllipticCurve.getSECCurveByName("secp256k1");
|
||||
try {
|
||||
var pt = curve.curve.decodePointHex(pubkey);
|
||||
var x = pt.getX().toBigInteger();
|
||||
var y = pt.getY().toBigInteger();
|
||||
|
||||
var publicKeyBytes = EllipticCurve.integerToBytes(x, 32);
|
||||
publicKeyBytes = publicKeyBytes.concat(EllipticCurve.integerToBytes(y,32));
|
||||
publicKeyBytes.unshift(0x04);
|
||||
return Crypto.util.bytesToHex(publicKeyBytes);
|
||||
} catch (e) {
|
||||
// console.log(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* start of script functions */
|
||||
|
||||
coinjs.script = function(data) {
|
||||
var r = {};
|
||||
|
||||
if(!data){
|
||||
r.buffer = [];
|
||||
} else if ("string" == typeof data) {
|
||||
r.buffer = Crypto.util.hexToBytes(data);
|
||||
} else if (coinjs.isArray(data)) {
|
||||
r.buffer = data;
|
||||
} else if (data instanceof coinjs.script) {
|
||||
r.buffer = r.buffer;
|
||||
} else {
|
||||
r.buffer = data;
|
||||
}
|
||||
|
||||
/* parse buffer array */
|
||||
r.parse = function () {
|
||||
|
||||
var self = this;
|
||||
r.chunks = [];
|
||||
var i = 0;
|
||||
|
||||
function readChunk(n) {
|
||||
self.chunks.push(self.buffer.slice(i, i + n));
|
||||
i += n;
|
||||
};
|
||||
|
||||
while (i < this.buffer.length) {
|
||||
var opcode = this.buffer[i++];
|
||||
if (opcode >= 0xF0) {
|
||||
opcode = (opcode << 8) | this.buffer[i++];
|
||||
}
|
||||
|
||||
var len;
|
||||
if (opcode > 0 && opcode < 76) { //OP_PUSHDATA1
|
||||
readChunk(opcode);
|
||||
} else if (opcode == 76) { //OP_PUSHDATA1
|
||||
len = this.buffer[i++];
|
||||
readChunk(len);
|
||||
} else if (opcode == 77) { //OP_PUSHDATA2
|
||||
len = (this.buffer[i++] << 8) | this.buffer[i++];
|
||||
readChunk(len);
|
||||
} else if (opcode == 78) { //OP_PUSHDATA4
|
||||
len = (this.buffer[i++] << 24) | (this.buffer[i++] << 16) | (this.buffer[i++] << 8) | this.buffer[i++];
|
||||
readChunk(len);
|
||||
} else {
|
||||
this.chunks.push(opcode);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/* decode the redeemscript of a multisignature transaction */
|
||||
r.decodeRedeemScript = function(script){
|
||||
var r = false;
|
||||
try {
|
||||
var s = coinjs.script(Crypto.util.hexToBytes(script));
|
||||
if((s.chunks.length>=3) && s.chunks[s.chunks.length-1] == 174){//OP_CHECKMULTISIG
|
||||
r = {};
|
||||
r.signaturesRequired = s.chunks[0]-80;
|
||||
var pubkeys = [];
|
||||
for(var i=1;i<s.chunks.length-2;i++){
|
||||
pubkeys.push(Crypto.util.bytesToHex(s.chunks[i]));
|
||||
}
|
||||
r.pubkeys = pubkeys;
|
||||
var multi = coinjs.pubkeys2MultisigAddress(pubkeys, r.signaturesRequired);
|
||||
r.address = multi['address'];
|
||||
}
|
||||
} catch(e) {
|
||||
// console.log(e);
|
||||
r = false;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* create output script to spend */
|
||||
r.spendToScript = function(address){
|
||||
var addr = coinjs.addressDecode(address);
|
||||
var s = coinjs.script();
|
||||
if(addr.version==5){ // multisig address
|
||||
s.writeOp(169); //OP_HASH160
|
||||
s.writeBytes(addr);
|
||||
s.writeOp(135); //OP_EQUAL
|
||||
} else { // regular address
|
||||
s.writeOp(118); //OP_DUP
|
||||
s.writeOp(169); //OP_HASH160
|
||||
s.writeBytes(addr);
|
||||
s.writeOp(136); //OP_EQUALVERIFY
|
||||
s.writeOp(172); //OP_CHECKSIG
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* geneate a (script) pubkey hash of the address - used for when signing */
|
||||
r.pubkeyHash = function(address) {
|
||||
var addr = coinjs.addressDecode(address);
|
||||
var s = coinjs.script();
|
||||
s.writeOp(118);//OP_DUP
|
||||
s.writeOp(169);//OP_HASH160
|
||||
s.writeBytes(addr);
|
||||
s.writeOp(136);//OP_EQUALVERIFY
|
||||
s.writeOp(172);//OP_CHECKSIG
|
||||
return s;
|
||||
}
|
||||
|
||||
/* write to buffer */
|
||||
r.writeOp = function(op){
|
||||
this.buffer.push(op);
|
||||
this.chunks.push(op);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* write bytes to buffer */
|
||||
r.writeBytes = function(data){
|
||||
if (data.length < 76) { //OP_PUSHDATA1
|
||||
this.buffer.push(data.length);
|
||||
} else if (data.length <= 0xff) {
|
||||
this.buffer.push(76); //OP_PUSHDATA1
|
||||
this.buffer.push(data.length);
|
||||
} else if (data.length <= 0xffff) {
|
||||
this.buffer.push(77); //OP_PUSHDATA2
|
||||
this.buffer.push(data.length & 0xff);
|
||||
this.buffer.push((data.length >>> 8) & 0xff);
|
||||
} else {
|
||||
this.buffer.push(78); //OP_PUSHDATA4
|
||||
this.buffer.push(data.length & 0xff);
|
||||
this.buffer.push((data.length >>> 8) & 0xff);
|
||||
this.buffer.push((data.length >>> 16) & 0xff);
|
||||
this.buffer.push((data.length >>> 24) & 0xff);
|
||||
}
|
||||
this.buffer = this.buffer.concat(data);
|
||||
this.chunks.push(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
r.parse();
|
||||
return r;
|
||||
}
|
||||
|
||||
/* start of transaction functions */
|
||||
|
||||
/* create a new transaction object */
|
||||
coinjs.transaction = function() {
|
||||
|
||||
var r = {};
|
||||
r.version = 1;
|
||||
r.lock_time = 0;
|
||||
r.ins = [];
|
||||
r.outs = [];
|
||||
r.timestamp = null;
|
||||
r.block = null;
|
||||
|
||||
/* add an input to a transaction */
|
||||
r.addinput = function(txid, index, script){
|
||||
var o = {};
|
||||
o.outpoint = {'hash':txid, 'index':index};
|
||||
o.script = coinjs.script(script||[]);
|
||||
o.sequence = 4294967295;
|
||||
return this.ins.push(o);
|
||||
}
|
||||
|
||||
/* add an output to a transaction */
|
||||
r.addoutput = function(address, value){
|
||||
var o = {};
|
||||
o.value = new BigInteger('' + Math.round((value*1) * 1e8), 10);
|
||||
var s = coinjs.script();
|
||||
o.script = s.spendToScript(address);
|
||||
return this.outs.push(o);
|
||||
}
|
||||
|
||||
/* list unspent transactions */
|
||||
r.listUnspent = function(address, callback) {
|
||||
coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=addresses&request=unspent&address='+address, callback, "GET");
|
||||
}
|
||||
|
||||
/* add unspent to transaction */
|
||||
r.addUnspent = function(address, callback){
|
||||
var self = this;
|
||||
this.listUnspent(address, function(data){
|
||||
var s = coinjs.script();
|
||||
var pubkeyScript = s.pubkeyHash(address);
|
||||
var value = 0;
|
||||
var total = 0;
|
||||
var x = {};
|
||||
|
||||
var unspent = data.getElementsByTagName("unspent")[0];
|
||||
for(i=1;i<=unspent.childElementCount;i++){
|
||||
var u = data.getElementsByTagName("unspent_"+i)[0]
|
||||
var txhash = u.getElementsByTagName("tx_hash")[0].childNodes[0].nodeValue;
|
||||
var n = u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue;
|
||||
value += u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1;
|
||||
total++;
|
||||
}
|
||||
|
||||
x.unspent = $(data).find("unspent");
|
||||
x.value = value;
|
||||
x.total = total;
|
||||
return callback(x);
|
||||
});
|
||||
}
|
||||
|
||||
/* add unspent and sign */
|
||||
r.addUnspentAndSign = function(wif, callback){
|
||||
var self = this;
|
||||
var address = coinjs.wif2address(wif);
|
||||
self.addUnspent(address['address'], function(data){
|
||||
self.sign(wif);
|
||||
return callback(data);
|
||||
});
|
||||
}
|
||||
|
||||
/* broadcast a transaction */
|
||||
r.broadcast = function(callback, txhex){
|
||||
var tx = txhex || this.serialize()
|
||||
coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=bitcoin&request=sendrawtransaction&rawtx='+tx, callback, "GET");
|
||||
}
|
||||
|
||||
/* generate the transaction hash to sign from a transaction input */
|
||||
r.transactionHash = function(index) {
|
||||
var clone = coinjs.clone(this);
|
||||
if((clone.ins) && clone.ins[index]){
|
||||
for (var i = 0; i < clone.ins.length; i++) {
|
||||
if(index!=i){
|
||||
clone.ins[i].script = coinjs.script();
|
||||
}
|
||||
}
|
||||
|
||||
var extract = this.extractScriptKey(index);
|
||||
clone.ins[index].script = coinjs.script(extract['script']);
|
||||
|
||||
var buffer = Crypto.util.hexToBytes(clone.serialize());
|
||||
buffer = buffer.concat(coinjs.numToBytes(parseInt(1),4));
|
||||
var hash = Crypto.SHA256(buffer, {asBytes: true});
|
||||
var r = Crypto.util.bytesToHex(Crypto.SHA256(hash, {asBytes: true}));
|
||||
return r;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* extract the scriptSig, used in the transactionHash() function */
|
||||
r.extractScriptKey = function(index) {
|
||||
if(this.ins[index]){
|
||||
if((this.ins[index].script.chunks.length==5) && this.ins[index].script.chunks[4]==172 && coinjs.isArray(this.ins[index].script.chunks[2])){ //OP_CHECKSIG
|
||||
// regular scriptPubkey (not signed)
|
||||
return {'type':'scriptpubkey', 'signed':'false', 'signatures':0, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)};
|
||||
} else if((this.ins[index].script.chunks.length==2) && this.ins[index].script.chunks[0][0]==48){
|
||||
// regular scriptPubkey (probably signed)
|
||||
return {'type':'scriptpubkey', 'signed':'true', 'signatures':1, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)};
|
||||
} else if (this.ins[index].script.chunks[0]==0 && this.ins[index].script.chunks[this.ins[index].script.chunks.length-1][this.ins[index].script.chunks[this.ins[index].script.chunks.length-1].length-1]==174) { // OP_CHECKMULTISIG
|
||||
// multisig script, with signature(s) included
|
||||
return {'type':'multisig', 'signed':'true', 'signatures':this.ins[index].script.chunks.length-2, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[this.ins[index].script.chunks.length-1])};
|
||||
} else if (this.ins[index].script.chunks[0]>=80 && this.ins[index].script.chunks[this.ins[index].script.chunks.length-1]==174) { // OP_CHECKMULTISIG
|
||||
// multisig script, without signature!
|
||||
return {'type':'multisig', 'signed':'false', 'signatures':0, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)};
|
||||
} else if (this.ins[index].script.chunks.length==0) {
|
||||
// empty
|
||||
return {'type':'empty', 'signed':'false', 'signatures':0, 'script': ''};
|
||||
} else {
|
||||
// something else
|
||||
return {'type':'unknown', 'signed':'false', 'signatures':0, 'script':Crypto.util.bytesToHex(this.ins[index].script.buffer)};
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a signature from a transaction hash */
|
||||
r.transactionSig = function(index, wif){
|
||||
|
||||
function serializeSig(r, s) {
|
||||
var rBa = r.toByteArraySigned();
|
||||
var sBa = s.toByteArraySigned();
|
||||
|
||||
var sequence = [];
|
||||
sequence.push(0x02); // INTEGER
|
||||
sequence.push(rBa.length);
|
||||
sequence = sequence.concat(rBa);
|
||||
|
||||
sequence.push(0x02); // INTEGER
|
||||
sequence.push(sBa.length);
|
||||
sequence = sequence.concat(sBa);
|
||||
|
||||
sequence.unshift(sequence.length);
|
||||
sequence.unshift(0x30); // SEQUENCE
|
||||
|
||||
return sequence;
|
||||
}
|
||||
|
||||
var hash = Crypto.util.hexToBytes(this.transactionHash(index));
|
||||
|
||||
if(hash){
|
||||
var rng = new SecureRandom();
|
||||
var curve = EllipticCurve.getSECCurveByName("secp256k1");
|
||||
var key = coinjs.wif2privkey(wif);
|
||||
var priv = BigInteger.fromByteArrayUnsigned(Crypto.util.hexToBytes(key['privkey']));
|
||||
var n = curve.getN();
|
||||
var e = BigInteger.fromByteArrayUnsigned(hash);
|
||||
do {
|
||||
var k = new BigInteger(n.bitLength(), rng).mod(n.subtract(BigInteger.ONE)).add(BigInteger.ONE);
|
||||
var G = curve.getG();
|
||||
var Q = G.multiply(k);
|
||||
var r = Q.getX().toBigInteger().mod(n);
|
||||
} while (r.compareTo(BigInteger.ZERO) <= 0);
|
||||
|
||||
var s = k.modInverse(n).multiply(e.add(priv.multiply(r))).mod(n);
|
||||
|
||||
var sig = serializeSig(r, s);
|
||||
sig.push(parseInt(1, 10));
|
||||
|
||||
return Crypto.util.bytesToHex(sig);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* sign a "standard" input */
|
||||
r.signinput = function(index, wif){
|
||||
var key = coinjs.wif2pubkey(wif);
|
||||
var signature = this.transactionSig(index, wif);
|
||||
var s = coinjs.script();
|
||||
s.writeBytes(Crypto.util.hexToBytes(signature));
|
||||
s.writeBytes(Crypto.util.hexToBytes(key['pubkey']));
|
||||
this.ins[index].script = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* sign a multisig input */
|
||||
r.signmultisig = function(index, wif){
|
||||
|
||||
function scriptListPubkey(redeemScript){
|
||||
var r = {};
|
||||
for(var i=1;i<redeemScript.chunks.length-2;i++){
|
||||
r[i] = Crypto.util.hexToBytes(coinjs.pubkeydecompress(Crypto.util.bytesToHex(redeemScript.chunks[i])));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
function scriptListSigs(scriptSig){
|
||||
var r = {};
|
||||
if (scriptSig.chunks[0]==0 && scriptSig.chunks[scriptSig.chunks.length-1][scriptSig.chunks[scriptSig.chunks.length-1].length-1]==174){
|
||||
for(var i=1;i<scriptSig.chunks.length-1;i++){
|
||||
r[i] = scriptSig.chunks[i];
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
var redeemScript = (this.ins[index].script.chunks[this.ins[index].script.chunks.length-1]==174) ? this.ins[index].script.buffer : this.ins[index].script.chunks[this.ins[index].script.chunks.length-1];
|
||||
var sighash = Crypto.util.hexToBytes(this.transactionHash(index));
|
||||
var signature = Crypto.util.hexToBytes(this.transactionSig(index, wif));
|
||||
var s = coinjs.script();
|
||||
|
||||
s.writeOp(0);
|
||||
|
||||
if(this.ins[index].script.chunks[this.ins[index].script.chunks.length-1]==174){
|
||||
s.writeBytes(signature);
|
||||
|
||||
} else if (this.ins[index].script.chunks[0]==0 && this.ins[index].script.chunks[this.ins[index].script.chunks.length-1][this.ins[index].script.chunks[this.ins[index].script.chunks.length-1].length-1]==174){
|
||||
var pubkeyList = scriptListPubkey(coinjs.script(redeemScript));
|
||||
var sigsList = scriptListSigs(this.ins[index].script);
|
||||
sigsList[coinjs.countObject(sigsList)+1] = signature;
|
||||
|
||||
for(x in pubkeyList){
|
||||
for(y in sigsList){
|
||||
if(coinjs.verifySignature(sighash, sigsList[y], pubkeyList[x])){
|
||||
s.writeBytes(sigsList[y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
s.writeBytes(redeemScript);
|
||||
this.ins[index].script = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* sign inputs */
|
||||
r.sign = function(wif){
|
||||
for (var i = 0; i < this.ins.length; i++) {
|
||||
var d = this.extractScriptKey(i);
|
||||
|
||||
var w2a = coinjs.wif2address(wif);
|
||||
var script = coinjs.script();
|
||||
var pubkeyHash = script.pubkeyHash(w2a['address']);
|
||||
|
||||
if(((d['type'] == 'scriptpubkey' && d['script']==Crypto.util.bytesToHex(pubkeyHash.buffer)) || d['type'] == 'empty') && d['signed'] == "false"){
|
||||
this.signinput(i, wif);
|
||||
} else if (d['type'] == 'multisig') {
|
||||
this.signmultisig(i, wif);
|
||||
} else {
|
||||
// could not sign
|
||||
}
|
||||
}
|
||||
return this.serialize();
|
||||
}
|
||||
|
||||
/* serialize a transaction */
|
||||
r.serialize = function(){
|
||||
var buffer = [];
|
||||
buffer = buffer.concat(coinjs.numToBytes(parseInt(this.version),4));
|
||||
buffer = buffer.concat(coinjs.numToVarInt(this.ins.length));
|
||||
|
||||
for (var i = 0; i < this.ins.length; i++) {
|
||||
var txin = this.ins[i];
|
||||
buffer = buffer.concat(Crypto.util.hexToBytes(txin.outpoint.hash).reverse());
|
||||
buffer = buffer.concat(coinjs.numToBytes(parseInt(txin.outpoint.index),4));
|
||||
var scriptBytes = txin.script.buffer;
|
||||
buffer = buffer.concat(coinjs.numToVarInt(scriptBytes.length));
|
||||
buffer = buffer.concat(scriptBytes);
|
||||
buffer = buffer.concat(coinjs.numToBytes(parseInt(txin.sequence),4));
|
||||
}
|
||||
buffer = buffer.concat(coinjs.numToVarInt(this.outs.length));
|
||||
|
||||
for (var i = 0; i < this.outs.length; i++) {
|
||||
var txout = this.outs[i];
|
||||
buffer = buffer.concat(coinjs.numToBytes(txout.value,8));
|
||||
var scriptBytes = txout.script.buffer;
|
||||
buffer = buffer.concat(coinjs.numToVarInt(scriptBytes.length));
|
||||
buffer = buffer.concat(scriptBytes);
|
||||
}
|
||||
|
||||
buffer = buffer.concat(coinjs.numToBytes(parseInt(this.lock_time),4));
|
||||
return Crypto.util.bytesToHex(buffer);
|
||||
}
|
||||
|
||||
/* deserialize a transaction */
|
||||
r.deserialize = function(buffer){
|
||||
if (typeof buffer == "string") {
|
||||
buffer = Crypto.util.hexToBytes(buffer)
|
||||
}
|
||||
|
||||
var pos = 0;
|
||||
var readAsInt = function(bytes) {
|
||||
if (bytes == 0) return 0;
|
||||
pos++;
|
||||
return buffer[pos-1] + readAsInt(bytes-1) * 256;
|
||||
}
|
||||
|
||||
var readVarInt = function() {
|
||||
pos++;
|
||||
if (buffer[pos-1] < 253) {
|
||||
return buffer[pos-1];
|
||||
}
|
||||
return readAsInt(buffer[pos-1] - 251);
|
||||
}
|
||||
|
||||
var readBytes = function(bytes) {
|
||||
pos += bytes;
|
||||
return buffer.slice(pos - bytes, pos);
|
||||
}
|
||||
|
||||
var readVarString = function() {
|
||||
var size = readVarInt();
|
||||
return readBytes(size);
|
||||
}
|
||||
|
||||
var obj = new coinjs.transaction();
|
||||
|
||||
obj.version = readAsInt(4);
|
||||
var ins = readVarInt();
|
||||
for (var i = 0; i < ins; i++) {
|
||||
obj.ins.push({
|
||||
outpoint: {
|
||||
hash: Crypto.util.bytesToHex(readBytes(32).reverse()),
|
||||
index: readAsInt(4)
|
||||
},
|
||||
script: coinjs.script(readVarString()),
|
||||
sequence: readAsInt(4)
|
||||
});
|
||||
}
|
||||
|
||||
var outs = readVarInt();
|
||||
for (var i = 0; i < outs; i++) {
|
||||
obj.outs.push({
|
||||
value: coinjs.bytesToNum(readBytes(8)),
|
||||
script: coinjs.script(readVarString())
|
||||
});
|
||||
}
|
||||
|
||||
obj.locktime = readAsInt(4);
|
||||
return obj;
|
||||
}
|
||||
|
||||
r.size = function(){
|
||||
return ((this.serialize()).length/2).toFixed(0);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* start of signature vertification functions */
|
||||
|
||||
coinjs.verifySignature = function (hash, sig, pubkey) {
|
||||
|
||||
function parseSig (sig) {
|
||||
var cursor;
|
||||
if (sig[0] != 0x30)
|
||||
throw new Error("Signature not a valid DERSequence");
|
||||
|
||||
cursor = 2;
|
||||
if (sig[cursor] != 0x02)
|
||||
throw new Error("First element in signature must be a DERInteger"); ;
|
||||
|
||||
var rBa = sig.slice(cursor + 2, cursor + 2 + sig[cursor + 1]);
|
||||
|
||||
cursor += 2 + sig[cursor + 1];
|
||||
if (sig[cursor] != 0x02)
|
||||
throw new Error("Second element in signature must be a DERInteger");
|
||||
|
||||
var sBa = sig.slice(cursor + 2, cursor + 2 + sig[cursor + 1]);
|
||||
|
||||
cursor += 2 + sig[cursor + 1];
|
||||
|
||||
var r = BigInteger.fromByteArrayUnsigned(rBa);
|
||||
var s = BigInteger.fromByteArrayUnsigned(sBa);
|
||||
|
||||
return { r: r, s: s };
|
||||
}
|
||||
|
||||
var r, s;
|
||||
|
||||
if (coinjs.isArray(sig)) {
|
||||
var obj = parseSig(sig);
|
||||
r = obj.r;
|
||||
s = obj.s;
|
||||
} else if ("object" === typeof sig && sig.r && sig.s) {
|
||||
r = sig.r;
|
||||
s = sig.s;
|
||||
} else {
|
||||
throw "Invalid value for signature";
|
||||
}
|
||||
|
||||
var Q;
|
||||
if (coinjs.isArray(pubkey)) {
|
||||
var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
||||
Q = EllipticCurve.PointFp.decodeFrom(ecparams.getCurve(), pubkey);
|
||||
} else {
|
||||
throw "Invalid format for pubkey value, must be byte array";
|
||||
}
|
||||
var e = BigInteger.fromByteArrayUnsigned(hash);
|
||||
|
||||
return coinjs.verifySignatureRaw(e, r, s, Q);
|
||||
}
|
||||
|
||||
coinjs.verifySignatureRaw = function (e, r, s, Q) {
|
||||
var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
||||
var n = ecparams.getN();
|
||||
var G = ecparams.getG();
|
||||
|
||||
if (r.compareTo(BigInteger.ONE) < 0 || r.compareTo(n) >= 0)
|
||||
return false;
|
||||
|
||||
if (s.compareTo(BigInteger.ONE) < 0 || s.compareTo(n) >= 0)
|
||||
return false;
|
||||
|
||||
var c = s.modInverse(n);
|
||||
|
||||
var u1 = e.multiply(c).mod(n);
|
||||
var u2 = r.multiply(c).mod(n);
|
||||
|
||||
var point = G.multiply(u1).add(Q.multiply(u2));
|
||||
|
||||
var v = point.getX().toBigInteger().mod(n);
|
||||
|
||||
return v.equals(r);
|
||||
}
|
||||
|
||||
/* start of privates functions */
|
||||
|
||||
/* base58 encode function */
|
||||
coinjs.base58encode = function(buffer) {
|
||||
var alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
var base = BigInteger.valueOf(58);
|
||||
|
||||
var bi = BigInteger.fromByteArrayUnsigned(buffer);
|
||||
var chars = [];
|
||||
|
||||
while (bi.compareTo(base) >= 0) {
|
||||
var mod = bi.mod(base);
|
||||
chars.unshift(alphabet[mod.intValue()]);
|
||||
bi = bi.subtract(mod).divide(base);
|
||||
}
|
||||
|
||||
chars.unshift(alphabet[bi.intValue()]);
|
||||
for (var i = 0; i < buffer.length; i++) {
|
||||
if (buffer[i] == 0x00) {
|
||||
chars.unshift(alphabet[0]);
|
||||
} else break;
|
||||
}
|
||||
return chars.join('');
|
||||
}
|
||||
|
||||
/* base58 decode function */
|
||||
coinjs.base58decode = function(buffer){
|
||||
var alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
var base = BigInteger.valueOf(58);
|
||||
var validRegex = /^[1-9A-HJ-NP-Za-km-z]+$/;
|
||||
|
||||
var bi = BigInteger.valueOf(0);
|
||||
var leadingZerosNum = 0;
|
||||
for (var i = buffer.length - 1; i >= 0; i--) {
|
||||
var alphaIndex = alphabet.indexOf(buffer[i]);
|
||||
if (alphaIndex < 0) {
|
||||
throw "Invalid character";
|
||||
}
|
||||
bi = bi.add(BigInteger.valueOf(alphaIndex).multiply(base.pow(buffer.length - 1 - i)));
|
||||
|
||||
if (buffer[i] == "1") leadingZerosNum++;
|
||||
else leadingZerosNum = 0;
|
||||
}
|
||||
|
||||
var bytes = bi.toByteArrayUnsigned();
|
||||
while (leadingZerosNum-- > 0) bytes.unshift(0);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* raw ajax function to avoid needing bigger frame works like jquery, mootools etc */
|
||||
coinjs.ajax = function(u, f, m, a){
|
||||
var x = false;
|
||||
try{
|
||||
x = new ActiveXObject('Msxml2.XMLHTTP')
|
||||
} catch(e) {
|
||||
try {
|
||||
x = new ActiveXObject('Microsoft.XMLHTTP')
|
||||
} catch(e) {
|
||||
x = new XMLHttpRequest()
|
||||
}
|
||||
}
|
||||
|
||||
if(x==false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
x.open(m, u, true);
|
||||
x.onreadystatechange=function(){
|
||||
if((x.readyState==4) && f)
|
||||
f(x.responseText);
|
||||
};
|
||||
|
||||
if(m == 'POST'){
|
||||
x.setRequestHeader('Content-type','application/x-www-form-urlencoded');
|
||||
}
|
||||
|
||||
x.send(a);
|
||||
}
|
||||
|
||||
/* clone an object */
|
||||
coinjs.clone = function(obj) {
|
||||
if(obj == null || typeof(obj) != 'object') return obj;
|
||||
var temp = obj.constructor();
|
||||
|
||||
for(var key in obj) {
|
||||
if(obj.hasOwnProperty(key)) {
|
||||
temp[key] = coinjs.clone(obj[key]);
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
coinjs.numToBytes = function(num,bytes) {
|
||||
if (bytes === undefined) bytes = 8;
|
||||
if (bytes == 0) {
|
||||
return [];
|
||||
} else {
|
||||
return [num % 256].concat(coinjs.numToBytes(Math.floor(num / 256),bytes-1));
|
||||
}
|
||||
}
|
||||
|
||||
coinjs.numToVarInt = function(num) {
|
||||
if (num < 253) {
|
||||
return [num];
|
||||
} else if (num < 65536) {
|
||||
return [253].concat(coinjs.numToBytes(num,2));
|
||||
} else if (num < 4294967296) {
|
||||
return [254].concat(coinjs.numToBytes(num,4));
|
||||
} else {
|
||||
return [253].concat(coinjs.numToBytes(num,8));
|
||||
}
|
||||
}
|
||||
|
||||
coinjs.bytesToNum = function(bytes) {
|
||||
if (bytes.length == 0) return 0;
|
||||
else return bytes[0] + 256 * coinjs.bytesToNum(bytes.slice(1));
|
||||
}
|
||||
|
||||
coinjs.isArray = function(o){
|
||||
return Object.prototype.toString.call(o) === '[object Array]';
|
||||
}
|
||||
|
||||
coinjs.countObject = function(obj){
|
||||
var count = 0;
|
||||
var i;
|
||||
for (i in obj) {
|
||||
if (obj.hasOwnProperty(i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
})();
|
||||
+712
@@ -0,0 +1,712 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
/* open wallet code */
|
||||
|
||||
$("#openBtn").click(function(){
|
||||
var email = $("#openEmail").val().toLowerCase();
|
||||
if(email.match(/[\s\w\d]+@[\s\w\d]+/g)){
|
||||
if($("#openPass").val().length>=10){
|
||||
if($("#openPass").val()==$("#openPassConfirm").val()){
|
||||
|
||||
var email = $("#openEmail").val().toLowerCase();
|
||||
var pass = $("#openPass").val();
|
||||
var s = email;
|
||||
s += '|'+pass+'|';
|
||||
s += s.length+'|!@'+((pass.length*7)+email.length)*7;
|
||||
var regchars = (pass.match(/[a-z]+/g)) ? pass.match(/[a-z]+/g).length : 1;
|
||||
var regupchars = (pass.match(/[A-Z]+/g)) ? pass.match(/[A-Z]+/g).length : 1;
|
||||
var regnums = (pass.match(/[0-9]+/g)) ? pass.match(/[0-9]+/g).length : 1;
|
||||
s += ((regnums+regchars)+regupchars)*pass.length+'3571';
|
||||
s += (s+s);
|
||||
|
||||
for(i=0;i<=50;i++){
|
||||
s = Crypto.SHA256(s);
|
||||
}
|
||||
|
||||
coinjs.compressed = true;
|
||||
var keys = coinjs.newKeys(s);
|
||||
|
||||
$("#walletAddress").html(keys.address);
|
||||
$("#walletHistory").attr('href','http://www.blockchain.info/address/'+keys.address);
|
||||
$("#walletQrCode").html('<img src="https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=bitcoin:'+keys.address+'">');
|
||||
$("#walletKeys .privkey").val(keys.wif);
|
||||
$("#walletKeys .pubkey").val(keys.pubkey);
|
||||
|
||||
$("#openLogin").hide();
|
||||
$("#openWallet").removeClass("hidden").show();
|
||||
|
||||
walletBalance();
|
||||
checkBalanceLoop();
|
||||
} else {
|
||||
$("#openLoginStatus").html("Your passwords do not match!").removeClass("hidden").fadeOut().fadeIn();
|
||||
}
|
||||
} else {
|
||||
$("#openLoginStatus").html("Your password must be at least 10 chars long").removeClass("hidden").fadeOut().fadeIn();
|
||||
}
|
||||
} else {
|
||||
$("#openLoginStatus").html("Your email address doesn't appear to be valid").removeClass("hidden").fadeOut().fadeIn();
|
||||
}
|
||||
|
||||
$("#openLoginStatus").prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ');
|
||||
});
|
||||
|
||||
$("#walletLogout").click(function(){
|
||||
$("#openEmail").val("");
|
||||
$("#openPass").val("");
|
||||
$("#openPassConfirm").val("");
|
||||
|
||||
$("#openLogin").show();
|
||||
$("#openWallet").addClass("hidden").show();
|
||||
|
||||
$("#walletAddress").html("");
|
||||
$("#walletHistory").attr('href','http://www.blockchain.info/address/');
|
||||
$("#walletQrCode").html('<img src="https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=bitcoin:">');
|
||||
$("#walletKeys .privkey").val("");
|
||||
$("#walletKeys .pubkey").val("");
|
||||
|
||||
});
|
||||
|
||||
$("#walletShowKeys").click(function(){
|
||||
$("#walletKeys").removeClass("hidden");
|
||||
$("#walletSpend").removeClass("hidden").addClass("hidden");
|
||||
});
|
||||
|
||||
$("#walletBalance").click(function(){
|
||||
walletBalance();
|
||||
});
|
||||
|
||||
$("#walletConfirmSend").click(function(){
|
||||
var thisbtn = $(this);
|
||||
var tx = coinjs.transaction();
|
||||
var txfee = $("#txFee");
|
||||
var devaddr = coinjs.developer;
|
||||
var devamount = $("#developerDonation");
|
||||
|
||||
if((devamount.val()*1)>0){
|
||||
tx.addoutput(devaddr, devamount.val()*1);
|
||||
}
|
||||
|
||||
var total = (devamount.val()*1) + (txfee.val()*1);
|
||||
|
||||
$.each($("#walletSpendTo .output"), function(i,o){
|
||||
var addr = $('.addressTo',o);
|
||||
var amount = $('.amount',o);
|
||||
total += amount.val()*1;
|
||||
tx.addoutput(addr.val(), amount.val()*1);
|
||||
});
|
||||
|
||||
thisbtn.attr('disabled',true);
|
||||
|
||||
tx.addUnspent($("#walletAddress").html(), function(data){
|
||||
var dvalue = data.value/100000000
|
||||
if(dvalue>=total){
|
||||
var change = dvalue-total;
|
||||
if(change>0){
|
||||
tx.addoutput($("#walletAddress").html(), change);
|
||||
}
|
||||
|
||||
// clone the transaction with out using coinjs.clone() function as it gives us trouble
|
||||
var tx2 = coinjs.transaction();
|
||||
var txunspent = tx2.deserialize(tx.serialize());
|
||||
|
||||
// then sign
|
||||
var signed = txunspent.sign($("#walletKeys .privkey").val());
|
||||
|
||||
// and finally broadcast!
|
||||
tx2.broadcast(function(data){
|
||||
if($(data).find("result").text()=="1"){
|
||||
$("#walletSendConfirmStatus").removeClass('hidden').addClass('alert-success').html("txid: "+$(data).find("txid").text());
|
||||
} else {
|
||||
$("#walletSendConfirmStatus").removeClass('hidden').addClass('alert-danger').html(unescape($(data).find("response").text()).replace(/\+/g,' '));
|
||||
}
|
||||
|
||||
// update wallet balance
|
||||
walletBalance();
|
||||
|
||||
}, signed);
|
||||
} else {
|
||||
$("#walletSendConfirmStatus").removeClass("hidden").addClass('alert-danger').html("You have a confirmed balance of "+data.value+" BTC unable to send "+total+" BTC").fadeOut().fadeIn();
|
||||
}
|
||||
|
||||
thisbtn.attr('disabled',false);
|
||||
$("#walletLoader").addClass("hidden");
|
||||
});
|
||||
});
|
||||
|
||||
$("#walletSendBtn").click(function(){
|
||||
|
||||
$("#walletSendStatus").addClass("hidden").html("");
|
||||
|
||||
var thisbtn = $(this);
|
||||
var txfee = $("#txFee");
|
||||
var devamount = $("#developerDonation");
|
||||
|
||||
if((!isNaN(devamount.val())) && devamount.val()>=0){
|
||||
$(devamount).parent().removeClass('has-error');
|
||||
} else {
|
||||
$(devamount).parent().addClass('has-error')
|
||||
}
|
||||
|
||||
if((!isNaN(txfee.val())) && txfee.val()>=0){
|
||||
$(txfee).parent().removeClass('has-error');
|
||||
} else {
|
||||
$(txfee).parent().addClass('has-error');
|
||||
}
|
||||
|
||||
var total = (devamount.val()*1) + (txfee.val()*1);
|
||||
|
||||
$.each($("#walletSpendTo .output"), function(i,o){
|
||||
var amount = $('.amount',o);
|
||||
var address = $('.addressTo',o);
|
||||
|
||||
total += amount.val()*1;
|
||||
|
||||
if((!isNaN($(amount).val())) && $(amount).val()>0){
|
||||
$(amount).parent().removeClass('has-error');
|
||||
} else {
|
||||
$(amount).parent().addClass('has-error');
|
||||
}
|
||||
|
||||
if(coinjs.addressDecode($(address).val())){
|
||||
$(address).parent().removeClass('has-error');
|
||||
} else {
|
||||
$(address).parent().addClass('has-error');
|
||||
}
|
||||
});
|
||||
|
||||
total = total.toFixed(8);
|
||||
|
||||
if($("#walletSpend .has-error").length==0){
|
||||
var balance = ($("#walletBalance").html()).replace(/[^0-9\.]+/g,'')*1;
|
||||
if(total<=balance){
|
||||
$("#walletSendConfirmStatus").addClass("hidden").removeClass('alert-success').removeClass('alert-danger').html("");
|
||||
$("#spendAmount").html(total);
|
||||
$("#modalWalletConfirm").modal("show");
|
||||
$("#walletConfirmSend").attr('disabled',false);
|
||||
} else {
|
||||
$("#walletSendStatus").removeClass("hidden").html("You are trying to spend "+total+' but have a balance of '+balance);
|
||||
}
|
||||
} else {
|
||||
$("#walletSpend .has-error").fadeOut().fadeIn();
|
||||
$("#walletSendStatus").removeClass("hidden").html('<span class="glyphicon glyphicon-exclamation-sign"></span> One or more input has an error');
|
||||
}
|
||||
});
|
||||
|
||||
$("#walletShowSpend").click(function(){
|
||||
$("#walletSpend").removeClass("hidden");
|
||||
$("#walletKeys").removeClass("hidden").addClass("hidden");
|
||||
});
|
||||
|
||||
$("#walletSpendTo .addressAdd").click(function(){
|
||||
var clone = '<div class="form-inline output">'+$(this).parent().html()+'</div>';
|
||||
$("#walletSpendTo").append(clone);
|
||||
$("#walletSpendTo .glyphicon-plus:last").removeClass('glyphicon-plus').addClass('glyphicon-minus');
|
||||
$("#walletSpendTo .glyphicon-minus:last").parent().removeClass('addressAdd').addClass('addressRemove');
|
||||
$("#walletSpendTo .addressRemove").unbind("");
|
||||
$("#walletSpendTo .addressRemove").click(function(){
|
||||
$(this).parent().fadeOut().remove();
|
||||
});
|
||||
});
|
||||
|
||||
function walletBalance(){
|
||||
var tx = coinjs.transaction();
|
||||
$("#walletLoader").removeClass("hidden");
|
||||
coinjs.addressBalance($("#walletAddress").html(),function(data){
|
||||
if($(data).find("result").text()==1){
|
||||
var v = $(data).find("balance").text()/100000000;
|
||||
$("#walletBalance").html(v+" BTC").attr('rel',v).fadeOut().fadeIn();
|
||||
} else {
|
||||
$("#walletBalance").html("0.00 BTC").attr('rel',v).fadeOut().fadeIn();
|
||||
}
|
||||
|
||||
$("#walletLoader").addClass("hidden");
|
||||
});
|
||||
}
|
||||
|
||||
function checkBalanceLoop(){
|
||||
setTimeout(function(){
|
||||
walletBalance();
|
||||
checkBalanceLoop();
|
||||
},45000);
|
||||
}
|
||||
|
||||
/* new -> address code */
|
||||
|
||||
$("#newKeysBtn").click(function(){
|
||||
coinjs.compressed = false;
|
||||
if($("#newCompressed").is(":checked")){
|
||||
coinjs.compressed = true;
|
||||
}
|
||||
var s = ($("#newBrainwallet").is(":checked")) ? $("#brainwallet").val() : null;
|
||||
var coin = coinjs.newKeys(s);
|
||||
$("#newBitcoinAddress").val(coin.address);
|
||||
$("#newPubKey").val(coin.pubkey);
|
||||
$("#newPrivKey").val(coin.wif);
|
||||
});
|
||||
|
||||
$("#newBrainwallet").click(function(){
|
||||
if($(this).is(":checked")){
|
||||
$("#brainwallet").removeClass("hidden");
|
||||
} else {
|
||||
$("#brainwallet").addClass("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
/* new -> multisig code */
|
||||
|
||||
$("#newMultiSigAddress").click(function(){
|
||||
|
||||
$("#multiSigData").removeClass('show').addClass('hidden').fadeOut();
|
||||
$("#multisigPubKeys .pubkey").parent().removeClass('has-error');
|
||||
$("#releaseCoins").parent().removeClass('has-error');
|
||||
$("#multiSigErrorMsg").hide();
|
||||
|
||||
if((isNaN($("#releaseCoins option:selected").html())) || ((!isNaN($("#releaseCoins option:selected").html())) && ($("#releaseCoins option:selected").html()>$("#multisigPubKeys .pubkey").length || $("#releaseCoins option:selected").html()*1<=0 || $("#releaseCoins option:selected").html()*1>8))){
|
||||
$("#releaseCoins").parent().addClass('has-error');
|
||||
$("#multiSigErrorMsg").html('<span class="glyphicon glyphicon-exclamation-sign"></span> Minimum signatures required is greater than the amount of public keys provided').fadeIn();
|
||||
return false;
|
||||
}
|
||||
|
||||
var keys = [];
|
||||
$.each($("#multisigPubKeys .pubkey"), function(i,o){
|
||||
if(coinjs.pubkeydecompress($(o).val())){
|
||||
keys.push($(o).val());
|
||||
$(o).parent().removeClass('has-error');
|
||||
} else {
|
||||
$(o).parent().addClass('has-error');
|
||||
}
|
||||
});
|
||||
|
||||
if(($("#multisigPubKeys .pubkey").parent().hasClass('has-error')==false) && $("#releaseCoins").parent().hasClass('has-error')==false){
|
||||
var sigsNeeded = $("#releaseCoins option:selected").html();
|
||||
var multisig = coinjs.pubkeys2MultisigAddress(keys, sigsNeeded);
|
||||
$("#multiSigData .address").val(multisig['address']);
|
||||
$("#multiSigData .script").val(multisig['redeemScript']);
|
||||
$("#multiSigData").removeClass('hidden').addClass('show').fadeIn();
|
||||
$("#releaseCoins").removeClass('has-error');
|
||||
} else {
|
||||
$("#multiSigErrorMsg").html('<span class="glyphicon glyphicon-exclamation-sign"></span> One or more public key is invalid!').fadeIn();
|
||||
}
|
||||
});
|
||||
|
||||
$("#multisigPubKeys .pubkeyAdd").click(function(){
|
||||
if($("#multisigPubKeys .pubkeyRemove").length<14){
|
||||
var clone = '<div class="form-inline">'+$(this).parent().html()+'</div>';
|
||||
$("#multisigPubKeys").append(clone);
|
||||
$("#multisigPubKeys .glyphicon-plus:last").removeClass('glyphicon-plus').addClass('glyphicon-minus');
|
||||
$("#multisigPubKeys .glyphicon-minus:last").parent().removeClass('pubkeyAdd').addClass('pubkeyRemove');
|
||||
$("#multisigPubKeys .pubkeyRemove").unbind("");
|
||||
$("#multisigPubKeys .pubkeyRemove").click(function(){
|
||||
$(this).parent().fadeOut().remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/* new -> transaction code */
|
||||
|
||||
$("#recipients .addressAddTo").click(function(){
|
||||
if($("#recipients .addressRemoveTo").length<19){
|
||||
var clone = '<div class="row recipient"><br>'+$(this).parent().parent().html()+'</div>';
|
||||
$("#recipients").append(clone);
|
||||
$("#recipients .glyphicon-plus:last").removeClass('glyphicon-plus').addClass('glyphicon-minus');
|
||||
$("#recipients .glyphicon-minus:last").parent().removeClass('addressAdd').addClass('addressRemoveTo');
|
||||
$("#recipients .addressRemoveTo").unbind("");
|
||||
$("#recipients .addressRemoveTo").click(function(){
|
||||
$(this).parent().parent().fadeOut().remove();
|
||||
validateOutputAmount();
|
||||
});
|
||||
validateOutputAmount();
|
||||
}
|
||||
});
|
||||
|
||||
$("#inputs .txidAdd").click(function(){
|
||||
var clone = '<div class="row inputs"><br>'+$(this).parent().parent().html()+'</div>';
|
||||
$("#inputs").append(clone);
|
||||
$("#inputs .txidClear:last").remove();
|
||||
$("#inputs .glyphicon-plus:last").removeClass('glyphicon-plus').addClass('glyphicon-minus');
|
||||
$("#inputs .glyphicon-minus:last").parent().removeClass('txidAdd').addClass('txidRemove');
|
||||
$("#inputs .txidRemove").unbind("");
|
||||
$("#inputs .txidRemove").click(function(){
|
||||
$(this).parent().parent().fadeOut().remove();
|
||||
totalInputAmount();
|
||||
});
|
||||
$("#inputs .row:last input").attr('disabled',false);
|
||||
|
||||
$("#inputs .txIdAmount").unbind("").change(function(){
|
||||
totalInputAmount();
|
||||
}).keyup(function(){
|
||||
totalInputAmount();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$("#transactionBtn").click(function(){
|
||||
var tx = coinjs.transaction();
|
||||
$.each($("#inputs .row"), function(i,o){
|
||||
if($(".txId",o).val()!="" && $(".txIdN",o).val()!=""){
|
||||
tx.addinput($(".txId",o).val(), $(".txIdN",o).val(), $(".txIdScript",o).val());
|
||||
}
|
||||
});
|
||||
|
||||
$.each($("#recipients .row"), function(i,o){
|
||||
if($(".address",o).val()!="" && $(".amount",o).val()!=""){
|
||||
tx.addoutput($(".address",o).val(), $(".amount",o).val());
|
||||
}
|
||||
});
|
||||
|
||||
$("#transactionCreate textarea").val(tx.serialize());
|
||||
$("#transactionCreate .txSize").html(tx.size());
|
||||
|
||||
$("#transactionCreate").removeClass("hidden");
|
||||
});
|
||||
|
||||
$(".txidClear").click(function(){
|
||||
$("#inputs .row:first input").attr('disabled',false);
|
||||
$("#inputs .row:first input").val("");
|
||||
totalInputAmount();
|
||||
});
|
||||
|
||||
$("#inputs .txIdAmount").unbind("").change(function(){
|
||||
totalInputAmount();
|
||||
}).keyup(function(){
|
||||
totalInputAmount();
|
||||
});
|
||||
|
||||
$("#redeemFromBtn").click(function(){
|
||||
var thisbtn = this;
|
||||
var addr = '';
|
||||
var isMultiSig = false;
|
||||
var s = $("#redeemFrom").val();
|
||||
|
||||
$("#redeemFromStatus, #redeemFromAddress").addClass('hidden');
|
||||
$(thisbtn).html("Please wait, loading...").attr('disabled',true);
|
||||
|
||||
var decode = coinjs.addressDecode(s);
|
||||
|
||||
if(decode.version == coinjs.pub){
|
||||
addr = s;
|
||||
} else if (decode.version == coinjs.priv){
|
||||
var a = coinjs.wif2address(s);
|
||||
addr = a['address'];
|
||||
} else if (decode.version == coinjs.multisig){
|
||||
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> You should use the redeem script, not the multisig address!');
|
||||
} else {
|
||||
var script = coinjs.script();
|
||||
var decodeRs = script.decodeRedeemScript(s);
|
||||
if(decodeRs){
|
||||
addr = decodeRs['address'];
|
||||
isMultiSig = true;
|
||||
} else {
|
||||
// input is neither a regular address or redeem script
|
||||
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> The address or multisig redeem script you have entered is invalid');
|
||||
}
|
||||
}
|
||||
|
||||
var tx = coinjs.transaction();
|
||||
tx.listUnspent(addr, function(data){
|
||||
if(addr) {
|
||||
$("#inputs .txidRemove, #inputs .txidClear").click();
|
||||
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="https://www.blockchain.info/address/'+addr+'" target="_blank">'+addr+'</a>');
|
||||
|
||||
$.each($(data).find("unspent").children(), function(i,o){
|
||||
var val = (($(o).find("value").text()*1)/100000000);
|
||||
var txid = (($(o).find("tx_hash").text()).match(/.{1,2}/g).reverse()).join("")+'';
|
||||
|
||||
$("#inputs .txId:last").val(txid);
|
||||
$("#inputs .txIdN:last").val($(o).find("tx_output_n").text());
|
||||
$("#inputs .txIdAmount:last").val(val.toFixed(8));
|
||||
if(isMultiSig==true){
|
||||
$("#inputs .txIdScript:last").val(s);
|
||||
} else {
|
||||
$("#inputs .txIdScript:last").val($(o).find("script").text());
|
||||
}
|
||||
|
||||
$("#inputs .row:last input").attr('disabled',true);
|
||||
|
||||
if(i<($(data).find("unspent").children().length-1)){
|
||||
$("#inputs .txidAdd").click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(thisbtn).html("Load").attr('disabled',false);
|
||||
totalInputAmount();
|
||||
});
|
||||
});
|
||||
|
||||
function totalInputAmount(){
|
||||
$("#totalInput").html('0.00');
|
||||
$.each($("#inputs .txIdAmount"), function(i,o){
|
||||
if(isNaN($(o).val())){
|
||||
$(o).parent().addClass('has-error');
|
||||
} else {
|
||||
$(o).parent().removeClass('has-error');
|
||||
var f = 0;
|
||||
if(!isNaN($(o).val())){
|
||||
f += $(o).val()*1;
|
||||
}
|
||||
$("#totalInput").html((($("#totalInput").html()*1) + (f*1)).toFixed(8));
|
||||
}
|
||||
});
|
||||
totalFee();
|
||||
}
|
||||
|
||||
function validateOutputAmount(){
|
||||
$("#recipients .amount").unbind('');
|
||||
$("#recipients .amount").keyup(function(){
|
||||
if(isNaN($(this).val())){
|
||||
$(this).parent().addClass('has-error');
|
||||
} else {
|
||||
$(this).parent().removeClass('has-error');
|
||||
var f = 0;
|
||||
$.each($("#recipients .amount"),function(i,o){
|
||||
if(!isNaN($(o).val())){
|
||||
f += $(o).val()*1;
|
||||
}
|
||||
});
|
||||
$("#totalOutput").html((f).toFixed(8));
|
||||
}
|
||||
totalFee();
|
||||
}).keyup();
|
||||
}
|
||||
|
||||
function totalFee(){
|
||||
var fee = (($("#totalInput").html()*1) - ($("#totalOutput").html()*1)).toFixed(8);
|
||||
$("#transactionFee").val((fee>0)?fee:'0.00');
|
||||
}
|
||||
|
||||
/* broadcast a transaction */
|
||||
|
||||
$("#rawSubmitBtn").click(function(){
|
||||
var tx = coinjs.transaction();
|
||||
tx.broadcast(function(data){
|
||||
$("#rawTransactionStatus").html(unescape($(data).find("response").text()).replace(/\+/g,' ')).removeClass('hidden');
|
||||
if($(data).find("result").text()==1){
|
||||
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger');
|
||||
$("#rawTransactionStatus").html('txid: '+$(data).find("txid").text());
|
||||
} else {
|
||||
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ');
|
||||
}
|
||||
$("#rawTransactionStatus").fadeOut().fadeIn();
|
||||
}, $("#rawTransaction").val());
|
||||
});
|
||||
|
||||
/* verify script code */
|
||||
|
||||
$("#verifyBtn").click(function(){
|
||||
$(".verifyData").addClass("hidden");
|
||||
$("#verifyStatus").hide();
|
||||
if(!decodeRedeemScript()){
|
||||
if(!decodeTransactionScript()){
|
||||
if(!decodePrivKey()){
|
||||
if(!decodePubKey()){
|
||||
$("#verifyStatus").removeClass('hidden').fadeOut().fadeIn();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function decodeRedeemScript(){
|
||||
var script = coinjs.script();
|
||||
var decode = script.decodeRedeemScript($("#verifyScript").val());
|
||||
if(decode){
|
||||
$("#verifyRsData .multisigAddress").val(decode['address']);
|
||||
$("#verifyRsData .signaturesRequired").html(decode['signaturesRequired']);
|
||||
$("#verifyRsData table tbody").html("");
|
||||
for(var i=0;i<decode.pubkeys.length;i++){
|
||||
$('<tr><td><input type="text" class="form-control" value="'+decode.pubkeys[i]+'" readonly></td></tr>').appendTo("#verifyRsData table tbody");
|
||||
}
|
||||
$("#verifyRsData").removeClass("hidden");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function decodeTransactionScript(){
|
||||
var tx = coinjs.transaction();
|
||||
try {
|
||||
var decode = tx.deserialize($("#verifyScript").val());
|
||||
$("#verifyTransactionData .transactionVersion").html(decode['version']);
|
||||
$("#verifyTransactionData .transactionSize").html(decode.size()+' <i>bytes</i>');
|
||||
$("#verifyTransactionData .transactionLockTime").html(decode['lock_time']);
|
||||
$("#verifyTransactionData").removeClass("hidden");
|
||||
$("#verifyTransactionData tbody").html("");
|
||||
|
||||
var h = '';
|
||||
$.each(decode.ins, function(i,o){
|
||||
var s = decode.extractScriptKey(i);
|
||||
h += '<tr>';
|
||||
h += '<td><input class="form-control" type="text" value="'+o.outpoint.hash+'" readonly></td>';
|
||||
h += '<td class="col-xs-1">'+o.outpoint.index+'</td>';
|
||||
h += '<td class="col-xs-2"><input class="form-control" type="text" value="'+Crypto.util.bytesToHex(o.script.buffer)+'" readonly></td>';
|
||||
h += '<td class="col-xs-1"> <span class="glyphicon glyphicon-'+((s.signed=='true')?'ok':'remove')+'-circle"></span>';
|
||||
if(s['type']=='multisig' && s['signatures']>=1){
|
||||
h += ' '+s['signatures'];
|
||||
}
|
||||
h += '</td>';
|
||||
h += '<td class="col-xs-1">';
|
||||
if(s['type']=='multisig'){
|
||||
var script = coinjs.script();
|
||||
var rs = script.decodeRedeemScript(s.script);
|
||||
h += rs['signaturesRequired']+' of '+rs['pubkeys'].length;
|
||||
} else {
|
||||
h += '<span class="glyphicon glyphicon-remove-circle"></span>';
|
||||
}
|
||||
h += '</td>';
|
||||
h += '</tr>';
|
||||
});
|
||||
$(h).appendTo("#verifyTransactionData .ins tbody");
|
||||
|
||||
h = '';
|
||||
$.each(decode.outs, function(i,o){
|
||||
|
||||
var addr = '';
|
||||
if(o.script.chunks.length==5){
|
||||
addr = coinjs.scripthash2address(Crypto.util.bytesToHex(o.script.chunks[2]));
|
||||
} else {
|
||||
var priv = coinjs.priv;
|
||||
coinjs.priv = 0x05;
|
||||
addr = coinjs.scripthash2address(Crypto.util.bytesToHex(o.script.chunks[1]));
|
||||
coinjs.priv = priv;
|
||||
}
|
||||
|
||||
h += '<tr>';
|
||||
h += '<td><input class="form-control" type="text" value="'+addr+'" readonly></td>';
|
||||
h += '<td class="col-xs-1">'+(o.value/100000000).toFixed(8)+'</td>';
|
||||
h += '<td class="col-xs-2"><input class="form-control" type="text" value="'+Crypto.util.bytesToHex(o.script.buffer)+'" readonly></td>';
|
||||
h += '</tr>';
|
||||
});
|
||||
$(h).appendTo("#verifyTransactionData .outs tbody");
|
||||
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function decodePrivKey(){
|
||||
var wif = $("#verifyScript").val();
|
||||
if(wif.length==51 || wif.length==52){
|
||||
try {
|
||||
var w2address = coinjs.wif2address(wif);
|
||||
var w2pubkey = coinjs.wif2pubkey(wif);
|
||||
var w2privkey = coinjs.wif2privkey(wif);
|
||||
|
||||
$("#verifyPrivKey .address").val(w2address['address']);
|
||||
$("#verifyPrivKey .pubkey").val(w2pubkey['pubkey']);
|
||||
$("#verifyPrivKey .privkey").val(w2privkey['privkey']);
|
||||
$("#verifyPrivKey .iscompressed").html(w2address['compressed']?'true':'false');
|
||||
|
||||
$("#verifyPrivKey").removeClass("hidden");
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function decodePubKey(){
|
||||
var pubkey = $("#verifyScript").val();
|
||||
if(pubkey.length==66 || pubkey.length==130){
|
||||
try {
|
||||
$("#verifyPubKey .address").val(coinjs.pubkey2address(pubkey));
|
||||
$("#verifyPubKey").removeClass("hidden");
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* sign code */
|
||||
|
||||
$("#signBtn").click(function(){
|
||||
var wifkey = $("#signPrivateKey");
|
||||
var script = $("#signTransaction");
|
||||
|
||||
if(coinjs.addressDecode(wifkey.val())){
|
||||
$(wifkey).parent().removeClass('has-error');
|
||||
} else {
|
||||
$(wifkey).parent().addClass('has-error');
|
||||
}
|
||||
|
||||
if((script.val()).match(/^[a-f0-9]+$/ig)){
|
||||
$(script).parent().removeClass('has-error');
|
||||
} else {
|
||||
$(script).parent().addClass('has-error');
|
||||
}
|
||||
|
||||
if($("#sign .has-error").length==0){
|
||||
$("#signedDataError").addClass('hidden');
|
||||
try {
|
||||
var tx = coinjs.transaction();
|
||||
var t = tx.deserialize(script.val());
|
||||
var signed = t.sign(wifkey.val());
|
||||
$("#signedData textarea").val(signed);
|
||||
$("#signedData .txSize").html(t.size());
|
||||
$("#signedData").removeClass('hidden').fadeIn();
|
||||
} catch(e) {
|
||||
// console.log(e);
|
||||
}
|
||||
} else {
|
||||
$("#signedDataError").removeClass('hidden');
|
||||
$("#signedData").addClass('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/* page load code */
|
||||
|
||||
$(".qrcodeBtn").click(function(){
|
||||
var thisbtn = $(this).parent().parent();
|
||||
$("#qrcode").attr('src','https://chart.googleapis.com/chart?chs=250x250&cht=qr&chl=bitcoin:'+$('.address',thisbtn).val());
|
||||
});
|
||||
|
||||
$('input[title!=""], abbr[title!=""]').tooltip({'placement':'bottom'});
|
||||
|
||||
if (location.hash !== ''){
|
||||
$('a[href="' + location.hash + '"]').tab('show');
|
||||
}
|
||||
|
||||
$(".showKey").click(function(){
|
||||
$("input[type='password']",$(this).parent().parent()).attr('type','text');
|
||||
});
|
||||
|
||||
$("#homeBtn").click(function(e){
|
||||
e.preventDefault();
|
||||
history.pushState(null, null, '#home');
|
||||
$("#header .active, #content .tab-content").removeClass("active");
|
||||
$("#home").addClass("active");
|
||||
});
|
||||
|
||||
$('a[data-toggle="tab"]').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
if(e.target){
|
||||
history.pushState(null, null, '#'+$(e.target).attr('href').substr(1));
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("popstate", function(e) {
|
||||
var activeTab = $('[href=' + location.hash + ']');
|
||||
if (activeTab.length) {
|
||||
activeTab.tab('show');
|
||||
} else {
|
||||
$('.nav-tabs a:first').tab('show');
|
||||
}
|
||||
});
|
||||
|
||||
for(i=1;i<3;i++){
|
||||
$(".pubkeyAdd").click();
|
||||
}
|
||||
|
||||
$("#newKeysBtn").click();
|
||||
|
||||
validateOutputAmount();
|
||||
});
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Crypto-JS v2.5.4
|
||||
* http://code.google.com/p/crypto-js/
|
||||
* (c) 2009-2012 by Jeff Mott. All rights reserved.
|
||||
* http://code.google.com/p/crypto-js/wiki/License
|
||||
*/
|
||||
(typeof Crypto=="undefined"||!Crypto.util)&&function(){var e=window.Crypto={},f=e.util={rotl:function(a,b){return a<<b|a>>>32-b},rotr:function(a,b){return a<<32-b|a>>>b},endian:function(a){if(a.constructor==Number)return f.rotl(a,8)&16711935|f.rotl(a,24)&4278255360;for(var b=0;b<a.length;b++)a[b]=f.endian(a[b]);return a},randomBytes:function(a){for(var b=[];a>0;a--)b.push(Math.floor(Math.random()*256));return b},bytesToWords:function(a){for(var b=[],c=0,d=0;c<a.length;c++,d+=8)b[d>>>5]|=(a[c]&255)<<
|
||||
24-d%32;return b},wordsToBytes:function(a){for(var b=[],c=0;c<a.length*32;c+=8)b.push(a[c>>>5]>>>24-c%32&255);return b},bytesToHex:function(a){for(var b=[],c=0;c<a.length;c++)b.push((a[c]>>>4).toString(16)),b.push((a[c]&15).toString(16));return b.join("")},hexToBytes:function(a){for(var b=[],c=0;c<a.length;c+=2)b.push(parseInt(a.substr(c,2),16));return b},bytesToBase64:function(a){for(var b=[],c=0;c<a.length;c+=3)for(var d=a[c]<<16|a[c+1]<<8|a[c+2],e=0;e<4;e++)c*8+e*6<=a.length*8?b.push("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d>>>
|
||||
6*(3-e)&63)):b.push("=");return b.join("")},base64ToBytes:function(a){for(var a=a.replace(/[^A-Z0-9+\/]/ig,""),b=[],c=0,d=0;c<a.length;d=++c%4)d!=0&&b.push(("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(a.charAt(c-1))&Math.pow(2,-2*d+8)-1)<<d*2|"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(a.charAt(c))>>>6-d*2);return b}},e=e.charenc={};e.UTF8={stringToBytes:function(a){return g.stringToBytes(unescape(encodeURIComponent(a)))},bytesToString:function(a){return decodeURIComponent(escape(g.bytesToString(a)))}};
|
||||
var g=e.Binary={stringToBytes:function(a){for(var b=[],c=0;c<a.length;c++)b.push(a.charCodeAt(c)&255);return b},bytesToString:function(a){for(var b=[],c=0;c<a.length;c++)b.push(String.fromCharCode(a[c]));return b.join("")}}}();
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Crypto-JS v2.5.4
|
||||
* http://code.google.com/p/crypto-js/
|
||||
* (c) 2009-2012 by Jeff Mott. All rights reserved.
|
||||
* http://code.google.com/p/crypto-js/wiki/License
|
||||
*/
|
||||
(typeof Crypto=="undefined"||!Crypto.util)&&function(){var f=window.Crypto={},l=f.util={rotl:function(b,a){return b<<a|b>>>32-a},rotr:function(b,a){return b<<32-a|b>>>a},endian:function(b){if(b.constructor==Number)return l.rotl(b,8)&16711935|l.rotl(b,24)&4278255360;for(var a=0;a<b.length;a++)b[a]=l.endian(b[a]);return b},randomBytes:function(b){for(var a=[];b>0;b--)a.push(Math.floor(Math.random()*256));return a},bytesToWords:function(b){for(var a=[],c=0,d=0;c<b.length;c++,d+=8)a[d>>>5]|=(b[c]&255)<<
|
||||
24-d%32;return a},wordsToBytes:function(b){for(var a=[],c=0;c<b.length*32;c+=8)a.push(b[c>>>5]>>>24-c%32&255);return a},bytesToHex:function(b){for(var a=[],c=0;c<b.length;c++)a.push((b[c]>>>4).toString(16)),a.push((b[c]&15).toString(16));return a.join("")},hexToBytes:function(b){for(var a=[],c=0;c<b.length;c+=2)a.push(parseInt(b.substr(c,2),16));return a},bytesToBase64:function(b){for(var a=[],c=0;c<b.length;c+=3)for(var d=b[c]<<16|b[c+1]<<8|b[c+2],q=0;q<4;q++)c*8+q*6<=b.length*8?a.push("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d>>>
|
||||
6*(3-q)&63)):a.push("=");return a.join("")},base64ToBytes:function(b){for(var b=b.replace(/[^A-Z0-9+\/]/ig,""),a=[],c=0,d=0;c<b.length;d=++c%4)d!=0&&a.push(("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(b.charAt(c-1))&Math.pow(2,-2*d+8)-1)<<d*2|"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(b.charAt(c))>>>6-d*2);return a}},f=f.charenc={};f.UTF8={stringToBytes:function(b){return i.stringToBytes(unescape(encodeURIComponent(b)))},bytesToString:function(b){return decodeURIComponent(escape(i.bytesToString(b)))}};
|
||||
var i=f.Binary={stringToBytes:function(b){for(var a=[],c=0;c<b.length;c++)a.push(b.charCodeAt(c)&255);return a},bytesToString:function(b){for(var a=[],c=0;c<b.length;c++)a.push(String.fromCharCode(b[c]));return a.join("")}}}();
|
||||
(function(){var f=Crypto,l=f.util,i=f.charenc,b=i.UTF8,a=i.Binary,c=[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=f.SHA256=function(b,c){var e=l.wordsToBytes(d._sha256(b));return c&&c.asBytes?e:c&&c.asString?a.bytesToString(e):l.bytesToHex(e)};d._sha256=function(a){a.constructor==String&&(a=b.stringToBytes(a));var d=l.bytesToWords(a),e=a.length*8,a=[1779033703,3144134277,
|
||||
1013904242,2773480762,1359893119,2600822924,528734635,1541459225],f=[],m,n,i,h,o,p,r,s,g,k,j;d[e>>5]|=128<<24-e%32;d[(e+64>>9<<4)+15]=e;for(s=0;s<d.length;s+=16){e=a[0];m=a[1];n=a[2];i=a[3];h=a[4];o=a[5];p=a[6];r=a[7];for(g=0;g<64;g++){g<16?f[g]=d[g+s]:(k=f[g-15],j=f[g-2],f[g]=((k<<25|k>>>7)^(k<<14|k>>>18)^k>>>3)+(f[g-7]>>>0)+((j<<15|j>>>17)^(j<<13|j>>>19)^j>>>10)+(f[g-16]>>>0));j=e&m^e&n^m&n;var t=(e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22);k=(r>>>0)+((h<<26|h>>>6)^(h<<21|h>>>11)^(h<<7|h>>>25))+
|
||||
(h&o^~h&p)+c[g]+(f[g]>>>0);j=t+j;r=p;p=o;o=h;h=i+k>>>0;i=n;n=m;m=e;e=k+j>>>0}a[0]+=e;a[1]+=m;a[2]+=n;a[3]+=i;a[4]+=h;a[5]+=o;a[6]+=p;a[7]+=r}return a};d._blocksize=16;d._digestsize=32})();
|
||||
@@ -0,0 +1,407 @@
|
||||
/*!
|
||||
* Crypto-JS v2.5.4 AES.js
|
||||
* http://code.google.com/p/crypto-js/
|
||||
* Copyright (c) 2009-2013, Jeff Mott. All rights reserved.
|
||||
* http://code.google.com/p/crypto-js/wiki/License
|
||||
*/
|
||||
(function () {
|
||||
|
||||
// Shortcuts
|
||||
var C = Crypto,
|
||||
util = C.util,
|
||||
charenc = C.charenc,
|
||||
UTF8 = charenc.UTF8;
|
||||
|
||||
// Precomputed SBOX
|
||||
var SBOX = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
|
||||
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
|
||||
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
|
||||
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
|
||||
0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
|
||||
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
|
||||
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
|
||||
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
|
||||
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
|
||||
0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
|
||||
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
|
||||
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
|
||||
0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
|
||||
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
|
||||
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
|
||||
0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
|
||||
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16];
|
||||
|
||||
// Compute inverse SBOX lookup table
|
||||
for (var INVSBOX = [], i = 0; i < 256; i++) INVSBOX[SBOX[i]] = i;
|
||||
|
||||
// Compute multiplication in GF(2^8) lookup tables
|
||||
var MULT2 = [],
|
||||
MULT3 = [],
|
||||
MULT9 = [],
|
||||
MULTB = [],
|
||||
MULTD = [],
|
||||
MULTE = [];
|
||||
|
||||
function xtime(a, b) {
|
||||
for (var result = 0, i = 0; i < 8; i++) {
|
||||
if (b & 1) result ^= a;
|
||||
var hiBitSet = a & 0x80;
|
||||
a = (a << 1) & 0xFF;
|
||||
if (hiBitSet) a ^= 0x1b;
|
||||
b >>>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 256; i++) {
|
||||
MULT2[i] = xtime(i, 2);
|
||||
MULT3[i] = xtime(i, 3);
|
||||
MULT9[i] = xtime(i, 9);
|
||||
MULTB[i] = xtime(i, 0xB);
|
||||
MULTD[i] = xtime(i, 0xD);
|
||||
MULTE[i] = xtime(i, 0xE);
|
||||
}
|
||||
|
||||
// Precomputed RCon lookup
|
||||
var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
|
||||
|
||||
// Inner state
|
||||
var state = [[], [], [], []],
|
||||
keylength,
|
||||
nrounds,
|
||||
keyschedule;
|
||||
|
||||
var AES = C.AES = {
|
||||
|
||||
/**
|
||||
* Public API
|
||||
*/
|
||||
|
||||
encrypt: function (message, password, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
// Determine mode
|
||||
var mode = options.mode || new C.mode.OFB;
|
||||
|
||||
// Allow mode to override options
|
||||
if (mode.fixOptions) mode.fixOptions(options);
|
||||
|
||||
var
|
||||
|
||||
// Convert to bytes if message is a string
|
||||
m = (
|
||||
message.constructor == String ?
|
||||
UTF8.stringToBytes(message) :
|
||||
message
|
||||
),
|
||||
|
||||
// Generate random IV
|
||||
iv = options.iv || util.randomBytes(AES._blocksize * 4),
|
||||
|
||||
// Generate key
|
||||
k = (
|
||||
password.constructor == String ?
|
||||
// Derive key from pass-phrase
|
||||
C.PBKDF2(password, iv, 32, { asBytes: true }) :
|
||||
// else, assume byte array representing cryptographic key
|
||||
password
|
||||
);
|
||||
|
||||
// Encrypt
|
||||
AES._init(k);
|
||||
mode.encrypt(AES, m, iv);
|
||||
|
||||
// Return ciphertext
|
||||
m = options.iv ? m : iv.concat(m);
|
||||
return (options && options.asBytes) ? m : util.bytesToBase64(m);
|
||||
|
||||
},
|
||||
|
||||
decrypt: function (ciphertext, password, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
// Determine mode
|
||||
var mode = options.mode || new C.mode.OFB;
|
||||
|
||||
// Allow mode to override options
|
||||
if (mode.fixOptions) mode.fixOptions(options);
|
||||
|
||||
var
|
||||
|
||||
// Convert to bytes if ciphertext is a string
|
||||
c = (
|
||||
ciphertext.constructor == String ?
|
||||
util.base64ToBytes(ciphertext) :
|
||||
ciphertext
|
||||
),
|
||||
|
||||
// Separate IV and message
|
||||
iv = options.iv || c.splice(0, AES._blocksize * 4),
|
||||
|
||||
// Generate key
|
||||
k = (
|
||||
password.constructor == String ?
|
||||
// Derive key from pass-phrase
|
||||
C.PBKDF2(password, iv, 32, { asBytes: true }) :
|
||||
// else, assume byte array representing cryptographic key
|
||||
password
|
||||
);
|
||||
|
||||
// Decrypt
|
||||
AES._init(k);
|
||||
mode.decrypt(AES, c, iv);
|
||||
|
||||
// Return plaintext
|
||||
return (options && options.asBytes) ? c : UTF8.bytesToString(c);
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Package private methods and properties
|
||||
*/
|
||||
|
||||
_blocksize: 4,
|
||||
|
||||
_encryptblock: function (m, offset) {
|
||||
|
||||
// Set input
|
||||
for (var row = 0; row < AES._blocksize; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] = m[offset + col * 4 + row];
|
||||
}
|
||||
|
||||
// Add round key
|
||||
for (var row = 0; row < 4; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] ^= keyschedule[col][row];
|
||||
}
|
||||
|
||||
for (var round = 1; round < nrounds; round++) {
|
||||
|
||||
// Sub bytes
|
||||
for (var row = 0; row < 4; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] = SBOX[state[row][col]];
|
||||
}
|
||||
|
||||
// Shift rows
|
||||
state[1].push(state[1].shift());
|
||||
state[2].push(state[2].shift());
|
||||
state[2].push(state[2].shift());
|
||||
state[3].unshift(state[3].pop());
|
||||
|
||||
// Mix columns
|
||||
for (var col = 0; col < 4; col++) {
|
||||
|
||||
var s0 = state[0][col],
|
||||
s1 = state[1][col],
|
||||
s2 = state[2][col],
|
||||
s3 = state[3][col];
|
||||
|
||||
state[0][col] = MULT2[s0] ^ MULT3[s1] ^ s2 ^ s3;
|
||||
state[1][col] = s0 ^ MULT2[s1] ^ MULT3[s2] ^ s3;
|
||||
state[2][col] = s0 ^ s1 ^ MULT2[s2] ^ MULT3[s3];
|
||||
state[3][col] = MULT3[s0] ^ s1 ^ s2 ^ MULT2[s3];
|
||||
|
||||
}
|
||||
|
||||
// Add round key
|
||||
for (var row = 0; row < 4; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] ^= keyschedule[round * 4 + col][row];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Sub bytes
|
||||
for (var row = 0; row < 4; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] = SBOX[state[row][col]];
|
||||
}
|
||||
|
||||
// Shift rows
|
||||
state[1].push(state[1].shift());
|
||||
state[2].push(state[2].shift());
|
||||
state[2].push(state[2].shift());
|
||||
state[3].unshift(state[3].pop());
|
||||
|
||||
// Add round key
|
||||
for (var row = 0; row < 4; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] ^= keyschedule[nrounds * 4 + col][row];
|
||||
}
|
||||
|
||||
// Set output
|
||||
for (var row = 0; row < AES._blocksize; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
m[offset + col * 4 + row] = state[row][col];
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
_decryptblock: function (c, offset) {
|
||||
|
||||
// Set input
|
||||
for (var row = 0; row < AES._blocksize; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] = c[offset + col * 4 + row];
|
||||
}
|
||||
|
||||
// Add round key
|
||||
for (var row = 0; row < 4; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] ^= keyschedule[nrounds * 4 + col][row];
|
||||
}
|
||||
|
||||
for (var round = 1; round < nrounds; round++) {
|
||||
|
||||
// Inv shift rows
|
||||
state[1].unshift(state[1].pop());
|
||||
state[2].push(state[2].shift());
|
||||
state[2].push(state[2].shift());
|
||||
state[3].push(state[3].shift());
|
||||
|
||||
// Inv sub bytes
|
||||
for (var row = 0; row < 4; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] = INVSBOX[state[row][col]];
|
||||
}
|
||||
|
||||
// Add round key
|
||||
for (var row = 0; row < 4; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] ^= keyschedule[(nrounds - round) * 4 + col][row];
|
||||
}
|
||||
|
||||
// Inv mix columns
|
||||
for (var col = 0; col < 4; col++) {
|
||||
|
||||
var s0 = state[0][col],
|
||||
s1 = state[1][col],
|
||||
s2 = state[2][col],
|
||||
s3 = state[3][col];
|
||||
|
||||
state[0][col] = MULTE[s0] ^ MULTB[s1] ^ MULTD[s2] ^ MULT9[s3];
|
||||
state[1][col] = MULT9[s0] ^ MULTE[s1] ^ MULTB[s2] ^ MULTD[s3];
|
||||
state[2][col] = MULTD[s0] ^ MULT9[s1] ^ MULTE[s2] ^ MULTB[s3];
|
||||
state[3][col] = MULTB[s0] ^ MULTD[s1] ^ MULT9[s2] ^ MULTE[s3];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Inv shift rows
|
||||
state[1].unshift(state[1].pop());
|
||||
state[2].push(state[2].shift());
|
||||
state[2].push(state[2].shift());
|
||||
state[3].push(state[3].shift());
|
||||
|
||||
// Inv sub bytes
|
||||
for (var row = 0; row < 4; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] = INVSBOX[state[row][col]];
|
||||
}
|
||||
|
||||
// Add round key
|
||||
for (var row = 0; row < 4; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
state[row][col] ^= keyschedule[col][row];
|
||||
}
|
||||
|
||||
// Set output
|
||||
for (var row = 0; row < AES._blocksize; row++) {
|
||||
for (var col = 0; col < 4; col++)
|
||||
c[offset + col * 4 + row] = state[row][col];
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Private methods
|
||||
*/
|
||||
|
||||
_init: function (k) {
|
||||
keylength = k.length / 4;
|
||||
nrounds = keylength + 6;
|
||||
AES._keyexpansion(k);
|
||||
},
|
||||
|
||||
// Generate a key schedule
|
||||
_keyexpansion: function (k) {
|
||||
|
||||
keyschedule = [];
|
||||
|
||||
for (var row = 0; row < keylength; row++) {
|
||||
keyschedule[row] = [
|
||||
k[row * 4],
|
||||
k[row * 4 + 1],
|
||||
k[row * 4 + 2],
|
||||
k[row * 4 + 3]
|
||||
];
|
||||
}
|
||||
|
||||
for (var row = keylength; row < AES._blocksize * (nrounds + 1); row++) {
|
||||
|
||||
var temp = [
|
||||
keyschedule[row - 1][0],
|
||||
keyschedule[row - 1][1],
|
||||
keyschedule[row - 1][2],
|
||||
keyschedule[row - 1][3]
|
||||
];
|
||||
|
||||
if (row % keylength == 0) {
|
||||
|
||||
// Rot word
|
||||
temp.push(temp.shift());
|
||||
|
||||
// Sub word
|
||||
temp[0] = SBOX[temp[0]];
|
||||
temp[1] = SBOX[temp[1]];
|
||||
temp[2] = SBOX[temp[2]];
|
||||
temp[3] = SBOX[temp[3]];
|
||||
|
||||
temp[0] ^= RCON[row / keylength];
|
||||
|
||||
} else if (keylength > 6 && row % keylength == 4) {
|
||||
|
||||
// Sub word
|
||||
temp[0] = SBOX[temp[0]];
|
||||
temp[1] = SBOX[temp[1]];
|
||||
temp[2] = SBOX[temp[2]];
|
||||
temp[3] = SBOX[temp[3]];
|
||||
|
||||
}
|
||||
|
||||
keyschedule[row] = [
|
||||
keyschedule[row - keylength][0] ^ temp[0],
|
||||
keyschedule[row - keylength][1] ^ temp[1],
|
||||
keyschedule[row - keylength][2] ^ temp[2],
|
||||
keyschedule[row - keylength][3] ^ temp[3]
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,164 @@
|
||||
/*!
|
||||
* Crypto-JS v2.0.0 RIPEMD-160
|
||||
* http://code.google.com/p/crypto-js/
|
||||
* Copyright (c) 2009, Jeff Mott. All rights reserved.
|
||||
* http://code.google.com/p/crypto-js/wiki/License
|
||||
*
|
||||
* A JavaScript implementation of the RIPEMD-160 Algorithm
|
||||
* Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
|
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||
* Distributed under the BSD License
|
||||
* See http://pajhome.org.uk/crypt/md5 for details.
|
||||
* Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
|
||||
* Ported to Crypto-JS by Stefan Thomas.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
// Shortcuts
|
||||
var C = Crypto,
|
||||
util = C.util,
|
||||
charenc = C.charenc,
|
||||
UTF8 = charenc.UTF8,
|
||||
Binary = charenc.Binary;
|
||||
|
||||
// Convert a byte array to little-endian 32-bit words
|
||||
util.bytesToLWords = function (bytes) {
|
||||
|
||||
var output = Array(bytes.length >> 2);
|
||||
for (var i = 0; i < output.length; i++)
|
||||
output[i] = 0;
|
||||
for (var i = 0; i < bytes.length * 8; i += 8)
|
||||
output[i >> 5] |= (bytes[i / 8] & 0xFF) << (i % 32);
|
||||
return output;
|
||||
};
|
||||
|
||||
// Convert little-endian 32-bit words to a byte array
|
||||
util.lWordsToBytes = function (words) {
|
||||
var output = [];
|
||||
for (var i = 0; i < words.length * 32; i += 8)
|
||||
output.push((words[i >> 5] >>> (i % 32)) & 0xff);
|
||||
return output;
|
||||
};
|
||||
|
||||
// Public API
|
||||
var RIPEMD160 = C.RIPEMD160 = function (message, options) {
|
||||
var digestbytes = util.lWordsToBytes(RIPEMD160._rmd160(message));
|
||||
return options && options.asBytes ? digestbytes :
|
||||
options && options.asString ? Binary.bytesToString(digestbytes) :
|
||||
util.bytesToHex(digestbytes);
|
||||
};
|
||||
|
||||
// The core
|
||||
RIPEMD160._rmd160 = function (message) {
|
||||
// Convert to byte array
|
||||
if (message.constructor == String) message = UTF8.stringToBytes(message);
|
||||
|
||||
var x = util.bytesToLWords(message),
|
||||
len = message.length * 8;
|
||||
|
||||
/* append padding */
|
||||
x[len >> 5] |= 0x80 << (len % 32);
|
||||
x[(((len + 64) >>> 9) << 4) + 14] = len;
|
||||
|
||||
var h0 = 0x67452301;
|
||||
var h1 = 0xefcdab89;
|
||||
var h2 = 0x98badcfe;
|
||||
var h3 = 0x10325476;
|
||||
var h4 = 0xc3d2e1f0;
|
||||
|
||||
for (var i = 0; i < x.length; i += 16) {
|
||||
var T;
|
||||
var A1 = h0, B1 = h1, C1 = h2, D1 = h3, E1 = h4;
|
||||
var A2 = h0, B2 = h1, C2 = h2, D2 = h3, E2 = h4;
|
||||
for (var j = 0; j <= 79; ++j) {
|
||||
T = safe_add(A1, rmd160_f(j, B1, C1, D1));
|
||||
T = safe_add(T, x[i + rmd160_r1[j]]);
|
||||
T = safe_add(T, rmd160_K1(j));
|
||||
T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
|
||||
A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
|
||||
T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
|
||||
T = safe_add(T, x[i + rmd160_r2[j]]);
|
||||
T = safe_add(T, rmd160_K2(j));
|
||||
T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
|
||||
A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
|
||||
}
|
||||
T = safe_add(h1, safe_add(C1, D2));
|
||||
h1 = safe_add(h2, safe_add(D1, E2));
|
||||
h2 = safe_add(h3, safe_add(E1, A2));
|
||||
h3 = safe_add(h4, safe_add(A1, B2));
|
||||
h4 = safe_add(h0, safe_add(B1, C2));
|
||||
h0 = T;
|
||||
}
|
||||
return [h0, h1, h2, h3, h4];
|
||||
}
|
||||
|
||||
function rmd160_f(j, x, y, z) {
|
||||
return (0 <= j && j <= 15) ? (x ^ y ^ z) :
|
||||
(16 <= j && j <= 31) ? (x & y) | (~x & z) :
|
||||
(32 <= j && j <= 47) ? (x | ~y) ^ z :
|
||||
(48 <= j && j <= 63) ? (x & z) | (y & ~z) :
|
||||
(64 <= j && j <= 79) ? x ^ (y | ~z) :
|
||||
"rmd160_f: j out of range";
|
||||
}
|
||||
function rmd160_K1(j) {
|
||||
return (0 <= j && j <= 15) ? 0x00000000 :
|
||||
(16 <= j && j <= 31) ? 0x5a827999 :
|
||||
(32 <= j && j <= 47) ? 0x6ed9eba1 :
|
||||
(48 <= j && j <= 63) ? 0x8f1bbcdc :
|
||||
(64 <= j && j <= 79) ? 0xa953fd4e :
|
||||
"rmd160_K1: j out of range";
|
||||
}
|
||||
function rmd160_K2(j) {
|
||||
return (0 <= j && j <= 15) ? 0x50a28be6 :
|
||||
(16 <= j && j <= 31) ? 0x5c4dd124 :
|
||||
(32 <= j && j <= 47) ? 0x6d703ef3 :
|
||||
(48 <= j && j <= 63) ? 0x7a6d76e9 :
|
||||
(64 <= j && j <= 79) ? 0x00000000 :
|
||||
"rmd160_K2: j out of range";
|
||||
}
|
||||
var rmd160_r1 = [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
|
||||
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
|
||||
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
|
||||
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
|
||||
];
|
||||
var rmd160_r2 = [
|
||||
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
|
||||
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
|
||||
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
|
||||
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
|
||||
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
|
||||
];
|
||||
var rmd160_s1 = [
|
||||
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
|
||||
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
|
||||
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
|
||||
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
|
||||
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
|
||||
];
|
||||
var rmd160_s2 = [
|
||||
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
|
||||
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
|
||||
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
|
||||
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
|
||||
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
|
||||
];
|
||||
|
||||
/*
|
||||
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
||||
* to work around bugs in some JS interpreters.
|
||||
*/
|
||||
function safe_add(x, y) {
|
||||
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
||||
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||||
return (msw << 16) | (lsw & 0xFFFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bitwise rotate a 32-bit number to the left.
|
||||
*/
|
||||
function bit_rol(num, cnt) {
|
||||
return (num << cnt) | (num >>> (32 - cnt));
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,668 @@
|
||||
/*!
|
||||
* Basic Javascript Elliptic Curve implementation
|
||||
* Ported loosely from BouncyCastle's Java EC code
|
||||
* Only Fp curves implemented for now
|
||||
*
|
||||
* Copyright Tom Wu, bitaddress.org BSD License.
|
||||
* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
|
||||
*/
|
||||
(function () {
|
||||
|
||||
// Constructor function of Global EllipticCurve object
|
||||
var ec = window.EllipticCurve = function () { };
|
||||
|
||||
|
||||
// ----------------
|
||||
// ECFieldElementFp constructor
|
||||
// q instanceof BigInteger
|
||||
// x instanceof BigInteger
|
||||
ec.FieldElementFp = function (q, x) {
|
||||
this.x = x;
|
||||
// TODO if(x.compareTo(q) >= 0) error
|
||||
this.q = q;
|
||||
};
|
||||
|
||||
ec.FieldElementFp.prototype.equals = function (other) {
|
||||
if (other == this) return true;
|
||||
return (this.q.equals(other.q) && this.x.equals(other.x));
|
||||
};
|
||||
|
||||
ec.FieldElementFp.prototype.toBigInteger = function () {
|
||||
return this.x;
|
||||
};
|
||||
|
||||
ec.FieldElementFp.prototype.negate = function () {
|
||||
return new ec.FieldElementFp(this.q, this.x.negate().mod(this.q));
|
||||
};
|
||||
|
||||
ec.FieldElementFp.prototype.add = function (b) {
|
||||
return new ec.FieldElementFp(this.q, this.x.add(b.toBigInteger()).mod(this.q));
|
||||
};
|
||||
|
||||
ec.FieldElementFp.prototype.subtract = function (b) {
|
||||
return new ec.FieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q));
|
||||
};
|
||||
|
||||
ec.FieldElementFp.prototype.multiply = function (b) {
|
||||
return new ec.FieldElementFp(this.q, this.x.multiply(b.toBigInteger()).mod(this.q));
|
||||
};
|
||||
|
||||
ec.FieldElementFp.prototype.square = function () {
|
||||
return new ec.FieldElementFp(this.q, this.x.square().mod(this.q));
|
||||
};
|
||||
|
||||
ec.FieldElementFp.prototype.divide = function (b) {
|
||||
return new ec.FieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q));
|
||||
};
|
||||
|
||||
ec.FieldElementFp.prototype.getByteLength = function () {
|
||||
return Math.floor((this.toBigInteger().bitLength() + 7) / 8);
|
||||
};
|
||||
|
||||
// D.1.4 91
|
||||
/**
|
||||
* return a sqrt root - the routine verifies that the calculation
|
||||
* returns the right value - if none exists it returns null.
|
||||
*
|
||||
* Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
|
||||
* Ported to JavaScript by bitaddress.org
|
||||
*/
|
||||
ec.FieldElementFp.prototype.sqrt = function () {
|
||||
if (!this.q.testBit(0)) throw new Error("even value of q");
|
||||
|
||||
// p mod 4 == 3
|
||||
if (this.q.testBit(1)) {
|
||||
// z = g^(u+1) + p, p = 4u + 3
|
||||
var z = new ec.FieldElementFp(this.q, this.x.modPow(this.q.shiftRight(2).add(BigInteger.ONE), this.q));
|
||||
return z.square().equals(this) ? z : null;
|
||||
}
|
||||
|
||||
// p mod 4 == 1
|
||||
var qMinusOne = this.q.subtract(BigInteger.ONE);
|
||||
var legendreExponent = qMinusOne.shiftRight(1);
|
||||
if (!(this.x.modPow(legendreExponent, this.q).equals(BigInteger.ONE))) return null;
|
||||
var u = qMinusOne.shiftRight(2);
|
||||
var k = u.shiftLeft(1).add(BigInteger.ONE);
|
||||
var Q = this.x;
|
||||
var fourQ = Q.shiftLeft(2).mod(this.q);
|
||||
var U, V;
|
||||
|
||||
do {
|
||||
var rand = new SecureRandom();
|
||||
var P;
|
||||
do {
|
||||
P = new BigInteger(this.q.bitLength(), rand);
|
||||
}
|
||||
while (P.compareTo(this.q) >= 0 || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, this.q).equals(qMinusOne)));
|
||||
|
||||
var result = ec.FieldElementFp.fastLucasSequence(this.q, P, Q, k);
|
||||
|
||||
U = result[0];
|
||||
V = result[1];
|
||||
if (V.multiply(V).mod(this.q).equals(fourQ)) {
|
||||
// Integer division by 2, mod q
|
||||
if (V.testBit(0)) {
|
||||
V = V.add(this.q);
|
||||
}
|
||||
V = V.shiftRight(1);
|
||||
return new ec.FieldElementFp(this.q, V);
|
||||
}
|
||||
}
|
||||
while (U.equals(BigInteger.ONE) || U.equals(qMinusOne));
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
|
||||
* Ported to JavaScript by bitaddress.org
|
||||
*/
|
||||
ec.FieldElementFp.fastLucasSequence = function (p, P, Q, k) {
|
||||
// TODO Research and apply "common-multiplicand multiplication here"
|
||||
|
||||
var n = k.bitLength();
|
||||
var s = k.getLowestSetBit();
|
||||
var Uh = BigInteger.ONE;
|
||||
var Vl = BigInteger.TWO;
|
||||
var Vh = P;
|
||||
var Ql = BigInteger.ONE;
|
||||
var Qh = BigInteger.ONE;
|
||||
|
||||
for (var j = n - 1; j >= s + 1; --j) {
|
||||
Ql = Ql.multiply(Qh).mod(p);
|
||||
if (k.testBit(j)) {
|
||||
Qh = Ql.multiply(Q).mod(p);
|
||||
Uh = Uh.multiply(Vh).mod(p);
|
||||
Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
|
||||
Vh = Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p);
|
||||
}
|
||||
else {
|
||||
Qh = Ql;
|
||||
Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
|
||||
Vh = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
|
||||
Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
|
||||
}
|
||||
}
|
||||
|
||||
Ql = Ql.multiply(Qh).mod(p);
|
||||
Qh = Ql.multiply(Q).mod(p);
|
||||
Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
|
||||
Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
|
||||
Ql = Ql.multiply(Qh).mod(p);
|
||||
|
||||
for (var j = 1; j <= s; ++j) {
|
||||
Uh = Uh.multiply(Vl).mod(p);
|
||||
Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
|
||||
Ql = Ql.multiply(Ql).mod(p);
|
||||
}
|
||||
|
||||
return [Uh, Vl];
|
||||
};
|
||||
|
||||
// ----------------
|
||||
// ECPointFp constructor
|
||||
ec.PointFp = function (curve, x, y, z, compressed) {
|
||||
this.curve = curve;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
// Projective coordinates: either zinv == null or z * zinv == 1
|
||||
// z and zinv are just BigIntegers, not fieldElements
|
||||
if (z == null) {
|
||||
this.z = BigInteger.ONE;
|
||||
}
|
||||
else {
|
||||
this.z = z;
|
||||
}
|
||||
this.zinv = null;
|
||||
// compression flag
|
||||
this.compressed = !!compressed;
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.getX = function () {
|
||||
if (this.zinv == null) {
|
||||
this.zinv = this.z.modInverse(this.curve.q);
|
||||
}
|
||||
var r = this.x.toBigInteger().multiply(this.zinv);
|
||||
this.curve.reduce(r);
|
||||
return this.curve.fromBigInteger(r);
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.getY = function () {
|
||||
if (this.zinv == null) {
|
||||
this.zinv = this.z.modInverse(this.curve.q);
|
||||
}
|
||||
var r = this.y.toBigInteger().multiply(this.zinv);
|
||||
this.curve.reduce(r);
|
||||
return this.curve.fromBigInteger(r);
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.equals = function (other) {
|
||||
if (other == this) return true;
|
||||
if (this.isInfinity()) return other.isInfinity();
|
||||
if (other.isInfinity()) return this.isInfinity();
|
||||
var u, v;
|
||||
// u = Y2 * Z1 - Y1 * Z2
|
||||
u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q);
|
||||
if (!u.equals(BigInteger.ZERO)) return false;
|
||||
// v = X2 * Z1 - X1 * Z2
|
||||
v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q);
|
||||
return v.equals(BigInteger.ZERO);
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.isInfinity = function () {
|
||||
if ((this.x == null) && (this.y == null)) return true;
|
||||
return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO);
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.negate = function () {
|
||||
return new ec.PointFp(this.curve, this.x, this.y.negate(), this.z);
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.add = function (b) {
|
||||
if (this.isInfinity()) return b;
|
||||
if (b.isInfinity()) return this;
|
||||
|
||||
// u = Y2 * Z1 - Y1 * Z2
|
||||
var u = b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q);
|
||||
// v = X2 * Z1 - X1 * Z2
|
||||
var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);
|
||||
|
||||
|
||||
if (BigInteger.ZERO.equals(v)) {
|
||||
if (BigInteger.ZERO.equals(u)) {
|
||||
return this.twice(); // this == b, so double
|
||||
}
|
||||
return this.curve.getInfinity(); // this = -b, so infinity
|
||||
}
|
||||
|
||||
var THREE = new BigInteger("3");
|
||||
var x1 = this.x.toBigInteger();
|
||||
var y1 = this.y.toBigInteger();
|
||||
var x2 = b.x.toBigInteger();
|
||||
var y2 = b.y.toBigInteger();
|
||||
|
||||
var v2 = v.square();
|
||||
var v3 = v2.multiply(v);
|
||||
var x1v2 = x1.multiply(v2);
|
||||
var zu2 = u.square().multiply(this.z);
|
||||
|
||||
// x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3)
|
||||
var x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q);
|
||||
// y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3
|
||||
var y3 = x1v2.multiply(THREE).multiply(u).subtract(y1.multiply(v3)).subtract(zu2.multiply(u)).multiply(b.z).add(u.multiply(v3)).mod(this.curve.q);
|
||||
// z3 = v^3 * z1 * z2
|
||||
var z3 = v3.multiply(this.z).multiply(b.z).mod(this.curve.q);
|
||||
|
||||
return new ec.PointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.twice = function () {
|
||||
if (this.isInfinity()) return this;
|
||||
if (this.y.toBigInteger().signum() == 0) return this.curve.getInfinity();
|
||||
|
||||
// TODO: optimized handling of constants
|
||||
var THREE = new BigInteger("3");
|
||||
var x1 = this.x.toBigInteger();
|
||||
var y1 = this.y.toBigInteger();
|
||||
|
||||
var y1z1 = y1.multiply(this.z);
|
||||
var y1sqz1 = y1z1.multiply(y1).mod(this.curve.q);
|
||||
var a = this.curve.a.toBigInteger();
|
||||
|
||||
// w = 3 * x1^2 + a * z1^2
|
||||
var w = x1.square().multiply(THREE);
|
||||
if (!BigInteger.ZERO.equals(a)) {
|
||||
w = w.add(this.z.square().multiply(a));
|
||||
}
|
||||
w = w.mod(this.curve.q);
|
||||
//this.curve.reduce(w);
|
||||
// x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
|
||||
var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q);
|
||||
// y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
|
||||
var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q);
|
||||
// z3 = 8 * (y1 * z1)^3
|
||||
var z3 = y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);
|
||||
|
||||
return new ec.PointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
|
||||
};
|
||||
|
||||
// Simple NAF (Non-Adjacent Form) multiplication algorithm
|
||||
// TODO: modularize the multiplication algorithm
|
||||
ec.PointFp.prototype.multiply = function (k) {
|
||||
if (this.isInfinity()) return this;
|
||||
if (k.signum() == 0) return this.curve.getInfinity();
|
||||
|
||||
var e = k;
|
||||
var h = e.multiply(new BigInteger("3"));
|
||||
|
||||
var neg = this.negate();
|
||||
var R = this;
|
||||
|
||||
var i;
|
||||
for (i = h.bitLength() - 2; i > 0; --i) {
|
||||
R = R.twice();
|
||||
|
||||
var hBit = h.testBit(i);
|
||||
var eBit = e.testBit(i);
|
||||
|
||||
if (hBit != eBit) {
|
||||
R = R.add(hBit ? this : neg);
|
||||
}
|
||||
}
|
||||
|
||||
return R;
|
||||
};
|
||||
|
||||
// Compute this*j + x*k (simultaneous multiplication)
|
||||
ec.PointFp.prototype.multiplyTwo = function (j, x, k) {
|
||||
var i;
|
||||
if (j.bitLength() > k.bitLength())
|
||||
i = j.bitLength() - 1;
|
||||
else
|
||||
i = k.bitLength() - 1;
|
||||
|
||||
var R = this.curve.getInfinity();
|
||||
var both = this.add(x);
|
||||
while (i >= 0) {
|
||||
R = R.twice();
|
||||
if (j.testBit(i)) {
|
||||
if (k.testBit(i)) {
|
||||
R = R.add(both);
|
||||
}
|
||||
else {
|
||||
R = R.add(this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (k.testBit(i)) {
|
||||
R = R.add(x);
|
||||
}
|
||||
}
|
||||
--i;
|
||||
}
|
||||
|
||||
return R;
|
||||
};
|
||||
|
||||
// patched by bitaddress.org and Casascius for use with Bitcoin.ECKey
|
||||
// patched by coretechs to support compressed public keys
|
||||
ec.PointFp.prototype.getEncoded = function (compressed) {
|
||||
var x = this.getX().toBigInteger();
|
||||
var y = this.getY().toBigInteger();
|
||||
var len = 32; // integerToBytes will zero pad if integer is less than 32 bytes. 32 bytes length is required by the Bitcoin protocol.
|
||||
var enc = ec.integerToBytes(x, len);
|
||||
|
||||
// when compressed prepend byte depending if y point is even or odd
|
||||
if (compressed) {
|
||||
if (y.isEven()) {
|
||||
enc.unshift(0x02);
|
||||
}
|
||||
else {
|
||||
enc.unshift(0x03);
|
||||
}
|
||||
}
|
||||
else {
|
||||
enc.unshift(0x04);
|
||||
enc = enc.concat(ec.integerToBytes(y, len)); // uncompressed public key appends the bytes of the y point
|
||||
}
|
||||
return enc;
|
||||
};
|
||||
|
||||
ec.PointFp.decodeFrom = function (curve, enc) {
|
||||
var type = enc[0];
|
||||
var dataLen = enc.length - 1;
|
||||
|
||||
// Extract x and y as byte arrays
|
||||
var xBa = enc.slice(1, 1 + dataLen / 2);
|
||||
var yBa = enc.slice(1 + dataLen / 2, 1 + dataLen);
|
||||
|
||||
// Prepend zero byte to prevent interpretation as negative integer
|
||||
xBa.unshift(0);
|
||||
yBa.unshift(0);
|
||||
|
||||
// Convert to BigIntegers
|
||||
var x = new BigInteger(xBa);
|
||||
var y = new BigInteger(yBa);
|
||||
|
||||
// Return point
|
||||
return new ec.PointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y));
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.add2D = function (b) {
|
||||
if (this.isInfinity()) return b;
|
||||
if (b.isInfinity()) return this;
|
||||
|
||||
if (this.x.equals(b.x)) {
|
||||
if (this.y.equals(b.y)) {
|
||||
// this = b, i.e. this must be doubled
|
||||
return this.twice();
|
||||
}
|
||||
// this = -b, i.e. the result is the point at infinity
|
||||
return this.curve.getInfinity();
|
||||
}
|
||||
|
||||
var x_x = b.x.subtract(this.x);
|
||||
var y_y = b.y.subtract(this.y);
|
||||
var gamma = y_y.divide(x_x);
|
||||
|
||||
var x3 = gamma.square().subtract(this.x).subtract(b.x);
|
||||
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
|
||||
|
||||
return new ec.PointFp(this.curve, x3, y3);
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.twice2D = function () {
|
||||
if (this.isInfinity()) return this;
|
||||
if (this.y.toBigInteger().signum() == 0) {
|
||||
// if y1 == 0, then (x1, y1) == (x1, -y1)
|
||||
// and hence this = -this and thus 2(x1, y1) == infinity
|
||||
return this.curve.getInfinity();
|
||||
}
|
||||
|
||||
var TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
|
||||
var THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
|
||||
var gamma = this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO));
|
||||
|
||||
var x3 = gamma.square().subtract(this.x.multiply(TWO));
|
||||
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
|
||||
|
||||
return new ec.PointFp(this.curve, x3, y3);
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.multiply2D = function (k) {
|
||||
if (this.isInfinity()) return this;
|
||||
if (k.signum() == 0) return this.curve.getInfinity();
|
||||
|
||||
var e = k;
|
||||
var h = e.multiply(new BigInteger("3"));
|
||||
|
||||
var neg = this.negate();
|
||||
var R = this;
|
||||
|
||||
var i;
|
||||
for (i = h.bitLength() - 2; i > 0; --i) {
|
||||
R = R.twice();
|
||||
|
||||
var hBit = h.testBit(i);
|
||||
var eBit = e.testBit(i);
|
||||
|
||||
if (hBit != eBit) {
|
||||
R = R.add2D(hBit ? this : neg);
|
||||
}
|
||||
}
|
||||
|
||||
return R;
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.isOnCurve = function () {
|
||||
var x = this.getX().toBigInteger();
|
||||
var y = this.getY().toBigInteger();
|
||||
var a = this.curve.getA().toBigInteger();
|
||||
var b = this.curve.getB().toBigInteger();
|
||||
var n = this.curve.getQ();
|
||||
var lhs = y.multiply(y).mod(n);
|
||||
var rhs = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(n);
|
||||
return lhs.equals(rhs);
|
||||
};
|
||||
|
||||
ec.PointFp.prototype.toString = function () {
|
||||
return '(' + this.getX().toBigInteger().toString() + ',' + this.getY().toBigInteger().toString() + ')';
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate an elliptic curve point.
|
||||
*
|
||||
* See SEC 1, section 3.2.2.1: Elliptic Curve Public Key Validation Primitive
|
||||
*/
|
||||
ec.PointFp.prototype.validate = function () {
|
||||
var n = this.curve.getQ();
|
||||
|
||||
// Check Q != O
|
||||
if (this.isInfinity()) {
|
||||
throw new Error("Point is at infinity.");
|
||||
}
|
||||
|
||||
// Check coordinate bounds
|
||||
var x = this.getX().toBigInteger();
|
||||
var y = this.getY().toBigInteger();
|
||||
if (x.compareTo(BigInteger.ONE) < 0 || x.compareTo(n.subtract(BigInteger.ONE)) > 0) {
|
||||
throw new Error('x coordinate out of bounds');
|
||||
}
|
||||
if (y.compareTo(BigInteger.ONE) < 0 || y.compareTo(n.subtract(BigInteger.ONE)) > 0) {
|
||||
throw new Error('y coordinate out of bounds');
|
||||
}
|
||||
|
||||
// Check y^2 = x^3 + ax + b (mod n)
|
||||
if (!this.isOnCurve()) {
|
||||
throw new Error("Point is not on the curve.");
|
||||
}
|
||||
|
||||
// Check nQ = 0 (Q is a scalar multiple of G)
|
||||
if (this.multiply(n).isInfinity()) {
|
||||
// TODO: This check doesn't work - fix.
|
||||
throw new Error("Point is not a scalar multiple of G.");
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// ----------------
|
||||
// ECCurveFp constructor
|
||||
ec.CurveFp = function (q, a, b) {
|
||||
this.q = q;
|
||||
this.a = this.fromBigInteger(a);
|
||||
this.b = this.fromBigInteger(b);
|
||||
this.infinity = new ec.PointFp(this, null, null);
|
||||
this.reducer = new Barrett(this.q);
|
||||
}
|
||||
|
||||
ec.CurveFp.prototype.getQ = function () {
|
||||
return this.q;
|
||||
};
|
||||
|
||||
ec.CurveFp.prototype.getA = function () {
|
||||
return this.a;
|
||||
};
|
||||
|
||||
ec.CurveFp.prototype.getB = function () {
|
||||
return this.b;
|
||||
};
|
||||
|
||||
ec.CurveFp.prototype.equals = function (other) {
|
||||
if (other == this) return true;
|
||||
return (this.q.equals(other.q) && this.a.equals(other.a) && this.b.equals(other.b));
|
||||
};
|
||||
|
||||
ec.CurveFp.prototype.getInfinity = function () {
|
||||
return this.infinity;
|
||||
};
|
||||
|
||||
ec.CurveFp.prototype.fromBigInteger = function (x) {
|
||||
return new ec.FieldElementFp(this.q, x);
|
||||
};
|
||||
|
||||
ec.CurveFp.prototype.reduce = function (x) {
|
||||
this.reducer.reduce(x);
|
||||
};
|
||||
|
||||
// for now, work with hex strings because they're easier in JS
|
||||
// compressed support added by bitaddress.org
|
||||
ec.CurveFp.prototype.decodePointHex = function (s) {
|
||||
var firstByte = parseInt(s.substr(0, 2), 16);
|
||||
switch (firstByte) { // first byte
|
||||
case 0:
|
||||
return this.infinity;
|
||||
case 2: // compressed
|
||||
case 3: // compressed
|
||||
var yTilde = firstByte & 1;
|
||||
var xHex = s.substr(2, s.length - 2);
|
||||
var X1 = new BigInteger(xHex, 16);
|
||||
return this.decompressPoint(yTilde, X1);
|
||||
case 4: // uncompressed
|
||||
case 6: // hybrid
|
||||
case 7: // hybrid
|
||||
var len = (s.length - 2) / 2;
|
||||
var xHex = s.substr(2, len);
|
||||
var yHex = s.substr(len + 2, len);
|
||||
|
||||
return new ec.PointFp(this,
|
||||
this.fromBigInteger(new BigInteger(xHex, 16)),
|
||||
this.fromBigInteger(new BigInteger(yHex, 16)));
|
||||
|
||||
default: // unsupported
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
ec.CurveFp.prototype.encodePointHex = function (p) {
|
||||
if (p.isInfinity()) return "00";
|
||||
var xHex = p.getX().toBigInteger().toString(16);
|
||||
var yHex = p.getY().toBigInteger().toString(16);
|
||||
var oLen = this.getQ().toString(16).length;
|
||||
if ((oLen % 2) != 0) oLen++;
|
||||
while (xHex.length < oLen) {
|
||||
xHex = "0" + xHex;
|
||||
}
|
||||
while (yHex.length < oLen) {
|
||||
yHex = "0" + yHex;
|
||||
}
|
||||
return "04" + xHex + yHex;
|
||||
};
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
|
||||
* Ported to JavaScript by bitaddress.org
|
||||
*
|
||||
* Number yTilde
|
||||
* BigInteger X1
|
||||
*/
|
||||
ec.CurveFp.prototype.decompressPoint = function (yTilde, X1) {
|
||||
var x = this.fromBigInteger(X1);
|
||||
var alpha = x.multiply(x.square().add(this.getA())).add(this.getB());
|
||||
var beta = alpha.sqrt();
|
||||
// if we can't find a sqrt we haven't got a point on the curve - run!
|
||||
if (beta == null) throw new Error("Invalid point compression");
|
||||
var betaValue = beta.toBigInteger();
|
||||
var bit0 = betaValue.testBit(0) ? 1 : 0;
|
||||
if (bit0 != yTilde) {
|
||||
// Use the other root
|
||||
beta = this.fromBigInteger(this.getQ().subtract(betaValue));
|
||||
}
|
||||
return new ec.PointFp(this, x, beta, null, true);
|
||||
};
|
||||
|
||||
|
||||
ec.fromHex = function (s) { return new BigInteger(s, 16); };
|
||||
|
||||
ec.integerToBytes = function (i, len) {
|
||||
var bytes = i.toByteArrayUnsigned();
|
||||
if (len < bytes.length) {
|
||||
bytes = bytes.slice(bytes.length - len);
|
||||
} else while (len > bytes.length) {
|
||||
bytes.unshift(0);
|
||||
}
|
||||
return bytes;
|
||||
};
|
||||
|
||||
|
||||
// Named EC curves
|
||||
// ----------------
|
||||
// X9ECParameters constructor
|
||||
ec.X9Parameters = function (curve, g, n, h) {
|
||||
this.curve = curve;
|
||||
this.g = g;
|
||||
this.n = n;
|
||||
this.h = h;
|
||||
}
|
||||
ec.X9Parameters.prototype.getCurve = function () { return this.curve; };
|
||||
ec.X9Parameters.prototype.getG = function () { return this.g; };
|
||||
ec.X9Parameters.prototype.getN = function () { return this.n; };
|
||||
ec.X9Parameters.prototype.getH = function () { return this.h; };
|
||||
|
||||
// secp256k1 is the Curve used by Bitcoin
|
||||
ec.secNamedCurves = {
|
||||
// used by Bitcoin
|
||||
"secp256k1": function () {
|
||||
// p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
|
||||
var p = ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
|
||||
var a = BigInteger.ZERO;
|
||||
var b = ec.fromHex("7");
|
||||
var n = ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
|
||||
var h = BigInteger.ONE;
|
||||
var curve = new ec.CurveFp(p, a, b);
|
||||
var G = curve.decodePointHex("04"
|
||||
+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
|
||||
+ "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8");
|
||||
return new ec.X9Parameters(curve, G, n, h);
|
||||
}
|
||||
};
|
||||
|
||||
// secp256k1 called by Bitcoin's ECKEY
|
||||
ec.getSECCurveByName = function (name) {
|
||||
if (ec.secNamedCurves[name] == undefined) return null;
|
||||
return ec.secNamedCurves[name]();
|
||||
}
|
||||
})();
|
||||
Vendored
+5
File diff suppressed because one or more lines are too long
Vendored
+4
File diff suppressed because one or more lines are too long
+1298
File diff suppressed because it is too large
Load Diff
+195
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
CryptoJS v3.1.2
|
||||
code.google.com/p/crypto-js
|
||||
(c) 2009-2013 by Jeff Mott. All rights reserved.
|
||||
code.google.com/p/crypto-js/wiki/License
|
||||
*/
|
||||
/** @preserve
|
||||
(c) 2012 by Cédric Mesnil. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Constants table
|
||||
var zl = [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
|
||||
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
|
||||
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
|
||||
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13];
|
||||
var zr = [
|
||||
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
|
||||
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
|
||||
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
|
||||
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
|
||||
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11];
|
||||
var sl = [
|
||||
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
|
||||
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
|
||||
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
|
||||
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
|
||||
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 ];
|
||||
var sr = [
|
||||
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
|
||||
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
|
||||
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
|
||||
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
|
||||
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 ];
|
||||
|
||||
var hl = [ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E];
|
||||
var hr = [ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000];
|
||||
|
||||
var bytesToWords = function (bytes) {
|
||||
var words = [];
|
||||
for (var i = 0, b = 0; i < bytes.length; i++, b += 8) {
|
||||
words[b >>> 5] |= bytes[i] << (24 - b % 32);
|
||||
}
|
||||
return words;
|
||||
};
|
||||
|
||||
var wordsToBytes = function (words) {
|
||||
var bytes = [];
|
||||
for (var b = 0; b < words.length * 32; b += 8) {
|
||||
bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
|
||||
}
|
||||
return bytes;
|
||||
};
|
||||
|
||||
var processBlock = function (H, M, offset) {
|
||||
|
||||
// Swap endian
|
||||
for (var i = 0; i < 16; i++) {
|
||||
var offset_i = offset + i;
|
||||
var M_offset_i = M[offset_i];
|
||||
|
||||
// Swap
|
||||
M[offset_i] = (
|
||||
(((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) |
|
||||
(((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00)
|
||||
);
|
||||
}
|
||||
|
||||
// Working variables
|
||||
var al, bl, cl, dl, el;
|
||||
var ar, br, cr, dr, er;
|
||||
|
||||
ar = al = H[0];
|
||||
br = bl = H[1];
|
||||
cr = cl = H[2];
|
||||
dr = dl = H[3];
|
||||
er = el = H[4];
|
||||
// Computation
|
||||
var t;
|
||||
for (var i = 0; i < 80; i += 1) {
|
||||
t = (al + M[offset+zl[i]])|0;
|
||||
if (i<16){
|
||||
t += f1(bl,cl,dl) + hl[0];
|
||||
} else if (i<32) {
|
||||
t += f2(bl,cl,dl) + hl[1];
|
||||
} else if (i<48) {
|
||||
t += f3(bl,cl,dl) + hl[2];
|
||||
} else if (i<64) {
|
||||
t += f4(bl,cl,dl) + hl[3];
|
||||
} else {// if (i<80) {
|
||||
t += f5(bl,cl,dl) + hl[4];
|
||||
}
|
||||
t = t|0;
|
||||
t = rotl(t,sl[i]);
|
||||
t = (t+el)|0;
|
||||
al = el;
|
||||
el = dl;
|
||||
dl = rotl(cl, 10);
|
||||
cl = bl;
|
||||
bl = t;
|
||||
|
||||
t = (ar + M[offset+zr[i]])|0;
|
||||
if (i<16){
|
||||
t += f5(br,cr,dr) + hr[0];
|
||||
} else if (i<32) {
|
||||
t += f4(br,cr,dr) + hr[1];
|
||||
} else if (i<48) {
|
||||
t += f3(br,cr,dr) + hr[2];
|
||||
} else if (i<64) {
|
||||
t += f2(br,cr,dr) + hr[3];
|
||||
} else {// if (i<80) {
|
||||
t += f1(br,cr,dr) + hr[4];
|
||||
}
|
||||
t = t|0;
|
||||
t = rotl(t,sr[i]) ;
|
||||
t = (t+er)|0;
|
||||
ar = er;
|
||||
er = dr;
|
||||
dr = rotl(cr, 10);
|
||||
cr = br;
|
||||
br = t;
|
||||
}
|
||||
// Intermediate hash value
|
||||
t = (H[1] + cl + dr)|0;
|
||||
H[1] = (H[2] + dl + er)|0;
|
||||
H[2] = (H[3] + el + ar)|0;
|
||||
H[3] = (H[4] + al + br)|0;
|
||||
H[4] = (H[0] + bl + cr)|0;
|
||||
H[0] = t;
|
||||
};
|
||||
|
||||
function f1(x, y, z) {
|
||||
return ((x) ^ (y) ^ (z));
|
||||
}
|
||||
|
||||
function f2(x, y, z) {
|
||||
return (((x)&(y)) | ((~x)&(z)));
|
||||
}
|
||||
|
||||
function f3(x, y, z) {
|
||||
return (((x) | (~(y))) ^ (z));
|
||||
}
|
||||
|
||||
function f4(x, y, z) {
|
||||
return (((x) & (z)) | ((y)&(~(z))));
|
||||
}
|
||||
|
||||
function f5(x, y, z) {
|
||||
return ((x) ^ ((y) |(~(z))));
|
||||
}
|
||||
|
||||
function rotl(x,n) {
|
||||
return (x<<n) | (x>>>(32-n));
|
||||
}
|
||||
|
||||
function ripemd160(message) {
|
||||
var H = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
|
||||
|
||||
var m = bytesToWords(message);
|
||||
|
||||
var nBitsLeft = message.length * 8;
|
||||
var nBitsTotal = message.length * 8;
|
||||
|
||||
// Add padding
|
||||
m[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
|
||||
m[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
|
||||
(((nBitsTotal << 8) | (nBitsTotal >>> 24)) & 0x00ff00ff) |
|
||||
(((nBitsTotal << 24) | (nBitsTotal >>> 8)) & 0xff00ff00)
|
||||
);
|
||||
|
||||
for (var i=0 ; i<m.length; i += 16) {
|
||||
processBlock(H, m, i);
|
||||
}
|
||||
|
||||
// Swap endian
|
||||
for (var i = 0; i < 5; i++) {
|
||||
// Shortcut
|
||||
var H_i = H[i];
|
||||
|
||||
// Swap
|
||||
H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) |
|
||||
(((H_i << 24) | (H_i >>> 8)) & 0xff00ff00);
|
||||
}
|
||||
|
||||
var digestbytes = wordsToBytes(H);
|
||||
return digestbytes;
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*!
|
||||
* Random number generator with ArcFour PRNG
|
||||
*
|
||||
* NOTE: For best results, put code like
|
||||
* <body onclick='SecureRandom.seedTime();' onkeypress='SecureRandom.seedTime();'>
|
||||
* in your main HTML document.
|
||||
*
|
||||
* Copyright Tom Wu, bitaddress.org BSD License.
|
||||
* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE
|
||||
*/
|
||||
(function () {
|
||||
|
||||
// Constructor function of Global SecureRandom object
|
||||
var sr = window.SecureRandom = function () { };
|
||||
|
||||
// Properties
|
||||
sr.state;
|
||||
sr.pool;
|
||||
sr.pptr;
|
||||
sr.poolCopyOnInit;
|
||||
|
||||
// Pool size must be a multiple of 4 and greater than 32.
|
||||
// An array of bytes the size of the pool will be passed to init()
|
||||
sr.poolSize = 256;
|
||||
|
||||
// --- object methods ---
|
||||
|
||||
// public method
|
||||
// ba: byte array
|
||||
sr.prototype.nextBytes = function (ba) {
|
||||
var i;
|
||||
if (window.crypto && window.crypto.getRandomValues && window.Uint8Array) {
|
||||
try {
|
||||
var rvBytes = new Uint8Array(ba.length);
|
||||
window.crypto.getRandomValues(rvBytes);
|
||||
for (i = 0; i < ba.length; ++i)
|
||||
ba[i] = sr.getByte() ^ rvBytes[i];
|
||||
return;
|
||||
} catch (e) {
|
||||
alert(e);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ba.length; ++i) ba[i] = sr.getByte();
|
||||
};
|
||||
|
||||
|
||||
// --- static methods ---
|
||||
|
||||
// Mix in the current time (w/milliseconds) into the pool
|
||||
// NOTE: this method should be called from body click/keypress event handlers to increase entropy
|
||||
sr.seedTime = function () {
|
||||
sr.seedInt(new Date().getTime());
|
||||
}
|
||||
|
||||
sr.getByte = function () {
|
||||
if (sr.state == null) {
|
||||
sr.seedTime();
|
||||
sr.state = sr.ArcFour(); // Plug in your RNG constructor here
|
||||
sr.state.init(sr.pool);
|
||||
sr.poolCopyOnInit = [];
|
||||
for (sr.pptr = 0; sr.pptr < sr.pool.length; ++sr.pptr)
|
||||
sr.poolCopyOnInit[sr.pptr] = sr.pool[sr.pptr];
|
||||
sr.pptr = 0;
|
||||
}
|
||||
// TODO: allow reseeding after first request
|
||||
return sr.state.next();
|
||||
}
|
||||
|
||||
// Mix in a 32-bit integer into the pool
|
||||
sr.seedInt = function (x) {
|
||||
sr.seedInt8(x);
|
||||
sr.seedInt8((x >> 8));
|
||||
sr.seedInt8((x >> 16));
|
||||
sr.seedInt8((x >> 24));
|
||||
}
|
||||
|
||||
// Mix in a 16-bit integer into the pool
|
||||
sr.seedInt16 = function (x) {
|
||||
sr.seedInt8(x);
|
||||
sr.seedInt8((x >> 8));
|
||||
}
|
||||
|
||||
// Mix in a 8-bit integer into the pool
|
||||
sr.seedInt8 = function (x) {
|
||||
sr.pool[sr.pptr++] ^= x & 255;
|
||||
if (sr.pptr >= sr.poolSize) sr.pptr -= sr.poolSize;
|
||||
}
|
||||
|
||||
// Arcfour is a PRNG
|
||||
sr.ArcFour = function () {
|
||||
function Arcfour() {
|
||||
this.i = 0;
|
||||
this.j = 0;
|
||||
this.S = new Array();
|
||||
}
|
||||
|
||||
// Initialize arcfour context from key, an array of ints, each from [0..255]
|
||||
function ARC4init(key) {
|
||||
var i, j, t;
|
||||
for (i = 0; i < 256; ++i)
|
||||
this.S[i] = i;
|
||||
j = 0;
|
||||
for (i = 0; i < 256; ++i) {
|
||||
j = (j + this.S[i] + key[i % key.length]) & 255;
|
||||
t = this.S[i];
|
||||
this.S[i] = this.S[j];
|
||||
this.S[j] = t;
|
||||
}
|
||||
this.i = 0;
|
||||
this.j = 0;
|
||||
}
|
||||
|
||||
function ARC4next() {
|
||||
var t;
|
||||
this.i = (this.i + 1) & 255;
|
||||
this.j = (this.j + this.S[this.i]) & 255;
|
||||
t = this.S[this.i];
|
||||
this.S[this.i] = this.S[this.j];
|
||||
this.S[this.j] = t;
|
||||
return this.S[(t + this.S[this.i]) & 255];
|
||||
}
|
||||
|
||||
Arcfour.prototype.init = ARC4init;
|
||||
Arcfour.prototype.next = ARC4next;
|
||||
|
||||
return new Arcfour();
|
||||
};
|
||||
|
||||
|
||||
// Initialize the pool with junk if needed.
|
||||
if (sr.pool == null) {
|
||||
sr.pool = new Array();
|
||||
sr.pptr = 0;
|
||||
var t;
|
||||
if (window.crypto && window.crypto.getRandomValues && window.Uint8Array) {
|
||||
try {
|
||||
// Use webcrypto if available
|
||||
var ua = new Uint8Array(sr.poolSize);
|
||||
window.crypto.getRandomValues(ua);
|
||||
for (t = 0; t < sr.poolSize; ++t)
|
||||
sr.pool[sr.pptr++] = ua[t];
|
||||
} catch (e) { alert(e); }
|
||||
}
|
||||
while (sr.pptr < sr.poolSize) { // extract some randomness from Math.random()
|
||||
t = Math.floor(65536 * Math.random());
|
||||
sr.pool[sr.pptr++] = t >>> 8;
|
||||
sr.pool[sr.pptr++] = t & 255;
|
||||
}
|
||||
sr.pptr = Math.floor(sr.poolSize * Math.random());
|
||||
sr.seedTime();
|
||||
// entropy
|
||||
var entropyStr = "";
|
||||
// screen size and color depth: ~4.8 to ~5.4 bits
|
||||
entropyStr += (window.screen.height * window.screen.width * window.screen.colorDepth);
|
||||
entropyStr += (window.screen.availHeight * window.screen.availWidth * window.screen.pixelDepth);
|
||||
// time zone offset: ~4 bits
|
||||
var dateObj = new Date();
|
||||
var timeZoneOffset = dateObj.getTimezoneOffset();
|
||||
entropyStr += timeZoneOffset;
|
||||
// user agent: ~8.3 to ~11.6 bits
|
||||
entropyStr += navigator.userAgent;
|
||||
// browser plugin details: ~16.2 to ~21.8 bits
|
||||
var pluginsStr = "";
|
||||
for (var i = 0; i < navigator.plugins.length; i++) {
|
||||
pluginsStr += navigator.plugins[i].name + " " + navigator.plugins[i].filename + " " + navigator.plugins[i].description + " " + navigator.plugins[i].version + ", ";
|
||||
}
|
||||
var mimeTypesStr = "";
|
||||
for (var i = 0; i < navigator.mimeTypes.length; i++) {
|
||||
mimeTypesStr += navigator.mimeTypes[i].description + " " + navigator.mimeTypes[i].type + " " + navigator.mimeTypes[i].suffixes + ", ";
|
||||
}
|
||||
entropyStr += pluginsStr + mimeTypesStr;
|
||||
// cookies and storage: 1 bit
|
||||
entropyStr += navigator.cookieEnabled + typeof (sessionStorage) + typeof (localStorage);
|
||||
// language: ~7 bit
|
||||
entropyStr += navigator.language;
|
||||
// history: ~2 bit
|
||||
entropyStr += window.history.length;
|
||||
// location
|
||||
entropyStr += window.location;
|
||||
|
||||
var entropyBytes = Crypto.SHA256(entropyStr, { asBytes: true });
|
||||
for (var i = 0 ; i < entropyBytes.length ; i++) {
|
||||
sr.seedInt8(entropyBytes[i]);
|
||||
}
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user