Merge pull request #734 from maraoz/add/interpreter4
Add ScriptInterpreter for script evaluation
This commit is contained in:
commit
bacdff5c27
1
index.js
1
index.js
|
@ -46,6 +46,7 @@ bitcore.PaymentProtocol = require('./lib/paymentprotocol');
|
|||
bitcore.PrivateKey = require('./lib/privatekey');
|
||||
bitcore.PublicKey = require('./lib/publickey');
|
||||
bitcore.Script = require('./lib/script');
|
||||
bitcore.ScriptInterpreter = require('./lib/script_interpreter');
|
||||
bitcore.Transaction = require('./lib/transaction');
|
||||
bitcore.URI = require('./lib/uri');
|
||||
bitcore.Unit = require('./lib/unit');
|
||||
|
|
|
@ -140,7 +140,7 @@ BN.prototype.toSM = function(opts) {
|
|||
// bitcoind's script interpreter use CScriptNum, which is not really a proper
|
||||
// bignum. Instead, an error is thrown if trying to input a number bigger than
|
||||
// 4 bytes. We copy that behavior here.
|
||||
BN.prototype.fromCScriptNumBuffer = function(buf, fRequireMinimal) {
|
||||
BN.prototype.fromScriptNumBuffer = function(buf, fRequireMinimal) {
|
||||
var nMaxNumSize = 4;
|
||||
if (buf.length > nMaxNumSize)
|
||||
throw new Error('script number overflow');
|
||||
|
@ -169,7 +169,7 @@ BN.prototype.fromCScriptNumBuffer = function(buf, fRequireMinimal) {
|
|||
// an error if the output is larger than four bytes. (Which can happen if
|
||||
// performing a numerical operation that results in an overflow to more than 4
|
||||
// bytes).
|
||||
BN.prototype.toCScriptNumBuffer = function(buf) {
|
||||
BN.prototype.toScriptNumBuffer = function(buf) {
|
||||
return this.toSM({endian: 'little'});
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
var BN = require('./bn');
|
||||
var BufferReader = require('../encoding/bufferreader');
|
||||
var Point = require('./point');
|
||||
var Signature = require('./signature');
|
||||
var PublicKey = require('../publickey');
|
||||
|
@ -66,7 +65,7 @@ ECDSA.prototype.fromString = function(str) {
|
|||
this.privkey = PrivateKey.fromString(obj.privkey);
|
||||
}
|
||||
if (obj.sig) {
|
||||
this.sig = Signature().fromString(obj.sig);
|
||||
this.sig = Signature.fromString(obj.sig);
|
||||
}
|
||||
if (obj.k) {
|
||||
this.k = BN(obj.k, 10);
|
||||
|
|
|
@ -2,44 +2,44 @@
|
|||
|
||||
var hashjs = require('hash.js');
|
||||
var sha512 = require('sha512');
|
||||
var crypto = require('crypto');
|
||||
var BufferUtil = require('../util/buffer');
|
||||
var $ = require('../util/preconditions');
|
||||
|
||||
var Hash = module.exports;
|
||||
|
||||
Hash.sha1 = function(buf) {
|
||||
$.checkArgument(BufferUtil.isBuffer(buf));
|
||||
return crypto.createHash('sha1').update(buf).digest();
|
||||
};
|
||||
|
||||
Hash.sha1.blocksize = 512;
|
||||
|
||||
Hash.sha256 = function(buf) {
|
||||
if (!Buffer.isBuffer(buf))
|
||||
throw new Error('sha256 hash must be of a buffer');
|
||||
var hash = (new hashjs.sha256()).update(buf).digest();
|
||||
return new Buffer(hash);
|
||||
$.checkArgument(BufferUtil.isBuffer(buf));
|
||||
return crypto.createHash('sha256').update(buf).digest();
|
||||
};
|
||||
|
||||
Hash.sha256.blocksize = 512;
|
||||
|
||||
Hash.sha256sha256 = function(buf) {
|
||||
try {
|
||||
return Hash.sha256(Hash.sha256(buf));
|
||||
} catch (e) {
|
||||
throw new Error('sha256sha256 hash must be of a buffer');
|
||||
}
|
||||
$.checkArgument(BufferUtil.isBuffer(buf));
|
||||
return Hash.sha256(Hash.sha256(buf));
|
||||
};
|
||||
|
||||
Hash.ripemd160 = function(buf) {
|
||||
if (!Buffer.isBuffer(buf))
|
||||
throw new Error('ripemd160 hash must be of a buffer');
|
||||
$.checkArgument(BufferUtil.isBuffer(buf));
|
||||
var hash = (new hashjs.ripemd160()).update(buf).digest();
|
||||
return new Buffer(hash);
|
||||
};
|
||||
|
||||
Hash.sha256ripemd160 = function(buf) {
|
||||
try {
|
||||
return Hash.ripemd160(Hash.sha256(buf));
|
||||
} catch (e) {
|
||||
throw new Error('sha256ripemd160 hash must be of a buffer');
|
||||
}
|
||||
$.checkArgument(BufferUtil.isBuffer(buf));
|
||||
return Hash.ripemd160(Hash.sha256(buf));
|
||||
};
|
||||
|
||||
Hash.sha512 = function(buf) {
|
||||
if (!Buffer.isBuffer(buf))
|
||||
throw new Error('sha512 hash must be of a buffer');
|
||||
$.checkArgument(BufferUtil.isBuffer(buf));
|
||||
var hash = sha512(buf);
|
||||
return new Buffer(hash);
|
||||
};
|
||||
|
@ -47,19 +47,17 @@ Hash.sha512 = function(buf) {
|
|||
Hash.sha512.blocksize = 1024;
|
||||
|
||||
Hash.hmac = function(hashf, data, key) {
|
||||
if (!Buffer.isBuffer(data) || !Buffer.isBuffer(key))
|
||||
throw new Error('data and key must be buffers');
|
||||
|
||||
//http://en.wikipedia.org/wiki/Hash-based_message_authentication_code
|
||||
//http://tools.ietf.org/html/rfc4868#section-2
|
||||
if (!hashf.blocksize)
|
||||
throw new Error('Blocksize for hash function unknown');
|
||||
$.checkArgument(BufferUtil.isBuffer(data));
|
||||
$.checkArgument(BufferUtil.isBuffer(key));
|
||||
$.checkArgument(hashf.blocksize);
|
||||
|
||||
var blocksize = hashf.blocksize/8;
|
||||
|
||||
if (key.length > blocksize)
|
||||
var blocksize = hashf.blocksize / 8;
|
||||
|
||||
if (key.length > blocksize) {
|
||||
key = hashf(key);
|
||||
else if (key < blocksize) {
|
||||
} else if (key < blocksize) {
|
||||
var fill = new Buffer(blocksize);
|
||||
fill.fill(0);
|
||||
key.copy(fill);
|
||||
|
|
|
@ -10,8 +10,7 @@ var Signature = function Signature(r, s) {
|
|||
r: r,
|
||||
s: s
|
||||
});
|
||||
}
|
||||
else if (r) {
|
||||
} else if (r) {
|
||||
var obj = r;
|
||||
this.set(obj);
|
||||
}
|
||||
|
@ -25,88 +24,114 @@ Signature.prototype.set = function(obj) {
|
|||
return this;
|
||||
};
|
||||
|
||||
Signature.prototype.fromCompact = function(buf) {
|
||||
Signature.fromCompact = function(buf) {
|
||||
var sig = new Signature();
|
||||
var compressed = true;
|
||||
var i = buf.slice(0, 1)[0] - 27 - 4;
|
||||
//TODO: handle uncompressed pubkeys
|
||||
/*
|
||||
if (i < 0) {
|
||||
compressed = false;
|
||||
i = i + 4;
|
||||
}
|
||||
*/
|
||||
|
||||
var b2 = buf.slice(1, 33);
|
||||
var b3 = buf.slice(33, 65);
|
||||
|
||||
if (!(i === 0 || i === 1 || i === 2 || i === 3))
|
||||
if (!(i === 0 || i === 1 || i === 2 || i === 3)) {
|
||||
throw new Error('i must be 0, 1, 2, or 3');
|
||||
if (b2.length !== 32)
|
||||
}
|
||||
if (b2.length !== 32) {
|
||||
throw new Error('r must be 32 bytes');
|
||||
if (b3.length !== 32)
|
||||
}
|
||||
if (b3.length !== 32) {
|
||||
throw new Error('s must be 32 bytes');
|
||||
}
|
||||
|
||||
this.compressed = compressed;
|
||||
this.i = i;
|
||||
this.r = BN().fromBuffer(b2);
|
||||
this.s = BN().fromBuffer(b3);
|
||||
sig.compressed = compressed;
|
||||
sig.i = i;
|
||||
sig.r = BN().fromBuffer(b2);
|
||||
sig.s = BN().fromBuffer(b3);
|
||||
|
||||
return this;
|
||||
return sig;
|
||||
};
|
||||
|
||||
Signature.prototype.fromDER = function(buf) {
|
||||
var obj = Signature.parseDER(buf);
|
||||
this.r = obj.r;
|
||||
this.s = obj.s;
|
||||
Signature.fromDER = function(buf, strict) {
|
||||
var obj = Signature.parseDER(buf, strict);
|
||||
var sig = new Signature();
|
||||
|
||||
return this;
|
||||
sig.r = obj.r;
|
||||
sig.s = obj.s;
|
||||
|
||||
return sig;
|
||||
};
|
||||
|
||||
Signature.prototype.fromString = function(str) {
|
||||
// The format used in a tx
|
||||
Signature.fromTxFormat = function(buf) {
|
||||
var nhashtype = buf.readUInt8(buf.length - 1);
|
||||
var derbuf = buf.slice(0, buf.length - 1);
|
||||
var sig = new Signature.fromDER(derbuf, false);
|
||||
sig.nhashtype = nhashtype;
|
||||
return sig;
|
||||
};
|
||||
|
||||
Signature.fromString = function(str) {
|
||||
var buf = new Buffer(str, 'hex');
|
||||
this.fromDER(buf);
|
||||
|
||||
return this;
|
||||
return Signature.fromDER(buf);
|
||||
};
|
||||
|
||||
Signature.parseDER = function(buf) {
|
||||
if (!Buffer.isBuffer(buf))
|
||||
|
||||
/**
|
||||
* In order to mimic the non-strict DER encoding of OpenSSL, set strict = false.
|
||||
*/
|
||||
Signature.parseDER = function(buf, strict) {
|
||||
if (typeof strict === 'undefined') {
|
||||
strict = true;
|
||||
}
|
||||
|
||||
if (!Buffer.isBuffer(buf)) {
|
||||
throw new Error('DER formatted signature should be a buffer');
|
||||
}
|
||||
|
||||
var header = buf[0];
|
||||
|
||||
if (header !== 0x30)
|
||||
if (header !== 0x30) {
|
||||
throw new Error('Header byte should be 0x30');
|
||||
}
|
||||
|
||||
var length = buf[1];
|
||||
if (length !== buf.slice(2).length)
|
||||
var buflength = buf.slice(2).length;
|
||||
if (strict && length !== buflength) {
|
||||
throw new Error('Length byte should length of what follows');
|
||||
} else {
|
||||
length = length < buflength ? length : buflength;
|
||||
}
|
||||
|
||||
var rheader = buf[2 + 0];
|
||||
if (rheader !== 0x02)
|
||||
if (rheader !== 0x02) {
|
||||
throw new Error('Integer byte for r should be 0x02');
|
||||
}
|
||||
|
||||
var rlength = buf[2 + 1];
|
||||
var rbuf = buf.slice(2 + 2, 2 + 2 + rlength);
|
||||
var r = BN().fromBuffer(rbuf);
|
||||
var rneg = buf[2 + 1 + 1] === 0x00 ? true : false;
|
||||
if (rlength !== rbuf.length)
|
||||
if (rlength !== rbuf.length) {
|
||||
throw new Error('Length of r incorrect');
|
||||
}
|
||||
|
||||
var sheader = buf[2 + 2 + rlength + 0];
|
||||
if (sheader !== 0x02)
|
||||
if (sheader !== 0x02) {
|
||||
throw new Error('Integer byte for s should be 0x02');
|
||||
}
|
||||
|
||||
var slength = buf[2 + 2 + rlength + 1];
|
||||
var sbuf = buf.slice(2 + 2 + rlength + 2, 2 + 2 + rlength + 2 + slength);
|
||||
var s = BN().fromBuffer(sbuf);
|
||||
var sneg = buf[2 + 2 + rlength + 2 + 2] === 0x00 ? true : false;
|
||||
if (slength !== sbuf.length)
|
||||
if (slength !== sbuf.length) {
|
||||
throw new Error('Length of s incorrect');
|
||||
}
|
||||
|
||||
var sumlength = 2 + 2 + rlength + 2 + slength;
|
||||
if (length !== sumlength - 2)
|
||||
if (length !== sumlength - 2) {
|
||||
throw new Error('Length of signature incorrect');
|
||||
}
|
||||
|
||||
var obj = {
|
||||
header: header,
|
||||
|
@ -126,19 +151,25 @@ Signature.parseDER = function(buf) {
|
|||
return obj;
|
||||
};
|
||||
|
||||
|
||||
Signature.prototype.toCompact = function(i, compressed) {
|
||||
i = typeof i === 'number' ? i : this.i;
|
||||
compressed = typeof compressed === 'boolean' ? compressed : this.compressed;
|
||||
|
||||
if (!(i === 0 || i === 1 || i === 2 || i === 3))
|
||||
if (!(i === 0 || i === 1 || i === 2 || i === 3)) {
|
||||
throw new Error('i must be equal to 0, 1, 2, or 3');
|
||||
|
||||
}
|
||||
|
||||
var val = i + 27 + 4;
|
||||
if (compressed === false)
|
||||
val = val - 4;
|
||||
var b1 = new Buffer([val]);
|
||||
var b2 = this.r.toBuffer({size: 32});
|
||||
var b3 = this.s.toBuffer({size: 32});
|
||||
var b2 = this.r.toBuffer({
|
||||
size: 32
|
||||
});
|
||||
var b3 = this.s.toBuffer({
|
||||
size: 32
|
||||
});
|
||||
return Buffer.concat([b1, b2, b3]);
|
||||
};
|
||||
|
||||
|
@ -168,6 +199,115 @@ Signature.prototype.toString = function() {
|
|||
return buf.toString('hex');
|
||||
};
|
||||
|
||||
/**
|
||||
* This function is translated from bitcoind's IsDERSignature and is used in
|
||||
* the script interpreter. This "DER" format actually includes an extra byte,
|
||||
* the nhashtype, at the end. It is really the tx format, not DER format.
|
||||
*
|
||||
* A canonical signature exists of: [30] [total len] [02] [len R] [R] [02] [len S] [S] [hashtype]
|
||||
* Where R and S are not negative (their first byte has its highest bit not set), and not
|
||||
* excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
|
||||
* in which case a single 0 byte is necessary and even required).
|
||||
*
|
||||
* See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
|
||||
*/
|
||||
Signature.isTxDER = function(buf) {
|
||||
if (buf.length < 9) {
|
||||
// Non-canonical signature: too short
|
||||
return false;
|
||||
}
|
||||
if (buf.length > 73) {
|
||||
// Non-canonical signature: too long
|
||||
return false;
|
||||
}
|
||||
if (buf[0] !== 0x30) {
|
||||
// Non-canonical signature: wrong type
|
||||
return false;
|
||||
}
|
||||
if (buf[1] !== buf.length - 3) {
|
||||
// Non-canonical signature: wrong length marker
|
||||
return false;
|
||||
}
|
||||
var nLenR = buf[3];
|
||||
if (5 + nLenR >= buf.length) {
|
||||
// Non-canonical signature: S length misplaced
|
||||
return false;
|
||||
}
|
||||
var nLenS = buf[5 + nLenR];
|
||||
if ((nLenR + nLenS + 7) !== buf.length) {
|
||||
// Non-canonical signature: R+S length mismatch
|
||||
return false;
|
||||
}
|
||||
|
||||
var R = buf.slice(4);
|
||||
if (buf[4 - 2] !== 0x02) {
|
||||
// Non-canonical signature: R value type mismatch
|
||||
return false;
|
||||
}
|
||||
if (nLenR === 0) {
|
||||
// Non-canonical signature: R length is zero
|
||||
return false;
|
||||
}
|
||||
if (R[0] & 0x80) {
|
||||
// Non-canonical signature: R value negative
|
||||
return false;
|
||||
}
|
||||
if (nLenR > 1 && (R[0] === 0x00) && !(R[1] & 0x80)) {
|
||||
// Non-canonical signature: R value excessively padded
|
||||
return false;
|
||||
}
|
||||
|
||||
var S = buf.slice(6 + nLenR);
|
||||
if (buf[6 + nLenR - 2] !== 0x02) {
|
||||
// Non-canonical signature: S value type mismatch
|
||||
return false;
|
||||
}
|
||||
if (nLenS === 0) {
|
||||
// Non-canonical signature: S length is zero
|
||||
return false;
|
||||
}
|
||||
if (S[0] & 0x80) {
|
||||
// Non-canonical signature: S value negative
|
||||
return false;
|
||||
}
|
||||
if (nLenS > 1 && (S[0] === 0x00) && !(S[1] & 0x80)) {
|
||||
// Non-canonical signature: S value excessively padded
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compares to bitcoind's IsLowDERSignature
|
||||
* See also ECDSA signature algorithm which enforces this.
|
||||
* See also BIP 62, "low S values in signatures"
|
||||
*/
|
||||
Signature.prototype.hasLowS = function() {
|
||||
if (this.s.lt(1) ||
|
||||
this.s.gt(BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0'))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns true if the nhashtype is exactly equal to one of the standard options or combinations thereof.
|
||||
* Translated from bitcoind's IsDefinedHashtypeSignature
|
||||
*/
|
||||
Signature.prototype.hasDefinedHashtype = function() {
|
||||
if (this.nhashtype < Signature.SIGHASH_ALL || this.nhashtype > Signature.SIGHASH_SINGLE) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Signature.prototype.toTxFormat = function() {
|
||||
var derbuf = this.toDER();
|
||||
var buf = new Buffer(1);
|
||||
buf.writeUInt8(this.nhashtype, 0);
|
||||
return Buffer.concat([derbuf, buf]);
|
||||
};
|
||||
|
||||
Signature.SIGHASH_ALL = 0x01;
|
||||
Signature.SIGHASH_NONE = 0x02;
|
||||
Signature.SIGHASH_SINGLE = 0x03;
|
||||
|
|
|
@ -388,7 +388,7 @@ PaymentProtocol.prototype.sinVerify = function() {
|
|||
var buf = this.serializeForSig();
|
||||
var hash = magicHash(buf);
|
||||
var publicKey = PublicKey.fromBuffer(pubkey);
|
||||
var signature = new Signature().fromString(sig);
|
||||
var signature = new Signature.fromString(sig);
|
||||
var verified = ECDSA.verify(hash, signature, publicKey);
|
||||
return verified;
|
||||
};
|
||||
|
|
104
lib/publickey.js
104
lib/publickey.js
|
@ -1,11 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var Address = require('./address');
|
||||
var BN = require('./crypto/bn');
|
||||
var Point = require('./crypto/point');
|
||||
var JSUtil = require('./util/js');
|
||||
var Network = require('./networks');
|
||||
var _ = require('lodash');
|
||||
var $ = require('./util/preconditions');
|
||||
|
||||
/**
|
||||
* Instantiate a PublicKey from a 'PrivateKey', 'Point', 'string', 'Buffer'.
|
||||
|
@ -33,9 +34,9 @@ var PublicKey = function PublicKey(data, extra) {
|
|||
if (!(this instanceof PublicKey)) {
|
||||
return new PublicKey(data, extra);
|
||||
}
|
||||
if (!data) {
|
||||
throw new TypeError('First argument is required, please include public key data.');
|
||||
}
|
||||
|
||||
$.checkArgument(data, new TypeError('First argument is required, please include public key data.'));
|
||||
|
||||
if (data instanceof PublicKey) {
|
||||
// Return copy, but as it's an immutable object, return same argument
|
||||
return data;
|
||||
|
@ -92,8 +93,8 @@ var PublicKey = function PublicKey(data, extra) {
|
|||
* @private
|
||||
*/
|
||||
PublicKey._isPrivateKey = function(param) {
|
||||
return param && param.constructor && param.constructor.name
|
||||
&& param.constructor.name === 'PrivateKey';
|
||||
var PrivateKey = require('./privatekey');
|
||||
return param instanceof PrivateKey;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -126,10 +127,9 @@ PublicKey._isJSON = function(json) {
|
|||
* @private
|
||||
*/
|
||||
PublicKey._transformPrivateKey = function(privkey) {
|
||||
$.checkArgument(PublicKey._isPrivateKey(privkey),
|
||||
new TypeError('Must be an instance of PrivateKey'));
|
||||
var info = {};
|
||||
if (!PublicKey._isPrivateKey(privkey)) {
|
||||
throw new TypeError('Must be an instance of PrivateKey');
|
||||
}
|
||||
info.point = Point.getG().mul(privkey.bn);
|
||||
info.compressed = privkey.compressed;
|
||||
info.network = privkey.network;
|
||||
|
@ -140,21 +140,22 @@ PublicKey._transformPrivateKey = function(privkey) {
|
|||
* Internal function to transform DER into a public key point
|
||||
*
|
||||
* @param {Buffer} buf - An hex encoded buffer
|
||||
* @param {bool} [strict] - if set to false, will loosen some conditions
|
||||
* @returns {Object} An object with keys: point and compressed
|
||||
* @private
|
||||
*/
|
||||
PublicKey._transformDER = function(buf){
|
||||
PublicKey._transformDER = function(buf, strict) {
|
||||
$.checkArgument(PublicKey._isBuffer(buf), new TypeError('Must be a hex buffer of DER encoded public key'));
|
||||
var info = {};
|
||||
if (!PublicKey._isBuffer(buf)) {
|
||||
throw new TypeError('Must be a hex buffer of DER encoded public key');
|
||||
}
|
||||
|
||||
strict = _.isUndefined(strict) ? true : strict;
|
||||
|
||||
var x;
|
||||
var y;
|
||||
var xbuf;
|
||||
var ybuf;
|
||||
|
||||
if (buf[0] === 0x04) {
|
||||
if (buf[0] === 0x04 || (!strict && (buf[0] === 0x06 || buf[0] === 0x07))) {
|
||||
xbuf = buf.slice(1, 33);
|
||||
ybuf = buf.slice(33, 65);
|
||||
if (xbuf.length !== 32 || ybuf.length !== 32 || buf.length !== 65) {
|
||||
|
@ -169,7 +170,7 @@ PublicKey._transformDER = function(buf){
|
|||
x = BN(xbuf);
|
||||
info = PublicKey._transformX(true, x);
|
||||
info.compressed = true;
|
||||
} else if (buf[0] == 0x02) {
|
||||
} else if (buf[0] === 0x02) {
|
||||
xbuf = buf.slice(1);
|
||||
x = BN(xbuf);
|
||||
info = PublicKey._transformX(false, x);
|
||||
|
@ -188,11 +189,10 @@ PublicKey._transformDER = function(buf){
|
|||
* @returns {Object} An object with keys: point and compressed
|
||||
* @private
|
||||
*/
|
||||
PublicKey._transformX = function(odd, x){
|
||||
PublicKey._transformX = function(odd, x) {
|
||||
$.checkArgument(typeof odd === 'boolean',
|
||||
new TypeError('Must specify whether y is odd or not (true or false)'));
|
||||
var info = {};
|
||||
if (typeof odd !== 'boolean') {
|
||||
throw new TypeError('Must specify whether y is odd or not (true or false)');
|
||||
}
|
||||
info.point = Point.fromX(odd, x);
|
||||
return info;
|
||||
};
|
||||
|
@ -204,10 +204,8 @@ PublicKey._transformX = function(odd, x){
|
|||
* @returns {PublicKey} A new valid instance of PublicKey
|
||||
*/
|
||||
PublicKey.fromJSON = function(json) {
|
||||
if (!PublicKey._isJSON(json)) {
|
||||
throw new TypeError('Must be a valid JSON string or plain object');
|
||||
}
|
||||
|
||||
$.checkArgument(PublicKey._isJSON(json),
|
||||
new TypeError('Must be a valid JSON string or plain object'));
|
||||
return new PublicKey(json);
|
||||
};
|
||||
|
||||
|
@ -225,7 +223,9 @@ PublicKey._transformJSON = function(json) {
|
|||
var x = BN(json.x, 'hex');
|
||||
var y = BN(json.y, 'hex');
|
||||
var point = new Point(x, y);
|
||||
return new PublicKey(point, {compressed: json.compressed});
|
||||
return new PublicKey(point, {
|
||||
compressed: json.compressed
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -235,25 +235,27 @@ PublicKey._transformJSON = function(json) {
|
|||
* @returns {PublicKey} A new valid instance of PublicKey
|
||||
*/
|
||||
PublicKey.fromPrivateKey = function(privkey) {
|
||||
if (!PublicKey._isPrivateKey(privkey)) {
|
||||
throw new TypeError('Must be an instance of PrivateKey');
|
||||
}
|
||||
$.checkArgument(PublicKey._isPrivateKey(privkey), new TypeError('Must be an instance of PrivateKey'));
|
||||
var info = PublicKey._transformPrivateKey(privkey);
|
||||
return new PublicKey(info.point, {compressed: info.compressed, network: info.network});
|
||||
return new PublicKey(info.point, {
|
||||
compressed: info.compressed,
|
||||
network: info.network
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate a PublicKey from a Buffer
|
||||
*
|
||||
* @param {Buffer} buf - A DER buffer
|
||||
* @param {Buffer} buf - A DER hex buffer
|
||||
* @param {bool} [strict] - if set to false, will loosen some conditions
|
||||
* @returns {PublicKey} A new valid instance of PublicKey
|
||||
*/
|
||||
PublicKey.fromDER = PublicKey.fromBuffer = function(buf) {
|
||||
if (!PublicKey._isBuffer(buf)) {
|
||||
throw new TypeError('Must be a hex buffer of DER encoded public key');
|
||||
}
|
||||
var info = PublicKey._transformDER(buf);
|
||||
return new PublicKey(info.point, {compressed: info.compressed});
|
||||
PublicKey.fromDER = PublicKey.fromBuffer = function(buf, strict) {
|
||||
$.checkArgument(PublicKey._isBuffer(buf),
|
||||
new TypeError('Must be a hex buffer of DER encoded public key'));
|
||||
var info = PublicKey._transformDER(buf, strict);
|
||||
return new PublicKey(info.point, {
|
||||
compressed: info.compressed
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -263,11 +265,12 @@ PublicKey.fromDER = PublicKey.fromBuffer = function(buf) {
|
|||
* @param {boolean=true} compressed - whether to store this public key as compressed format
|
||||
* @returns {PublicKey} A new valid instance of PublicKey
|
||||
*/
|
||||
PublicKey.fromPoint = function(point, compressed){
|
||||
if (!(point instanceof Point)) {
|
||||
throw new TypeError('First argument must be an instance of Point.');
|
||||
}
|
||||
return new PublicKey(point, {compressed: compressed});
|
||||
PublicKey.fromPoint = function(point, compressed) {
|
||||
$.checkArgument(point instanceof Point,
|
||||
new TypeError('First argument must be an instance of Point.'));
|
||||
return new PublicKey(point, {
|
||||
compressed: compressed
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -280,7 +283,9 @@ PublicKey.fromPoint = function(point, compressed){
|
|||
PublicKey.fromString = function(str, encoding) {
|
||||
var buf = new Buffer(str, encoding || 'hex');
|
||||
var info = PublicKey._transformDER(buf);
|
||||
return new PublicKey(info.point, {compressed: info.compressed});
|
||||
return new PublicKey(info.point, {
|
||||
compressed: info.compressed
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -292,7 +297,9 @@ PublicKey.fromString = function(str, encoding) {
|
|||
*/
|
||||
PublicKey.fromX = function(odd, x) {
|
||||
var info = PublicKey._transformX(odd, x);
|
||||
return new PublicKey(info.point, {compressed: info.compressed});
|
||||
return new PublicKey(info.point, {
|
||||
compressed: info.compressed
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -334,7 +341,7 @@ PublicKey.prototype.toObject = function toObject() {
|
|||
};
|
||||
};
|
||||
|
||||
PublicKey.prototype.toJSON = function toJSON(){
|
||||
PublicKey.prototype.toJSON = function toJSON() {
|
||||
return JSON.stringify(this.toObject());
|
||||
};
|
||||
|
||||
|
@ -347,8 +354,12 @@ PublicKey.prototype.toBuffer = PublicKey.prototype.toDER = function() {
|
|||
var x = this.point.getX();
|
||||
var y = this.point.getY();
|
||||
|
||||
var xbuf = x.toBuffer({size: 32});
|
||||
var ybuf = y.toBuffer({size: 32});
|
||||
var xbuf = x.toBuffer({
|
||||
size: 32
|
||||
});
|
||||
var ybuf = y.toBuffer({
|
||||
size: 32
|
||||
});
|
||||
|
||||
var prefix;
|
||||
if (!this.compressed) {
|
||||
|
@ -395,4 +406,5 @@ PublicKey.prototype.inspect = function() {
|
|||
(this.network ? this.network.name : '') + '>';
|
||||
};
|
||||
|
||||
|
||||
module.exports = PublicKey;
|
||||
|
|
|
@ -127,7 +127,7 @@ Script.prototype.toBuffer = function() {
|
|||
};
|
||||
|
||||
Script.fromString = function(str) {
|
||||
if (jsUtil.isHexa(str)) {
|
||||
if (jsUtil.isHexa(str) || str.length === 0) {
|
||||
return new Script(new buffer.Buffer(str, 'hex'));
|
||||
}
|
||||
var script = new Script();
|
||||
|
@ -140,7 +140,7 @@ Script.fromString = function(str) {
|
|||
var opcode = Opcode(token);
|
||||
var opcodenum = opcode.toNumber();
|
||||
|
||||
if (typeof opcodenum === 'undefined') {
|
||||
if (_.isUndefined(opcodenum)) {
|
||||
opcodenum = parseInt(token);
|
||||
if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) {
|
||||
script.chunks.push({
|
||||
|
@ -184,7 +184,11 @@ Script.prototype.toString = function() {
|
|||
if (typeof Opcode.reverseMap[opcodenum] !== 'undefined') {
|
||||
str = str + ' ' + Opcode(opcodenum).toString();
|
||||
} else {
|
||||
str = str + ' ' + '0x' + opcodenum.toString(16);
|
||||
var numstr = opcodenum.toString(16);
|
||||
if (numstr.length % 2 !== 0) {
|
||||
numstr = '0' + numstr;
|
||||
}
|
||||
str = str + ' ' + '0x' + numstr;
|
||||
}
|
||||
} else {
|
||||
if (opcodenum === Opcode.OP_PUSHDATA1 ||
|
||||
|
@ -193,7 +197,9 @@ Script.prototype.toString = function() {
|
|||
str = str + ' ' + Opcode(opcodenum).toString();
|
||||
}
|
||||
str = str + ' ' + chunk.len;
|
||||
str = str + ' ' + '0x' + chunk.buf.toString('hex');
|
||||
if (chunk.len > 0) {
|
||||
str = str + ' ' + '0x' + chunk.buf.toString('hex');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,11 +264,11 @@ Script.prototype.isPublicKeyIn = function() {
|
|||
* @returns true if this is a p2sh output script
|
||||
*/
|
||||
Script.prototype.isScriptHashOut = function() {
|
||||
return this.chunks.length === 3 &&
|
||||
this.chunks[0].opcodenum === Opcode.OP_HASH160 &&
|
||||
this.chunks[1].buf &&
|
||||
this.chunks[1].buf.length === 20 &&
|
||||
this.chunks[2].opcodenum === Opcode.OP_EQUAL;
|
||||
var buf = this.toBuffer();
|
||||
return (buf.length === 23 &&
|
||||
buf[0] === Opcode.OP_HASH160 &&
|
||||
buf[1] === 0x14 &&
|
||||
buf[buf.length - 1] === Opcode.OP_EQUAL);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -475,9 +481,7 @@ Script.prototype._addOpcode = function(opcode, prepend) {
|
|||
Script.prototype._addBuffer = function(buf, prepend) {
|
||||
var opcodenum;
|
||||
var len = buf.length;
|
||||
if (len === 0) {
|
||||
return;
|
||||
} else if (len > 0 && len < Opcode.OP_PUSHDATA1) {
|
||||
if (len >= 0 && len < Opcode.OP_PUSHDATA1) {
|
||||
opcodenum = len;
|
||||
} else if (len < Math.pow(2, 8)) {
|
||||
opcodenum = Opcode.OP_PUSHDATA1;
|
||||
|
@ -522,7 +526,9 @@ Script.buildMultisigOut = function(pubkeys, m, opts) {
|
|||
opts = opts || {};
|
||||
var s = new Script();
|
||||
s.add(Opcode.smallInt(m));
|
||||
pubkeys = _.map(pubkeys, function(pubkey) { return PublicKey(pubkey); });
|
||||
pubkeys = _.map(pubkeys, function(pubkey) {
|
||||
return PublicKey(pubkey);
|
||||
});
|
||||
var sorted = pubkeys;
|
||||
if (!opts.noSorting) {
|
||||
sorted = _.sortBy(pubkeys, function(pubkey) {
|
||||
|
@ -548,7 +554,7 @@ Script.buildMultisigOut = function(pubkeys, m, opts) {
|
|||
* @param {boolean=false} opts.noSorting don't sort the given public keys before creating the script
|
||||
* @param {Script=} opts.cachedMultisig don't recalculate the redeemScript
|
||||
*
|
||||
* @returns Script
|
||||
* @returns Script
|
||||
*/
|
||||
Script.buildP2SHMultisigIn = function(pubkeys, threshold, signatures, opts) {
|
||||
opts = opts || {};
|
||||
|
@ -601,8 +607,10 @@ Script.buildDataOut = function(data) {
|
|||
data = new Buffer(data);
|
||||
}
|
||||
var s = new Script();
|
||||
s.add(Opcode.OP_RETURN)
|
||||
.add(data);
|
||||
s.add(Opcode.OP_RETURN);
|
||||
if (!_.isUndefined(data)) {
|
||||
s.add(data);
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
|
@ -663,4 +671,61 @@ Script.fromAddress = function(address) {
|
|||
throw new errors.Script.UnrecognizedAddress(address);
|
||||
};
|
||||
|
||||
/**
|
||||
* Analagous to bitcoind's FindAndDelete. Find and delete equivalent chunks,
|
||||
* typically used with push data chunks. Note that this will find and delete
|
||||
* not just the same data, but the same data with the same push data op as
|
||||
* produced by default. i.e., if a pushdata in a tx does not use the minimal
|
||||
* pushdata op, then when you try to remove the data it is pushing, it will not
|
||||
* be removed, because they do not use the same pushdata op.
|
||||
*/
|
||||
Script.prototype.findAndDelete = function(script) {
|
||||
var buf = script.toBuffer();
|
||||
var hex = buf.toString('hex');
|
||||
for (var i = 0; i < this.chunks.length; i++) {
|
||||
var script2 = Script({
|
||||
chunks: [this.chunks[i]]
|
||||
});
|
||||
var buf2 = script2.toBuffer();
|
||||
var hex2 = buf2.toString('hex');
|
||||
if (hex === hex2) {
|
||||
this.chunks.splice(i, 1);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns true if the chunk {i} is the smallest way to push that particular data.
|
||||
* Comes from bitcoind's script interpreter CheckMinimalPush function
|
||||
*/
|
||||
Script.prototype.checkMinimalPush = function(i) {
|
||||
var chunk = this.chunks[i];
|
||||
var buf = chunk.buf;
|
||||
var opcodenum = chunk.opcodenum;
|
||||
if (!buf) {
|
||||
return true;
|
||||
}
|
||||
if (buf.length === 0) {
|
||||
// Could have used OP_0.
|
||||
return opcodenum === Opcode.OP_0;
|
||||
} else if (buf.length === 1 && buf[0] >= 1 && buf[0] <= 16) {
|
||||
// Could have used OP_1 .. OP_16.
|
||||
return opcodenum === Opcode.OP_1 + (buf[0] - 1);
|
||||
} else if (buf.length === 1 && buf[0] === 0x81) {
|
||||
// Could have used OP_1NEGATE
|
||||
return opcodenum === Opcode.OP_1NEGATE;
|
||||
} else if (buf.length <= 75) {
|
||||
// Could have used a direct push (opcode indicating number of bytes pushed + those bytes).
|
||||
return opcodenum === buf.length;
|
||||
} else if (buf.length <= 255) {
|
||||
// Could have used OP_PUSHDATA.
|
||||
return opcodenum === Opcode.OP_PUSHDATA1;
|
||||
} else if (buf.length <= 65535) {
|
||||
// Could have used OP_PUSHDATA2.
|
||||
return opcodenum === Opcode.OP_PUSHDATA2;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
module.exports = Script;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,7 +4,7 @@ var _ = require('lodash');
|
|||
var errors = require('../../errors');
|
||||
var BufferWriter = require('../../encoding/bufferwriter');
|
||||
var buffer = require('buffer');
|
||||
var bufferUtil = require('../../util/buffer');
|
||||
var BufferUtil = require('../../util/buffer');
|
||||
var JSUtil = require('../../util/js');
|
||||
var Script = require('../../script');
|
||||
var Sighash = require('../sighash');
|
||||
|
@ -99,7 +99,7 @@ Input.prototype.setScript = function(script) {
|
|||
if (script instanceof Script) {
|
||||
this._script = script;
|
||||
this._scriptBuffer = script.toBuffer();
|
||||
} else if (bufferUtil.isBuffer(script)) {
|
||||
} else if (BufferUtil.isBuffer(script)) {
|
||||
this._script = null;
|
||||
this._scriptBuffer = new buffer.Buffer(script);
|
||||
} else {
|
||||
|
|
|
@ -10,6 +10,7 @@ var BufferWriter = require('../encoding/bufferwriter');
|
|||
var BN = require('../crypto/bn');
|
||||
var Hash = require('../crypto/hash');
|
||||
var ECDSA = require('../crypto/ecdsa');
|
||||
var $ = require('../util/preconditions');
|
||||
|
||||
var SIGHASH_SINGLE_BUG = '0000000000000000000000000000000000000000000000000000000000000001';
|
||||
var BITS_64_ON = 'ffffffffffffffff';
|
||||
|
@ -23,7 +24,7 @@ var BITS_64_ON = 'ffffffffffffffff';
|
|||
* @param {number} inputNumber the input index for the signature
|
||||
* @param {Script} subscript the script that will be signed
|
||||
*/
|
||||
function sighash(transaction, sighashType, inputNumber, subscript) {
|
||||
var sighash = function sighash(transaction, sighashType, inputNumber, subscript) {
|
||||
var Transaction = require('./transaction');
|
||||
var Input = require('./input');
|
||||
|
||||
|
@ -39,11 +40,11 @@ function sighash(transaction, sighashType, inputNumber, subscript) {
|
|||
// Blank signatures for other inputs
|
||||
txcopy.inputs[i] = new Input(txcopy.inputs[i]).setScript(Script.empty());
|
||||
}
|
||||
|
||||
|
||||
txcopy.inputs[inputNumber] = new Input(txcopy.inputs[inputNumber]).setScript(subscript);
|
||||
|
||||
if ((sighashType & 31) === Signature.SIGHASH_NONE ||
|
||||
(sighashType & 31) === Signature.SIGHASH_SINGLE) {
|
||||
(sighashType & 31) === Signature.SIGHASH_SINGLE) {
|
||||
|
||||
// clear all sequenceNumbers
|
||||
for (i = 0; i < txcopy.inputs.length; i++) {
|
||||
|
@ -84,21 +85,25 @@ function sighash(transaction, sighashType, inputNumber, subscript) {
|
|||
.write(txcopy.toBuffer())
|
||||
.writeInt32LE(sighashType)
|
||||
.toBuffer();
|
||||
return BufferReader(Hash.sha256sha256(buf)).readReverse();
|
||||
}
|
||||
var ret = Hash.sha256sha256(buf);
|
||||
ret = new BufferReader(ret).readReverse();
|
||||
return ret;
|
||||
};
|
||||
|
||||
function sign(transaction, keypair, nhashtype, nin, subscript) {
|
||||
var sign = function sign(transaction, keypair, nhashtype, nin, subscript) {
|
||||
var hashbuf = sighash(transaction, nhashtype, nin, subscript);
|
||||
hashbuf = new BufferReader(hashbuf).readReverse();
|
||||
var sig = ECDSA.sign(hashbuf, keypair, 'little').set({nhashtype: nhashtype});
|
||||
var sig = ECDSA.sign(hashbuf, keypair, 'little').set({
|
||||
nhashtype: nhashtype
|
||||
});
|
||||
return sig;
|
||||
}
|
||||
};
|
||||
|
||||
function verify(transaction, sig, pubkey, nin, subscript) {
|
||||
var verify = function verify(transaction, sig, pubkey, nin, subscript) {
|
||||
$.checkArgument(transaction);
|
||||
$.checkArgument(sig && sig.nhashtype);
|
||||
var hashbuf = sighash(transaction, sig.nhashtype, nin, subscript);
|
||||
hashbuf = new BufferReader(hashbuf).readReverse();
|
||||
return ECDSA.verify(hashbuf, sig, pubkey, 'little');
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
sighash: sighash,
|
||||
|
|
|
@ -11,6 +11,7 @@ var BufferReader = require('../encoding/bufferreader');
|
|||
var BufferWriter = require('../encoding/bufferwriter');
|
||||
var Hash = require('../crypto/hash');
|
||||
var Signature = require('../crypto/signature');
|
||||
var Sighash = require('./sighash');
|
||||
|
||||
var Address = require('../address');
|
||||
var Unit = require('../unit');
|
||||
|
@ -97,7 +98,7 @@ Transaction.prototype.serialize = Transaction.prototype.toString = function() {
|
|||
return this.toBuffer().toString('hex');
|
||||
};
|
||||
|
||||
Transaction.prototype.inspect = function () {
|
||||
Transaction.prototype.inspect = function() {
|
||||
return '<Transaction: ' + this.toString() + '>';
|
||||
};
|
||||
|
||||
|
@ -231,12 +232,16 @@ Transaction.prototype._fromNonP2SH = function(utxo) {
|
|||
};
|
||||
|
||||
Transaction._isNewUtxo = function(utxo) {
|
||||
var isDefined = function(param) { return !_.isUndefined(param); };
|
||||
var isDefined = function(param) {
|
||||
return !_.isUndefined(param);
|
||||
};
|
||||
return _.all(_.map([utxo.txId, utxo.outputIndex, utxo.satoshis, utxo.script], isDefined));
|
||||
};
|
||||
|
||||
Transaction._isOldUtxo = function(utxo) {
|
||||
var isDefined = function(param) { return !_.isUndefined(param); };
|
||||
var isDefined = function(param) {
|
||||
return !_.isUndefined(param);
|
||||
};
|
||||
return _.all(_.map([utxo.txid, utxo.vout, utxo.scriptPubKey, utxo.amount], isDefined));
|
||||
};
|
||||
|
||||
|
@ -383,4 +388,11 @@ Transaction.prototype.isValidSignature = function(signature) {
|
|||
return this.inputs[signature.inputIndex].isValidSignature(self, signature);
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {bool} whether the signature is valid for this transaction input
|
||||
*/
|
||||
Transaction.prototype.verify = function(sig, pubkey, nin, subscript) {
|
||||
return Sighash.verify(this, sig, pubkey, nin, subscript);
|
||||
};
|
||||
|
||||
module.exports = Transaction;
|
||||
|
|
|
@ -127,7 +127,7 @@ describe("ECDSA", function() {
|
|||
|
||||
it('should calculate the correct public key for this signature with low s', function() {
|
||||
ecdsa.k = BN('114860389168127852803919605627759231199925249596762615988727970217268189974335', 10);
|
||||
ecdsa.sig = Signature().fromString('3045022100ec3cfe0e335791ad278b4ec8eac93d0347a97877bb1d54d35d189e225c15f6650220278cf15b05ce47fb37d2233802899d94c774d5480bba9f0f2d996baa13370c43');
|
||||
ecdsa.sig = Signature.fromString('3045022100ec3cfe0e335791ad278b4ec8eac93d0347a97877bb1d54d35d189e225c15f6650220278cf15b05ce47fb37d2233802899d94c774d5480bba9f0f2d996baa13370c43');
|
||||
ecdsa.sig.i = 0;
|
||||
var pubkey = ecdsa.sig2pubkey();
|
||||
pubkey.point.eq(ecdsa.pubkey.point).should.equal(true);
|
||||
|
@ -136,7 +136,7 @@ describe("ECDSA", function() {
|
|||
it('should calculate the correct public key for this signature with high s', function() {
|
||||
ecdsa.k = BN('114860389168127852803919605627759231199925249596762615988727970217268189974335', 10);
|
||||
ecdsa.sign();
|
||||
ecdsa.sig = Signature().fromString('3046022100ec3cfe0e335791ad278b4ec8eac93d0347a97877bb1d54d35d189e225c15f665022100d8730ea4fa31b804c82ddcc7fd766269f33a079ea38e012c9238f2e2bcff34fe');
|
||||
ecdsa.sig = Signature.fromString('3046022100ec3cfe0e335791ad278b4ec8eac93d0347a97877bb1d54d35d189e225c15f665022100d8730ea4fa31b804c82ddcc7fd766269f33a079ea38e012c9238f2e2bcff34fe');
|
||||
ecdsa.sig.i = 1;
|
||||
var pubkey = ecdsa.sig2pubkey();
|
||||
pubkey.point.eq(ecdsa.pubkey.point).should.equal(true);
|
||||
|
@ -169,8 +169,7 @@ describe("ECDSA", function() {
|
|||
});
|
||||
|
||||
it('should return an error if the signature is incorrect', function() {
|
||||
ecdsa.sig = new Signature();
|
||||
ecdsa.sig.fromString('3046022100e9915e6236695f093a4128ac2a956c40ed971531de2f4f41ba05fac7e2bd019c02210094e6a4a769cc7f2a8ab3db696c7cd8d56bcdbfff860a8c81de4bc6a798b90827');
|
||||
ecdsa.sig = new Signature.fromString('3046022100e9915e6236695f093a4128ac2a956c40ed971531de2f4f41ba05fac7e2bd019c02210094e6a4a769cc7f2a8ab3db696c7cd8d56bcdbfff860a8c81de4bc6a798b90827');
|
||||
ecdsa.sig.r = ecdsa.sig.r.add(BN(1));
|
||||
ecdsa.sigError().should.equal("Invalid signature");
|
||||
});
|
||||
|
@ -235,8 +234,7 @@ describe("ECDSA", function() {
|
|||
describe('#verify', function() {
|
||||
|
||||
it('should verify a signature that was just signed', function() {
|
||||
ecdsa.sig = new Signature();
|
||||
ecdsa.sig.fromString('3046022100e9915e6236695f093a4128ac2a956c40ed971531de2f4f41ba05fac7e2bd019c02210094e6a4a769cc7f2a8ab3db696c7cd8d56bcdbfff860a8c81de4bc6a798b90827');
|
||||
ecdsa.sig = new Signature.fromString('3046022100e9915e6236695f093a4128ac2a956c40ed971531de2f4f41ba05fac7e2bd019c02210094e6a4a769cc7f2a8ab3db696c7cd8d56bcdbfff860a8c81de4bc6a798b90827');
|
||||
ecdsa.verify().verified.should.equal(true);
|
||||
});
|
||||
|
||||
|
|
|
@ -8,6 +8,23 @@ describe('Hash', function() {
|
|||
var buf = new Buffer([0, 1, 2, 3, 253, 254, 255]);
|
||||
var str = 'test string';
|
||||
|
||||
describe('@sha1', function() {
|
||||
|
||||
it('should calculate the hash of this buffer correctly', function() {
|
||||
var hash = Hash.sha1(buf);
|
||||
hash.toString('hex').should.equal('de69b8a4a5604d0486e6420db81e39eb464a17b2');
|
||||
hash = Hash.sha1(new Buffer(0));
|
||||
hash.toString('hex').should.equal('da39a3ee5e6b4b0d3255bfef95601890afd80709');
|
||||
});
|
||||
|
||||
it('should throw an error when the input is not a buffer', function() {
|
||||
(function() {
|
||||
Hash.sha1(str);
|
||||
}).should.throw('Invalid Argument');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#sha256', function() {
|
||||
|
||||
it('should calculate the hash of this buffer correctly', function() {
|
||||
|
@ -18,13 +35,13 @@ describe('Hash', function() {
|
|||
it('should throw an error when the input is not a buffer', function() {
|
||||
(function() {
|
||||
Hash.sha256(str);
|
||||
}).should.throw('sha256 hash must be of a buffer');
|
||||
}).should.throw('Invalid Argument');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#sha256hmac', function() {
|
||||
|
||||
|
||||
it('should compute this known empty test vector correctly', function() {
|
||||
var key = new Buffer('');
|
||||
var data = new Buffer('');
|
||||
|
@ -49,7 +66,7 @@ describe('Hash', function() {
|
|||
it('should throw an error when the input is not a buffer', function() {
|
||||
(function() {
|
||||
Hash.sha256sha256(str);
|
||||
}).should.throw('sha256sha256 hash must be of a buffer');
|
||||
}).should.throw('Invalid Argument');
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -64,7 +81,7 @@ describe('Hash', function() {
|
|||
it('should throw an error when the input is not a buffer', function() {
|
||||
(function() {
|
||||
Hash.sha256ripemd160(str);
|
||||
}).should.throw('sha256ripemd160 hash must be of a buffer');
|
||||
}).should.throw('Invalid Argument');
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -79,7 +96,7 @@ describe('Hash', function() {
|
|||
it('should throw an error when the input is not a buffer', function() {
|
||||
(function() {
|
||||
Hash.ripemd160(str);
|
||||
}).should.throw('ripemd160 hash must be of a buffer');
|
||||
}).should.throw('Invalid Argument');
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -94,7 +111,7 @@ describe('Hash', function() {
|
|||
it('should throw an error when the input is not a buffer', function() {
|
||||
(function() {
|
||||
Hash.sha512(str);
|
||||
}).should.throw('sha512 hash must be of a buffer');
|
||||
}).should.throw('Invalid Argument');
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -4,6 +4,10 @@ var should = require('chai').should();
|
|||
var bitcore = require('../..');
|
||||
var BN = bitcore.crypto.BN;
|
||||
var Signature = bitcore.crypto.Signature;
|
||||
var JSUtil = bitcore.util.js;
|
||||
|
||||
var sig_canonical = require('../data/bitcoind/sig_canonical');
|
||||
var sig_noncanonical = require('../data/bitcoind/sig_noncanonical');
|
||||
|
||||
describe('Signature', function() {
|
||||
|
||||
|
@ -41,8 +45,7 @@ describe('Signature', function() {
|
|||
blank,
|
||||
blank
|
||||
]);
|
||||
var sig = new Signature();
|
||||
sig.fromCompact(compressed);
|
||||
var sig = Signature.fromCompact(compressed);
|
||||
sig.r.cmp(0).should.equal(0);
|
||||
sig.s.cmp(0).should.equal(0);
|
||||
});
|
||||
|
@ -54,8 +57,7 @@ describe('Signature', function() {
|
|||
var buf = new Buffer('3044022075fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e62770220729e85cc46ffab881065ec07694220e71d4df9b2b8c8fd12c3122cf3a5efbcf2', 'hex');
|
||||
|
||||
it('should parse this DER format signature', function() {
|
||||
var sig = new Signature();
|
||||
sig.fromDER(buf);
|
||||
var sig = Signature.fromDER(buf);
|
||||
sig.r.toBuffer({
|
||||
size: 32
|
||||
}).toString('hex').should.equal('75fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e6277');
|
||||
|
@ -71,8 +73,7 @@ describe('Signature', function() {
|
|||
var buf = new Buffer('3044022075fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e62770220729e85cc46ffab881065ec07694220e71d4df9b2b8c8fd12c3122cf3a5efbcf2', 'hex');
|
||||
|
||||
it('should parse this DER format signature in hex', function() {
|
||||
var sig = new Signature();
|
||||
sig.fromString(buf.toString('hex'));
|
||||
var sig = Signature.fromString(buf.toString('hex'));
|
||||
sig.r.toBuffer({
|
||||
size: 32
|
||||
}).toString('hex').should.equal('75fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e6277');
|
||||
|
@ -83,6 +84,25 @@ describe('Signature', function() {
|
|||
|
||||
});
|
||||
|
||||
describe('#fromTxFormat', function() {
|
||||
|
||||
it('should convert from this known tx-format buffer', function() {
|
||||
var buf = new Buffer('30450221008bab1f0a2ff2f9cb8992173d8ad73c229d31ea8e10b0f4d4ae1a0d8ed76021fa02200993a6ec81755b9111762fc2cf8e3ede73047515622792110867d12654275e7201', 'hex');
|
||||
var sig = Signature.fromTxFormat(buf);
|
||||
sig.r.toString().should.equal('63173831029936981022572627018246571655303050627048489594159321588908385378810');
|
||||
sig.s.toString().should.equal('4331694221846364448463828256391194279133231453999942381442030409253074198130');
|
||||
sig.nhashtype.should.equal(Signature.SIGHASH_ALL);
|
||||
});
|
||||
|
||||
it('should parse this known signature and rebuild it', function() {
|
||||
var hex = "3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501";
|
||||
var buf = new Buffer(hex, 'hex');
|
||||
var sig = Signature.fromTxFormat(buf);
|
||||
sig.toTxFormat().toString('hex').should.equal(hex);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#parseDER', function() {
|
||||
|
||||
it('should parse this signature generated in node', function() {
|
||||
|
@ -133,6 +153,13 @@ describe('Signature', function() {
|
|||
parsed.s.toString().should.equal('44212963026209759051804639008236126356702363229859210154760104982946304432721');
|
||||
});
|
||||
|
||||
it('should parse this signature from script_valid.json', function() {
|
||||
var sighex = '304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef051';
|
||||
var sig = Buffer(sighex, 'hex');
|
||||
var parsed = Signature.parseDER(sig, false);
|
||||
should.exist(parsed);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#toDER', function() {
|
||||
|
@ -151,7 +178,6 @@ describe('Signature', function() {
|
|||
});
|
||||
|
||||
describe('#toString', function() {
|
||||
|
||||
it('should convert this signature in to hex DER', function() {
|
||||
var r = BN('63173831029936981022572627018246571655303050627048489594159321588908385378810');
|
||||
var s = BN('4331694221846364448463828256391194279133231453999942381442030409253074198130');
|
||||
|
@ -162,7 +188,62 @@ describe('Signature', function() {
|
|||
var hex = sig.toString();
|
||||
hex.should.equal('30450221008bab1f0a2ff2f9cb8992173d8ad73c229d31ea8e10b0f4d4ae1a0d8ed76021fa02200993a6ec81755b9111762fc2cf8e3ede73047515622792110867d12654275e72');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('@isTxDER', function() {
|
||||
it('should know this is a DER signature', function() {
|
||||
var sighex = '3042021e17cfe77536c3fb0526bd1a72d7a8e0973f463add210be14063c8a9c37632022061bfa677f825ded82ba0863fb0c46ca1388dd3e647f6a93c038168b59d131a5101';
|
||||
var sigbuf = new Buffer(sighex, 'hex');
|
||||
Signature.isTxDER(sigbuf).should.equal(true);
|
||||
});
|
||||
|
||||
it('should know this is not a DER signature', function() {
|
||||
//for more extensive tests, see the script interpreter
|
||||
var sighex = '3042021e17cfe77536c3fb0526bd1a72d7a8e0973f463add210be14063c8a9c37632022061bfa677f825ded82ba0863fb0c46ca1388dd3e647f6a93c038168b59d131a5101';
|
||||
var sigbuf = new Buffer(sighex, 'hex');
|
||||
sigbuf[0] = 0x31;
|
||||
Signature.isTxDER(sigbuf).should.equal(false);
|
||||
});
|
||||
|
||||
|
||||
describe('bitcoind fixtures', function() {
|
||||
var test_sigs = function(set, expected) {
|
||||
var i = 0;
|
||||
set.forEach(function(vector) {
|
||||
if (!JSUtil.isHexa(vector)) {
|
||||
// non-hex strings are ignored
|
||||
return;
|
||||
}
|
||||
it('should be ' + (expected ? '' : 'in') + 'valid for fixture #' + i, function() {
|
||||
var sighex = vector;
|
||||
Signature.isTxDER(new Buffer(sighex, 'hex')).should.equal(expected);
|
||||
});
|
||||
i++;
|
||||
});
|
||||
};
|
||||
test_sigs(sig_canonical, true);
|
||||
//test_sigs(sig_noncanonical, false);
|
||||
});
|
||||
|
||||
});
|
||||
describe('#hasLowS', function() {
|
||||
it('should detect high and low S', function() {
|
||||
var r = BN('63173831029936981022572627018246571655303050627048489594159321588908385378810');
|
||||
var s = BN('4331694221846364448463828256391194279133231453999942381442030409253074198130');
|
||||
var s2 = BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B2000');
|
||||
var sig = new Signature({
|
||||
r: r,
|
||||
s: s
|
||||
});
|
||||
var sig2 = new Signature({
|
||||
r: r,
|
||||
s: s2
|
||||
});
|
||||
sig2.hasLowS().should.equal(true);
|
||||
sig.hasLowS().should.equal(false);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[
|
||||
"300602010002010001",
|
||||
"3008020200ff020200ff01",
|
||||
"304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001",
|
||||
"30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01",
|
||||
"3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01"
|
||||
]
|
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
"non-hex strings are ignored",
|
||||
|
||||
"too short:", "30050201FF020001",
|
||||
"too long:", "30470221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"hashtype:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed11",
|
||||
"type:", "314402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"total length:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"S len oob:", "301F01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb101",
|
||||
"R+S:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed0001",
|
||||
|
||||
"R type:", "304401205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"R len = 0:", "3024020002202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"R<0:", "304402208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"R padded:", "30450221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
|
||||
|
||||
"S type:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610501202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"S len = 0:", "302402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105020001",
|
||||
"S<0:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01",
|
||||
"S padded:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"
|
||||
]
|
101
test/script.js
101
test/script.js
|
@ -7,7 +7,6 @@ var Opcode = bitcore.Opcode;
|
|||
var PublicKey = bitcore.PublicKey;
|
||||
var Address = bitcore.Address;
|
||||
|
||||
|
||||
describe('Script', function() {
|
||||
|
||||
it('should make a new script', function() {
|
||||
|
@ -19,7 +18,7 @@ describe('Script', function() {
|
|||
|
||||
it('should parse this buffer containing an OP code', function() {
|
||||
var buf = new Buffer(1);
|
||||
buf[0] = Opcode('OP_0').toNumber();
|
||||
buf[0] = Opcode.OP_0;
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(1);
|
||||
script.chunks[0].opcodenum.should.equal(buf[0]);
|
||||
|
@ -27,7 +26,7 @@ describe('Script', function() {
|
|||
|
||||
it('should parse this buffer containing another OP code', function() {
|
||||
var buf = new Buffer(1);
|
||||
buf[0] = Opcode('OP_CHECKMULTISIG').toNumber();
|
||||
buf[0] = Opcode.OP_CHECKMULTISIG;
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(1);
|
||||
script.chunks[0].opcodenum.should.equal(buf[0]);
|
||||
|
@ -42,7 +41,7 @@ describe('Script', function() {
|
|||
|
||||
it('should parse this buffer containing OP_PUSHDATA1 and three bytes of data', function() {
|
||||
var buf = new Buffer([0, 0, 1, 2, 3]);
|
||||
buf[0] = Opcode('OP_PUSHDATA1').toNumber();
|
||||
buf[0] = Opcode.OP_PUSHDATA1;
|
||||
buf.writeUInt8(3, 1);
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(1);
|
||||
|
@ -51,7 +50,7 @@ describe('Script', function() {
|
|||
|
||||
it('should parse this buffer containing OP_PUSHDATA2 and three bytes of data', function() {
|
||||
var buf = new Buffer([0, 0, 0, 1, 2, 3]);
|
||||
buf[0] = Opcode('OP_PUSHDATA2').toNumber();
|
||||
buf[0] = Opcode.OP_PUSHDATA2;
|
||||
buf.writeUInt16LE(3, 1);
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(1);
|
||||
|
@ -60,7 +59,7 @@ describe('Script', function() {
|
|||
|
||||
it('should parse this buffer containing OP_PUSHDATA4 and three bytes of data', function() {
|
||||
var buf = new Buffer([0, 0, 0, 0, 0, 1, 2, 3]);
|
||||
buf[0] = Opcode('OP_PUSHDATA4').toNumber();
|
||||
buf[0] = Opcode.OP_PUSHDATA4;
|
||||
buf.writeUInt16LE(3, 1);
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(1);
|
||||
|
@ -69,10 +68,10 @@ describe('Script', function() {
|
|||
|
||||
it('should parse this buffer an OP code, data, and another OP code', function() {
|
||||
var buf = new Buffer([0, 0, 0, 0, 0, 0, 1, 2, 3, 0]);
|
||||
buf[0] = Opcode('OP_0').toNumber();
|
||||
buf[1] = Opcode('OP_PUSHDATA4').toNumber();
|
||||
buf[0] = Opcode.OP_0;
|
||||
buf[1] = Opcode.OP_PUSHDATA4;
|
||||
buf.writeUInt16LE(3, 2);
|
||||
buf[buf.length - 1] = Opcode('OP_0').toNumber();
|
||||
buf[buf.length - 1] = Opcode.OP_0;
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(3);
|
||||
script.chunks[0].opcodenum.should.equal(buf[0]);
|
||||
|
@ -86,7 +85,7 @@ describe('Script', function() {
|
|||
|
||||
it('should output this buffer containing an OP code', function() {
|
||||
var buf = new Buffer(1);
|
||||
buf[0] = Opcode('OP_0').toNumber();
|
||||
buf[0] = Opcode.OP_0;
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(1);
|
||||
script.chunks[0].opcodenum.should.equal(buf[0]);
|
||||
|
@ -95,7 +94,7 @@ describe('Script', function() {
|
|||
|
||||
it('should output this buffer containing another OP code', function() {
|
||||
var buf = new Buffer(1);
|
||||
buf[0] = Opcode('OP_CHECKMULTISIG').toNumber();
|
||||
buf[0] = Opcode.OP_CHECKMULTISIG;
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(1);
|
||||
script.chunks[0].opcodenum.should.equal(buf[0]);
|
||||
|
@ -112,7 +111,7 @@ describe('Script', function() {
|
|||
|
||||
it('should output this buffer containing OP_PUSHDATA1 and three bytes of data', function() {
|
||||
var buf = new Buffer([0, 0, 1, 2, 3]);
|
||||
buf[0] = Opcode('OP_PUSHDATA1').toNumber();
|
||||
buf[0] = Opcode.OP_PUSHDATA1;
|
||||
buf.writeUInt8(3, 1);
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(1);
|
||||
|
@ -122,7 +121,7 @@ describe('Script', function() {
|
|||
|
||||
it('should output this buffer containing OP_PUSHDATA2 and three bytes of data', function() {
|
||||
var buf = new Buffer([0, 0, 0, 1, 2, 3]);
|
||||
buf[0] = Opcode('OP_PUSHDATA2').toNumber();
|
||||
buf[0] = Opcode.OP_PUSHDATA2;
|
||||
buf.writeUInt16LE(3, 1);
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(1);
|
||||
|
@ -132,7 +131,7 @@ describe('Script', function() {
|
|||
|
||||
it('should output this buffer containing OP_PUSHDATA4 and three bytes of data', function() {
|
||||
var buf = new Buffer([0, 0, 0, 0, 0, 1, 2, 3]);
|
||||
buf[0] = Opcode('OP_PUSHDATA4').toNumber();
|
||||
buf[0] = Opcode.OP_PUSHDATA4;
|
||||
buf.writeUInt16LE(3, 1);
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(1);
|
||||
|
@ -142,10 +141,10 @@ describe('Script', function() {
|
|||
|
||||
it('should output this buffer an OP code, data, and another OP code', function() {
|
||||
var buf = new Buffer([0, 0, 0, 0, 0, 0, 1, 2, 3, 0]);
|
||||
buf[0] = Opcode('OP_0').toNumber();
|
||||
buf[1] = Opcode('OP_PUSHDATA4').toNumber();
|
||||
buf[0] = Opcode.OP_0;
|
||||
buf[1] = Opcode.OP_PUSHDATA4;
|
||||
buf.writeUInt16LE(3, 2);
|
||||
buf[buf.length - 1] = Opcode('OP_0').toNumber();
|
||||
buf[buf.length - 1] = Opcode.OP_0;
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(3);
|
||||
script.chunks[0].opcodenum.should.equal(buf[0]);
|
||||
|
@ -176,10 +175,10 @@ describe('Script', function() {
|
|||
|
||||
it('should output this buffer an OP code, data, and another OP code', function() {
|
||||
var buf = new Buffer([0, 0, 0, 0, 0, 0, 1, 2, 3, 0]);
|
||||
buf[0] = Opcode('OP_0').toNumber();
|
||||
buf[1] = Opcode('OP_PUSHDATA4').toNumber();
|
||||
buf[0] = Opcode.OP_0;
|
||||
buf[1] = Opcode.OP_PUSHDATA4;
|
||||
buf.writeUInt16LE(3, 2);
|
||||
buf[buf.length - 1] = Opcode('OP_0').toNumber();
|
||||
buf[buf.length - 1] = Opcode.OP_0;
|
||||
var script = Script.fromBuffer(buf);
|
||||
script.chunks.length.should.equal(3);
|
||||
script.chunks[0].opcodenum.should.equal(buf[0]);
|
||||
|
@ -349,12 +348,11 @@ describe('Script', function() {
|
|||
describe('#add and #prepend', function() {
|
||||
|
||||
it('should add these ops', function() {
|
||||
Script().add(Opcode('OP_RETURN')).add(new Buffer('')).toString().should.equal('OP_RETURN');
|
||||
});
|
||||
it('should add these ops', function() {
|
||||
Script().add(1).add(10).add(186).toString().should.equal('0x01 0x0a 0xba');
|
||||
Script().add(1000).toString().should.equal('0x03e8');
|
||||
Script().add('OP_CHECKMULTISIG').toString().should.equal('OP_CHECKMULTISIG');
|
||||
Script().add('OP_1').add('OP_2').toString().should.equal('OP_1 OP_2');
|
||||
Script().add(new Opcode('OP_CHECKMULTISIG')).toString().should.equal('OP_CHECKMULTISIG');
|
||||
Script().add(Opcode.OP_CHECKMULTISIG).toString().should.equal('OP_CHECKMULTISIG');
|
||||
Script().add(Opcode.map.OP_CHECKMULTISIG).toString().should.equal('OP_CHECKMULTISIG');
|
||||
});
|
||||
|
||||
|
@ -390,6 +388,10 @@ describe('Script', function() {
|
|||
buf.fill(0);
|
||||
Script().add(buf).toString().should.equal('1 0x00');
|
||||
});
|
||||
|
||||
it('should work for no data OP_RETURN', function() {
|
||||
Script().add(Opcode.OP_RETURN).add(new Buffer('')).toString().should.equal('OP_RETURN 0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isStandard', function() {
|
||||
|
@ -469,11 +471,17 @@ describe('Script', function() {
|
|||
});
|
||||
});
|
||||
describe('#buildDataOut', function() {
|
||||
it('should create script from no data', function() {
|
||||
var s = Script.buildDataOut();
|
||||
should.exist(s);
|
||||
s.toString().should.equal('OP_RETURN');
|
||||
s.isDataOut().should.equal(true);
|
||||
});
|
||||
it('should create script from empty data', function() {
|
||||
var data = new Buffer('');
|
||||
var s = Script.buildDataOut(data);
|
||||
should.exist(s);
|
||||
s.toString().should.equal('OP_RETURN');
|
||||
s.toString().should.equal('OP_RETURN 0');
|
||||
s.isDataOut().should.equal(true);
|
||||
});
|
||||
it('should create script from some data', function() {
|
||||
|
@ -515,4 +523,47 @@ describe('Script', function() {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
describe('#findAndDelete', function() {
|
||||
it('should find and delete this buffer', function() {
|
||||
Script('OP_RETURN 2 0xf0f0')
|
||||
.findAndDelete(Script('2 0xf0f0'))
|
||||
.toString()
|
||||
.should.equal('OP_RETURN');
|
||||
});
|
||||
it('should do nothing', function() {
|
||||
Script('OP_RETURN 2 0xf0f0')
|
||||
.findAndDelete(Script('2 0xffff'))
|
||||
.toString()
|
||||
.should.equal('OP_RETURN 2 0xf0f0');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('#checkMinimalPush', function() {
|
||||
|
||||
it('should check these minimal pushes', function() {
|
||||
Script().add(1).checkMinimalPush(0).should.equal(true);
|
||||
Script().add(0).checkMinimalPush(0).should.equal(true);
|
||||
Script().add(-1).checkMinimalPush(0).should.equal(true);
|
||||
Script().add(1000).checkMinimalPush(0).should.equal(true);
|
||||
Script().add(0xffffffff).checkMinimalPush(0).should.equal(true);
|
||||
Script().add(0xffffffffffffffff).checkMinimalPush(0).should.equal(true);
|
||||
Script().add(new Buffer([0])).checkMinimalPush(0).should.equal(true);
|
||||
|
||||
var buf = new Buffer(75);
|
||||
buf.fill(1);
|
||||
Script().add(buf).checkMinimalPush(0).should.equal(true);
|
||||
|
||||
buf = new Buffer(76);
|
||||
buf.fill(1);
|
||||
Script().add(buf).checkMinimalPush(0).should.equal(true);
|
||||
|
||||
buf = new Buffer(256);
|
||||
buf.fill(1);
|
||||
Script().add(buf).checkMinimalPush(0).should.equal(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -0,0 +1,315 @@
|
|||
'use strict';
|
||||
|
||||
var should = require('chai').should();
|
||||
var bitcore = require('..');
|
||||
var ScriptInterpreter = bitcore.ScriptInterpreter;
|
||||
var Transaction = bitcore.Transaction;
|
||||
var Script = bitcore.Script;
|
||||
var BN = bitcore.crypto.BN;
|
||||
var BufferReader = bitcore.encoding.BufferReader;
|
||||
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||
var Opcode = bitcore.Opcode;
|
||||
|
||||
var script_valid = require('./data/bitcoind/script_valid');
|
||||
var script_invalid = require('./data/bitcoind/script_invalid');
|
||||
var tx_valid = require('./transaction/tx_valid');
|
||||
var tx_invalid = require('./transaction/tx_invalid');
|
||||
|
||||
//the script string format used in bitcoind data tests
|
||||
Script.fromBitcoindString = function(str) {
|
||||
var bw = new BufferWriter();
|
||||
var tokens = str.split(' ');
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
var token = tokens[i];
|
||||
if (token === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var opstr;
|
||||
var opcodenum;
|
||||
var tbuf;
|
||||
if (token[0] === '0' && token[1] === 'x') {
|
||||
var hex = token.slice(2);
|
||||
bw.write(new Buffer(hex, 'hex'));
|
||||
} else if (token[0] === '\'') {
|
||||
var tstr = token.slice(1, token.length - 1);
|
||||
var cbuf = new Buffer(tstr);
|
||||
tbuf = Script().add(cbuf).toBuffer();
|
||||
bw.write(tbuf);
|
||||
} else if (typeof Opcode['OP_' + token] !== 'undefined') {
|
||||
opstr = 'OP_' + token;
|
||||
opcodenum = Opcode[opstr];
|
||||
bw.writeUInt8(opcodenum);
|
||||
} else if (typeof Opcode[token] === 'number') {
|
||||
opstr = token;
|
||||
opcodenum = Opcode[opstr];
|
||||
bw.writeUInt8(opcodenum);
|
||||
} else if (!isNaN(parseInt(token))) {
|
||||
var script = Script().add(BN(token).toScriptNumBuffer());
|
||||
tbuf = script.toBuffer();
|
||||
bw.write(tbuf);
|
||||
} else {
|
||||
throw new Error('Could not determine type of script value');
|
||||
}
|
||||
}
|
||||
var buf = bw.concat();
|
||||
return this.fromBuffer(buf);
|
||||
};
|
||||
|
||||
|
||||
|
||||
describe('ScriptInterpreter', function() {
|
||||
|
||||
it('should make a new interp', function() {
|
||||
var interp = new ScriptInterpreter();
|
||||
(interp instanceof ScriptInterpreter).should.equal(true);
|
||||
interp.stack.length.should.equal(0);
|
||||
interp.altstack.length.should.equal(0);
|
||||
interp.pc.should.equal(0);
|
||||
interp.pbegincodehash.should.equal(0);
|
||||
interp.nOpCount.should.equal(0);
|
||||
interp.vfExec.length.should.equal(0);
|
||||
interp.errstr.should.equal('');
|
||||
interp.flags.should.equal(0);
|
||||
});
|
||||
|
||||
describe('@castToBool', function() {
|
||||
|
||||
it('should cast these bufs to bool correctly', function() {
|
||||
ScriptInterpreter.castToBool(BN(0).toSM({
|
||||
endian: 'little'
|
||||
})).should.equal(false);
|
||||
ScriptInterpreter.castToBool(new Buffer('0080', 'hex')).should.equal(false); //negative 0
|
||||
ScriptInterpreter.castToBool(BN(1).toSM({
|
||||
endian: 'little'
|
||||
})).should.equal(true);
|
||||
ScriptInterpreter.castToBool(BN(-1).toSM({
|
||||
endian: 'little'
|
||||
})).should.equal(true);
|
||||
|
||||
var buf = new Buffer('00', 'hex');
|
||||
var bool = BN().fromSM(buf, {
|
||||
endian: 'little'
|
||||
}).cmp(0) !== 0;
|
||||
ScriptInterpreter.castToBool(buf).should.equal(bool);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#verify', function() {
|
||||
|
||||
it('should verify these trivial scripts', function() {
|
||||
var verified;
|
||||
var si = ScriptInterpreter();
|
||||
verified = si.verify(Script('OP_1'), Script('OP_1'));
|
||||
verified.should.equal(true);
|
||||
verified = ScriptInterpreter().verify(Script('OP_1'), Script('OP_0'));
|
||||
verified.should.equal(false);
|
||||
verified = ScriptInterpreter().verify(Script('OP_0'), Script('OP_1'));
|
||||
verified.should.equal(true);
|
||||
verified = ScriptInterpreter().verify(Script('OP_CODESEPARATOR'), Script('OP_1'));
|
||||
verified.should.equal(true);
|
||||
verified = ScriptInterpreter().verify(Script(''), Script('OP_DEPTH OP_0 OP_EQUAL'));
|
||||
verified.should.equal(true);
|
||||
verified = ScriptInterpreter().verify(Script('OP_1 OP_2'), Script('OP_2 OP_EQUALVERIFY OP_1 OP_EQUAL'));
|
||||
verified.should.equal(true);
|
||||
verified = ScriptInterpreter().verify(Script('9 0x000000000000000010'), Script(''));
|
||||
verified.should.equal(true);
|
||||
verified = ScriptInterpreter().verify(Script('OP_1'), Script('OP_15 OP_ADD OP_16 OP_EQUAL'));
|
||||
verified.should.equal(true);
|
||||
verified = ScriptInterpreter().verify(Script('OP_0'), Script('OP_IF OP_VER OP_ELSE OP_1 OP_ENDIF'));
|
||||
verified.should.equal(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
var getFlags = function getFlags(flagstr) {
|
||||
var flags = 0;
|
||||
if (flagstr.indexOf('NONE') !== -1) {
|
||||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_NONE;
|
||||
}
|
||||
if (flagstr.indexOf('P2SH') !== -1) {
|
||||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_P2SH;
|
||||
}
|
||||
if (flagstr.indexOf('STRICTENC') !== -1) {
|
||||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_STRICTENC;
|
||||
}
|
||||
if (flagstr.indexOf('DERSIG') !== -1) {
|
||||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_DERSIG;
|
||||
}
|
||||
if (flagstr.indexOf('LOW_S') !== -1) {
|
||||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_LOW_S;
|
||||
}
|
||||
if (flagstr.indexOf('NULLDUMMY') !== -1) {
|
||||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_NULLDUMMY;
|
||||
}
|
||||
if (flagstr.indexOf('SIGPUSHONLY') !== -1) {
|
||||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_SIGPUSHONLY;
|
||||
}
|
||||
if (flagstr.indexOf('MINIMALDATA') !== -1) {
|
||||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_MINIMALDATA;
|
||||
}
|
||||
if (flagstr.indexOf('DISCOURAGE_UPGRADABLE_NOPS') !== -1) {
|
||||
flags = flags | ScriptInterpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS;
|
||||
}
|
||||
return flags;
|
||||
};
|
||||
|
||||
|
||||
var testToFromString = function(script) {
|
||||
var s = script.toString();
|
||||
Script.fromString(s).toString().should.equal(s);
|
||||
};
|
||||
|
||||
var testFixture = function(vector, expected) {
|
||||
var scriptSig = Script.fromBitcoindString(vector[0]);
|
||||
var scriptPubkey = Script.fromBitcoindString(vector[1]);
|
||||
var flags = getFlags(vector[2]);
|
||||
|
||||
|
||||
//testToFromString(scriptSig);
|
||||
//testToFromString(scriptPubkey);
|
||||
|
||||
var hashbuf = new Buffer(32);
|
||||
hashbuf.fill(0);
|
||||
var credtx = Transaction();
|
||||
credtx.inputs.push(new Transaction.Input({
|
||||
prevTxId: '0000000000000000000000000000000000000000000000000000000000000000',
|
||||
outputIndex: 0xffffffff,
|
||||
sequenceNumber: 0xffffffff,
|
||||
script: Script('OP_0 OP_0')
|
||||
}));
|
||||
credtx._addOutput(new Transaction.Output({
|
||||
script: scriptPubkey,
|
||||
satoshis: 0
|
||||
}));
|
||||
var idbuf = credtx.id;
|
||||
|
||||
var spendtx = Transaction();
|
||||
spendtx.inputs.push(new Transaction.Input({
|
||||
prevTxId: idbuf.toString('hex'),
|
||||
outputIndex: 0,
|
||||
sequenceNumber: 0xffffffff,
|
||||
script: scriptSig
|
||||
}));
|
||||
spendtx._addOutput(new Transaction.Output({
|
||||
script: Script(),
|
||||
satoshis: 0
|
||||
}));
|
||||
|
||||
var interp = ScriptInterpreter();
|
||||
var verified = interp.verify(scriptSig, scriptPubkey, spendtx, 0, flags);
|
||||
verified.should.equal(expected);
|
||||
};
|
||||
describe('bitcoind fixtures', function() {
|
||||
var testAllFixtures = function(set, expected) {
|
||||
var c = 0;
|
||||
set.forEach(function(vector) {
|
||||
if (vector.length === 1) {
|
||||
return;
|
||||
}
|
||||
c++;
|
||||
var descstr = vector[3];
|
||||
var fullScriptString = vector[0] + ' ' + vector[1];
|
||||
var comment = descstr ? (' (' + descstr + ')') : '';
|
||||
it('should pass script_' + (expected ? '' : 'in') + 'valid vector #' + c + ': ' + fullScriptString + comment, function() {
|
||||
testFixture(vector, expected);
|
||||
});
|
||||
});
|
||||
};
|
||||
testAllFixtures(script_valid, true);
|
||||
testAllFixtures(script_invalid, false);
|
||||
|
||||
var c = 0;
|
||||
tx_valid.forEach(function(vector) {
|
||||
if (vector.length === 1) {
|
||||
return;
|
||||
}
|
||||
c++;
|
||||
it.skip('should pass tx_valid vector ' + c, function() {
|
||||
var inputs = vector[0];
|
||||
var txhex = vector[1];
|
||||
var flags = getFlags(vector[2]);
|
||||
|
||||
var map = {};
|
||||
inputs.forEach(function(input) {
|
||||
var txid = input[0];
|
||||
var txoutnum = input[1];
|
||||
var scriptPubKeyStr = input[2];
|
||||
if (txoutnum === -1) {
|
||||
txoutnum = 0xffffffff; //bitcoind casts -1 to an unsigned int
|
||||
}
|
||||
var txkey = txid + ':' + txoutnum;
|
||||
map[txkey] = Script.fromBitcoindString(scriptPubKeyStr);
|
||||
});
|
||||
|
||||
var tx = Transaction(txhex);
|
||||
tx.inputs.forEach(function(txin, j) {
|
||||
var scriptSig = txin.script;
|
||||
var txidhex = txin.prevTxId.toString('hex');
|
||||
var txoutnum = txin.outputIndex;
|
||||
var txkey = txidhex + ':' + txoutnum;
|
||||
var scriptPubkey = map[txkey];
|
||||
should.exist(scriptPubkey);
|
||||
var interp = ScriptInterpreter();
|
||||
var verified = interp.verify(scriptSig, scriptPubkey, tx, j, flags);
|
||||
verified.should.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
c = 0;
|
||||
tx_invalid.forEach(function(vector) {
|
||||
if (vector.length === 1) {
|
||||
return;
|
||||
}
|
||||
c++;
|
||||
|
||||
// tests intentionally not performed by the script interpreter:
|
||||
// TODO: check this?
|
||||
/*
|
||||
if (c === 7 || // tests if valuebn is negative
|
||||
c === 8 || // tests if valuebn is greater than MAX_MONEY
|
||||
c === 10 || // tests if two inputs are equal
|
||||
c === 11 || // coinbase
|
||||
c === 12 || // coinbase
|
||||
c === 13 // null input
|
||||
) {
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
it.skip('should pass tx_invalid vector ' + c, function() {
|
||||
var inputs = vector[0];
|
||||
var txhex = vector[1];
|
||||
var flags = getFlags(vector[2]);
|
||||
|
||||
var map = {};
|
||||
inputs.forEach(function(input) {
|
||||
var txoutnum = input[1];
|
||||
if (txoutnum === -1) {
|
||||
txoutnum = 0xffffffff; //bitcoind casts -1 to an unsigned int
|
||||
}
|
||||
map[input[0] + ':' + txoutnum] = Script.fromBitcoindString(input[2]);
|
||||
});
|
||||
|
||||
var tx = Transaction().fromBuffer(new Buffer(txhex, 'hex'));
|
||||
if (tx.txins.length > 0) {
|
||||
tx.txins.some(function(txin, j) {
|
||||
var scriptSig = txin.script;
|
||||
var txidhex = BufferReader(txin.txidbuf).readReverse().toString('hex');
|
||||
var txoutnum = txin.txoutnum;
|
||||
var scriptPubkey = map[txidhex + ':' + txoutnum];
|
||||
should.exist(scriptPubkey);
|
||||
var interp = ScriptInterpreter();
|
||||
var verified = interp.verify(scriptSig, scriptPubkey, tx, j, flags);
|
||||
return verified === false;
|
||||
}).should.equal(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -14,7 +14,7 @@ module.exports = [
|
|||
}],
|
||||
'to', ['mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc', 1010000],
|
||||
'sign', ['cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY'],
|
||||
'serialize', '01000000015884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a4000000006b4830450221009972100061da4a17a471ac1906c18bb5445c03da2a0be52c59aca6c58f1e342302205eac5ba43830a397f613f40addea4a2eeaa485a1f9a6efa61344c3560762fe3d01210223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5effffffff0150690f00000000001976a9147821c0a3768aa9d1a37e16cf76002aef5373f1a888ac00000000'
|
||||
'serialize', '01000000015884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a4000000006a473044022013fa3089327b50263029265572ae1b022a91d10ac80eb4f32f291c914533670b02200d8a5ed5f62634a7e1a0dc9188a3cc460a986267ae4d58faf50c79105431327501210223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5effffffff0150690f00000000001976a9147821c0a3768aa9d1a37e16cf76002aef5373f1a888ac00000000'
|
||||
],
|
||||
[
|
||||
'from', [{
|
||||
|
@ -27,7 +27,7 @@ module.exports = [
|
|||
'to', ['mn9new5vPYWuVN5m3gUBujfKh1uPQvR9mf', 500000],
|
||||
'to', ['mw5ctwgEaNRbxkM4JhXH3rp5AyGvTWDZCD', 570000],
|
||||
'sign', ['cSQUuwwJBAg6tYQhzqqLWW115D1s5KFZDyhCF2ffrnukZxMK6rNZ'],
|
||||
'serialize', '0100000001863957ca797bf847eae50f6999e4c3616dc64b1e6661b16d9da2b57d184724e4010000006b483045022100855691c90510edf83ab632f0a0b17f5202d2cf7071050dcf0c2778325ed403cd02207270a2f0b30c13dc3c1dee74b5ccabcc2632b402c4f38adabcd07357df1442270121039dd446bbc85db6917f39c0b4c295b0f8cce76d1926fa76d7b84e3f7ff1c5eec5ffffffff0220a10700000000001976a91448c819246ae5645ceecd41fbe1aa6202a0a9b5ca88ac90b20800000000001976a914aab76ba4877d696590d94ea3e02948b55294815188ac00000000'
|
||||
'serialize', '0100000001863957ca797bf847eae50f6999e4c3616dc64b1e6661b16d9da2b57d184724e4010000006b4830450221009d23f7c1e790ecf839e0e53248dacfa559194735e477aa3ee5897fd74fe3ec0402205eff578518e7c59beeb03ee85e5c4b5bc2730addca2f0321d80aadfbcc1976de0121039dd446bbc85db6917f39c0b4c295b0f8cce76d1926fa76d7b84e3f7ff1c5eec5ffffffff0220a10700000000001976a91448c819246ae5645ceecd41fbe1aa6202a0a9b5ca88ac90b20800000000001976a914aab76ba4877d696590d94ea3e02948b55294815188ac00000000'
|
||||
],
|
||||
[
|
||||
'from', [[{
|
||||
|
@ -49,7 +49,7 @@ module.exports = [
|
|||
}]],
|
||||
'to', ['mtymcCX5KixPjT1zxtg59qewBGWptj9etH', 1060000],
|
||||
'sign', [['cPGbA2C54ZZ1sw4dc2ckBE1WqkdrNSbEV8Tkjhi2p1J15oErdgP2', 'cSpyve5bXAuyHrNeV9MjTdFz3HLw739yUjjUAUSMe3ppf2qzj2hw']],
|
||||
'serialize', '0100000002b3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9000000006a4730440220635e95e1981bbb360feaf4c232f626a0af8eb5c043a99749a21b0e37fd0048fd02207889f6974f0cad39ce8c2a6dff05c8ca402da9ff6fc41e06c12d86853c91a9d80121030253c73236acf5ea9085d408220141197f6094de07426bd0d32c7a543614fdd7ffffffffb3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9010000006a4730440220319a0b5ee9c67ccb7de4222234f31059354be4f239c99ca24bff30adfec8e8ec022056e6e99e50f7ceaa062958b8424cde1d504019f95c1dc0a0f0778848d0fb9f4b012102977a001a0a7bbfd1f8a647c7d46e13e8f6920635b328390b43b3303977101149ffffffff01a02c1000000000001976a91493abf1e9e4a20c125b93f93ee39efc16b6e4bc4688ac00000000'
|
||||
'serialize', '0100000002b3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9000000006a47304402205d591b93871b63205ea80f6976b4d76ce23ca95c825d0c74b44e9816c9488ae8022012476dd8a2780028ed3e72ac1f2620580e82a25c22d1c31afca6fb14b125a35c0121030253c73236acf5ea9085d408220141197f6094de07426bd0d32c7a543614fdd7ffffffffb3028cf4ae5b4b6d8f79ab6fc0dd251b28ab28287d33861e35c90f6e5684dba9010000006a4730440220320367535c9bc525c581939b36ebe70dd0845851e68fa9e3cf2d90642bf551b3022055d6fcaef32d9b584eea757fa633c31449f43272d131588ddd87a22d16dd7129012102977a001a0a7bbfd1f8a647c7d46e13e8f6920635b328390b43b3303977101149ffffffff01a02c1000000000001976a91493abf1e9e4a20c125b93f93ee39efc16b6e4bc4688ac00000000'
|
||||
],
|
||||
[
|
||||
'from', [{
|
||||
|
@ -62,7 +62,7 @@ module.exports = [
|
|||
}],
|
||||
'to', ['2NEQb8rtiUgxqQ9eif4XVeMUEW2LSZ64s58', 1050000],
|
||||
'sign', ['cMh7xdJ5EZVg6kvFsBybwK1EYGJw3G1DHhe5sNPAwbDts94ohKyK'],
|
||||
'serialize', '01000000019c58233f15d582a2e969d37bd05f2e0cb52994015defc65eaec7de64b9cebec8000000006a473044022050442862e892b1d12bcaa03857746f0ed168122e093d799861f4e081756bb8aa0220081d4eaf9281ae8f954efaeb47500d9a02e5a74b3ada51b6a258ac83c1f4f6420121039dbeac2610d53eb7107b14c0fa9be4006a731fa5bcef392d4e1a25ec0e58f0d3ffffffff01900510000000000017a91490edc43da6b052c4a23fc178979ce358a8caad5e8700000000'
|
||||
'serialize', '01000000019c58233f15d582a2e969d37bd05f2e0cb52994015defc65eaec7de64b9cebec8000000006a47304402205db94e075d4cf740c69e878fa0079e004bbc323be71b1f8944de702b362ca6880220616e2791168e0a2ffc36dc1847f46b79d7ffb5314ae20ee4066feea2b5a32cdc0121039dbeac2610d53eb7107b14c0fa9be4006a731fa5bcef392d4e1a25ec0e58f0d3ffffffff01900510000000000017a91490edc43da6b052c4a23fc178979ce358a8caad5e8700000000'
|
||||
],
|
||||
[
|
||||
'from', [{
|
||||
|
@ -74,6 +74,18 @@ module.exports = [
|
|||
}, ['03fd45c8cd28c4c6a9a89b4515173edebc66a2418353976eccf01c73a7da9bbb12', '0349e0138b2c2f496121258e0426e1dbd698b2c6038e70fd17e3563aa87b4384f9'], 2],
|
||||
'to', ['mssMdcEm6PiJEr4XZtjk6kkai84EjBbi91', 1040000],
|
||||
'sign', [['L3wRFe9XHLnkLquf41F56ac77uRXwJ97HZPQ9tppqyMANBKXpoc5', 'KzkfNSL1gvdyU3CGLaP1Cs3pW167M8r9uE8yMtWQrAzz5vCv59CM']],
|
||||
'serialize', '010000000140c1ae9d6933e4a08594f814ba73a4e94d19c8a83f45784b1684b3a3f84ee66600000000da004730440220366678972728684a94f35635b855583603b28065d430949c08be89412a4ee45d02201aa62e3129c8819ecf2048230e8c77e244d6a496f296954a5bb4a0d0185f8c0201483045022100d06f348b4ef793f2bf749b288f1df165c0946779391c50ddc050e5b1608b2dda02200fcc8c6874b9a313374020253c5de346fe3517c97b18bfa769cea1089ad97144014752210349e0138b2c2f496121258e0426e1dbd698b2c6038e70fd17e3563aa87b4384f92103fd45c8cd28c4c6a9a89b4515173edebc66a2418353976eccf01c73a7da9bbb1252aeffffffff0180de0f00000000001976a914877d4f3be444448f868b345153bc4fc7a11a7c6388ac00000000'
|
||||
'serialize', '010000000140c1ae9d6933e4a08594f814ba73a4e94d19c8a83f45784b1684b3a3f84ee66600000000d900473044022057c6961adc330ad231f7e1e58f46987637118f85f5f621425a401c609f36abca022017a21edf778d115bab05c70d3c8c4ac16fff52a2686cbb6b60a08b192a5e4e8a01473044022049c8bc0137c49ff87c1c6ef6ef9a7162a64e4519022bd7d68ae523dd6b14c4b2022012f28917b1602d0311ab6c43fa901bf3e5414524252ac85bc9ef8a52d9094210014752210349e0138b2c2f496121258e0426e1dbd698b2c6038e70fd17e3563aa87b4384f92103fd45c8cd28c4c6a9a89b4515173edebc66a2418353976eccf01c73a7da9bbb1252aeffffffff0180de0f00000000001976a914877d4f3be444448f868b345153bc4fc7a11a7c6388ac00000000'
|
||||
],
|
||||
[
|
||||
'from', [{
|
||||
"address": "mgJT8iegL4f9NCgQFeFyfvnSw1Yj4M5Woi",
|
||||
"txid": "f50e13cecda9a438ebd7df213a2899e42b2461a18d4630ee773d26b4f2688bdc",
|
||||
"vout": 1,
|
||||
"scriptPubKey": "76a914089acaba6af8b2b4fb4bed3b747ab1e4e60b496588ac",
|
||||
"amount": 0.01
|
||||
}],
|
||||
'to', ['n3riXZowrjGnY74rx7Hdi9wCyvgyJC28zZ', 990000],
|
||||
'sign', ['cPwWtDztEgRCMCU8pMQp4HgphvyadrAsYBrCjXUZuDSmnZkyoyNF'],
|
||||
'serialize', '0100000001dc8b68f2b4263d77ee30468da161242be499283a21dfd7eb38a4a9cdce130ef5010000006a4730440220337e09c2729423302abe5e386d5e0f060ae8c006693f87342322bb1fe50065ff0220217a12de44139c57f01d35e988ffe3b0f86005d0cefcecf877b54c67473211d2012103e26b47e7c0d8946954bf9dd4bc7f9e415437eb98271d05f69e78cef8fc6c9a54ffffffff01301b0f00000000001976a914f50f9826ef186074c6fe206cca6b71472ff07ba888ac00000000'
|
||||
]
|
||||
];
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
var buffer = require('buffer');
|
||||
var bufferUtil = require('../../lib/util/buffer');
|
||||
|
||||
var Script = require('../../lib/script');
|
||||
var Signature = require('../../lib/crypto/signature');
|
||||
var Transaction = require('../../lib/transaction');
|
||||
var sighash = require('../../lib/transaction/sighash');
|
||||
|
||||
|
@ -12,12 +10,12 @@ var vectors_sighash = require('./sighash.json');
|
|||
|
||||
describe('sighash', function() {
|
||||
|
||||
it('test vector from bitcoind', function() {
|
||||
vectors_sighash.forEach(function(vector, i) {
|
||||
if (i === 0) {
|
||||
// First element is just a row describing the next ones
|
||||
return;
|
||||
}
|
||||
vectors_sighash.forEach(function(vector, i) {
|
||||
if (i === 0) {
|
||||
// First element is just a row describing the next ones
|
||||
return;
|
||||
}
|
||||
it('test vector from bitcoind #' + i + ' (' + vector[4].substring(0, 16) + ')', function() {
|
||||
var txbuf = new buffer.Buffer(vector[0], 'hex');
|
||||
var scriptbuf = new buffer.Buffer(vector[1], 'hex');
|
||||
var subscript = Script(scriptbuf);
|
||||
|
|
|
@ -50,7 +50,7 @@ describe('Transaction', function() {
|
|||
var transaction = new Transaction();
|
||||
while (i < vector.length) {
|
||||
var command = vector[i];
|
||||
var args = vector[i+1];
|
||||
var args = vector[i + 1];
|
||||
if (command === 'serialize') {
|
||||
transaction.serialize().should.equal(args);
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue