Skip to content
This repository has been archived by the owner on Apr 3, 2019. It is now read-only.

Commit

Permalink
Merge branch 'matiu-update-json-abc-tests' into cash
Browse files Browse the repository at this point in the history
  • Loading branch information
nitsujlangston committed Apr 19, 2018
2 parents feccd2d + f51321e commit 6b35351
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 754 deletions.
2 changes: 1 addition & 1 deletion lib/crypto/signature.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ Signature.prototype.hasDefinedHashtype = function() {
return false;
}
// accept with or without Signature.SIGHASH_ANYONECANPAY by ignoring the bit
var temp = this.nhashtype & ~Signature.SIGHASH_ANYONECANPAY;
var temp = this.nhashtype & 0x1F
if (temp < Signature.SIGHASH_ALL || temp > Signature.SIGHASH_SINGLE) {
return false;
}
Expand Down
6 changes: 3 additions & 3 deletions lib/opcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ Opcode.map = {

// splice ops
OP_CAT: 126,
OP_SUBSTR: 127,
OP_LEFT: 128,
OP_RIGHT: 129,
OP_SPLIT: 127,
OP_NUM2BIN: 128,
OP_BIN2NUM: 129,
OP_SIZE: 130,

// bit logic
Expand Down
86 changes: 68 additions & 18 deletions lib/script/interpreter.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ var Interpreter = function Interpreter(obj) {
* to check signature validity for some opcodes like OP_CHECKSIG)
* @param {number} nin - index of the transaction input containing the scriptSig verified.
* @param {number} flags - evaluation flags. See Interpreter.SCRIPT_* constants
* @param {number} satoshisBN - amount in satoshis of the input to be verified (when FORKID signhash is used)
*
* Translated from bitcoind's VerifyScript
*/
Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags) {
Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags, satoshisBN) {
var Transaction = require('../transaction');

if (_.isUndefined(tx)) {
Expand All @@ -56,11 +57,23 @@ Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags)
if (_.isUndefined(flags)) {
flags = 0;
}

// If FORKID is enabled, we also ensure strict encoding.
if (flags & Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID) {
flags |= Interpreter.SCRIPT_VERIFY_STRICTENC;

// If FORKID is enabled, we need the input amount.
if (!satoshisBN) {
throw new Error('internal error - need satoshisBN to verify FORKID transactions');
}
}

this.set({
script: scriptSig,
tx: tx,
nin: nin,
flags: flags
flags: flags,
satoshisBN: satoshisBN,
});
var stackCopy;

Expand All @@ -85,7 +98,8 @@ Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags)
stack: stack,
tx: tx,
nin: nin,
flags: flags
flags: flags,
satoshisBN: satoshisBN,
});

// evaluate scriptPubkey
Expand Down Expand Up @@ -129,7 +143,8 @@ Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags)
stack: stackCopy,
tx: tx,
nin: nin,
flags: flags
flags: flags,
satoshisBN: satoshisBN,
});

// evaluate redeemScript
Expand Down Expand Up @@ -188,6 +203,7 @@ Interpreter.prototype.set = function(obj) {
this.script = obj.script || this.script;
this.tx = obj.tx || this.tx;
this.nin = typeof obj.nin !== 'undefined' ? obj.nin : this.nin;
this.satoshisBN = obj.satoshisBN || this.satoshisBN;
this.stack = obj.stack || this.stack;
this.altstack = obj.altack || this.altstack;
this.pc = typeof obj.pc !== 'undefined' ? obj.pc : this.pc;
Expand Down Expand Up @@ -264,30 +280,35 @@ Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1 << 9);
// support CHECKSEQUENCEVERIFY opcode
//
// See BIP112 for details
Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1 << 10),
Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1 << 10);

// For compatibility with the json tests
Interpreter.SCRIPT_VERIFY_WITNESS = (1 << 11),
Interpreter.SCRIPT_VERIFY_WITNESS = (1 << 11);


// Segwit script only: Require the argument of OP_IF/NOTIF to be exactly
// 0x01 or empty vector
//
Interpreter.SCRIPT_VERIFY_MINIMALIF = (1 << 13);

// Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed
//
Interpreter.SCRIPT_VERIFY_NULLFAIL = (1 << 14),
Interpreter.SCRIPT_VERIFY_NULLFAIL = (1 << 14);

// Public keys in scripts must be compressed
//
Interpreter.SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE = (1 << 15),
Interpreter.SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE = (1 << 15);

// Do we accept signature using SIGHASH_FORKID
//
Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID = (1 << 16),
Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID = (1 << 16);

// Do we accept activate replay protection using a different fork id.
//
Interpreter.SCRIPT_ENABLE_REPLAY_PROTECTION = (1 << 17),
Interpreter.SCRIPT_ENABLE_REPLAY_PROTECTION = (1 << 17);

// Enable new opcodes.
//
Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES = (1 << 18),
Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES = (1 << 18);



Expand Down Expand Up @@ -347,11 +368,24 @@ Interpreter.prototype.checkSignatureEncoding = function(buf) {
return false;
}
} else if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0) {

sig = Signature.fromTxFormat(buf);
if (!sig.hasDefinedHashtype()) {
this.errstr = 'SCRIPT_ERR_SIG_HASHTYPE';
return false;
}

if (!(this.flags & Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID) &&
(sig.nhashtype & Signature.SIGHASH_FORKID)) {
this.errstr = 'SCRIPT_ERR_ILLEGAL_FORKID';
return false;
}

if ( (this.flags & Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID) &&
!(sig.nhashtype & Signature.SIGHASH_FORKID)) {
this.errstr = 'SCRIPT_ERR_MUST_USE_FORKID';
return false;
}
}

return true;
Expand Down Expand Up @@ -545,9 +579,9 @@ Interpreter.prototype.step = function() {


if (opcodenum === Opcode.OP_CAT ||
opcodenum === Opcode.OP_SUBSTR ||
opcodenum === Opcode.OP_LEFT ||
opcodenum === Opcode.OP_RIGHT ||
opcodenum === Opcode.OP_SPLIT ||
opcodenum === Opcode.OP_NUM2BIN ||
opcodenum === Opcode.OP_BIN2NUM ||
opcodenum === Opcode.OP_INVERT ||
opcodenum === Opcode.OP_AND ||
opcodenum === Opcode.OP_OR ||
Expand Down Expand Up @@ -738,11 +772,24 @@ Interpreter.prototype.step = function() {
this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL';
return false;
}
buf = this.stack.pop();
buf = this.stack[this.stack.length - 1];

if (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALIF) {
buf = this.stack[this.stack.length - 1];
if (buf.length > 1) {
this.errstr = 'SCRIPT_ERR_MINIMALIF';
return false;
}
if (buf.length == 1 && buf[0]!=1) {
this.errstr = 'SCRIPT_ERR_MINIMALIF';
return false;
}
}
fValue = Interpreter.castToBool(buf);
if (opcodenum === Opcode.OP_NOTIF) {
fValue = !fValue;
}
this.stack.pop();
}
this.vfExec.push(fValue);
}
Expand Down Expand Up @@ -1290,6 +1337,7 @@ Interpreter.prototype.step = function() {
bufPubkey = this.stack[this.stack.length - 1];

if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) {

return false;
}

Expand All @@ -1306,7 +1354,8 @@ Interpreter.prototype.step = function() {
try {
sig = Signature.fromTxFormat(bufSig);
pubkey = PublicKey.fromBuffer(bufPubkey, false);
fSuccess = this.tx.verifySignature(sig, pubkey, this.nin, subscript);

fSuccess = this.tx.verifySignature(sig, pubkey, this.nin, subscript, this.satoshisBN, this.flags);
} catch (e) {
//invalid sig or pubkey
fSuccess = false;
Expand Down Expand Up @@ -1402,14 +1451,15 @@ Interpreter.prototype.step = function() {
bufPubkey = this.stack[this.stack.length - ikey];

if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) {

return false;
}

var fOk;
try {
sig = Signature.fromTxFormat(bufSig);
pubkey = PublicKey.fromBuffer(bufPubkey, false);
fOk = this.tx.verifySignature(sig, pubkey, this.nin, subscript);
fOk = this.tx.verifySignature(sig, pubkey, this.nin, subscript, this.satoshisBN, this.flags);
} catch (e) {
//invalid sig or pubkey
fOk = false;
Expand Down
37 changes: 26 additions & 11 deletions lib/transaction/sighash.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ var Hash = require('../crypto/hash');
var ECDSA = require('../crypto/ecdsa');
var $ = require('../util/preconditions');
var BufferUtil = require('../util/buffer');
var Interpreter = require('../script/interpreter');
var _ = require('lodash');

var SIGHASH_SINGLE_BUG = '0000000000000000000000000000000000000000000000000000000000000001';
var BITS_64_ON = 'ffffffffffffffff';


var ENABLE_SIGHASH_FORKID = true;
// By default, we sign with sighash_forkid
var DEFAULT_SIGN_FLAGS = Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID;


var sighashForForkId = function(transaction, sighashType, inputNumber, subscript, satoshisBN) {
Expand All @@ -28,8 +29,6 @@ var sighashForForkId = function(transaction, sighashType, inputNumber, subscript
'For ForkId=0 signatures, satoshis or complete input must be provided'
);



function GetForkId() {
return 0; // In the UAHF, a fork id of 0 is used (see [4] REQ-6-2 NOTE 4)
};
Expand Down Expand Up @@ -154,21 +153,33 @@ function getHash (w) {
* @param {number} sighashType the type of the hash
* @param {number} inputNumber the input index for the signature
* @param {Script} subscript the script that will be signed
* @param {satoshisBN} sed in ForkId signatures. If not provided, outputs's amount is used.
* @param {satoshisBN} input's amount (for ForkId signatures)
*
*/
var sighash = function sighash(transaction, sighashType, inputNumber, subscript, satoshisBN) {
var sighash = function sighash(transaction, sighashType, inputNumber, subscript, satoshisBN, flags) {
var Transaction = require('./transaction');
var Input = require('./input');

if (_.isUndefined(flags)){
flags = DEFAULT_SIGN_FLAGS;
}

// Copy transaction
var txcopy = Transaction.shallowCopy(transaction);

// Copy script
subscript = new Script(subscript);

if (flags & Interpreter.SCRIPT_ENABLE_REPLAY_PROTECTION) {
// Legacy chain's value for fork id must be of the form 0xffxxxx.
// By xoring with 0xdead, we ensure that the value will be different
// from the original one, even if it already starts with 0xff.
var forkValue = sighashType >> 8;
var newForkValue = 0xff0000 | ( forkValue ^ 0xdead);
sighashType = (newForkValue << 8) | (sighashType & 0xff)
}

if ( ( sighashType & Signature.SIGHASH_FORKID) && ENABLE_SIGHASH_FORKID) {
if ( ( sighashType & Signature.SIGHASH_FORKID) && (flags & Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID) ) {
return sighashForForkId(txcopy, sighashType, inputNumber, subscript, satoshisBN);
}

Expand Down Expand Up @@ -240,8 +251,11 @@ var sighash = function sighash(transaction, sighashType, inputNumber, subscript,
* @param {satoshisBN} input's amount
* @return {Signature}
*/
function sign(transaction, privateKey, sighashType, inputIndex, subscript, satoshisBN) {
var hashbuf = sighash(transaction, sighashType, inputIndex, subscript, satoshisBN);
function sign(transaction, privateKey, sighashType, inputIndex, subscript, satoshisBN, flags) {
var hashbuf = sighash(transaction, sighashType, inputIndex, subscript, satoshisBN, flags);



var sig = ECDSA.sign(hashbuf, privateKey, 'little').set({
nhashtype: sighashType
});
Expand All @@ -258,12 +272,13 @@ function sign(transaction, privateKey, sighashType, inputIndex, subscript, satos
* @param {number} inputIndex
* @param {Script} subscript
* @param {satoshisBN} input's amount
* @param {flags} verification flags
* @return {boolean}
*/
function verify(transaction, signature, publicKey, inputIndex, subscript, satoshisBN) {
function verify(transaction, signature, publicKey, inputIndex, subscript, satoshisBN, flags) {
$.checkArgument(!_.isUndefined(transaction));
$.checkArgument(!_.isUndefined(signature) && !_.isUndefined(signature.nhashtype));
var hashbuf = sighash(transaction, signature.nhashtype, inputIndex, subscript, satoshisBN);
var hashbuf = sighash(transaction, signature.nhashtype, inputIndex, subscript, satoshisBN, flags);
return ECDSA.verify(hashbuf, signature, publicKey, 'little');
}

Expand Down
4 changes: 2 additions & 2 deletions lib/transaction/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -1113,8 +1113,8 @@ Transaction.prototype.isValidSignature = function(signature) {
/**
* @returns {bool} whether the signature is valid for this transaction input
*/
Transaction.prototype.verifySignature = function(sig, pubkey, nin, subscript) {
return Sighash.verify(this, sig, pubkey, nin, subscript);
Transaction.prototype.verifySignature = function(sig, pubkey, nin, subscript, satoshisBN, flags) {
return Sighash.verify(this, sig, pubkey, nin, subscript, satoshisBN, flags);
};

/**
Expand Down

0 comments on commit 6b35351

Please sign in to comment.