Kyle Drake
11 years ago
50 changed files with 4561 additions and 5454 deletions
@ -0,0 +1,6 @@ |
|||||
|
language: node_js |
||||
|
node_js: |
||||
|
- "0.11" |
||||
|
- "0.10" |
||||
|
- "0.8" |
||||
|
- "0.6" |
@ -1,53 +0,0 @@ |
|||||
var pkginfo = require('pkginfo')(module); |
|
||||
var minify = require('jake-uglify').minify; |
|
||||
|
|
||||
var headerJS = "\ |
|
||||
/**\n\ |
|
||||
* BitcoinJS-lib v"+exports.version+"-default\n\ |
|
||||
* Copyright (c) 2011 BitcoinJS Project\n\ |
|
||||
* \n\ |
|
||||
* This program is free software; you can redistribute it and/or modify\n\ |
|
||||
* it under the terms of the MIT license.\n\ |
|
||||
*/"; |
|
||||
|
|
||||
task({'default': [ |
|
||||
'build/bitcoinjs-min.js', |
|
||||
'build/bitcoinjs-exit-min.js' |
|
||||
]}); |
|
||||
|
|
||||
desc('General-purpose build containing most features'); |
|
||||
minify({'build/bitcoinjs-min.js': [ |
|
||||
'src/crypto-js/crypto.js', |
|
||||
'src/crypto-js/sha256.js', |
|
||||
'src/crypto-js/ripemd160.js', |
|
||||
'src/jsbn/prng4.js', |
|
||||
'src/jsbn/rng.js', |
|
||||
'src/jsbn/jsbn.js', |
|
||||
'src/jsbn/jsbn2.js', |
|
||||
|
|
||||
'src/jsbn/ec.js', |
|
||||
'src/jsbn/sec.js', |
|
||||
'src/events/eventemitter.js', |
|
||||
'src/bitcoin.js', |
|
||||
'src/util.js', |
|
||||
'src/base58.js', |
|
||||
|
|
||||
'src/address.js', |
|
||||
'src/ecdsa.js', |
|
||||
'src/eckey.js', |
|
||||
'src/opcode.js', |
|
||||
'src/script.js', |
|
||||
'src/transaction.js', |
|
||||
|
|
||||
'src/wallet.js', |
|
||||
'src/txdb.js' |
|
||||
]}, { |
|
||||
header: headerJS |
|
||||
}); |
|
||||
|
|
||||
desc('Exit node client implementation'); |
|
||||
minify({'build/bitcoinjs-exit-min.js': [ |
|
||||
'src/exit/client.js' |
|
||||
]}, { |
|
||||
header: headerJS |
|
||||
}); |
|
File diff suppressed because one or more lines are too long
@ -1,8 +0,0 @@ |
|||||
/** |
|
||||
* BitcoinJS-lib v0.1.0-default |
|
||||
* Copyright (c) 2011 BitcoinJS Project |
|
||||
* |
|
||||
* This program is free software; you can redistribute it and/or modify |
|
||||
* it under the terms of the MIT license. |
|
||||
*/ |
|
||||
(function(a,b,c,d,e){function f(a,b,c){this.setUri(a,b,c),this.unique=1,this.connected=!1,this.callbacks=[]}a.ExitNode=f,b.EventEmitter.augment(f),f.prototype.setUri=function(a,b,c){this.uri=(c?"https://":"http://")+a+":"+b},f.prototype.connect=function(a){this.wallet=a,delete c.sockets[this.uri],c.j=[],this.socket=c.connect(this.uri),this.socket.on("connect",d.proxy(this.handleConnect,this)),this.socket.on("error",function(){console.log("error, test")}),this.socket.on("message",d.proxy(this.handleMessage,this)),this.socket.on("disconnect",d.proxy(this.handleDisconnect,this))},f.prototype.disconnect=function(){this.socket&&(this.socket.disconnect(),this.socket=null,this.connected=!1),this.trigger("connectStatus",{status:"unknown"})},f.prototype.call=function(a,b,c){this.socket.send(d.toJSON({method:a,params:[b],id:this.unique})),c&&(this.callbacks[this.unique]=c),this.unique++},f.prototype.handleConnect=function(){var a=this;this.connected=!0},f.prototype.listen=function(a){self.call("pubkeysRegister",{keys:a.join(",")},function(a,b){if(a){console.error("Could not register public keys");return}self.call("pubkeysListen",{handle:b.handle},function(a,b){self.trigger("blockInit",{height:b.height}),self.trigger("txData",{confirmed:!0,txs:b.txs}),self.trigger("connectStatus",{status:"ok"})}),self.call("pubkeysUnconfirmed",{handle:b.handle},function(a,b){self.trigger("txData",{confirmed:!1,txs:b.txs})})})},f.prototype.handleMessage=function(a){"undefined"!=typeof a.result&&"function"==typeof this.callbacks[a.id]?this.callbacks[a.id](a.error,a.result):"undefined"!=typeof a.method&&this.trigger(a.method,a.params[0])},f.prototype.handleDisconnect=function(){},f.prototype.query=function(a,b,c,e){"function"==typeof c&&(e=c,c=!1),b=b||{},e="function"==typeof e?e:function(){};var f=this.uri+"/"+a;c&&(f+="?callback=?"),d.getJSON(f,b,e)}})("undefined"!=typeof Bitcoin?Bitcoin:module.exports,"undefined"!=typeof Bitcoin?Bitcoin:require("bitcoinjs-lib"),"undefined"!=typeof io?io:require("io"),jQuery,this) |
|
File diff suppressed because one or more lines are too long
@ -1,175 +0,0 @@ |
|||||
(function (exports) { |
|
||||
var Bitcoin = exports; |
|
||||
|
|
||||
if ('object' !== typeof module) { |
|
||||
Bitcoin.EventEmitter = EventEmitter; |
|
||||
} |
|
||||
})( |
|
||||
'object' === typeof module ? module.exports : (window.Bitcoin = {}) |
|
||||
); |
|
||||
|
|
||||
/* |
|
||||
function makeKeypair() |
|
||||
{ |
|
||||
// Generate private key
|
|
||||
var n = ecparams.getN(); |
|
||||
var n1 = n.subtract(BigInteger.ONE); |
|
||||
var r = new BigInteger(n.bitLength(), rng); |
|
||||
|
|
||||
var privateKey = r.mod(n1).add(BigInteger.ONE); |
|
||||
|
|
||||
// Generate public key
|
|
||||
var G = ecparams.getG(); |
|
||||
var publicPoint = G.multiply(privateKey); |
|
||||
|
|
||||
return {priv: privateKey, pubkey: publicPoint}; |
|
||||
}; |
|
||||
|
|
||||
function serializeTransaction(tx) |
|
||||
{ |
|
||||
var buffer = []; |
|
||||
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(tx.version)])); |
|
||||
buffer = buffer.concat(numToVarInt(tx.ins.length)); |
|
||||
for (var i = 0; i < tx.ins.length; i++) { |
|
||||
var txin = tx.ins[i]; |
|
||||
buffer = buffer.concat(Crypto.util.base64ToBytes(txin.outpoint.hash)); |
|
||||
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.index)])); |
|
||||
var scriptBytes = Crypto.util.base64ToBytes(txin.script); |
|
||||
buffer = buffer.concat(numToVarInt(scriptBytes.length)); |
|
||||
buffer = buffer.concat(scriptBytes); |
|
||||
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.sequence)])); |
|
||||
} |
|
||||
buffer = buffer.concat(numToVarInt(tx.outs.length)); |
|
||||
for (var i = 0; i < tx.outs.length; i++) { |
|
||||
var txout = tx.outs[i]; |
|
||||
var valueHex = (new BigInteger(txout.value, 10)).toString(16); |
|
||||
while (valueHex.length < 16) valueHex = "0" + valueHex; |
|
||||
buffer = buffer.concat(Crypto.util.hexToBytes(valueHex)); |
|
||||
var scriptBytes = Crypto.util.base64ToBytes(txout.script); |
|
||||
buffer = buffer.concat(numToVarInt(scriptBytes.length)); |
|
||||
buffer = buffer.concat(scriptBytes); |
|
||||
} |
|
||||
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(tx.lock_time)])); |
|
||||
|
|
||||
return buffer; |
|
||||
}; |
|
||||
|
|
||||
var OP_CODESEPARATOR = 171; |
|
||||
|
|
||||
var SIGHASH_ALL = 1; |
|
||||
var SIGHASH_NONE = 2; |
|
||||
var SIGHASH_SINGLE = 3; |
|
||||
var SIGHASH_ANYONECANPAY = 80; |
|
||||
|
|
||||
function hashTransactionForSignature(scriptCode, tx, inIndex, hashType) |
|
||||
{ |
|
||||
// TODO: We need to actually deep copy here
|
|
||||
var txTmp = tx; |
|
||||
|
|
||||
// In case concatenating two scripts ends up with two codeseparators,
|
|
||||
// or an extra one at the end, this prevents all those possible incompatibilities.
|
|
||||
scriptCode = scriptCode.filter(function (val) { |
|
||||
return val !== OP_CODESEPARATOR; |
|
||||
}); |
|
||||
|
|
||||
// Blank out other inputs' signatures
|
|
||||
for (var i = 0; i < txTmp.ins.length; i++) { |
|
||||
txTmp.ins[i].script = Crypto.util.bytesToBase64([]); |
|
||||
} |
|
||||
txTmp.ins[inIndex].script = Crypto.util.bytesToBase64(scriptCode); |
|
||||
|
|
||||
// Blank out some of the outputs
|
|
||||
if ((hashType & 0x1f) == SIGHASH_NONE) { |
|
||||
txTmp.outs = []; |
|
||||
|
|
||||
// Let the others update at will
|
|
||||
for (var i = 0; i < txTmp.ins.length; i++) |
|
||||
if (i != inIndex) |
|
||||
txTmp.ins[i].sequence = 0; |
|
||||
} else if ((hashType & 0x1f) == SIGHASH_SINGLE) { |
|
||||
// TODO: Implement
|
|
||||
} |
|
||||
|
|
||||
// Blank out other inputs completely, not recommended for open transactions
|
|
||||
if (hashType & SIGHASH_ANYONECANPAY) { |
|
||||
txTmp.ins = [txTmp.ins[inIndex]]; |
|
||||
} |
|
||||
|
|
||||
var buffer = serializeTransaction(txTmp); |
|
||||
|
|
||||
buffer.concat(Crypto.util.wordsToBytes([parseInt(hashType)])); |
|
||||
|
|
||||
console.log(buffer); |
|
||||
|
|
||||
return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true}); |
|
||||
}; |
|
||||
|
|
||||
function verifyTransactionSignature(tx) { |
|
||||
var hash = hashTransactionForSignature([], tx, 0, 0); |
|
||||
return Crypto.util.bytesToHex(hash); |
|
||||
}; |
|
||||
|
|
||||
function numToVarInt(i) |
|
||||
{ |
|
||||
// TODO: THIS IS TOTALLY UNTESTED!
|
|
||||
if (i < 0xfd) { |
|
||||
// unsigned char
|
|
||||
return [i]; |
|
||||
} else if (i <= 1<<16) { |
|
||||
// unsigned short (LE)
|
|
||||
return [0xfd, i >>> 8, i & 255]; |
|
||||
} else if (i <= 1<<32) { |
|
||||
// unsigned int (LE)
|
|
||||
return [0xfe].concat(Crypto.util.wordsToBytes([i])); |
|
||||
} else { |
|
||||
// unsigned long long (LE)
|
|
||||
return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i])); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
var testTx = { |
|
||||
"version":"1", |
|
||||
"lock_time":"0", |
|
||||
"block": { |
|
||||
"hash":"N/A", |
|
||||
"height":115806 |
|
||||
}, |
|
||||
"index":6, |
|
||||
"hash":"WUFzjKubG1kqfJWMb4qZdlhU2F3l5NGXN7AUg8Jwl14=", |
|
||||
"ins":[{ |
|
||||
"outpoint":{ |
|
||||
"hash":"nqcbMM1oRhfLdZga11q7x0CpUMujm+vtxHXO9V0gnwE=", |
|
||||
"index":0 |
|
||||
}, |
|
||||
"script":"RzBEAiB2XXkx1pca9SlfCmCGNUVf+h2sAFBttcxG1VnypIcvEgIgXrOp7LSdYBYp3nPsQAz8BOLD3K4pAlXfZImP1rkzk2EBQQRi7NcODzNfnVqLtG79Axp5UF6EhFIhCmzqKqssfKpfCIOmzCuXEeDFUFvFzeGLJx5N+wp2qRS1TqYezGD3yERk", |
|
||||
"sequence":4294967295 |
|
||||
}], |
|
||||
"outs":[{ |
|
||||
"value":"3000000000", |
|
||||
"script":"dqkUBLZwqhAPRVgZvwI8MN5gLHbU8NOIrA==" |
|
||||
},{ |
|
||||
"value":"25937000000", |
|
||||
"script":"dqkUQ82gJ0O5vOBg6yK5/yorLLV5zLKIrA==" |
|
||||
}] |
|
||||
}; |
|
||||
|
|
||||
TODO: Make this stuff into test cases ;) |
|
||||
$(function () { |
|
||||
var key = new Bitcoin.ECKey(Crypto.util.hexToBytes("5c0b98e524ad188ddef35dc6abba13c34a351a05409e5d285403718b93336a4a")); |
|
||||
key = new Bitcoin.ECKey(Crypto.util.hexToBytes("180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19")); |
|
||||
//console.log(key.getBitcoinAddress().toString());
|
|
||||
//var message = Crypto.util.hexToBytes("2aec28d323ee7b06a799d540d224b351161fe48967174ca5e43164e86137da11");
|
|
||||
//message = [0];
|
|
||||
//var out = key.sign(message);
|
|
||||
//console.log("pubkey: "+Crypto.util.bytesToHex(key.getPub()));
|
|
||||
//console.log("sig: "+Crypto.util.bytesToHex(out));
|
|
||||
|
|
||||
//console.log(key.verify(message, out));
|
|
||||
|
|
||||
//console.log(Bitcoin.ECDSA.verify(message, Crypto.util.hexToBytes("3046022100dffbc26774fc841bbe1c1362fd643609c6e42dcb274763476d87af2c0597e89e022100c59e3c13b96b316cae9fa0ab0260612c7a133a6fe2b3445b6bf80b3123bf274d"), Crypto.util.hexToBytes("0401de173aa944eacf7e44e5073baca93fb34fe4b7897a1c82c92dfdc8a1f75ef58cd1b06e8052096980cb6e1ad6d3df143c34b3d7394bae2782a4df570554c2fb")));
|
|
||||
|
|
||||
//console.log(Bitcoin.ECDSA.verify(Crypto.util.hexToBytes("230aba77ccde46bb17fcb0295a92c0cc42a6ea9f439aaadeb0094625f49e6ed8"), Crypto.util.hexToBytes("3046022100a3ee5408f0003d8ef00ff2e0537f54ba09771626ff70dca1f01296b05c510e85022100d4dc70a5bb50685b65833a97e536909a6951dd247a2fdbde6688c33ba6d6407501"),Crypto.util.hexToBytes("04a19c1f07c7a0868d86dbb37510305843cc730eb3bea8a99d92131f44950cecd923788419bfef2f635fad621d753f30d4b4b63b29da44b4f3d92db974537ad5a4")));
|
|
||||
//console.log(Bitcoin.ECDSA.verify(Crypto.util.hexToBytes("c2c75bb77d7a5acddceb1d45ceef58e7451fd0d3abc9d4c16df7848eefafe00d"), Crypto.util.hexToBytes("3045022100ff9362dadcbf1f6ef954bc8eb27144bbb4f49abd32be1eb04c311151dcf4bcf802205112c2ca6a25aefb8be98bf460c5a9056c01253f31e118d80b81ec9604e3201a01"),Crypto.util.hexToBytes("04fe62ce7892ec209310c176ef7f06565865e286e8699e884603657efa9aa51086785099d544d4e04f1f7b4b065205c1783fade8daf4ba1e0d1962292e8eb722cd")));
|
|
||||
}); |
|
||||
//
|
|
||||
*/ |
|
@ -0,0 +1,74 @@ |
|||||
|
// convert to/from various values
|
||||
|
|
||||
|
var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
||||
|
|
||||
|
String.prototype.lpad = function(padString, length) { |
||||
|
var str = this; |
||||
|
while (str.length < length) str = padString + str; |
||||
|
return str; |
||||
|
} |
||||
|
|
||||
|
// Convert a byte array to a hex string
|
||||
|
module.exports.bytesToHex = function(bytes) { |
||||
|
return bytes.map(function(x) { return x.toString(16).lpad('0',2) }).join(''); |
||||
|
}; |
||||
|
|
||||
|
// Convert a hex string to a byte array
|
||||
|
module.exports.hexToBytes = function(hex) { |
||||
|
return hex.match(/../g).map(function(x) { return parseInt(x,16) }); |
||||
|
} |
||||
|
|
||||
|
// Convert a byte array to a base-64 string
|
||||
|
module.exports.bytesToBase64 = function(bytes) { |
||||
|
|
||||
|
for(var base64 = [], i = 0; i < bytes.length; i += 3) { |
||||
|
var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; |
||||
|
for (var j = 0; j < 4; j++) { |
||||
|
if (i * 8 + j * 6 <= bytes.length * 8) |
||||
|
base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F)); |
||||
|
else base64.push("="); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return base64.join(""); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// Convert a base-64 string to a byte array
|
||||
|
module.exports.base64ToBytes = function(base64) { |
||||
|
|
||||
|
// Remove non-base-64 characters
|
||||
|
base64 = base64.replace(/[^A-Z0-9+\/]/ig, ""); |
||||
|
|
||||
|
for (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) { |
||||
|
if (imod4 == 0) continue; |
||||
|
bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) | |
||||
|
(base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2))); |
||||
|
} |
||||
|
|
||||
|
return bytes; |
||||
|
} |
||||
|
|
||||
|
// Hex only (allowing bin would be potentially risky, as 01010101 = \x01 * 4 or 85)
|
||||
|
module.exports.coerceToBytes = function(input) { |
||||
|
if (typeof input == "string") return module.exports.hexToBytes(input); |
||||
|
return input; |
||||
|
} |
||||
|
|
||||
|
module.exports.binToBytes = function(bin) { |
||||
|
return bin.match(/......../g).map(function(x) { return parseInt(x,2) }); |
||||
|
} |
||||
|
|
||||
|
module.exports.bytesToBin = function(bytes) { |
||||
|
return bytes.map(function(x) { return x.toString(2).lpad('0',8) }).join(''); |
||||
|
} |
||||
|
|
||||
|
module.exports.bytesToString = function(bytes) { |
||||
|
return bytes.map(function(x){ return String.fromCharCode(x) }).join(''); |
||||
|
} |
||||
|
|
||||
|
module.exports.stringToBytes = function(string) { |
||||
|
return string.split('').map(function(x) { return x.charCodeAt(0) }); |
||||
|
} |
||||
|
|
||||
|
// utf8
|
@ -1,7 +0,0 @@ |
|||||
/* |
|
||||
* Crypto-JS v2.0.0 |
|
||||
* http://code.google.com/p/crypto-js/
|
|
||||
* Copyright (c) 2009, Jeff Mott. All rights reserved. |
|
||||
* http://code.google.com/p/crypto-js/wiki/License
|
|
||||
*/ |
|
||||
(function(){var c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var d=window.Crypto={};var a=d.util={rotl:function(h,g){return(h<<g)|(h>>>(32-g))},rotr:function(h,g){return(h<<(32-g))|(h>>>g)},endian:function(h){if(h.constructor==Number){return a.rotl(h,8)&16711935|a.rotl(h,24)&4278255360}for(var g=0;g<h.length;g++){h[g]=a.endian(h[g])}return h},randomBytes:function(h){for(var g=[];h>0;h--){g.push(Math.floor(Math.random()*256))}return g},bytesToWords:function(h){for(var k=[],j=0,g=0;j<h.length;j++,g+=8){k[g>>>5]|=h[j]<<(24-g%32)}return k},wordsToBytes:function(i){for(var h=[],g=0;g<i.length*32;g+=8){h.push((i[g>>>5]>>>(24-g%32))&255)}return h},bytesToHex:function(g){for(var j=[],h=0;h<g.length;h++){j.push((g[h]>>>4).toString(16));j.push((g[h]&15).toString(16))}return j.join("")},hexToBytes:function(h){for(var g=[],i=0;i<h.length;i+=2){g.push(parseInt(h.substr(i,2),16))}return g},bytesToBase64:function(h){if(typeof btoa=="function"){return btoa(e.bytesToString(h))}for(var g=[],l=0;l<h.length;l+=3){var m=(h[l]<<16)|(h[l+1]<<8)|h[l+2];for(var k=0;k<4;k++){if(l*8+k*6<=h.length*8){g.push(c.charAt((m>>>6*(3-k))&63))}else{g.push("=")}}}return g.join("")},base64ToBytes:function(h){if(typeof atob=="function"){return e.stringToBytes(atob(h))}h=h.replace(/[^A-Z0-9+\/]/ig,"");for(var g=[],j=0,k=0;j<h.length;k=++j%4){if(k==0){continue}g.push(((c.indexOf(h.charAt(j-1))&(Math.pow(2,-2*k+8)-1))<<(k*2))|(c.indexOf(h.charAt(j))>>>(6-k*2)))}return g}};d.mode={};var b=d.charenc={};var f=b.UTF8={stringToBytes:function(g){return e.stringToBytes(unescape(encodeURIComponent(g)))},bytesToString:function(g){return decodeURIComponent(escape(e.bytesToString(g)))}};var e=b.Binary={stringToBytes:function(j){for(var g=[],h=0;h<j.length;h++){g.push(j.charCodeAt(h))}return g},bytesToString:function(g){for(var j=[],h=0;h<g.length;h++){j.push(String.fromCharCode(g[h]))}return j.join("")}}})(); |
|
@ -1,160 +1,66 @@ |
|||||
/*! |
/*! |
||||
* Crypto-JS v2.0.0 |
* Crypto-JS v2.0.0 |
||||
* http://code.google.com/p/crypto-js/
|
* http://code.google.com/p/crypto-js/
|
||||
* Copyright (c) 2009, Jeff Mott. All rights reserved. |
* Copyright (c) 2009, Jeff Mott. All rights reserved. |
||||
* http://code.google.com/p/crypto-js/wiki/License
|
* http://code.google.com/p/crypto-js/wiki/License
|
||||
*/ |
*/ |
||||
(function(){ |
|
||||
|
// Global Crypto object
|
||||
var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
var Crypto = module.exports = {}; |
||||
|
|
||||
// Global Crypto object
|
// Crypto utilities
|
||||
var Crypto = window.Crypto = {}; |
var util = Crypto.util = { |
||||
|
|
||||
// Crypto utilities
|
// Generate an array of any length of random bytes
|
||||
var util = Crypto.util = { |
randomBytes: function (n) { |
||||
|
for (var bytes = []; n > 0; n--) |
||||
// Bit-wise rotate left
|
bytes.push(Math.floor(Math.random() * 256)); |
||||
rotl: function (n, b) { |
return bytes; |
||||
return (n << b) | (n >>> (32 - b)); |
}, |
||||
}, |
|
||||
|
}; |
||||
// Bit-wise rotate right
|
|
||||
rotr: function (n, b) { |
// Crypto mode namespace
|
||||
return (n << (32 - b)) | (n >>> b); |
Crypto.mode = {}; |
||||
}, |
|
||||
|
// Crypto character encodings
|
||||
// Swap big-endian to little-endian and vice versa
|
var charenc = Crypto.charenc = {}; |
||||
endian: function (n) { |
|
||||
|
// UTF-8 encoding
|
||||
// If number given, swap endian
|
var UTF8 = charenc.UTF8 = { |
||||
if (n.constructor == Number) { |
|
||||
return util.rotl(n, 8) & 0x00FF00FF | |
// Convert a string to a byte array
|
||||
util.rotl(n, 24) & 0xFF00FF00; |
stringToBytes: function (str) { |
||||
} |
return Binary.stringToBytes(unescape(encodeURIComponent(str))); |
||||
|
}, |
||||
// Else, assume array and swap all items
|
|
||||
for (var i = 0; i < n.length; i++) |
// Convert a byte array to a string
|
||||
n[i] = util.endian(n[i]); |
bytesToString: function (bytes) { |
||||
return n; |
return decodeURIComponent(escape(Binary.bytesToString(bytes))); |
||||
|
} |
||||
}, |
|
||||
|
}; |
||||
// Generate an array of any length of random bytes
|
|
||||
randomBytes: function (n) { |
// Binary encoding
|
||||
for (var bytes = []; n > 0; n--) |
var Binary = charenc.Binary = { |
||||
bytes.push(Math.floor(Math.random() * 256)); |
|
||||
return bytes; |
// Convert a string to a byte array
|
||||
}, |
stringToBytes: function (str) { |
||||
|
for (var bytes = [], i = 0; i < str.length; i++) |
||||
// Convert a byte array to big-endian 32-bit words
|
bytes.push(str.charCodeAt(i)); |
||||
bytesToWords: function (bytes) { |
return bytes; |
||||
for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8) |
}, |
||||
words[b >>> 5] |= bytes[i] << (24 - b % 32); |
|
||||
return words; |
// Convert a byte array to a string
|
||||
}, |
bytesToString: function (bytes) { |
||||
|
for (var str = [], i = 0; i < bytes.length; i++) |
||||
// Convert big-endian 32-bit words to a byte array
|
str.push(String.fromCharCode(bytes[i])); |
||||
wordsToBytes: function (words) { |
return str.join(""); |
||||
for (var bytes = [], b = 0; b < words.length * 32; b += 8) |
} |
||||
bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); |
|
||||
return bytes; |
}; |
||||
}, |
|
||||
|
module.exports.SHA256 = require('./sha256'); |
||||
// Convert a byte array to a hex string
|
module.exports.SHA512 = require('./sha512'); |
||||
bytesToHex: function (bytes) { |
module.exports.RIPEMD160 = require('./ripemd160'); |
||||
for (var hex = [], i = 0; i < bytes.length; i++) { |
module.exports.HMAC = require('./hmac'); |
||||
hex.push((bytes[i] >>> 4).toString(16)); |
|
||||
hex.push((bytes[i] & 0xF).toString(16)); |
|
||||
} |
|
||||
return hex.join(""); |
|
||||
}, |
|
||||
|
|
||||
// Convert a hex string to a byte array
|
|
||||
hexToBytes: function (hex) { |
|
||||
for (var bytes = [], c = 0; c < hex.length; c += 2) |
|
||||
bytes.push(parseInt(hex.substr(c, 2), 16)); |
|
||||
return bytes; |
|
||||
}, |
|
||||
|
|
||||
// Convert a byte array to a base-64 string
|
|
||||
bytesToBase64: function (bytes) { |
|
||||
|
|
||||
// Use browser-native function if it exists
|
|
||||
if (typeof btoa == "function") return btoa(Binary.bytesToString(bytes)); |
|
||||
|
|
||||
for(var base64 = [], i = 0; i < bytes.length; i += 3) { |
|
||||
var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; |
|
||||
for (var j = 0; j < 4; j++) { |
|
||||
if (i * 8 + j * 6 <= bytes.length * 8) |
|
||||
base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F)); |
|
||||
else base64.push("="); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return base64.join(""); |
|
||||
|
|
||||
}, |
|
||||
|
|
||||
// Convert a base-64 string to a byte array
|
|
||||
base64ToBytes: function (base64) { |
|
||||
|
|
||||
// Use browser-native function if it exists
|
|
||||
if (typeof atob == "function") return Binary.stringToBytes(atob(base64)); |
|
||||
|
|
||||
// Remove non-base-64 characters
|
|
||||
base64 = base64.replace(/[^A-Z0-9+\/]/ig, ""); |
|
||||
|
|
||||
for (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) { |
|
||||
if (imod4 == 0) continue; |
|
||||
bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) | |
|
||||
(base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2))); |
|
||||
} |
|
||||
|
|
||||
return bytes; |
|
||||
|
|
||||
} |
|
||||
|
|
||||
}; |
|
||||
|
|
||||
// Crypto mode namespace
|
|
||||
Crypto.mode = {}; |
|
||||
|
|
||||
// Crypto character encodings
|
|
||||
var charenc = Crypto.charenc = {}; |
|
||||
|
|
||||
// UTF-8 encoding
|
|
||||
var UTF8 = charenc.UTF8 = { |
|
||||
|
|
||||
// Convert a string to a byte array
|
|
||||
stringToBytes: function (str) { |
|
||||
return Binary.stringToBytes(unescape(encodeURIComponent(str))); |
|
||||
}, |
|
||||
|
|
||||
// Convert a byte array to a string
|
|
||||
bytesToString: function (bytes) { |
|
||||
return decodeURIComponent(escape(Binary.bytesToString(bytes))); |
|
||||
} |
|
||||
|
|
||||
}; |
|
||||
|
|
||||
// Binary encoding
|
|
||||
var Binary = charenc.Binary = { |
|
||||
|
|
||||
// Convert a string to a byte array
|
|
||||
stringToBytes: function (str) { |
|
||||
for (var bytes = [], i = 0; i < str.length; i++) |
|
||||
bytes.push(str.charCodeAt(i)); |
|
||||
return bytes; |
|
||||
}, |
|
||||
|
|
||||
// Convert a byte array to a string
|
|
||||
bytesToString: function (bytes) { |
|
||||
for (var str = [], i = 0; i < bytes.length; i++) |
|
||||
str.push(String.fromCharCode(bytes[i])); |
|
||||
return str.join(""); |
|
||||
} |
|
||||
|
|
||||
}; |
|
||||
|
|
||||
})(); |
|
||||
|
@ -0,0 +1,38 @@ |
|||||
|
/*! |
||||
|
* Crypto-JS v2.0.0 |
||||
|
* http://code.google.com/p/crypto-js/
|
||||
|
* Copyright (c) 2009, Jeff Mott. All rights reserved. |
||||
|
* http://code.google.com/p/crypto-js/wiki/License
|
||||
|
*/ |
||||
|
|
||||
|
var conv = require('../convert'), |
||||
|
util = require('../util'); |
||||
|
|
||||
|
// Shortcuts
|
||||
|
|
||||
|
module.exports = function (hasher, message, key, options) { |
||||
|
|
||||
|
// Convert to byte arrays
|
||||
|
if (message.constructor == String) message = conv.stringToBytes(message); |
||||
|
if (key.constructor == String) key = conv.stringToBytes(key); |
||||
|
/* else, assume byte arrays already */ |
||||
|
|
||||
|
// Allow arbitrary length keys
|
||||
|
if (key.length > hasher._blocksize) |
||||
|
key = hasher(key, { asBytes: true }); |
||||
|
|
||||
|
// XOR keys with pad constants
|
||||
|
var okey = key.slice(0), |
||||
|
ikey = key.slice(0); |
||||
|
for (var i = 0; i < hasher._blocksize; i++) { |
||||
|
okey[i] ^= 0x5C; |
||||
|
ikey[i] ^= 0x36; |
||||
|
} |
||||
|
|
||||
|
var hmacbytes = hasher(okey.concat(hasher(ikey.concat(message), { asBytes: true })), { asBytes: true }); |
||||
|
|
||||
|
return options && options.asBytes ? hmacbytes : |
||||
|
options && options.asString ? conv.bytesToString(hmacbytes) : |
||||
|
conv.bytesToHex(hmacbytes); |
||||
|
|
||||
|
}; |
@ -1,170 +1,209 @@ |
|||||
/*! |
/* |
||||
* Crypto-JS v2.0.0 |
CryptoJS v3.1.2 |
||||
* http://code.google.com/p/crypto-js/
|
code.google.com/p/crypto-js |
||||
* Copyright (c) 2009, Jeff Mott. All rights reserved. |
(c) 2009-2013 by Jeff Mott. All rights reserved. |
||||
* http://code.google.com/p/crypto-js/wiki/License
|
code.google.com/p/crypto-js/wiki/License |
||||
* |
*/ |
||||
* A JavaScript implementation of the RIPEMD-160 Algorithm |
/** @preserve |
||||
* Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009. |
(c) 2012 by Cédric Mesnil. All rights reserved. |
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet |
|
||||
* Distributed under the BSD License |
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
||||
* See http://pajhome.org.uk/crypt/md5 for details.
|
|
||||
* Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
|
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
||||
* Ported to Crypto-JS by Stefan Thomas. |
- 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. |
||||
|
*/ |
||||
|
|
||||
|
var conv = require('../convert'); |
||||
|
var UTF8 = require('./crypto').charenc.UTF8; |
||||
|
|
||||
|
// 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)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* RIPEMD160 hash algorithm. |
||||
*/ |
*/ |
||||
|
module.exports = function(message, options) { |
||||
|
|
||||
|
if (message.constructor === String) { |
||||
|
message = UTF8.stringToBytes(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); |
||||
|
} |
||||
|
|
||||
(function () { |
var digestbytes = wordsToBytes(H); |
||||
// Shortcuts
|
return options && options.asBytes ? digestbytes : |
||||
var C = Crypto, |
options && options.asString ? Binary.bytesToString(digestbytes) : |
||||
util = C.util, |
conv.bytesToHex(digestbytes); |
||||
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)); |
|
||||
} |
|
||||
})(); |
|
||||
|
@ -1,7 +0,0 @@ |
|||||
/* |
|
||||
* Crypto-JS v2.0.0 |
|
||||
* http://code.google.com/p/crypto-js/
|
|
||||
* Copyright (c) 2009, Jeff Mott. All rights reserved. |
|
||||
* http://code.google.com/p/crypto-js/wiki/License
|
|
||||
*/ |
|
||||
(function(){var g=Crypto,b=g.util,c=g.charenc,f=c.UTF8,e=c.Binary;var a=[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];var d=g.SHA256=function(j,h){var i=b.wordsToBytes(d._sha256(j));return h&&h.asBytes?i:h&&h.asString?e.bytesToString(i):b.bytesToHex(i)};d._sha256=function(q){if(q.constructor==String){q=f.stringToBytes(q)}var y=b.bytesToWords(q),z=q.length*8,r=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],s=[],K,J,I,G,F,E,D,C,B,A,p,o;y[z>>5]|=128<<(24-z%32);y[((z+64>>9)<<4)+15]=z;for(var B=0;B<y.length;B+=16){K=r[0];J=r[1];I=r[2];G=r[3];F=r[4];E=r[5];D=r[6];C=r[7];for(var A=0;A<64;A++){if(A<16){s[A]=y[A+B]}else{var n=s[A-15],u=s[A-2],M=((n<<25)|(n>>>7))^((n<<14)|(n>>>18))^(n>>>3),L=((u<<15)|(u>>>17))^((u<<13)|(u>>>19))^(u>>>10);s[A]=M+(s[A-7]>>>0)+L+(s[A-16]>>>0)}var t=F&E^~F&D,k=K&J^K&I^J&I,x=((K<<30)|(K>>>2))^((K<<19)|(K>>>13))^((K<<10)|(K>>>22)),v=((F<<26)|(F>>>6))^((F<<21)|(F>>>11))^((F<<7)|(F>>>25));p=(C>>>0)+v+t+(a[A])+(s[A]>>>0);o=x+k;C=D;D=E;E=F;F=G+p;G=I;I=J;J=K;K=p+o}r[0]+=K;r[1]+=J;r[2]+=I;r[3]+=G;r[4]+=F;r[5]+=E;r[6]+=D;r[7]+=C}return r};d._blocksize=16})(); |
|
@ -1,133 +1,134 @@ |
|||||
/*! |
/* |
||||
* Crypto-JS v2.0.0 |
CryptoJS v3.1.2 |
||||
* http://code.google.com/p/crypto-js/
|
code.google.com/p/crypto-js |
||||
* Copyright (c) 2009, Jeff Mott. All rights reserved. |
(c) 2009-2013 by Jeff Mott. All rights reserved. |
||||
* http://code.google.com/p/crypto-js/wiki/License
|
code.google.com/p/crypto-js/wiki/License |
||||
*/ |
*/ |
||||
(function(){ |
|
||||
|
var conv = require('../convert'), |
||||
// Shortcuts
|
util = require('../util'); |
||||
var C = Crypto, |
|
||||
util = C.util, |
// Initialization round constants tables
|
||||
charenc = C.charenc, |
var K = []; |
||||
UTF8 = charenc.UTF8, |
|
||||
Binary = charenc.Binary; |
// Compute constants
|
||||
|
(function () { |
||||
// Constants
|
function isPrime(n) { |
||||
var K = [ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, |
var sqrtN = Math.sqrt(n); |
||||
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, |
for (var factor = 2; factor <= sqrtN; factor++) { |
||||
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, |
if (!(n % factor)) { |
||||
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, |
return false; |
||||
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, |
} |
||||
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, |
} |
||||
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, |
|
||||
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, |
return true; |
||||
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, |
} |
||||
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, |
|
||||
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, |
function getFractionalBits(n) { |
||||
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, |
return ((n - (n | 0)) * 0x100000000) | 0; |
||||
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, |
} |
||||
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, |
|
||||
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, |
var n = 2; |
||||
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 ]; |
var nPrime = 0; |
||||
|
while (nPrime < 64) { |
||||
// Public API
|
if (isPrime(n)) { |
||||
var SHA256 = C.SHA256 = function (message, options) { |
K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); |
||||
var digestbytes = util.wordsToBytes(SHA256._sha256(message)); |
nPrime++; |
||||
return options && options.asBytes ? digestbytes : |
} |
||||
options && options.asString ? Binary.bytesToString(digestbytes) : |
|
||||
util.bytesToHex(digestbytes); |
n++; |
||||
|
} |
||||
|
}()); |
||||
|
|
||||
|
// Reusable object
|
||||
|
var W = []; |
||||
|
|
||||
|
var processBlock = function (H, M, offset) { |
||||
|
|
||||
|
// Working variables
|
||||
|
var a = H[0]; |
||||
|
var b = H[1]; |
||||
|
var c = H[2]; |
||||
|
var d = H[3]; |
||||
|
var e = H[4]; |
||||
|
var f = H[5]; |
||||
|
var g = H[6]; |
||||
|
var h = H[7]; |
||||
|
|
||||
|
// Computation
|
||||
|
for (var i = 0; i < 64; i++) { |
||||
|
if (i < 16) { |
||||
|
W[i] = M[offset + i] | 0; |
||||
|
} else { |
||||
|
var gamma0x = W[i - 15]; |
||||
|
var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ |
||||
|
((gamma0x << 14) | (gamma0x >>> 18)) ^ |
||||
|
(gamma0x >>> 3); |
||||
|
|
||||
|
var gamma1x = W[i - 2]; |
||||
|
var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ |
||||
|
((gamma1x << 13) | (gamma1x >>> 19)) ^ |
||||
|
(gamma1x >>> 10); |
||||
|
|
||||
|
W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; |
||||
|
} |
||||
|
|
||||
|
var ch = (e & f) ^ (~e & g); |
||||
|
var maj = (a & b) ^ (a & c) ^ (b & c); |
||||
|
|
||||
|
var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); |
||||
|
var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); |
||||
|
|
||||
|
var t1 = h + sigma1 + ch + K[i] + W[i]; |
||||
|
var t2 = sigma0 + maj; |
||||
|
|
||||
|
h = g; |
||||
|
g = f; |
||||
|
f = e; |
||||
|
e = (d + t1) | 0; |
||||
|
d = c; |
||||
|
c = b; |
||||
|
b = a; |
||||
|
a = (t1 + t2) | 0; |
||||
|
} |
||||
|
|
||||
|
// Intermediate hash value
|
||||
|
H[0] = (H[0] + a) | 0; |
||||
|
H[1] = (H[1] + b) | 0; |
||||
|
H[2] = (H[2] + c) | 0; |
||||
|
H[3] = (H[3] + d) | 0; |
||||
|
H[4] = (H[4] + e) | 0; |
||||
|
H[5] = (H[5] + f) | 0; |
||||
|
H[6] = (H[6] + g) | 0; |
||||
|
H[7] = (H[7] + h) | 0; |
||||
}; |
}; |
||||
|
|
||||
// The core
|
/** |
||||
SHA256._sha256 = function (message) { |
* SHA-256 hash algorithm. |
||||
|
*/ |
||||
// Convert to byte array
|
module.exports = function(message, options) {; |
||||
if (message.constructor == String) message = UTF8.stringToBytes(message); |
|
||||
/* else, assume byte array already */ |
var H =[ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, |
||||
|
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 ]; |
||||
var m = util.bytesToWords(message), |
|
||||
l = message.length * 8, |
|
||||
H = [ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, |
|
||||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 ], |
|
||||
w = [], |
|
||||
a, b, c, d, e, f, g, h, i, j, |
|
||||
t1, t2; |
|
||||
|
|
||||
// Padding
|
|
||||
m[l >> 5] |= 0x80 << (24 - l % 32); |
|
||||
m[((l + 64 >> 9) << 4) + 15] = l; |
|
||||
|
|
||||
for (var i = 0; i < m.length; i += 16) { |
|
||||
|
|
||||
a = H[0]; |
|
||||
b = H[1]; |
|
||||
c = H[2]; |
|
||||
d = H[3]; |
|
||||
e = H[4]; |
|
||||
f = H[5]; |
|
||||
g = H[6]; |
|
||||
h = H[7]; |
|
||||
|
|
||||
for (var j = 0; j < 64; j++) { |
|
||||
|
|
||||
if (j < 16) w[j] = m[j + i]; |
|
||||
else { |
|
||||
|
|
||||
var gamma0x = w[j - 15], |
|
||||
gamma1x = w[j - 2], |
|
||||
gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ |
|
||||
((gamma0x << 14) | (gamma0x >>> 18)) ^ |
|
||||
(gamma0x >>> 3), |
|
||||
gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ |
|
||||
((gamma1x << 13) | (gamma1x >>> 19)) ^ |
|
||||
(gamma1x >>> 10); |
|
||||
|
|
||||
w[j] = gamma0 + (w[j - 7] >>> 0) + |
|
||||
gamma1 + (w[j - 16] >>> 0); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
var ch = e & f ^ ~e & g, |
|
||||
maj = a & b ^ a & c ^ b & c, |
|
||||
sigma0 = ((a << 30) | (a >>> 2)) ^ |
|
||||
((a << 19) | (a >>> 13)) ^ |
|
||||
((a << 10) | (a >>> 22)), |
|
||||
sigma1 = ((e << 26) | (e >>> 6)) ^ |
|
||||
((e << 21) | (e >>> 11)) ^ |
|
||||
((e << 7) | (e >>> 25)); |
|
||||
|
|
||||
|
|
||||
t1 = (h >>> 0) + sigma1 + ch + (K[j]) + (w[j] >>> 0); |
|
||||
t2 = sigma0 + maj; |
|
||||
|
|
||||
h = g; |
|
||||
g = f; |
|
||||
f = e; |
|
||||
e = d + t1; |
|
||||
d = c; |
|
||||
c = b; |
|
||||
b = a; |
|
||||
a = t1 + t2; |
|
||||
|
|
||||
} |
|
||||
|
|
||||
H[0] += a; |
|
||||
H[1] += b; |
|
||||
H[2] += c; |
|
||||
H[3] += d; |
|
||||
H[4] += e; |
|
||||
H[5] += f; |
|
||||
H[6] += g; |
|
||||
H[7] += h; |
|
||||
|
|
||||
} |
|
||||
|
|
||||
return H; |
|
||||
|
|
||||
}; |
if (message.constructor === String) { |
||||
|
message = conv.stringToBytes(message); |
||||
|
} |
||||
|
|
||||
// Package private blocksize
|
var m = util.bytesToWords(message); |
||||
SHA256._blocksize = 16; |
var l = message.length * 8; |
||||
|
|
||||
|
m[l >> 5] |= 0x80 << (24 - l % 32); |
||||
|
m[((l + 64 >> 9) << 4) + 15] = l; |
||||
|
|
||||
|
for (var i=0 ; i<m.length; i += 16) { |
||||
|
processBlock(H, m, i); |
||||
|
} |
||||
|
|
||||
|
var digestbytes = util.wordsToBytes(H); |
||||
|
return options && options.asBytes ? digestbytes : |
||||
|
options && options.asString ? Binary.bytesToString(digestbytes) : |
||||
|
conv.bytesToHex(digestbytes); |
||||
|
}; |
||||
|
|
||||
})(); |
module.exports._blocksize = 64 |
||||
|
@ -0,0 +1,239 @@ |
|||||
|
var conv = require('../convert'); |
||||
|
var util = require('../util'); |
||||
|
|
||||
|
var K = [ |
||||
|
[0x428a2f98, 0xd728ae22], [0x71374491, 0x23ef65cd], |
||||
|
[0xb5c0fbcf, 0xec4d3b2f], [0xe9b5dba5, 0x8189dbbc], |
||||
|
[0x3956c25b, 0xf348b538], [0x59f111f1, 0xb605d019], |
||||
|
[0x923f82a4, 0xaf194f9b], [0xab1c5ed5, 0xda6d8118], |
||||
|
[0xd807aa98, 0xa3030242], [0x12835b01, 0x45706fbe], |
||||
|
[0x243185be, 0x4ee4b28c], [0x550c7dc3, 0xd5ffb4e2], |
||||
|
[0x72be5d74, 0xf27b896f], [0x80deb1fe, 0x3b1696b1], |
||||
|
[0x9bdc06a7, 0x25c71235], [0xc19bf174, 0xcf692694], |
||||
|
[0xe49b69c1, 0x9ef14ad2], [0xefbe4786, 0x384f25e3], |
||||
|
[0x0fc19dc6, 0x8b8cd5b5], [0x240ca1cc, 0x77ac9c65], |
||||
|
[0x2de92c6f, 0x592b0275], [0x4a7484aa, 0x6ea6e483], |
||||
|
[0x5cb0a9dc, 0xbd41fbd4], [0x76f988da, 0x831153b5], |
||||
|
[0x983e5152, 0xee66dfab], [0xa831c66d, 0x2db43210], |
||||
|
[0xb00327c8, 0x98fb213f], [0xbf597fc7, 0xbeef0ee4], |
||||
|
[0xc6e00bf3, 0x3da88fc2], [0xd5a79147, 0x930aa725], |
||||
|
[0x06ca6351, 0xe003826f], [0x14292967, 0x0a0e6e70], |
||||
|
[0x27b70a85, 0x46d22ffc], [0x2e1b2138, 0x5c26c926], |
||||
|
[0x4d2c6dfc, 0x5ac42aed], [0x53380d13, 0x9d95b3df], |
||||
|
[0x650a7354, 0x8baf63de], [0x766a0abb, 0x3c77b2a8], |
||||
|
[0x81c2c92e, 0x47edaee6], [0x92722c85, 0x1482353b], |
||||
|
[0xa2bfe8a1, 0x4cf10364], [0xa81a664b, 0xbc423001], |
||||
|
[0xc24b8b70, 0xd0f89791], [0xc76c51a3, 0x0654be30], |
||||
|
[0xd192e819, 0xd6ef5218], [0xd6990624, 0x5565a910], |
||||
|
[0xf40e3585, 0x5771202a], [0x106aa070, 0x32bbd1b8], |
||||
|
[0x19a4c116, 0xb8d2d0c8], [0x1e376c08, 0x5141ab53], |
||||
|
[0x2748774c, 0xdf8eeb99], [0x34b0bcb5, 0xe19b48a8], |
||||
|
[0x391c0cb3, 0xc5c95a63], [0x4ed8aa4a, 0xe3418acb], |
||||
|
[0x5b9cca4f, 0x7763e373], [0x682e6ff3, 0xd6b2b8a3], |
||||
|
[0x748f82ee, 0x5defb2fc], [0x78a5636f, 0x43172f60], |
||||
|
[0x84c87814, 0xa1f0ab72], [0x8cc70208, 0x1a6439ec], |
||||
|
[0x90befffa, 0x23631e28], [0xa4506ceb, 0xde82bde9], |
||||
|
[0xbef9a3f7, 0xb2c67915], [0xc67178f2, 0xe372532b], |
||||
|
[0xca273ece, 0xea26619c], [0xd186b8c7, 0x21c0c207], |
||||
|
[0xeada7dd6, 0xcde0eb1e], [0xf57d4f7f, 0xee6ed178], |
||||
|
[0x06f067aa, 0x72176fba], [0x0a637dc5, 0xa2c898a6], |
||||
|
[0x113f9804, 0xbef90dae], [0x1b710b35, 0x131c471b], |
||||
|
[0x28db77f5, 0x23047d84], [0x32caab7b, 0x40c72493], |
||||
|
[0x3c9ebe0a, 0x15c9bebc], [0x431d67c4, 0x9c100d4c], |
||||
|
[0x4cc5d4be, 0xcb3e42b6], [0x597f299c, 0xfc657e2a], |
||||
|
[0x5fcb6fab, 0x3ad6faec], [0x6c44198c, 0x4a475817] |
||||
|
]; |
||||
|
// Reusable objects
|
||||
|
var W = []; |
||||
|
for (var i = 0; i < 80; i++) W.push([0,0]) |
||||
|
|
||||
|
/** |
||||
|
* SHA-512 hash algorithm. |
||||
|
*/ |
||||
|
var processBlock = function (H, M, offset) { |
||||
|
// Shortcuts
|
||||
|
var H0 = H[0]; |
||||
|
var H1 = H[1]; |
||||
|
var H2 = H[2]; |
||||
|
var H3 = H[3]; |
||||
|
var H4 = H[4]; |
||||
|
var H5 = H[5]; |
||||
|
var H6 = H[6]; |
||||
|
var H7 = H[7]; |
||||
|
|
||||
|
var H0h = H0[0]; |
||||
|
var H0l = H0[1]; |
||||
|
var H1h = H1[0]; |
||||
|
var H1l = H1[1]; |
||||
|
var H2h = H2[0]; |
||||
|
var H2l = H2[1]; |
||||
|
var H3h = H3[0]; |
||||
|
var H3l = H3[1]; |
||||
|
var H4h = H4[0]; |
||||
|
var H4l = H4[1]; |
||||
|
var H5h = H5[0]; |
||||
|
var H5l = H5[1]; |
||||
|
var H6h = H6[0]; |
||||
|
var H6l = H6[1]; |
||||
|
var H7h = H7[0]; |
||||
|
var H7l = H7[1]; |
||||
|
|
||||
|
// Working variables
|
||||
|
var ah = H0h; |
||||
|
var al = H0l; |
||||
|
var bh = H1h; |
||||
|
var bl = H1l; |
||||
|
var ch = H2h; |
||||
|
var cl = H2l; |
||||
|
var dh = H3h; |
||||
|
var dl = H3l; |
||||
|
var eh = H4h; |
||||
|
var el = H4l; |
||||
|
var fh = H5h; |
||||
|
var fl = H5l; |
||||
|
var gh = H6h; |
||||
|
var gl = H6l; |
||||
|
var hh = H7h; |
||||
|
var hl = H7l; |
||||
|
|
||||
|
// Rounds
|
||||
|
for (var i = 0; i < 80; i++) { |
||||
|
// Shortcut
|
||||
|
var Wi = W[i]; |
||||
|
|
||||
|
// Extend message
|
||||
|
if (i < 16) { |
||||
|
var Wih = Wi[0] = M[offset + i * 2] | 0; |
||||
|
var Wil = Wi[1] = M[offset + i * 2 + 1] | 0; |
||||
|
} else { |
||||
|
// Gamma0
|
||||
|
var gamma0x = W[i - 15]; |
||||
|
var gamma0xh = gamma0x[0]; |
||||
|
var gamma0xl = gamma0x[1]; |
||||
|
var gamma0h = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7); |
||||
|
var gamma0l = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25)); |
||||
|
|
||||
|
// Gamma1
|
||||
|
var gamma1x = W[i - 2]; |
||||
|
var gamma1xh = gamma1x[0]; |
||||
|
var gamma1xl = gamma1x[1]; |
||||
|
var gamma1h = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6); |
||||
|
var gamma1l = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26)); |
||||
|
|
||||
|
// W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]
|
||||
|
var Wi7 = W[i - 7]; |
||||
|
var Wi7h = Wi7[0]; |
||||
|
var Wi7l = Wi7[1]; |
||||
|
|
||||
|
var Wi16 = W[i - 16]; |
||||
|
var Wi16h = Wi16[0]; |
||||
|
var Wi16l = Wi16[1]; |
||||
|
|
||||
|
var Wil = gamma0l + Wi7l; |
||||
|
var Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); |
||||
|
var Wil = Wil + gamma1l; |
||||
|
var Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); |
||||
|
var Wil = Wil + Wi16l; |
||||
|
var Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); |
||||
|
|
||||
|
Wi[0] = Wih; |
||||
|
Wi[1] = Wil; |
||||
|
} |
||||
|
|
||||
|
var chh = (eh & fh) ^ (~eh & gh); |
||||
|
var chl = (el & fl) ^ (~el & gl); |
||||
|
var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch); |
||||
|
var majl = (al & bl) ^ (al & cl) ^ (bl & cl); |
||||
|
|
||||
|
var sigma0h = ((ah >>> 28) | (al << 4)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7)); |
||||
|
var sigma0l = ((al >>> 28) | (ah << 4)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7)); |
||||
|
var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9)); |
||||
|
var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9)); |
||||
|
|
||||
|
// t1 = h + sigma1 + ch + K[i] + W[i]
|
||||
|
var Ki = K[i]; |
||||
|
var Kih = Ki[0]; |
||||
|
var Kil = Ki[1]; |
||||
|
|
||||
|
var t1l = hl + sigma1l; |
||||
|
var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0); |
||||
|
var t1l = t1l + chl; |
||||
|
var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0); |
||||
|
var t1l = t1l + Kil; |
||||
|
var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0); |
||||
|
var t1l = t1l + Wil; |
||||
|
var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0); |
||||
|
|
||||
|
// t2 = sigma0 + maj
|
||||
|
var t2l = sigma0l + majl; |
||||
|
var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0); |
||||
|
|
||||
|
// Update working variables
|
||||
|
hh = gh; |
||||
|
hl = gl; |
||||
|
gh = fh; |
||||
|
gl = fl; |
||||
|
fh = eh; |
||||
|
fl = el; |
||||
|
el = (dl + t1l) | 0; |
||||
|
eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0; |
||||
|
dh = ch; |
||||
|
dl = cl; |
||||
|
ch = bh; |
||||
|
cl = bl; |
||||
|
bh = ah; |
||||
|
bl = al; |
||||
|
al = (t1l + t2l) | 0; |
||||
|
ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0; |
||||
|
} |
||||
|
|
||||
|
// Intermediate hash value
|
||||
|
H0l = H0[1] = (H0l + al); |
||||
|
H0[0] = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0)); |
||||
|
H1l = H1[1] = (H1l + bl); |
||||
|
H1[0] = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0)); |
||||
|
H2l = H2[1] = (H2l + cl); |
||||
|
H2[0] = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0)); |
||||
|
H3l = H3[1] = (H3l + dl); |
||||
|
H3[0] = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0)); |
||||
|
H4l = H4[1] = (H4l + el); |
||||
|
H4[0] = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0)); |
||||
|
H5l = H5[1] = (H5l + fl); |
||||
|
H5[0] = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0)); |
||||
|
H6l = H6[1] = (H6l + gl); |
||||
|
H6[0] = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0)); |
||||
|
H7l = H7[1] = (H7l + hl); |
||||
|
H7[0] = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0)); |
||||
|
return H |
||||
|
} |
||||
|
|
||||
|
module.exports = function(message, options) {; |
||||
|
|
||||
|
var H = [ |
||||
|
[0x6a09e667, 0xf3bcc908], [0xbb67ae85, 0x84caa73b], |
||||
|
[0x3c6ef372, 0xfe94f82b], [0xa54ff53a, 0x5f1d36f1], |
||||
|
[0x510e527f, 0xade682d1], [0x9b05688c, 0x2b3e6c1f], |
||||
|
[0x1f83d9ab, 0xfb41bd6b], [0x5be0cd19, 0x137e2179] |
||||
|
]; |
||||
|
|
||||
|
if (message.constructor === String) { |
||||
|
message = conv.stringToBytes(message); |
||||
|
} |
||||
|
|
||||
|
var m = util.bytesToWords(message); |
||||
|
var l = message.length * 8; |
||||
|
|
||||
|
m[l >> 5] |= 0x80 << (24 - l % 32); |
||||
|
m[((l + 64 >> 10) << 5) + 31] = l; |
||||
|
|
||||
|
for (var i=0 ; i<m.length; i += 32) { |
||||
|
processBlock(H, m, i); |
||||
|
} |
||||
|
|
||||
|
var digestbytes = util.wordsToBytes(Array.prototype.concat.apply([],H)) |
||||
|
return options && options.asBytes ? digestbytes : |
||||
|
options && options.asString ? Binary.bytesToString(digestbytes) : |
||||
|
conv.bytesToHex(digestbytes); |
||||
|
}; |
||||
|
|
||||
|
module.exports._blocksize = 128 |
@ -1,131 +1,179 @@ |
|||||
Bitcoin.ECKey = (function () { |
var BigInteger = require('./jsbn/jsbn'); |
||||
var ECDSA = Bitcoin.ECDSA; |
var sec = require('./jsbn/sec'); |
||||
var ecparams = getSECCurveByName("secp256k1"); |
var base58 = require('./base58'); |
||||
var rng = new SecureRandom(); |
var Crypto = require('./crypto-js/crypto'); |
||||
|
var util = require('./util'); |
||||
var ECKey = function (input) { |
var conv = require('./convert'); |
||||
|
var Address = require('./address'); |
||||
|
var ecdsa = require('./ecdsa'); |
||||
|
var ECPointFp = require('./jsbn/ec').ECPointFp; |
||||
|
|
||||
|
var ecparams = sec("secp256k1"); |
||||
|
|
||||
|
// input can be nothing, array of bytes, hex string, or base58 string
|
||||
|
var ECKey = function (input,compressed) { |
||||
|
if (!(this instanceof ECKey)) { return new ECKey(input); } |
||||
if (!input) { |
if (!input) { |
||||
// Generate new key
|
// Generate new key
|
||||
var n = ecparams.getN(); |
var n = ecparams.getN(); |
||||
this.priv = ECDSA.getBigRandom(n); |
this.priv = ecdsa.getBigRandom(n); |
||||
} else if (input instanceof BigInteger) { |
this.compressed = compressed || false; |
||||
// Input is a private key value
|
|
||||
this.priv = input; |
|
||||
} else if (Bitcoin.Util.isArray(input)) { |
|
||||
// Prepend zero byte to prevent interpretation as negative integer
|
|
||||
this.priv = BigInteger.fromByteArrayUnsigned(input); |
|
||||
} else if ("string" == typeof input) { |
|
||||
if (input.length == 51 && input[0] == '5') { |
|
||||
// Base58 encoded private key
|
|
||||
this.priv = BigInteger.fromByteArrayUnsigned(ECKey.decodeString(input)); |
|
||||
} else { |
|
||||
// Prepend zero byte to prevent interpretation as negative integer
|
|
||||
this.priv = BigInteger.fromByteArrayUnsigned(Crypto.util.base64ToBytes(input)); |
|
||||
} |
|
||||
} |
|
||||
this.compressed = !!ECKey.compressByDefault; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Whether public keys should be returned compressed by default. |
|
||||
*/ |
|
||||
ECKey.compressByDefault = false; |
|
||||
|
|
||||
/** |
|
||||
* Set whether the public key should be returned compressed or not. |
|
||||
*/ |
|
||||
ECKey.prototype.setCompressed = function (v) { |
|
||||
this.compressed = !!v; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Return public key in DER encoding. |
|
||||
*/ |
|
||||
ECKey.prototype.getPub = function () { |
|
||||
return this.getPubPoint().getEncoded(this.compressed); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Return public point as ECPoint object. |
|
||||
*/ |
|
||||
ECKey.prototype.getPubPoint = function () { |
|
||||
if (!this.pub) this.pub = ecparams.getG().multiply(this.priv); |
|
||||
|
|
||||
return this.pub; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Get the pubKeyHash for this key. |
|
||||
* |
|
||||
* This is calculated as RIPE160(SHA256([encoded pubkey])) and returned as |
|
||||
* a byte array. |
|
||||
*/ |
|
||||
ECKey.prototype.getPubKeyHash = function () { |
|
||||
if (this.pubKeyHash) return this.pubKeyHash; |
|
||||
|
|
||||
return this.pubKeyHash = Bitcoin.Util.sha256ripe160(this.getPub()); |
|
||||
}; |
|
||||
|
|
||||
ECKey.prototype.getBitcoinAddress = function () { |
|
||||
var hash = this.getPubKeyHash(); |
|
||||
var addr = new Bitcoin.Address(hash); |
|
||||
return addr; |
|
||||
}; |
|
||||
|
|
||||
ECKey.prototype.getExportedPrivateKey = function () { |
|
||||
var hash = this.priv.toByteArrayUnsigned(); |
|
||||
while (hash.length < 32) hash.unshift(0); |
|
||||
hash.unshift(0x80); |
|
||||
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true}); |
|
||||
var bytes = hash.concat(checksum.slice(0,4)); |
|
||||
return Bitcoin.Base58.encode(bytes); |
|
||||
}; |
|
||||
|
|
||||
ECKey.prototype.setPub = function (pub) { |
|
||||
this.pub = ECPointFp.decodeFrom(ecparams.getCurve(), pub); |
|
||||
}; |
|
||||
|
|
||||
ECKey.prototype.toString = function (format) { |
|
||||
if (format === "base64") { |
|
||||
return Crypto.util.bytesToBase64(this.priv.toByteArrayUnsigned()); |
|
||||
} else { |
|
||||
return Crypto.util.bytesToHex(this.priv.toByteArrayUnsigned()); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
ECKey.prototype.sign = function (hash) { |
|
||||
return ECDSA.sign(hash, this.priv); |
|
||||
}; |
|
||||
|
|
||||
ECKey.prototype.verify = function (hash, sig) { |
|
||||
return ECDSA.verify(hash, sig, this.getPub()); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Parse an exported private key contained in a string. |
|
||||
*/ |
|
||||
ECKey.decodeString = function (string) { |
|
||||
var bytes = Bitcoin.Base58.decode(string); |
|
||||
|
|
||||
var hash = bytes.slice(0, 33); |
|
||||
|
|
||||
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true}); |
|
||||
|
|
||||
if (checksum[0] != bytes[33] || |
|
||||
checksum[1] != bytes[34] || |
|
||||
checksum[2] != bytes[35] || |
|
||||
checksum[3] != bytes[36]) { |
|
||||
throw "Checksum validation failed!"; |
|
||||
} |
} |
||||
|
else this.import(input,compressed) |
||||
var version = hash.shift(); |
}; |
||||
|
|
||||
if (version != 0x80) { |
ECKey.prototype.import = function (input,compressed) { |
||||
throw "Version "+version+" not supported!"; |
function has(li,v) { return li.indexOf(v) >= 0 } |
||||
|
function fromBin(x) { return BigInteger.fromByteArrayUnsigned(x) } |
||||
|
this.priv = |
||||
|
input instanceof ECKey ? input.priv |
||||
|
: input instanceof BigInteger ? input.mod(ecparams.getN()) |
||||
|
: util.isArray(input) ? fromBin(input.slice(0,32)) |
||||
|
: typeof input != "string" ? null |
||||
|
: input.length == 51 && input[0] == '5' ? fromBin(base58.checkDecode(input)) |
||||
|
: input.length == 52 && has('LK',input[0]) ? fromBin(base58.checkDecode(input)) |
||||
|
: has([64,65],input.length) ? fromBin(conv.hexToBytes(input.slice(0,64))) |
||||
|
: null |
||||
|
|
||||
|
this.compressed = |
||||
|
compressed !== undefined ? compressed |
||||
|
: input instanceof ECKey ? input.compressed |
||||
|
: input instanceof BigInteger ? false |
||||
|
: util.isArray(input) ? false |
||||
|
: typeof input != "string" ? null |
||||
|
: input.length == 51 && input[0] == '5' ? false |
||||
|
: input.length == 52 && has('LK',input[0]) ? true |
||||
|
: input.length == 64 ? false |
||||
|
: input.length == 65 ? true |
||||
|
: null |
||||
|
}; |
||||
|
|
||||
|
ECKey.prototype.getPub = function(compressed) { |
||||
|
if (compressed === undefined) compressed = this.compressed |
||||
|
return ECPubKey(ecparams.getG().multiply(this.priv),compressed) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @deprecated Reserved keyword, factory pattern. Use toHex, toBytes, etc. |
||||
|
*/ |
||||
|
ECKey.prototype['export'] = function(format) { |
||||
|
format || (format = 'hex') |
||||
|
return this['to' + format.substr(0, 1).toUpperCase() + format.substr(1)]() |
||||
|
}; |
||||
|
|
||||
|
ECKey.prototype.toBin = function() { |
||||
|
return conv.bytesToString(this.toBytes()) |
||||
|
} |
||||
|
|
||||
|
ECKey.prototype.toBase58 = function() { |
||||
|
return base58.checkEncode(this.toBytes(), 128) |
||||
|
} |
||||
|
|
||||
|
ECKey.prototype.toWif = ECKey.prototype.toBase58 |
||||
|
|
||||
|
ECKey.prototype.toHex = function() { |
||||
|
return conv.bytesToHex(this.toBytes()) |
||||
|
} |
||||
|
|
||||
|
ECKey.prototype.toBytes = function() { |
||||
|
var bytes = this.priv.toByteArrayUnsigned(); |
||||
|
if (this.compressed) bytes.push(1) |
||||
|
return bytes |
||||
|
} |
||||
|
|
||||
|
ECKey.prototype.toString = ECKey.prototype.toBase58 |
||||
|
|
||||
|
ECKey.prototype.getBitcoinAddress = function(v) { |
||||
|
return this.getPub().getBitcoinAddress(v) |
||||
|
} |
||||
|
|
||||
|
ECKey.prototype.add = function(key) { |
||||
|
return ECKey(this.priv.add(ECKey(key).priv),this.compressed) |
||||
|
} |
||||
|
|
||||
|
ECKey.prototype.multiply = function(key) { |
||||
|
return ECKey(this.priv.multiply(ECKey(key).priv),this.compressed) |
||||
|
} |
||||
|
|
||||
|
var ECPubKey = function(input,compressed) { |
||||
|
if (!(this instanceof ECPubKey)) { return new ECPubKey(input,compressed); } |
||||
|
if (!input) { |
||||
|
// Generate new key
|
||||
|
var n = ecparams.getN(); |
||||
|
this.pub = ecparams.getG().multiply(ecdsa.getBigRandom(n)) |
||||
|
this.compressed = compressed || false; |
||||
} |
} |
||||
|
else this.import(input,compressed) |
||||
return hash; |
} |
||||
}; |
|
||||
|
ECPubKey.prototype.import = function(input,compressed) { |
||||
return ECKey; |
var decode = function(x) { return ECPointFp.decodeFrom(ecparams.getCurve(), x) } |
||||
})(); |
this.pub = |
||||
|
input instanceof ECPointFp ? input |
||||
|
: input instanceof ECKey ? ecparams.getG().multiply(input.priv) |
||||
|
: input instanceof ECPubKey ? input.pub |
||||
|
: typeof input == "string" ? decode(conv.hexToBytes(input)) |
||||
|
: util.isArray(input) ? decode(input) |
||||
|
: ecparams.getG().multiply(ecdsa.getBigRandom(ecparams.getN())) |
||||
|
|
||||
|
this.compressed = |
||||
|
arguments.length > 1 ? compressed |
||||
|
: input instanceof ECPointFp ? input.compressed |
||||
|
: input instanceof ECPubKey ? input.compressed |
||||
|
: (this.pub[0] < 4) |
||||
|
} |
||||
|
|
||||
|
ECPubKey.prototype.add = function(key) { |
||||
|
return ECPubKey(this.pub.add(ECPubKey(key).pub),this.compressed) |
||||
|
} |
||||
|
|
||||
|
ECPubKey.prototype.multiply = function(key) { |
||||
|
return ECPubKey(this.pub.multiply(ECKey(key).priv),this.compressed) |
||||
|
} |
||||
|
|
||||
|
ECPubKey.prototype['export'] = function(format) { |
||||
|
format || (format = 'hex') |
||||
|
return this['to' + format.substr(0, 1).toUpperCase() + format.substr(1)]() |
||||
|
} |
||||
|
|
||||
|
ECPubKey.prototype.toBytes = function(compressed) { |
||||
|
if (compressed === undefined) compressed = this.compressed |
||||
|
return this.pub.getEncoded(compressed) |
||||
|
} |
||||
|
|
||||
|
ECPubKey.prototype.toHex = function() { |
||||
|
return conv.bytesToHex(this.toBytes()) |
||||
|
} |
||||
|
|
||||
|
ECPubKey.prototype.toBin = function() { |
||||
|
return conv.bytesToString(this.toBytes()) |
||||
|
} |
||||
|
|
||||
|
ECPubKey.prototype.toBase58 = function() { |
||||
|
return base58.checkEncode(this.toBytes(), 128) |
||||
|
} |
||||
|
|
||||
|
ECPubKey.prototype.toWif = ECPubKey.prototype.toBase58 |
||||
|
|
||||
|
ECPubKey.prototype.toString = function() { |
||||
|
return this.getBitcoinAddress().toString() |
||||
|
} |
||||
|
|
||||
|
ECPubKey.prototype.getBitcoinAddress = function(v) { |
||||
|
return new Address(util.sha256ripe160(this.toBytes()), v); |
||||
|
} |
||||
|
|
||||
|
ECKey.prototype.sign = function (hash) { |
||||
|
return ecdsa.sign(hash, this.priv); |
||||
|
}; |
||||
|
|
||||
|
ECKey.prototype.verify = function (hash, sig) { |
||||
|
return ecdsa.verify(hash, sig, this.getPub()['export']('bytes')); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Parse an exported private key contained in a string. |
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
module.exports = { ECKey: ECKey, ECPubKey: ECPubKey }; |
||||
|
@ -0,0 +1,235 @@ |
|||||
|
var convert = require('./convert.js') |
||||
|
, base58 = require('./base58.js') |
||||
|
, assert = require('assert') |
||||
|
, format = require('util').format |
||||
|
, util = require('./util.js') |
||||
|
, Crypto = require('./crypto-js/crypto.js') |
||||
|
, ECKey = require('./eckey.js').ECKey |
||||
|
, ECPubKey = require('./eckey.js').ECPubKey |
||||
|
, Address = require('./address.js') |
||||
|
|
||||
|
var HDWallet = module.exports = function(seed, network) { |
||||
|
if (seed === undefined) return |
||||
|
|
||||
|
var I = Crypto.HMAC(Crypto.SHA512, seed, 'Bitcoin seed', { asBytes: true }) |
||||
|
this.chaincode = I.slice(32) |
||||
|
this.priv = new ECKey(I.slice(0, 32).concat([1]), true) |
||||
|
this.pub = this.priv.getPub() |
||||
|
this.network = network || 'Bitcoin' |
||||
|
this.index = 0 |
||||
|
this.depth = 0 |
||||
|
} |
||||
|
|
||||
|
HDWallet.HIGHEST_BIT = 0x80000000 |
||||
|
HDWallet.LENGTH = 78 |
||||
|
|
||||
|
HDWallet.VERSIONS = { |
||||
|
Bitcoin: [0x0488B21E, 0x0488ADE4], |
||||
|
BitcoinTest: [0x043587CF, 0x04358394] |
||||
|
} |
||||
|
|
||||
|
function arrayEqual(a, b) { |
||||
|
return !(a < b || a > b) |
||||
|
} |
||||
|
|
||||
|
HDWallet.getChecksum = function(buffer) { |
||||
|
assert.equal(buffer.length, HDWallet.LENGTH) |
||||
|
return Crypto.SHA256(Crypto.SHA256(buffer, { asBytes: true }), { asBytes: true }).slice(0, 4) |
||||
|
} |
||||
|
|
||||
|
HDWallet.fromMasterHex = function(hex) { |
||||
|
var bytes = convert.hexToBytes(hex) |
||||
|
return new HDWallet(convert.bytesToString(bytes)) |
||||
|
} |
||||
|
|
||||
|
HDWallet.fromBase58 = function(input) { |
||||
|
var buffer = base58.decode(input) |
||||
|
|
||||
|
if (buffer.length == HDWallet.LENGTH + 4) { |
||||
|
var expectedChecksum = buffer.slice(HDWallet.LENGTH, HDWallet.LENGTH + 4) |
||||
|
buffer = buffer.slice(0, HDWallet.LENGTH) |
||||
|
var actualChecksum = HDWallet.getChecksum(buffer) |
||||
|
|
||||
|
if (!arrayEqual(expectedChecksum, actualChecksum)) { |
||||
|
throw new Error('Checksum mismatch') |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return HDWallet.fromBytes(buffer) |
||||
|
} |
||||
|
|
||||
|
HDWallet.fromHex = function(input) { |
||||
|
return HDWallet.fromBytes(convert.hexToBytes(input)) |
||||
|
} |
||||
|
|
||||
|
HDWallet.fromBytes = function(input) { |
||||
|
// This 78 byte structure can be encoded like other Bitcoin data in Base58. (+32 bits checksum)
|
||||
|
if (input.length != HDWallet.LENGTH) { |
||||
|
throw new Error(format('Invalid input length, %s. Expected %s.', input.length, HDWallet.LENGTH)) |
||||
|
} |
||||
|
|
||||
|
var hd = new HDWallet() |
||||
|
|
||||
|
// 4 byte: version bytes (mainnet: 0x0488B21E public, 0x0488ADE4 private;
|
||||
|
// testnet: 0x043587CF public, 0x04358394 private)
|
||||
|
var versionBytes = input.slice(0, 4) |
||||
|
, versionWord = util.bytesToWords(versionBytes)[0] |
||||
|
, type |
||||
|
|
||||
|
Object.keys(HDWallet.VERSIONS).forEach(function(name) { |
||||
|
HDWallet.VERSIONS[name].forEach(function(word, i) { |
||||
|
if (versionWord != word) return |
||||
|
type = i ? 'private' : 'public' |
||||
|
hd.network = name |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
if (!hd.network) { |
||||
|
throw new Error(format('Could not find version %s', convert.bytesToHex(versionBytes))) |
||||
|
} |
||||
|
|
||||
|
// 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ...
|
||||
|
hd.depth = input[4] |
||||
|
|
||||
|
// 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
|
||||
|
hd.parentFingerprint = input.slice(5, 9) |
||||
|
assert((hd.depth === 0) == arrayEqual(hd.parentFingerprint, [0, 0, 0, 0])) |
||||
|
|
||||
|
// 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized.
|
||||
|
// This is encoded in MSB order. (0x00000000 if master key)
|
||||
|
hd.index = util.bytesToNum(input.slice(9, 13).reverse()) |
||||
|
assert(hd.depth > 0 || hd.index === 0) |
||||
|
|
||||
|
// 32 bytes: the chain code
|
||||
|
hd.chaincode = input.slice(13, 45) |
||||
|
|
||||
|
// 33 bytes: the public key or private key data (0x02 + X or 0x03 + X for
|
||||
|
// public keys, 0x00 + k for private keys)
|
||||
|
if (type == 'private') { |
||||
|
hd.priv = new ECKey(input.slice(46, 78).concat([1]), true) |
||||
|
hd.pub = hd.priv.getPub() |
||||
|
} else { |
||||
|
hd.pub = new ECPubKey(input.slice(45, 78), true) |
||||
|
} |
||||
|
|
||||
|
return hd |
||||
|
} |
||||
|
|
||||
|
HDWallet.prototype.getIdentifier = function() { |
||||
|
return util.sha256ripe160(this.pub.toBytes()) |
||||
|
} |
||||
|
|
||||
|
HDWallet.prototype.getFingerprint = function() { |
||||
|
return this.getIdentifier().slice(0, 4) |
||||
|
} |
||||
|
|
||||
|
HDWallet.prototype.getBitcoinAddress = function() { |
||||
|
var test = this.network.match(/Test$/) |
||||
|
return new Address(util.sha256ripe160(this.pub.toBytes()), test ? 111 : 0) |
||||
|
} |
||||
|
|
||||
|
HDWallet.prototype.toBytes = function(priv) { |
||||
|
var buffer = [] |
||||
|
|
||||
|
// Version
|
||||
|
// 4 byte: version bytes (mainnet: 0x0488B21E public, 0x0488ADE4 private; testnet: 0x043587CF public,
|
||||
|
// 0x04358394 private)
|
||||
|
var vBytes = util.wordsToBytes([HDWallet.VERSIONS[this.network][priv ? 1 : 0]]) |
||||
|
|
||||
|
buffer = buffer.concat(vBytes) |
||||
|
assert.equal(buffer.length, 4) |
||||
|
|
||||
|
// Depth
|
||||
|
// 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ....
|
||||
|
buffer.push(this.depth) |
||||
|
assert.equal(buffer.length, 4 + 1) |
||||
|
|
||||
|
// 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
|
||||
|
buffer = buffer.concat(this.depth ? this.parentFingerprint : [0, 0, 0, 0]) |
||||
|
assert.equal(buffer.length, 4 + 1 + 4) |
||||
|
|
||||
|
// 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized.
|
||||
|
// This is encoded in MSB order. (0x00000000 if master key)
|
||||
|
buffer = buffer.concat(util.numToBytes(this.index, 4).reverse()) |
||||
|
assert.equal(buffer.length, 4 + 1 + 4 + 4) |
||||
|
|
||||
|
// 32 bytes: the chain code
|
||||
|
buffer = buffer.concat(this.chaincode) |
||||
|
assert.equal(buffer.length, 4 + 1 + 4 + 4 + 32) |
||||
|
|
||||
|
// 33 bytes: the public key or private key data
|
||||
|
// (0x02 + X or 0x03 + X for public keys, 0x00 + k for private keys)
|
||||
|
if (priv) { |
||||
|
assert(this.priv, 'Cannot serialize to private without private key') |
||||
|
buffer.push(0) |
||||
|
buffer = buffer.concat(this.priv.toBytes().slice(0, 32)) |
||||
|
} else { |
||||
|
buffer = buffer.concat(this.pub.toBytes(true)) |
||||
|
} |
||||
|
|
||||
|
return buffer |
||||
|
} |
||||
|
|
||||
|
HDWallet.prototype.toHex = function(priv) { |
||||
|
var bytes = this.toBytes(priv) |
||||
|
return convert.bytesToHex(bytes) |
||||
|
} |
||||
|
|
||||
|
HDWallet.prototype.toBase58 = function(priv) { |
||||
|
var buffer = this.toBytes(priv) |
||||
|
, checksum = HDWallet.getChecksum(buffer) |
||||
|
buffer = buffer.concat(checksum) |
||||
|
return base58.encode(buffer) |
||||
|
} |
||||
|
|
||||
|
HDWallet.prototype.derive = function(i) { |
||||
|
var I |
||||
|
, iBytes = util.numToBytes(i, 4).reverse() |
||||
|
, cPar = this.chaincode |
||||
|
, usePriv = i >= HDWallet.HIGHEST_BIT |
||||
|
|
||||
|
if (usePriv) { |
||||
|
assert(this.priv, 'Private derive on public key') |
||||
|
|
||||
|
// If 1, private derivation is used:
|
||||
|
// let I = HMAC-SHA512(Key = cpar, Data = 0x00 || kpar || i) [Note:]
|
||||
|
var kPar = this.priv.toBytes().slice(0, 32) |
||||
|
I = Crypto.HMAC(Crypto.SHA512, [0].concat(kPar, iBytes), cPar, { asBytes: true }) |
||||
|
} else { |
||||
|
// If 0, public derivation is used:
|
||||
|
// let I = HMAC-SHA512(Key = cpar, Data = χ(kpar*G) || i)
|
||||
|
var KPar = this.pub.toBytes(true) |
||||
|
I = Crypto.HMAC(Crypto.SHA512, KPar.concat(iBytes), cPar, { asBytes: true }) |
||||
|
} |
||||
|
|
||||
|
// Split I = IL || IR into two 32-byte sequences, IL and IR.
|
||||
|
var IL = I.slice(0, 32) |
||||
|
, IR = I.slice(32) |
||||
|
|
||||
|
var hd = new HDWallet() |
||||
|
hd.network = this.network |
||||
|
|
||||
|
if (this.priv) { |
||||
|
// ki = IL + kpar (mod n).
|
||||
|
hd.priv = this.priv.add(new ECKey(IL.concat([1]))) |
||||
|
hd.priv.compressed = true |
||||
|
hd.pub = hd.priv.getPub() |
||||
|
} else { |
||||
|
// Ki = (IL + kpar)*G = IL*G + Kpar
|
||||
|
hd.pub = this.pub.add(new ECKey(IL.concat([1])).getPub()) |
||||
|
} |
||||
|
|
||||
|
// ci = IR.
|
||||
|
hd.chaincode = IR |
||||
|
hd.parentFingerprint = this.getFingerprint() |
||||
|
hd.depth = this.depth + 1 |
||||
|
hd.index = i |
||||
|
hd.pub.compressed = true |
||||
|
return hd |
||||
|
} |
||||
|
|
||||
|
HDWallet.prototype.derivePrivate = function(index) { |
||||
|
return this.derive(index + HDWallet.HIGHEST_BIT) |
||||
|
} |
||||
|
|
||||
|
HDWallet.prototype.toString = HDWallet.prototype.toBase58 |
@ -0,0 +1,54 @@ |
|||||
|
// Bit-wise rotate left
|
||||
|
var rotl = function (n, b) { |
||||
|
return (n << b) | (n >>> (32 - b)); |
||||
|
}; |
||||
|
|
||||
|
// Bit-wise rotate right
|
||||
|
var rotr = function (n, b) { |
||||
|
return (n << (32 - b)) | (n >>> b); |
||||
|
}; |
||||
|
|
||||
|
// Swap big-endian to little-endian and vice versa
|
||||
|
var endian = function (n) { |
||||
|
// If number given, swap endian
|
||||
|
if (n.constructor == Number) { |
||||
|
return rotl(n, 8) & 0x00FF00FF | rotl(n, 24) & 0xFF00FF00; |
||||
|
} |
||||
|
|
||||
|
// Else, assume array and swap all items
|
||||
|
for (var i = 0; i < n.length; i++) { |
||||
|
n[i] = endian(n[i]); |
||||
|
} |
||||
|
return n; |
||||
|
} |
||||
|
|
||||
|
var Key = require('./eckey'); |
||||
|
|
||||
|
module.exports = { |
||||
|
Address: require('./address'), |
||||
|
Key: Key.ECKey, |
||||
|
ECKey: Key.ECKey, |
||||
|
ECPubKey: Key.ECPubKey, |
||||
|
Message: require('./message'), |
||||
|
BigInteger: require('./jsbn/jsbn'), |
||||
|
Crypto: require('./crypto-js/crypto'), |
||||
|
Script: require('./script'), |
||||
|
Opcode: require('./opcode'), |
||||
|
Transaction: require('./transaction').Transaction, |
||||
|
Util: require('./util'), |
||||
|
TransactionIn: require('./transaction').TransactionIn, |
||||
|
TransactionOut: require('./transaction').TransactionOut, |
||||
|
ECPointFp: require('./jsbn/ec').ECPointFp, |
||||
|
Wallet: require('./wallet'), |
||||
|
|
||||
|
ecdsa: require('./ecdsa'), |
||||
|
HDWallet: require('./hdwallet.js'), |
||||
|
|
||||
|
// base58 encoding/decoding to bytes
|
||||
|
base58: require('./base58'), |
||||
|
|
||||
|
// conversions
|
||||
|
convert: require('./convert'), |
||||
|
|
||||
|
endian: endian |
||||
|
} |
File diff suppressed because it is too large
@ -1,656 +0,0 @@ |
|||||
// Copyright (c) 2005-2009 Tom Wu
|
|
||||
// All Rights Reserved.
|
|
||||
// See "LICENSE" for details.
|
|
||||
|
|
||||
// Extended JavaScript BN functions, required for RSA private ops.
|
|
||||
|
|
||||
// Version 1.1: new BigInteger("0", 10) returns "proper" zero
|
|
||||
// Version 1.2: square() API, isProbablePrime fix
|
|
||||
|
|
||||
// (public)
|
|
||||
function bnClone() { var r = nbi(); this.copyTo(r); return r; } |
|
||||
|
|
||||
// (public) return value as integer
|
|
||||
function bnIntValue() { |
|
||||
if(this.s < 0) { |
|
||||
if(this.t == 1) return this[0]-this.DV; |
|
||||
else if(this.t == 0) return -1; |
|
||||
} |
|
||||
else if(this.t == 1) return this[0]; |
|
||||
else if(this.t == 0) return 0; |
|
||||
// assumes 16 < DB < 32
|
|
||||
return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0]; |
|
||||
} |
|
||||
|
|
||||
// (public) return value as byte
|
|
||||
function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; } |
|
||||
|
|
||||
// (public) return value as short (assumes DB>=16)
|
|
||||
function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; } |
|
||||
|
|
||||
// (protected) return x s.t. r^x < DV
|
|
||||
function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); } |
|
||||
|
|
||||
// (public) 0 if this == 0, 1 if this > 0
|
|
||||
function bnSigNum() { |
|
||||
if(this.s < 0) return -1; |
|
||||
else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; |
|
||||
else return 1; |
|
||||
} |
|
||||
|
|
||||
// (protected) convert to radix string
|
|
||||
function bnpToRadix(b) { |
|
||||
if(b == null) b = 10; |
|
||||
if(this.signum() == 0 || b < 2 || b > 36) return "0"; |
|
||||
var cs = this.chunkSize(b); |
|
||||
var a = Math.pow(b,cs); |
|
||||
var d = nbv(a), y = nbi(), z = nbi(), r = ""; |
|
||||
this.divRemTo(d,y,z); |
|
||||
while(y.signum() > 0) { |
|
||||
r = (a+z.intValue()).toString(b).substr(1) + r; |
|
||||
y.divRemTo(d,y,z); |
|
||||
} |
|
||||
return z.intValue().toString(b) + r; |
|
||||
} |
|
||||
|
|
||||
// (protected) convert from radix string
|
|
||||
function bnpFromRadix(s,b) { |
|
||||
this.fromInt(0); |
|
||||
if(b == null) b = 10; |
|
||||
var cs = this.chunkSize(b); |
|
||||
var d = Math.pow(b,cs), mi = false, j = 0, w = 0; |
|
||||
for(var i = 0; i < s.length; ++i) { |
|
||||
var x = intAt(s,i); |
|
||||
if(x < 0) { |
|
||||
if(s.charAt(i) == "-" && this.signum() == 0) mi = true; |
|
||||
continue; |
|
||||
} |
|
||||
w = b*w+x; |
|
||||
if(++j >= cs) { |
|
||||
this.dMultiply(d); |
|
||||
this.dAddOffset(w,0); |
|
||||
j = 0; |
|
||||
w = 0; |
|
||||
} |
|
||||
} |
|
||||
if(j > 0) { |
|
||||
this.dMultiply(Math.pow(b,j)); |
|
||||
this.dAddOffset(w,0); |
|
||||
} |
|
||||
if(mi) BigInteger.ZERO.subTo(this,this); |
|
||||
} |
|
||||
|
|
||||
// (protected) alternate constructor
|
|
||||
function bnpFromNumber(a,b,c) { |
|
||||
if("number" == typeof b) { |
|
||||
// new BigInteger(int,int,RNG)
|
|
||||
if(a < 2) this.fromInt(1); |
|
||||
else { |
|
||||
this.fromNumber(a,c); |
|
||||
if(!this.testBit(a-1)) // force MSB set
|
|
||||
this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this); |
|
||||
if(this.isEven()) this.dAddOffset(1,0); // force odd
|
|
||||
while(!this.isProbablePrime(b)) { |
|
||||
this.dAddOffset(2,0); |
|
||||
if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
else { |
|
||||
// new BigInteger(int,RNG)
|
|
||||
var x = new Array(), t = a&7; |
|
||||
x.length = (a>>3)+1; |
|
||||
b.nextBytes(x); |
|
||||
if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0; |
|
||||
this.fromString(x,256); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// (public) convert to bigendian byte array
|
|
||||
function bnToByteArray() { |
|
||||
var i = this.t, r = new Array(); |
|
||||
r[0] = this.s; |
|
||||
var p = this.DB-(i*this.DB)%8, d, k = 0; |
|
||||
if(i-- > 0) { |
|
||||
if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p) |
|
||||
r[k++] = d|(this.s<<(this.DB-p)); |
|
||||
while(i >= 0) { |
|
||||
if(p < 8) { |
|
||||
d = (this[i]&((1<<p)-1))<<(8-p); |
|
||||
d |= this[--i]>>(p+=this.DB-8); |
|
||||
} |
|
||||
else { |
|
||||
d = (this[i]>>(p-=8))&0xff; |
|
||||
if(p <= 0) { p += this.DB; --i; } |
|
||||
} |
|
||||
if((d&0x80) != 0) d |= -256; |
|
||||
if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; |
|
||||
if(k > 0 || d != this.s) r[k++] = d; |
|
||||
} |
|
||||
} |
|
||||
return r; |
|
||||
} |
|
||||
|
|
||||
function bnEquals(a) { return(this.compareTo(a)==0); } |
|
||||
function bnMin(a) { return(this.compareTo(a)<0)?this:a; } |
|
||||
function bnMax(a) { return(this.compareTo(a)>0)?this:a; } |
|
||||
|
|
||||
// (protected) r = this op a (bitwise)
|
|
||||
function bnpBitwiseTo(a,op,r) { |
|
||||
var i, f, m = Math.min(a.t,this.t); |
|
||||
for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]); |
|
||||
if(a.t < this.t) { |
|
||||
f = a.s&this.DM; |
|
||||
for(i = m; i < this.t; ++i) r[i] = op(this[i],f); |
|
||||
r.t = this.t; |
|
||||
} |
|
||||
else { |
|
||||
f = this.s&this.DM; |
|
||||
for(i = m; i < a.t; ++i) r[i] = op(f,a[i]); |
|
||||
r.t = a.t; |
|
||||
} |
|
||||
r.s = op(this.s,a.s); |
|
||||
r.clamp(); |
|
||||
} |
|
||||
|
|
||||
// (public) this & a
|
|
||||
function op_and(x,y) { return x&y; } |
|
||||
function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; } |
|
||||
|
|
||||
// (public) this | a
|
|
||||
function op_or(x,y) { return x|y; } |
|
||||
function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; } |
|
||||
|
|
||||
// (public) this ^ a
|
|
||||
function op_xor(x,y) { return x^y; } |
|
||||
function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; } |
|
||||
|
|
||||
// (public) this & ~a
|
|
||||
function op_andnot(x,y) { return x&~y; } |
|
||||
function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; } |
|
||||
|
|
||||
// (public) ~this
|
|
||||
function bnNot() { |
|
||||
var r = nbi(); |
|
||||
for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i]; |
|
||||
r.t = this.t; |
|
||||
r.s = ~this.s; |
|
||||
return r; |
|
||||
} |
|
||||
|
|
||||
// (public) this << n
|
|
||||
function bnShiftLeft(n) { |
|
||||
var r = nbi(); |
|
||||
if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); |
|
||||
return r; |
|
||||
} |
|
||||
|
|
||||
// (public) this >> n
|
|
||||
function bnShiftRight(n) { |
|
||||
var r = nbi(); |
|
||||
if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); |
|
||||
return r; |
|
||||
} |
|
||||
|
|
||||
// return index of lowest 1-bit in x, x < 2^31
|
|
||||
function lbit(x) { |
|
||||
if(x == 0) return -1; |
|
||||
var r = 0; |
|
||||
if((x&0xffff) == 0) { x >>= 16; r += 16; } |
|
||||
if((x&0xff) == 0) { x >>= 8; r += 8; } |
|
||||
if((x&0xf) == 0) { x >>= 4; r += 4; } |
|
||||
if((x&3) == 0) { x >>= 2; r += 2; } |
|
||||
if((x&1) == 0) ++r; |
|
||||
return r; |
|
||||
} |
|
||||
|
|
||||
// (public) returns index of lowest 1-bit (or -1 if none)
|
|
||||
function bnGetLowestSetBit() { |
|
||||
for(var i = 0; i < this.t; ++i) |
|
||||
if(this[i] != 0) return i*this.DB+lbit(this[i]); |
|
||||
if(this.s < 0) return this.t*this.DB; |
|
||||
return -1; |
|
||||
} |
|
||||
|
|
||||
// return number of 1 bits in x
|
|
||||
function cbit(x) { |
|
||||
var r = 0; |
|
||||
while(x != 0) { x &= x-1; ++r; } |
|
||||
return r; |
|
||||
} |
|
||||
|
|
||||
// (public) return number of set bits
|
|
||||
function bnBitCount() { |
|
||||
var r = 0, x = this.s&this.DM; |
|
||||
for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x); |
|
||||
return r; |
|
||||
} |
|
||||
|
|
||||
// (public) true iff nth bit is set
|
|
||||
function bnTestBit(n) { |
|
||||
var j = Math.floor(n/this.DB); |
|
||||
if(j >= this.t) return(this.s!=0); |
|
||||
return((this[j]&(1<<(n%this.DB)))!=0); |
|
||||
} |
|
||||
|
|
||||
// (protected) this op (1<<n)
|
|
||||
function bnpChangeBit(n,op) { |
|
||||
var r = BigInteger.ONE.shiftLeft(n); |
|
||||
this.bitwiseTo(r,op,r); |
|
||||
return r; |
|
||||
} |
|
||||
|
|
||||
// (public) this | (1<<n)
|
|
||||
function bnSetBit(n) { return this.changeBit(n,op_or); } |
|
||||
|
|
||||
// (public) this & ~(1<<n)
|
|
||||
function bnClearBit(n) { return this.changeBit(n,op_andnot); } |
|
||||
|
|
||||
// (public) this ^ (1<<n)
|
|
||||
function bnFlipBit(n) { return this.changeBit(n,op_xor); } |
|
||||
|
|
||||
// (protected) r = this + a
|
|
||||
function bnpAddTo(a,r) { |
|
||||
var i = 0, c = 0, m = Math.min(a.t,this.t); |
|
||||
while(i < m) { |
|
||||
c += this[i]+a[i]; |
|
||||
r[i++] = c&this.DM; |
|
||||
c >>= this.DB; |
|
||||
} |
|
||||
if(a.t < this.t) { |
|
||||
c += a.s; |
|
||||
while(i < this.t) { |
|
||||
c += this[i]; |
|
||||
r[i++] = c&this.DM; |
|
||||
c >>= this.DB; |
|
||||
} |
|
||||
c += this.s; |
|
||||
} |
|
||||
else { |
|
||||
c += this.s; |
|
||||
while(i < a.t) { |
|
||||
c += a[i]; |
|
||||
r[i++] = c&this.DM; |
|
||||
c >>= this.DB; |
|
||||
} |
|
||||
c += a.s; |
|
||||
} |
|
||||
r.s = (c<0)?-1:0; |
|
||||
if(c > 0) r[i++] = c; |
|
||||
else if(c < -1) r[i++] = this.DV+c; |
|
||||
r.t = i; |
|
||||
r.clamp(); |
|
||||
} |
|
||||
|
|
||||
// (public) this + a
|
|
||||
function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; } |
|
||||
|
|
||||
// (public) this - a
|
|
||||
function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; } |
|
||||
|
|
||||
// (public) this * a
|
|
||||
function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; } |
|
||||
|
|
||||
// (public) this^2
|
|
||||
function bnSquare() { var r = nbi(); this.squareTo(r); return r; } |
|
||||
|
|
||||
// (public) this / a
|
|
||||
function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; } |
|
||||
|
|
||||
// (public) this % a
|
|
||||
function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; } |
|
||||
|
|
||||
// (public) [this/a,this%a]
|
|
||||
function bnDivideAndRemainder(a) { |
|
||||
var q = nbi(), r = nbi(); |
|
||||
this.divRemTo(a,q,r); |
|
||||
return new Array(q,r); |
|
||||
} |
|
||||
|
|
||||
// (protected) this *= n, this >= 0, 1 < n < DV
|
|
||||
function bnpDMultiply(n) { |
|
||||
this[this.t] = this.am(0,n-1,this,0,0,this.t); |
|
||||
++this.t; |
|
||||
this.clamp(); |
|
||||
} |
|
||||
|
|
||||
// (protected) this += n << w words, this >= 0
|
|
||||
function bnpDAddOffset(n,w) { |
|
||||
if(n == 0) return; |
|
||||
while(this.t <= w) this[this.t++] = 0; |
|
||||
this[w] += n; |
|
||||
while(this[w] >= this.DV) { |
|
||||
this[w] -= this.DV; |
|
||||
if(++w >= this.t) this[this.t++] = 0; |
|
||||
++this[w]; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// A "null" reducer
|
|
||||
function NullExp() {} |
|
||||
function nNop(x) { return x; } |
|
||||
function nMulTo(x,y,r) { x.multiplyTo(y,r); } |
|
||||
function nSqrTo(x,r) { x.squareTo(r); } |
|
||||
|
|
||||
NullExp.prototype.convert = nNop; |
|
||||
NullExp.prototype.revert = nNop; |
|
||||
NullExp.prototype.mulTo = nMulTo; |
|
||||
NullExp.prototype.sqrTo = nSqrTo; |
|
||||
|
|
||||
// (public) this^e
|
|
||||
function bnPow(e) { return this.exp(e,new NullExp()); } |
|
||||
|
|
||||
// (protected) r = lower n words of "this * a", a.t <= n
|
|
||||
// "this" should be the larger one if appropriate.
|
|
||||
function bnpMultiplyLowerTo(a,n,r) { |
|
||||
var i = Math.min(this.t+a.t,n); |
|
||||
r.s = 0; // assumes a,this >= 0
|
|
||||
r.t = i; |
|
||||
while(i > 0) r[--i] = 0; |
|
||||
var j; |
|
||||
for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t); |
|
||||
for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i); |
|
||||
r.clamp(); |
|
||||
} |
|
||||
|
|
||||
// (protected) r = "this * a" without lower n words, n > 0
|
|
||||
// "this" should be the larger one if appropriate.
|
|
||||
function bnpMultiplyUpperTo(a,n,r) { |
|
||||
--n; |
|
||||
var i = r.t = this.t+a.t-n; |
|
||||
r.s = 0; // assumes a,this >= 0
|
|
||||
while(--i >= 0) r[i] = 0; |
|
||||
for(i = Math.max(n-this.t,0); i < a.t; ++i) |
|
||||
r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n); |
|
||||
r.clamp(); |
|
||||
r.drShiftTo(1,r); |
|
||||
} |
|
||||
|
|
||||
// Barrett modular reduction
|
|
||||
function Barrett(m) { |
|
||||
// setup Barrett
|
|
||||
this.r2 = nbi(); |
|
||||
this.q3 = nbi(); |
|
||||
BigInteger.ONE.dlShiftTo(2*m.t,this.r2); |
|
||||
this.mu = this.r2.divide(m); |
|
||||
this.m = m; |
|
||||
} |
|
||||
|
|
||||
function barrettConvert(x) { |
|
||||
if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m); |
|
||||
else if(x.compareTo(this.m) < 0) return x; |
|
||||
else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } |
|
||||
} |
|
||||
|
|
||||
function barrettRevert(x) { return x; } |
|
||||
|
|
||||
// x = x mod m (HAC 14.42)
|
|
||||
function barrettReduce(x) { |
|
||||
x.drShiftTo(this.m.t-1,this.r2); |
|
||||
if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); } |
|
||||
this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3); |
|
||||
this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2); |
|
||||
while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1); |
|
||||
x.subTo(this.r2,x); |
|
||||
while(x.compareTo(this.m) >= 0) x.subTo(this.m,x); |
|
||||
} |
|
||||
|
|
||||
// r = x^2 mod m; x != r
|
|
||||
function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); } |
|
||||
|
|
||||
// r = x*y mod m; x,y != r
|
|
||||
function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } |
|
||||
|
|
||||
Barrett.prototype.convert = barrettConvert; |
|
||||
Barrett.prototype.revert = barrettRevert; |
|
||||
Barrett.prototype.reduce = barrettReduce; |
|
||||
Barrett.prototype.mulTo = barrettMulTo; |
|
||||
Barrett.prototype.sqrTo = barrettSqrTo; |
|
||||
|
|
||||
// (public) this^e % m (HAC 14.85)
|
|
||||
function bnModPow(e,m) { |
|
||||
var i = e.bitLength(), k, r = nbv(1), z; |
|
||||
if(i <= 0) return r; |
|
||||
else if(i < 18) k = 1; |
|
||||
else if(i < 48) k = 3; |
|
||||
else if(i < 144) k = 4; |
|
||||
else if(i < 768) k = 5; |
|
||||
else k = 6; |
|
||||
if(i < 8) |
|
||||
z = new Classic(m); |
|
||||
else if(m.isEven()) |
|
||||
z = new Barrett(m); |
|
||||
else |
|
||||
z = new Montgomery(m); |
|
||||
|
|
||||
// precomputation
|
|
||||
var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1; |
|
||||
g[1] = z.convert(this); |
|
||||
if(k > 1) { |
|
||||
var g2 = nbi(); |
|
||||
z.sqrTo(g[1],g2); |
|
||||
while(n <= km) { |
|
||||
g[n] = nbi(); |
|
||||
z.mulTo(g2,g[n-2],g[n]); |
|
||||
n += 2; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
var j = e.t-1, w, is1 = true, r2 = nbi(), t; |
|
||||
i = nbits(e[j])-1; |
|
||||
while(j >= 0) { |
|
||||
if(i >= k1) w = (e[j]>>(i-k1))&km; |
|
||||
else { |
|
||||
w = (e[j]&((1<<(i+1))-1))<<(k1-i); |
|
||||
if(j > 0) w |= e[j-1]>>(this.DB+i-k1); |
|
||||
} |
|
||||
|
|
||||
n = k; |
|
||||
while((w&1) == 0) { w >>= 1; --n; } |
|
||||
if((i -= n) < 0) { i += this.DB; --j; } |
|
||||
if(is1) { // ret == 1, don't bother squaring or multiplying it
|
|
||||
g[w].copyTo(r); |
|
||||
is1 = false; |
|
||||
} |
|
||||
else { |
|
||||
while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } |
|
||||
if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } |
|
||||
z.mulTo(r2,g[w],r); |
|
||||
} |
|
||||
|
|
||||
while(j >= 0 && (e[j]&(1<<i)) == 0) { |
|
||||
z.sqrTo(r,r2); t = r; r = r2; r2 = t; |
|
||||
if(--i < 0) { i = this.DB-1; --j; } |
|
||||
} |
|
||||
} |
|
||||
return z.revert(r); |
|
||||
} |
|
||||
|
|
||||
// (public) gcd(this,a) (HAC 14.54)
|
|
||||
function bnGCD(a) { |
|
||||
var x = (this.s<0)?this.negate():this.clone(); |
|
||||
var y = (a.s<0)?a.negate():a.clone(); |
|
||||
if(x.compareTo(y) < 0) { var t = x; x = y; y = t; } |
|
||||
var i = x.getLowestSetBit(), g = y.getLowestSetBit(); |
|
||||
if(g < 0) return x; |
|
||||
if(i < g) g = i; |
|
||||
if(g > 0) { |
|
||||
x.rShiftTo(g,x); |
|
||||
y.rShiftTo(g,y); |
|
||||
} |
|
||||
while(x.signum() > 0) { |
|
||||
if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); |
|
||||
if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); |
|
||||
if(x.compareTo(y) >= 0) { |
|
||||
x.subTo(y,x); |
|
||||
x.rShiftTo(1,x); |
|
||||
} |
|
||||
else { |
|
||||
y.subTo(x,y); |
|
||||
y.rShiftTo(1,y); |
|
||||
} |
|
||||
} |
|
||||
if(g > 0) y.lShiftTo(g,y); |
|
||||
return y; |
|
||||
} |
|
||||
|
|
||||
// (protected) this % n, n < 2^26
|
|
||||
function bnpModInt(n) { |
|
||||
if(n <= 0) return 0; |
|
||||
var d = this.DV%n, r = (this.s<0)?n-1:0; |
|
||||
if(this.t > 0) |
|
||||
if(d == 0) r = this[0]%n; |
|
||||
else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n; |
|
||||
return r; |
|
||||
} |
|
||||
|
|
||||
// (public) 1/this % m (HAC 14.61)
|
|
||||
function bnModInverse(m) { |
|
||||
var ac = m.isEven(); |
|
||||
if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; |
|
||||
var u = m.clone(), v = this.clone(); |
|
||||
var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); |
|
||||
while(u.signum() != 0) { |
|
||||
while(u.isEven()) { |
|
||||
u.rShiftTo(1,u); |
|
||||
if(ac) { |
|
||||
if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } |
|
||||
a.rShiftTo(1,a); |
|
||||
} |
|
||||
else if(!b.isEven()) b.subTo(m,b); |
|
||||
b.rShiftTo(1,b); |
|
||||
} |
|
||||
while(v.isEven()) { |
|
||||
v.rShiftTo(1,v); |
|
||||
if(ac) { |
|
||||
if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } |
|
||||
c.rShiftTo(1,c); |
|
||||
} |
|
||||
else if(!d.isEven()) d.subTo(m,d); |
|
||||
d.rShiftTo(1,d); |
|
||||
} |
|
||||
if(u.compareTo(v) >= 0) { |
|
||||
u.subTo(v,u); |
|
||||
if(ac) a.subTo(c,a); |
|
||||
b.subTo(d,b); |
|
||||
} |
|
||||
else { |
|
||||
v.subTo(u,v); |
|
||||
if(ac) c.subTo(a,c); |
|
||||
d.subTo(b,d); |
|
||||
} |
|
||||
} |
|
||||
if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; |
|
||||
if(d.compareTo(m) >= 0) return d.subtract(m); |
|
||||
if(d.signum() < 0) d.addTo(m,d); else return d; |
|
||||
if(d.signum() < 0) return d.add(m); else return d; |
|
||||
} |
|
||||
|
|
||||
var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997]; |
|
||||
var lplim = (1<<26)/lowprimes[lowprimes.length-1]; |
|
||||
|
|
||||
// (public) test primality with certainty >= 1-.5^t
|
|
||||
function bnIsProbablePrime(t) { |
|
||||
var i, x = this.abs(); |
|
||||
if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) { |
|
||||
for(i = 0; i < lowprimes.length; ++i) |
|
||||
if(x[0] == lowprimes[i]) return true; |
|
||||
return false; |
|
||||
} |
|
||||
if(x.isEven()) return false; |
|
||||
i = 1; |
|
||||
while(i < lowprimes.length) { |
|
||||
var m = lowprimes[i], j = i+1; |
|
||||
while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; |
|
||||
m = x.modInt(m); |
|
||||
while(i < j) if(m%lowprimes[i++] == 0) return false; |
|
||||
} |
|
||||
return x.millerRabin(t); |
|
||||
} |
|
||||
|
|
||||
// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
|
|
||||
function bnpMillerRabin(t) { |
|
||||
var n1 = this.subtract(BigInteger.ONE); |
|
||||
var k = n1.getLowestSetBit(); |
|
||||
if(k <= 0) return false; |
|
||||
var r = n1.shiftRight(k); |
|
||||
t = (t+1)>>1; |
|
||||
if(t > lowprimes.length) t = lowprimes.length; |
|
||||
var a = nbi(); |
|
||||
for(var i = 0; i < t; ++i) { |
|
||||
//Pick bases at random, instead of starting at 2
|
|
||||
a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]); |
|
||||
var y = a.modPow(r,this); |
|
||||
if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { |
|
||||
var j = 1; |
|
||||
while(j++ < k && y.compareTo(n1) != 0) { |
|
||||
y = y.modPowInt(2,this); |
|
||||
if(y.compareTo(BigInteger.ONE) == 0) return false; |
|
||||
} |
|
||||
if(y.compareTo(n1) != 0) return false; |
|
||||
} |
|
||||
} |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
// protected
|
|
||||
BigInteger.prototype.chunkSize = bnpChunkSize; |
|
||||
BigInteger.prototype.toRadix = bnpToRadix; |
|
||||
BigInteger.prototype.fromRadix = bnpFromRadix; |
|
||||
BigInteger.prototype.fromNumber = bnpFromNumber; |
|
||||
BigInteger.prototype.bitwiseTo = bnpBitwiseTo; |
|
||||
BigInteger.prototype.changeBit = bnpChangeBit; |
|
||||
BigInteger.prototype.addTo = bnpAddTo; |
|
||||
BigInteger.prototype.dMultiply = bnpDMultiply; |
|
||||
BigInteger.prototype.dAddOffset = bnpDAddOffset; |
|
||||
BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo; |
|
||||
BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo; |
|
||||
BigInteger.prototype.modInt = bnpModInt; |
|
||||
BigInteger.prototype.millerRabin = bnpMillerRabin; |
|
||||
|
|
||||
// public
|
|
||||
BigInteger.prototype.clone = bnClone; |
|
||||
BigInteger.prototype.intValue = bnIntValue; |
|
||||
BigInteger.prototype.byteValue = bnByteValue; |
|
||||
BigInteger.prototype.shortValue = bnShortValue; |
|
||||
BigInteger.prototype.signum = bnSigNum; |
|
||||
BigInteger.prototype.toByteArray = bnToByteArray; |
|
||||
BigInteger.prototype.equals = bnEquals; |
|
||||
BigInteger.prototype.min = bnMin; |
|
||||
BigInteger.prototype.max = bnMax; |
|
||||
BigInteger.prototype.and = bnAnd; |
|
||||
BigInteger.prototype.or = bnOr; |
|
||||
BigInteger.prototype.xor = bnXor; |
|
||||
BigInteger.prototype.andNot = bnAndNot; |
|
||||
BigInteger.prototype.not = bnNot; |
|
||||
BigInteger.prototype.shiftLeft = bnShiftLeft; |
|
||||
BigInteger.prototype.shiftRight = bnShiftRight; |
|
||||
BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit; |
|
||||
BigInteger.prototype.bitCount = bnBitCount; |
|
||||
BigInteger.prototype.testBit = bnTestBit; |
|
||||
BigInteger.prototype.setBit = bnSetBit; |
|
||||
BigInteger.prototype.clearBit = bnClearBit; |
|
||||
BigInteger.prototype.flipBit = bnFlipBit; |
|
||||
BigInteger.prototype.add = bnAdd; |
|
||||
BigInteger.prototype.subtract = bnSubtract; |
|
||||
BigInteger.prototype.multiply = bnMultiply; |
|
||||
BigInteger.prototype.divide = bnDivide; |
|
||||
BigInteger.prototype.remainder = bnRemainder; |
|
||||
BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder; |
|
||||
BigInteger.prototype.modPow = bnModPow; |
|
||||
BigInteger.prototype.modInverse = bnModInverse; |
|
||||
BigInteger.prototype.pow = bnPow; |
|
||||
BigInteger.prototype.gcd = bnGCD; |
|
||||
BigInteger.prototype.isProbablePrime = bnIsProbablePrime; |
|
||||
|
|
||||
// JSBN-specific extension
|
|
||||
BigInteger.prototype.square = bnSquare; |
|
||||
|
|
||||
// BigInteger interfaces not implemented in jsbn:
|
|
||||
|
|
||||
// BigInteger(int signum, byte[] magnitude)
|
|
||||
// double doubleValue()
|
|
||||
// float floatValue()
|
|
||||
// int hashCode()
|
|
||||
// long longValue()
|
|
||||
// static BigInteger valueOf(long val)
|
|
@ -1,69 +1,68 @@ |
|||||
/** |
/// Implements Bitcoin's feature for signing arbitrary messages.
|
||||
* Implements Bitcoin's feature for signing arbitrary messages. |
|
||||
*/ |
|
||||
Bitcoin.Message = (function () { |
|
||||
var Message = {}; |
|
||||
|
|
||||
Message.magicPrefix = "Bitcoin Signed Message:\n"; |
var Crypto = require('./crypto-js/crypto'); |
||||
|
var ecdsa = require('./ecdsa'); |
||||
|
var conv = require('./convert'); |
||||
|
var util = require('./util'); |
||||
|
|
||||
Message.makeMagicMessage = function (message) { |
var Message = {}; |
||||
var magicBytes = Crypto.charenc.UTF8.stringToBytes(Message.magicPrefix); |
|
||||
var messageBytes = Crypto.charenc.UTF8.stringToBytes(message); |
|
||||
|
|
||||
var buffer = []; |
Message.magicPrefix = "Bitcoin Signed Message:\n"; |
||||
buffer = buffer.concat(Bitcoin.Util.numToVarInt(magicBytes.length)); |
|
||||
buffer = buffer.concat(magicBytes); |
|
||||
buffer = buffer.concat(Bitcoin.Util.numToVarInt(messageBytes.length)); |
|
||||
buffer = buffer.concat(messageBytes); |
|
||||
|
|
||||
return buffer; |
Message.makeMagicMessage = function (message) { |
||||
}; |
var magicBytes = conv.stringToBytes(Message.magicPrefix); |
||||
|
var messageBytes = conv.stringToBytes(message); |
||||
|
|
||||
Message.getHash = function (message) { |
var buffer = []; |
||||
var buffer = Message.makeMagicMessage(message); |
buffer = buffer.concat(util.numToVarInt(magicBytes.length)); |
||||
return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true}); |
buffer = buffer.concat(magicBytes); |
||||
}; |
buffer = buffer.concat(util.numToVarInt(messageBytes.length)); |
||||
|
buffer = buffer.concat(messageBytes); |
||||
|
|
||||
Message.signMessage = function (key, message, compressed) { |
return buffer; |
||||
var hash = Message.getHash(message); |
}; |
||||
|
|
||||
var sig = key.sign(hash); |
Message.getHash = function (message) { |
||||
|
var buffer = Message.makeMagicMessage(message); |
||||
|
return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true}); |
||||
|
}; |
||||
|
|
||||
var obj = Bitcoin.ECDSA.parseSig(sig); |
Message.signMessage = function (key, message, compressed) { |
||||
|
var hash = Message.getHash(message); |
||||
|
|
||||
var address = key.getBitcoinAddress().toString(); |
var sig = key.sign(hash); |
||||
var i = Bitcoin.ECDSA.calcPubkeyRecoveryParam(address, obj.r, obj.s, hash); |
|
||||
|
|
||||
i += 27; |
var obj = ecdsa.parseSig(sig); |
||||
if (compressed) i += 4; |
|
||||
|
|
||||
var rBa = obj.r.toByteArrayUnsigned(); |
var i = ecdsa.calcPubkeyRecoveryParam(key, obj.r, obj.s, hash); |
||||
var sBa = obj.s.toByteArrayUnsigned(); |
|
||||
|
|
||||
// Pad to 32 bytes per value
|
i += 27; |
||||
while (rBa.length < 32) rBa.unshift(0); |
if (compressed) i += 4; |
||||
while (sBa.length < 32) sBa.unshift(0); |
|
||||
|
|
||||
sig = [i].concat(rBa).concat(sBa); |
var rBa = obj.r.toByteArrayUnsigned(); |
||||
|
var sBa = obj.s.toByteArrayUnsigned(); |
||||
|
|
||||
return Crypto.util.bytesToBase64(sig); |
// Pad to 32 bytes per value
|
||||
}; |
while (rBa.length < 32) rBa.unshift(0); |
||||
|
while (sBa.length < 32) sBa.unshift(0); |
||||
|
|
||||
Message.verifyMessage = function (address, sig, message) { |
sig = [i].concat(rBa).concat(sBa); |
||||
sig = Crypto.util.base64ToBytes(sig); |
|
||||
sig = Bitcoin.ECDSA.parseSigCompact(sig); |
|
||||
|
|
||||
var hash = Message.getHash(message); |
return conv.bytesToHex(sig); |
||||
|
}; |
||||
|
|
||||
var isCompressed = !!(sig.i & 4); |
Message.verifyMessage = function (address, sig, message) { |
||||
var pubKey = Bitcoin.ECDSA.recoverPubKey(sig.r, sig.s, hash, sig.i); |
sig = conv.hexToBytes(sig); |
||||
|
sig = ecdsa.parseSigCompact(sig); |
||||
|
|
||||
pubKey.setCompressed(isCompressed); |
var hash = Message.getHash(message); |
||||
|
|
||||
var expectedAddress = pubKey.getBitcoinAddress().toString(); |
var isCompressed = !!(sig.i & 4); |
||||
|
var pubKey = ecdsa.recoverPubKey(sig.r, sig.s, hash, sig.i); |
||||
|
|
||||
return (address === expectedAddress); |
var expectedAddress = pubKey.getBitcoinAddress().toString(); |
||||
}; |
|
||||
|
|
||||
return Message; |
return (address === expectedAddress); |
||||
})(); |
}; |
||||
|
|
||||
|
module.exports = Message; |
||||
|
@ -1,154 +1,154 @@ |
|||||
(function () { |
var Opcode = function (num) { |
||||
var Opcode = Bitcoin.Opcode = function (num) { |
this.code = num; |
||||
this.code = num; |
}; |
||||
}; |
|
||||
|
Opcode.prototype.toString = function () { |
||||
Opcode.prototype.toString = function () { |
return Opcode.reverseMap[this.code]; |
||||
return Opcode.reverseMap[this.code]; |
}; |
||||
}; |
|
||||
|
Opcode.map = { |
||||
Opcode.map = { |
// push value
|
||||
// push value
|
OP_0 : 0, |
||||
OP_0 : 0, |
OP_FALSE : 0, |
||||
OP_FALSE : 0, |
OP_PUSHDATA1 : 76, |
||||
OP_PUSHDATA1 : 76, |
OP_PUSHDATA2 : 77, |
||||
OP_PUSHDATA2 : 77, |
OP_PUSHDATA4 : 78, |
||||
OP_PUSHDATA4 : 78, |
OP_1NEGATE : 79, |
||||
OP_1NEGATE : 79, |
OP_RESERVED : 80, |
||||
OP_RESERVED : 80, |
OP_1 : 81, |
||||
OP_1 : 81, |
OP_TRUE : 81, |
||||
OP_TRUE : 81, |
OP_2 : 82, |
||||
OP_2 : 82, |
OP_3 : 83, |
||||
OP_3 : 83, |
OP_4 : 84, |
||||
OP_4 : 84, |
OP_5 : 85, |
||||
OP_5 : 85, |
OP_6 : 86, |
||||
OP_6 : 86, |
OP_7 : 87, |
||||
OP_7 : 87, |
OP_8 : 88, |
||||
OP_8 : 88, |
OP_9 : 89, |
||||
OP_9 : 89, |
OP_10 : 90, |
||||
OP_10 : 90, |
OP_11 : 91, |
||||
OP_11 : 91, |
OP_12 : 92, |
||||
OP_12 : 92, |
OP_13 : 93, |
||||
OP_13 : 93, |
OP_14 : 94, |
||||
OP_14 : 94, |
OP_15 : 95, |
||||
OP_15 : 95, |
OP_16 : 96, |
||||
OP_16 : 96, |
|
||||
|
// control
|
||||
// control
|
OP_NOP : 97, |
||||
OP_NOP : 97, |
OP_VER : 98, |
||||
OP_VER : 98, |
OP_IF : 99, |
||||
OP_IF : 99, |
OP_NOTIF : 100, |
||||
OP_NOTIF : 100, |
OP_VERIF : 101, |
||||
OP_VERIF : 101, |
OP_VERNOTIF : 102, |
||||
OP_VERNOTIF : 102, |
OP_ELSE : 103, |
||||
OP_ELSE : 103, |
OP_ENDIF : 104, |
||||
OP_ENDIF : 104, |
OP_VERIFY : 105, |
||||
OP_VERIFY : 105, |
OP_RETURN : 106, |
||||
OP_RETURN : 106, |
|
||||
|
// stack ops
|
||||
// stack ops
|
OP_TOALTSTACK : 107, |
||||
OP_TOALTSTACK : 107, |
OP_FROMALTSTACK : 108, |
||||
OP_FROMALTSTACK : 108, |
OP_2DROP : 109, |
||||
OP_2DROP : 109, |
OP_2DUP : 110, |
||||
OP_2DUP : 110, |
OP_3DUP : 111, |
||||
OP_3DUP : 111, |
OP_2OVER : 112, |
||||
OP_2OVER : 112, |
OP_2ROT : 113, |
||||
OP_2ROT : 113, |
OP_2SWAP : 114, |
||||
OP_2SWAP : 114, |
OP_IFDUP : 115, |
||||
OP_IFDUP : 115, |
OP_DEPTH : 116, |
||||
OP_DEPTH : 116, |
OP_DROP : 117, |
||||
OP_DROP : 117, |
OP_DUP : 118, |
||||
OP_DUP : 118, |
OP_NIP : 119, |
||||
OP_NIP : 119, |
OP_OVER : 120, |
||||
OP_OVER : 120, |
OP_PICK : 121, |
||||
OP_PICK : 121, |
OP_ROLL : 122, |
||||
OP_ROLL : 122, |
OP_ROT : 123, |
||||
OP_ROT : 123, |
OP_SWAP : 124, |
||||
OP_SWAP : 124, |
OP_TUCK : 125, |
||||
OP_TUCK : 125, |
|
||||
|
// splice ops
|
||||
// splice ops
|
OP_CAT : 126, |
||||
OP_CAT : 126, |
OP_SUBSTR : 127, |
||||
OP_SUBSTR : 127, |
OP_LEFT : 128, |
||||
OP_LEFT : 128, |
OP_RIGHT : 129, |
||||
OP_RIGHT : 129, |
OP_SIZE : 130, |
||||
OP_SIZE : 130, |
|
||||
|
// bit logic
|
||||
// bit logic
|
OP_INVERT : 131, |
||||
OP_INVERT : 131, |
OP_AND : 132, |
||||
OP_AND : 132, |
OP_OR : 133, |
||||
OP_OR : 133, |
OP_XOR : 134, |
||||
OP_XOR : 134, |
OP_EQUAL : 135, |
||||
OP_EQUAL : 135, |
OP_EQUALVERIFY : 136, |
||||
OP_EQUALVERIFY : 136, |
OP_RESERVED1 : 137, |
||||
OP_RESERVED1 : 137, |
OP_RESERVED2 : 138, |
||||
OP_RESERVED2 : 138, |
|
||||
|
// numeric
|
||||
// numeric
|
OP_1ADD : 139, |
||||
OP_1ADD : 139, |
OP_1SUB : 140, |
||||
OP_1SUB : 140, |
OP_2MUL : 141, |
||||
OP_2MUL : 141, |
OP_2DIV : 142, |
||||
OP_2DIV : 142, |
OP_NEGATE : 143, |
||||
OP_NEGATE : 143, |
OP_ABS : 144, |
||||
OP_ABS : 144, |
OP_NOT : 145, |
||||
OP_NOT : 145, |
OP_0NOTEQUAL : 146, |
||||
OP_0NOTEQUAL : 146, |
|
||||
|
OP_ADD : 147, |
||||
OP_ADD : 147, |
OP_SUB : 148, |
||||
OP_SUB : 148, |
OP_MUL : 149, |
||||
OP_MUL : 149, |
OP_DIV : 150, |
||||
OP_DIV : 150, |
OP_MOD : 151, |
||||
OP_MOD : 151, |
OP_LSHIFT : 152, |
||||
OP_LSHIFT : 152, |
OP_RSHIFT : 153, |
||||
OP_RSHIFT : 153, |
|
||||
|
OP_BOOLAND : 154, |
||||
OP_BOOLAND : 154, |
OP_BOOLOR : 155, |
||||
OP_BOOLOR : 155, |
OP_NUMEQUAL : 156, |
||||
OP_NUMEQUAL : 156, |
OP_NUMEQUALVERIFY : 157, |
||||
OP_NUMEQUALVERIFY : 157, |
OP_NUMNOTEQUAL : 158, |
||||
OP_NUMNOTEQUAL : 158, |
OP_LESSTHAN : 159, |
||||
OP_LESSTHAN : 159, |
OP_GREATERTHAN : 160, |
||||
OP_GREATERTHAN : 160, |
OP_LESSTHANOREQUAL : 161, |
||||
OP_LESSTHANOREQUAL : 161, |
OP_GREATERTHANOREQUAL : 162, |
||||
OP_GREATERTHANOREQUAL : 162, |
OP_MIN : 163, |
||||
OP_MIN : 163, |
OP_MAX : 164, |
||||
OP_MAX : 164, |
|
||||
|
OP_WITHIN : 165, |
||||
OP_WITHIN : 165, |
|
||||
|
// crypto
|
||||
// crypto
|
OP_RIPEMD160 : 166, |
||||
OP_RIPEMD160 : 166, |
OP_SHA1 : 167, |
||||
OP_SHA1 : 167, |
OP_SHA256 : 168, |
||||
OP_SHA256 : 168, |
OP_HASH160 : 169, |
||||
OP_HASH160 : 169, |
OP_HASH256 : 170, |
||||
OP_HASH256 : 170, |
OP_CODESEPARATOR : 171, |
||||
OP_CODESEPARATOR : 171, |
OP_CHECKSIG : 172, |
||||
OP_CHECKSIG : 172, |
OP_CHECKSIGVERIFY : 173, |
||||
OP_CHECKSIGVERIFY : 173, |
OP_CHECKMULTISIG : 174, |
||||
OP_CHECKMULTISIG : 174, |
OP_CHECKMULTISIGVERIFY : 175, |
||||
OP_CHECKMULTISIGVERIFY : 175, |
|
||||
|
// expansion
|
||||
// expansion
|
OP_NOP1 : 176, |
||||
OP_NOP1 : 176, |
OP_NOP2 : 177, |
||||
OP_NOP2 : 177, |
OP_NOP3 : 178, |
||||
OP_NOP3 : 178, |
OP_NOP4 : 179, |
||||
OP_NOP4 : 179, |
OP_NOP5 : 180, |
||||
OP_NOP5 : 180, |
OP_NOP6 : 181, |
||||
OP_NOP6 : 181, |
OP_NOP7 : 182, |
||||
OP_NOP7 : 182, |
OP_NOP8 : 183, |
||||
OP_NOP8 : 183, |
OP_NOP9 : 184, |
||||
OP_NOP9 : 184, |
OP_NOP10 : 185, |
||||
OP_NOP10 : 185, |
|
||||
|
// template matching params
|
||||
// template matching params
|
OP_PUBKEYHASH : 253, |
||||
OP_PUBKEYHASH : 253, |
OP_PUBKEY : 254, |
||||
OP_PUBKEY : 254, |
OP_INVALIDOPCODE : 255 |
||||
OP_INVALIDOPCODE : 255 |
}; |
||||
}; |
|
||||
|
Opcode.reverseMap = []; |
||||
Opcode.reverseMap = []; |
|
||||
|
for (var i in Opcode.map) { |
||||
for (var i in Opcode.map) { |
Opcode.reverseMap[Opcode.map[i]] = i; |
||||
Opcode.reverseMap[Opcode.map[i]] = i; |
} |
||||
} |
|
||||
})(); |
module.exports = Opcode; |
||||
|
@ -1,347 +1,382 @@ |
|||||
(function () { |
var Opcode = require('./opcode'); |
||||
var Opcode = Bitcoin.Opcode; |
var util = require('./util'); |
||||
|
var conv = require('./convert'); |
||||
|
var Address = require('./address'); |
||||
|
|
||||
// Make opcodes available as pseudo-constants
|
var Script = function (data) { |
||||
for (var i in Opcode.map) { |
if (!data) { |
||||
eval("var " + i + " = " + Opcode.map[i] + ";"); |
this.buffer = []; |
||||
|
} else if ("string" == typeof data) { |
||||
|
this.buffer = conv.hexToBytes(data); |
||||
|
} else if (util.isArray(data)) { |
||||
|
this.buffer = data; |
||||
|
} else if (data instanceof Script) { |
||||
|
this.buffer = data.buffer; |
||||
|
} else { |
||||
|
throw new Error("Invalid script"); |
||||
} |
} |
||||
|
|
||||
var Script = Bitcoin.Script = function (data) { |
this.parse(); |
||||
if (!data) { |
}; |
||||
this.buffer = []; |
|
||||
} else if ("string" == typeof data) { |
Script.fromPubKey = function(str) { |
||||
this.buffer = Crypto.util.base64ToBytes(data); |
var script = new Script(); |
||||
} else if (Bitcoin.Util.isArray(data)) { |
var s = str.split(" "); |
||||
this.buffer = data; |
for (var i in s) { |
||||
} else if (data instanceof Script) { |
if (Opcode.map.hasOwnProperty(s[i])){ |
||||
this.buffer = data.buffer; |
script.writeOp(Opcode.map[s[i]]); |
||||
} else { |
} else { |
||||
throw new Error("Invalid script"); |
script.writeBytes(conv.hexToBytes(s[i])); |
||||
} |
} |
||||
|
} |
||||
|
return script; |
||||
|
}; |
||||
|
|
||||
this.parse(); |
Script.fromScriptSig = function(str) { |
||||
}; |
var script = new Script(); |
||||
|
var s = str.split(" "); |
||||
|
for (var i in s) { |
||||
|
if (Opcode.map.hasOwnProperty(s[i])){ |
||||
|
script.writeOp(Opcode.map[s[i]]); |
||||
|
} else { |
||||
|
script.writeBytes(conv.hexToBytes(s[i])); |
||||
|
} |
||||
|
} |
||||
|
return script; |
||||
|
}; |
||||
|
|
||||
/** |
/** |
||||
* Update the parsed script representation. |
* Update the parsed script representation. |
||||
* |
* |
||||
* Each Script object stores the script in two formats. First as a raw byte |
* Each Script object stores the script in two formats. First as a raw byte |
||||
* array and second as an array of "chunks", such as opcodes and pieces of |
* array and second as an array of "chunks", such as opcodes and pieces of |
||||
* data. |
* data. |
||||
* |
* |
||||
* This method updates the chunks cache. Normally this is called by the |
* This method updates the chunks cache. Normally this is called by the |
||||
* constructor and you don't need to worry about it. However, if you change |
* constructor and you don't need to worry about it. However, if you change |
||||
* the script buffer manually, you should update the chunks using this method. |
* the script buffer manually, you should update the chunks using this method. |
||||
*/ |
*/ |
||||
Script.prototype.parse = function () { |
Script.prototype.parse = function () { |
||||
var self = this; |
var self = this; |
||||
|
|
||||
this.chunks = []; |
this.chunks = []; |
||||
|
|
||||
// Cursor
|
// Cursor
|
||||
var i = 0; |
var i = 0; |
||||
|
|
||||
// Read n bytes and store result as a chunk
|
// Read n bytes and store result as a chunk
|
||||
function readChunk(n) { |
function readChunk(n) { |
||||
self.chunks.push(self.buffer.slice(i, i + n)); |
self.chunks.push(self.buffer.slice(i, i + n)); |
||||
i += n; |
i += n; |
||||
}; |
}; |
||||
|
|
||||
while (i < this.buffer.length) { |
while (i < this.buffer.length) { |
||||
var opcode = this.buffer[i++]; |
var opcode = this.buffer[i++]; |
||||
if (opcode >= 0xF0) { |
if (opcode >= 0xF0) { |
||||
// Two byte opcode
|
// Two byte opcode
|
||||
opcode = (opcode << 8) | this.buffer[i++]; |
opcode = (opcode << 8) | this.buffer[i++]; |
||||
} |
} |
||||
|
|
||||
var len; |
var len; |
||||
if (opcode > 0 && opcode < OP_PUSHDATA1) { |
if (opcode > 0 && opcode < Opcode.map.OP_PUSHDATA1) { |
||||
// Read some bytes of data, opcode value is the length of data
|
// Read some bytes of data, opcode value is the length of data
|
||||
readChunk(opcode); |
readChunk(opcode); |
||||
} else if (opcode == OP_PUSHDATA1) { |
} else if (opcode == Opcode.map.OP_PUSHDATA1) { |
||||
len = this.buffer[i++]; |
len = this.buffer[i++]; |
||||
readChunk(len); |
readChunk(len); |
||||
} else if (opcode == OP_PUSHDATA2) { |
} else if (opcode == Opcode.map.OP_PUSHDATA2) { |
||||
len = (this.buffer[i++] << 8) | this.buffer[i++]; |
len = (this.buffer[i++] << 8) | this.buffer[i++]; |
||||
readChunk(len); |
readChunk(len); |
||||
} else if (opcode == OP_PUSHDATA4) { |
} else if (opcode == Opcode.map.OP_PUSHDATA4) { |
||||
len = (this.buffer[i++] << 24) | |
len = (this.buffer[i++] << 24) | |
||||
(this.buffer[i++] << 16) | |
(this.buffer[i++] << 16) | |
||||
(this.buffer[i++] << 8) | |
(this.buffer[i++] << 8) | |
||||
this.buffer[i++]; |
this.buffer[i++]; |
||||
readChunk(len); |
readChunk(len); |
||||
} else { |
} else { |
||||
this.chunks.push(opcode); |
this.chunks.push(opcode); |
||||
} |
|
||||
} |
} |
||||
}; |
} |
||||
|
}; |
||||
|
|
||||
/** |
/** |
||||
* Compare the script to known templates of scriptPubKey. |
* Compare the script to known templates of scriptPubKey. |
||||
* |
* |
||||
* This method will compare the script to a small number of standard script |
* This method will compare the script to a small number of standard script |
||||
* templates and return a string naming the detected type. |
* templates and return a string naming the detected type. |
||||
* |
* |
||||
* Currently supported are: |
* Currently supported are: |
||||
* Address: |
* Address: |
||||
* Paying to a Bitcoin address which is the hash of a pubkey. |
* Paying to a Bitcoin address which is the hash of a pubkey. |
||||
* OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG |
* OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG |
||||
* |
* |
||||
* Pubkey: |
* Pubkey: |
||||
* Paying to a public key directly. |
* Paying to a public key directly. |
||||
* [pubKey] OP_CHECKSIG |
* [pubKey] OP_CHECKSIG |
||||
* |
* |
||||
* Strange: |
* Strange: |
||||
* Any other script (no template matched). |
* Any other script (no template matched). |
||||
*/ |
*/ |
||||
Script.prototype.getOutType = function () { |
Script.prototype.getOutType = function () { |
||||
|
if (this.chunks[this.chunks.length-1] == Opcode.map.OP_EQUAL && |
||||
|
this.chunks[0] == Opcode.map.OP_HASH160 && |
||||
|
this.chunks.length == 3) { |
||||
|
// Transfer to M-OF-N
|
||||
|
return 'P2SH'; |
||||
|
} |
||||
|
else if (this.chunks.length == 5 && |
||||
|
this.chunks[0] == Opcode.map.OP_DUP && |
||||
|
this.chunks[1] == Opcode.map.OP_HASH160 && |
||||
|
this.chunks[3] == Opcode.map.OP_EQUALVERIFY && |
||||
|
this.chunks[4] == Opcode.map.OP_CHECKSIG) { |
||||
|
// Transfer to Bitcoin address
|
||||
|
return 'Pubkey'; |
||||
|
} |
||||
|
else { |
||||
|
return 'Strange'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
if (this.chunks[this.chunks.length-1] == OP_CHECKMULTISIG && this.chunks[this.chunks.length-2] <= 3) { |
/** |
||||
// Transfer to M-OF-N
|
* Returns the address corresponding to this output in hash160 form. |
||||
return 'Multisig'; |
* Assumes strange scripts are P2SH |
||||
} else if (this.chunks.length == 5 && |
*/ |
||||
this.chunks[0] == OP_DUP && |
Script.prototype.toScriptHash = function () { |
||||
this.chunks[1] == OP_HASH160 && |
var outType = this.getOutType(); |
||||
this.chunks[3] == OP_EQUALVERIFY && |
|
||||
this.chunks[4] == OP_CHECKSIG) { |
return outType == 'Pubkey' ? this.chunks[2] |
||||
// Transfer to Bitcoin address
|
: outType == 'P2SH' ? util.sha256ripe160(this.buffer) |
||||
return 'Address'; |
: util.sha256ripe160(this.buffer) |
||||
} else if (this.chunks.length == 2 && |
}; |
||||
this.chunks[1] == OP_CHECKSIG) { |
|
||||
// Transfer to IP address
|
Script.prototype.toAddress = function() { |
||||
|
var outType = this.getOutType(); |
||||
|
return outType == 'Pubkey' ? new Address(this.chunks[2]) |
||||
|
: outType == 'P2SH' ? new Address(this.chunks[1],5) |
||||
|
: new Address(this.chunks[1],5) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Compare the script to known templates of scriptSig. |
||||
|
* |
||||
|
* This method will compare the script to a small number of standard script |
||||
|
* templates and return a string naming the detected type. |
||||
|
* |
||||
|
* WARNING: Use this method with caution. It merely represents a heuristic |
||||
|
* based on common transaction formats. A non-standard transaction could |
||||
|
* very easily match one of these templates by accident. |
||||
|
* |
||||
|
* Currently supported are: |
||||
|
* Address: |
||||
|
* Paying to a Bitcoin address which is the hash of a pubkey. |
||||
|
* [sig] [pubKey] |
||||
|
* |
||||
|
* Pubkey: |
||||
|
* Paying to a public key directly. |
||||
|
* [sig] |
||||
|
* |
||||
|
* Multisig: |
||||
|
* Paying to M-of-N public keys. |
||||
|
* |
||||
|
* Strange: |
||||
|
* Any other script (no template matched). |
||||
|
*/ |
||||
|
Script.prototype.getInType = function () |
||||
|
{ |
||||
|
if (this.chunks.length == 1 && |
||||
|
util.isArray(this.chunks[0])) { |
||||
|
// Direct IP to IP transactions only have the signature in their scriptSig.
|
||||
|
// TODO: We could also check that the length of the data is correct.
|
||||
return 'Pubkey'; |
return 'Pubkey'; |
||||
|
} else if (this.chunks.length == 2 && |
||||
|
util.isArray(this.chunks[0]) && |
||||
|
util.isArray(this.chunks[1])) { |
||||
|
return 'Address'; |
||||
|
} else if (this.chunks[0] == Opcode.map.OP_0 && |
||||
|
this.chunks.slice(1).reduce(function(t,chunk,i) { |
||||
|
return t && util.isArray(chunk) |
||||
|
&& (chunk[0] == 48 || i == this.chunks.length - 1); |
||||
|
},true)) { |
||||
|
return 'Multisig'; |
||||
} else { |
} else { |
||||
return 'Strange'; |
return 'Strange'; |
||||
} |
} |
||||
} |
}; |
||||
|
|
||||
/** |
/** |
||||
* Returns the affected address hash for this output. |
* Returns the affected public key for this input. |
||||
* |
* |
||||
* For standard transactions, this will return the hash of the pubKey that |
* This currently only works with payToPubKeyHash transactions. It will also |
||||
* can spend this output. |
* work in the future for standard payToScriptHash transactions that use a |
||||
* |
* single public key. |
||||
* In the future, for payToScriptHash outputs, this will return the |
* |
||||
* scriptHash. Note that non-standard and standard payToScriptHash transactions |
* However for multi-key and other complex transactions, this will only return |
||||
* look the same |
* one of the keys or raise an error. Therefore, it is recommended for indexing |
||||
* |
* purposes to use Script#simpleInHash or Script#simpleOutHash instead. |
||||
* This method is useful for indexing transactions. |
* |
||||
*/ |
* @deprecated |
||||
Script.prototype.simpleOutHash = function () |
*/ |
||||
{ |
Script.prototype.simpleInPubKey = function () |
||||
switch (this.getOutType()) { |
{ |
||||
case 'Address': |
switch (this.getInType()) { |
||||
return this.chunks[2]; |
case 'Address': |
||||
case 'Pubkey': |
return this.chunks[1]; |
||||
return Bitcoin.Util.sha256ripe160(this.chunks[0]); |
case 'Pubkey': |
||||
default: |
// TODO: Theoretically, we could recover the pubkey from the sig here.
|
||||
throw new Error("Encountered non-standard scriptPubKey"); |
// See https://bitcointalk.org/?topic=6430.0
|
||||
} |
throw new Error("Script does not contain pubkey."); |
||||
}; |
default: |
||||
|
throw new Error("Encountered non-standard scriptSig"); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
/** |
/** |
||||
* Old name for Script#simpleOutHash. |
* Returns the affected address hash for this input. |
||||
* |
* |
||||
* @deprecated |
* For standard transactions, this will return the hash of the pubKey that |
||||
*/ |
* can spend this output. |
||||
Script.prototype.simpleOutPubKeyHash = Script.prototype.simpleOutHash; |
* |
||||
|
* In the future, for standard payToScriptHash inputs, this will return the |
||||
|
* scriptHash. |
||||
|
* |
||||
|
* Note: This function provided for convenience. If you have the corresponding |
||||
|
* scriptPubKey available, you are urged to use Script#simpleOutHash instead |
||||
|
* as it is more reliable for non-standard payToScriptHash transactions. |
||||
|
* |
||||
|
* This method is useful for indexing transactions. |
||||
|
*/ |
||||
|
Script.prototype.simpleInHash = function () |
||||
|
{ |
||||
|
return util.sha256ripe160(this.simpleInPubKey()); |
||||
|
}; |
||||
|
|
||||
/** |
/** |
||||
* Compare the script to known templates of scriptSig. |
* Old name for Script#simpleInHash. |
||||
* |
* |
||||
* This method will compare the script to a small number of standard script |
* @deprecated |
||||
* templates and return a string naming the detected type. |
*/ |
||||
* |
Script.prototype.simpleInPubKeyHash = Script.prototype.simpleInHash; |
||||
* WARNING: Use this method with caution. It merely represents a heuristic |
|
||||
* based on common transaction formats. A non-standard transaction could |
|
||||
* very easily match one of these templates by accident. |
|
||||
* |
|
||||
* Currently supported are: |
|
||||
* Address: |
|
||||
* Paying to a Bitcoin address which is the hash of a pubkey. |
|
||||
* [sig] [pubKey] |
|
||||
* |
|
||||
* Pubkey: |
|
||||
* Paying to a public key directly. |
|
||||
* [sig] |
|
||||
* |
|
||||
* Strange: |
|
||||
* Any other script (no template matched). |
|
||||
*/ |
|
||||
Script.prototype.getInType = function () |
|
||||
{ |
|
||||
if (this.chunks.length == 1 && |
|
||||
Bitcoin.Util.isArray(this.chunks[0])) { |
|
||||
// Direct IP to IP transactions only have the signature in their scriptSig.
|
|
||||
// TODO: We could also check that the length of the data is correct.
|
|
||||
return 'Pubkey'; |
|
||||
} else if (this.chunks.length == 2 && |
|
||||
Bitcoin.Util.isArray(this.chunks[0]) && |
|
||||
Bitcoin.Util.isArray(this.chunks[1])) { |
|
||||
return 'Address'; |
|
||||
} else { |
|
||||
return 'Strange'; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** |
/** |
||||
* Returns the affected public key for this input. |
* Add an op code to the script. |
||||
* |
*/ |
||||
* This currently only works with payToPubKeyHash transactions. It will also |
Script.prototype.writeOp = function (opcode) |
||||
* work in the future for standard payToScriptHash transactions that use a |
{ |
||||
* single public key. |
this.buffer.push(opcode); |
||||
* |
this.chunks.push(opcode); |
||||
* However for multi-key and other complex transactions, this will only return |
}; |
||||
* one of the keys or raise an error. Therefore, it is recommended for indexing |
|
||||
* purposes to use Script#simpleInHash or Script#simpleOutHash instead. |
|
||||
* |
|
||||
* @deprecated |
|
||||
*/ |
|
||||
Script.prototype.simpleInPubKey = function () |
|
||||
{ |
|
||||
switch (this.getInType()) { |
|
||||
case 'Address': |
|
||||
return this.chunks[1]; |
|
||||
case 'Pubkey': |
|
||||
// TODO: Theoretically, we could recover the pubkey from the sig here.
|
|
||||
// See https://bitcointalk.org/?topic=6430.0
|
|
||||
throw new Error("Script does not contain pubkey."); |
|
||||
default: |
|
||||
throw new Error("Encountered non-standard scriptSig"); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** |
/** |
||||
* Returns the affected address hash for this input. |
* Add a data chunk to the script. |
||||
* |
*/ |
||||
* For standard transactions, this will return the hash of the pubKey that |
Script.prototype.writeBytes = function (data) |
||||
* can spend this output. |
{ |
||||
* |
if (data.length < Opcode.map.OP_PUSHDATA1) { |
||||
* In the future, for standard payToScriptHash inputs, this will return the |
this.buffer.push(data.length); |
||||
* scriptHash. |
} else if (data.length <= 0xff) { |
||||
* |
this.buffer.push(Opcode.map.OP_PUSHDATA1); |
||||
* Note: This function provided for convenience. If you have the corresponding |
this.buffer.push(data.length); |
||||
* scriptPubKey available, you are urged to use Script#simpleOutHash instead |
} else if (data.length <= 0xffff) { |
||||
* as it is more reliable for non-standard payToScriptHash transactions. |
this.buffer.push(Opcode.map.OP_PUSHDATA2); |
||||
* |
this.buffer.push(data.length & 0xff); |
||||
* This method is useful for indexing transactions. |
this.buffer.push((data.length >>> 8) & 0xff); |
||||
*/ |
} else { |
||||
Script.prototype.simpleInHash = function () |
this.buffer.push(Opcode.map.OP_PUSHDATA4); |
||||
{ |
this.buffer.push(data.length & 0xff); |
||||
return Bitcoin.Util.sha256ripe160(this.simpleInPubKey()); |
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); |
||||
|
}; |
||||
|
|
||||
/** |
/** |
||||
* Old name for Script#simpleInHash. |
* Create an output for an address |
||||
* |
*/ |
||||
* @deprecated |
Script.createOutputScript = function (address) |
||||
*/ |
{ |
||||
Script.prototype.simpleInPubKeyHash = Script.prototype.simpleInHash; |
var script = new Script(); |
||||
|
address = new Address(address); |
||||
|
// Standard pay-to-pubkey-hash
|
||||
|
if (!address.version) { |
||||
|
script.writeOp(Opcode.map.OP_DUP); |
||||
|
script.writeOp(Opcode.map.OP_HASH160); |
||||
|
script.writeBytes(address.hash); |
||||
|
script.writeOp(Opcode.map.OP_EQUALVERIFY); |
||||
|
script.writeOp(Opcode.map.OP_CHECKSIG); |
||||
|
} |
||||
|
// Standard pay-to-script-hash
|
||||
|
else { |
||||
|
script.writeOp(Opcode.map.OP_HASH160); |
||||
|
script.writeBytes(address.hash); |
||||
|
script.writeOp(Opcode.map.OP_EQUAL); |
||||
|
} |
||||
|
return script; |
||||
|
}; |
||||
|
|
||||
/** |
/** |
||||
* Add an op code to the script. |
* Extract pubkeys from a multisig script |
||||
*/ |
*/ |
||||
Script.prototype.writeOp = function (opcode) |
|
||||
{ |
|
||||
this.buffer.push(opcode); |
|
||||
this.chunks.push(opcode); |
|
||||
}; |
|
||||
|
|
||||
/** |
Script.prototype.extractPubkeys = function() { |
||||
* Add a data chunk to the script. |
return this.chunks.filter(function(chunk) { |
||||
*/ |
return (chunk[0] == 4 && chunk.length == 65 |
||||
Script.prototype.writeBytes = function (data) |
|| chunk[0] < 4 && chunk.length == 33) |
||||
{ |
}); |
||||
if (data.length < OP_PUSHDATA1) { |
} |
||||
this.buffer.push(data.length); |
|
||||
} else if (data.length <= 0xff) { |
|
||||
this.buffer.push(OP_PUSHDATA1); |
|
||||
this.buffer.push(data.length); |
|
||||
} else if (data.length <= 0xffff) { |
|
||||
this.buffer.push(OP_PUSHDATA2); |
|
||||
this.buffer.push(data.length & 0xff); |
|
||||
this.buffer.push((data.length >>> 8) & 0xff); |
|
||||
} else { |
|
||||
this.buffer.push(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); |
|
||||
}; |
|
||||
|
|
||||
/** |
/** |
||||
* Create a standard payToPubKeyHash output. |
* Create an m-of-n output script |
||||
*/ |
*/ |
||||
Script.createOutputScript = function (address) |
Script.createMultiSigOutputScript = function (m, pubkeys) |
||||
{ |
{ |
||||
var script = new Script(); |
var script = new Script(); |
||||
script.writeOp(OP_DUP); |
|
||||
script.writeOp(OP_HASH160); |
pubkeys = pubkeys.sort(); |
||||
script.writeBytes(address.hash); |
|
||||
script.writeOp(OP_EQUALVERIFY); |
|
||||
script.writeOp(OP_CHECKSIG); |
|
||||
return script; |
|
||||
}; |
|
||||
|
|
||||
|
script.writeOp(Opcode.map.OP_1 + m - 1); |
||||
|
|
||||
/** |
for (var i = 0; i < pubkeys.length; ++i) { |
||||
* Extract bitcoin addresses from an output script |
script.writeBytes(pubkeys[i]); |
||||
*/ |
} |
||||
Script.prototype.extractAddresses = function (addresses) |
|
||||
{ |
script.writeOp(Opcode.map.OP_1 + pubkeys.length - 1); |
||||
switch (this.getOutType()) { |
|
||||
case 'Address': |
|
||||
addresses.push(new Address(this.chunks[2])); |
|
||||
return 1; |
|
||||
case 'Pubkey': |
|
||||
addresses.push(new Address(Util.sha256ripe160(this.chunks[0]))); |
|
||||
return 1; |
|
||||
case 'Multisig': |
|
||||
for (var i = 1; i < this.chunks.length-2; ++i) { |
|
||||
addresses.push(new Address(Util.sha256ripe160(this.chunks[i]))); |
|
||||
} |
|
||||
return this.chunks[0] - OP_1 + 1; |
|
||||
default: |
|
||||
throw new Error("Encountered non-standard scriptPubKey"); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** |
script.writeOp(Opcode.map.OP_CHECKMULTISIG); |
||||
* Create an m-of-n output script |
|
||||
*/ |
|
||||
Script.createMultiSigOutputScript = function (m, pubkeys) |
|
||||
{ |
|
||||
var script = new Bitcoin.Script(); |
|
||||
|
|
||||
script.writeOp(OP_1 + m - 1); |
|
||||
|
|
||||
for (var i = 0; i < pubkeys.length; ++i) { |
|
||||
script.writeBytes(pubkeys[i]); |
|
||||
} |
|
||||
|
|
||||
script.writeOp(OP_1 + pubkeys.length - 1); |
|
||||
|
|
||||
script.writeOp(OP_CHECKMULTISIG); |
return script; |
||||
|
}; |
||||
|
|
||||
return script; |
/** |
||||
}; |
* Create a standard payToPubKeyHash input. |
||||
|
*/ |
||||
|
Script.createInputScript = function (signature, pubKey) |
||||
|
{ |
||||
|
var script = new Script(); |
||||
|
script.writeBytes(signature); |
||||
|
script.writeBytes(pubKey); |
||||
|
return script; |
||||
|
}; |
||||
|
|
||||
/** |
/** |
||||
* Create a standard payToPubKeyHash input. |
* Create a multisig input |
||||
*/ |
*/ |
||||
Script.createInputScript = function (signature, pubKey) |
Script.createMultiSigInputScript = function(signatures, script) |
||||
{ |
{ |
||||
var script = new Script(); |
script = new Script(script); |
||||
script.writeBytes(signature); |
var k = script.chunks[0][0]; |
||||
script.writeBytes(pubKey); |
if (signatures.length < k) return false; //Not enough sigs
|
||||
return script; |
var inScript = new Script(); |
||||
}; |
inScript.writeOp(Opcode.map.OP_0); |
||||
|
signatures.map(function(sig) { inScript.writeBytes(sig) }); |
||||
|
inScript.writeBytes(script.buffer); |
||||
|
return inScript; |
||||
|
} |
||||
|
|
||||
Script.prototype.clone = function () |
Script.prototype.clone = function () |
||||
{ |
{ |
||||
return new Script(this.buffer); |
return new Script(this.buffer); |
||||
}; |
}; |
||||
})(); |
|
||||
|
module.exports = Script; |
||||
|
@ -1,445 +1,587 @@ |
|||||
(function () { |
var BigInteger = require('./jsbn/jsbn'); |
||||
var Script = Bitcoin.Script; |
var Script = require('./script'); |
||||
|
var util = require('./util'); |
||||
var Transaction = Bitcoin.Transaction = function (doc) { |
var conv = require('./convert'); |
||||
|
var Crypto = require('./crypto-js/crypto'); |
||||
|
var Wallet = require('./wallet'); |
||||
|
var ECKey = require('./eckey').ECKey; |
||||
|
var ECDSA = require('./ecdsa'); |
||||
|
var Address = require('./address'); |
||||
|
|
||||
|
var Transaction = function (doc) { |
||||
this.version = 1; |
this.version = 1; |
||||
this.lock_time = 0; |
this.lock_time = 0; |
||||
this.ins = []; |
this.ins = []; |
||||
this.outs = []; |
this.outs = []; |
||||
this.timestamp = null; |
this.timestamp = null; |
||||
this.block = null; |
this.block = null; |
||||
|
|
||||
if (doc) { |
if (doc) { |
||||
if (doc.hash) this.hash = doc.hash; |
if (typeof doc == "string" || util.isArray(doc)) { |
||||
if (doc.version) this.version = doc.version; |
doc = Transaction.deserialize(doc) |
||||
if (doc.lock_time) this.lock_time = doc.lock_time; |
|
||||
if (doc.ins && doc.ins.length) { |
|
||||
for (var i = 0; i < doc.ins.length; i++) { |
|
||||
this.addInput(new TransactionIn(doc.ins[i])); |
|
||||
} |
} |
||||
} |
if (doc.hash) this.hash = doc.hash; |
||||
if (doc.outs && doc.outs.length) { |
if (doc.version) this.version = doc.version; |
||||
for (var i = 0; i < doc.outs.length; i++) { |
if (doc.lock_time) this.lock_time = doc.lock_time; |
||||
this.addOutput(new TransactionOut(doc.outs[i])); |
if (doc.ins && doc.ins.length) { |
||||
|
for (var i = 0; i < doc.ins.length; i++) { |
||||
|
this.addInput(new TransactionIn(doc.ins[i])); |
||||
|
} |
||||
} |
} |
||||
} |
if (doc.outs && doc.outs.length) { |
||||
if (doc.timestamp) this.timestamp = doc.timestamp; |
for (var i = 0; i < doc.outs.length; i++) { |
||||
if (doc.block) this.block = doc.block; |
this.addOutput(new TransactionOut(doc.outs[i])); |
||||
} |
} |
||||
}; |
} |
||||
|
if (doc.timestamp) this.timestamp = doc.timestamp; |
||||
/** |
if (doc.block) this.block = doc.block; |
||||
* Turn transaction data into Transaction objects. |
|
||||
* |
|
||||
* Takes an array of plain JavaScript objects containing transaction data and |
|
||||
* returns an array of Transaction objects. |
|
||||
*/ |
|
||||
Transaction.objectify = function (txs) { |
|
||||
var objs = []; |
|
||||
for (var i = 0; i < txs.length; i++) { |
|
||||
objs.push(new Transaction(txs[i])); |
|
||||
} |
} |
||||
return objs; |
}; |
||||
}; |
|
||||
|
/** |
||||
/** |
* Turn transaction data into Transaction objects. |
||||
* Create a new txin. |
* |
||||
* |
* Takes an array of plain JavaScript objects containing transaction data and |
||||
* Can be called with an existing TransactionIn object to add it to the |
* returns an array of Transaction objects. |
||||
* transaction. Or it can be called with a Transaction object and an integer |
*/ |
||||
* output index, in which case a new TransactionIn object pointing to the |
Transaction.objectify = function (txs) { |
||||
* referenced output will be created. |
var objs = []; |
||||
* |
for (var i = 0; i < txs.length; i++) { |
||||
* Note that this method does not sign the created input. |
objs.push(new Transaction(txs[i])); |
||||
*/ |
} |
||||
Transaction.prototype.addInput = function (tx, outIndex) { |
return objs; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Create a new txin. |
||||
|
* |
||||
|
* Can be called with any of: |
||||
|
* |
||||
|
* - An existing TransactionOut object |
||||
|
* - A transaction and an index |
||||
|
* - A transaction hash and an index |
||||
|
* - A single string argument of the form txhash:index |
||||
|
* |
||||
|
* Note that this method does not sign the created input. |
||||
|
*/ |
||||
|
Transaction.prototype.addInput = function (tx, outIndex) { |
||||
if (arguments[0] instanceof TransactionIn) { |
if (arguments[0] instanceof TransactionIn) { |
||||
this.ins.push(arguments[0]); |
this.ins.push(arguments[0]); |
||||
} else { |
} |
||||
this.ins.push(new TransactionIn({ |
else if (arguments[0].length > 65) { |
||||
outpoint: { |
var args = arguments[0].split(':'); |
||||
hash: tx.hash, |
return this.addInput(args[0], args[1]); |
||||
index: outIndex |
} |
||||
}, |
else { |
||||
script: new Bitcoin.Script(), |
this.ins.push(new TransactionIn({ |
||||
sequence: 4294967295 |
outpoint: { |
||||
})); |
hash: tx.hash || tx, |
||||
|
index: outIndex |
||||
|
}, |
||||
|
script: new Script(), |
||||
|
sequence: 4294967295 |
||||
|
})); |
||||
} |
} |
||||
}; |
}; |
||||
|
|
||||
/** |
/** |
||||
* Create a new txout. |
* Create a new txout. |
||||
* |
* |
||||
* Can be called with an existing TransactionOut object to add it to the |
* Can be called with: |
||||
* transaction. Or it can be called with an Address object and a BigInteger |
* |
||||
* for the amount, in which case a new TransactionOut object with those |
* i) An existing TransactionOut object |
||||
* values will be created. |
* ii) An address object or an address and a value |
||||
*/ |
* iii) An address:value string |
||||
Transaction.prototype.addOutput = function (address, value) { |
* |
||||
|
*/ |
||||
|
Transaction.prototype.addOutput = function (address, value) { |
||||
if (arguments[0] instanceof TransactionOut) { |
if (arguments[0] instanceof TransactionOut) { |
||||
this.outs.push(arguments[0]); |
this.outs.push(arguments[0]); |
||||
} else { |
return; |
||||
if (value instanceof BigInteger) { |
} |
||||
value = value.toByteArrayUnsigned().reverse(); |
if (arguments[0].indexOf(':') >= 0) { |
||||
while (value.length < 8) value.push(0); |
var args = arguments[0].split(':'); |
||||
} else if (Bitcoin.Util.isArray(value)) { |
address = args[0]; |
||||
// Nothing to do
|
value = parseInt(args[1]); |
||||
} |
} |
||||
|
this.outs.push(new TransactionOut({ |
||||
this.outs.push(new TransactionOut({ |
|
||||
value: value, |
value: value, |
||||
script: Script.createOutputScript(address) |
script: Script.createOutputScript(address) |
||||
})); |
})); |
||||
} |
}; |
||||
}; |
|
||||
|
/** |
||||
/** |
* Serialize this transaction. |
||||
* Serialize this transaction. |
* |
||||
* |
* Returns the transaction as a byte array in the standard Bitcoin binary |
||||
* Returns the transaction as a byte array in the standard Bitcoin binary |
* format. This method is byte-perfect, i.e. the resulting byte array can |
||||
* format. This method is byte-perfect, i.e. the resulting byte array can |
* be hashed to get the transaction's standard Bitcoin hash. |
||||
* be hashed to get the transaction's standard Bitcoin hash. |
*/ |
||||
*/ |
Transaction.prototype.serialize = function () { |
||||
Transaction.prototype.serialize = function () |
|
||||
{ |
|
||||
var buffer = []; |
var buffer = []; |
||||
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(this.version)]).reverse()); |
buffer = buffer.concat(util.numToBytes(parseInt(this.version),4)); |
||||
buffer = buffer.concat(Bitcoin.Util.numToVarInt(this.ins.length)); |
buffer = buffer.concat(util.numToVarInt(this.ins.length)); |
||||
for (var i = 0; i < this.ins.length; i++) { |
for (var i = 0; i < this.ins.length; i++) { |
||||
var txin = this.ins[i]; |
var txin = this.ins[i]; |
||||
buffer = buffer.concat(Crypto.util.base64ToBytes(txin.outpoint.hash)); |
|
||||
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.outpoint.index)]).reverse()); |
|
||||
var scriptBytes = txin.script.buffer; |
|
||||
buffer = buffer.concat(Bitcoin.Util.numToVarInt(scriptBytes.length)); |
|
||||
buffer = buffer.concat(scriptBytes); |
|
||||
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(txin.sequence)]).reverse()); |
|
||||
} |
|
||||
buffer = buffer.concat(Bitcoin.Util.numToVarInt(this.outs.length)); |
|
||||
for (var i = 0; i < this.outs.length; i++) { |
|
||||
var txout = this.outs[i]; |
|
||||
buffer = buffer.concat(txout.value); |
|
||||
var scriptBytes = txout.script.buffer; |
|
||||
buffer = buffer.concat(Bitcoin.Util.numToVarInt(scriptBytes.length)); |
|
||||
buffer = buffer.concat(scriptBytes); |
|
||||
} |
|
||||
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(this.lock_time)]).reverse()); |
|
||||
|
|
||||
return buffer; |
|
||||
}; |
|
||||
|
|
||||
var OP_CODESEPARATOR = 171; |
|
||||
|
|
||||
var SIGHASH_ALL = 1; |
|
||||
var SIGHASH_NONE = 2; |
|
||||
var SIGHASH_SINGLE = 3; |
|
||||
var SIGHASH_ANYONECANPAY = 80; |
|
||||
|
|
||||
/** |
|
||||
* Hash transaction for signing a specific input. |
|
||||
* |
|
||||
* Bitcoin uses a different hash for each signed transaction input. This |
|
||||
* method copies the transaction, makes the necessary changes based on the |
|
||||
* hashType, serializes and finally hashes the result. This hash can then be |
|
||||
* used to sign the transaction input in question. |
|
||||
*/ |
|
||||
Transaction.prototype.hashTransactionForSignature = |
|
||||
function (connectedScript, inIndex, hashType) |
|
||||
{ |
|
||||
var txTmp = this.clone(); |
|
||||
|
|
||||
// In case concatenating two scripts ends up with two codeseparators,
|
|
||||
// or an extra one at the end, this prevents all those possible
|
|
||||
// incompatibilities.
|
|
||||
/*scriptCode = scriptCode.filter(function (val) { |
|
||||
return val !== OP_CODESEPARATOR; |
|
||||
});*/ |
|
||||
|
|
||||
// Blank out other inputs' signatures
|
|
||||
for (var i = 0; i < txTmp.ins.length; i++) { |
|
||||
txTmp.ins[i].script = new Script(); |
|
||||
} |
|
||||
|
|
||||
txTmp.ins[inIndex].script = connectedScript; |
|
||||
|
|
||||
// Blank out some of the outputs
|
|
||||
if ((hashType & 0x1f) == SIGHASH_NONE) { |
|
||||
txTmp.outs = []; |
|
||||
|
|
||||
// Let the others update at will
|
|
||||
for (var i = 0; i < txTmp.ins.length; i++) |
|
||||
if (i != inIndex) |
|
||||
txTmp.ins[i].sequence = 0; |
|
||||
} else if ((hashType & 0x1f) == SIGHASH_SINGLE) { |
|
||||
// TODO: Implement
|
|
||||
} |
|
||||
|
|
||||
// Blank out other inputs completely, not recommended for open transactions
|
|
||||
if (hashType & SIGHASH_ANYONECANPAY) { |
|
||||
txTmp.ins = [txTmp.ins[inIndex]]; |
|
||||
} |
|
||||
|
|
||||
var buffer = txTmp.serialize(); |
|
||||
|
|
||||
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(hashType)]).reverse()); |
|
||||
|
|
||||
var hash1 = Crypto.SHA256(buffer, {asBytes: true}); |
|
||||
|
|
||||
return Crypto.SHA256(hash1, {asBytes: true}); |
// Why do blockchain.info, blockexplorer.com, sx and just about everybody
|
||||
}; |
// else use little-endian hashes? No idea...
|
||||
|
buffer = buffer.concat(conv.hexToBytes(txin.outpoint.hash).reverse()); |
||||
|
|
||||
/** |
buffer = buffer.concat(util.numToBytes(parseInt(txin.outpoint.index),4)); |
||||
* Calculate and return the transaction's hash. |
var scriptBytes = txin.script.buffer; |
||||
*/ |
buffer = buffer.concat(util.numToVarInt(scriptBytes.length)); |
||||
Transaction.prototype.getHash = function () |
buffer = buffer.concat(scriptBytes); |
||||
{ |
buffer = buffer.concat(util.numToBytes(parseInt(txin.sequence),4)); |
||||
var buffer = this.serialize(); |
|
||||
return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Create a copy of this transaction object. |
|
||||
*/ |
|
||||
Transaction.prototype.clone = function () |
|
||||
{ |
|
||||
var newTx = new Transaction(); |
|
||||
newTx.version = this.version; |
|
||||
newTx.lock_time = this.lock_time; |
|
||||
for (var i = 0; i < this.ins.length; i++) { |
|
||||
var txin = this.ins[i].clone(); |
|
||||
newTx.addInput(txin); |
|
||||
} |
} |
||||
|
buffer = buffer.concat(util.numToVarInt(this.outs.length)); |
||||
for (var i = 0; i < this.outs.length; i++) { |
for (var i = 0; i < this.outs.length; i++) { |
||||
var txout = this.outs[i].clone(); |
var txout = this.outs[i]; |
||||
newTx.addOutput(txout); |
buffer = buffer.concat(util.numToBytes(txout.value,8)); |
||||
} |
var scriptBytes = txout.script.buffer; |
||||
return newTx; |
buffer = buffer.concat(util.numToVarInt(scriptBytes.length)); |
||||
}; |
buffer = buffer.concat(scriptBytes); |
||||
|
|
||||
/** |
|
||||
* Analyze how this transaction affects a wallet. |
|
||||
* |
|
||||
* Returns an object with properties 'impact', 'type' and 'addr'. |
|
||||
* |
|
||||
* 'impact' is an object, see Transaction#calcImpact. |
|
||||
* |
|
||||
* 'type' can be one of the following: |
|
||||
* |
|
||||
* recv: |
|
||||
* This is an incoming transaction, the wallet received money. |
|
||||
* 'addr' contains the first address in the wallet that receives money |
|
||||
* from this transaction. |
|
||||
* |
|
||||
* self: |
|
||||
* This is an internal transaction, money was sent within the wallet. |
|
||||
* 'addr' is undefined. |
|
||||
* |
|
||||
* sent: |
|
||||
* This is an outgoing transaction, money was sent out from the wallet. |
|
||||
* 'addr' contains the first external address, i.e. the recipient. |
|
||||
* |
|
||||
* other: |
|
||||
* This method was unable to detect what the transaction does. Either it |
|
||||
*/ |
|
||||
Transaction.prototype.analyze = function (wallet) { |
|
||||
if (!(wallet instanceof Bitcoin.Wallet)) return null; |
|
||||
|
|
||||
var allFromMe = true, |
|
||||
allToMe = true, |
|
||||
firstRecvHash = null, |
|
||||
firstMeRecvHash = null, |
|
||||
firstSendHash = null; |
|
||||
|
|
||||
for (var i = this.outs.length-1; i >= 0; i--) { |
|
||||
var txout = this.outs[i]; |
|
||||
var hash = txout.script.simpleOutPubKeyHash(); |
|
||||
if (!wallet.hasHash(hash)) { |
|
||||
allToMe = false; |
|
||||
} else { |
|
||||
firstMeRecvHash = hash; |
|
||||
} |
|
||||
firstRecvHash = hash; |
|
||||
} |
|
||||
for (var i = this.ins.length-1; i >= 0; i--) { |
|
||||
var txin = this.ins[i]; |
|
||||
firstSendHash = txin.script.simpleInPubKeyHash(); |
|
||||
if (!wallet.hasHash(firstSendHash)) { |
|
||||
allFromMe = false; |
|
||||
break; |
|
||||
} |
|
||||
} |
} |
||||
|
buffer = buffer.concat(util.numToBytes(parseInt(this.lock_time),4)); |
||||
|
|
||||
var impact = this.calcImpact(wallet); |
return buffer; |
||||
|
}; |
||||
var analysis = {}; |
|
||||
|
Transaction.prototype.serializeHex = function() { |
||||
analysis.impact = impact; |
return conv.bytesToHex(this.serialize()); |
||||
|
} |
||||
if (impact.sign > 0 && impact.value.compareTo(BigInteger.ZERO) > 0) { |
|
||||
analysis.type = 'recv'; |
var OP_CODESEPARATOR = 171; |
||||
analysis.addr = new Bitcoin.Address(firstMeRecvHash); |
|
||||
} else if (allFromMe && allToMe) { |
var SIGHASH_ALL = 1; |
||||
analysis.type = 'self'; |
var SIGHASH_NONE = 2; |
||||
} else if (allFromMe) { |
var SIGHASH_SINGLE = 3; |
||||
analysis.type = 'sent'; |
var SIGHASH_ANYONECANPAY = 80; |
||||
// TODO: Right now, firstRecvHash is the first output, which - if the
|
|
||||
// transaction was not generated by this library could be the
|
/** |
||||
// change address.
|
* Hash transaction for signing a specific input. |
||||
analysis.addr = new Bitcoin.Address(firstRecvHash); |
* |
||||
} else { |
* Bitcoin uses a different hash for each signed transaction input. This |
||||
analysis.type = "other"; |
* method copies the transaction, makes the necessary changes based on the |
||||
|
* hashType, serializes and finally hashes the result. This hash can then be |
||||
|
* used to sign the transaction input in question. |
||||
|
*/ |
||||
|
Transaction.prototype.hashTransactionForSignature = |
||||
|
function (connectedScript, inIndex, hashType) |
||||
|
{ |
||||
|
var txTmp = this.clone(); |
||||
|
|
||||
|
// In case concatenating two scripts ends up with two codeseparators,
|
||||
|
// or an extra one at the end, this prevents all those possible
|
||||
|
// incompatibilities.
|
||||
|
/*scriptCode = scriptCode.filter(function (val) { |
||||
|
return val !== OP_CODESEPARATOR; |
||||
|
});*/ |
||||
|
|
||||
|
// Blank out other inputs' signatures
|
||||
|
for (var i = 0; i < txTmp.ins.length; i++) { |
||||
|
txTmp.ins[i].script = new Script(); |
||||
|
} |
||||
|
|
||||
|
txTmp.ins[inIndex].script = connectedScript; |
||||
|
|
||||
|
// Blank out some of the outputs
|
||||
|
if ((hashType & 0x1f) == SIGHASH_NONE) { |
||||
|
txTmp.outs = []; |
||||
|
|
||||
|
// Let the others update at will
|
||||
|
for (var i = 0; i < txTmp.ins.length; i++) |
||||
|
if (i != inIndex) |
||||
|
txTmp.ins[i].sequence = 0; |
||||
|
} else if ((hashType & 0x1f) == SIGHASH_SINGLE) { |
||||
|
// TODO: Implement
|
||||
|
} |
||||
|
|
||||
|
// Blank out other inputs completely, not recommended for open transactions
|
||||
|
if (hashType & SIGHASH_ANYONECANPAY) { |
||||
|
txTmp.ins = [txTmp.ins[inIndex]]; |
||||
|
} |
||||
|
|
||||
|
var buffer = txTmp.serialize(); |
||||
|
|
||||
|
buffer = buffer.concat(util.numToBytes(parseInt(hashType),4)); |
||||
|
|
||||
|
var hash1 = Crypto.SHA256(buffer, {asBytes: true}); |
||||
|
|
||||
|
return Crypto.SHA256(hash1, {asBytes: true}); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Calculate and return the transaction's hash. |
||||
|
* Reverses hash since blockchain.info, blockexplorer.com and others |
||||
|
* use little-endian hashes for some stupid reason |
||||
|
*/ |
||||
|
Transaction.prototype.getHash = function () |
||||
|
{ |
||||
|
var buffer = this.serialize(); |
||||
|
return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true}).reverse(); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Create a copy of this transaction object. |
||||
|
*/ |
||||
|
Transaction.prototype.clone = function () |
||||
|
{ |
||||
|
var newTx = new Transaction(); |
||||
|
newTx.version = this.version; |
||||
|
newTx.lock_time = this.lock_time; |
||||
|
for (var i = 0; i < this.ins.length; i++) { |
||||
|
var txin = this.ins[i].clone(); |
||||
|
newTx.addInput(txin); |
||||
|
} |
||||
|
for (var i = 0; i < this.outs.length; i++) { |
||||
|
var txout = this.outs[i].clone(); |
||||
|
newTx.addOutput(txout); |
||||
|
} |
||||
|
return newTx; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Analyze how this transaction affects a wallet. |
||||
|
* |
||||
|
* Returns an object with properties 'impact', 'type' and 'addr'. |
||||
|
* |
||||
|
* 'impact' is an object, see Transaction#calcImpact. |
||||
|
* |
||||
|
* 'type' can be one of the following: |
||||
|
* |
||||
|
* recv: |
||||
|
* This is an incoming transaction, the wallet received money. |
||||
|
* 'addr' contains the first address in the wallet that receives money |
||||
|
* from this transaction. |
||||
|
* |
||||
|
* self: |
||||
|
* This is an internal transaction, money was sent within the wallet. |
||||
|
* 'addr' is undefined. |
||||
|
* |
||||
|
* sent: |
||||
|
* This is an outgoing transaction, money was sent out from the wallet. |
||||
|
* 'addr' contains the first external address, i.e. the recipient. |
||||
|
* |
||||
|
* other: |
||||
|
* This method was unable to detect what the transaction does. Either it |
||||
|
*/ |
||||
|
Transaction.prototype.analyze = function (wallet) { |
||||
|
if (!(wallet instanceof Wallet)) return null; |
||||
|
|
||||
|
var allFromMe = true, |
||||
|
allToMe = true, |
||||
|
firstRecvHash = null, |
||||
|
firstMeRecvHash = null, |
||||
|
firstSendHash = null; |
||||
|
|
||||
|
for (var i = this.outs.length-1; i >= 0; i--) { |
||||
|
var txout = this.outs[i]; |
||||
|
var hash = txout.script.simpleOutPubKeyHash(); |
||||
|
if (!wallet.hasHash(hash)) { |
||||
|
allToMe = false; |
||||
|
} else { |
||||
|
firstMeRecvHash = hash; |
||||
} |
} |
||||
|
firstRecvHash = hash; |
||||
return analysis; |
} |
||||
}; |
for (var i = this.ins.length-1; i >= 0; i--) { |
||||
|
var txin = this.ins[i]; |
||||
/** |
firstSendHash = txin.script.simpleInPubKeyHash(); |
||||
* Get a human-readable version of the data returned by Transaction#analyze. |
if (!wallet.hasHash(firstSendHash)) { |
||||
* |
allFromMe = false; |
||||
* This is merely a convenience function. Clients should consider implementing |
|
||||
* this themselves based on their UI, I18N, etc. |
|
||||
*/ |
|
||||
Transaction.prototype.getDescription = function (wallet) { |
|
||||
var analysis = this.analyze(wallet); |
|
||||
|
|
||||
if (!analysis) return ""; |
|
||||
|
|
||||
switch (analysis.type) { |
|
||||
case 'recv': |
|
||||
return "Received with "+analysis.addr; |
|
||||
break; |
break; |
||||
|
|
||||
case 'sent': |
|
||||
return "Payment to "+analysis.addr; |
|
||||
break; |
|
||||
|
|
||||
case 'self': |
|
||||
return "Payment to yourself"; |
|
||||
break; |
|
||||
|
|
||||
case 'other': |
|
||||
default: |
|
||||
return ""; |
|
||||
} |
} |
||||
}; |
} |
||||
|
|
||||
/** |
var impact = this.calcImpact(wallet); |
||||
* Get the total amount of a transaction's outputs. |
|
||||
*/ |
var analysis = {}; |
||||
Transaction.prototype.getTotalOutValue = function () { |
|
||||
var totalValue = BigInteger.ZERO; |
analysis.impact = impact; |
||||
for (var j = 0; j < this.outs.length; j++) { |
|
||||
var txout = this.outs[j]; |
if (impact.sign > 0 && impact.value > 0) { |
||||
totalValue = totalValue.add(Bitcoin.Util.valueToBigInt(txout.value)); |
analysis.type = 'recv'; |
||||
|
analysis.addr = new Address(firstMeRecvHash); |
||||
|
} else if (allFromMe && allToMe) { |
||||
|
analysis.type = 'self'; |
||||
|
} else if (allFromMe) { |
||||
|
analysis.type = 'sent'; |
||||
|
// TODO: Right now, firstRecvHash is the first output, which - if the
|
||||
|
// transaction was not generated by this library could be the
|
||||
|
// change address.
|
||||
|
analysis.addr = new Address(firstRecvHash); |
||||
|
} else { |
||||
|
analysis.type = "other"; |
||||
|
} |
||||
|
|
||||
|
return analysis; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Get a human-readable version of the data returned by Transaction#analyze. |
||||
|
* |
||||
|
* This is merely a convenience function. Clients should consider implementing |
||||
|
* this themselves based on their UI, I18N, etc. |
||||
|
*/ |
||||
|
Transaction.prototype.getDescription = function (wallet) { |
||||
|
var analysis = this.analyze(wallet); |
||||
|
|
||||
|
if (!analysis) return ""; |
||||
|
|
||||
|
switch (analysis.type) { |
||||
|
case 'recv': |
||||
|
return "Received with "+analysis.addr; |
||||
|
break; |
||||
|
|
||||
|
case 'sent': |
||||
|
return "Payment to "+analysis.addr; |
||||
|
break; |
||||
|
|
||||
|
case 'self': |
||||
|
return "Payment to yourself"; |
||||
|
break; |
||||
|
|
||||
|
case 'other': |
||||
|
default: |
||||
|
return ""; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Get the total amount of a transaction's outputs. |
||||
|
*/ |
||||
|
Transaction.prototype.getTotalOutValue = function () { |
||||
|
return this.outs.reduce(function(t,o) { return t + o.value },0); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Old name for Transaction#getTotalOutValue. |
||||
|
* |
||||
|
* @deprecated |
||||
|
*/ |
||||
|
Transaction.prototype.getTotalValue = Transaction.prototype.getTotalOutValue; |
||||
|
|
||||
|
/** |
||||
|
* Calculates the impact a transaction has on this wallet. |
||||
|
* |
||||
|
* Based on the its public keys, the wallet will calculate the |
||||
|
* credit or debit of this transaction. |
||||
|
* |
||||
|
* It will return an object with two properties: |
||||
|
* - sign: 1 or -1 depending on sign of the calculated impact. |
||||
|
* - value: amount of calculated impact |
||||
|
* |
||||
|
* @returns Object Impact on wallet |
||||
|
*/ |
||||
|
Transaction.prototype.calcImpact = function (wallet) { |
||||
|
if (!(wallet instanceof Wallet)) return 0; |
||||
|
|
||||
|
// Calculate credit to us from all outputs
|
||||
|
var valueOut = this.outs.filter(function(o) { |
||||
|
return wallet.hasHash(conv.bytesToHex(o.script.simpleOutPubKeyHash())); |
||||
|
}) |
||||
|
.reduce(function(t,o) { return t+o.value },0); |
||||
|
|
||||
|
var valueIn = this.ins.filter(function(i) { |
||||
|
return wallet.hasHash(conv.bytesToHex(i.script.simpleInPubKeyHash())) |
||||
|
&& wallet.txIndex[i.outpoint.hash]; |
||||
|
}) |
||||
|
.reduce(function(t,i) { |
||||
|
return t + wallet.txIndex[i.outpoint.hash].outs[i.outpoint.index].value |
||||
|
},0); |
||||
|
|
||||
|
if (valueOut > valueIn) { |
||||
|
return { |
||||
|
sign: 1, |
||||
|
value: valueOut - valueIn |
||||
|
}; |
||||
|
} else { |
||||
|
return { |
||||
|
sign: -1, |
||||
|
value: valueIn - valueOut |
||||
|
}; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Converts a serialized transaction into a transaction object |
||||
|
*/ |
||||
|
|
||||
|
Transaction.deserialize = function(buffer) { |
||||
|
if (typeof buffer == "string") { |
||||
|
buffer = conv.hexToBytes(buffer) |
||||
} |
} |
||||
return totalValue; |
var pos = 0; |
||||
}; |
var readAsInt = function(bytes) { |
||||
|
if (bytes == 0) return 0; |
||||
/** |
pos++; |
||||
* Old name for Transaction#getTotalOutValue. |
return buffer[pos-1] + readAsInt(bytes-1) * 256; |
||||
* |
|
||||
* @deprecated |
|
||||
*/ |
|
||||
Transaction.prototype.getTotalValue = Transaction.prototype.getTotalOutValue; |
|
||||
|
|
||||
/** |
|
||||
* Calculates the impact a transaction has on this wallet. |
|
||||
* |
|
||||
* Based on the its public keys, the wallet will calculate the |
|
||||
* credit or debit of this transaction. |
|
||||
* |
|
||||
* It will return an object with two properties: |
|
||||
* - sign: 1 or -1 depending on sign of the calculated impact. |
|
||||
* - value: amount of calculated impact |
|
||||
* |
|
||||
* @returns Object Impact on wallet |
|
||||
*/ |
|
||||
Transaction.prototype.calcImpact = function (wallet) { |
|
||||
if (!(wallet instanceof Bitcoin.Wallet)) return BigInteger.ZERO; |
|
||||
|
|
||||
// Calculate credit to us from all outputs
|
|
||||
var valueOut = BigInteger.ZERO; |
|
||||
for (var j = 0; j < this.outs.length; j++) { |
|
||||
var txout = this.outs[j]; |
|
||||
var hash = Crypto.util.bytesToBase64(txout.script.simpleOutPubKeyHash()); |
|
||||
if (wallet.hasHash(hash)) { |
|
||||
valueOut = valueOut.add(Bitcoin.Util.valueToBigInt(txout.value)); |
|
||||
} |
|
||||
} |
} |
||||
|
var readVarInt = function() { |
||||
// Calculate debit to us from all ins
|
pos++; |
||||
var valueIn = BigInteger.ZERO; |
if (buffer[pos-1] < 253) { |
||||
for (var j = 0; j < this.ins.length; j++) { |
return buffer[pos-1]; |
||||
var txin = this.ins[j]; |
|
||||
var hash = Crypto.util.bytesToBase64(txin.script.simpleInPubKeyHash()); |
|
||||
if (wallet.hasHash(hash)) { |
|
||||
var fromTx = wallet.txIndex[txin.outpoint.hash]; |
|
||||
if (fromTx) { |
|
||||
valueIn = valueIn.add(Bitcoin.Util.valueToBigInt(fromTx.outs[txin.outpoint.index].value)); |
|
||||
} |
} |
||||
} |
return readAsInt(buffer[pos-1] - 251); |
||||
} |
} |
||||
if (valueOut.compareTo(valueIn) >= 0) { |
var readBytes = function(bytes) { |
||||
return { |
pos += bytes; |
||||
sign: 1, |
return buffer.slice(pos - bytes, pos); |
||||
value: valueOut.subtract(valueIn) |
|
||||
}; |
|
||||
} else { |
|
||||
return { |
|
||||
sign: -1, |
|
||||
value: valueIn.subtract(valueOut) |
|
||||
}; |
|
||||
} |
} |
||||
}; |
var readVarString = function() { |
||||
|
var size = readVarInt(); |
||||
var TransactionIn = Bitcoin.TransactionIn = function (data) |
return readBytes(size); |
||||
{ |
} |
||||
this.outpoint = data.outpoint; |
var obj = { |
||||
if (data.script instanceof Script) { |
ins: [], |
||||
this.script = data.script; |
outs: [] |
||||
} else { |
} |
||||
this.script = new Script(data.script); |
obj.version = readAsInt(4); |
||||
|
var ins = readVarInt(); |
||||
|
for (var i = 0; i < ins; i++) { |
||||
|
obj.ins.push({ |
||||
|
outpoint: { |
||||
|
hash: conv.bytesToHex(readBytes(32).reverse()), |
||||
|
index: readAsInt(4) |
||||
|
}, |
||||
|
script: new Script(readVarString()), |
||||
|
sequence: readAsInt(4) |
||||
|
}); |
||||
} |
} |
||||
this.sequence = data.sequence; |
var outs = readVarInt(); |
||||
}; |
for (var i = 0; i < outs; i++) { |
||||
|
obj.outs.push({ |
||||
TransactionIn.prototype.clone = function () |
value: util.bytesToNum(readBytes(8)), |
||||
{ |
script: new Script(readVarString()) |
||||
var newTxin = new TransactionIn({ |
}); |
||||
outpoint: { |
} |
||||
hash: this.outpoint.hash, |
obj.locktime = readAsInt(4); |
||||
index: this.outpoint.index |
return new Transaction(obj); |
||||
}, |
} |
||||
script: this.script.clone(), |
|
||||
sequence: this.sequence |
/** |
||||
|
* Signs a standard output at some index with the given key |
||||
|
*/ |
||||
|
|
||||
|
Transaction.prototype.sign = function(index, key, type) { |
||||
|
type = type || SIGHASH_ALL; |
||||
|
key = new ECKey(key); |
||||
|
var pub = key.getPub().export('bytes'), |
||||
|
hash160 = util.sha256ripe160(pub), |
||||
|
script = Script.createOutputScript(new Address(hash160)), |
||||
|
hash = this.hashTransactionForSignature( script, index, type), |
||||
|
sig = key.sign(hash).concat([type]); |
||||
|
this.ins[index].script = Script.createInputScript(sig,pub); |
||||
|
} |
||||
|
|
||||
|
// Takes outputs of the form [{ output: 'txhash:index', address: 'address' },...]
|
||||
|
Transaction.prototype.signWithKeys = function(keys, outputs, type) { |
||||
|
type = type || SIGHASH_ALL; |
||||
|
var addrdata = keys.map(function(key) { |
||||
|
key = new ECKey(key); |
||||
|
return { |
||||
|
key: key, |
||||
|
address: key.getBitcoinAddress().toString() |
||||
|
} |
||||
}); |
}); |
||||
return newTxin; |
var hmap = {}; |
||||
}; |
for (var o in outputs) { |
||||
|
hmap[outputs[o].output] = outputs[o]; |
||||
var TransactionOut = Bitcoin.TransactionOut = function (data) |
|
||||
{ |
|
||||
if (data.script instanceof Script) { |
|
||||
this.script = data.script; |
|
||||
} else { |
|
||||
this.script = new Script(data.script); |
|
||||
} |
} |
||||
|
for (var i = 0; i < this.ins.length; i++) { |
||||
if (Bitcoin.Util.isArray(data.value)) { |
var outpoint = this.ins[i].outpoint.hash+':'+this.ins[i].outpoint.index, |
||||
this.value = data.value; |
histItem = hmap[outpoint]; |
||||
} else if ("string" == typeof data.value) { |
if (!histItem) continue; |
||||
var valueHex = (new BigInteger(data.value, 10)).toString(16); |
var thisInputAddrdata = addrdata.filter(function(a) { |
||||
while (valueHex.length < 16) valueHex = "0" + valueHex; |
return a.address == histItem.address; |
||||
this.value = Crypto.util.hexToBytes(valueHex); |
}); |
||||
|
if (thisInputAddrdata.length == 0) continue; |
||||
|
this.sign(i,thisInputAddrdata[0].key); |
||||
} |
} |
||||
}; |
} |
||||
|
|
||||
TransactionOut.prototype.clone = function () |
/** |
||||
{ |
* Signs a P2SH output at some index with the given key |
||||
var newTxout = new TransactionOut({ |
*/ |
||||
script: this.script.clone(), |
|
||||
value: this.value.slice(0) |
Transaction.prototype.p2shsign = function(index, script, key, type) { |
||||
|
script = new Script(script); |
||||
|
key = new ECKey(key); |
||||
|
type = type || SIGHASH_ALL; |
||||
|
var hash = this.hashTransactionForSignature(script, index, type), |
||||
|
sig = key.sign(hash).concat([type]); |
||||
|
return sig; |
||||
|
} |
||||
|
|
||||
|
Transaction.prototype.multisign = Transaction.prototype.p2shsign; |
||||
|
|
||||
|
Transaction.prototype.applyMultisigs = function(index, script, sigs, type) { |
||||
|
this.ins[index].script = Script.createMultiSigInputScript(sigs, script); |
||||
|
} |
||||
|
|
||||
|
Transaction.prototype.validateSig = function(index, script, sig, pub) { |
||||
|
script = new Script(script); |
||||
|
var hash = this.hashTransactionForSignature(script,index,1); |
||||
|
return ECDSA.verify(hash, conv.coerceToBytes(sig), |
||||
|
conv.coerceToBytes(pub)); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
var TransactionIn = function (data) { |
||||
|
if (typeof data == "string") |
||||
|
this.outpoint = { hash: data.split(':')[0], index: data.split(':')[1] } |
||||
|
else if (data.outpoint) |
||||
|
this.outpoint = data.outpoint |
||||
|
else |
||||
|
this.outpoint = { hash: data.hash, index: data.index } |
||||
|
|
||||
|
if (data.scriptSig) |
||||
|
this.script = Script.fromScriptSig(data.scriptSig) |
||||
|
else |
||||
|
this.script = new Script(data.script) |
||||
|
|
||||
|
this.sequence = data.sequence || 4294967295; |
||||
|
}; |
||||
|
|
||||
|
TransactionIn.prototype.clone = function () { |
||||
|
return new TransactionIn({ |
||||
|
outpoint: { |
||||
|
hash: this.outpoint.hash, |
||||
|
index: this.outpoint.index |
||||
|
}, |
||||
|
script: this.script.clone(), |
||||
|
sequence: this.sequence |
||||
}); |
}); |
||||
return newTxout; |
}; |
||||
}; |
|
||||
})(); |
var TransactionOut = function (data) { |
||||
|
this.script = |
||||
|
data.script instanceof Script ? data.script.clone() |
||||
|
: util.isArray(data.script) ? new Script(data.script) |
||||
|
: typeof data.script == "string" ? new Script(conv.hexToBytes(data.script)) |
||||
|
: data.scriptPubKey ? Script.fromScriptSig(data.scriptPubKey) |
||||
|
: data.address ? Script.createOutputScript(data.address) |
||||
|
: new Script(); |
||||
|
|
||||
|
if (this.script.buffer.length > 0) this.address = this.script.toAddress(); |
||||
|
|
||||
|
this.value = |
||||
|
util.isArray(data.value) ? util.bytesToNum(data.value) |
||||
|
: "string" == typeof data.value ? parseInt(data.value) |
||||
|
: data.value instanceof BigInteger ? parseInt(data.value.toString()) |
||||
|
: data.value; |
||||
|
}; |
||||
|
|
||||
|
TransactionOut.prototype.clone = function () |
||||
|
{ |
||||
|
var newTxout = new TransactionOut({ |
||||
|
script: this.script.clone(), |
||||
|
value: this.value |
||||
|
}); |
||||
|
return newTxout; |
||||
|
}; |
||||
|
|
||||
|
module.exports.Transaction = Transaction; |
||||
|
module.exports.TransactionIn = TransactionIn; |
||||
|
module.exports.TransactionOut = TransactionOut; |
||||
|
@ -1,228 +1,69 @@ |
|||||
// BigInteger monkey patching
|
var Crypto = require('./crypto-js/crypto'); |
||||
BigInteger.valueOf = nbv; |
|
||||
|
|
||||
/** |
/** |
||||
* Returns a byte array representation of the big integer. |
* Cross-browser compatibility version of Array.isArray. |
||||
* |
|
||||
* This returns the absolute of the contained value in big endian |
|
||||
* form. A value of zero results in an empty array. |
|
||||
*/ |
*/ |
||||
BigInteger.prototype.toByteArrayUnsigned = function () { |
exports.isArray = Array.isArray || function(o) { |
||||
var ba = this.abs().toByteArray(); |
return Object.prototype.toString.call(o) === '[object Array]'; |
||||
if (ba.length) { |
} |
||||
if (ba[0] == 0) { |
|
||||
ba = ba.slice(1); |
|
||||
} |
|
||||
return ba.map(function (v) { |
|
||||
return (v < 0) ? v + 256 : v; |
|
||||
}); |
|
||||
} else { |
|
||||
// Empty array, nothing to do
|
|
||||
return ba; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** |
/** |
||||
* Turns a byte array into a big integer. |
* Create a byte array representing a number with the given length |
||||
* |
|
||||
* This function will interpret a byte array as a big integer in big |
|
||||
* endian notation and ignore leading zeros. |
|
||||
*/ |
*/ |
||||
BigInteger.fromByteArrayUnsigned = function (ba) { |
exports.numToBytes = function(num, bytes) { |
||||
if (!ba.length) { |
if (bytes === undefined) bytes = 8; |
||||
return ba.valueOf(0); |
if (bytes === 0) return []; |
||||
} else if (ba[0] & 0x80) { |
return [num % 256].concat(module.exports.numToBytes(Math.floor(num / 256), bytes - 1)); |
||||
// Prepend a zero so the BigInteger class doesn't mistake this
|
} |
||||
// for a negative integer.
|
|
||||
return new BigInteger([0].concat(ba)); |
|
||||
} else { |
|
||||
return new BigInteger(ba); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** |
/** |
||||
* Converts big integer to signed byte representation. |
* Convert a byte array to the number that it represents |
||||
* |
|
||||
* The format for this value uses a the most significant bit as a sign |
|
||||
* bit. If the most significant bit is already occupied by the |
|
||||
* absolute value, an extra byte is prepended and the sign bit is set |
|
||||
* there. |
|
||||
* |
|
||||
* Examples: |
|
||||
* |
|
||||
* 0 => 0x00 |
|
||||
* 1 => 0x01 |
|
||||
* -1 => 0x81 |
|
||||
* 127 => 0x7f |
|
||||
* -127 => 0xff |
|
||||
* 128 => 0x0080 |
|
||||
* -128 => 0x8080 |
|
||||
* 255 => 0x00ff |
|
||||
* -255 => 0x80ff |
|
||||
* 16300 => 0x3fac |
|
||||
* -16300 => 0xbfac |
|
||||
* 62300 => 0x00f35c |
|
||||
* -62300 => 0x80f35c |
|
||||
*/ |
*/ |
||||
BigInteger.prototype.toByteArraySigned = function () { |
exports.bytesToNum = function(bytes) { |
||||
var val = this.abs().toByteArrayUnsigned(); |
if (bytes.length === 0) return 0; |
||||
var neg = this.compareTo(BigInteger.ZERO) < 0; |
return bytes[0] + 256 * module.exports.bytesToNum(bytes.slice(1)); |
||||
|
} |
||||
if (neg) { |
|
||||
if (val[0] & 0x80) { |
|
||||
val.unshift(0x80); |
|
||||
} else { |
|
||||
val[0] |= 0x80; |
|
||||
} |
|
||||
} else { |
|
||||
if (val[0] & 0x80) { |
|
||||
val.unshift(0x00); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return val; |
|
||||
}; |
|
||||
|
|
||||
/** |
/** |
||||
* Parse a signed big integer byte representation. |
* Turn an integer into a "var_int". |
||||
|
* |
||||
|
* "var_int" is a variable length integer used by Bitcoin's binary format. |
||||
* |
* |
||||
* For details on the format please see BigInteger.toByteArraySigned. |
* Returns a byte array. |
||||
*/ |
*/ |
||||
BigInteger.fromByteArraySigned = function (ba) { |
exports.numToVarInt = function(num) { |
||||
// Check for negative value
|
if (num < 253) return [num]; |
||||
if (ba[0] & 0x80) { |
if (num < 65536) return [253].concat(exports.numToBytes(num, 2)); |
||||
// Remove sign bit
|
if (num < 4294967296) return [254].concat(exports.numToBytes(num, 4)); |
||||
ba[0] &= 0x7f; |
return [253].concat(exports.numToBytes(num, 8)); |
||||
|
} |
||||
return BigInteger.fromByteArrayUnsigned(ba).negate(); |
|
||||
} else { |
|
||||
return BigInteger.fromByteArrayUnsigned(ba); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
// Console ignore
|
|
||||
var names = ["log", "debug", "info", "warn", "error", "assert", "dir", |
|
||||
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", |
|
||||
"trace", "profile", "profileEnd"]; |
|
||||
|
|
||||
if ("undefined" == typeof window.console) window.console = {}; |
|
||||
for (var i = 0; i < names.length; ++i) |
|
||||
if ("undefined" == typeof window.console[names[i]]) |
|
||||
window.console[names[i]] = function() {}; |
|
||||
|
|
||||
// Bitcoin utility functions
|
|
||||
Bitcoin.Util = { |
|
||||
/** |
|
||||
* Cross-browser compatibility version of Array.isArray. |
|
||||
*/ |
|
||||
isArray: Array.isArray || function(o) |
|
||||
{ |
|
||||
return Object.prototype.toString.call(o) === '[object Array]'; |
|
||||
}, |
|
||||
|
|
||||
/** |
exports.bytesToWords = function (bytes) { |
||||
* Create an array of a certain length filled with a specific value. |
var words = []; |
||||
*/ |
for (var i = 0, b = 0; i < bytes.length; i++, b += 8) { |
||||
makeFilledArray: function (len, val) |
words[b >>> 5] |= bytes[i] << (24 - b % 32); |
||||
{ |
|
||||
var array = []; |
|
||||
var i = 0; |
|
||||
while (i < len) { |
|
||||
array[i++] = val; |
|
||||
} |
} |
||||
return array; |
return words; |
||||
}, |
} |
||||
|
|
||||
/** |
exports.wordsToBytes = function (words) { |
||||
* Turn an integer into a "var_int". |
var bytes = []; |
||||
* |
for (var b = 0; b < words.length * 32; b += 8) { |
||||
* "var_int" is a variable length integer used by Bitcoin's binary format. |
bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); |
||||
* |
|
||||
* Returns a byte array. |
|
||||
*/ |
|
||||
numToVarInt: function (i) |
|
||||
{ |
|
||||
if (i < 0xfd) { |
|
||||
// unsigned char
|
|
||||
return [i]; |
|
||||
} else if (i <= 1<<16) { |
|
||||
// unsigned short (LE)
|
|
||||
return [0xfd, i >>> 8, i & 255]; |
|
||||
} else if (i <= 1<<32) { |
|
||||
// unsigned int (LE)
|
|
||||
return [0xfe].concat(Crypto.util.wordsToBytes([i])); |
|
||||
} else { |
|
||||
// unsigned long long (LE)
|
|
||||
return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i])); |
|
||||
} |
} |
||||
}, |
return bytes; |
||||
|
}, |
||||
/** |
|
||||
* Parse a Bitcoin value byte array, returning a BigInteger. |
|
||||
*/ |
|
||||
valueToBigInt: function (valueBuffer) |
|
||||
{ |
|
||||
if (valueBuffer instanceof BigInteger) return valueBuffer; |
|
||||
|
|
||||
// Prepend zero byte to prevent interpretation as negative integer
|
/** |
||||
return BigInteger.fromByteArrayUnsigned(valueBuffer); |
* Calculate RIPEMD160(SHA256(data)). |
||||
}, |
* |
||||
|
* Takes an arbitrary byte array as inputs and returns the hash as a byte |
||||
/** |
* array. |
||||
* Format a Bitcoin value as a string. |
*/ |
||||
* |
exports.sha256ripe160 = function (data) { |
||||
* Takes a BigInteger or byte-array and returns that amount of Bitcoins in a |
|
||||
* nice standard formatting. |
|
||||
* |
|
||||
* Examples: |
|
||||
* 12.3555 |
|
||||
* 0.1234 |
|
||||
* 900.99998888 |
|
||||
* 34.00 |
|
||||
*/ |
|
||||
formatValue: function (valueBuffer) { |
|
||||
var value = this.valueToBigInt(valueBuffer).toString(); |
|
||||
var integerPart = value.length > 8 ? value.substr(0, value.length-8) : '0'; |
|
||||
var decimalPart = value.length > 8 ? value.substr(value.length-8) : value; |
|
||||
while (decimalPart.length < 8) decimalPart = "0"+decimalPart; |
|
||||
decimalPart = decimalPart.replace(/0*$/, ''); |
|
||||
while (decimalPart.length < 2) decimalPart += "0"; |
|
||||
return integerPart+"."+decimalPart; |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* Parse a floating point string as a Bitcoin value. |
|
||||
* |
|
||||
* Keep in mind that parsing user input is messy. You should always display |
|
||||
* the parsed value back to the user to make sure we understood his input |
|
||||
* correctly. |
|
||||
*/ |
|
||||
parseValue: function (valueString) { |
|
||||
// TODO: Detect other number formats (e.g. comma as decimal separator)
|
|
||||
var valueComp = valueString.split('.'); |
|
||||
var integralPart = valueComp[0]; |
|
||||
var fractionalPart = valueComp[1] || "0"; |
|
||||
while (fractionalPart.length < 8) fractionalPart += "0"; |
|
||||
fractionalPart = fractionalPart.replace(/^0+/g, ''); |
|
||||
var value = BigInteger.valueOf(parseInt(integralPart)); |
|
||||
value = value.multiply(BigInteger.valueOf(100000000)); |
|
||||
value = value.add(BigInteger.valueOf(parseInt(fractionalPart))); |
|
||||
return value; |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* Calculate RIPEMD160(SHA256(data)). |
|
||||
* |
|
||||
* Takes an arbitrary byte array as inputs and returns the hash as a byte |
|
||||
* array. |
|
||||
*/ |
|
||||
sha256ripe160: function (data) { |
|
||||
return Crypto.RIPEMD160(Crypto.SHA256(data, {asBytes: true}), {asBytes: true}); |
return Crypto.RIPEMD160(Crypto.SHA256(data, {asBytes: true}), {asBytes: true}); |
||||
} |
} |
||||
}; |
|
||||
|
|
||||
for (var i in Crypto.util) { |
exports.error = function(msg) { |
||||
if (Crypto.util.hasOwnProperty(i)) { |
throw new Error(msg); |
||||
Bitcoin.Util[i] = Crypto.util[i]; |
|
||||
} |
|
||||
} |
} |
||||
|
@ -1,308 +1,182 @@ |
|||||
Bitcoin.Wallet = (function () { |
var Script = require('./script'); |
||||
var Script = Bitcoin.Script, |
var ECKey = require('./eckey').ECKey; |
||||
TransactionIn = Bitcoin.TransactionIn, |
var conv = require('./convert'); |
||||
TransactionOut = Bitcoin.TransactionOut; |
var util = require('./util'); |
||||
|
|
||||
var Wallet = function () { |
var BigInteger = require('./jsbn/jsbn'); |
||||
// Keychain
|
|
||||
//
|
|
||||
// The keychain is stored as a var in this closure to make accidental
|
|
||||
// serialization less likely.
|
|
||||
//
|
|
||||
// Any functions accessing this value therefore have to be defined in
|
|
||||
// the closure of this constructor.
|
|
||||
var keys = []; |
|
||||
|
|
||||
// Public hashes of our keys
|
|
||||
this.addressHashes = []; |
|
||||
|
|
||||
// Transaction data
|
|
||||
this.txIndex = {}; |
|
||||
this.unspentOuts = []; |
|
||||
|
|
||||
// Other fields
|
|
||||
this.addressPointer = 0; |
|
||||
|
|
||||
/** |
|
||||
* Add a key to the keychain. |
|
||||
* |
|
||||
* The corresponding public key can be provided as a second parameter. This |
|
||||
* adds it to the cache in the ECKey object and avoid the need to |
|
||||
* expensively calculate it later. |
|
||||
*/ |
|
||||
this.addKey = function (key, pub) { |
|
||||
if (!(key instanceof Bitcoin.ECKey)) { |
|
||||
key = new Bitcoin.ECKey(key); |
|
||||
} |
|
||||
keys.push(key); |
|
||||
|
|
||||
if (pub) { |
|
||||
if ("string" === typeof pub) { |
|
||||
pub = Crypto.util.base64ToBytes(pub); |
|
||||
} |
|
||||
key.setPub(pub); |
|
||||
} |
|
||||
|
|
||||
this.addressHashes.push(key.getBitcoinAddress().getHashBase64()); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Add multiple keys at once. |
|
||||
*/ |
|
||||
this.addKeys = function (keys, pubs) { |
|
||||
if ("string" === typeof keys) { |
|
||||
keys = keys.split(','); |
|
||||
} |
|
||||
if ("string" === typeof pubs) { |
|
||||
pubs = pubs.split(','); |
|
||||
} |
|
||||
var i; |
|
||||
if (Array.isArray(pubs) && keys.length == pubs.length) { |
|
||||
for (i = 0; i < keys.length; i++) { |
|
||||
this.addKey(keys[i], pubs[i]); |
|
||||
} |
|
||||
} else { |
|
||||
for (i = 0; i < keys.length; i++) { |
|
||||
this.addKey(keys[i]); |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** |
var Transaction = require('./transaction').Transaction; |
||||
* Get the key chain. |
var TransactionIn = require('./transaction').TransactionIn; |
||||
* |
var TransactionOut = require('./transaction').TransactionOut; |
||||
* Returns an array of base64-encoded private values. |
var HDWallet = require('./hdwallet.js') |
||||
*/ |
|
||||
this.getKeys = function () { |
|
||||
var serializedWallet = []; |
|
||||
|
|
||||
for (var i = 0; i < keys.length; i++) { |
var SecureRandom = require('./jsbn/rng'); |
||||
serializedWallet.push(keys[i].toString('base64')); |
var rng = new SecureRandom(); |
||||
} |
|
||||
|
|
||||
return serializedWallet; |
var Wallet = function (seed) { |
||||
}; |
|
||||
|
|
||||
/** |
// Stored in a closure to make accidental serialization less likely
|
||||
* Get the public keys. |
var keys = []; |
||||
* |
var masterkey = null; |
||||
* Returns an array of base64-encoded public keys. |
var me = this; |
||||
*/ |
|
||||
this.getPubKeys = function () { |
|
||||
var pubs = []; |
|
||||
|
|
||||
for (var i = 0; i < keys.length; i++) { |
|
||||
pubs.push(Crypto.util.bytesToBase64(keys[i].getPub())); |
|
||||
} |
|
||||
|
|
||||
return pubs; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Delete all keys. |
|
||||
*/ |
|
||||
this.clear = function () { |
|
||||
keys = []; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Return the number of keys in this wallet. |
|
||||
*/ |
|
||||
this.getLength = function () { |
|
||||
return keys.length; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Get the addresses for this wallet. |
|
||||
* |
|
||||
* Returns an array of Address objects. |
|
||||
*/ |
|
||||
this.getAllAddresses = function () { |
|
||||
var addresses = []; |
|
||||
for (var i = 0; i < keys.length; i++) { |
|
||||
addresses.push(keys[i].getBitcoinAddress()); |
|
||||
} |
|
||||
return addresses; |
|
||||
}; |
|
||||
|
|
||||
this.getCurAddress = function () { |
|
||||
if (keys[this.addressPointer]) { |
|
||||
return keys[this.addressPointer].getBitcoinAddress(); |
|
||||
} else { |
|
||||
return null; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** |
// Addresses
|
||||
* Go to the next address. |
this.addresses = []; |
||||
* |
|
||||
* If there are no more new addresses available, one will be generated |
|
||||
* automatically. |
|
||||
*/ |
|
||||
this.getNextAddress = function () { |
|
||||
this.addressPointer++; |
|
||||
if (!keys[this.addressPointer]) { |
|
||||
this.generateAddress(); |
|
||||
} |
|
||||
return keys[this.addressPointer].getBitcoinAddress(); |
|
||||
}; |
|
||||
|
|
||||
/** |
// Transaction output data
|
||||
* Sign a hash with a key. |
this.outputs = {}; |
||||
* |
|
||||
* This method expects the pubKeyHash as the first parameter and the hash |
|
||||
* to be signed as the second parameter. |
|
||||
*/ |
|
||||
this.signWithKey = function (pubKeyHash, hash) { |
|
||||
pubKeyHash = Crypto.util.bytesToBase64(pubKeyHash); |
|
||||
for (var i = 0; i < this.addressHashes.length; i++) { |
|
||||
if (this.addressHashes[i] == pubKeyHash) { |
|
||||
return keys[i].sign(hash); |
|
||||
} |
|
||||
} |
|
||||
throw new Error("Missing key for signature"); |
|
||||
}; |
|
||||
|
|
||||
/** |
// Make a new master key
|
||||
* Retrieve the corresponding pubKey for a pubKeyHash. |
this.newMasterKey = function(seed) { |
||||
* |
if (!seed) { |
||||
* This function only works if the pubKey in question is part of this |
var seedBytes = new Array(32); |
||||
* wallet. |
rng.nextBytes(seedBytes); |
||||
*/ |
seed = conv.bytesToString(seedBytes) |
||||
this.getPubKeyFromHash = function (pubKeyHash) { |
|
||||
pubKeyHash = Crypto.util.bytesToBase64(pubKeyHash); |
|
||||
for (var i = 0; i < this.addressHashes.length; i++) { |
|
||||
if (this.addressHashes[i] == pubKeyHash) { |
|
||||
return keys[i].getPub(); |
|
||||
} |
} |
||||
} |
masterkey = new HDWallet(seed); |
||||
throw new Error("Hash unknown"); |
keys = [] |
||||
}; |
} |
||||
}; |
this.newMasterKey(seed) |
||||
|
|
||||
Wallet.prototype.generateAddress = function () { |
|
||||
this.addKey(new Bitcoin.ECKey()); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Add a transaction to the wallet's processed transaction. |
|
||||
* |
|
||||
* This will add a transaction to the wallet, updating its balance and |
|
||||
* available unspent outputs. |
|
||||
*/ |
|
||||
Wallet.prototype.process = function (tx) { |
|
||||
if (this.txIndex[tx.hash]) return; |
|
||||
|
|
||||
var j; |
// Add a new address
|
||||
var k; |
this.generateAddress = function() { |
||||
var hash; |
keys.push(masterkey.ckd(keys.length).key) |
||||
// Gather outputs
|
this.addresses.push(keys[keys.length-1].getBitcoinAddress().toString()) |
||||
for (j = 0; j < tx.outs.length; j++) { |
return this.addresses[this.addresses.length - 1] |
||||
var txout = new TransactionOut(tx.outs[j]); |
|
||||
hash = Crypto.util.bytesToBase64(txout.script.simpleOutPubKeyHash()); |
|
||||
for (k = 0; k < this.addressHashes.length; k++) { |
|
||||
if (this.addressHashes[k] === hash) { |
|
||||
this.unspentOuts.push({tx: tx, index: j, out: txout}); |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
// Remove spent outputs
|
// Processes a transaction object
|
||||
for (j = 0; j < tx.ins.length; j++) { |
// If "verified" is true, then we trust the transaction as "final"
|
||||
var txin = new TransactionIn(tx.ins[j]); |
this.processTx = function(tx, verified) { |
||||
var pubkey = txin.script.simpleInPubKey(); |
var txhash = conv.bytesToHex(tx.getHash()) |
||||
hash = Crypto.util.bytesToBase64(Bitcoin.Util.sha256ripe160(pubkey)); |
for (var i = 0; i < tx.outs.length; i++) { |
||||
for (k = 0; k < this.addressHashes.length; k++) { |
if (this.addresses.indexOf(tx.outs[i].address.toString()) >= 0) { |
||||
if (this.addressHashes[k] === hash) { |
me.outputs[txhash+':'+i] = { |
||||
for (var l = 0; l < this.unspentOuts.length; l++) { |
output: txhash+':'+i, |
||||
if (txin.outpoint.hash == this.unspentOuts[l].tx.hash && |
value: tx.outs[i].value, |
||||
txin.outpoint.index == this.unspentOuts[l].index) { |
address: tx.outs[i].address.toString(), |
||||
this.unspentOuts.splice(l, 1); |
timestamp: new Date().getTime() / 1000, |
||||
|
pending: true |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
for (var i = 0; i < tx.ins.length; i++) { |
||||
|
var op = tx.ins[i].outpoint |
||||
|
var o = me.outputs[op.hash+':'+op.index] |
||||
|
if (o) { |
||||
|
o.spend = txhash+':'+i |
||||
|
o.spendpending = true |
||||
|
o.timestamp = new Date().getTime() / 1000 |
||||
} |
} |
||||
} |
|
||||
break; |
|
||||
} |
} |
||||
} |
|
||||
} |
} |
||||
|
// Processes an output from an external source of the form
|
||||
// Index transaction
|
// { output: txhash:index, value: integer, address: address }
|
||||
this.txIndex[tx.hash] = tx; |
// Excellent compatibility with SX and pybitcointools
|
||||
}; |
this.processOutput = function(o) { |
||||
|
if (!this.outputs[o.output] || this.outputs[o.output].pending) |
||||
Wallet.prototype.getBalance = function () { |
this.outputs[o.output] = o; |
||||
var balance = BigInteger.valueOf(0); |
|
||||
for (var i = 0; i < this.unspentOuts.length; i++) { |
|
||||
var txout = this.unspentOuts[i].out; |
|
||||
balance = balance.add(Bitcoin.Util.valueToBigInt(txout.value)); |
|
||||
} |
} |
||||
return balance; |
|
||||
}; |
|
||||
|
|
||||
Wallet.prototype.createSend = function (address, sendValue, feeValue) { |
this.processExistingOutputs = function() { |
||||
var selectedOuts = []; |
var t = new Date().getTime() / 1000 |
||||
var txValue = sendValue.add(feeValue); |
for (var o in this.outputs) { |
||||
var availableValue = BigInteger.ZERO; |
if (o.pending && t > o.timestamp + 1200) |
||||
var i; |
delete this.outputs[o] |
||||
for (i = 0; i < this.unspentOuts.length; i++) { |
if (o.spendpending && t > o.timestamp + 1200) { |
||||
selectedOuts.push(this.unspentOuts[i]); |
o.spendpending = false |
||||
availableValue = availableValue.add(Bitcoin.Util.valueToBigInt(this.unspentOuts[i].out.value)); |
o.spend = false |
||||
|
delete o.timestamp |
||||
if (availableValue.compareTo(txValue) >= 0) break; |
} |
||||
|
} |
||||
} |
} |
||||
|
var peoInterval = setInterval(this.processExistingOutputs, 10000) |
||||
if (availableValue.compareTo(txValue) < 0) { |
|
||||
throw new Error('Insufficient funds.'); |
this.getUtxoToPay = function(value) { |
||||
|
var h = [] |
||||
|
for (var out in this.outputs) h.push(this.outputs[out]) |
||||
|
var utxo = h.filter(function(x) { return !x.spend }); |
||||
|
var valuecompare = function(a,b) { return a.value > b.value; } |
||||
|
var high = utxo.filter(function(o) { return o.value >= value; }) |
||||
|
.sort(valuecompare); |
||||
|
if (high.length > 0) return [high[0]]; |
||||
|
utxo.sort(valuecompare); |
||||
|
var totalval = 0; |
||||
|
for (var i = 0; i < utxo.length; i++) { |
||||
|
totalval += utxo[i].value; |
||||
|
if (totalval >= value) return utxo.slice(0,i+1); |
||||
|
} |
||||
|
throw ("Not enough money to send funds including transaction fee. Have: " |
||||
|
+ (totalval / 100000000) + ", needed: " + (value / 100000000)); |
||||
} |
} |
||||
|
|
||||
|
this.mkSend = function(to, value, fee) { |
||||
var changeValue = availableValue.subtract(txValue); |
var utxo = this.getUtxoToPay(value + fee) |
||||
|
var sum = utxo.reduce(function(t,o) { return t + o.value },0), |
||||
var sendTx = new Bitcoin.Transaction(); |
remainder = sum - value - fee |
||||
|
if (value < 5430) throw new Error("Amount below dust threshold!") |
||||
for (i = 0; i < selectedOuts.length; i++) { |
var unspentOuts = 0; |
||||
sendTx.addInput(selectedOuts[i].tx, selectedOuts[i].index); |
for (var o in this.outputs) { |
||||
|
if (!this.outputs[o].spend) unspentOuts += 1 |
||||
|
if (unspentOuts >= 5) return |
||||
|
} |
||||
|
var change = this.addresses[this.addresses.length - 1] |
||||
|
var toOut = { address: to, value: value }, |
||||
|
changeOut = { address: change, value: remainder } |
||||
|
halfChangeOut = { address: change, value: Math.floor(remainder/2) }; |
||||
|
|
||||
|
var outs = |
||||
|
remainder < 5430 ? [toOut] |
||||
|
: remainder < 10860 ? [toOut, changeOut] |
||||
|
: unspentOuts == 5 ? [toOut, changeOut] |
||||
|
: [toOut, halfChangeOut, halfChangeOut] |
||||
|
|
||||
|
var tx = new Bitcoin.Transaction({ |
||||
|
ins: utxo.map(function(x) { return x.output }), |
||||
|
outs: outs |
||||
|
}) |
||||
|
this.sign(tx) |
||||
|
return tx |
||||
} |
} |
||||
|
|
||||
sendTx.addOutput(address, sendValue); |
this.mkSendToOutputs = function(outputs, changeIndex, fee) { |
||||
if (changeValue.compareTo(BigInteger.ZERO) > 0) { |
var value = outputs.reduce(function(t,o) { return t + o.value },0), |
||||
sendTx.addOutput(this.getNextAddress(), changeValue); |
utxo = this.getUtxoToPay(value + fee), |
||||
|
sum = utxo.reduce(function(t,p) { return t + o.value },0); |
||||
|
utxo[changeIndex].value += sum - value - fee; |
||||
|
var tx = new Bitcoin.Transaction({ |
||||
|
ins: utxo.map(function(x) { return x.output }), |
||||
|
outs: outputs |
||||
|
}) |
||||
|
this.sign(tx) |
||||
|
return tx |
||||
} |
} |
||||
|
|
||||
var hashType = 1; // SIGHASH_ALL
|
this.sign = function(tx) { |
||||
|
tx.ins.map(function(inp,i) { |
||||
for (i = 0; i < sendTx.ins.length; i++) { |
var inp = inp.outpoint.hash+':'+inp.outpoint.index; |
||||
var hash = sendTx.hashTransactionForSignature(selectedOuts[i].out.script, i, hashType); |
if (me.outputs[inp]) { |
||||
var pubKeyHash = selectedOuts[i].out.script.simpleOutPubKeyHash(); |
var address = me.outputs[inp].address, |
||||
var signature = this.signWithKey(pubKeyHash, hash); |
ind = me.addresses.indexOf(address); |
||||
|
if (ind >= 0) { |
||||
// Append hash type
|
var key = keys[ind] |
||||
signature.push(parseInt(hashType, 10)); |
tx.sign(ind,key) |
||||
|
} |
||||
sendTx.ins[i].script = Script.createInputScript(signature, this.getPubKeyFromHash(pubKeyHash)); |
} |
||||
|
}) |
||||
|
return tx; |
||||
} |
} |
||||
|
|
||||
return sendTx; |
this.getMasterKey = function() { return masterkey } |
||||
}; |
|
||||
|
|
||||
Wallet.prototype.clearTransactions = function () { |
|
||||
this.txIndex = {}; |
|
||||
this.unspentOuts = []; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Check to see if a pubKeyHash belongs to this wallet. |
|
||||
*/ |
|
||||
Wallet.prototype.hasHash = function (hash) { |
|
||||
if (Bitcoin.Util.isArray(hash)) hash = Crypto.util.bytesToBase64(hash); |
|
||||
|
|
||||
// TODO: Just create an object with base64 hashes as keys for faster lookup
|
this.getPrivateKey = function(index) { |
||||
for (var k = 0; k < this.addressHashes.length; k++) { |
if (typeof index == "string") |
||||
if (this.addressHashes[k] === hash) return true; |
return keys.filter(function(i,k){ return addresses[i] == index })[0] |
||||
|
else |
||||
|
return keys[index] |
||||
} |
} |
||||
return false; |
|
||||
}; |
|
||||
|
|
||||
return Wallet; |
this.getPrivateKeys = function() { return keys } |
||||
})(); |
}; |
||||
|
|
||||
|
module.exports = Wallet; |
||||
|
@ -0,0 +1,52 @@ |
|||||
|
/* global describe, it */ |
||||
|
var assert = require('assert'); |
||||
|
var Address = require('../src/address.js'); |
||||
|
|
||||
|
describe('Address', function() { |
||||
|
describe('toString', function() { |
||||
|
it('defaults to base58', function() { |
||||
|
var addr = '18fN1QTGWmHWCA9r2dyDH6FbMEyc7XHmQQ'; |
||||
|
assert.equal((new Address(addr)).toString(), addr); |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
describe('validate', function() { |
||||
|
it('validates known good addresses', function() { |
||||
|
function validate(addr) { |
||||
|
assert.ok(Address.validate(addr)); |
||||
|
} |
||||
|
|
||||
|
validate('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa'); |
||||
|
// validate('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', 'prod');
|
||||
|
validate('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhef'); |
||||
|
// validate('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhef', 'testnet');
|
||||
|
|
||||
|
validate('12KYrjTdVGjFMtaxERSk3gphreJ5US8aUP'); |
||||
|
validate('12QeMLzSrB8XH8FvEzPMVoRxVAzTr5XM2y'); |
||||
|
validate('1oNLrsHnBcR6dpaBpwz3LSwutbUNkNSjs'); |
||||
|
validate('1SQHtwR5oJRKLfiWQ2APsAd9miUc4k2ez'); |
||||
|
validate('116CGDLddrZhMrTwhCVJXtXQpxygTT1kHd'); |
||||
|
|
||||
|
// p2sh addresses
|
||||
|
validate('3NJZLcZEEYBpxYEUGewU4knsQRn1WM5Fkt'); |
||||
|
// validate('3NJZLcZEEYBpxYEUGewU4knsQRn1WM5Fkt', 'prod');
|
||||
|
validate('2MxKEf2su6FGAUfCEAHreGFQvEYrfYNHvL7'); |
||||
|
// validate('2MxKEf2su6FGAUfCEAHreGFQvEYrfYNHvL7', 'testnet');
|
||||
|
}) |
||||
|
|
||||
|
it('does not validate illegal examples', function() { |
||||
|
function invalid(addr) { |
||||
|
assert.ok(!Address.validate(addr)); |
||||
|
} |
||||
|
|
||||
|
invalid(''); |
||||
|
invalid('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhe'); |
||||
|
|
||||
|
// invalid('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', 'testnet');
|
||||
|
// invalid('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhef', 'prod');
|
||||
|
|
||||
|
// invalid base58 string
|
||||
|
invalid('%%@'); |
||||
|
}) |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,22 @@ |
|||||
|
/* global describe, it */ |
||||
|
var assert = require('assert'); |
||||
|
var base58 = require('../').base58; |
||||
|
var conv = require('../').convert; |
||||
|
|
||||
|
describe('base58', function() { |
||||
|
describe('decode', function() { |
||||
|
it('validates known examples', function() { |
||||
|
var enc = '5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ'; |
||||
|
var hex = '800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d'; |
||||
|
assert.deepEqual(base58.decode(enc), conv.hexToBytes(hex)); |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
describe('encode', function() { |
||||
|
it('handles known examples', function() { |
||||
|
var enc = '5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ'; |
||||
|
var hex = '800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d'; |
||||
|
assert.equal(base58.encode(conv.hexToBytes(hex)), enc); |
||||
|
}) |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,28 @@ |
|||||
|
/* global describe, it */ |
||||
|
var assert = require('assert'); |
||||
|
var convert = require('../src/convert.js'); |
||||
|
|
||||
|
describe('convert', function() { |
||||
|
describe('bytesToHex', function() { |
||||
|
it('handles example 1', function() { |
||||
|
assert.equal(convert.bytesToHex([0, 1, 2, 255]), '000102ff'); |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
describe('hexToBytes', function() { |
||||
|
it('handles example 1', function() { |
||||
|
assert.deepEqual(convert.hexToBytes('000102ff'), [0, 1, 2, 255]); |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
it('converts from bytes to hex and back', function() { |
||||
|
var bytes = []; |
||||
|
for (var i=0 ; i<256 ; ++i) { |
||||
|
bytes.push(i); |
||||
|
} |
||||
|
|
||||
|
var hex = convert.bytesToHex(bytes); |
||||
|
assert.equal(hex.length, 512); |
||||
|
assert.deepEqual(convert.hexToBytes(hex), bytes); |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,23 @@ |
|||||
|
/* global describe, it */ |
||||
|
var assert = require('assert'); |
||||
|
var sec = require('../src/jsbn/sec'); |
||||
|
var ecdsa = require('../').ecdsa; |
||||
|
|
||||
|
var ecparams = sec('secp256k1'); |
||||
|
|
||||
|
describe('ecdsa', function() { |
||||
|
it('handles point ultiplication', function() { |
||||
|
var G = ecparams.getG(); |
||||
|
var n = ecparams.getN(); |
||||
|
|
||||
|
assert.ok(G.multiply(n).isInfinity(), "Gn is infinite"); |
||||
|
|
||||
|
var k = ecdsa.getBigRandom(n); |
||||
|
var P = G.multiply(k); |
||||
|
assert.ok(!P.isInfinity(), "kG is not infinite"); |
||||
|
assert.ok(P.isOnCurve(), "kG on curve"); |
||||
|
assert.ok(P.multiply(n).isInfinity(), "kGn is infinite"); |
||||
|
|
||||
|
assert.ok(P.validate(), "kG validates as a public key"); |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,43 @@ |
|||||
|
/* global describe, it */ |
||||
|
var assert = require('assert'); |
||||
|
var ECKey = require('../src/eckey.js').ECKey; |
||||
|
var convert = require('../src/convert.js'); |
||||
|
var bytesToHex = convert.bytesToHex; |
||||
|
var hexToBytes = convert.hexToBytes; |
||||
|
|
||||
|
describe('ECKey', function() { |
||||
|
describe('constructor (base58 private)', function() { |
||||
|
it('parses case 1', function() { |
||||
|
var priv = '18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725'; |
||||
|
var pub = '0450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b235' + |
||||
|
'22cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6'; |
||||
|
var key = new ECKey(hexToBytes(priv)); |
||||
|
|
||||
|
assert.equal(bytesToHex(key.getPub()['export']('bytes')), pub); |
||||
|
assert.equal(key.compressed, false); |
||||
|
}) |
||||
|
|
||||
|
it('parses case 2', function() { |
||||
|
var priv = '5HwoXVkHoRM8sL2KmNRS217n1g8mPPBomrY7yehCuXC1115WWsh'; |
||||
|
var pub = '044f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0' + |
||||
|
'f0b704075871aa385b6b1b8ead809ca67454d9683fcf2ba03456d6fe2c4abe2b07f0fbdbb2f1c1'; |
||||
|
var addr = '1MsHWS1BnwMc3tLE8G35UXsS58fKipzB7a'; |
||||
|
var key = new ECKey(priv); |
||||
|
|
||||
|
assert.equal(key.compressed, false); |
||||
|
assert.equal(bytesToHex(key.getPub()['export']('bytes')), pub); |
||||
|
assert.equal(key.getBitcoinAddress().toString(), addr); |
||||
|
}) |
||||
|
|
||||
|
it('parses case 3', function() { |
||||
|
var priv = 'KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp'; |
||||
|
var pub = '034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa' |
||||
|
var addr = '1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9'; |
||||
|
var key = new ECKey(priv); |
||||
|
|
||||
|
assert.equal(key.compressed, true); |
||||
|
assert.equal(bytesToHex(key.getPub()['export']('bytes')), pub); |
||||
|
assert.equal(key.getBitcoinAddress().toString(), addr); |
||||
|
}) |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,217 @@ |
|||||
|
/* global describe, it */ |
||||
|
var HDWallet = require('../src/hdwallet.js') |
||||
|
, assert = require('assert') |
||||
|
, convert = require('../src/convert.js') |
||||
|
|
||||
|
var b2h = convert.bytesToHex |
||||
|
|
||||
|
describe('HDWallet', function() { |
||||
|
describe('toBase58', function() { |
||||
|
it('reproduces input', function() { |
||||
|
var input = 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5' |
||||
|
, output = HDWallet.fromBase58(input).toBase58(false) |
||||
|
assert.equal(output, input) |
||||
|
|
||||
|
input = 'xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334' |
||||
|
output = HDWallet.fromBase58(input).toBase58(true) |
||||
|
assert.equal(output, input) |
||||
|
}) |
||||
|
|
||||
|
it('fails with priv=true when theres no private key', function() { |
||||
|
var hd = HDWallet.fromBase58('xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon') |
||||
|
try { |
||||
|
hd.toBase58(true) |
||||
|
} catch(e) { |
||||
|
assert(e.message.match(/private key/i)) |
||||
|
return |
||||
|
} |
||||
|
assert.fail() |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
describe('ctor', function() { |
||||
|
it('creates from seed', function() { |
||||
|
var seed = 'crazy horse battery staple' |
||||
|
, hd = new HDWallet(seed) |
||||
|
|
||||
|
assert(hd.priv) |
||||
|
assert(hd.pub) |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
describe('Test vectors', function() { |
||||
|
it('Test vector 1', function() { |
||||
|
var hd = HDWallet.fromMasterHex('000102030405060708090a0b0c0d0e0f') |
||||
|
|
||||
|
// m
|
||||
|
assert.equal(b2h(hd.getIdentifier()), '3442193e1bb70916e914552172cd4e2dbc9df811') |
||||
|
assert.equal(b2h(hd.getFingerprint()), '3442193e') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma') |
||||
|
assert.equal(hd.priv.toHex(), 'e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b3501') |
||||
|
assert.equal(hd.priv.toWif(), 'L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW') |
||||
|
assert.equal(hd.pub.toHex(), '0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2') |
||||
|
assert.equal(b2h(hd.chaincode), '873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508') |
||||
|
assert.equal(hd.toHex(false), '0488b21e000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d5080339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2') |
||||
|
assert.equal(hd.toHex(true), '0488ade4000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d50800e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35') |
||||
|
assert.equal(hd.toBase58(false), 'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8') |
||||
|
assert.equal(hd.toBase58(true), 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi') |
||||
|
|
||||
|
// m/0'
|
||||
|
hd = hd.derivePrivate(0) |
||||
|
assert.equal(b2h(hd.getIdentifier()), '5c1bd648ed23aa5fd50ba52b2457c11e9e80a6a7') |
||||
|
assert.equal(b2h(hd.getFingerprint()), '5c1bd648') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh') |
||||
|
assert.equal(hd.priv.toHex().slice(0, 64), 'edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea') |
||||
|
assert.equal(hd.priv.toWif(), 'L5BmPijJjrKbiUfG4zbiFKNqkvuJ8usooJmzuD7Z8dkRoTThYnAT') |
||||
|
assert.equal(hd.pub.toHex(), '035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56') |
||||
|
assert.equal(b2h(hd.chaincode), '47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141') |
||||
|
assert.equal(hd.toHex(false), '0488b21e013442193e8000000047fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56') |
||||
|
assert.equal(hd.toHex(true), '0488ade4013442193e8000000047fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae623614100edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea') |
||||
|
assert.equal(hd.toBase58(false), 'xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw') |
||||
|
assert.equal(hd.toBase58(true), 'xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7') |
||||
|
|
||||
|
// m/0'/1
|
||||
|
hd = hd.derive(1) |
||||
|
assert.equal(b2h(hd.getIdentifier()), 'bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe') |
||||
|
assert.equal(b2h(hd.getFingerprint()), 'bef5a2f9') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj') |
||||
|
assert.equal(hd.priv.toHex().slice(0, 64), '3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368') |
||||
|
assert.equal(hd.priv.toWif(), 'KyFAjQ5rgrKvhXvNMtFB5PCSKUYD1yyPEe3xr3T34TZSUHycXtMM') |
||||
|
assert.equal(hd.pub.toHex(), '03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c') |
||||
|
assert.equal(b2h(hd.chaincode), '2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19') |
||||
|
assert.equal(hd.toHex(false), '0488b21e025c1bd648000000012a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c1903501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c') |
||||
|
assert.equal(hd.toHex(true), '0488ade4025c1bd648000000012a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19003c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368') |
||||
|
assert.equal(hd.toBase58(false), 'xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ') |
||||
|
assert.equal(hd.toBase58(true), 'xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs') |
||||
|
|
||||
|
// m/0'/1/2'
|
||||
|
hd = hd.derivePrivate(2) |
||||
|
assert.equal(b2h(hd.getIdentifier()), 'ee7ab90cde56a8c0e2bb086ac49748b8db9dce72') |
||||
|
assert.equal(b2h(hd.getFingerprint()), 'ee7ab90c') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x') |
||||
|
assert.equal(hd.priv.toHex().slice(0, 64), 'cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca') |
||||
|
assert.equal(hd.priv.toWif(), 'L43t3od1Gh7Lj55Bzjj1xDAgJDcL7YFo2nEcNaMGiyRZS1CidBVU') |
||||
|
assert.equal(hd.pub.toHex(), '0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2') |
||||
|
assert.equal(b2h(hd.chaincode), '04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f') |
||||
|
assert.equal(hd.toHex(false), '0488b21e03bef5a2f98000000204466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2') |
||||
|
assert.equal(hd.toHex(true), '0488ade403bef5a2f98000000204466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f00cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca') |
||||
|
assert.equal(hd.toBase58(false), 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5') |
||||
|
assert.equal(hd.toBase58(true), 'xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM') |
||||
|
|
||||
|
// m/0'/1/2'/2
|
||||
|
hd = hd.derive(2) |
||||
|
assert.equal(b2h(hd.getIdentifier()), 'd880d7d893848509a62d8fb74e32148dac68412f') |
||||
|
assert.equal(b2h(hd.getFingerprint()), 'd880d7d8') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '1LjmJcdPnDHhNTUgrWyhLGnRDKxQjoxAgt') |
||||
|
assert.equal(hd.priv.toHex().slice(0, 64), '0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4') |
||||
|
assert.equal(hd.priv.toWif(), 'KwjQsVuMjbCP2Zmr3VaFaStav7NvevwjvvkqrWd5Qmh1XVnCteBR') |
||||
|
assert.equal(hd.pub.toHex(), '02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29') |
||||
|
assert.equal(b2h(hd.chaincode), 'cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd') |
||||
|
assert.equal(hd.toHex(false), '0488b21e04ee7ab90c00000002cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29') |
||||
|
assert.equal(hd.toHex(true), '0488ade404ee7ab90c00000002cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd000f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4') |
||||
|
assert.equal(hd.toBase58(false), 'xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV') |
||||
|
assert.equal(hd.toBase58(true), 'xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334') |
||||
|
|
||||
|
// m/0'/1/2'/2/1000000000
|
||||
|
hd = hd.derive(1000000000) |
||||
|
assert.equal(b2h(hd.getIdentifier()), 'd69aa102255fed74378278c7812701ea641fdf32') |
||||
|
assert.equal(b2h(hd.getFingerprint()), 'd69aa102') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '1LZiqrop2HGR4qrH1ULZPyBpU6AUP49Uam') |
||||
|
assert.equal(hd.priv.toHex().slice(0, 64), '471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8') |
||||
|
assert.equal(hd.priv.toWif(), 'Kybw8izYevo5xMh1TK7aUr7jHFCxXS1zv8p3oqFz3o2zFbhRXHYs') |
||||
|
assert.equal(hd.pub.toHex(), '022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011') |
||||
|
assert.equal(b2h(hd.chaincode), 'c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e') |
||||
|
assert.equal(hd.toHex(false), '0488b21e05d880d7d83b9aca00c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011') |
||||
|
assert.equal(hd.toHex(true), '0488ade405d880d7d83b9aca00c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e00471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8') |
||||
|
assert.equal(hd.toBase58(false), 'xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy') |
||||
|
assert.equal(hd.toBase58(true), 'xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76') |
||||
|
}) |
||||
|
|
||||
|
it('Test vector 2', function() { |
||||
|
var hd = HDWallet.fromMasterHex('fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542') |
||||
|
|
||||
|
// m
|
||||
|
assert.equal(b2h(hd.getIdentifier()), 'bd16bee53961a47d6ad888e29545434a89bdfe95') |
||||
|
assert.equal(b2h(hd.getFingerprint()), 'bd16bee5') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '1JEoxevbLLG8cVqeoGKQiAwoWbNYSUyYjg') |
||||
|
assert.equal(hd.priv.toHex().slice(0, 64), '4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e') |
||||
|
assert.equal(hd.priv.toWif(), 'KyjXhyHF9wTphBkfpxjL8hkDXDUSbE3tKANT94kXSyh6vn6nKaoy') |
||||
|
assert.equal(hd.pub.toHex(), '03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7') |
||||
|
assert.equal(b2h(hd.chaincode), '60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689') |
||||
|
assert.equal(hd.toHex(false), '0488b21e00000000000000000060499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd968903cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7') |
||||
|
assert.equal(hd.toHex(true), '0488ade400000000000000000060499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689004b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e') |
||||
|
assert.equal(hd.toBase58(false), 'xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB') |
||||
|
assert.equal(hd.toBase58(true), 'xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U') |
||||
|
|
||||
|
// m/0
|
||||
|
hd = hd.derive(0) |
||||
|
assert.equal(b2h(hd.getIdentifier()), '5a61ff8eb7aaca3010db97ebda76121610b78096') |
||||
|
assert.equal(b2h(hd.getFingerprint()), '5a61ff8e') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ') |
||||
|
assert.equal(hd.priv.toHex().slice(0, 64), 'abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e') |
||||
|
assert.equal(hd.priv.toWif(), 'L2ysLrR6KMSAtx7uPqmYpoTeiRzydXBattRXjXz5GDFPrdfPzKbj') |
||||
|
assert.equal(hd.pub.toHex(), '02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea') |
||||
|
assert.equal(b2h(hd.chaincode), 'f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c') |
||||
|
assert.equal(hd.toHex(false), '0488b21e01bd16bee500000000f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea') |
||||
|
assert.equal(hd.toHex(true), '0488ade401bd16bee500000000f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c00abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e') |
||||
|
assert.equal(hd.toBase58(false), 'xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH') |
||||
|
assert.equal(hd.toBase58(true), 'xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt') |
||||
|
|
||||
|
// m/0/2147483647'
|
||||
|
hd = hd.derivePrivate(2147483647) |
||||
|
assert.equal(b2h(hd.getIdentifier()), 'd8ab493736da02f11ed682f88339e720fb0379d1') |
||||
|
assert.equal(b2h(hd.getFingerprint()), 'd8ab4937') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '1Lke9bXGhn5VPrBuXgN12uGUphrttUErmk') |
||||
|
assert.equal(hd.priv.toHex().slice(0, 64), '877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93') |
||||
|
assert.equal(hd.priv.toWif(), 'L1m5VpbXmMp57P3knskwhoMTLdhAAaXiHvnGLMribbfwzVRpz2Sr') |
||||
|
assert.equal(hd.pub.toHex(), '03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b') |
||||
|
assert.equal(b2h(hd.chaincode), 'be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9') |
||||
|
assert.equal(hd.toHex(false), '0488b21e025a61ff8effffffffbe17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d903c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b') |
||||
|
assert.equal(hd.toHex(true), '0488ade4025a61ff8effffffffbe17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d900877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93') |
||||
|
assert.equal(hd.toBase58(false), 'xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a') |
||||
|
assert.equal(hd.toBase58(true), 'xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9') |
||||
|
|
||||
|
// m/0/2147483647'/1
|
||||
|
hd = hd.derive(1) |
||||
|
assert.equal(b2h(hd.getIdentifier()), '78412e3a2296a40de124307b6485bd19833e2e34') |
||||
|
assert.equal(b2h(hd.getFingerprint()), '78412e3a') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '1BxrAr2pHpeBheusmd6fHDP2tSLAUa3qsW') |
||||
|
assert.equal(hd.priv.toHex().slice(0, 64), '704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7') |
||||
|
assert.equal(hd.priv.toWif(), 'KzyzXnznxSv249b4KuNkBwowaN3akiNeEHy5FWoPCJpStZbEKXN2') |
||||
|
assert.equal(hd.pub.toHex(), '03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9') |
||||
|
assert.equal(b2h(hd.chaincode), 'f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb') |
||||
|
assert.equal(hd.toHex(false), '0488b21e03d8ab493700000001f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9') |
||||
|
assert.equal(hd.toHex(true), '0488ade403d8ab493700000001f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb00704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7') |
||||
|
assert.equal(hd.toBase58(false), 'xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon') |
||||
|
assert.equal(hd.toBase58(true), 'xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef') |
||||
|
|
||||
|
// m/0/2147483647'/1/2147483646'
|
||||
|
hd = hd.derivePrivate(2147483646) |
||||
|
assert.equal(b2h(hd.getIdentifier()), '31a507b815593dfc51ffc7245ae7e5aee304246e') |
||||
|
assert.equal(b2h(hd.getFingerprint()), '31a507b8') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '15XVotxCAV7sRx1PSCkQNsGw3W9jT9A94R') |
||||
|
assert.equal(hd.priv.toHex().slice(0, 64), 'f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d') |
||||
|
assert.equal(hd.priv.toWif(), 'L5KhaMvPYRW1ZoFmRjUtxxPypQ94m6BcDrPhqArhggdaTbbAFJEF') |
||||
|
assert.equal(hd.pub.toHex(), '02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0') |
||||
|
assert.equal(b2h(hd.chaincode), '637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29') |
||||
|
assert.equal(hd.toHex(false), '0488b21e0478412e3afffffffe637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e2902d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0') |
||||
|
assert.equal(hd.toHex(true), '0488ade40478412e3afffffffe637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e2900f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d') |
||||
|
assert.equal(hd.toBase58(false), 'xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL') |
||||
|
assert.equal(hd.toBase58(true), 'xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc') |
||||
|
|
||||
|
// Chain m/0/2147483647'/1/2147483646'/2
|
||||
|
hd = hd.derive(2) |
||||
|
assert.equal(b2h(hd.getIdentifier()), '26132fdbe7bf89cbc64cf8dafa3f9f88b8666220') |
||||
|
assert.equal(b2h(hd.getFingerprint()), '26132fdb') |
||||
|
assert.equal(hd.getBitcoinAddress().toString(), '14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt') |
||||
|
assert.equal(hd.priv.toHex().slice(0, 64), 'bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23') |
||||
|
assert.equal(hd.priv.toWif(), 'L3WAYNAZPxx1fr7KCz7GN9nD5qMBnNiqEJNJMU1z9MMaannAt4aK') |
||||
|
assert.equal(hd.pub.toHex(), '024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c') |
||||
|
assert.equal(b2h(hd.chaincode), '9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271') |
||||
|
assert.equal(hd.toHex(false), '0488b21e0531a507b8000000029452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c') |
||||
|
assert.equal(hd.toHex(true), '0488ade40531a507b8000000029452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed27100bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23') |
||||
|
assert.equal(hd.toBase58(false), 'xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt') |
||||
|
assert.equal(hd.toBase58(true), 'xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j') |
||||
|
}) |
||||
|
}) |
||||
|
}) |
@ -1,36 +0,0 @@ |
|||||
<!DOCTYPE html> |
|
||||
<html> |
|
||||
<head> |
|
||||
<title>BitcoinJS-lib Test Suite</title> |
|
||||
<link rel="stylesheet" href="../vendor/qunit/qunit.css" type="text/css" media="screen"> |
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script> |
|
||||
<script type="text/javascript" src="../vendor/qunit/qunit.js"></script> |
|
||||
<script type="text/javascript" src="../src/crypto-js/crypto.js"></script> |
|
||||
<script type="text/javascript" src="../src/crypto-js/sha256.js"></script> |
|
||||
<script type="text/javascript" src="../src/jsbn/prng4.js"></script> |
|
||||
<script type="text/javascript" src="../src/jsbn/rng.js"></script> |
|
||||
<script type="text/javascript" src="../src/jsbn/jsbn.js"></script> |
|
||||
<script type="text/javascript" src="../src/jsbn/jsbn2.js"></script> |
|
||||
|
|
||||
<script type="text/javascript" src="../src/jsbn/ec.js"></script> |
|
||||
<script type="text/javascript" src="../src/jsbn/sec.js"></script> |
|
||||
<script type="text/javascript" src="../src/events/eventemitter.js"></script> |
|
||||
<script type="text/javascript" src="../src/bitcoin.js"></script> |
|
||||
<script type="text/javascript" src="../src/util.js"></script> |
|
||||
<script type="text/javascript" src="../src/base58.js"></script> |
|
||||
|
|
||||
<script type="text/javascript" src="../src/address.js"></script> |
|
||||
<script type="text/javascript" src="../src/ecdsa.js"></script> |
|
||||
<script type="text/javascript" src="../src/eckey.js"></script> |
|
||||
<script type="text/javascript" src="../src/paillier.js"></script> |
|
||||
<script type="text/javascript" src="test.js"></script> |
|
||||
</head> |
|
||||
<body> |
|
||||
<h1 id="qunit-header">BitcoinJS-lib Test Suite</h1> |
|
||||
<h2 id="qunit-banner"></h2> |
|
||||
<div id="qunit-testrunner-toolbar"></div> |
|
||||
<h2 id="qunit-userAgent"></h2> |
|
||||
<ol id="qunit-tests"></ol> |
|
||||
<div id="qunit-fixture"></div> |
|
||||
</body> |
|
||||
</html> |
|
@ -0,0 +1,28 @@ |
|||||
|
/* global describe, it */ |
||||
|
var assert = require('assert'); |
||||
|
var BigInteger = require('../src/jsbn/jsbn.js') |
||||
|
var bytesToHex = require('../src/convert.js').bytesToHex; |
||||
|
|
||||
|
describe('BigInteger', function() { |
||||
|
describe('toByteArraySigned', function() { |
||||
|
it('handles examples', function() { |
||||
|
function hex(num) { |
||||
|
var bytes = BigInteger.valueOf(num).toByteArraySigned(); |
||||
|
var h = bytesToHex(bytes); |
||||
|
return '0x' + h; |
||||
|
} |
||||
|
|
||||
|
assert.equal(hex( 0), '0x'); |
||||
|
assert.equal(hex( 1), '0x01'); |
||||
|
assert.equal(hex(-1), '0x81'); |
||||
|
assert.equal(hex( 127), '0x7f'); |
||||
|
assert.equal(hex(-127), '0xff'); |
||||
|
assert.equal(hex( 255), '0x00ff'); |
||||
|
assert.equal(hex(-255), '0x80ff'); |
||||
|
assert.equal(hex( 16300), '0x3fac'); |
||||
|
assert.equal(hex(-16300), '0xbfac'); |
||||
|
assert.equal(hex( 62300), '0x00f35c'); |
||||
|
assert.equal(hex(-62300), '0x80f35c'); |
||||
|
}) |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,34 @@ |
|||||
|
/* global describe, it */ |
||||
|
var assert = require('assert'); |
||||
|
var Message = require('../src/message.js'); |
||||
|
var ECKey = require('../src/eckey.js').ECKey; |
||||
|
var hexToBytes = require('../src/convert.js').hexToBytes; |
||||
|
|
||||
|
var priv = '18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725'; |
||||
|
var addr = '16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM'; |
||||
|
var msg = 'foobar'; |
||||
|
|
||||
|
describe('Message', function() { |
||||
|
describe('verify', function() { |
||||
|
it('passes case 1', function() { |
||||
|
var key = new ECKey(hexToBytes(priv)); |
||||
|
assert.equal(key.getBitcoinAddress().toString(), addr); |
||||
|
|
||||
|
var sig = Message.signMessage(key, msg); |
||||
|
assert.ok(Message.verifyMessage(addr, sig, msg)); |
||||
|
|
||||
|
// wrong message
|
||||
|
assert.ok(!Message.verifyMessage(addr, sig, 'not foobar')); |
||||
|
|
||||
|
// wrong address
|
||||
|
assert.ok(!Message.verifyMessage('1MsHWS1BnwMc3tLE8G35UXsS58fKipzB7a', sig, msg)); |
||||
|
}) |
||||
|
|
||||
|
it('passes case 2', function() { |
||||
|
var priv = '5HwoXVkHoRM8sL2KmNRS217n1g8mPPBomrY7yehCuXC1115WWsh'; |
||||
|
var key = new ECKey(hexToBytes(priv)); |
||||
|
var sig = Message.signMessage(key, msg); |
||||
|
assert.ok(!Message.verifyMessage(addr, sig, msg)); |
||||
|
}) |
||||
|
}) |
||||
|
}) |
@ -0,0 +1,68 @@ |
|||||
|
/* global it */ |
||||
|
var assert = require('assert'); |
||||
|
var bitcoinjs = require('../'); |
||||
|
var sec = require('../src/jsbn/sec'); |
||||
|
var BigInteger = require('../src/jsbn/jsbn.js'); |
||||
|
var Crypto = require('../src/crypto-js/crypto.js'); |
||||
|
|
||||
|
var SecureRandom = require('../src/jsbn/rng'); |
||||
|
var rng = new SecureRandom(); |
||||
|
|
||||
|
var ecparams = sec('secp256k1'); |
||||
|
var ECPointFp = bitcoinjs.ECPointFp; |
||||
|
|
||||
|
it('Keys & Key Management', function () { |
||||
|
var p1 = bitcoinjs.Key().getPub()['export']('bytes'); |
||||
|
assert.equal(p1.length, 65); |
||||
|
|
||||
|
var p1_q = ECPointFp.decodeFrom(ecparams.getCurve(), p1); |
||||
|
assert.ok(p1_q); |
||||
|
assert.ok(p1_q.validate()); |
||||
|
|
||||
|
var p2 = bitcoinjs.convert.hexToBytes( |
||||
|
'0486f356006a38b847bedec1bf47013776925d939d5a35a97a4d1263e550c7f1a' + |
||||
|
'b5aba44ab74d22892097a0e851addf07ba97e33416df5affaceeb35d5607cd23c'); |
||||
|
|
||||
|
var p2_q = ECPointFp.decodeFrom(ecparams.getCurve(), p2); |
||||
|
assert.ok(p2_q); |
||||
|
assert.ok(p2_q.validate()); |
||||
|
}); |
||||
|
|
||||
|
it('Signing and Verifying', function () { |
||||
|
var s1 = bitcoinjs.Key(); |
||||
|
var sig_a = s1.sign(BigInteger.ZERO); |
||||
|
assert.ok(sig_a, 'Sign null'); |
||||
|
|
||||
|
assert.ok(s1.verify(BigInteger.ZERO, sig_a)); |
||||
|
|
||||
|
var message = new BigInteger(1024, rng).toByteArrayUnsigned(); |
||||
|
var hash = Crypto.SHA256(message, { |
||||
|
asBytes: true |
||||
|
}); |
||||
|
var sig_b = s1.sign(hash); |
||||
|
assert.ok(sig_b, 'Sign random string'); |
||||
|
assert.ok(s1.verify(hash, sig_b)); |
||||
|
|
||||
|
var message2 = bitcoinjs.convert.hexToBytes( |
||||
|
'12dce2c169986b3346827ffb2305cf393984627f5f9722a1b1368e933c8d' + |
||||
|
'd296653fbe5d7ac031c4962ad0eb1c4298c3b91d244e1116b4a76a130c13' + |
||||
|
'1e7aec7fa70184a71a2e66797052831511b93c6e8d72ae58a1980eaacb66' + |
||||
|
'8a33f50d7cefb96a5dab897b5efcb99cbafb0d777cb83fc9b2115b69c0fa' + |
||||
|
'3d82507b932b84e4'); |
||||
|
|
||||
|
var hash2 = Crypto.SHA256(message2, { |
||||
|
asBytes: true |
||||
|
}); |
||||
|
|
||||
|
var sig_c = bitcoinjs.convert.hexToBytes( |
||||
|
'3044022038d9b8dd5c9fbf330565c1f51d72a59ba869aeb2c2001be959d3' + |
||||
|
'79e861ec71960220a73945f32cf90d03127d2c3410d16cee120fa1a4b4c3' + |
||||
|
'f273ab082801a95506c4'); |
||||
|
|
||||
|
var s2 = bitcoinjs.convert.hexToBytes( |
||||
|
'045a1594316e433fb91f35ef4874610d22177c3f1a1060f6c1e70a609d51' + |
||||
|
'b20be5795cd2a5eae0d6b872ba42db95e9afaeea3fbb89e98099575b6828' + |
||||
|
'609a978528'); |
||||
|
|
||||
|
assert.ok(bitcoinjs.ecdsa.verify(hash2, sig_c, s2), 'Verify constant signature'); |
||||
|
}); |
@ -0,0 +1 @@ |
|||||
|
--ui qunit |
@ -1,112 +0,0 @@ |
|||||
//
|
|
||||
// Testing elliptic curve math
|
|
||||
// -----------------------------------------------------------------------------
|
|
||||
module("ec"); |
|
||||
|
|
||||
var ecparams = getSECCurveByName("secp256k1"); |
|
||||
var rng = new SecureRandom(); |
|
||||
|
|
||||
test("Classes", function () { |
|
||||
expect(3); |
|
||||
ok(ECPointFp, "ECPointFp"); |
|
||||
ok(ECFieldElementFp, "ECFieldElementFp"); |
|
||||
ok(ECCurveFp, "ECCurveFp"); |
|
||||
}); |
|
||||
|
|
||||
test("Point multiplication", function () { |
|
||||
expect(5); |
|
||||
|
|
||||
var G = ecparams.getG(); |
|
||||
var n = ecparams.getN(); |
|
||||
|
|
||||
ok(G.multiply(n).isInfinity(), "Gn is infinite"); |
|
||||
|
|
||||
var k = Bitcoin.ECDSA.getBigRandom(n); |
|
||||
var P = G.multiply(k); |
|
||||
ok(!P.isInfinity(), "kG is not infinite"); |
|
||||
ok(P.isOnCurve(), "kG on curve"); |
|
||||
ok(P.multiply(n).isInfinity(), "kGn is infinite"); |
|
||||
|
|
||||
ok(P.validate(), "kG validates as a public key"); |
|
||||
}); |
|
||||
|
|
||||
|
|
||||
//
|
|
||||
// Testing ECDSA
|
|
||||
// -----------------------------------------------------------------------------
|
|
||||
module("ecdsa"); |
|
||||
|
|
||||
test("Classes", function () { |
|
||||
expect(2); |
|
||||
ok(Bitcoin.ECDSA, "Bitcoin.ECDSA"); |
|
||||
ok(Bitcoin.ECKey, "Bitcoin.ECKey"); |
|
||||
}); |
|
||||
|
|
||||
test("Keys & Key Management", function () { |
|
||||
expect(5); |
|
||||
|
|
||||
var s1 = new Bitcoin.ECKey(); |
|
||||
var p1 = s1.getPub(); |
|
||||
equals(p1.length, 65, "Public key is correct length"); |
|
||||
|
|
||||
var p1_q = ECPointFp.decodeFrom(ecparams.getCurve(), p1); |
|
||||
ok(p1_q, "Decode point from generated bytestring"); |
|
||||
ok(p1_q.validate(), "Is a valid public point"); |
|
||||
|
|
||||
var p2 = Crypto.util.hexToBytes( |
|
||||
"0486f356006a38b847bedec1bf47013776925d939d5a35a97a4d1263e550c7f1a" + |
|
||||
"b5aba44ab74d22892097a0e851addf07ba97e33416df5affaceeb35d5607cd23c" |
|
||||
); |
|
||||
var p2_q = ECPointFp.decodeFrom(ecparams.getCurve(), p2); |
|
||||
ok(p2_q, "Decode point from constant"); |
|
||||
ok(p2_q.validate(), "Is a valid public point"); |
|
||||
}); |
|
||||
|
|
||||
test("Signing and Verifying", function () { |
|
||||
expect(7); |
|
||||
|
|
||||
var s1 = new Bitcoin.ECKey(); |
|
||||
var sig_a = s1.sign(BigInteger.ZERO); |
|
||||
ok(sig_a, "Sign null"); |
|
||||
equals(sig_a.length, 70, "Signature is correct length"); |
|
||||
ok(s1.verify(BigInteger.ZERO, sig_a)); |
|
||||
|
|
||||
var message = new BigInteger(1024, rng).toByteArrayUnsigned(); |
|
||||
var hash = Crypto.SHA256(message, {asBytes: true}); |
|
||||
var sig_b = s1.sign(hash); |
|
||||
ok(sig_b, "Sign random string"); |
|
||||
equals(sig_b.length, 70, "Signature is correct length"); |
|
||||
ok(s1.verify(hash, sig_b)); |
|
||||
|
|
||||
var message2 = Crypto.util.hexToBytes( |
|
||||
"12dce2c169986b3346827ffb2305cf393984627f5f9722a1b1368e933c8d" + |
|
||||
"d296653fbe5d7ac031c4962ad0eb1c4298c3b91d244e1116b4a76a130c13" + |
|
||||
"1e7aec7fa70184a71a2e66797052831511b93c6e8d72ae58a1980eaacb66" + |
|
||||
"8a33f50d7cefb96a5dab897b5efcb99cbafb0d777cb83fc9b2115b69c0fa" + |
|
||||
"3d82507b932b84e4" |
|
||||
); |
|
||||
var hash2 = Crypto.SHA256(message2, {asBytes: true}); |
|
||||
var sig_c = Crypto.util.hexToBytes( |
|
||||
"3044022038d9b8dd5c9fbf330565c1f51d72a59ba869aeb2c2001be959d3" + |
|
||||
"79e861ec71960220a73945f32cf90d03127d2c3410d16cee120fa1a4b4c3" + |
|
||||
"f273ab082801a95506c4" |
|
||||
); |
|
||||
var s2 = Crypto.util.hexToBytes( |
|
||||
"045a1594316e433fb91f35ef4874610d22177c3f1a1060f6c1e70a609d51" + |
|
||||
"b20be5795cd2a5eae0d6b872ba42db95e9afaeea3fbb89e98099575b6828" + |
|
||||
"609a978528" |
|
||||
); |
|
||||
ok(Bitcoin.ECDSA.verify(hash2, sig_c, s2), "Verify constant signature"); |
|
||||
}); |
|
||||
|
|
||||
//
|
|
||||
// Testing Paillier
|
|
||||
// -----------------------------------------------------------------------------
|
|
||||
module("paillier"); |
|
||||
|
|
||||
test("Classes", function () { |
|
||||
expect(3); |
|
||||
ok(Bitcoin.Paillier, "Bitcoin.Paillier"); |
|
||||
ok(Bitcoin.Paillier.PublicKey, "Bitcoin.Paillier.PublicKey"); |
|
||||
ok(Bitcoin.Paillier.PrivateKey, "Bitcoin.Paillier.PrivateKey"); |
|
||||
}); |
|
@ -1,226 +0,0 @@ |
|||||
/** |
|
||||
* QUnit - A JavaScript Unit Testing Framework |
|
||||
* |
|
||||
* http://docs.jquery.com/QUnit |
|
||||
* |
|
||||
* Copyright (c) 2011 John Resig, Jörn Zaefferer |
|
||||
* Dual licensed under the MIT (MIT-LICENSE.txt) |
|
||||
* or GPL (GPL-LICENSE.txt) licenses. |
|
||||
*/ |
|
||||
|
|
||||
/** Font Family and Sizes */ |
|
||||
|
|
||||
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { |
|
||||
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; |
|
||||
} |
|
||||
|
|
||||
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } |
|
||||
#qunit-tests { font-size: smaller; } |
|
||||
|
|
||||
|
|
||||
/** Resets */ |
|
||||
|
|
||||
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { |
|
||||
margin: 0; |
|
||||
padding: 0; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/** Header */ |
|
||||
|
|
||||
#qunit-header { |
|
||||
padding: 0.5em 0 0.5em 1em; |
|
||||
|
|
||||
color: #8699a4; |
|
||||
background-color: #0d3349; |
|
||||
|
|
||||
font-size: 1.5em; |
|
||||
line-height: 1em; |
|
||||
font-weight: normal; |
|
||||
|
|
||||
border-radius: 15px 15px 0 0; |
|
||||
-moz-border-radius: 15px 15px 0 0; |
|
||||
-webkit-border-top-right-radius: 15px; |
|
||||
-webkit-border-top-left-radius: 15px; |
|
||||
} |
|
||||
|
|
||||
#qunit-header a { |
|
||||
text-decoration: none; |
|
||||
color: #c2ccd1; |
|
||||
} |
|
||||
|
|
||||
#qunit-header a:hover, |
|
||||
#qunit-header a:focus { |
|
||||
color: #fff; |
|
||||
} |
|
||||
|
|
||||
#qunit-banner { |
|
||||
height: 5px; |
|
||||
} |
|
||||
|
|
||||
#qunit-testrunner-toolbar { |
|
||||
padding: 0.5em 0 0.5em 2em; |
|
||||
color: #5E740B; |
|
||||
background-color: #eee; |
|
||||
} |
|
||||
|
|
||||
#qunit-userAgent { |
|
||||
padding: 0.5em 0 0.5em 2.5em; |
|
||||
background-color: #2b81af; |
|
||||
color: #fff; |
|
||||
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/** Tests: Pass/Fail */ |
|
||||
|
|
||||
#qunit-tests { |
|
||||
list-style-position: inside; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests li { |
|
||||
padding: 0.4em 0.5em 0.4em 2.5em; |
|
||||
border-bottom: 1px solid #fff; |
|
||||
list-style-position: inside; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { |
|
||||
display: none; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests li strong { |
|
||||
cursor: pointer; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests li a { |
|
||||
padding: 0.5em; |
|
||||
color: #c2ccd1; |
|
||||
text-decoration: none; |
|
||||
} |
|
||||
#qunit-tests li a:hover, |
|
||||
#qunit-tests li a:focus { |
|
||||
color: #000; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests ol { |
|
||||
margin-top: 0.5em; |
|
||||
padding: 0.5em; |
|
||||
|
|
||||
background-color: #fff; |
|
||||
|
|
||||
border-radius: 15px; |
|
||||
-moz-border-radius: 15px; |
|
||||
-webkit-border-radius: 15px; |
|
||||
|
|
||||
box-shadow: inset 0px 2px 13px #999; |
|
||||
-moz-box-shadow: inset 0px 2px 13px #999; |
|
||||
-webkit-box-shadow: inset 0px 2px 13px #999; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests table { |
|
||||
border-collapse: collapse; |
|
||||
margin-top: .2em; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests th { |
|
||||
text-align: right; |
|
||||
vertical-align: top; |
|
||||
padding: 0 .5em 0 0; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests td { |
|
||||
vertical-align: top; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests pre { |
|
||||
margin: 0; |
|
||||
white-space: pre-wrap; |
|
||||
word-wrap: break-word; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests del { |
|
||||
background-color: #e0f2be; |
|
||||
color: #374e0c; |
|
||||
text-decoration: none; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests ins { |
|
||||
background-color: #ffcaca; |
|
||||
color: #500; |
|
||||
text-decoration: none; |
|
||||
} |
|
||||
|
|
||||
/*** Test Counts */ |
|
||||
|
|
||||
#qunit-tests b.counts { color: black; } |
|
||||
#qunit-tests b.passed { color: #5E740B; } |
|
||||
#qunit-tests b.failed { color: #710909; } |
|
||||
|
|
||||
#qunit-tests li li { |
|
||||
margin: 0.5em; |
|
||||
padding: 0.4em 0.5em 0.4em 0.5em; |
|
||||
background-color: #fff; |
|
||||
border-bottom: none; |
|
||||
list-style-position: inside; |
|
||||
} |
|
||||
|
|
||||
/*** Passing Styles */ |
|
||||
|
|
||||
#qunit-tests li li.pass { |
|
||||
color: #5E740B; |
|
||||
background-color: #fff; |
|
||||
border-left: 26px solid #C6E746; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } |
|
||||
#qunit-tests .pass .test-name { color: #366097; } |
|
||||
|
|
||||
#qunit-tests .pass .test-actual, |
|
||||
#qunit-tests .pass .test-expected { color: #999999; } |
|
||||
|
|
||||
#qunit-banner.qunit-pass { background-color: #C6E746; } |
|
||||
|
|
||||
/*** Failing Styles */ |
|
||||
|
|
||||
#qunit-tests li li.fail { |
|
||||
color: #710909; |
|
||||
background-color: #fff; |
|
||||
border-left: 26px solid #EE5757; |
|
||||
white-space: pre; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests > li:last-child { |
|
||||
border-radius: 0 0 15px 15px; |
|
||||
-moz-border-radius: 0 0 15px 15px; |
|
||||
-webkit-border-bottom-right-radius: 15px; |
|
||||
-webkit-border-bottom-left-radius: 15px; |
|
||||
} |
|
||||
|
|
||||
#qunit-tests .fail { color: #000000; background-color: #EE5757; } |
|
||||
#qunit-tests .fail .test-name, |
|
||||
#qunit-tests .fail .module-name { color: #000000; } |
|
||||
|
|
||||
#qunit-tests .fail .test-actual { color: #EE5757; } |
|
||||
#qunit-tests .fail .test-expected { color: green; } |
|
||||
|
|
||||
#qunit-banner.qunit-fail { background-color: #EE5757; } |
|
||||
|
|
||||
|
|
||||
/** Result */ |
|
||||
|
|
||||
#qunit-testresult { |
|
||||
padding: 0.5em 0.5em 0.5em 2.5em; |
|
||||
|
|
||||
color: #2b81af; |
|
||||
background-color: #D2E0E6; |
|
||||
|
|
||||
border-bottom: 1px solid white; |
|
||||
} |
|
||||
|
|
||||
/** Fixture */ |
|
||||
|
|
||||
#qunit-fixture { |
|
||||
position: absolute; |
|
||||
top: -10000px; |
|
||||
left: -10000px; |
|
||||
} |
|
File diff suppressed because it is too large
Loading…
Reference in new issue