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 |
|||
* 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 base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
|||
|
|||
// Global Crypto object
|
|||
var Crypto = window.Crypto = {}; |
|||
|
|||
// Crypto utilities
|
|||
var util = Crypto.util = { |
|||
|
|||
// Bit-wise rotate left
|
|||
rotl: function (n, b) { |
|||
return (n << b) | (n >>> (32 - b)); |
|||
}, |
|||
|
|||
// Bit-wise rotate right
|
|||
rotr: function (n, b) { |
|||
return (n << (32 - b)) | (n >>> b); |
|||
}, |
|||
|
|||
// Swap big-endian to little-endian and vice versa
|
|||
endian: function (n) { |
|||
|
|||
// If number given, swap endian
|
|||
if (n.constructor == Number) { |
|||
return util.rotl(n, 8) & 0x00FF00FF | |
|||
util.rotl(n, 24) & 0xFF00FF00; |
|||
} |
|||
|
|||
// Else, assume array and swap all items
|
|||
for (var i = 0; i < n.length; i++) |
|||
n[i] = util.endian(n[i]); |
|||
return n; |
|||
|
|||
}, |
|||
|
|||
// Generate an array of any length of random bytes
|
|||
randomBytes: function (n) { |
|||
for (var bytes = []; n > 0; n--) |
|||
bytes.push(Math.floor(Math.random() * 256)); |
|||
return bytes; |
|||
}, |
|||
|
|||
// Convert a byte array to big-endian 32-bit words
|
|||
bytesToWords: function (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 big-endian 32-bit words to a byte array
|
|||
wordsToBytes: function (words) { |
|||
for (var bytes = [], b = 0; b < words.length * 32; b += 8) |
|||
bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); |
|||
return bytes; |
|||
}, |
|||
|
|||
// Convert a byte array to a hex string
|
|||
bytesToHex: function (bytes) { |
|||
for (var hex = [], i = 0; i < bytes.length; i++) { |
|||
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(""); |
|||
} |
|||
|
|||
}; |
|||
|
|||
})(); |
|||
/*! |
|||
* 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
|
|||
*/ |
|||
|
|||
// Global Crypto object
|
|||
var Crypto = module.exports = {}; |
|||
|
|||
// Crypto utilities
|
|||
var util = Crypto.util = { |
|||
|
|||
// Generate an array of any length of random bytes
|
|||
randomBytes: function (n) { |
|||
for (var bytes = []; n > 0; n--) |
|||
bytes.push(Math.floor(Math.random() * 256)); |
|||
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(""); |
|||
} |
|||
|
|||
}; |
|||
|
|||
module.exports.SHA256 = require('./sha256'); |
|||
module.exports.SHA512 = require('./sha512'); |
|||
module.exports.RIPEMD160 = require('./ripemd160'); |
|||
module.exports.HMAC = require('./hmac'); |
|||
|
@ -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 |
|||
* http://code.google.com/p/crypto-js/
|
|||
* Copyright (c) 2009, Jeff Mott. All rights reserved. |
|||
* http://code.google.com/p/crypto-js/wiki/License
|
|||
* |
|||
* A JavaScript implementation of the RIPEMD-160 Algorithm |
|||
* Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009. |
|||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet |
|||
* Distributed under the BSD License |
|||
* See http://pajhome.org.uk/crypt/md5 for details.
|
|||
* Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
|
|||
* Ported to Crypto-JS by Stefan Thomas. |
|||
/* |
|||
CryptoJS v3.1.2 |
|||
code.google.com/p/crypto-js |
|||
(c) 2009-2013 by Jeff Mott. All rights reserved. |
|||
code.google.com/p/crypto-js/wiki/License |
|||
*/ |
|||
/** @preserve |
|||
(c) 2012 by Cédric Mesnil. All rights reserved. |
|||
|
|||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
|||
|
|||
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
|||
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
|||
|
|||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
*/ |
|||
|
|||
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 () { |
|||
// Shortcuts
|
|||
var C = Crypto, |
|||
util = C.util, |
|||
charenc = C.charenc, |
|||
UTF8 = charenc.UTF8, |
|||
Binary = charenc.Binary; |
|||
|
|||
// Convert a byte array to little-endian 32-bit words
|
|||
util.bytesToLWords = function (bytes) { |
|||
|
|||
var output = Array(bytes.length >> 2); |
|||
for (var i = 0; i < output.length; i++) |
|||
output[i] = 0; |
|||
for (var i = 0; i < bytes.length * 8; i += 8) |
|||
output[i>>5] |= (bytes[i / 8] & 0xFF) << (i%32); |
|||
return output; |
|||
}; |
|||
|
|||
// Convert little-endian 32-bit words to a byte array
|
|||
util.lWordsToBytes = function (words) { |
|||
var output = []; |
|||
for (var i = 0; i < words.length * 32; i += 8) |
|||
output.push((words[i>>5] >>> (i % 32)) & 0xff); |
|||
return output; |
|||
}; |
|||
|
|||
// Public API
|
|||
var RIPEMD160 = C.RIPEMD160 = function (message, options) { |
|||
var digestbytes = util.lWordsToBytes(RIPEMD160._rmd160(message)); |
|||
return options && options.asBytes ? digestbytes : |
|||
options && options.asString ? Binary.bytesToString(digestbytes) : |
|||
util.bytesToHex(digestbytes); |
|||
}; |
|||
|
|||
// The core
|
|||
RIPEMD160._rmd160 = function (message) |
|||
{ |
|||
// Convert to byte array
|
|||
if (message.constructor == String) message = UTF8.stringToBytes(message); |
|||
|
|||
var x = util.bytesToLWords(message), |
|||
len = message.length * 8; |
|||
|
|||
/* append padding */ |
|||
x[len >> 5] |= 0x80 << (len % 32); |
|||
x[(((len + 64) >>> 9) << 4) + 14] = len; |
|||
|
|||
var h0 = 0x67452301; |
|||
var h1 = 0xefcdab89; |
|||
var h2 = 0x98badcfe; |
|||
var h3 = 0x10325476; |
|||
var h4 = 0xc3d2e1f0; |
|||
|
|||
for (var i = 0; i < x.length; i += 16) { |
|||
var T; |
|||
var A1 = h0, B1 = h1, C1 = h2, D1 = h3, E1 = h4; |
|||
var A2 = h0, B2 = h1, C2 = h2, D2 = h3, E2 = h4; |
|||
for (var j = 0; j <= 79; ++j) { |
|||
T = safe_add(A1, rmd160_f(j, B1, C1, D1)); |
|||
T = safe_add(T, x[i + rmd160_r1[j]]); |
|||
T = safe_add(T, rmd160_K1(j)); |
|||
T = safe_add(bit_rol(T, rmd160_s1[j]), E1); |
|||
A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T; |
|||
T = safe_add(A2, rmd160_f(79-j, B2, C2, D2)); |
|||
T = safe_add(T, x[i + rmd160_r2[j]]); |
|||
T = safe_add(T, rmd160_K2(j)); |
|||
T = safe_add(bit_rol(T, rmd160_s2[j]), E2); |
|||
A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T; |
|||
} |
|||
T = safe_add(h1, safe_add(C1, D2)); |
|||
h1 = safe_add(h2, safe_add(D1, E2)); |
|||
h2 = safe_add(h3, safe_add(E1, A2)); |
|||
h3 = safe_add(h4, safe_add(A1, B2)); |
|||
h4 = safe_add(h0, safe_add(B1, C2)); |
|||
h0 = T; |
|||
} |
|||
return [h0, h1, h2, h3, h4]; |
|||
} |
|||
|
|||
function rmd160_f(j, x, y, z) |
|||
{ |
|||
return ( 0 <= j && j <= 15) ? (x ^ y ^ z) : |
|||
(16 <= j && j <= 31) ? (x & y) | (~x & z) : |
|||
(32 <= j && j <= 47) ? (x | ~y) ^ z : |
|||
(48 <= j && j <= 63) ? (x & z) | (y & ~z) : |
|||
(64 <= j && j <= 79) ? x ^ (y | ~z) : |
|||
"rmd160_f: j out of range"; |
|||
} |
|||
function rmd160_K1(j) |
|||
{ |
|||
return ( 0 <= j && j <= 15) ? 0x00000000 : |
|||
(16 <= j && j <= 31) ? 0x5a827999 : |
|||
(32 <= j && j <= 47) ? 0x6ed9eba1 : |
|||
(48 <= j && j <= 63) ? 0x8f1bbcdc : |
|||
(64 <= j && j <= 79) ? 0xa953fd4e : |
|||
"rmd160_K1: j out of range"; |
|||
} |
|||
function rmd160_K2(j) |
|||
{ |
|||
return ( 0 <= j && j <= 15) ? 0x50a28be6 : |
|||
(16 <= j && j <= 31) ? 0x5c4dd124 : |
|||
(32 <= j && j <= 47) ? 0x6d703ef3 : |
|||
(48 <= j && j <= 63) ? 0x7a6d76e9 : |
|||
(64 <= j && j <= 79) ? 0x00000000 : |
|||
"rmd160_K2: j out of range"; |
|||
} |
|||
var rmd160_r1 = [ |
|||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, |
|||
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, |
|||
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, |
|||
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, |
|||
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 |
|||
]; |
|||
var rmd160_r2 = [ |
|||
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, |
|||
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, |
|||
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, |
|||
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, |
|||
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 |
|||
]; |
|||
var rmd160_s1 = [ |
|||
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, |
|||
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, |
|||
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, |
|||
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, |
|||
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 |
|||
]; |
|||
var rmd160_s2 = [ |
|||
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, |
|||
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, |
|||
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, |
|||
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, |
|||
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 |
|||
]; |
|||
|
|||
/* |
|||
* Add integers, wrapping at 2^32. This uses 16-bit operations internally |
|||
* to work around bugs in some JS interpreters. |
|||
*/ |
|||
function safe_add(x, y) |
|||
{ |
|||
var lsw = (x & 0xFFFF) + (y & 0xFFFF); |
|||
var msw = (x >> 16) + (y >> 16) + (lsw >> 16); |
|||
return (msw << 16) | (lsw & 0xFFFF); |
|||
} |
|||
|
|||
/* |
|||
* Bitwise rotate a 32-bit number to the left. |
|||
*/ |
|||
function bit_rol(num, cnt) |
|||
{ |
|||
return (num << cnt) | (num >>> (32 - cnt)); |
|||
} |
|||
})(); |
|||
var digestbytes = wordsToBytes(H); |
|||
return options && options.asBytes ? digestbytes : |
|||
options && options.asString ? Binary.bytesToString(digestbytes) : |
|||
conv.bytesToHex(digestbytes); |
|||
}; |
|||
|
@ -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 |
|||
* 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(){ |
|||
|
|||
// Shortcuts
|
|||
var C = Crypto, |
|||
util = C.util, |
|||
charenc = C.charenc, |
|||
UTF8 = charenc.UTF8, |
|||
Binary = charenc.Binary; |
|||
|
|||
// Constants
|
|||
var K = [ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, |
|||
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, |
|||
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, |
|||
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, |
|||
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, |
|||
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, |
|||
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, |
|||
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, |
|||
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, |
|||
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, |
|||
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, |
|||
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, |
|||
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, |
|||
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, |
|||
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, |
|||
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 ]; |
|||
|
|||
// Public API
|
|||
var SHA256 = C.SHA256 = function (message, options) { |
|||
var digestbytes = util.wordsToBytes(SHA256._sha256(message)); |
|||
return options && options.asBytes ? digestbytes : |
|||
options && options.asString ? Binary.bytesToString(digestbytes) : |
|||
util.bytesToHex(digestbytes); |
|||
/* |
|||
CryptoJS v3.1.2 |
|||
code.google.com/p/crypto-js |
|||
(c) 2009-2013 by Jeff Mott. All rights reserved. |
|||
code.google.com/p/crypto-js/wiki/License |
|||
*/ |
|||
|
|||
var conv = require('../convert'), |
|||
util = require('../util'); |
|||
|
|||
// Initialization round constants tables
|
|||
var K = []; |
|||
|
|||
// Compute constants
|
|||
(function () { |
|||
function isPrime(n) { |
|||
var sqrtN = Math.sqrt(n); |
|||
for (var factor = 2; factor <= sqrtN; factor++) { |
|||
if (!(n % factor)) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
function getFractionalBits(n) { |
|||
return ((n - (n | 0)) * 0x100000000) | 0; |
|||
} |
|||
|
|||
var n = 2; |
|||
var nPrime = 0; |
|||
while (nPrime < 64) { |
|||
if (isPrime(n)) { |
|||
K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); |
|||
nPrime++; |
|||
} |
|||
|
|||
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) { |
|||
|
|||
// Convert to byte array
|
|||
if (message.constructor == String) message = UTF8.stringToBytes(message); |
|||
/* else, assume byte array already */ |
|||
|
|||
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; |
|||
/** |
|||
* SHA-256 hash algorithm. |
|||
*/ |
|||
module.exports = function(message, options) {; |
|||
|
|||
var H =[ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, |
|||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 ]; |
|||
|
|||
}; |
|||
if (message.constructor === String) { |
|||
message = conv.stringToBytes(message); |
|||
} |
|||
|
|||
// Package private blocksize
|
|||
SHA256._blocksize = 16; |
|||
var m = util.bytesToWords(message); |
|||
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 ECDSA = Bitcoin.ECDSA; |
|||
var ecparams = getSECCurveByName("secp256k1"); |
|||
var rng = new SecureRandom(); |
|||
|
|||
var ECKey = function (input) { |
|||
var BigInteger = require('./jsbn/jsbn'); |
|||
var sec = require('./jsbn/sec'); |
|||
var base58 = require('./base58'); |
|||
var Crypto = require('./crypto-js/crypto'); |
|||
var util = require('./util'); |
|||
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) { |
|||
// Generate new key
|
|||
var n = ecparams.getN(); |
|||
this.priv = ECDSA.getBigRandom(n); |
|||
} else if (input instanceof BigInteger) { |
|||
// 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!"; |
|||
// Generate new key
|
|||
var n = ecparams.getN(); |
|||
this.priv = ecdsa.getBigRandom(n); |
|||
this.compressed = compressed || false; |
|||
} |
|||
|
|||
var version = hash.shift(); |
|||
|
|||
if (version != 0x80) { |
|||
throw "Version "+version+" not supported!"; |
|||
else this.import(input,compressed) |
|||
}; |
|||
|
|||
ECKey.prototype.import = function (input,compressed) { |
|||
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; |
|||
} |
|||
|
|||
return hash; |
|||
}; |
|||
|
|||
return ECKey; |
|||
})(); |
|||
else this.import(input,compressed) |
|||
} |
|||
|
|||
ECPubKey.prototype.import = function(input,compressed) { |
|||
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. |
|||
*/ |
|||
Bitcoin.Message = (function () { |
|||
var Message = {}; |
|||
/// Implements Bitcoin's feature for signing arbitrary messages.
|
|||
|
|||
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 magicBytes = Crypto.charenc.UTF8.stringToBytes(Message.magicPrefix); |
|||
var messageBytes = Crypto.charenc.UTF8.stringToBytes(message); |
|||
var Message = {}; |
|||
|
|||
var buffer = []; |
|||
buffer = buffer.concat(Bitcoin.Util.numToVarInt(magicBytes.length)); |
|||
buffer = buffer.concat(magicBytes); |
|||
buffer = buffer.concat(Bitcoin.Util.numToVarInt(messageBytes.length)); |
|||
buffer = buffer.concat(messageBytes); |
|||
Message.magicPrefix = "Bitcoin Signed Message:\n"; |
|||
|
|||
return buffer; |
|||
}; |
|||
Message.makeMagicMessage = function (message) { |
|||
var magicBytes = conv.stringToBytes(Message.magicPrefix); |
|||
var messageBytes = conv.stringToBytes(message); |
|||
|
|||
Message.getHash = function (message) { |
|||
var buffer = Message.makeMagicMessage(message); |
|||
return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true}); |
|||
}; |
|||
var buffer = []; |
|||
buffer = buffer.concat(util.numToVarInt(magicBytes.length)); |
|||
buffer = buffer.concat(magicBytes); |
|||
buffer = buffer.concat(util.numToVarInt(messageBytes.length)); |
|||
buffer = buffer.concat(messageBytes); |
|||
|
|||
Message.signMessage = function (key, message, compressed) { |
|||
var hash = Message.getHash(message); |
|||
return buffer; |
|||
}; |
|||
|
|||
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 i = Bitcoin.ECDSA.calcPubkeyRecoveryParam(address, obj.r, obj.s, hash); |
|||
var sig = key.sign(hash); |
|||
|
|||
i += 27; |
|||
if (compressed) i += 4; |
|||
var obj = ecdsa.parseSig(sig); |
|||
|
|||
var rBa = obj.r.toByteArrayUnsigned(); |
|||
var sBa = obj.s.toByteArrayUnsigned(); |
|||
var i = ecdsa.calcPubkeyRecoveryParam(key, obj.r, obj.s, hash); |
|||
|
|||
// Pad to 32 bytes per value
|
|||
while (rBa.length < 32) rBa.unshift(0); |
|||
while (sBa.length < 32) sBa.unshift(0); |
|||
i += 27; |
|||
if (compressed) i += 4; |
|||
|
|||
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 = Crypto.util.base64ToBytes(sig); |
|||
sig = Bitcoin.ECDSA.parseSigCompact(sig); |
|||
sig = [i].concat(rBa).concat(sBa); |
|||
|
|||
var hash = Message.getHash(message); |
|||
return conv.bytesToHex(sig); |
|||
}; |
|||
|
|||
var isCompressed = !!(sig.i & 4); |
|||
var pubKey = Bitcoin.ECDSA.recoverPubKey(sig.r, sig.s, hash, sig.i); |
|||
Message.verifyMessage = function (address, sig, message) { |
|||
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 = Bitcoin.Opcode = function (num) { |
|||
this.code = num; |
|||
}; |
|||
|
|||
Opcode.prototype.toString = function () { |
|||
return Opcode.reverseMap[this.code]; |
|||
}; |
|||
|
|||
Opcode.map = { |
|||
// push value
|
|||
OP_0 : 0, |
|||
OP_FALSE : 0, |
|||
OP_PUSHDATA1 : 76, |
|||
OP_PUSHDATA2 : 77, |
|||
OP_PUSHDATA4 : 78, |
|||
OP_1NEGATE : 79, |
|||
OP_RESERVED : 80, |
|||
OP_1 : 81, |
|||
OP_TRUE : 81, |
|||
OP_2 : 82, |
|||
OP_3 : 83, |
|||
OP_4 : 84, |
|||
OP_5 : 85, |
|||
OP_6 : 86, |
|||
OP_7 : 87, |
|||
OP_8 : 88, |
|||
OP_9 : 89, |
|||
OP_10 : 90, |
|||
OP_11 : 91, |
|||
OP_12 : 92, |
|||
OP_13 : 93, |
|||
OP_14 : 94, |
|||
OP_15 : 95, |
|||
OP_16 : 96, |
|||
|
|||
// control
|
|||
OP_NOP : 97, |
|||
OP_VER : 98, |
|||
OP_IF : 99, |
|||
OP_NOTIF : 100, |
|||
OP_VERIF : 101, |
|||
OP_VERNOTIF : 102, |
|||
OP_ELSE : 103, |
|||
OP_ENDIF : 104, |
|||
OP_VERIFY : 105, |
|||
OP_RETURN : 106, |
|||
|
|||
// stack ops
|
|||
OP_TOALTSTACK : 107, |
|||
OP_FROMALTSTACK : 108, |
|||
OP_2DROP : 109, |
|||
OP_2DUP : 110, |
|||
OP_3DUP : 111, |
|||
OP_2OVER : 112, |
|||
OP_2ROT : 113, |
|||
OP_2SWAP : 114, |
|||
OP_IFDUP : 115, |
|||
OP_DEPTH : 116, |
|||
OP_DROP : 117, |
|||
OP_DUP : 118, |
|||
OP_NIP : 119, |
|||
OP_OVER : 120, |
|||
OP_PICK : 121, |
|||
OP_ROLL : 122, |
|||
OP_ROT : 123, |
|||
OP_SWAP : 124, |
|||
OP_TUCK : 125, |
|||
|
|||
// splice ops
|
|||
OP_CAT : 126, |
|||
OP_SUBSTR : 127, |
|||
OP_LEFT : 128, |
|||
OP_RIGHT : 129, |
|||
OP_SIZE : 130, |
|||
|
|||
// bit logic
|
|||
OP_INVERT : 131, |
|||
OP_AND : 132, |
|||
OP_OR : 133, |
|||
OP_XOR : 134, |
|||
OP_EQUAL : 135, |
|||
OP_EQUALVERIFY : 136, |
|||
OP_RESERVED1 : 137, |
|||
OP_RESERVED2 : 138, |
|||
|
|||
// numeric
|
|||
OP_1ADD : 139, |
|||
OP_1SUB : 140, |
|||
OP_2MUL : 141, |
|||
OP_2DIV : 142, |
|||
OP_NEGATE : 143, |
|||
OP_ABS : 144, |
|||
OP_NOT : 145, |
|||
OP_0NOTEQUAL : 146, |
|||
|
|||
OP_ADD : 147, |
|||
OP_SUB : 148, |
|||
OP_MUL : 149, |
|||
OP_DIV : 150, |
|||
OP_MOD : 151, |
|||
OP_LSHIFT : 152, |
|||
OP_RSHIFT : 153, |
|||
|
|||
OP_BOOLAND : 154, |
|||
OP_BOOLOR : 155, |
|||
OP_NUMEQUAL : 156, |
|||
OP_NUMEQUALVERIFY : 157, |
|||
OP_NUMNOTEQUAL : 158, |
|||
OP_LESSTHAN : 159, |
|||
OP_GREATERTHAN : 160, |
|||
OP_LESSTHANOREQUAL : 161, |
|||
OP_GREATERTHANOREQUAL : 162, |
|||
OP_MIN : 163, |
|||
OP_MAX : 164, |
|||
|
|||
OP_WITHIN : 165, |
|||
|
|||
// crypto
|
|||
OP_RIPEMD160 : 166, |
|||
OP_SHA1 : 167, |
|||
OP_SHA256 : 168, |
|||
OP_HASH160 : 169, |
|||
OP_HASH256 : 170, |
|||
OP_CODESEPARATOR : 171, |
|||
OP_CHECKSIG : 172, |
|||
OP_CHECKSIGVERIFY : 173, |
|||
OP_CHECKMULTISIG : 174, |
|||
OP_CHECKMULTISIGVERIFY : 175, |
|||
|
|||
// expansion
|
|||
OP_NOP1 : 176, |
|||
OP_NOP2 : 177, |
|||
OP_NOP3 : 178, |
|||
OP_NOP4 : 179, |
|||
OP_NOP5 : 180, |
|||
OP_NOP6 : 181, |
|||
OP_NOP7 : 182, |
|||
OP_NOP8 : 183, |
|||
OP_NOP9 : 184, |
|||
OP_NOP10 : 185, |
|||
|
|||
// template matching params
|
|||
OP_PUBKEYHASH : 253, |
|||
OP_PUBKEY : 254, |
|||
OP_INVALIDOPCODE : 255 |
|||
}; |
|||
|
|||
Opcode.reverseMap = []; |
|||
|
|||
for (var i in Opcode.map) { |
|||
Opcode.reverseMap[Opcode.map[i]] = i; |
|||
} |
|||
})(); |
|||
var Opcode = function (num) { |
|||
this.code = num; |
|||
}; |
|||
|
|||
Opcode.prototype.toString = function () { |
|||
return Opcode.reverseMap[this.code]; |
|||
}; |
|||
|
|||
Opcode.map = { |
|||
// push value
|
|||
OP_0 : 0, |
|||
OP_FALSE : 0, |
|||
OP_PUSHDATA1 : 76, |
|||
OP_PUSHDATA2 : 77, |
|||
OP_PUSHDATA4 : 78, |
|||
OP_1NEGATE : 79, |
|||
OP_RESERVED : 80, |
|||
OP_1 : 81, |
|||
OP_TRUE : 81, |
|||
OP_2 : 82, |
|||
OP_3 : 83, |
|||
OP_4 : 84, |
|||
OP_5 : 85, |
|||
OP_6 : 86, |
|||
OP_7 : 87, |
|||
OP_8 : 88, |
|||
OP_9 : 89, |
|||
OP_10 : 90, |
|||
OP_11 : 91, |
|||
OP_12 : 92, |
|||
OP_13 : 93, |
|||
OP_14 : 94, |
|||
OP_15 : 95, |
|||
OP_16 : 96, |
|||
|
|||
// control
|
|||
OP_NOP : 97, |
|||
OP_VER : 98, |
|||
OP_IF : 99, |
|||
OP_NOTIF : 100, |
|||
OP_VERIF : 101, |
|||
OP_VERNOTIF : 102, |
|||
OP_ELSE : 103, |
|||
OP_ENDIF : 104, |
|||
OP_VERIFY : 105, |
|||
OP_RETURN : 106, |
|||
|
|||
// stack ops
|
|||
OP_TOALTSTACK : 107, |
|||
OP_FROMALTSTACK : 108, |
|||
OP_2DROP : 109, |
|||
OP_2DUP : 110, |
|||
OP_3DUP : 111, |
|||
OP_2OVER : 112, |
|||
OP_2ROT : 113, |
|||
OP_2SWAP : 114, |
|||
OP_IFDUP : 115, |
|||
OP_DEPTH : 116, |
|||
OP_DROP : 117, |
|||
OP_DUP : 118, |
|||
OP_NIP : 119, |
|||
OP_OVER : 120, |
|||
OP_PICK : 121, |
|||
OP_ROLL : 122, |
|||
OP_ROT : 123, |
|||
OP_SWAP : 124, |
|||
OP_TUCK : 125, |
|||
|
|||
// splice ops
|
|||
OP_CAT : 126, |
|||
OP_SUBSTR : 127, |
|||
OP_LEFT : 128, |
|||
OP_RIGHT : 129, |
|||
OP_SIZE : 130, |
|||
|
|||
// bit logic
|
|||
OP_INVERT : 131, |
|||
OP_AND : 132, |
|||
OP_OR : 133, |
|||
OP_XOR : 134, |
|||
OP_EQUAL : 135, |
|||
OP_EQUALVERIFY : 136, |
|||
OP_RESERVED1 : 137, |
|||
OP_RESERVED2 : 138, |
|||
|
|||
// numeric
|
|||
OP_1ADD : 139, |
|||
OP_1SUB : 140, |
|||
OP_2MUL : 141, |
|||
OP_2DIV : 142, |
|||
OP_NEGATE : 143, |
|||
OP_ABS : 144, |
|||
OP_NOT : 145, |
|||
OP_0NOTEQUAL : 146, |
|||
|
|||
OP_ADD : 147, |
|||
OP_SUB : 148, |
|||
OP_MUL : 149, |
|||
OP_DIV : 150, |
|||
OP_MOD : 151, |
|||
OP_LSHIFT : 152, |
|||
OP_RSHIFT : 153, |
|||
|
|||
OP_BOOLAND : 154, |
|||
OP_BOOLOR : 155, |
|||
OP_NUMEQUAL : 156, |
|||
OP_NUMEQUALVERIFY : 157, |
|||
OP_NUMNOTEQUAL : 158, |
|||
OP_LESSTHAN : 159, |
|||
OP_GREATERTHAN : 160, |
|||
OP_LESSTHANOREQUAL : 161, |
|||
OP_GREATERTHANOREQUAL : 162, |
|||
OP_MIN : 163, |
|||
OP_MAX : 164, |
|||
|
|||
OP_WITHIN : 165, |
|||
|
|||
// crypto
|
|||
OP_RIPEMD160 : 166, |
|||
OP_SHA1 : 167, |
|||
OP_SHA256 : 168, |
|||
OP_HASH160 : 169, |
|||
OP_HASH256 : 170, |
|||
OP_CODESEPARATOR : 171, |
|||
OP_CHECKSIG : 172, |
|||
OP_CHECKSIGVERIFY : 173, |
|||
OP_CHECKMULTISIG : 174, |
|||
OP_CHECKMULTISIGVERIFY : 175, |
|||
|
|||
// expansion
|
|||
OP_NOP1 : 176, |
|||
OP_NOP2 : 177, |
|||
OP_NOP3 : 178, |
|||
OP_NOP4 : 179, |
|||
OP_NOP5 : 180, |
|||
OP_NOP6 : 181, |
|||
OP_NOP7 : 182, |
|||
OP_NOP8 : 183, |
|||
OP_NOP9 : 184, |
|||
OP_NOP10 : 185, |
|||
|
|||
// template matching params
|
|||
OP_PUBKEYHASH : 253, |
|||
OP_PUBKEY : 254, |
|||
OP_INVALIDOPCODE : 255 |
|||
}; |
|||
|
|||
Opcode.reverseMap = []; |
|||
|
|||
for (var i in Opcode.map) { |
|||
Opcode.reverseMap[Opcode.map[i]] = i; |
|||
} |
|||
|
|||
module.exports = Opcode; |
|||
|
@ -1,347 +1,382 @@ |
|||
(function () { |
|||
var Opcode = Bitcoin.Opcode; |
|||
var Opcode = require('./opcode'); |
|||
var util = require('./util'); |
|||
var conv = require('./convert'); |
|||
var Address = require('./address'); |
|||
|
|||
// Make opcodes available as pseudo-constants
|
|||
for (var i in Opcode.map) { |
|||
eval("var " + i + " = " + Opcode.map[i] + ";"); |
|||
var Script = function (data) { |
|||
if (!data) { |
|||
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) { |
|||
if (!data) { |
|||
this.buffer = []; |
|||
} else if ("string" == typeof data) { |
|||
this.buffer = Crypto.util.base64ToBytes(data); |
|||
} else if (Bitcoin.Util.isArray(data)) { |
|||
this.buffer = data; |
|||
} else if (data instanceof Script) { |
|||
this.buffer = data.buffer; |
|||
this.parse(); |
|||
}; |
|||
|
|||
Script.fromPubKey = 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 { |
|||
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. |
|||
* |
|||
* 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 |
|||
* data. |
|||
* |
|||
* 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 |
|||
* the script buffer manually, you should update the chunks using this method. |
|||
*/ |
|||
Script.prototype.parse = function () { |
|||
var self = this; |
|||
/** |
|||
* Update the parsed script representation. |
|||
* |
|||
* 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 |
|||
* data. |
|||
* |
|||
* 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 |
|||
* the script buffer manually, you should update the chunks using this method. |
|||
*/ |
|||
Script.prototype.parse = function () { |
|||
var self = this; |
|||
|
|||
this.chunks = []; |
|||
this.chunks = []; |
|||
|
|||
// Cursor
|
|||
var i = 0; |
|||
// Cursor
|
|||
var i = 0; |
|||
|
|||
// Read n bytes and store result as a chunk
|
|||
function readChunk(n) { |
|||
self.chunks.push(self.buffer.slice(i, i + n)); |
|||
i += n; |
|||
}; |
|||
// Read n bytes and store result as a chunk
|
|||
function readChunk(n) { |
|||
self.chunks.push(self.buffer.slice(i, i + n)); |
|||
i += n; |
|||
}; |
|||
|
|||
while (i < this.buffer.length) { |
|||
var opcode = this.buffer[i++]; |
|||
if (opcode >= 0xF0) { |
|||
// Two byte opcode
|
|||
opcode = (opcode << 8) | this.buffer[i++]; |
|||
} |
|||
while (i < this.buffer.length) { |
|||
var opcode = this.buffer[i++]; |
|||
if (opcode >= 0xF0) { |
|||
// Two byte opcode
|
|||
opcode = (opcode << 8) | this.buffer[i++]; |
|||
} |
|||
|
|||
var len; |
|||
if (opcode > 0 && opcode < OP_PUSHDATA1) { |
|||
// Read some bytes of data, opcode value is the length of data
|
|||
readChunk(opcode); |
|||
} else if (opcode == OP_PUSHDATA1) { |
|||
len = this.buffer[i++]; |
|||
readChunk(len); |
|||
} else if (opcode == OP_PUSHDATA2) { |
|||
len = (this.buffer[i++] << 8) | this.buffer[i++]; |
|||
readChunk(len); |
|||
} else if (opcode == OP_PUSHDATA4) { |
|||
len = (this.buffer[i++] << 24) | |
|||
(this.buffer[i++] << 16) | |
|||
(this.buffer[i++] << 8) | |
|||
this.buffer[i++]; |
|||
readChunk(len); |
|||
} else { |
|||
this.chunks.push(opcode); |
|||
} |
|||
var len; |
|||
if (opcode > 0 && opcode < Opcode.map.OP_PUSHDATA1) { |
|||
// Read some bytes of data, opcode value is the length of data
|
|||
readChunk(opcode); |
|||
} else if (opcode == Opcode.map.OP_PUSHDATA1) { |
|||
len = this.buffer[i++]; |
|||
readChunk(len); |
|||
} else if (opcode == Opcode.map.OP_PUSHDATA2) { |
|||
len = (this.buffer[i++] << 8) | this.buffer[i++]; |
|||
readChunk(len); |
|||
} else if (opcode == Opcode.map.OP_PUSHDATA4) { |
|||
len = (this.buffer[i++] << 24) | |
|||
(this.buffer[i++] << 16) | |
|||
(this.buffer[i++] << 8) | |
|||
this.buffer[i++]; |
|||
readChunk(len); |
|||
} else { |
|||
this.chunks.push(opcode); |
|||
} |
|||
}; |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* Compare the script to known templates of scriptPubKey. |
|||
* |
|||
* This method will compare the script to a small number of standard script |
|||
* templates and return a string naming the detected type. |
|||
* |
|||
* Currently supported are: |
|||
* Address: |
|||
* Paying to a Bitcoin address which is the hash of a pubkey. |
|||
* OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG |
|||
* |
|||
* Pubkey: |
|||
* Paying to a public key directly. |
|||
* [pubKey] OP_CHECKSIG |
|||
* |
|||
* Strange: |
|||
* Any other script (no template matched). |
|||
*/ |
|||
Script.prototype.getOutType = function () { |
|||
/** |
|||
* Compare the script to known templates of scriptPubKey. |
|||
* |
|||
* This method will compare the script to a small number of standard script |
|||
* templates and return a string naming the detected type. |
|||
* |
|||
* Currently supported are: |
|||
* Address: |
|||
* Paying to a Bitcoin address which is the hash of a pubkey. |
|||
* OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG |
|||
* |
|||
* Pubkey: |
|||
* Paying to a public key directly. |
|||
* [pubKey] OP_CHECKSIG |
|||
* |
|||
* Strange: |
|||
* Any other script (no template matched). |
|||
*/ |
|||
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
|
|||
return 'Multisig'; |
|||
} else if (this.chunks.length == 5 && |
|||
this.chunks[0] == OP_DUP && |
|||
this.chunks[1] == OP_HASH160 && |
|||
this.chunks[3] == OP_EQUALVERIFY && |
|||
this.chunks[4] == OP_CHECKSIG) { |
|||
// Transfer to Bitcoin address
|
|||
return 'Address'; |
|||
} else if (this.chunks.length == 2 && |
|||
this.chunks[1] == OP_CHECKSIG) { |
|||
// Transfer to IP address
|
|||
/** |
|||
* Returns the address corresponding to this output in hash160 form. |
|||
* Assumes strange scripts are P2SH |
|||
*/ |
|||
Script.prototype.toScriptHash = function () { |
|||
var outType = this.getOutType(); |
|||
|
|||
return outType == 'Pubkey' ? this.chunks[2] |
|||
: outType == 'P2SH' ? util.sha256ripe160(this.buffer) |
|||
: util.sha256ripe160(this.buffer) |
|||
}; |
|||
|
|||
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'; |
|||
} 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 { |
|||
return 'Strange'; |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* Returns the affected address hash for this output. |
|||
* |
|||
* For standard transactions, this will return the hash of the pubKey that |
|||
* can spend this output. |
|||
* |
|||
* In the future, for payToScriptHash outputs, this will return the |
|||
* scriptHash. Note that non-standard and standard payToScriptHash transactions |
|||
* look the same |
|||
* |
|||
* This method is useful for indexing transactions. |
|||
*/ |
|||
Script.prototype.simpleOutHash = function () |
|||
{ |
|||
switch (this.getOutType()) { |
|||
case 'Address': |
|||
return this.chunks[2]; |
|||
case 'Pubkey': |
|||
return Bitcoin.Util.sha256ripe160(this.chunks[0]); |
|||
default: |
|||
throw new Error("Encountered non-standard scriptPubKey"); |
|||
} |
|||
}; |
|||
/** |
|||
* Returns the affected public key for this input. |
|||
* |
|||
* This currently only works with payToPubKeyHash transactions. It will also |
|||
* work in the future for standard payToScriptHash transactions that use a |
|||
* single public key. |
|||
* |
|||
* 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"); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* Old name for Script#simpleOutHash. |
|||
* |
|||
* @deprecated |
|||
*/ |
|||
Script.prototype.simpleOutPubKeyHash = Script.prototype.simpleOutHash; |
|||
/** |
|||
* Returns the affected address hash for this input. |
|||
* |
|||
* For standard transactions, this will return the hash of the pubKey that |
|||
* can spend this output. |
|||
* |
|||
* 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. |
|||
* |
|||
* 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] |
|||
* |
|||
* 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'; |
|||
} |
|||
}; |
|||
/** |
|||
* Old name for Script#simpleInHash. |
|||
* |
|||
* @deprecated |
|||
*/ |
|||
Script.prototype.simpleInPubKeyHash = Script.prototype.simpleInHash; |
|||
|
|||
/** |
|||
* Returns the affected public key for this input. |
|||
* |
|||
* This currently only works with payToPubKeyHash transactions. It will also |
|||
* work in the future for standard payToScriptHash transactions that use a |
|||
* single public key. |
|||
* |
|||
* 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"); |
|||
} |
|||
}; |
|||
/** |
|||
* Add an op code to the script. |
|||
*/ |
|||
Script.prototype.writeOp = function (opcode) |
|||
{ |
|||
this.buffer.push(opcode); |
|||
this.chunks.push(opcode); |
|||
}; |
|||
|
|||
/** |
|||
* Returns the affected address hash for this input. |
|||
* |
|||
* For standard transactions, this will return the hash of the pubKey that |
|||
* can spend this output. |
|||
* |
|||
* 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 Bitcoin.Util.sha256ripe160(this.simpleInPubKey()); |
|||
}; |
|||
/** |
|||
* Add a data chunk to the script. |
|||
*/ |
|||
Script.prototype.writeBytes = function (data) |
|||
{ |
|||
if (data.length < Opcode.map.OP_PUSHDATA1) { |
|||
this.buffer.push(data.length); |
|||
} else if (data.length <= 0xff) { |
|||
this.buffer.push(Opcode.map.OP_PUSHDATA1); |
|||
this.buffer.push(data.length); |
|||
} else if (data.length <= 0xffff) { |
|||
this.buffer.push(Opcode.map.OP_PUSHDATA2); |
|||
this.buffer.push(data.length & 0xff); |
|||
this.buffer.push((data.length >>> 8) & 0xff); |
|||
} else { |
|||
this.buffer.push(Opcode.map.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); |
|||
}; |
|||
|
|||
/** |
|||
* Old name for Script#simpleInHash. |
|||
* |
|||
* @deprecated |
|||
*/ |
|||
Script.prototype.simpleInPubKeyHash = Script.prototype.simpleInHash; |
|||
/** |
|||
* Create an output for an address |
|||
*/ |
|||
Script.createOutputScript = function (address) |
|||
{ |
|||
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. |
|||
*/ |
|||
Script.prototype.writeOp = function (opcode) |
|||
{ |
|||
this.buffer.push(opcode); |
|||
this.chunks.push(opcode); |
|||
}; |
|||
/** |
|||
* Extract pubkeys from a multisig script |
|||
*/ |
|||
|
|||
/** |
|||
* Add a data chunk to the script. |
|||
*/ |
|||
Script.prototype.writeBytes = function (data) |
|||
{ |
|||
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); |
|||
}; |
|||
Script.prototype.extractPubkeys = function() { |
|||
return this.chunks.filter(function(chunk) { |
|||
return (chunk[0] == 4 && chunk.length == 65 |
|||
|| chunk[0] < 4 && chunk.length == 33) |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Create a standard payToPubKeyHash output. |
|||
*/ |
|||
Script.createOutputScript = function (address) |
|||
{ |
|||
var script = new Script(); |
|||
script.writeOp(OP_DUP); |
|||
script.writeOp(OP_HASH160); |
|||
script.writeBytes(address.hash); |
|||
script.writeOp(OP_EQUALVERIFY); |
|||
script.writeOp(OP_CHECKSIG); |
|||
return script; |
|||
}; |
|||
/** |
|||
* Create an m-of-n output script |
|||
*/ |
|||
Script.createMultiSigOutputScript = function (m, pubkeys) |
|||
{ |
|||
var script = new Script(); |
|||
|
|||
pubkeys = pubkeys.sort(); |
|||
|
|||
script.writeOp(Opcode.map.OP_1 + m - 1); |
|||
|
|||
/** |
|||
* Extract bitcoin addresses from an output script |
|||
*/ |
|||
Script.prototype.extractAddresses = function (addresses) |
|||
{ |
|||
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"); |
|||
} |
|||
}; |
|||
for (var i = 0; i < pubkeys.length; ++i) { |
|||
script.writeBytes(pubkeys[i]); |
|||
} |
|||
|
|||
script.writeOp(Opcode.map.OP_1 + pubkeys.length - 1); |
|||
|
|||
/** |
|||
* 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(Opcode.map.OP_CHECKMULTISIG); |
|||
|
|||
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. |
|||
*/ |
|||
Script.createInputScript = function (signature, pubKey) |
|||
{ |
|||
var script = new Script(); |
|||
script.writeBytes(signature); |
|||
script.writeBytes(pubKey); |
|||
return script; |
|||
}; |
|||
/** |
|||
* Create a multisig input |
|||
*/ |
|||
Script.createMultiSigInputScript = function(signatures, script) |
|||
{ |
|||
script = new Script(script); |
|||
var k = script.chunks[0][0]; |
|||
if (signatures.length < k) return false; //Not enough sigs
|
|||
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 () |
|||
{ |
|||
return new Script(this.buffer); |
|||
}; |
|||
})(); |
|||
Script.prototype.clone = function () |
|||
{ |
|||
return new Script(this.buffer); |
|||
}; |
|||
|
|||
module.exports = Script; |
|||
|
@ -1,445 +1,587 @@ |
|||
(function () { |
|||
var Script = Bitcoin.Script; |
|||
|
|||
var Transaction = Bitcoin.Transaction = function (doc) { |
|||
var BigInteger = require('./jsbn/jsbn'); |
|||
var Script = require('./script'); |
|||
var util = require('./util'); |
|||
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.lock_time = 0; |
|||
this.ins = []; |
|||
this.outs = []; |
|||
this.timestamp = null; |
|||
this.block = null; |
|||
|
|||
|
|||
if (doc) { |
|||
if (doc.hash) this.hash = doc.hash; |
|||
if (doc.version) this.version = doc.version; |
|||
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 (typeof doc == "string" || util.isArray(doc)) { |
|||
doc = Transaction.deserialize(doc) |
|||
} |
|||
} |
|||
if (doc.outs && doc.outs.length) { |
|||
for (var i = 0; i < doc.outs.length; i++) { |
|||
this.addOutput(new TransactionOut(doc.outs[i])); |
|||
if (doc.hash) this.hash = doc.hash; |
|||
if (doc.version) this.version = doc.version; |
|||
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.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])); |
|||
if (doc.outs && doc.outs.length) { |
|||
for (var i = 0; i < doc.outs.length; i++) { |
|||
this.addOutput(new TransactionOut(doc.outs[i])); |
|||
} |
|||
} |
|||
if (doc.timestamp) this.timestamp = doc.timestamp; |
|||
if (doc.block) this.block = doc.block; |
|||
} |
|||
return objs; |
|||
}; |
|||
|
|||
/** |
|||
* Create a new txin. |
|||
* |
|||
* Can be called with an existing TransactionIn object to add it to the |
|||
* 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 |
|||
* referenced output will be created. |
|||
* |
|||
* Note that this method does not sign the created input. |
|||
*/ |
|||
Transaction.prototype.addInput = function (tx, outIndex) { |
|||
}; |
|||
|
|||
/** |
|||
* 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; |
|||
}; |
|||
|
|||
/** |
|||
* 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) { |
|||
this.ins.push(arguments[0]); |
|||
} else { |
|||
this.ins.push(new TransactionIn({ |
|||
outpoint: { |
|||
hash: tx.hash, |
|||
index: outIndex |
|||
}, |
|||
script: new Bitcoin.Script(), |
|||
sequence: 4294967295 |
|||
})); |
|||
this.ins.push(arguments[0]); |
|||
} |
|||
else if (arguments[0].length > 65) { |
|||
var args = arguments[0].split(':'); |
|||
return this.addInput(args[0], args[1]); |
|||
} |
|||
else { |
|||
this.ins.push(new TransactionIn({ |
|||
outpoint: { |
|||
hash: tx.hash || tx, |
|||
index: outIndex |
|||
}, |
|||
script: new Script(), |
|||
sequence: 4294967295 |
|||
})); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* Create a new txout. |
|||
* |
|||
* Can be called with an existing TransactionOut object to add it to the |
|||
* 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 |
|||
* values will be created. |
|||
*/ |
|||
Transaction.prototype.addOutput = function (address, value) { |
|||
}; |
|||
|
|||
/** |
|||
* Create a new txout. |
|||
* |
|||
* Can be called with: |
|||
* |
|||
* i) An existing TransactionOut object |
|||
* ii) An address object or an address and a value |
|||
* iii) An address:value string |
|||
* |
|||
*/ |
|||
Transaction.prototype.addOutput = function (address, value) { |
|||
if (arguments[0] instanceof TransactionOut) { |
|||
this.outs.push(arguments[0]); |
|||
} else { |
|||
if (value instanceof BigInteger) { |
|||
value = value.toByteArrayUnsigned().reverse(); |
|||
while (value.length < 8) value.push(0); |
|||
} else if (Bitcoin.Util.isArray(value)) { |
|||
// Nothing to do
|
|||
} |
|||
|
|||
this.outs.push(new TransactionOut({ |
|||
this.outs.push(arguments[0]); |
|||
return; |
|||
} |
|||
if (arguments[0].indexOf(':') >= 0) { |
|||
var args = arguments[0].split(':'); |
|||
address = args[0]; |
|||
value = parseInt(args[1]); |
|||
} |
|||
this.outs.push(new TransactionOut({ |
|||
value: value, |
|||
script: Script.createOutputScript(address) |
|||
})); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* Serialize this transaction. |
|||
* |
|||
* 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 |
|||
* be hashed to get the transaction's standard Bitcoin hash. |
|||
*/ |
|||
Transaction.prototype.serialize = function () |
|||
{ |
|||
})); |
|||
}; |
|||
|
|||
/** |
|||
* Serialize this transaction. |
|||
* |
|||
* 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 |
|||
* be hashed to get the transaction's standard Bitcoin hash. |
|||
*/ |
|||
Transaction.prototype.serialize = function () { |
|||
var buffer = []; |
|||
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(this.version)]).reverse()); |
|||
buffer = buffer.concat(Bitcoin.Util.numToVarInt(this.ins.length)); |
|||
buffer = buffer.concat(util.numToBytes(parseInt(this.version),4)); |
|||
buffer = buffer.concat(util.numToVarInt(this.ins.length)); |
|||
for (var i = 0; i < this.ins.length; 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}); |
|||
var txin = this.ins[i]; |
|||
|
|||
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()); |
|||
|
|||
/** |
|||
* Calculate and return the transaction's hash. |
|||
*/ |
|||
Transaction.prototype.getHash = function () |
|||
{ |
|||
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.numToBytes(parseInt(txin.outpoint.index),4)); |
|||
var scriptBytes = txin.script.buffer; |
|||
buffer = buffer.concat(util.numToVarInt(scriptBytes.length)); |
|||
buffer = buffer.concat(scriptBytes); |
|||
buffer = buffer.concat(util.numToBytes(parseInt(txin.sequence),4)); |
|||
} |
|||
buffer = buffer.concat(util.numToVarInt(this.outs.length)); |
|||
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 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; |
|||
} |
|||
var txout = this.outs[i]; |
|||
buffer = buffer.concat(util.numToBytes(txout.value,8)); |
|||
var scriptBytes = txout.script.buffer; |
|||
buffer = buffer.concat(util.numToVarInt(scriptBytes.length)); |
|||
buffer = buffer.concat(scriptBytes); |
|||
} |
|||
buffer = buffer.concat(util.numToBytes(parseInt(this.lock_time),4)); |
|||
|
|||
var impact = this.calcImpact(wallet); |
|||
|
|||
var analysis = {}; |
|||
|
|||
analysis.impact = impact; |
|||
|
|||
if (impact.sign > 0 && impact.value.compareTo(BigInteger.ZERO) > 0) { |
|||
analysis.type = 'recv'; |
|||
analysis.addr = new Bitcoin.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 Bitcoin.Address(firstRecvHash); |
|||
} else { |
|||
analysis.type = "other"; |
|||
return buffer; |
|||
}; |
|||
|
|||
Transaction.prototype.serializeHex = function() { |
|||
return conv.bytesToHex(this.serialize()); |
|||
} |
|||
|
|||
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(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; |
|||
} |
|||
|
|||
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; |
|||
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; |
|||
|
|||
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 () { |
|||
var totalValue = BigInteger.ZERO; |
|||
for (var j = 0; j < this.outs.length; j++) { |
|||
var txout = this.outs[j]; |
|||
totalValue = totalValue.add(Bitcoin.Util.valueToBigInt(txout.value)); |
|||
} |
|||
|
|||
var impact = this.calcImpact(wallet); |
|||
|
|||
var analysis = {}; |
|||
|
|||
analysis.impact = impact; |
|||
|
|||
if (impact.sign > 0 && impact.value > 0) { |
|||
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; |
|||
}; |
|||
|
|||
/** |
|||
* 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 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 pos = 0; |
|||
var readAsInt = function(bytes) { |
|||
if (bytes == 0) return 0; |
|||
pos++; |
|||
return buffer[pos-1] + readAsInt(bytes-1) * 256; |
|||
} |
|||
|
|||
// Calculate debit to us from all ins
|
|||
var valueIn = BigInteger.ZERO; |
|||
for (var j = 0; j < this.ins.length; j++) { |
|||
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)); |
|||
var readVarInt = function() { |
|||
pos++; |
|||
if (buffer[pos-1] < 253) { |
|||
return buffer[pos-1]; |
|||
} |
|||
} |
|||
return readAsInt(buffer[pos-1] - 251); |
|||
} |
|||
if (valueOut.compareTo(valueIn) >= 0) { |
|||
return { |
|||
sign: 1, |
|||
value: valueOut.subtract(valueIn) |
|||
}; |
|||
} else { |
|||
return { |
|||
sign: -1, |
|||
value: valueIn.subtract(valueOut) |
|||
}; |
|||
var readBytes = function(bytes) { |
|||
pos += bytes; |
|||
return buffer.slice(pos - bytes, pos); |
|||
} |
|||
}; |
|||
|
|||
var TransactionIn = Bitcoin.TransactionIn = function (data) |
|||
{ |
|||
this.outpoint = data.outpoint; |
|||
if (data.script instanceof Script) { |
|||
this.script = data.script; |
|||
} else { |
|||
this.script = new Script(data.script); |
|||
var readVarString = function() { |
|||
var size = readVarInt(); |
|||
return readBytes(size); |
|||
} |
|||
var obj = { |
|||
ins: [], |
|||
outs: [] |
|||
} |
|||
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; |
|||
}; |
|||
|
|||
TransactionIn.prototype.clone = function () |
|||
{ |
|||
var newTxin = new TransactionIn({ |
|||
outpoint: { |
|||
hash: this.outpoint.hash, |
|||
index: this.outpoint.index |
|||
}, |
|||
script: this.script.clone(), |
|||
sequence: this.sequence |
|||
var outs = readVarInt(); |
|||
for (var i = 0; i < outs; i++) { |
|||
obj.outs.push({ |
|||
value: util.bytesToNum(readBytes(8)), |
|||
script: new Script(readVarString()) |
|||
}); |
|||
} |
|||
obj.locktime = readAsInt(4); |
|||
return new Transaction(obj); |
|||
} |
|||
|
|||
/** |
|||
* 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 TransactionOut = Bitcoin.TransactionOut = function (data) |
|||
{ |
|||
if (data.script instanceof Script) { |
|||
this.script = data.script; |
|||
} else { |
|||
this.script = new Script(data.script); |
|||
var hmap = {}; |
|||
for (var o in outputs) { |
|||
hmap[outputs[o].output] = outputs[o]; |
|||
} |
|||
|
|||
if (Bitcoin.Util.isArray(data.value)) { |
|||
this.value = data.value; |
|||
} else if ("string" == typeof data.value) { |
|||
var valueHex = (new BigInteger(data.value, 10)).toString(16); |
|||
while (valueHex.length < 16) valueHex = "0" + valueHex; |
|||
this.value = Crypto.util.hexToBytes(valueHex); |
|||
for (var i = 0; i < this.ins.length; i++) { |
|||
var outpoint = this.ins[i].outpoint.hash+':'+this.ins[i].outpoint.index, |
|||
histItem = hmap[outpoint]; |
|||
if (!histItem) continue; |
|||
var thisInputAddrdata = addrdata.filter(function(a) { |
|||
return a.address == histItem.address; |
|||
}); |
|||
if (thisInputAddrdata.length == 0) continue; |
|||
this.sign(i,thisInputAddrdata[0].key); |
|||
} |
|||
}; |
|||
|
|||
TransactionOut.prototype.clone = function () |
|||
{ |
|||
var newTxout = new TransactionOut({ |
|||
script: this.script.clone(), |
|||
value: this.value.slice(0) |
|||
} |
|||
|
|||
/** |
|||
* Signs a P2SH output at some index with the given key |
|||
*/ |
|||
|
|||
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
|
|||
BigInteger.valueOf = nbv; |
|||
var Crypto = require('./crypto-js/crypto'); |
|||
|
|||
/** |
|||
* Returns a byte array representation of the big integer. |
|||
* |
|||
* This returns the absolute of the contained value in big endian |
|||
* form. A value of zero results in an empty array. |
|||
* Cross-browser compatibility version of Array.isArray. |
|||
*/ |
|||
BigInteger.prototype.toByteArrayUnsigned = function () { |
|||
var ba = this.abs().toByteArray(); |
|||
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; |
|||
} |
|||
}; |
|||
exports.isArray = Array.isArray || function(o) { |
|||
return Object.prototype.toString.call(o) === '[object Array]'; |
|||
} |
|||
|
|||
/** |
|||
* Turns a byte array into a big integer. |
|||
* |
|||
* This function will interpret a byte array as a big integer in big |
|||
* endian notation and ignore leading zeros. |
|||
* Create a byte array representing a number with the given length |
|||
*/ |
|||
BigInteger.fromByteArrayUnsigned = function (ba) { |
|||
if (!ba.length) { |
|||
return ba.valueOf(0); |
|||
} else if (ba[0] & 0x80) { |
|||
// 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); |
|||
} |
|||
}; |
|||
exports.numToBytes = function(num, bytes) { |
|||
if (bytes === undefined) bytes = 8; |
|||
if (bytes === 0) return []; |
|||
return [num % 256].concat(module.exports.numToBytes(Math.floor(num / 256), bytes - 1)); |
|||
} |
|||
|
|||
/** |
|||
* Converts big integer to signed byte representation. |
|||
* |
|||
* 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 |
|||
* Convert a byte array to the number that it represents |
|||
*/ |
|||
BigInteger.prototype.toByteArraySigned = function () { |
|||
var val = this.abs().toByteArrayUnsigned(); |
|||
var neg = this.compareTo(BigInteger.ZERO) < 0; |
|||
|
|||
if (neg) { |
|||
if (val[0] & 0x80) { |
|||
val.unshift(0x80); |
|||
} else { |
|||
val[0] |= 0x80; |
|||
} |
|||
} else { |
|||
if (val[0] & 0x80) { |
|||
val.unshift(0x00); |
|||
} |
|||
} |
|||
|
|||
return val; |
|||
}; |
|||
exports.bytesToNum = function(bytes) { |
|||
if (bytes.length === 0) return 0; |
|||
return bytes[0] + 256 * module.exports.bytesToNum(bytes.slice(1)); |
|||
} |
|||
|
|||
/** |
|||
* 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) { |
|||
// Check for negative value
|
|||
if (ba[0] & 0x80) { |
|||
// Remove sign bit
|
|||
ba[0] &= 0x7f; |
|||
|
|||
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.numToVarInt = function(num) { |
|||
if (num < 253) return [num]; |
|||
if (num < 65536) return [253].concat(exports.numToBytes(num, 2)); |
|||
if (num < 4294967296) return [254].concat(exports.numToBytes(num, 4)); |
|||
return [253].concat(exports.numToBytes(num, 8)); |
|||
} |
|||
|
|||
/** |
|||
* Create an array of a certain length filled with a specific value. |
|||
*/ |
|||
makeFilledArray: function (len, val) |
|||
{ |
|||
var array = []; |
|||
var i = 0; |
|||
while (i < len) { |
|||
array[i++] = val; |
|||
exports.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 array; |
|||
}, |
|||
return words; |
|||
} |
|||
|
|||
/** |
|||
* Turn an integer into a "var_int". |
|||
* |
|||
* "var_int" is a variable length integer used by Bitcoin's binary format. |
|||
* |
|||
* 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])); |
|||
exports.wordsToBytes = function (words) { |
|||
var bytes = []; |
|||
for (var b = 0; b < words.length * 32; b += 8) { |
|||
bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* Parse a Bitcoin value byte array, returning a BigInteger. |
|||
*/ |
|||
valueToBigInt: function (valueBuffer) |
|||
{ |
|||
if (valueBuffer instanceof BigInteger) return valueBuffer; |
|||
return bytes; |
|||
}, |
|||
|
|||
// Prepend zero byte to prevent interpretation as negative integer
|
|||
return BigInteger.fromByteArrayUnsigned(valueBuffer); |
|||
}, |
|||
|
|||
/** |
|||
* Format a Bitcoin value as a string. |
|||
* |
|||
* 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) { |
|||
/** |
|||
* Calculate RIPEMD160(SHA256(data)). |
|||
* |
|||
* Takes an arbitrary byte array as inputs and returns the hash as a byte |
|||
* array. |
|||
*/ |
|||
exports.sha256ripe160 = function (data) { |
|||
return Crypto.RIPEMD160(Crypto.SHA256(data, {asBytes: true}), {asBytes: true}); |
|||
} |
|||
}; |
|||
} |
|||
|
|||
for (var i in Crypto.util) { |
|||
if (Crypto.util.hasOwnProperty(i)) { |
|||
Bitcoin.Util[i] = Crypto.util[i]; |
|||
} |
|||
exports.error = function(msg) { |
|||
throw new Error(msg); |
|||
} |
|||
|
@ -1,308 +1,182 @@ |
|||
Bitcoin.Wallet = (function () { |
|||
var Script = Bitcoin.Script, |
|||
TransactionIn = Bitcoin.TransactionIn, |
|||
TransactionOut = Bitcoin.TransactionOut; |
|||
var Script = require('./script'); |
|||
var ECKey = require('./eckey').ECKey; |
|||
var conv = require('./convert'); |
|||
var util = require('./util'); |
|||
|
|||
var Wallet = function () { |
|||
// 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 BigInteger = require('./jsbn/jsbn'); |
|||
|
|||
/** |
|||
* Get the key chain. |
|||
* |
|||
* Returns an array of base64-encoded private values. |
|||
*/ |
|||
this.getKeys = function () { |
|||
var serializedWallet = []; |
|||
var Transaction = require('./transaction').Transaction; |
|||
var TransactionIn = require('./transaction').TransactionIn; |
|||
var TransactionOut = require('./transaction').TransactionOut; |
|||
var HDWallet = require('./hdwallet.js') |
|||
|
|||
for (var i = 0; i < keys.length; i++) { |
|||
serializedWallet.push(keys[i].toString('base64')); |
|||
} |
|||
var SecureRandom = require('./jsbn/rng'); |
|||
var rng = new SecureRandom(); |
|||
|
|||
return serializedWallet; |
|||
}; |
|||
var Wallet = function (seed) { |
|||
|
|||
/** |
|||
* Get the public keys. |
|||
* |
|||
* Returns an array of base64-encoded public keys. |
|||
*/ |
|||
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; |
|||
} |
|||
}; |
|||
// Stored in a closure to make accidental serialization less likely
|
|||
var keys = []; |
|||
var masterkey = null; |
|||
var me = this; |
|||
|
|||
/** |
|||
* Go to the next address. |
|||
* |
|||
* 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(); |
|||
}; |
|||
// Addresses
|
|||
this.addresses = []; |
|||
|
|||
/** |
|||
* Sign a hash with a key. |
|||
* |
|||
* 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"); |
|||
}; |
|||
// Transaction output data
|
|||
this.outputs = {}; |
|||
|
|||
/** |
|||
* Retrieve the corresponding pubKey for a pubKeyHash. |
|||
* |
|||
* This function only works if the pubKey in question is part of this |
|||
* wallet. |
|||
*/ |
|||
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(); |
|||
// Make a new master key
|
|||
this.newMasterKey = function(seed) { |
|||
if (!seed) { |
|||
var seedBytes = new Array(32); |
|||
rng.nextBytes(seedBytes); |
|||
seed = conv.bytesToString(seedBytes) |
|||
} |
|||
} |
|||
throw new Error("Hash unknown"); |
|||
}; |
|||
}; |
|||
|
|||
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; |
|||
masterkey = new HDWallet(seed); |
|||
keys = [] |
|||
} |
|||
this.newMasterKey(seed) |
|||
|
|||
var j; |
|||
var k; |
|||
var hash; |
|||
// Gather outputs
|
|||
for (j = 0; j < tx.outs.length; j++) { |
|||
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; |
|||
} |
|||
} |
|||
// Add a new address
|
|||
this.generateAddress = function() { |
|||
keys.push(masterkey.ckd(keys.length).key) |
|||
this.addresses.push(keys[keys.length-1].getBitcoinAddress().toString()) |
|||
return this.addresses[this.addresses.length - 1] |
|||
} |
|||
|
|||
// Remove spent outputs
|
|||
for (j = 0; j < tx.ins.length; j++) { |
|||
var txin = new TransactionIn(tx.ins[j]); |
|||
var pubkey = txin.script.simpleInPubKey(); |
|||
hash = Crypto.util.bytesToBase64(Bitcoin.Util.sha256ripe160(pubkey)); |
|||
for (k = 0; k < this.addressHashes.length; k++) { |
|||
if (this.addressHashes[k] === hash) { |
|||
for (var l = 0; l < this.unspentOuts.length; l++) { |
|||
if (txin.outpoint.hash == this.unspentOuts[l].tx.hash && |
|||
txin.outpoint.index == this.unspentOuts[l].index) { |
|||
this.unspentOuts.splice(l, 1); |
|||
// Processes a transaction object
|
|||
// If "verified" is true, then we trust the transaction as "final"
|
|||
this.processTx = function(tx, verified) { |
|||
var txhash = conv.bytesToHex(tx.getHash()) |
|||
for (var i = 0; i < tx.outs.length; i++) { |
|||
if (this.addresses.indexOf(tx.outs[i].address.toString()) >= 0) { |
|||
me.outputs[txhash+':'+i] = { |
|||
output: txhash+':'+i, |
|||
value: tx.outs[i].value, |
|||
address: tx.outs[i].address.toString(), |
|||
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; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Index transaction
|
|||
this.txIndex[tx.hash] = tx; |
|||
}; |
|||
|
|||
Wallet.prototype.getBalance = function () { |
|||
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)); |
|||
// Processes an output from an external source of the form
|
|||
// { output: txhash:index, value: integer, address: address }
|
|||
// Excellent compatibility with SX and pybitcointools
|
|||
this.processOutput = function(o) { |
|||
if (!this.outputs[o.output] || this.outputs[o.output].pending) |
|||
this.outputs[o.output] = o; |
|||
} |
|||
return balance; |
|||
}; |
|||
|
|||
Wallet.prototype.createSend = function (address, sendValue, feeValue) { |
|||
var selectedOuts = []; |
|||
var txValue = sendValue.add(feeValue); |
|||
var availableValue = BigInteger.ZERO; |
|||
var i; |
|||
for (i = 0; i < this.unspentOuts.length; i++) { |
|||
selectedOuts.push(this.unspentOuts[i]); |
|||
availableValue = availableValue.add(Bitcoin.Util.valueToBigInt(this.unspentOuts[i].out.value)); |
|||
|
|||
if (availableValue.compareTo(txValue) >= 0) break; |
|||
this.processExistingOutputs = function() { |
|||
var t = new Date().getTime() / 1000 |
|||
for (var o in this.outputs) { |
|||
if (o.pending && t > o.timestamp + 1200) |
|||
delete this.outputs[o] |
|||
if (o.spendpending && t > o.timestamp + 1200) { |
|||
o.spendpending = false |
|||
o.spend = false |
|||
delete o.timestamp |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (availableValue.compareTo(txValue) < 0) { |
|||
throw new Error('Insufficient funds.'); |
|||
var peoInterval = setInterval(this.processExistingOutputs, 10000) |
|||
|
|||
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)); |
|||
} |
|||
|
|||
|
|||
var changeValue = availableValue.subtract(txValue); |
|||
|
|||
var sendTx = new Bitcoin.Transaction(); |
|||
|
|||
for (i = 0; i < selectedOuts.length; i++) { |
|||
sendTx.addInput(selectedOuts[i].tx, selectedOuts[i].index); |
|||
this.mkSend = function(to, value, fee) { |
|||
var utxo = this.getUtxoToPay(value + fee) |
|||
var sum = utxo.reduce(function(t,o) { return t + o.value },0), |
|||
remainder = sum - value - fee |
|||
if (value < 5430) throw new Error("Amount below dust threshold!") |
|||
var unspentOuts = 0; |
|||
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); |
|||
if (changeValue.compareTo(BigInteger.ZERO) > 0) { |
|||
sendTx.addOutput(this.getNextAddress(), changeValue); |
|||
this.mkSendToOutputs = function(outputs, changeIndex, fee) { |
|||
var value = outputs.reduce(function(t,o) { return t + o.value },0), |
|||
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
|
|||
|
|||
for (i = 0; i < sendTx.ins.length; i++) { |
|||
var hash = sendTx.hashTransactionForSignature(selectedOuts[i].out.script, i, hashType); |
|||
var pubKeyHash = selectedOuts[i].out.script.simpleOutPubKeyHash(); |
|||
var signature = this.signWithKey(pubKeyHash, hash); |
|||
|
|||
// Append hash type
|
|||
signature.push(parseInt(hashType, 10)); |
|||
|
|||
sendTx.ins[i].script = Script.createInputScript(signature, this.getPubKeyFromHash(pubKeyHash)); |
|||
this.sign = function(tx) { |
|||
tx.ins.map(function(inp,i) { |
|||
var inp = inp.outpoint.hash+':'+inp.outpoint.index; |
|||
if (me.outputs[inp]) { |
|||
var address = me.outputs[inp].address, |
|||
ind = me.addresses.indexOf(address); |
|||
if (ind >= 0) { |
|||
var key = keys[ind] |
|||
tx.sign(ind,key) |
|||
} |
|||
} |
|||
}) |
|||
return tx; |
|||
} |
|||
|
|||
return sendTx; |
|||
}; |
|||
|
|||
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); |
|||
this.getMasterKey = function() { return masterkey } |
|||
|
|||
// TODO: Just create an object with base64 hashes as keys for faster lookup
|
|||
for (var k = 0; k < this.addressHashes.length; k++) { |
|||
if (this.addressHashes[k] === hash) return true; |
|||
this.getPrivateKey = function(index) { |
|||
if (typeof index == "string") |
|||
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