Socket
Socket
Sign inDemoInstall

bitcoinjs-lib

Package Overview
Dependencies
Maintainers
1
Versions
88
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bitcoinjs-lib - npm Package Compare versions

Comparing version 0.1.0 to 0.1.3

.npmignore

2

package.json
{
"name": "bitcoinjs-lib",
"version": "0.1.0",
"version": "0.1.3",
"description": "Client-side Bitcoin JavaScript library",

@@ -5,0 +5,0 @@

@@ -13,1 +13,20 @@ # bitcoinjs-lib

Prototype software, use at your own peril.
# License
This library is free and open-source software released under the MIT
license.
# Copyright
BitcoinJS (c) 2011-2012 Stefan Thomas
Released under MIT license
http://bitcoinjs.org/
JSBN (c) 2003-2005 Tom Wu
Released under BSD license
http://www-cs-students.stanford.edu/~tjw/jsbn/
CryptoJS (c) 2009–2012 by Jeff Mott
Released under New BSD license
http://code.google.com/p/crypto-js/
Bitcoin.Address = function (bytes) {
if ("string" == typeof bytes) {
bytes = Bitcoin.Address.decodeString(bytes);
}
this.hash = bytes;
if ("string" == typeof bytes) {
bytes = Bitcoin.Address.decodeString(bytes);
}
this.hash = bytes;
this.version = 0x00;
this.version = 0x00;
};
/**
* Serialize this object as a standard Bitcoin address.
*
* Returns the address as a base58-encoded string in the standardized format.
*/
Bitcoin.Address.prototype.toString = function () {
// Get a copy of the hash
var hash = this.hash.slice(0);
// Get a copy of the hash
var hash = this.hash.slice(0);
// Version
hash.unshift(this.version);
// Version
hash.unshift(this.version);
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
var bytes = hash.concat(checksum.slice(0,4));
var bytes = hash.concat(checksum.slice(0,4));
return Bitcoin.Base58.encode(bytes);
return Bitcoin.Base58.encode(bytes);
};
Bitcoin.Address.prototype.getHashBase64 = function () {
return Crypto.util.bytesToBase64(this.hash);
return Crypto.util.bytesToBase64(this.hash);
};
/**
* Parse a Bitcoin address contained in a string.
*/
Bitcoin.Address.decodeString = function (string) {
var bytes = Bitcoin.Base58.decode(string);
var bytes = Bitcoin.Base58.decode(string);
var hash = bytes.slice(0, 21);
var hash = bytes.slice(0, 21);
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
if (checksum[0] != bytes[21] ||
checksum[1] != bytes[22] ||
checksum[2] != bytes[23] ||
checksum[3] != bytes[24]) {
throw "Checksum validation failed!";
}
if (checksum[0] != bytes[21] ||
checksum[1] != bytes[22] ||
checksum[2] != bytes[23] ||
checksum[3] != bytes[24]) {
throw "Checksum validation failed!";
}
var version = hash.shift();
var version = hash.shift();
if (version != 0) {
throw "Version "+version+" not supported!";
}
if (version != 0) {
throw "Version "+version+" not supported!";
}
return hash;
return hash;
};
(function (Bitcoin) {
Bitcoin.Base58 = {
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
base: BigInteger.valueOf(58),
Bitcoin.Base58 = {
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
validRegex: /^[1-9A-HJ-NP-Za-km-z]+$/,
base: BigInteger.valueOf(58),
/**
* Convert a byte array to a base58-encoded string.
*
* Written by Mike Hearn for BitcoinJ.
* Copyright (c) 2011 Google Inc.
*
* Ported to JavaScript by Stefan Thomas.
*/
encode: function (input) {
var bi = BigInteger.fromByteArrayUnsigned(input);
var chars = [];
/**
* Convert a byte array to a base58-encoded string.
*
* Written by Mike Hearn for BitcoinJ.
* Copyright (c) 2011 Google Inc.
*
* Ported to JavaScript by Stefan Thomas.
*/
encode: function (input) {
var bi = BigInteger.fromByteArrayUnsigned(input);
var chars = [];
while (bi.compareTo(B58.base) >= 0) {
var mod = bi.mod(B58.base);
chars.unshift(B58.alphabet[mod.intValue()]);
bi = bi.subtract(mod).divide(B58.base);
}
chars.unshift(B58.alphabet[bi.intValue()]);
while (bi.compareTo(B58.base) >= 0) {
var mod = bi.mod(B58.base);
chars.unshift(B58.alphabet[mod.intValue()]);
bi = bi.subtract(mod).divide(B58.base);
}
chars.unshift(B58.alphabet[bi.intValue()]);
// Convert leading zeros too.
for (var i = 0; i < input.length; i++) {
if (input[i] == 0x00) {
chars.unshift(B58.alphabet[0]);
} else break;
}
// Convert leading zeros too.
for (var i = 0; i < input.length; i++) {
if (input[i] == 0x00) {
chars.unshift(B58.alphabet[0]);
} else break;
}
s = chars.join('');
return s;
},
return chars.join('');
},
/**
* Convert a base58-encoded string to a byte array.
*
* Written by Mike Hearn for BitcoinJ.
* Copyright (c) 2011 Google Inc.
*
* Ported to JavaScript by Stefan Thomas.
*/
decode: function (input) {
bi = BigInteger.valueOf(0);
var leadingZerosNum = 0;
for (var i = input.length - 1; i >= 0; i--) {
var alphaIndex = B58.alphabet.indexOf(input[i]);
bi = bi.add(BigInteger.valueOf(alphaIndex)
.multiply(B58.base.pow(input.length - 1 -i)));
/**
* Convert a base58-encoded string to a byte array.
*
* Written by Mike Hearn for BitcoinJ.
* Copyright (c) 2011 Google Inc.
*
* Ported to JavaScript by Stefan Thomas.
*/
decode: function (input) {
var bi = BigInteger.valueOf(0);
var leadingZerosNum = 0;
for (var i = input.length - 1; i >= 0; i--) {
var alphaIndex = B58.alphabet.indexOf(input[i]);
if (alphaIndex < 0) {
throw "Invalid character";
}
bi = bi.add(BigInteger.valueOf(alphaIndex)
.multiply(B58.base.pow(input.length - 1 -i)));
// This counts leading zero bytes
if (input[i] == "1") leadingZerosNum++;
else leadingZerosNum = 0;
}
var bytes = bi.toByteArrayUnsigned();
// This counts leading zero bytes
if (input[i] == "1") leadingZerosNum++;
else leadingZerosNum = 0;
}
var bytes = bi.toByteArrayUnsigned();
// Add leading zeros
while (leadingZerosNum-- > 0) bytes.unshift(0);
// Add leading zeros
while (leadingZerosNum-- > 0) bytes.unshift(0);
return bytes;
}
};
return bytes;
}
};

@@ -65,0 +68,0 @@ var B58 = Bitcoin.Base58;

@@ -14,14 +14,14 @@ (function (exports) {

{
// 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);
// 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};
return {priv: privateKey, pubkey: publicPoint};
};

@@ -31,27 +31,27 @@

{
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 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;
};

@@ -68,14 +68,14 @@

{
// TODO: We need to actually deep copy here
var txTmp = tx;
// TODO: We need to actually deep copy here
var txTmp = tx;
// In case concatenating two scripts ends up with two codeseparators,
// 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;
});
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[i].script = Crypto.util.bytesToBase64([]);
}

@@ -86,3 +86,3 @@ txTmp.ins[inIndex].script = Crypto.util.bytesToBase64(scriptCode);

if ((hashType & 0x1f) == SIGHASH_NONE) {
txTmp.outs = [];
txTmp.outs = [];

@@ -102,14 +102,14 @@ // Let the others update at will

var buffer = serializeTransaction(txTmp);
buffer.concat(Crypto.util.wordsToBytes([parseInt(hashType)]));
var buffer = serializeTransaction(txTmp);
buffer.concat(Crypto.util.wordsToBytes([parseInt(hashType)]));
console.log(buffer);
return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true});
return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true});
};
function verifyTransactionSignature(tx) {
var hash = hashTransactionForSignature([], tx, 0, 0);
return Crypto.util.bytesToHex(hash);
var hash = hashTransactionForSignature([], tx, 0, 0);
return Crypto.util.bytesToHex(hash);
};

@@ -119,15 +119,15 @@

{
// 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]));
// 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]));
// unsigned long long (LE)
return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i]));
}

@@ -137,25 +137,25 @@ };

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=="
}]
"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=="
}]
};

@@ -165,19 +165,19 @@

$(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));
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(key.verify(message, out));
//console.log(Bitcoin.ECDSA.verify(message, Crypto.util.hexToBytes("3046022100dffbc26774fc841bbe1c1362fd643609c6e42dcb274763476d87af2c0597e89e022100c59e3c13b96b316cae9fa0ab0260612c7a133a6fe2b3445b6bf80b3123bf274d"), Crypto.util.hexToBytes("0401de173aa944eacf7e44e5073baca93fb34fe4b7897a1c82c92dfdc8a1f75ef58cd1b06e8052096980cb6e1ad6d3df143c34b3d7394bae2782a4df570554c2fb")));
//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")));
//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")));
});
//
*/
function integerToBytes(i, len) {
var bytes = i.toByteArrayUnsigned();
var bytes = i.toByteArrayUnsigned();
if (len < bytes.length) {
bytes = bytes.slice(bytes.length-len);
} else while (len > bytes.length) {
bytes.unshift(0);
}
if (len < bytes.length) {
bytes = bytes.slice(bytes.length-len);
} else while (len > bytes.length) {
bytes.unshift(0);
}
return bytes;
return bytes;
};
ECFieldElementFp.prototype.getByteLength = function () {
return Math.floor((this.toBigInteger().bitLength() + 7) / 8);
return Math.floor((this.toBigInteger().bitLength() + 7) / 8);
};
ECPointFp.prototype.getEncoded = function (compressed) {
var x = this.getX().toBigInteger();
var y = this.getY().toBigInteger();
var x = this.getX().toBigInteger();
var y = this.getY().toBigInteger();
// Get value as a 32-byte Buffer
// Fixed length based on a patch by bitaddress.org and Casascius
var enc = integerToBytes(x, 32);
var enc = integerToBytes(x, 32);
if (compressed) {
if (y.testBit(0)) {
enc.unshift(0x02);
} else {
enc.unshift(0x03);
}
// TODO: Implement
} else {
enc.unshift(0x04);
enc = enc.concat(integerToBytes(y, 32));
}
return enc;
if (compressed) {
if (y.isEven()) {
// Compressed even pubkey
// M = 02 || X
enc.unshift(0x02);
} else {
// Compressed uneven pubkey
// M = 03 || X
enc.unshift(0x03);
}
} else {
// Uncompressed pubkey
// M = 04 || X || Y
enc.unshift(0x04);
enc = enc.concat(integerToBytes(y, 32));
}
return enc;
};
ECPointFp.decodeFrom = function (curve, enc) {
var type = enc[0];
var type = enc[0];
var dataLen = enc.length-1;
// Extract x and y as byte arrays
var xBa = enc.slice(1, 1 + dataLen/2);
var yBa = enc.slice(1 + dataLen/2, 1 + dataLen);
// Extract x and y as byte arrays
var xBa = enc.slice(1, 1 + dataLen/2);
var yBa = enc.slice(1 + dataLen/2, 1 + dataLen);
// Prepend zero byte to prevent interpretation as negative integer
xBa.unshift(0);
yBa.unshift(0);
// Prepend zero byte to prevent interpretation as negative integer
xBa.unshift(0);
yBa.unshift(0);
// Convert to BigIntegers
var x = new BigInteger(xBa);
var y = new BigInteger(yBa);
// Convert to BigIntegers
var x = new BigInteger(xBa);
var y = new BigInteger(yBa);
// Return point
return new ECPointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y));
// Return point
return new ECPointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y));
};
ECPointFp.prototype.add2D = function (b) {
if(this.isInfinity()) return b;
if(b.isInfinity()) return this;
if(this.isInfinity()) return b;
if(b.isInfinity()) return this;
if (this.x.equals(b.x)) {
if (this.y.equals(b.y)) {
// this = b, i.e. this must be doubled
return this.twice();
}
// this = -b, i.e. the result is the point at infinity
return this.curve.getInfinity();
}
if (this.x.equals(b.x)) {
if (this.y.equals(b.y)) {
// this = b, i.e. this must be doubled
return this.twice();
}
// this = -b, i.e. the result is the point at infinity
return this.curve.getInfinity();
}
var x_x = b.x.subtract(this.x);
var y_y = b.y.subtract(this.y);
var gamma = y_y.divide(x_x);
var x_x = b.x.subtract(this.x);
var y_y = b.y.subtract(this.y);
var gamma = y_y.divide(x_x);
var x3 = gamma.square().subtract(this.x).subtract(b.x);
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
var x3 = gamma.square().subtract(this.x).subtract(b.x);
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
return new ECPointFp(this.curve, x3, y3);
return new ECPointFp(this.curve, x3, y3);
};
ECPointFp.prototype.twice2D = function () {
if (this.isInfinity()) return this;
if (this.y.toBigInteger().signum() == 0) {
// if y1 == 0, then (x1, y1) == (x1, -y1)
// and hence this = -this and thus 2(x1, y1) == infinity
return this.curve.getInfinity();
}
if (this.isInfinity()) return this;
if (this.y.toBigInteger().signum() == 0) {
// if y1 == 0, then (x1, y1) == (x1, -y1)
// and hence this = -this and thus 2(x1, y1) == infinity
return this.curve.getInfinity();
}
var TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
var THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
var gamma = this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO));
var TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
var THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
var gamma = this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO));
var x3 = gamma.square().subtract(this.x.multiply(TWO));
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
var x3 = gamma.square().subtract(this.x.multiply(TWO));
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
return new ECPointFp(this.curve, x3, y3);
return new ECPointFp(this.curve, x3, y3);
};
ECPointFp.prototype.multiply2D = function (k) {
if(this.isInfinity()) return this;
if(this.isInfinity()) return this;
if(k.signum() == 0) return this.curve.getInfinity();

@@ -112,10 +117,10 @@

for (i = h.bitLength() - 2; i > 0; --i) {
R = R.twice();
R = R.twice();
var hBit = h.testBit(i);
var eBit = e.testBit(i);
var hBit = h.testBit(i);
var eBit = e.testBit(i);
if (hBit != eBit) {
R = R.add2D(hBit ? this : neg);
}
if (hBit != eBit) {
R = R.add2D(hBit ? this : neg);
}
}

@@ -138,2 +143,12 @@

ECPointFp.prototype.toString = function () {
return '('+this.getX().toBigInteger().toString()+','+
this.getY().toBigInteger().toString()+')';
};
/**
* Validate an elliptic curve point.
*
* See SEC 1, section 3.2.2.1: Elliptic Curve Public Key Validation Primitive
*/
ECPointFp.prototype.validate = function () {

@@ -174,139 +189,290 @@ var n = this.curve.getQ();

function dmp(v) {
if (!(v instanceof BigInteger)) v = v.toBigInteger();
return Crypto.util.bytesToHex(v.toByteArrayUnsigned());
if (!(v instanceof BigInteger)) v = v.toBigInteger();
return Crypto.util.bytesToHex(v.toByteArrayUnsigned());
};
Bitcoin.ECDSA = (function () {
var ecparams = getSECCurveByName("secp256k1");
var rng = new SecureRandom();
var ecparams = getSECCurveByName("secp256k1");
var rng = new SecureRandom();
function implShamirsTrick(P, k, Q, l)
{
var m = Math.max(k.bitLength(), l.bitLength());
var Z = P.add2D(Q);
var R = P.curve.getInfinity();
var P_OVER_FOUR = null;
for (var i = m - 1; i >= 0; --i) {
R = R.twice2D();
function implShamirsTrick(P, k, Q, l)
{
var m = Math.max(k.bitLength(), l.bitLength());
var Z = P.add2D(Q);
var R = P.curve.getInfinity();
R.z = BigInteger.ONE;
for (var i = m - 1; i >= 0; --i) {
R = R.twice2D();
if (k.testBit(i)) {
if (l.testBit(i)) {
R = R.add2D(Z);
} else {
R = R.add2D(P);
}
} else {
if (l.testBit(i)) {
R = R.add2D(Q);
}
}
}
R.z = BigInteger.ONE;
return R;
};
if (k.testBit(i)) {
if (l.testBit(i)) {
R = R.add2D(Z);
} else {
R = R.add2D(P);
}
} else {
if (l.testBit(i)) {
R = R.add2D(Q);
}
}
}
var ECDSA = {
getBigRandom: function (limit) {
return new BigInteger(limit.bitLength(), rng)
.mod(limit.subtract(BigInteger.ONE))
.add(BigInteger.ONE)
;
},
sign: function (hash, priv) {
var d = priv;
var n = ecparams.getN();
var e = BigInteger.fromByteArrayUnsigned(hash);
return R;
};
do {
var k = ECDSA.getBigRandom(n);
var G = ecparams.getG();
var Q = G.multiply(k);
var r = Q.getX().toBigInteger().mod(n);
} while (r.compareTo(BigInteger.ZERO) <= 0);
var ECDSA = {
getBigRandom: function (limit) {
return new BigInteger(limit.bitLength(), rng)
.mod(limit.subtract(BigInteger.ONE))
.add(BigInteger.ONE)
;
},
sign: function (hash, priv) {
var d = priv;
var n = ecparams.getN();
var e = BigInteger.fromByteArrayUnsigned(hash);
var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
do {
var k = ECDSA.getBigRandom(n);
var G = ecparams.getG();
var Q = G.multiply(k);
var r = Q.getX().toBigInteger().mod(n);
} while (r.compareTo(BigInteger.ZERO) <= 0);
var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
return ECDSA.serializeSig(r, s);
},
},
verify: function (hash, sig, pubkey) {
var r,s;
if (Bitcoin.Util.isArray(sig)) {
var obj = ECDSA.parseSig(sig);
r = obj.r;
s = obj.s;
} else if ("object" === typeof sig && sig.r && sig.s) {
r = sig.r;
s = sig.s;
} else {
throw "Invalid value for signature";
}
var Q;
if (pubkey instanceof ECPointFp) {
Q = pubkey;
} else if (Bitcoin.Util.isArray(pubkey)) {
Q = ECPointFp.decodeFrom(ecparams.getCurve(), pubkey);
} else {
throw "Invalid format for pubkey value, must be byte array or ECPointFp";
}
var e = BigInteger.fromByteArrayUnsigned(hash);
return ECDSA.verifyRaw(e, r, s, Q);
},
verifyRaw: function (e, r, s, Q) {
var n = ecparams.getN();
var G = ecparams.getG();
if (r.compareTo(BigInteger.ONE) < 0 ||
r.compareTo(n) >= 0)
return false;
if (s.compareTo(BigInteger.ONE) < 0 ||
s.compareTo(n) >= 0)
return false;
var c = s.modInverse(n);
var u1 = e.multiply(c).mod(n);
var u2 = r.multiply(c).mod(n);
// TODO(!!!): For some reason Shamir's trick isn't working with
// signed message verification!? Probably an implementation
// error!
//var point = implShamirsTrick(G, u1, Q, u2);
var point = G.multiply(u1).add(Q.multiply(u2));
var v = point.getX().toBigInteger().mod(n);
return v.equals(r);
},
/**
* Serialize a signature into DER format.
*
* Takes two BigIntegers representing r and s and returns a byte array.
*/
serializeSig: function (r, s) {
var rBa = r.toByteArrayUnsigned();
var sBa = s.toByteArrayUnsigned();
var rBa = r.toByteArraySigned();
var sBa = s.toByteArraySigned();
var sequence = [];
sequence.push(0x02); // INTEGER
sequence.push(rBa.length);
sequence = sequence.concat(rBa);
var sequence = [];
sequence.push(0x02); // INTEGER
sequence.push(rBa.length);
sequence = sequence.concat(rBa);
sequence.push(0x02); // INTEGER
sequence.push(sBa.length);
sequence = sequence.concat(sBa);
sequence.push(0x02); // INTEGER
sequence.push(sBa.length);
sequence = sequence.concat(sBa);
sequence.unshift(sequence.length);
sequence.unshift(0x30) // SEQUENCE
sequence.unshift(sequence.length);
sequence.unshift(0x30); // SEQUENCE
return sequence;
return sequence;
},
verify: function (hash, sig, pubkey) {
var obj = ECDSA.parseSig(sig);
var r = obj.r;
var s = obj.s;
/**
* Parses a byte array containing a DER-encoded signature.
*
* This function will return an object of the form:
*
* {
* r: BigInteger,
* s: BigInteger
* }
*/
parseSig: function (sig) {
var cursor;
if (sig[0] != 0x30)
throw new Error("Signature not a valid DERSequence");
var n = ecparams.getN();
var e = BigInteger.fromByteArrayUnsigned(hash);
cursor = 2;
if (sig[cursor] != 0x02)
throw new Error("First element in signature must be a DERInteger");;
var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
if (r.compareTo(BigInteger.ONE) < 0 ||
r.compareTo(n) >= 0)
return false;
cursor += 2+sig[cursor+1];
if (sig[cursor] != 0x02)
throw new Error("Second element in signature must be a DERInteger");
var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
if (s.compareTo(BigInteger.ONE) < 0 ||
s.compareTo(n) >= 0)
return false;
cursor += 2+sig[cursor+1];
var c = s.modInverse(n);
//if (cursor != sig.length)
// throw new Error("Extra bytes in signature");
var u1 = e.multiply(c).mod(n);
var u2 = r.multiply(c).mod(n);
var r = BigInteger.fromByteArrayUnsigned(rBa);
var s = BigInteger.fromByteArrayUnsigned(sBa);
var G = ecparams.getG();
var Q = ECPointFp.decodeFrom(ecparams.getCurve(), pubkey);
return {r: r, s: s};
},
var point = implShamirsTrick(G, u1, Q, u2);
parseSigCompact: function (sig) {
if (sig.length !== 65) {
throw "Signature has the wrong length";
}
var v = point.x.toBigInteger().mod(n);
// Signature is prefixed with a type byte storing three bits of
// information.
var i = sig[0] - 27;
if (i < 0 || i > 7) {
throw "Invalid signature type";
}
return v.equals(r);
},
var n = ecparams.getN();
var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n);
var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n);
parseSig: function (sig) {
var cursor;
if (sig[0] != 0x30)
throw new Error("Signature not a valid DERSequence");
return {r: r, s: s, i: i};
},
cursor = 2;
if (sig[cursor] != 0x02)
throw new Error("First element in signature must be a DERInteger");;
var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
/**
* Recover a public key from a signature.
*
* See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
* Key Recovery Operation".
*
* http://www.secg.org/download/aid-780/sec1-v2.pdf
*/
recoverPubKey: function (r, s, hash, i) {
// The recovery parameter i has two bits.
i = i & 3;
cursor += 2+sig[cursor+1];
if (sig[cursor] != 0x02)
throw new Error("Second element in signature must be a DERInteger");
var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
// The less significant bit specifies whether the y coordinate
// of the compressed point is even or not.
var isYEven = i & 1;
cursor += 2+sig[cursor+1];
// The more significant bit specifies whether we should use the
// first or second candidate key.
var isSecondKey = i >> 1;
//if (cursor != sig.length)
// throw new Error("Extra bytes in signature");
var n = ecparams.getN();
var G = ecparams.getG();
var curve = ecparams.getCurve();
var p = curve.getQ();
var a = curve.getA().toBigInteger();
var b = curve.getB().toBigInteger();
var r = BigInteger.fromByteArrayUnsigned(rBa);
var s = BigInteger.fromByteArrayUnsigned(sBa);
// We precalculate (p + 1) / 4 where p is if the field order
if (!P_OVER_FOUR) {
P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4));
}
return {r: r, s: s};
// 1.1 Compute x
var x = isSecondKey ? r.add(n) : r;
// 1.3 Convert x to point
var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
var beta = alpha.modPow(P_OVER_FOUR, p);
var xorOdd = beta.isEven() ? (i % 2) : ((i+1) % 2);
// If beta is even, but y isn't or vice versa, then convert it,
// otherwise we're done and y == beta.
var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta);
// 1.4 Check that nR is at infinity
var R = new ECPointFp(curve,
curve.fromBigInteger(x),
curve.fromBigInteger(y));
R.validate();
// 1.5 Compute e from M
var e = BigInteger.fromByteArrayUnsigned(hash);
var eNeg = BigInteger.ZERO.subtract(e).mod(n);
// 1.6 Compute Q = r^-1 (sR - eG)
var rInv = r.modInverse(n);
var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv);
Q.validate();
if (!ECDSA.verifyRaw(e, r, s, Q)) {
throw "Pubkey recovery unsuccessful";
}
var pubKey = new Bitcoin.ECKey();
pubKey.pub = Q;
return pubKey;
},
/**
* Calculate pubkey extraction parameter.
*
* When extracting a pubkey from a signature, we have to
* distinguish four different cases. Rather than putting this
* burden on the verifier, Bitcoin includes a 2-bit value with the
* signature.
*
* This function simply tries all four cases and returns the value
* that resulted in a successful pubkey recovery.
*/
calcPubkeyRecoveryParam: function (address, r, s, hash)
{
for (var i = 0; i < 4; i++) {
try {
var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i);
if (pubkey.getBitcoinAddress().toString() == address) {
return i;
}
} catch (e) {}
}
throw "Unable to find valid recovery factor";
}
};
};
return ECDSA;
return ECDSA;
})();
Bitcoin.ECKey = (function () {
var ECDSA = Bitcoin.ECDSA;
var ecparams = getSECCurveByName("secp256k1");
var rng = new SecureRandom();
var ECDSA = Bitcoin.ECDSA;
var ecparams = getSECCurveByName("secp256k1");
var rng = new SecureRandom();
var ECKey = function (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) {
// Prepend zero byte to prevent interpretation as negative integer
this.priv = BigInteger.fromByteArrayUnsigned(Crypto.util.base64ToBytes(input));
}
};
var ECKey = function (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;
};
ECKey.prototype.getPub = function () {
if (this.pub) return this.pub;
/**
* Whether public keys should be returned compressed by default.
*/
ECKey.compressByDefault = false;
return this.pub = ecparams.getG().multiply(this.priv).getEncoded();
};
/**
* Set whether the public key should be returned compressed or not.
*/
ECKey.prototype.setCompressed = function (v) {
this.compressed = !!v;
};
ECKey.prototype.getPubKeyHash = function () {
if (this.pubKeyHash) return this.pubKeyHash;
/**
* Return public key in DER encoding.
*/
ECKey.prototype.getPub = function () {
return this.getPubPoint().getEncoded(this.compressed);
};
return this.pubKeyHash = Bitcoin.Util.sha256ripe160(this.getPub());
};
/**
* Return public point as ECPoint object.
*/
ECKey.prototype.getPubPoint = function () {
if (!this.pub) this.pub = ecparams.getG().multiply(this.priv);
ECKey.prototype.getBitcoinAddress = function () {
var hash = this.getPubKeyHash();
var addr = new Bitcoin.Address(hash);
return addr;
};
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 = 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.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.sign = function (hash) {
return ECDSA.sign(hash, this.priv);
};
ECKey.prototype.verify = function (hash, sig) {
return ECDSA.verify(hash, sig, this.getPub());
};
ECKey.prototype.verify = function (hash, sig) {
return ECDSA.verify(hash, sig, this.getPub());
};
return ECKey;
/**
* 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!";
}
var version = hash.shift();
if (version != 0x80) {
throw "Version "+version+" not supported!";
}
return hash;
};
return ECKey;
})();

@@ -10,8 +10,8 @@ (function (exports, Bitcoin, io, $, global) {

function ExitNode(host, port, secure) {
this.setUri(host, port, secure);
this.setUri(host, port, secure);
this.unique = 1;
this.unique = 1;
this.connected = false;
this.callbacks = [];
this.callbacks = [];
};

@@ -26,3 +26,3 @@

ExitNode.prototype.connect = function (wallet) {
this.wallet = wallet;
this.wallet = wallet;

@@ -33,13 +33,13 @@ // Workaround for socket.io not properly allowing disconnecting and reconnecting

this.socket = io.connect(this.uri);
this.socket.on('connect', $.proxy(this.handleConnect, this));
this.socket.on('error', function () {
console.log('error, test');
});
this.socket.on('message', $.proxy(this.handleMessage, this));
this.socket.on('disconnect', $.proxy(this.handleDisconnect, this));
this.socket = io.connect(this.uri);
this.socket.on('connect', $.proxy(this.handleConnect, this));
this.socket.on('error', function () {
console.log('error, test');
});
this.socket.on('message', $.proxy(this.handleMessage, this));
this.socket.on('disconnect', $.proxy(this.handleDisconnect, this));
};
ExitNode.prototype.disconnect = function () {
if (this.socket) {
if (this.socket) {
this.socket.disconnect();

@@ -57,13 +57,13 @@ this.socket = null;

ExitNode.prototype.call = function (method, argObj, callback) {
this.socket.send($.toJSON({
"method": method,
"params": [argObj],
"id": this.unique
}));
if (callback) this.callbacks[this.unique] = callback;
this.unique++;
this.socket.send($.toJSON({
"method": method,
"params": [argObj],
"id": this.unique
}));
if (callback) this.callbacks[this.unique] = callback;
this.unique++;
};
ExitNode.prototype.handleConnect = function () {
var self = this;
var self = this;

@@ -74,17 +74,17 @@ this.connected = true;

ExitNode.prototype.listen = function (addrs) {
self.call("pubkeysRegister", {
keys: addrs.join(',')
}, function (err, result) {
if (err) {
console.error("Could not register public keys");
return;
}
self.call("pubkeysRegister", {
keys: addrs.join(',')
}, function (err, result) {
if (err) {
console.error("Could not register public keys");
return;
}
self.call("pubkeysListen", {
handle: result.handle
}, function (err, result) {
// Communicate the block height
self.trigger('blockInit', {height: result.height});
self.call("pubkeysListen", {
handle: result.handle
}, function (err, result) {
// Communicate the block height
self.trigger('blockInit', {height: result.height});
// Pass on the newly downloaded transactions
// Pass on the newly downloaded transactions
self.trigger('txData', {

@@ -95,11 +95,11 @@ confirmed: true,

// TODO: Download more transactions
// TODO: Download more transactions
self.trigger('connectStatus', {status: 'ok'});
});
});
self.call("pubkeysUnconfirmed", {
handle: result.handle
}, function (err, result) {
// Pass on the newly downloaded transactions
self.call("pubkeysUnconfirmed", {
handle: result.handle
}, function (err, result) {
// Pass on the newly downloaded transactions
self.trigger('txData', {

@@ -109,4 +109,4 @@ confirmed: false,

});
});
});
});
});
};

@@ -116,12 +116,12 @@

ExitNode.prototype.handleMessage = function (data) {
// Handle JSON-RPC result messages
if ("undefined" !== typeof data.result &&
"function" == typeof this.callbacks[data.id]) {
this.callbacks[data.id](data.error, data.result);
// Handle JSON-RPC result messages
if ("undefined" !== typeof data.result &&
"function" == typeof this.callbacks[data.id]) {
this.callbacks[data.id](data.error, data.result);
// Handle JSON-RPC request messages
} else if ("undefined" !== typeof data.method) {
// Create an event
// Handle JSON-RPC request messages
} else if ("undefined" !== typeof data.method) {
// Create an event
this.trigger(data.method, data.params[0]);
}
}
};

@@ -131,3 +131,3 @@

ExitNode.prototype.handleDisconnect = function () {
// TODO: Attempt reconnect (unless disconnect was intended)
// TODO: Attempt reconnect (unless disconnect was intended)
};

@@ -134,0 +134,0 @@

@@ -35,5 +35,2 @@ // Basic Javascript Elliptic Curve implementation

function feFpSubtract(b) {
/*console.log("b.y (int): ", Crypto.util.bytesToHex(this.x.toByteArrayUnsigned()));
console.log("this.y (int): ", Crypto.util.bytesToHex(b.toBigInteger().toByteArrayUnsigned()));
console.log("b.y-this.y (premod): ", Crypto.util.bytesToHex(this.x.subtract(b.toBigInteger()).toByteArrayUnsigned()));*/
return new ECFieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q));

@@ -51,3 +48,2 @@ }

function feFpDivide(b) {
//console.log("x: ", Crypto.util.bytesToHex(this.x.toByteArrayUnsigned()));
return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q));

@@ -130,3 +126,2 @@ }

if(BigInteger.ZERO.equals(v)) {

@@ -133,0 +128,0 @@ if(BigInteger.ZERO.equals(u)) {

@@ -215,3 +215,3 @@ // Copyright (c) 2005 Tom Wu

r = i-a.t;
if(r != 0) return r;
if(r != 0) return (this.s<0)?-r:r;
while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;

@@ -218,0 +218,0 @@ return 0;

(function () {
var Opcode = Bitcoin.Opcode = function (num) {
this.code = num;
};
var Opcode = Bitcoin.Opcode = function (num) {
this.code = num;
};
Opcode.prototype.toString = function () {
return Opcode.reverseMap[this.code];
};
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,
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,
// 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,
// 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,
// 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,
// 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,
// 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_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_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,
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,
// 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,
// 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,
};
// template matching params
OP_PUBKEYHASH : 253,
OP_PUBKEY : 254,
OP_INVALIDOPCODE : 255
};
Opcode.reverseMap = [];
Opcode.reverseMap = [];
for (var i in Opcode.map) {
Opcode.reverseMap[Opcode.map[i]] = i;
}
for (var i in Opcode.map) {
Opcode.reverseMap[Opcode.map[i]] = i;
}
})();

@@ -0,3 +1,9 @@

/**
* Implement the Paillier cryptosystem in JavaScript.
*
* Paillier is useful for multiparty calculation. It is not currently part of any
* BitcoinJS-lib distribution, but it is included here for experimental use.
*/
Bitcoin.Paillier = (function () {
var rng = new SecureRandom();
var rng = new SecureRandom();
var TWO = BigInteger.valueOf(2);

@@ -4,0 +10,0 @@

(function () {
var Opcode = Bitcoin.Opcode;
var Opcode = Bitcoin.Opcode;
// Make opcodes available as pseudo-constants
for (var i in Opcode.map) {
eval("var " + i + " = " + Opcode.map[i] + ";");
}
// Make opcodes available as pseudo-constants
for (var i in Opcode.map) {
eval("var " + i + " = " + Opcode.map[i] + ";");
}
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;
} 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;
} else {
throw new Error("Invalid script");
}
this.parse();
};
this.parse();
};
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 < 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);
}
}
};
Script.prototype.getOutType = function ()
{
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) {
/**
* 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 () {
// Transfer to Bitcoin address
return 'Address';
} else if (this.chunks.length == 2 &&
this.chunks[1] == OP_CHECKSIG) {
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
return 'Pubkey';
} else {
return 'Strange';
}
}
// Transfer to IP address
return 'Pubkey';
} 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");
}
};
Script.prototype.simpleOutPubKeyHash = 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");
}
};
/**
* Old name for Script#simpleOutHash.
*
* @deprecated
*/
Script.prototype.simpleOutPubKeyHash = Script.prototype.simpleOutHash;
Script.prototype.getInType = function ()
{
if (this.chunks.length == 1) {
// Direct IP to IP transactions only have the public key in their scriptSig.
return 'Pubkey';
} else if (this.chunks.length == 2 &&
Bitcoin.Util.isArray(this.chunks[0]) &&
Bitcoin.Util.isArray(this.chunks[1])) {
return 'Address';
} else {
console.log(this.chunks);
throw new Error("Encountered non-standard scriptSig");
}
};
/**
* 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';
}
};
Script.prototype.simpleInPubKey = function ()
{
switch (this.getInType()) {
case 'Address':
return this.chunks[1];
case 'Pubkey':
return this.chunks[0];
default:
throw new Error("Encountered non-standard scriptSig");
}
};
/**
* 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");
}
};
Script.prototype.simpleInPubKeyHash = function ()
{
return Bitcoin.Util.sha256ripe160(this.simpleInPubKey());
};
/**
* 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());
};
Script.prototype.writeOp = function (opcode)
{
this.buffer.push(opcode);
this.chunks.push(opcode);
};
/**
* Old name for Script#simpleInHash.
*
* @deprecated
*/
Script.prototype.simpleInPubKeyHash = Script.prototype.simpleInHash;
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);
};
/**
* Add an op code to the script.
*/
Script.prototype.writeOp = function (opcode)
{
this.buffer.push(opcode);
this.chunks.push(opcode);
};
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;
};
/**
* 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.createInputScript = function (signature, pubKey)
{
var script = new Script();
script.writeBytes(signature);
script.writeBytes(pubKey);
return script;
};
/**
* 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;
};
/**
* 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");
}
};
Script.prototype.clone = function ()
{
return new Script(this.buffer);
};
/**
* Create an m-of-n output script
*/
Script.createMultiSigOutputScript = function (m, pubkeys)
{
var script = new Bitcoin.Script();
script.writeOp(OP_1 + m - 1);
for (var i = 0; i < pubkeys.length; ++i) {
script.writeBytes(pubkeys[i]);
}
script.writeOp(OP_1 + pubkeys.length - 1);
script.writeOp(OP_CHECKMULTISIG);
return script;
};
/**
* Create a standard payToPubKeyHash input.
*/
Script.createInputScript = function (signature, pubKey)
{
var script = new Script();
script.writeBytes(signature);
script.writeBytes(pubKey);
return script;
};
Script.prototype.clone = function ()
{
return new Script(this.buffer);
};
})();
(function () {
var Script = Bitcoin.Script;
var Script = Bitcoin.Script;
var Transaction = Bitcoin.Transaction = function (doc) {
this.version = 1;
this.lock_time = 0;
this.ins = [];
this.outs = [];
this.timestamp = null;
this.block = null;
var Transaction = Bitcoin.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 (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;
}
};
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 (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;
}
};
Transaction.objectify = function (txs) {
var objs = [];
for (var i = 0; i < txs.length; i++) {
objs.push(new Transaction(txs[i]));
}
return objs;
};
/**
* Turn transaction data into Transaction objects.
*
* 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;
};
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
}));
}
};
/**
* 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) {
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
}));
}
};
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
}
/**
* 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) {
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({
value: value,
script: Script.createOutputScript(address)
}));
}
};
this.outs.push(new TransactionOut({
value: value,
script: Script.createOutputScript(address)
}));
}
};
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));
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());
/**
* 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));
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;
};
return buffer;
};
var OP_CODESEPARATOR = 171;
var OP_CODESEPARATOR = 171;
var SIGHASH_ALL = 1;
var SIGHASH_NONE = 2;
var SIGHASH_SINGLE = 3;
var SIGHASH_ANYONECANPAY = 80;
var SIGHASH_ALL = 1;
var SIGHASH_NONE = 2;
var SIGHASH_SINGLE = 3;
var SIGHASH_ANYONECANPAY = 80;
Transaction.prototype.hashTransactionForSignature = function (connectedScript, inIndex, hashType)
{
var txTmp = this.clone();
/**
* 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;
});*/
// 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();
}
// 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;
txTmp.ins[inIndex].script = connectedScript;
// Blank out some of the outputs
if ((hashType & 0x1f) == SIGHASH_NONE) {
txTmp.outs = [];
// 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
}
// 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]];
}
// Blank out other inputs completely, not recommended for open transactions
if (hashType & SIGHASH_ANYONECANPAY) {
txTmp.ins = [txTmp.ins[inIndex]];
}
console.log(txTmp);
var buffer = txTmp.serialize();
var buffer = txTmp.serialize();
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(hashType)]).reverse());
buffer = buffer.concat(Crypto.util.wordsToBytes([parseInt(hashType)]).reverse());
console.log("signtx: "+Crypto.util.bytesToHex(buffer));
var hash1 = Crypto.SHA256(buffer, {asBytes: true});
var hash1 = Crypto.SHA256(buffer, {asBytes: true});
return Crypto.SHA256(hash1, {asBytes: true});
};
console.log("sha256_1: ", Crypto.util.bytesToHex(hash1));
/**
* 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});
};
return Crypto.SHA256(hash1, {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);
}
for (var i = 0; i < this.outs.length; i++) {
var txout = this.outs[i].clone();
newTx.addOutput(txout);
}
return newTx;
};
Transaction.prototype.getHash = function ()
{
var buffer = this.serialize();
return Crypto.SHA256(Crypto.SHA256(buffer, {asBytes: true}), {asBytes: true});
};
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 Bitcoin.Wallet)) return null;
Transaction.prototype.analyze = function (wallet) {
if (!(wallet instanceof Bitcoin.Wallet)) return null;
var allFromMe = true,
allToMe = true,
firstRecvHash = null,
firstMeRecvHash = null,
firstSendHash = 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;
}
}
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 impact = this.calcImpact(wallet);
var impact = this.calcImpact(wallet);

@@ -213,13 +277,16 @@ var analysis = {};

if (impact.sign > 0 && impact.value.compareTo(BigInteger.ZERO) > 0) {
analysis.type = 'recv';
if (impact.sign > 0 && impact.value.compareTo(BigInteger.ZERO) > 0) {
analysis.type = 'recv';
analysis.addr = new Bitcoin.Address(firstMeRecvHash);
} else if (allFromMe && allToMe) {
} else if (allFromMe && allToMe) {
analysis.type = 'self';
} else if (allFromMe) {
} 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";
}
} else {
analysis.type = "other";
}

@@ -229,3 +296,9 @@ return analysis;

Transaction.prototype.getDescription = function (wallet) {
/**
* 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);

@@ -241,7 +314,7 @@

case 'sent':
return "Payment to "+analysis.addr;
return "Payment to "+analysis.addr;
break;
case 'self':
return "Payment to yourself";
return "Payment to yourself";
break;

@@ -253,114 +326,124 @@

}
};
};
Transaction.prototype.getTotalValue = 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));
}
return totalValue;
};
/**
* 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));
}
return totalValue;
};
/**
* 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;
/**
* Old name for Transaction#getTotalOutValue.
*
* @deprecated
*/
Transaction.prototype.getTotalValue = Transaction.prototype.getTotalOutValue;
// 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));
}
}
/**
* 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 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));
}
}
}
if (valueOut.compareTo(valueIn) >= 0) {
return {
sign: 1,
value: valueOut.subtract(valueIn)
};
} else {
return {
sign: -1,
value: valueIn.subtract(valueOut)
};
}
};
// 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 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);
}
this.sequence = data.sequence;
};
// 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));
}
}
}
if (valueOut.compareTo(valueIn) >= 0) {
return {
sign: 1,
value: valueOut.subtract(valueIn)
};
} else {
return {
sign: -1,
value: valueIn.subtract(valueOut)
};
}
};
TransactionIn.prototype.clone = function ()
{
var newTxin = new TransactionIn({
outpoint: {
hash: this.outpoint.hash,
index: this.outpoint.index
},
script: this.script.clone(),
sequence: this.sequence
});
return newTxin;
};
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);
}
this.sequence = data.sequence;
};
var TransactionOut = Bitcoin.TransactionOut = function (data)
{
if (data.script instanceof Script) {
this.script = data.script;
} else {
this.script = new Script(data.script);
}
TransactionIn.prototype.clone = function ()
{
var newTxin = new TransactionIn({
outpoint: {
hash: this.outpoint.hash,
index: this.outpoint.index
},
script: this.script.clone(),
sequence: this.sequence
});
return newTxin;
};
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);
}
};
var TransactionOut = Bitcoin.TransactionOut = function (data)
{
if (data.script instanceof Script) {
this.script = data.script;
} else {
this.script = new Script(data.script);
}
TransactionOut.prototype.clone = function ()
{
var newTxout = new TransactionOut({
script: this.script.clone(),
value: this.value.slice(0)
});
return newTxout;
};
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);
}
};
TransactionOut.prototype.clone = function ()
{
var newTxout = new TransactionOut({
script: this.script.clone(),
value: this.value.slice(0)
});
return newTxout;
};
})();
var TransactionDatabase = function () {
this.txs = [];
this.txIndex = {};
this.txs = [];
this.txIndex = {};
};

@@ -9,49 +9,49 @@

TransactionDatabase.prototype.addTransaction = function (tx) {
this.addTransactionNoUpdate(tx);
$(this).trigger('update');
this.addTransactionNoUpdate(tx);
$(this).trigger('update');
};
TransactionDatabase.prototype.addTransactionNoUpdate = function (tx) {
// Return if transaction is already known
if (this.txIndex[tx.hash]) {
return;
}
// Return if transaction is already known
if (this.txIndex[tx.hash]) {
return;
}
this.txs.push(new Bitcoin.Transaction(tx));
this.txIndex[tx.hash] = tx;
this.txs.push(new Bitcoin.Transaction(tx));
this.txIndex[tx.hash] = tx;
};
TransactionDatabase.prototype.removeTransaction = function (hash) {
this.removeTransactionNoUpdate(hash);
$(this).trigger('update');
this.removeTransactionNoUpdate(hash);
$(this).trigger('update');
};
TransactionDatabase.prototype.removeTransactionNoUpdate = function (hash) {
var tx = this.txIndex[hash];
var tx = this.txIndex[hash];
if (!tx) {
// If the tx is not in the index, we don't actually waste our
// time looping through the array.
return;
}
if (!tx) {
// If the tx is not in the index, we don't actually waste our
// time looping through the array.
return;
}
for (var i = 0, l = this.txs.length; i < l; i++) {
if (this.txs[i].hash == hash) {
this.txs.splice(i, 1);
break;
}
}
for (var i = 0, l = this.txs.length; i < l; i++) {
if (this.txs[i].hash == hash) {
this.txs.splice(i, 1);
break;
}
}
delete this.txIndex[hash];
delete this.txIndex[hash];
};
TransactionDatabase.prototype.loadTransactions = function (txs) {
for (var i = 0; i < txs.length; i++) {
this.addTransactionNoUpdate(txs[i]);
}
$(this).trigger('update');
for (var i = 0; i < txs.length; i++) {
this.addTransactionNoUpdate(txs[i]);
}
$(this).trigger('update');
};
TransactionDatabase.prototype.getTransactions = function () {
return this.txs;
return this.txs;
};

@@ -58,0 +58,0 @@

// BigInteger monkey patching
BigInteger.valueOf = nbv;
/**
* 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.
*/
BigInteger.prototype.toByteArrayUnsigned = function () {
var ba = this.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;
}
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;
}
};
/**
* 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.
*/
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);
}
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);
}
};
/**
* 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
*/
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;
};
/**
* Parse a signed big integer byte representation.
*
* For details on the format please see BigInteger.toByteArraySigned.
*/
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"];
"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() {};
if ("undefined" == typeof window.console[names[i]])
window.console[names[i]] = function() {};
// Bitcoin utility functions
Bitcoin.Util = {
isArray: Array.isArray || function(o) {
return Object.prototype.toString.call(o) === '[object Array]';
},
makeFilledArray: function (len, val) {
var array = [];
var i = 0;
while (i < len) {
array[i++] = val;
}
return array;
},
numToVarInt: function (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]));
}
},
valueToBigInt: function (valueBuffer) {
if (valueBuffer instanceof BigInteger) return valueBuffer;
/**
* Cross-browser compatibility version of Array.isArray.
*/
isArray: Array.isArray || function(o)
{
return Object.prototype.toString.call(o) === '[object Array]';
},
// Prepend zero byte to prevent interpretation as negative integer
return BigInteger.fromByteArrayUnsigned(valueBuffer);
},
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;
},
/**
* 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;
}
return array;
},
/**
* 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]));
}
},
/**
* Parse a Bitcoin value byte array, returning a BigInteger.
*/
valueToBigInt: function (valueBuffer)
{
if (valueBuffer instanceof BigInteger) return valueBuffer;
// Prepend zero byte to prevent interpretation as negative integer
return BigInteger.fromByteArrayUnsigned(valueBuffer);
},
/**
* 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) {
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)));
// 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;
},
sha256ripe160: function (data) {
return Crypto.RIPEMD160(Crypto.SHA256(data, {asBytes: true}), {asBytes: true});
}
/**
* Calculate RIPEMD160(SHA256(data)).
*
* Takes an arbitrary byte array as inputs and returns the hash as a byte
* array.
*/
sha256ripe160: function (data) {
return Crypto.RIPEMD160(Crypto.SHA256(data, {asBytes: true}), {asBytes: true});
}
};

@@ -98,0 +223,0 @@

Bitcoin.Wallet = (function () {
var Script = Bitcoin.Script,
TransactionIn = Bitcoin.TransactionIn,
TransactionOut = Bitcoin.TransactionOut;
var Script = Bitcoin.Script,
TransactionIn = Bitcoin.TransactionIn,
TransactionOut = Bitcoin.TransactionOut;
var Wallet = function () {
// Keychain
var keys = [];
this.addressHashes = [];
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 = [];
// Transaction data
this.txIndex = {};
this.unspentOuts = [];
// Public hashes of our keys
this.addressHashes = [];
// Other fields
this.addressPointer = 0;
// Transaction data
this.txIndex = {};
this.unspentOuts = [];
this.addKey = function (key, pub) {
if (!(key instanceof Bitcoin.ECKey)) {
key = new Bitcoin.ECKey(key);
}
keys.push(key);
// 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) {

@@ -28,9 +43,12 @@ if ("string" === typeof pub) {

}
key.pub = pub;
key.setPub(pub);
}
this.addressHashes.push(key.getBitcoinAddress().getHashBase64());
};
this.addressHashes.push(key.getBitcoinAddress().getHashBase64());
};
this.addKeys = function (keys, pubs) {
/**
* Add multiple keys at once.
*/
this.addKeys = function (keys, pubs) {
if ("string" === typeof keys) {

@@ -42,38 +60,54 @@ keys = keys.split(',');

}
console.log(pubs);
var i;
if (Array.isArray(pubs) && keys.length == pubs.length) {
for (var i = 0; i < keys.length; i++) {
this.addKey(keys[i], pubs[i]);
for (i = 0; i < keys.length; i++) {
this.addKey(keys[i], pubs[i]);
}
} else {
for (var i = 0; i < keys.length; i++) {
this.addKey(keys[i]);
for (i = 0; i < keys.length; i++) {
this.addKey(keys[i]);
}
}
};
};
this.getKeys = function () {
var serializedWallet = [];
/**
* Get the key chain.
*
* Returns an array of base64-encoded private values.
*/
this.getKeys = function () {
var serializedWallet = [];
for (var i = 0; i < keys.length; i++) {
serializedWallet.push(keys[i].toString('base64'));
}
for (var i = 0; i < keys.length; i++) {
serializedWallet.push(keys[i].toString('base64'));
}
return serializedWallet;
};
return serializedWallet;
};
/**
* Get the public keys.
*
* Returns an array of base64-encoded public keys.
*/
this.getPubKeys = function () {
var pubs = [];
var pubs = [];
for (var i = 0; i < keys.length; i++) {
pubs.push(Crypto.util.bytesToBase64(keys[i].getPub()));
}
for (var i = 0; i < keys.length; i++) {
pubs.push(Crypto.util.bytesToBase64(keys[i].getPub()));
}
return pubs;
return pubs;
};
this.clear = function () {
keys = [];
};
/**
* Delete all keys.
*/
this.clear = function () {
keys = [];
};
/**
* Return the number of keys in this wallet.
*/
this.getLength = function () {

@@ -83,110 +117,140 @@ return keys.length;

this.getAllAddresses = function () {
var addresses = [];
for (var i = 0; i < keys.length; i++) {
addresses.push(keys[i].getBitcoinAddress());
}
return addresses;
};
/**
* 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;
}
};
this.getCurAddress = function () {
if (keys[this.addressPointer]) {
return keys[this.addressPointer].getBitcoinAddress();
} else {
return null;
}
};
this.getNextAddress = function () {
if (keys.length) {
// TODO: Create new addresses if we run out
this.addressPointer = (this.addressPointer + 1) % keys.length;
return keys[this.addressPointer].getBitcoinAddress();
} else {
return null;
}
};
/**
* 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();
};
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");
};
/**
* 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");
};
this.getPubKeyFromHash = function (pubKeyHash) {
pubKeyHash = Crypto.util.bytesToBase64(pubKeyHash);
for (var i = 0; i < this.addressHashes.length; i++) {
if (this.addressHashes[i] == pubKeyHash) {
console.log(Crypto.util.bytesToBase64(Bitcoin.Util.sha256ripe160(keys[i].getPub())), pubKeyHash);
return keys[i].getPub();
}
}
throw new Error("Hash unknown");
};
};
/**
* 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();
}
}
throw new Error("Hash unknown");
};
};
Wallet.prototype.generateAddress = function () {
this.addKey(new Bitcoin.ECKey());
};
Wallet.prototype.generateAddress = function () {
this.addKey(new Bitcoin.ECKey());
};
Wallet.prototype.process = function (tx) {
if (this.txIndex[tx.hash]) return;
/**
* 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;
// Gather outputs
for (var j = 0; j < tx.outs.length; j++) {
var txout = new TransactionOut(tx.outs[j]);
var hash = Crypto.util.bytesToBase64(txout.script.simpleOutPubKeyHash());
for (var k = 0; k < this.addressHashes.length; k++) {
if (this.addressHashes[k] === hash) {
this.unspentOuts.push({tx: tx, index: j, out: txout});
break;
}
}
}
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;
}
}
}
// Remove spent outputs
for (var j = 0; j < tx.ins.length; j++) {
var txin = new TransactionIn(tx.ins[j]);
var pubkey = txin.script.simpleInPubKey();
var hash = Crypto.util.bytesToBase64(Bitcoin.Util.sha256ripe160(pubkey));
for (var 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);
}
}
break;
}
}
}
// 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);
}
}
break;
}
}
}
// Index transaction
this.txIndex[tx.hash] = tx;
};
// 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));
}
return balance;
};
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));
}
return balance;
};
Wallet.prototype.createSend = function (address, sendValue, feeValue) {
var selectedOuts = [];
Wallet.prototype.createSend = function (address, sendValue, feeValue) {
var selectedOuts = [];
var txValue = sendValue.add(feeValue);
var availableValue = BigInteger.ZERO;
for (var i = 0; i < this.unspentOuts.length; i++) {
selectedOuts.push(this.unspentOuts[i]);
availableValue = availableValue.add(Bitcoin.Util.valueToBigInt(this.unspentOuts[i].out.value));
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;
}
if (availableValue.compareTo(txValue) >= 0) break;
}

@@ -197,37 +261,32 @@ if (availableValue.compareTo(txValue) < 0) {

console.log(selectedOuts);
var changeValue = availableValue.subtract(txValue);
var changeValue = availableValue.subtract(txValue);
var sendTx = new Bitcoin.Transaction();
var sendTx = new Bitcoin.Transaction();
for (var i = 0; i < selectedOuts.length; i++) {
sendTx.addInput(selectedOuts[i].tx, selectedOuts[i].index);
}
for (i = 0; i < selectedOuts.length; i++) {
sendTx.addInput(selectedOuts[i].tx, selectedOuts[i].index);
}
sendTx.addOutput(address, sendValue);
if (changeValue.compareTo(BigInteger.ZERO) > 0) {
sendTx.addOutput(this.getNextAddress(), changeValue);
}
sendTx.addOutput(address, sendValue);
if (changeValue.compareTo(BigInteger.ZERO) > 0) {
sendTx.addOutput(this.getNextAddress(), changeValue);
}
var hashType = 1; // SIGHASH_ALL
var hashType = 1; // SIGHASH_ALL
for (var 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);
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));
// Append hash type
signature.push(parseInt(hashType, 10));
sendTx.ins[i].script = Script.createInputScript(signature, this.getPubKeyFromHash(pubKeyHash));
}
sendTx.ins[i].script = Script.createInputScript(signature, this.getPubKeyFromHash(pubKeyHash));
}
console.log(sendTx);
return sendTx;
};
console.log("pubkey: "+Crypto.util.bytesToHex(this.getPubKeyFromHash(pubKeyHash)));
return sendTx;
};
Wallet.prototype.clearTransactions = function () {

@@ -238,17 +297,17 @@ this.txIndex = {};

/**
* 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);
/**
* Check to see if a pubKeyHash belongs to this wallet.
*/
Wallet.prototype.hasHash = function (hash) {
if (Bitcoin.Util.isArray(hash)) hash = Crypto.util.bytesToBase64(hash);
// TODO: Just create an object with base64 hashes as keys for faster lookup
for (var k = 0; k < this.addressHashes.length; k++) {
if (this.addressHashes[k] === hash) return true;
}
return false;
};
// 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;
}
return false;
};
return Wallet;
return Wallet;
})();
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc