cosmetic standardization

[closes #56]
This commit is contained in:
Wei Lu 2014-03-31 11:47:47 +08:00
parent 161127d65a
commit 93fe1b4c78
25 changed files with 2092 additions and 2142 deletions

View file

@ -4,8 +4,9 @@ var error = require('./util').error
var mainnet = require('./network').mainnet.addressVersion
function Address(bytes, version) {
if (!(this instanceof Address))
if (!(this instanceof Address)) {
return new Address(bytes, version)
}
if (bytes instanceof Address) {
this.hash = bytes.hash

View file

@ -1,16 +1,16 @@
// https://en.bitcoin.it/wiki/Base58Check_encoding
var BigInteger = require('./jsbn/jsbn');
var Crypto = require('crypto-js');
var convert = require('./convert');
var SHA256 = Crypto.SHA256;
var BigInteger = require('./jsbn/jsbn')
var Crypto = require('crypto-js')
var convert = require('./convert')
var SHA256 = Crypto.SHA256
var alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
var base = BigInteger.valueOf(58);
var alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
var base = BigInteger.valueOf(58)
var positions = {};
for (var i=0 ; i < alphabet.length ; ++i) {
positions[alphabet[i]] = i;
var positions = {}
for (var i=0; i<alphabet.length; ++i) {
positions[alphabet[i]] = i
}
// Convert a byte array to a base58-encoded string.
@ -18,92 +18,91 @@ for (var i=0 ; i < alphabet.length ; ++i) {
// Copyright (c) 2011 Google Inc.
// Ported to JavaScript by Stefan Thomas.
function encode(input) {
var bi = BigInteger.fromByteArrayUnsigned(input);
var chars = [];
var bi = BigInteger.fromByteArrayUnsigned(input)
var chars = []
while (bi.compareTo(base) >= 0) {
var mod = bi.mod(base);
chars.push(alphabet[mod.intValue()]);
bi = bi.subtract(mod).divide(base);
var mod = bi.mod(base)
chars.push(alphabet[mod.intValue()])
bi = bi.subtract(mod).divide(base)
}
chars.push(alphabet[bi.intValue()]);
chars.push(alphabet[bi.intValue()])
// Convert leading zeros too.
for (var i = 0; i < input.length; i++) {
for (var i=0; i<input.length; i++) {
if (input[i] == 0x00) {
chars.push(alphabet[0]);
} else break;
chars.push(alphabet[0])
} else break
}
return chars.reverse().join('');
return chars.reverse().join('')
}
// decode a base58 string into a byte array
// input should be a base58 encoded string
// @return Array
function decode(input) {
var base = BigInteger.valueOf(58);
var base = BigInteger.valueOf(58)
var length = input.length;
var num = BigInteger.valueOf(0);
var leading_zero = 0;
var seen_other = false;
for (var i=0; i<length ; ++i) {
var chr = input[i];
var p = positions[chr];
var length = input.length
var num = BigInteger.valueOf(0)
var leading_zero = 0
var seen_other = false
for (var i=0; i<length; ++i) {
var chr = input[i]
var p = positions[chr]
// if we encounter an invalid character, decoding fails
if (p === undefined) {
throw new Error('invalid base58 string: ' + input);
throw new Error('invalid base58 string: ' + input)
}
num = num.multiply(base).add(BigInteger.valueOf(p));
num = num.multiply(base).add(BigInteger.valueOf(p))
if (chr == '1' && !seen_other) {
++leading_zero;
}
else {
seen_other = true;
++leading_zero
} else {
seen_other = true
}
}
var bytes = num.toByteArrayUnsigned();
var bytes = num.toByteArrayUnsigned()
// remove leading zeros
while (leading_zero-- > 0) {
bytes.unshift(0);
bytes.unshift(0)
}
return bytes;
return bytes
}
function checkEncode(input, vbyte) {
vbyte = vbyte || 0;
vbyte = vbyte || 0
var front = [vbyte].concat(input);
return encode(front.concat(getChecksum(front)));
var front = [vbyte].concat(input)
return encode(front.concat(getChecksum(front)))
}
function checkDecode(input) {
var bytes = decode(input),
front = bytes.slice(0,bytes.length-4),
back = bytes.slice(bytes.length-4);
front = bytes.slice(0, bytes.length-4),
back = bytes.slice(bytes.length-4)
var checksum = getChecksum(front);
var checksum = getChecksum(front)
if ("" + checksum != "" + back) {
throw new Error("Checksum failed");
throw new Error("Checksum failed")
}
var o = front.slice(1);
o.version = front[0];
return o;
var o = front.slice(1)
o.version = front[0]
return o
}
function getChecksum(bytes) {
var wordArray = convert.bytesToWordArray(bytes)
return convert.hexToBytes(SHA256(SHA256(wordArray)).toString()).slice(0,4);
return convert.hexToBytes(SHA256(SHA256(wordArray)).toString()).slice(0, 4)
}
module.exports = {

View file

@ -1,60 +1,48 @@
var Crypto = require('crypto-js');
var WordArray = Crypto.lib.WordArray;
var base64map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var Crypto = require('crypto-js')
var WordArray = Crypto.lib.WordArray
var base64map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
function lpad(str, padString, length) {
while (str.length < length) str = padString + str;
return str;
while (str.length < length) str = padString + str
return str
}
/**
* Convert a byte array to a hex string
*/
function bytesToHex(bytes) {
return bytes.map(function(x) {
return lpad(x.toString(16), '0', 2)
}).join('');
};
}).join('')
}
/**
* Convert a hex string to a byte array
*/
function hexToBytes(hex) {
return hex.match(/../g).map(function(x) {
return parseInt(x,16)
});
})
}
/**
* Convert a byte array to a base-64 string
*/
function bytesToBase64(bytes) {
var base64 = []
for (var i = 0; i < bytes.length; i += 3) {
var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
for (var j = 0; j < 4; j++) {
if (i * 8 + j * 6 <= bytes.length * 8) {
base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F));
base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F))
} else {
base64.push('=');
base64.push('=')
}
}
}
return base64.join('');
return base64.join('')
}
/**
* Convert a base-64 string to a byte array
*/
function base64ToBytes(base64) {
// Remove non-base-64 characters
base64 = base64.replace(/[^A-Z0-9+\/]/ig, '');
base64 = base64.replace(/[^A-Z0-9+\/]/ig, '')
var bytes = [];
var imod4 = 0;
var bytes = []
var imod4 = 0
for (var i = 0; i < base64.length; imod4 = ++i % 4) {
if (!imod4) continue
@ -65,10 +53,10 @@ function base64ToBytes(base64) {
(imod4 * 2)
) |
(base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2))
);
)
}
return bytes;
return bytes
}
/**
@ -76,48 +64,48 @@ function base64ToBytes(base64) {
*/
function coerceToBytes(input) {
if (typeof input != 'string') return input
return hexToBytes(input);
return hexToBytes(input)
}
function binToBytes(bin) {
return bin.match(/......../g).map(function(x) {
return parseInt(x,2)
});
})
}
function bytesToBin(bytes) {
return bytes.map(function(x) {
return lpad(x.toString(2), '0', 8)
}).join('');
}).join('')
}
function bytesToString(bytes) {
return bytes.map(function(x){
return String.fromCharCode(x)
}).join('');
}).join('')
}
function stringToBytes(string) {
return string.split('').map(function(x) {
return x.charCodeAt(0)
});
})
}
/**
* Create a byte array representing a number with the given length
*/
function numToBytes(num, bytes) {
if (bytes === undefined) bytes = 8;
if (bytes === 0) return [];
return [num % 256].concat(numToBytes(Math.floor(num / 256), bytes - 1));
if (bytes === undefined) bytes = 8
if (bytes === 0) return []
return [num % 256].concat(numToBytes(Math.floor(num / 256), bytes - 1))
}
/**
* Convert a byte array to the number that it represents
*/
function bytesToNum(bytes) {
if (bytes.length === 0) return 0;
return bytes[0] + 256 * bytesToNum(bytes.slice(1));
if (bytes.length === 0) return 0
return bytes[0] + 256 * bytesToNum(bytes.slice(1))
}
/**
@ -128,10 +116,10 @@ function bytesToNum(bytes) {
* Returns a byte array.
*/
function numToVarInt(num) {
if (num < 253) return [num];
if (num < 65536) return [253].concat(numToBytes(num, 2));
if (num < 4294967296) return [254].concat(numToBytes(num, 4));
return [255].concat(numToBytes(num, 8));
if (num < 253) return [num]
if (num < 65536) return [253].concat(numToBytes(num, 2))
if (num < 4294967296) return [254].concat(numToBytes(num, 4))
return [255].concat(numToBytes(num, 8))
}
/**
@ -157,19 +145,19 @@ function varIntToNum(bytes) {
}
function bytesToWords(bytes) {
var words = [];
var words = []
for (var i = 0, b = 0; i < bytes.length; i++, b += 8) {
words[b >>> 5] |= bytes[i] << (24 - b % 32);
words[b >>> 5] |= bytes[i] << (24 - b % 32)
}
return words;
return words
}
function wordsToBytes(words) {
var bytes = [];
var bytes = []
for (var b = 0; b < words.length * 32; b += 8) {
bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF)
}
return bytes;
return bytes
}
function bytesToWordArray(bytes) {

View file

@ -1,46 +1,43 @@
var sec = require('./jsbn/sec');
var rng = require('secure-random');
var BigInteger = require('./jsbn/jsbn');
var sec = require('./jsbn/sec')
var rng = require('secure-random')
var BigInteger = require('./jsbn/jsbn')
var convert = require('./convert')
var HmacSHA256 = require('crypto-js/hmac-sha256');
var HmacSHA256 = require('crypto-js/hmac-sha256')
var ECPointFp = require('./jsbn/ec').ECPointFp
var ecparams = sec("secp256k1")
var P_OVER_FOUR = null
var ECPointFp = require('./jsbn/ec').ECPointFp;
var ecparams = sec("secp256k1");
var P_OVER_FOUR = null;
function implShamirsTrick(P, k, Q, l)
{
var m = Math.max(k.bitLength(), l.bitLength());
var Z = P.add2D(Q);
var R = P.curve.getInfinity();
function implShamirsTrick(P, k, Q, l) {
var m = Math.max(k.bitLength(), l.bitLength())
var Z = P.add2D(Q)
var R = P.curve.getInfinity()
for (var i = m - 1; i >= 0; --i) {
R = R.twice2D();
R = R.twice2D()
R.z = BigInteger.ONE;
R.z = BigInteger.ONE
if (k.testBit(i)) {
if (l.testBit(i)) {
R = R.add2D(Z);
R = R.add2D(Z)
} else {
R = R.add2D(P);
R = R.add2D(P)
}
} else {
if (l.testBit(i)) {
R = R.add2D(Q);
R = R.add2D(Q)
}
}
}
return R;
};
return R
}
function deterministicGenerateK(hash,key) {
var vArr = [];
var kArr = [];
for (var i = 0;i < 32;i++) vArr.push(1);
for (var i = 0;i < 32;i++) kArr.push(0);
var vArr = []
var kArr = []
for (var i = 0;i < 32;i++) vArr.push(1)
for (var i = 0;i < 32;i++) kArr.push(0)
var v = convert.bytesToWordArray(vArr)
var k = convert.bytesToWordArray(kArr)
@ -51,83 +48,82 @@ function deterministicGenerateK(hash,key) {
v = HmacSHA256(v,k)
v = HmacSHA256(v,k)
vArr = convert.wordArrayToBytes(v)
return BigInteger.fromByteArrayUnsigned(vArr);
return BigInteger.fromByteArrayUnsigned(vArr)
}
var ECDSA = {
getBigRandom: function (limit) {
return new BigInteger(limit.bitLength(), rng)
.mod(limit.subtract(BigInteger.ONE))
.add(BigInteger.ONE)
;
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 d = priv
var n = ecparams.getN()
var e = BigInteger.fromByteArrayUnsigned(hash)
var k = deterministicGenerateK(hash,priv.toByteArrayUnsigned())
var G = ecparams.getG();
var Q = G.multiply(k);
var r = Q.getX().toBigInteger().mod(n);
var G = ecparams.getG()
var Q = G.multiply(k)
var r = Q.getX().toBigInteger().mod(n)
var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n)
return ECDSA.serializeSig(r, s);
return ECDSA.serializeSig(r, s)
},
verify: function (hash, sig, pubkey) {
var r,s;
var r,s
if (Array.isArray(sig)) {
var obj = ECDSA.parseSig(sig);
r = obj.r;
s = obj.s;
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;
r = sig.r
s = sig.s
} else {
throw new Error("Invalid value for signature");
throw new Error("Invalid value for signature")
}
var Q;
var Q
if (pubkey instanceof ECPointFp) {
Q = pubkey;
Q = pubkey
} else if (Array.isArray(pubkey)) {
Q = ECPointFp.decodeFrom(ecparams.getCurve(), pubkey);
Q = ECPointFp.decodeFrom(ecparams.getCurve(), pubkey)
} else {
throw new Error("Invalid format for pubkey value, must be byte array or ECPointFp");
throw new Error("Invalid format for pubkey value, must be byte array or ECPointFp")
}
var e = BigInteger.fromByteArrayUnsigned(hash);
var e = BigInteger.fromByteArrayUnsigned(hash)
return ECDSA.verifyRaw(e, r, s, Q);
return ECDSA.verifyRaw(e, r, s, Q)
},
verifyRaw: function (e, r, s, Q) {
var n = ecparams.getN();
var G = ecparams.getG();
var n = ecparams.getN()
var G = ecparams.getG()
if (r.compareTo(BigInteger.ONE) < 0 ||
r.compareTo(n) >= 0)
return false;
if (r.compareTo(BigInteger.ONE) < 0 || r.compareTo(n) >= 0) {
return false
}
if (s.compareTo(BigInteger.ONE) < 0 ||
s.compareTo(n) >= 0)
return false;
if (s.compareTo(BigInteger.ONE) < 0 || s.compareTo(n) >= 0) {
return false
}
var c = s.modInverse(n);
var c = s.modInverse(n)
var u1 = e.multiply(c).mod(n);
var u2 = r.multiply(c).mod(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 point = implShamirsTrick(G, u1, Q, u2)
var point = G.multiply(u1).add(Q.multiply(u2))
var v = point.getX().toBigInteger().mod(n);
var v = point.getX().toBigInteger().mod(n)
return v.equals(r);
return v.equals(r)
},
/**
@ -136,22 +132,22 @@ var ECDSA = {
* Takes two BigIntegers representing r and s and returns a byte array.
*/
serializeSig: function (r, s) {
var rBa = r.toByteArraySigned();
var sBa = s.toByteArraySigned();
var rBa = r.toByteArraySigned()
var sBa = s.toByteArraySigned()
var sequence = [];
var sequence = []
sequence.push(0x02); // INTEGER
sequence.push(rBa.length);
sequence = sequence.concat(rBa);
sequence.push(rBa.length)
sequence = sequence.concat(rBa)
sequence.push(0x02); // INTEGER
sequence.push(sBa.length);
sequence = sequence.concat(sBa);
sequence.push(sBa.length)
sequence = sequence.concat(sBa)
sequence.unshift(sequence.length);
sequence.unshift(sequence.length)
sequence.unshift(0x30); // SEQUENCE
return sequence;
return sequence
},
/**
@ -165,48 +161,51 @@ var ECDSA = {
* }
*/
parseSig: function (sig) {
var cursor;
if (sig[0] != 0x30)
throw new Error("Signature not a valid DERSequence");
var cursor
if (sig[0] != 0x30) {
throw new Error("Signature not a valid DERSequence")
}
cursor = 2;
if (sig[cursor] != 0x02)
throw new Error("First element in signature must be a DERInteger");;
var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
cursor = 2
if (sig[cursor] != 0x02) {
throw new Error("First element in signature must be a DERInteger")
}
var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1])
cursor += 2+sig[cursor+1];
if (sig[cursor] != 0x02)
throw new Error("Second element in signature must be a DERInteger");
var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
cursor += 2+sig[cursor+1]
if (sig[cursor] != 0x02) {
throw new Error("Second element in signature must be a DERInteger")
}
var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1])
cursor += 2+sig[cursor+1];
cursor += 2+sig[cursor+1]
//if (cursor != sig.length)
// throw new Error("Extra bytes in signature");
// throw new Error("Extra bytes in signature")
var r = BigInteger.fromByteArrayUnsigned(rBa);
var s = BigInteger.fromByteArrayUnsigned(sBa);
var r = BigInteger.fromByteArrayUnsigned(rBa)
var s = BigInteger.fromByteArrayUnsigned(sBa)
return {r: r, s: s};
return {r: r, s: s}
},
parseSigCompact: function (sig) {
if (sig.length !== 65) {
throw new Error("Signature has the wrong length");
throw new Error("Signature has the wrong length")
}
// Signature is prefixed with a type byte storing three bits of
// information.
var i = sig[0] - 27;
var i = sig[0] - 27
if (i < 0 || i > 7) {
throw new Error("Invalid signature type");
throw new Error("Invalid signature type")
}
var n = ecparams.getN();
var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n);
var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n);
var n = ecparams.getN()
var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n)
var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n)
return {r: r, s: s, i: i};
return {r: r, s: s, i: i}
},
/**
@ -219,57 +218,55 @@ var ECDSA = {
*/
recoverPubKey: function (r, s, hash, i) {
// The recovery parameter i has two bits.
i = i & 3;
i = i & 3
// The less significant bit specifies whether the y coordinate
// of the compressed point is even or not.
var isYEven = i & 1;
var isYEven = i & 1
// The more significant bit specifies whether we should use the
// first or second candidate key.
var isSecondKey = i >> 1;
var isSecondKey = i >> 1
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 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()
// 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));
P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4))
}
// 1.1 Compute x
var x = isSecondKey ? r.add(n) : r;
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 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);
// 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);
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();
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);
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);
var rInv = r.modInverse(n)
var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv)
Q.validate();
Q.validate()
if (!ECDSA.verifyRaw(e, r, s, Q)) {
throw new Error("Pubkey recovery unsuccessful");
throw new Error("Pubkey recovery unsuccessful")
}
return Q
@ -297,6 +294,6 @@ var ECDSA = {
throw new Error("Unable to find valid recovery factor")
}
};
}
module.exports = ECDSA;
module.exports = ECDSA

View file

@ -8,7 +8,6 @@ var ECPointFp = require('./jsbn/ec').ECPointFp
var sec = require('./jsbn/sec')
var Network = require('./network')
var util = require('./util')
var ecparams = sec("secp256k1")
// input can be nothing, array of bytes, hex string, or base58 string
@ -75,7 +74,7 @@ ECKey.version_bytes = {
}
ECKey.prototype.toWif = function(version) {
version = version || Network.mainnet.addressVersion;
version = version || Network.mainnet.addressVersion
return base58.checkEncode(this.toBytes(), ECKey.version_bytes[version])
}
@ -85,7 +84,7 @@ ECKey.prototype.toHex = function() {
}
ECKey.prototype.toBytes = function() {
var bytes = this.priv.toByteArrayUnsigned();
var bytes = this.priv.toByteArrayUnsigned()
if (this.compressed) bytes.push(1)
return bytes
}
@ -109,7 +108,7 @@ ECKey.prototype.multiply = function(key) {
}
ECKey.prototype.sign = function(hash) {
return ecdsa.sign(hash, this.priv);
return ecdsa.sign(hash, this.priv)
}
ECKey.prototype.verify = function(hash, sig) {
@ -166,7 +165,7 @@ ECPubKey.prototype.toBin = function(compressed) {
}
ECPubKey.prototype.toWif = function(version) {
version = version || Network.mainnet.addressVersion;
version = version || Network.mainnet.addressVersion
return base58.checkEncode(this.toBytes(), version)
}
@ -174,9 +173,9 @@ ECPubKey.prototype.toWif = function(version) {
ECPubKey.prototype.toString = ECPubKey.prototype.toHex
ECPubKey.prototype.getAddress = function(version) {
version = version || Network.mainnet.addressVersion;
version = version || Network.mainnet.addressVersion
return new Address(util.sha256ripe160(this.toBytes()), version);
return new Address(util.sha256ripe160(this.toBytes()), version)
}
ECPubKey.prototype.verify = function(hash, sig) {

View file

@ -3,7 +3,7 @@ var base58 = require('./base58.js')
var assert = require('assert')
var format = require('util').format
var util = require('./util.js')
var Crypto = require('crypto-js');
var Crypto = require('crypto-js')
var HmacSHA512 = Crypto.HmacSHA512
var HMAC= Crypto.algo.HMAC
var ECKey = require('./eckey.js').ECKey
@ -12,7 +12,7 @@ var Address = require('./address.js')
var Network = require('./network')
var HDWallet = module.exports = function(seed, network) {
if (seed === undefined) return
if (seed === undefined) return;
var seedWords = convert.bytesToWordArray(seed)
var I = convert.wordArrayToBytes(HmacSHA512(seedWords, 'Bitcoin seed'))
@ -35,7 +35,7 @@ function arrayEqual(a, b) {
return !(a < b || a > b)
}
HDWallet.getChecksum = base58.getChecksum;
HDWallet.getChecksum = base58.getChecksum
HDWallet.fromSeedHex = function(hex, network) {
return new HDWallet(convert.hexToBytes(hex), network)
@ -73,7 +73,7 @@ HDWallet.fromBytes = function(input) {
var hd = new HDWallet()
// 4 byte: version bytes (mainnet: 0x0488B21E public, 0x0488ADE4 private;
// 4 byte: version bytes (mainnet: 0x0488B21E public, 0x0488ADE4 private
// testnet: 0x043587CF public, 0x04358394 private)
var versionBytes = input.slice(0, 4)
var versionWord = convert.bytesToWords(versionBytes)[0]

View file

@ -1,4 +1,5 @@
var Key = require('./eckey');
var Key = require('./eckey')
var T = require('./transaction')
module.exports = {
Address: require('./address'),
@ -10,20 +11,15 @@ module.exports = {
Crypto: require('crypto-js'), //should we expose this at all?
Script: require('./script'),
Opcode: require('./opcode'),
Transaction: require('./transaction').Transaction,
Transaction: T.Transaction,
Util: require('./util'),
TransactionIn: require('./transaction').TransactionIn,
TransactionOut: require('./transaction').TransactionOut,
TransactionIn: T.TransactionIn,
TransactionOut: T.TransactionOut,
ECPointFp: require('./jsbn/ec').ECPointFp,
Wallet: require('./wallet'),
network: require('./network'),
ecdsa: require('./ecdsa'),
HDWallet: require('./hdwallet.js'),
// base58 encoding/decoding to bytes
base58: require('./base58'),
// conversions
convert: require('./convert')
}

View file

@ -38,8 +38,8 @@ function sign(key, message) {
var sBa = obj.s.toByteArrayUnsigned()
// Pad to 32 bytes per value
while (rBa.length < 32) rBa.unshift(0)
while (sBa.length < 32) sBa.unshift(0)
while (rBa.length < 32) rBa.unshift(0);
while (sBa.length < 32) sBa.unshift(0);
sig = [i].concat(rBa, sBa)

View file

@ -15,5 +15,5 @@ module.exports = {
priv: 0x04358394
}
}
};
}

View file

@ -144,4 +144,4 @@ for(var i in Opcode.map) {
Opcode.reverseMap[Opcode.map[i]] = i
}
module.exports = Opcode;
module.exports = Opcode

View file

@ -1,46 +1,46 @@
var Opcode = require('./opcode');
var util = require('./util');
var convert = require('./convert');
var Address = require('./address');
var network = require('./network');
var Opcode = require('./opcode')
var util = require('./util')
var convert = require('./convert')
var Address = require('./address')
var network = require('./network')
var Script = function(data) {
this.buffer = data || [];
this.buffer = data || []
if(!Array.isArray(this.buffer)) {
throw new Error('expect Script to be initialized with Array, but got ' + data)
}
this.parse();
};
this.parse()
}
Script.fromHex = function(data) {
return new Script(convert.hexToBytes(data))
};
}
Script.fromPubKey = function(str) {
var script = new Script();
var s = str.split(' ');
var script = new Script()
var s = str.split(' ')
for (var i in s) {
if (Opcode.map.hasOwnProperty(s[i])) {
script.writeOp(Opcode.map[s[i]]);
script.writeOp(Opcode.map[s[i]])
} else {
script.writeBytes(convert.hexToBytes(s[i]));
script.writeBytes(convert.hexToBytes(s[i]))
}
}
return script;
};
return script
}
Script.fromScriptSig = function(str) {
var script = new Script();
var s = str.split(' ');
var script = new Script()
var s = str.split(' ')
for (var i in s) {
if (Opcode.map.hasOwnProperty(s[i])) {
script.writeOp(Opcode.map[s[i]]);
script.writeOp(Opcode.map[s[i]])
} else {
script.writeBytes(convert.hexToBytes(s[i]));
script.writeBytes(convert.hexToBytes(s[i]))
}
}
return script;
};
return script
}
/**
* Update the parsed script representation.
@ -54,47 +54,47 @@ Script.fromScriptSig = function(str) {
* the script buffer manually, you should update the chunks using this method.
*/
Script.prototype.parse = function() {
var self = this;
var self = this
this.chunks = [];
this.chunks = []
// Cursor
var i = 0;
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;
self.chunks.push(self.buffer.slice(i, i + n))
i += n
}
while (i < this.buffer.length) {
var opcode = this.buffer[i++];
var opcode = this.buffer[i++]
if (opcode >= 0xF0) {
// Two byte opcode
opcode = (opcode << 8) | this.buffer[i++];
opcode = (opcode << 8) | this.buffer[i++]
}
var len;
var len
if (opcode > 0 && opcode < Opcode.map.OP_PUSHDATA1) {
// Read some bytes of data, opcode value is the length of data
readChunk(opcode);
readChunk(opcode)
} else if (opcode == Opcode.map.OP_PUSHDATA1) {
len = this.buffer[i++];
readChunk(len);
len = this.buffer[i++]
readChunk(len)
} else if (opcode == Opcode.map.OP_PUSHDATA2) {
len = (this.buffer[i++] << 8) | this.buffer[i++];
readChunk(len);
len = (this.buffer[i++] << 8) | this.buffer[i++]
readChunk(len)
} else if (opcode == Opcode.map.OP_PUSHDATA4) {
len = (this.buffer[i++] << 24) |
(this.buffer[i++] << 16) |
(this.buffer[i++] << 8) |
this.buffer[i++];
readChunk(len);
this.buffer[i++]
readChunk(len)
} else {
this.chunks.push(opcode);
this.chunks.push(opcode)
}
}
};
}
/**
* Compare the script to known templates of scriptPubKey.
@ -119,16 +119,16 @@ Script.prototype.getOutType = function() {
this.chunks[0] == Opcode.map.OP_HASH160 &&
this.chunks.length == 3) {
// Transfer to M-OF-N
return 'P2SH';
return 'P2SH'
} else if (this.chunks.length == 5 &&
this.chunks[0] == Opcode.map.OP_DUP &&
this.chunks[1] == Opcode.map.OP_HASH160 &&
this.chunks[3] == Opcode.map.OP_EQUALVERIFY &&
this.chunks[4] == Opcode.map.OP_CHECKSIG) {
// Transfer to Bitcoin address
return 'Pubkey';
return 'Pubkey'
} else {
return 'Strange';
return 'Strange'
}
}
@ -137,7 +137,7 @@ Script.prototype.getOutType = function() {
* Assumes strange scripts are P2SH
*/
Script.prototype.toScriptHash = function() {
var outType = this.getOutType();
var outType = this.getOutType()
if (outType == 'Pubkey') {
return this.chunks[2]
@ -152,7 +152,7 @@ Script.prototype.toScriptHash = function() {
//TODO: support testnet
Script.prototype.getToAddress = function() {
var outType = this.getOutType();
var outType = this.getOutType()
if (outType == 'Pubkey') {
return new Address(this.chunks[2])
@ -167,7 +167,7 @@ Script.prototype.getToAddress = function() {
//TODO: support testnet
Script.prototype.getFromAddress = function(){
return new Address(this.simpleInHash());
return new Address(this.simpleInHash())
}
/**
@ -200,20 +200,20 @@ Script.prototype.getInType = function() {
Array.isArray(this.chunks[0])) {
// Direct IP to IP transactions only have the signature in their scriptSig.
// TODO: We could also check that the length of the data is correct.
return 'Pubkey';
return 'Pubkey'
} else if (this.chunks.length == 2 &&
Array.isArray(this.chunks[0]) &&
Array.isArray(this.chunks[1])) {
return 'Address';
return 'Address'
} else if (this.chunks[0] == Opcode.map.OP_0 &&
this.chunks.slice(1).reduce(function(t, chunk, i) {
return t && Array.isArray(chunk) && (chunk[0] == 48 || i == this.chunks.length - 1);
return t && Array.isArray(chunk) && (chunk[0] == 48 || i == this.chunks.length - 1)
}, true)) {
return 'Multisig';
return 'Multisig'
} else {
return 'Strange';
return 'Strange'
}
};
}
/**
* Returns the affected public key for this input.
@ -231,15 +231,15 @@ Script.prototype.getInType = function() {
Script.prototype.simpleInPubKey = function() {
switch (this.getInType()) {
case 'Address':
return this.chunks[1];
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');
throw new Error('Script does not contain pubkey')
default:
throw new Error('Encountered non-standard scriptSig');
throw new Error('Encountered non-standard scriptSig')
}
};
}
/**
* Returns the affected address hash for this input.
@ -257,70 +257,71 @@ Script.prototype.simpleInPubKey = function() {
* This method is useful for indexing transactions.
*/
Script.prototype.simpleInHash = function() {
return util.sha256ripe160(this.simpleInPubKey());
};
return util.sha256ripe160(this.simpleInPubKey())
}
/**
* Old name for Script#simpleInHash.
*
* @deprecated
*/
Script.prototype.simpleInPubKeyHash = Script.prototype.simpleInHash;
Script.prototype.simpleInPubKeyHash = Script.prototype.simpleInHash
/**
* Add an op code to the script.
*/
Script.prototype.writeOp = function(opcode) {
this.buffer.push(opcode);
this.chunks.push(opcode);
};
this.buffer.push(opcode)
this.chunks.push(opcode)
}
/**
* Add a data chunk to the script.
*/
Script.prototype.writeBytes = function(data) {
if (data.length < Opcode.map.OP_PUSHDATA1) {
this.buffer.push(data.length);
this.buffer.push(data.length)
} else if (data.length <= 0xff) {
this.buffer.push(Opcode.map.OP_PUSHDATA1);
this.buffer.push(data.length);
this.buffer.push(Opcode.map.OP_PUSHDATA1)
this.buffer.push(data.length)
} else if (data.length <= 0xffff) {
this.buffer.push(Opcode.map.OP_PUSHDATA2);
this.buffer.push(data.length & 0xff);
this.buffer.push((data.length >>> 8) & 0xff);
this.buffer.push(Opcode.map.OP_PUSHDATA2)
this.buffer.push(data.length & 0xff)
this.buffer.push((data.length >>> 8) & 0xff)
} else {
this.buffer.push(Opcode.map.OP_PUSHDATA4);
this.buffer.push(data.length & 0xff);
this.buffer.push((data.length >>> 8) & 0xff);
this.buffer.push((data.length >>> 16) & 0xff);
this.buffer.push((data.length >>> 24) & 0xff);
this.buffer.push(Opcode.map.OP_PUSHDATA4)
this.buffer.push(data.length & 0xff)
this.buffer.push((data.length >>> 8) & 0xff)
this.buffer.push((data.length >>> 16) & 0xff)
this.buffer.push((data.length >>> 24) & 0xff)
}
this.buffer = this.buffer.concat(data);
this.chunks.push(data);
};
this.buffer = this.buffer.concat(data)
this.chunks.push(data)
}
/**
* Create an output for an address
*/
Script.createOutputScript = function(address) {
var script = new Script();
address = new Address(address);
if (address.version == network.mainnet.p2shVersion || address.version == network.testnet.p2shVersion) {
var script = new Script()
address = new Address(address)
if (address.version == network.mainnet.p2shVersion ||
address.version == network.testnet.p2shVersion) {
// Standard pay-to-script-hash
script.writeOp(Opcode.map.OP_HASH160);
script.writeBytes(address.hash);
script.writeOp(Opcode.map.OP_EQUAL);
script.writeOp(Opcode.map.OP_HASH160)
script.writeBytes(address.hash)
script.writeOp(Opcode.map.OP_EQUAL)
}
else {
// Standard pay-to-pubkey-hash
script.writeOp(Opcode.map.OP_DUP);
script.writeOp(Opcode.map.OP_HASH160);
script.writeBytes(address.hash);
script.writeOp(Opcode.map.OP_EQUALVERIFY);
script.writeOp(Opcode.map.OP_CHECKSIG);
script.writeOp(Opcode.map.OP_DUP)
script.writeOp(Opcode.map.OP_HASH160)
script.writeBytes(address.hash)
script.writeOp(Opcode.map.OP_EQUALVERIFY)
script.writeOp(Opcode.map.OP_CHECKSIG)
}
return script;
};
return script
}
/**
* Extract pubkeys from a multisig script
@ -329,61 +330,57 @@ Script.createOutputScript = function(address) {
Script.prototype.extractPubkeys = function() {
return this.chunks.filter(function(chunk) {
return(chunk[0] == 4 && chunk.length == 65 || chunk[0] < 4 && chunk.length == 33)
});
})
}
/**
* Create an m-of-n output script
*/
Script.createMultiSigOutputScript = function(m, pubkeys) {
var script = new Script();
pubkeys = pubkeys.sort();
script.writeOp(Opcode.map.OP_1 + m - 1);
var script = new Script()
pubkeys = pubkeys.sort()
script.writeOp(Opcode.map.OP_1 + m - 1)
for (var i = 0; i < pubkeys.length; ++i) {
script.writeBytes(pubkeys[i]);
script.writeBytes(pubkeys[i])
}
script.writeOp(Opcode.map.OP_1 + pubkeys.length - 1)
script.writeOp(Opcode.map.OP_CHECKMULTISIG)
script.writeOp(Opcode.map.OP_1 + pubkeys.length - 1);
script.writeOp(Opcode.map.OP_CHECKMULTISIG);
return script;
};
return script
}
/**
* Create a standard payToPubKeyHash input.
*/
Script.createInputScript = function(signature, pubKey) {
var script = new Script();
script.writeBytes(signature);
script.writeBytes(pubKey);
return script;
};
var script = new Script()
script.writeBytes(signature)
script.writeBytes(pubKey)
return script
}
/**
* Create a multisig input
*/
Script.createMultiSigInputScript = function(signatures, script) {
script = new Script(script);
var k = script.chunks[0][0];
script = new Script(script)
var k = script.chunks[0][0]
//Not enough sigs
if (signatures.length < k) return false;
var inScript = new Script();
inScript.writeOp(Opcode.map.OP_0);
var inScript = new Script()
inScript.writeOp(Opcode.map.OP_0)
signatures.map(function(sig) {
inScript.writeBytes(sig)
});
inScript.writeBytes(script.buffer);
return inScript;
})
inScript.writeBytes(script.buffer)
return inScript
}
Script.prototype.clone = function() {
return new Script(this.buffer);
};
return new Script(this.buffer)
}
module.exports = Script;
module.exports = Script

View file

@ -1,23 +1,23 @@
var BigInteger = require('./jsbn/jsbn');
var Script = require('./script');
var util = require('./util');
var convert = require('./convert');
var ECKey = require('./eckey').ECKey;
var ECDSA = require('./ecdsa');
var Address = require('./address');
var SHA256 = require('crypto-js/sha256');
var BigInteger = require('./jsbn/jsbn')
var Script = require('./script')
var util = require('./util')
var convert = require('./convert')
var ECKey = require('./eckey').ECKey
var ECDSA = require('./ecdsa')
var Address = require('./address')
var SHA256 = require('crypto-js/sha256')
var Transaction = function (doc) {
if (!(this instanceof Transaction)) { return new Transaction(doc); }
this.version = 1;
this.locktime = 0;
this.ins = [];
this.outs = [];
this.defaultSequence = [255, 255, 255, 255]; // 0xFFFFFFFF
if (!(this instanceof Transaction)) { return new Transaction(doc) }
this.version = 1
this.locktime = 0
this.ins = []
this.outs = []
this.defaultSequence = [255, 255, 255, 255] // 0xFFFFFFFF
if (doc) {
if (typeof doc == "string" || Array.isArray(doc)) {
doc = Transaction.deserialize(doc);
doc = Transaction.deserialize(doc)
}
if (doc.hash) this.hash = doc.hash;
@ -25,19 +25,19 @@ var Transaction = function (doc) {
if (doc.locktime) this.locktime = doc.locktime;
if (doc.ins && doc.ins.length) {
doc.ins.forEach(function(input) {
this.addInput(new TransactionIn(input));
}, this);
this.addInput(new TransactionIn(input))
}, this)
}
if (doc.outs && doc.outs.length) {
doc.outs.forEach(function(output) {
this.addOutput(new TransactionOut(output));
}, this);
this.addOutput(new TransactionOut(output))
}, this)
}
this.hash = this.hash || this.getHash();
this.hash = this.hash || this.getHash()
}
};
}
/**
* Create a new txin.
@ -53,15 +53,15 @@ var Transaction = function (doc) {
*/
Transaction.prototype.addInput = function (tx, outIndex) {
if (arguments[0] instanceof TransactionIn) {
this.ins.push(arguments[0]);
this.ins.push(arguments[0])
}
else if (arguments[0].length > 65) {
var args = arguments[0].split(':');
return this.addInput(args[0], args[1]);
var args = arguments[0].split(':')
return this.addInput(args[0], args[1])
}
else {
var hash = typeof tx === "string" ? tx : tx.hash;
hash = Array.isArray(hash) ? convert.bytesToHex(hash) : hash;
var hash = typeof tx === "string" ? tx : tx.hash
hash = Array.isArray(hash) ? convert.bytesToHex(hash) : hash
this.ins.push(new TransactionIn({
outpoint: {
@ -70,9 +70,9 @@ Transaction.prototype.addInput = function (tx, outIndex) {
},
script: new Script(),
sequence: this.defaultSequence
}));
}))
}
};
}
/**
* Create a new txout.
@ -86,21 +86,21 @@ Transaction.prototype.addInput = function (tx, outIndex) {
*/
Transaction.prototype.addOutput = function (address, value) {
if (arguments[0] instanceof TransactionOut) {
this.outs.push(arguments[0]);
return;
this.outs.push(arguments[0])
return
}
if (arguments[0].indexOf(':') >= 0) {
var args = arguments[0].split(':');
address = args[0];
value = parseInt(args[1]);
var args = arguments[0].split(':')
address = args[0]
value = parseInt(args[1])
}
this.outs.push(new TransactionOut({
value: value,
script: Script.createOutputScript(address)
}));
};
}))
}
/**
* Serialize this transaction.
@ -110,48 +110,48 @@ Transaction.prototype.addOutput = function (address, value) {
* be hashed to get the transaction's standard Bitcoin hash.
*/
Transaction.prototype.serialize = function () {
var buffer = [];
buffer = buffer.concat(convert.numToBytes(parseInt(this.version), 4));
buffer = buffer.concat(convert.numToVarInt(this.ins.length));
var buffer = []
buffer = buffer.concat(convert.numToBytes(parseInt(this.version), 4))
buffer = buffer.concat(convert.numToVarInt(this.ins.length))
this.ins.forEach(function(txin) {
// Why do blockchain.info, blockexplorer.com, sx and just about everybody
// else use little-endian hashes? No idea...
buffer = buffer.concat(convert.hexToBytes(txin.outpoint.hash).reverse());
buffer = buffer.concat(convert.hexToBytes(txin.outpoint.hash).reverse())
buffer = buffer.concat(convert.numToBytes(parseInt(txin.outpoint.index), 4));
buffer = buffer.concat(convert.numToBytes(parseInt(txin.outpoint.index), 4))
var scriptBytes = txin.script.buffer;
buffer = buffer.concat(convert.numToVarInt(scriptBytes.length));
buffer = buffer.concat(scriptBytes);
buffer = buffer.concat(txin.sequence);
});
var scriptBytes = txin.script.buffer
buffer = buffer.concat(convert.numToVarInt(scriptBytes.length))
buffer = buffer.concat(scriptBytes)
buffer = buffer.concat(txin.sequence)
})
buffer = buffer.concat(convert.numToVarInt(this.outs.length));
buffer = buffer.concat(convert.numToVarInt(this.outs.length))
this.outs.forEach(function(txout) {
buffer = buffer.concat(convert.numToBytes(txout.value,8));
buffer = buffer.concat(convert.numToBytes(txout.value,8))
var scriptBytes = txout.script.buffer;
buffer = buffer.concat(convert.numToVarInt(scriptBytes.length));
buffer = buffer.concat(scriptBytes);
});
var scriptBytes = txout.script.buffer
buffer = buffer.concat(convert.numToVarInt(scriptBytes.length))
buffer = buffer.concat(scriptBytes)
})
buffer = buffer.concat(convert.numToBytes(parseInt(this.locktime), 4));
buffer = buffer.concat(convert.numToBytes(parseInt(this.locktime), 4))
return buffer;
};
Transaction.prototype.serializeHex = function() {
return convert.bytesToHex(this.serialize());
return buffer
}
//var OP_CODESEPARATOR = 171;
Transaction.prototype.serializeHex = function() {
return convert.bytesToHex(this.serialize())
}
var SIGHASH_ALL = 1;
var SIGHASH_NONE = 2;
var SIGHASH_SINGLE = 3;
var SIGHASH_ANYONECANPAY = 80;
//var OP_CODESEPARATOR = 171
var SIGHASH_ALL = 1
var SIGHASH_NONE = 2
var SIGHASH_SINGLE = 3
var SIGHASH_ANYONECANPAY = 80
/**
* Hash transaction for signing a specific input.
@ -162,34 +162,34 @@ var SIGHASH_ANYONECANPAY = 80;
* used to sign the transaction input in question.
*/
Transaction.prototype.hashTransactionForSignature =
function (connectedScript, inIndex, hashType)
function (connectedScript, inIndex, hashType)
{
var txTmp = this.clone();
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;
return val !== OP_CODESEPARATOR
});*/
// Blank out other inputs' signatures
txTmp.ins.forEach(function(txin) {
txin.script = new Script();
});
txin.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 = [];
txTmp.outs = []
// Let the others update at will
txTmp.ins.forEach(function(txin, i) {
if (i != inIndex) {
txTmp.ins[i].sequence = 0;
txTmp.ins[i].sequence = 0
}
});
})
} else if ((hashType & 0x1f) == SIGHASH_SINGLE) {
// TODO: Implement
@ -197,16 +197,16 @@ function (connectedScript, inIndex, hashType)
// Blank out other inputs completely, not recommended for open transactions
if (hashType & SIGHASH_ANYONECANPAY) {
txTmp.ins = [txTmp.ins[inIndex]];
txTmp.ins = [txTmp.ins[inIndex]]
}
var buffer = txTmp.serialize();
var buffer = txTmp.serialize()
buffer = buffer.concat(convert.numToBytes(parseInt(hashType), 4));
buffer = convert.bytesToWordArray(buffer);
buffer = buffer.concat(convert.numToBytes(parseInt(hashType), 4))
buffer = convert.bytesToWordArray(buffer)
return convert.wordArrayToBytes(SHA256(SHA256(buffer)));
};
return convert.wordArrayToBytes(SHA256(SHA256(buffer)))
}
/**
* Calculate and return the transaction's hash.
@ -215,43 +215,36 @@ function (connectedScript, inIndex, hashType)
*/
Transaction.prototype.getHash = function ()
{
var buffer = convert.bytesToWordArray(this.serialize());
return convert.wordArrayToBytes(SHA256(SHA256(buffer))).reverse();
};
var buffer = convert.bytesToWordArray(this.serialize())
return convert.wordArrayToBytes(SHA256(SHA256(buffer))).reverse()
}
/**
* Create a copy of this transaction object.
*/
Transaction.prototype.clone = function ()
{
var newTx = new Transaction();
newTx.version = this.version;
newTx.locktime = this.locktime;
var newTx = new Transaction()
newTx.version = this.version
newTx.locktime = this.locktime
this.ins.forEach(function(txin) {
newTx.addInput(txin.clone());
});
newTx.addInput(txin.clone())
})
this.outs.forEach(function(txout) {
newTx.addOutput(txout.clone());
});
newTx.addOutput(txout.clone())
})
return newTx;
};
/**
* Converts a serialized transaction into a transaction object
*/
return newTx
}
Transaction.deserialize = function(buffer) {
if (typeof buffer == "string") {
buffer = convert.hexToBytes(buffer)
}
var pos = 0;
var pos = 0
var readAsInt = function(bytes) {
if (bytes === 0) return 0;
pos++;
return buffer[pos-1] + readAsInt(bytes-1) * 256;
return buffer[pos-1] + readAsInt(bytes-1) * 256
}
var readVarInt = function() {
var bytes = buffer.slice(pos, pos + 9) // maximum possible number of bytes to read
@ -261,20 +254,20 @@ Transaction.deserialize = function(buffer) {
return result.number
}
var readBytes = function(bytes) {
pos += bytes;
return buffer.slice(pos - bytes, pos);
pos += bytes
return buffer.slice(pos - bytes, pos)
}
var readVarString = function() {
var size = readVarInt();
return readBytes(size);
var size = readVarInt()
return readBytes(size)
}
var obj = {
ins: [],
outs: []
}
obj.version = readAsInt(4);
var ins = readVarInt();
var i;
obj.version = readAsInt(4)
var ins = readVarInt()
var i
for (i = 0; i < ins; i++) {
obj.ins.push({
@ -284,29 +277,28 @@ Transaction.deserialize = function(buffer) {
},
script: new Script(readVarString()),
sequence: readBytes(4)
});
})
}
var outs = readVarInt();
var outs = readVarInt()
for (i = 0; i < outs; i++) {
obj.outs.push({
value: convert.bytesToNum(readBytes(8)),
script: new Script(readVarString())
});
})
}
obj.locktime = readAsInt(4);
obj.locktime = readAsInt(4)
return new Transaction(obj);
return new Transaction(obj)
}
/**
* Signs a standard output at some index with the given key
*/
Transaction.prototype.sign = function(index, key, type) {
type = type || SIGHASH_ALL;
key = new ECKey(key);
type = type || SIGHASH_ALL
key = new ECKey(key)
// TODO: getPub is slow, sha256ripe160 probably is too.
// This could be sped up a lot by providing these as inputs.
@ -314,67 +306,66 @@ Transaction.prototype.sign = function(index, key, type) {
hash160 = util.sha256ripe160(pub),
script = Script.createOutputScript(new Address(hash160)),
hash = this.hashTransactionForSignature(script, index, type),
sig = key.sign(hash).concat([type]);
this.ins[index].script = Script.createInputScript(sig, pub);
sig = key.sign(hash).concat([type])
this.ins[index].script = Script.createInputScript(sig, pub)
}
// Takes outputs of the form [{ output: 'txhash:index', address: 'address' },...]
Transaction.prototype.signWithKeys = function(keys, outputs, type) {
type = type || SIGHASH_ALL;
type = type || SIGHASH_ALL
var addrdata = keys.map(function(key) {
key = new ECKey(key);
key = new ECKey(key)
return {
key: key,
address: key.getAddress().toString()
}
});
})
var hmap = {};
var hmap = {}
outputs.forEach(function(o) {
hmap[o.output] = o;
});
hmap[o.output] = o
})
for (var i = 0; i < this.ins.length; i++) {
var outpoint = this.ins[i].outpoint.hash + ':' + this.ins[i].outpoint.index;
var histItem = hmap[outpoint];
var outpoint = this.ins[i].outpoint.hash + ':' + this.ins[i].outpoint.index
var histItem = hmap[outpoint]
if (!histItem) continue;
var thisInputAddrdata = addrdata.filter(function(a) {
return a.address == histItem.address;
});
return a.address == histItem.address
})
if (thisInputAddrdata.length === 0) continue;
this.sign(i,thisInputAddrdata[0].key);
this.sign(i,thisInputAddrdata[0].key)
}
}
/**
* Signs a P2SH output at some index with the given key
*/
Transaction.prototype.p2shsign = function(index, script, key, type) {
script = new Script(script);
key = new ECKey(key);
type = type || SIGHASH_ALL;
script = new Script(script)
key = new ECKey(key)
type = type || SIGHASH_ALL
var hash = this.hashTransactionForSignature(script, index, type),
sig = key.sign(hash).concat([type]);
return sig;
sig = key.sign(hash).concat([type])
return sig
}
Transaction.prototype.multisign = Transaction.prototype.p2shsign;
Transaction.prototype.multisign = Transaction.prototype.p2shsign
Transaction.prototype.applyMultisigs = function(index, script, sigs/*, type*/) {
this.ins[index].script = Script.createMultiSigInputScript(sigs, script);
this.ins[index].script = Script.createMultiSigInputScript(sigs, script)
}
Transaction.prototype.validateSig = function(index, script, sig, pub) {
script = new Script(script);
var hash = this.hashTransactionForSignature(script,index,1);
script = new Script(script)
var hash = this.hashTransactionForSignature(script,index,1)
return ECDSA.verify(hash, convert.coerceToBytes(sig),
convert.coerceToBytes(pub));
convert.coerceToBytes(pub))
}
Transaction.feePerKb = 20000
@ -383,29 +374,31 @@ Transaction.prototype.estimateFee = function(feePerKb){
var outSize = 34
var fixedPadding = 34
if(feePerKb == undefined) feePerKb = Transaction.feePerKb
if(feePerKb == undefined) feePerKb = Transaction.feePerKb;
var size = this.ins.length * uncompressedInSize + this.outs.length * outSize + fixedPadding
return feePerKb * Math.ceil(size / 1000)
}
var TransactionIn = function (data) {
if (typeof data == "string")
if (typeof data == "string") {
this.outpoint = { hash: data.split(':')[0], index: data.split(':')[1] }
else if (data.outpoint)
} else if (data.outpoint) {
this.outpoint = data.outpoint
else
} else {
this.outpoint = { hash: data.hash, index: data.index }
}
if (data.scriptSig)
if (data.scriptSig) {
this.script = Script.fromScriptSig(data.scriptSig)
else if (data.script)
} else if (data.script) {
this.script = data.script
else
} else {
this.script = new Script(data.script)
}
this.sequence = data.sequence || this.defaultSequence
};
}
TransactionIn.prototype.clone = function () {
return new TransactionIn({
@ -415,8 +408,8 @@ TransactionIn.prototype.clone = function () {
},
script: this.script.clone(),
sequence: this.sequence
});
};
})
}
var TransactionOut = function (data) {
this.script =
@ -425,7 +418,7 @@ var TransactionOut = function (data) {
: typeof data.script == "string" ? new Script(convert.hexToBytes(data.script))
: data.scriptPubKey ? Script.fromScriptSig(data.scriptPubKey)
: data.address ? Script.createOutputScript(data.address)
: new Script();
: new Script()
if (this.script.buffer.length > 0) this.address = this.script.getToAddress();
@ -433,16 +426,16 @@ var TransactionOut = function (data) {
Array.isArray(data.value) ? convert.bytesToNum(data.value)
: "string" == typeof data.value ? parseInt(data.value)
: data.value instanceof BigInteger ? parseInt(data.value.toString())
: data.value;
};
: data.value
}
TransactionOut.prototype.clone = function() {
var newTxout = new TransactionOut({
script: this.script.clone(),
value: this.value
});
return newTxout;
};
})
return newTxout
}
TransactionOut.prototype.scriptPubKey = function() {
return convert.bytesToHex(this.script.buffer)

View file

@ -3,21 +3,11 @@ var Crypto = require('crypto-js')
var RIPEMD160 = Crypto.RIPEMD160
var SHA256 = Crypto.SHA256
/**
* Calculate RIPEMD160(SHA256(data)).
*
* Takes an arbitrary byte array as inputs and returns the hash as a byte
* array.
*/
exports.sha256ripe160 = function (data) {
var wordArray = RIPEMD160(SHA256(convert.bytesToWordArray(data)))
return convert.wordArrayToBytes(wordArray)
}
/**
* Convenience method for throw new Error('some message'), e.g.
* error('something went wrong')
*/
exports.error = function (msg) {
throw new Error(msg)
}

View file

@ -1,7 +1,7 @@
var convert = require('./convert');
var Transaction = require('./transaction').Transaction;
var convert = require('./convert')
var Transaction = require('./transaction').Transaction
var HDNode = require('./hdwallet.js')
var rng = require('secure-random');
var rng = require('secure-random')
var Wallet = function (seed, options) {
if (!(this instanceof Wallet)) { return new Wallet(seed, options); }
@ -10,23 +10,23 @@ var Wallet = function (seed, options) {
var network = options.network || 'mainnet'
// Stored in a closure to make accidental serialization less likely
var masterkey = null;
var me = this;
var accountZero = null;
var internalAccount = null;
var externalAccount = null;
var masterkey = null
var me = this
var accountZero = null
var internalAccount = null
var externalAccount = null
// Addresses
this.addresses = [];
this.changeAddresses = [];
this.addresses = []
this.changeAddresses = []
// Transaction output data
this.outputs = {};
this.outputs = {}
// Make a new master key
this.newMasterKey = function(seed, network) {
if (!seed) seed= rng(32, { array: true })
masterkey = new HDNode(seed, network);
if (!seed) seed = rng(32, { array: true });
masterkey = new HDNode(seed, network)
// HD first-level child derivation method should be private
// See https://bitcointalk.org/index.php?topic=405179.msg4415254#msg4415254
@ -34,10 +34,10 @@ var Wallet = function (seed, options) {
externalAccount = accountZero.derive(0)
internalAccount = accountZero.derive(1)
me.addresses = [];
me.changeAddresses = [];
me.addresses = []
me.changeAddresses = []
me.outputs = {};
me.outputs = {}
}
this.newMasterKey(seed, network)
@ -117,7 +117,7 @@ var Wallet = function (seed, options) {
}
function validateUnspentOutput(uo) {
var missingField;
var missingField
if(isNullOrUndefined(uo.hash) && isNullOrUndefined(uo.hashLittleEndian)){
missingField = "hash(or hashLittleEndian)"
@ -182,16 +182,16 @@ var Wallet = function (seed, options) {
tx.addInput(output.receive)
totalInValue += output.value
if(totalInValue < value) continue;
if(totalInValue < value) continue
var fee = fixedFee == undefined ? estimateFeePadChangeOutput(tx) : fixedFee
if(totalInValue < value + fee) continue;
if(totalInValue < value + fee) continue
var change = totalInValue - value - fee
if(change > 0 && !isDust(change)) {
tx.addOutput(getChangeAddress(), change)
}
break;
break
}
checkInsufficientFund(totalInValue, value, fee)
@ -240,7 +240,7 @@ var Wallet = function (seed, options) {
return o2.value - o1.value
})
return sortByValueDesc;
return sortByValueDesc
}
function estimateFeePadChangeOutput(tx){
@ -250,7 +250,7 @@ var Wallet = function (seed, options) {
}
function getChangeAddress() {
if(me.changeAddresses.length === 0) me.generateChangeAddress()
if(me.changeAddresses.length === 0) me.generateChangeAddress();
return me.changeAddresses[me.changeAddresses.length - 1]
}
@ -263,12 +263,12 @@ var Wallet = function (seed, options) {
this.sign = function(tx) {
tx.ins.forEach(function(inp,i) {
var output = me.outputs[inp.outpoint.hash+':'+inp.outpoint.index]
var output = me.outputs[inp.outpoint.hash + ':' + inp.outpoint.index]
if (output) {
tx.sign(i, me.getPrivateKeyForAddress(output.address))
}
})
return tx;
return tx
}
this.getMasterKey = function() { return masterkey }
@ -285,7 +285,7 @@ var Wallet = function (seed, options) {
}
this.getPrivateKeyForAddress = function(address) {
var index;
var index
if((index = this.addresses.indexOf(address)) > -1) {
return this.getPrivateKey(index)
} else if((index = this.changeAddresses.indexOf(address)) > -1) {
@ -306,6 +306,6 @@ var Wallet = function (seed, options) {
function isMyAddress(address) {
return isReceiveAddress(address) || isChangeAddress(address)
}
};
}
module.exports = Wallet;
module.exports = Wallet

View file

@ -1,4 +1,3 @@
/* global describe, it */
var assert = require('assert')
var Address = require('../src/address.js')
var network = require('../src/network.js')
@ -7,7 +6,7 @@ var mainnet = network.mainnet.addressVersion
var testnet = network.testnet.addressVersion
describe('Address', function() {
var testnetAddress, mainnetAddress;
var testnetAddress, mainnetAddress
var testnetP2shAddress, mainnetP2shAddress
beforeEach(function(){
@ -64,8 +63,8 @@ describe('Address', function() {
describe('toString', function() {
it('defaults to base58', function() {
var addr = '18fN1QTGWmHWCA9r2dyDH6FbMEyc7XHmQQ';
assert.equal((new Address(addr)).toString(), addr);
var addr = '18fN1QTGWmHWCA9r2dyDH6FbMEyc7XHmQQ'
assert.equal((new Address(addr)).toString(), addr)
})
})
@ -81,25 +80,25 @@ describe('Address', function() {
describe('validate', function() {
it('validates known good addresses', function() {
function validate(addr, expectedVersion) {
assert.ok(Address.validate(addr));
assert.ok(Address.validate(addr))
}
validate(testnetAddress);
validate(mainnetAddress);
validate('12KYrjTdVGjFMtaxERSk3gphreJ5US8aUP');
validate('12QeMLzSrB8XH8FvEzPMVoRxVAzTr5XM2y');
validate('1oNLrsHnBcR6dpaBpwz3LSwutbUNkNSjs');
validate('1SQHtwR5oJRKLfiWQ2APsAd9miUc4k2ez');
validate('116CGDLddrZhMrTwhCVJXtXQpxygTT1kHd');
validate(testnetAddress)
validate(mainnetAddress)
validate('12KYrjTdVGjFMtaxERSk3gphreJ5US8aUP')
validate('12QeMLzSrB8XH8FvEzPMVoRxVAzTr5XM2y')
validate('1oNLrsHnBcR6dpaBpwz3LSwutbUNkNSjs')
validate('1SQHtwR5oJRKLfiWQ2APsAd9miUc4k2ez')
validate('116CGDLddrZhMrTwhCVJXtXQpxygTT1kHd')
// p2sh addresses
validate(testnetP2shAddress);
validate(mainnetP2shAddress);
validate(testnetP2shAddress)
validate(mainnetP2shAddress)
})
it('does not validate illegal examples', function() {
function invalid(addr) {
assert.ok(!Address.validate(addr));
assert.ok(!Address.validate(addr))
}
invalid(''); //empty should be invalid

View file

@ -1,22 +1,21 @@
/* global describe, it */
var assert = require('assert');
var base58 = require('../').base58;
var convert = require('../').convert;
var assert = require('assert')
var base58 = require('../').base58
var convert = require('../').convert
describe('base58', function() {
describe('decode', function() {
it('validates known examples', function() {
var enc = '5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ';
var hex = '800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d';
assert.deepEqual(base58.decode(enc), convert.hexToBytes(hex));
var enc = '5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ'
var hex = '800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d'
assert.deepEqual(base58.decode(enc), convert.hexToBytes(hex))
})
})
describe('encode', function() {
it('handles known examples', function() {
var enc = '5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ';
var hex = '800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d';
assert.equal(base58.encode(convert.hexToBytes(hex)), enc);
var enc = '5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ'
var hex = '800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d507a5b8d'
assert.equal(base58.encode(convert.hexToBytes(hex)), enc)
})
})
@ -30,7 +29,7 @@ describe('base58', function() {
var vbyte = 239
assert.equal(base58.checkEncode(input, vbyte),
'92tb9mjz6q9eKZjYvLsgk87kPrMoh7BGRumSzPeUGhmigtsfrbP');
'92tb9mjz6q9eKZjYvLsgk87kPrMoh7BGRumSzPeUGhmigtsfrbP')
})
})
@ -40,10 +39,10 @@ describe('base58', function() {
var expected = [
98, 233, 7, 177, 92, 191, 39, 213, 66, 83,
153, 235, 246, 240, 251, 80, 235, 184, 143, 24
];
]
expected.version = 0
assert.deepEqual(base58.checkDecode(input), expected);
assert.deepEqual(base58.checkDecode(input), expected)
})
})
})

View file

@ -1,29 +1,28 @@
/* global describe, it */
var assert = require('assert');
var convert = require('../src/convert.js');
var assert = require('assert')
var convert = require('../src/convert.js')
describe('convert', function() {
describe('bytesToHex', function() {
it('handles example 1', function() {
assert.equal(convert.bytesToHex([0, 1, 2, 255]), '000102ff');
assert.equal(convert.bytesToHex([0, 1, 2, 255]), '000102ff')
})
})
describe('hexToBytes', function() {
it('handles example 1', function() {
assert.deepEqual(convert.hexToBytes('000102ff'), [0, 1, 2, 255]);
assert.deepEqual(convert.hexToBytes('000102ff'), [0, 1, 2, 255])
})
})
it('converts from bytes to hex and back', function() {
var bytes = [];
var bytes = []
for (var i=0 ; i<256 ; ++i) {
bytes.push(i);
bytes.push(i)
}
var hex = convert.bytesToHex(bytes);
assert.equal(hex.length, 512);
assert.deepEqual(convert.hexToBytes(hex), bytes);
var hex = convert.bytesToHex(bytes)
assert.equal(hex.length, 512)
assert.deepEqual(convert.hexToBytes(hex), bytes)
})
describe('bytesToBase64', function() {
@ -46,7 +45,7 @@ describe('convert', function() {
})
describe('byte array and word array conversions', function(){
var bytes, wordArray;
var bytes, wordArray
beforeEach(function(){
bytes = [

View file

@ -1,23 +1,22 @@
/* global describe, it */
var assert = require('assert');
var sec = require('../src/jsbn/sec');
var ecdsa = require('../').ecdsa;
var assert = require('assert')
var sec = require('../src/jsbn/sec')
var ecdsa = require('../').ecdsa
var ecparams = sec('secp256k1');
var ecparams = sec('secp256k1')
describe('ecdsa', function() {
it('handles point multiplication', function() {
var G = ecparams.getG();
var n = ecparams.getN();
var G = ecparams.getG()
var n = ecparams.getN()
assert.ok(G.multiply(n).isInfinity(), "Gn is infinite");
assert.ok(G.multiply(n).isInfinity(), "Gn is infinite")
var k = ecdsa.getBigRandom(n);
var P = G.multiply(k);
assert.ok(!P.isInfinity(), "kG is not infinite");
assert.ok(P.isOnCurve(), "kG on curve");
assert.ok(P.multiply(n).isInfinity(), "kGn is infinite");
var k = ecdsa.getBigRandom(n)
var P = G.multiply(k)
assert.ok(!P.isInfinity(), "kG is not infinite")
assert.ok(P.isOnCurve(), "kG on curve")
assert.ok(P.multiply(n).isInfinity(), "kGn is infinite")
assert.ok(P.validate(), "kG validates as a public key");
assert.ok(P.validate(), "kG validates as a public key")
})
})

View file

@ -1,70 +1,67 @@
/* global describe, it */
var assert = require('assert');
var ECKey = require('../src/eckey.js').ECKey;
var ECPubKey = require('../src/eckey.js').ECPubKey;
var convert = require('../src/convert.js');
var bytesToHex = convert.bytesToHex;
var hexToBytes = convert.hexToBytes;
var Address = require('../src/address');
var assert = require('assert')
var ECKey = require('../src/eckey.js').ECKey
var ECPubKey = require('../src/eckey.js').ECPubKey
var convert = require('../src/convert.js')
var bytesToHex = convert.bytesToHex
var hexToBytes = convert.hexToBytes
var Address = require('../src/address')
var Network = require('../src/network')
var testnet = Network.testnet.addressVersion
describe('ECKey', function() {
describe('constructor', function() {
it('parses hex', function() {
var priv = '18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725';
var priv = '18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725'
var pub = '0450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b235' +
'22cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6';
var key = new ECKey(priv);
'22cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6'
var key = new ECKey(priv)
assert.equal(key.getPub().toHex(), pub);
assert.equal(key.compressed, false);
assert.equal(key.getPub().toHex(), pub)
assert.equal(key.compressed, false)
})
it('parses base64', function() {
var priv = 'VYdB+iv47y5FaUVIPdQInkgATrABeuD1lACUoM4x7tU=';
var priv = 'VYdB+iv47y5FaUVIPdQInkgATrABeuD1lACUoM4x7tU='
var pub = '042f43c16c08849fed20a35bb7b1947bbf0923c52d613ee13b5c665a1e10d24b2' +
'8be909a70f5f87c1adb79fbcd1b3f17d20aa91c04fc355112dba2ce9b1cbf013b';
var key = new ECKey(priv);
'8be909a70f5f87c1adb79fbcd1b3f17d20aa91c04fc355112dba2ce9b1cbf013b'
var key = new ECKey(priv)
assert.equal(key.getPub().toHex(), pub);
assert.equal(key.compressed, false);
assert.equal(key.getPub().toHex(), pub)
assert.equal(key.compressed, false)
})
it('parses WIF', function() {
var priv = '5HwoXVkHoRM8sL2KmNRS217n1g8mPPBomrY7yehCuXC1115WWsh';
var priv = '5HwoXVkHoRM8sL2KmNRS217n1g8mPPBomrY7yehCuXC1115WWsh'
var pub = '044f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0' +
'f0b704075871aa385b6b1b8ead809ca67454d9683fcf2ba03456d6fe2c4abe2b07f0fbdbb2f1c1';
var addr = '1MsHWS1BnwMc3tLE8G35UXsS58fKipzB7a';
var key = new ECKey(priv);
'f0b704075871aa385b6b1b8ead809ca67454d9683fcf2ba03456d6fe2c4abe2b07f0fbdbb2f1c1'
var addr = '1MsHWS1BnwMc3tLE8G35UXsS58fKipzB7a'
var key = new ECKey(priv)
assert.equal(key.compressed, false);
assert.equal(key.getPub().toHex(), pub);
assert.equal(key.getAddress().toString(), addr);
assert.equal(key.compressed, false)
assert.equal(key.getPub().toHex(), pub)
assert.equal(key.getAddress().toString(), addr)
})
it('parses compressed WIF', function() {
var priv = 'KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp';
var priv = 'KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp'
var pub = '034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa'
var addr = '1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9';
var key = new ECKey(priv);
var addr = '1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9'
var key = new ECKey(priv)
assert.equal(key.compressed, true);
assert.equal(key.getPub().toHex(), pub);
assert.equal(key.getAddress().toString(), addr);
assert.equal(key.compressed, true)
assert.equal(key.getPub().toHex(), pub)
assert.equal(key.getAddress().toString(), addr)
})
it('alternative constructor syntax', function() {
var priv = 'ca48ec9783cf3ad0dfeff1fc254395a2e403cbbc666477b61b45e31d3b8ab458';
var priv = 'ca48ec9783cf3ad0dfeff1fc254395a2e403cbbc666477b61b45e31d3b8ab458'
var pub = '044b12d9d7c77db68388b6ff7c89046174c871546436806bcd80d07c28ea81199' +
'283fbec990dad6fb98f93f712d50cb874dd717de6a184158d63886dda3090f566';
var key = ECKey(priv, false);
'283fbec990dad6fb98f93f712d50cb874dd717de6a184158d63886dda3090f566'
var key = ECKey(priv, false)
assert.equal(key.getPub().toHex(), pub);
assert.equal(key.compressed, false);
assert.equal(key.toHex(), priv);
assert.equal(key.getPub().toHex(), pub)
assert.equal(key.compressed, false)
assert.equal(key.toHex(), priv)
})
})
@ -73,42 +70,42 @@ describe('ECKey', function() {
'ca48ec9783cf3ad0dfeff1fc254395a2e403cbbc666477b61b45e31d3b8ab458',
'1111111111111111111111111111111111111111111111111111111111111111',
'18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725'
];
]
// compressed pubkeys
var cpubkeys = [
'024b12d9d7c77db68388b6ff7c89046174c871546436806bcd80d07c28ea811992',
'034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa',
'0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352'
];
]
var pubkeys = cpubkeys.map(function(x) {
return ECPubKey(x).toHex(false)
});
})
it('mainnet', function() {
var addresses = [
'19SgmoUj4xowEjwtXvNAtYTAgbvR9iBCui',
'1MsHWS1BnwMc3tLE8G35UXsS58fKipzB7a',
'16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM'
];
]
var compressedAddresses = [
'1AA4sjKW2aUmbtN3MtegdvhYtDBbDEke1q',
'1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9',
'1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs',
];
]
for (var i = 0; i < addresses.length; ++i) {
var priv = new ECKey(privkeys[i], false);
var pub = new ECPubKey(pubkeys[i], false);
var cpub = new ECPubKey(cpubkeys[i], true);
var priv = new ECKey(privkeys[i], false)
var pub = new ECPubKey(pubkeys[i], false)
var cpub = new ECPubKey(cpubkeys[i], true)
var addr = addresses[i];
var caddr = compressedAddresses[i];
var addr = addresses[i]
var caddr = compressedAddresses[i]
assert.equal(priv.getAddress().toString(), addr);
assert.equal(pub.getAddress().toString(), addr);
assert.equal(cpub.getAddress().toString(), caddr);
assert.equal(priv.getAddress().toString(), addr)
assert.equal(pub.getAddress().toString(), addr)
assert.equal(cpub.getAddress().toString(), caddr)
}
})
@ -117,27 +114,27 @@ describe('ECKey', function() {
'19SgmoUj4xowEjwtXvNAtYTAgbvR9iBCui',
'1MsHWS1BnwMc3tLE8G35UXsS58fKipzB7a',
'16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM'
];
]
var compressedAddresses = [
'1AA4sjKW2aUmbtN3MtegdvhYtDBbDEke1q',
'1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9',
'1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs',
];
]
for (var i = 0; i < addresses.length; ++i) {
var priv = new ECKey(privkeys[i], false);
var pub = new ECPubKey(pubkeys[i], false);
var cpub = new ECPubKey(cpubkeys[i], true);
var priv = new ECKey(privkeys[i], false)
var pub = new ECPubKey(pubkeys[i], false)
var cpub = new ECPubKey(cpubkeys[i], true)
var addr = addresses[i];
var caddr = compressedAddresses[i];
var addr = addresses[i]
var caddr = compressedAddresses[i]
assert.equal(priv.getAddress().toString(), addr);
assert.equal(pub.getAddress().toString(), addr);
assert.equal(cpub.getAddress().toString(), caddr);
assert.equal(priv.getAddress().toString(), addr)
assert.equal(pub.getAddress().toString(), addr)
assert.equal(cpub.getAddress().toString(), caddr)
}
})
});
})
describe('signing', function() {
var hpriv = 'ca48ec9783cf3ad0dfeff1fc254395a2e403cbbc666477b61b45e31d3b8ab458'

View file

@ -1,4 +1,3 @@
/* global describe, it */
var HDWallet = require('../src/hdwallet.js')
var assert = require('assert')
var convert = require('../src/convert.js')
@ -12,7 +11,7 @@ describe('HDWallet', function() {
describe('toBase58', function() {
it('reproduces input', function() {
var input = 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5'
, output = HDWallet.fromBase58(input).toBase58(false)
var output = HDWallet.fromBase58(input).toBase58(false)
assert.equal(output, input)
input = 'xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334'
@ -33,11 +32,11 @@ describe('HDWallet', function() {
})
describe('constructor & seed deserialization', function() {
var expectedPrivateKey = '0fd71c652e847ba7ea7956e3cf3fc0a0985871846b1b2c23b9c6a29a38cee86001';
var expectedPrivateKey = '0fd71c652e847ba7ea7956e3cf3fc0a0985871846b1b2c23b9c6a29a38cee86001'
var seed = [
99, 114, 97, 122, 121, 32, 104, 111, 114, 115, 101, 32, 98,
97, 116, 116, 101, 114, 121, 32, 115, 116, 97, 112, 108, 101
];
]
it('creates from binary seed', function() {
var hd = new HDWallet(seed)
@ -244,12 +243,12 @@ describe('HDWallet', function() {
describe('network types', function() {
it('ensures that a mainnet Wallet generates mainnet addresses', function() {
var wallet = new HDWallet('foobar', 'mainnet')
assert.equal(wallet.getAddress().toString(), '1JNymexJHEr5u1BndiChMStFkCgPm4EQ6o');
assert.equal(wallet.getAddress().toString(), '1JNymexJHEr5u1BndiChMStFkCgPm4EQ6o')
})
it('ensures that a testnet Wallet generates testnet addresses', function() {
var wallet = new HDWallet('foobar', 'testnet')
assert.equal(wallet.getAddress().toString(), 'mxtw4i3H6GHLg7fQMHB5BN6acCH6kQ7aoY');
assert.equal(wallet.getAddress().toString(), 'mxtw4i3H6GHLg7fQMHB5BN6acCH6kQ7aoY')
})
it('throws an excption when unknown network type is passed in', function() {

View file

@ -1,29 +1,28 @@
/* global describe, it */
var assert = require('assert');
var assert = require('assert')
var BigInteger = require('../src/jsbn/jsbn.js')
var bytesToHex = require('../src/convert.js').bytesToHex;
var secureRandom = require('secure-random');
var bytesToHex = require('../src/convert.js').bytesToHex
var secureRandom = require('secure-random')
describe('BigInteger', function() {
describe('toByteArraySigned', function() {
it('handles examples', function() {
function hex(num) {
var bytes = BigInteger.valueOf(num).toByteArraySigned();
var h = bytesToHex(bytes);
return '0x' + h;
var bytes = BigInteger.valueOf(num).toByteArraySigned()
var h = bytesToHex(bytes)
return '0x' + h
}
assert.equal(hex( 0), '0x');
assert.equal(hex( 1), '0x01');
assert.equal(hex(-1), '0x81');
assert.equal(hex( 127), '0x7f');
assert.equal(hex(-127), '0xff');
assert.equal(hex( 255), '0x00ff');
assert.equal(hex(-255), '0x80ff');
assert.equal(hex( 16300), '0x3fac');
assert.equal(hex(-16300), '0xbfac');
assert.equal(hex( 62300), '0x00f35c');
assert.equal(hex(-62300), '0x80f35c');
assert.equal(hex( 0), '0x')
assert.equal(hex( 1), '0x01')
assert.equal(hex(-1), '0x81')
assert.equal(hex( 127), '0x7f')
assert.equal(hex(-127), '0xff')
assert.equal(hex( 255), '0x00ff')
assert.equal(hex(-255), '0x80ff')
assert.equal(hex( 16300), '0x3fac')
assert.equal(hex(-16300), '0xbfac')
assert.equal(hex( 62300), '0x00f35c')
assert.equal(hex(-62300), '0x80f35c')
})
})

View file

@ -1,12 +1,12 @@
var assert = require('assert');
var bitcoinjs = require('../');
var sec = require('../src/jsbn/sec');
var BigInteger = require('../src/jsbn/jsbn.js');
var SHA256 = require('crypto-js/sha256');
var rng = require('secure-random');
var ecparams = sec('secp256k1');
var ECPointFp = bitcoinjs.ECPointFp;
var convert = require('../src/convert');
var assert = require('assert')
var bitcoinjs = require('../')
var sec = require('../src/jsbn/sec')
var BigInteger = require('../src/jsbn/jsbn.js')
var SHA256 = require('crypto-js/sha256')
var rng = require('secure-random')
var ecparams = sec('secp256k1')
var ECPointFp = bitcoinjs.ECPointFp
var convert = require('../src/convert')
function sha256FromBytesToBytes(message){
return convert.wordArrayToBytes(SHA256(convert.bytesToWordArray(message)))
@ -16,50 +16,50 @@ it('Keys & Key Management', function () {
var p1 = bitcoinjs.Key().getPub().toBytes()
assert.equal(p1.length, 65)
var p1_q = ECPointFp.decodeFrom(ecparams.getCurve(), p1);
assert.ok(p1_q);
assert.ok(p1_q.validate());
var p1_q = ECPointFp.decodeFrom(ecparams.getCurve(), p1)
assert.ok(p1_q)
assert.ok(p1_q.validate())
var p2 = bitcoinjs.convert.hexToBytes(
'0486f356006a38b847bedec1bf47013776925d939d5a35a97a4d1263e550c7f1a' +
'b5aba44ab74d22892097a0e851addf07ba97e33416df5affaceeb35d5607cd23c');
'b5aba44ab74d22892097a0e851addf07ba97e33416df5affaceeb35d5607cd23c')
var p2_q = ECPointFp.decodeFrom(ecparams.getCurve(), p2);
assert.ok(p2_q);
assert.ok(p2_q.validate());
});
var p2_q = ECPointFp.decodeFrom(ecparams.getCurve(), p2)
assert.ok(p2_q)
assert.ok(p2_q.validate())
})
it('Signing and Verifying', function () {
var s1 = bitcoinjs.Key();
var sig_a = s1.sign(BigInteger.ZERO);
assert.ok(sig_a, 'Sign null');
var s1 = bitcoinjs.Key()
var sig_a = s1.sign(BigInteger.ZERO)
assert.ok(sig_a, 'Sign null')
assert.ok(s1.verify(BigInteger.ZERO, sig_a));
assert.ok(s1.verify(BigInteger.ZERO, sig_a))
var message = new BigInteger(1024, rng).toByteArrayUnsigned();
var hash = sha256FromBytesToBytes(message);
var sig_b = s1.sign(hash);
assert.ok(sig_b, 'Sign random string');
assert.ok(s1.verify(hash, sig_b));
var message = new BigInteger(1024, rng).toByteArrayUnsigned()
var hash = sha256FromBytesToBytes(message)
var sig_b = s1.sign(hash)
assert.ok(sig_b, 'Sign random string')
assert.ok(s1.verify(hash, sig_b))
var message2 = bitcoinjs.convert.hexToBytes(
'12dce2c169986b3346827ffb2305cf393984627f5f9722a1b1368e933c8d' +
'd296653fbe5d7ac031c4962ad0eb1c4298c3b91d244e1116b4a76a130c13' +
'1e7aec7fa70184a71a2e66797052831511b93c6e8d72ae58a1980eaacb66' +
'8a33f50d7cefb96a5dab897b5efcb99cbafb0d777cb83fc9b2115b69c0fa' +
'3d82507b932b84e4');
'3d82507b932b84e4')
var hash2 = sha256FromBytesToBytes(message2);
var hash2 = sha256FromBytesToBytes(message2)
var sig_c = bitcoinjs.convert.hexToBytes(
'3044022038d9b8dd5c9fbf330565c1f51d72a59ba869aeb2c2001be959d3' +
'79e861ec71960220a73945f32cf90d03127d2c3410d16cee120fa1a4b4c3' +
'f273ab082801a95506c4');
'f273ab082801a95506c4')
var s2 = bitcoinjs.convert.hexToBytes(
'045a1594316e433fb91f35ef4874610d22177c3f1a1060f6c1e70a609d51' +
'b20be5795cd2a5eae0d6b872ba42db95e9afaeea3fbb89e98099575b6828' +
'609a978528');
'609a978528')
assert.ok(bitcoinjs.ecdsa.verify(hash2, sig_c, s2), 'Verify constant signature');
});
assert.ok(bitcoinjs.ecdsa.verify(hash2, sig_c, s2), 'Verify constant signature')
})

View file

@ -2,13 +2,11 @@ var Script = require('../src/script.js')
var assert = require('assert')
var Address = require('../src/address.js')
var Network = require('../src/network.js')
var Util = require('../src/util.js')
var sha256ripe160 = Util.sha256ripe160;
var sha256ripe160 = Util.sha256ripe160
var Convert = require('../src/convert.js')
var bytesToHex = Convert.bytesToHex;
var hexToBytes = Convert.hexToBytes;
var bytesToHex = Convert.bytesToHex
var hexToBytes = Convert.hexToBytes
describe('Script', function() {
var p2shScriptPubKey, pubkeyScriptPubkey, addressScriptSig
@ -72,7 +70,7 @@ describe('Script', function() {
})
describe('2-of-3 Multi-Signature', function() {
var compressedPubKeys = [];
var compressedPubKeys = []
var numSigs, script, multisig, network
beforeEach(function() {
@ -98,8 +96,11 @@ describe('Script', function() {
var deserialized = new Script(redeemScript)
var numOfSignatures = deserialized.chunks[deserialized.chunks.length - 2] - 80
var signaturesRequired = deserialized.chunks[0] - 80
var sigs = [bytesToHex(deserialized.chunks[1]), bytesToHex(deserialized.chunks[2]),
bytesToHex(deserialized.chunks[3])]
var sigs = [
bytesToHex(deserialized.chunks[1]),
bytesToHex(deserialized.chunks[2]),
bytesToHex(deserialized.chunks[3])
]
assert.equal(numOfSignatures, 3)
assert.equal(signaturesRequired, 2)

View file

@ -1,7 +1,6 @@
var T = require('../src/transaction')
var Transaction = T.Transaction
var TransactionOut = T.TransactionOut
var convert = require('../src/convert')
var ECKey = require('../src/eckey').ECKey
var Script = require('../src/script')
@ -84,7 +83,7 @@ describe('Transaction', function() {
// the deserialized-serialized transaction should return to its original state (== tx)
var bytes2 = Transaction.deserialize(mutated).serialize()
assert.deepEqual(bytes, bytes2)
});
})
})
describe('creating a transaction', function() {

View file

@ -6,6 +6,7 @@ var TransactionOut = T.TransactionOut
var Script = require('../src/script.js')
var convert = require('../src/convert.js')
var assert = require('assert')
var sinon = require('sinon')
var SHA256 = require('crypto-js/sha256')
var Crypto = require('crypto-js')
@ -13,10 +14,8 @@ var fixtureTxes = require('./fixtures/mainnet_tx')
var fixtureTx1Hex = fixtureTxes.prevTx
var fixtureTx2Hex = fixtureTxes.tx
var sinon = require('sinon')
describe('Wallet', function() {
var seed, wallet;
var seed, wallet
beforeEach(function(){
seed = convert.wordArrayToBytes(SHA256("don't use a string seed like this in real life"))
wallet = new Wallet(seed)
@ -155,7 +154,7 @@ describe('Wallet', function() {
})
describe('Unspent Outputs', function(){
var expectedUtxo, expectedOutputKey;
var expectedUtxo, expectedOutputKey
beforeEach(function(){
expectedUtxo = {
"hash":"6a4062273ac4f9ea4ffca52d9fd102b08f6c32faa0a4d1318e3a7b2e437bb9c7",
@ -216,7 +215,7 @@ describe('Wallet', function() {
})
describe('setUnspentOutputs', function(){
var utxo;
var utxo
beforeEach(function(){
utxo = cloneObject([expectedUtxo])
})
@ -275,7 +274,7 @@ describe('Wallet', function() {
})
describe('setUnspentOutputsAsync', function(){
var utxo;
var utxo
beforeEach(function(){
utxo = cloneObject([expectedUtxo])
})
@ -308,7 +307,7 @@ describe('Wallet', function() {
})
describe('processTx', function(){
var tx;
var tx
beforeEach(function(){
tx = Transaction.deserialize(fixtureTx1Hex)
@ -382,8 +381,8 @@ describe('Wallet', function() {
})
describe('createTx', function(){
var to, value;
var address1, address2;
var to, value
var address1, address2
beforeEach(function(){
to = '15mMHKL96tWAUtqF3tbVf99Z8arcmnJrr3'
@ -547,7 +546,7 @@ describe('Wallet', function() {
})
describe('createTxAsync', function(){
var to, value, fee;
var to, value, fee
beforeEach(function(){
to = '15mMHKL96tWAUtqF3tbVf99Z8arcmnJrr3'