correct segwit signing.

This commit is contained in:
Christopher Jeffrey 2016-02-28 05:01:10 -08:00
parent 3fcc7d5b07
commit 0e3aa32677
4 changed files with 122 additions and 15 deletions

View File

@ -699,8 +699,10 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
utils.debug('Block has invalid inputs: %s (%s/%d)',
block.rhash, tx.rhash, j);
utils.debug(input);
utils.debug('Signature Hash: %s',
utils.toHex(tx.signatureHash(j, input.output.script, 'all')));
utils.debug('Signature Hash v0: %s',
utils.toHex(tx.signatureHash(j, input.output.script, 'all', 0)));
utils.debug('Signature Hash v1: %s',
utils.toHex(tx.signatureHash(j, input.output.script, 'all', 1)));
utils.debug('Raw Script: %s',
utils.toHex(input.output.script._raw || []));
utils.debug('Reserialized Script: %s',

View File

@ -305,7 +305,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
return true;
};
MTX.prototype.createSignature = function createSignature(index, prev, key, type) {
MTX.prototype.createSignature = function createSignature(index, prev, key, type, version) {
var prev, hash, signature;
if (typeof index !== 'number')
@ -319,7 +319,7 @@ MTX.prototype.createSignature = function createSignature(index, prev, key, type)
// Get the hash of the current tx, minus the other
// inputs, plus the sighash type.
hash = this.signatureHash(index, prev, type);
hash = this.signatureHash(index, prev, type, version);
// Sign the transaction with our one input
signature = bcoin.script.sign(hash, key, type);
@ -332,7 +332,7 @@ MTX.prototype.createSignature = function createSignature(index, prev, key, type)
MTX.prototype.signInput = function signInput(index, addr, type) {
var input, prev, signature, ki, signatures, i;
var len, m, n, keys, vector, dummy;
var len, m, n, keys, vector, dummy, version;
if (typeof index !== 'number')
index = this.inputs.indexOf(index);
@ -350,6 +350,7 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
vector = input.script;
len = vector.length;
dummy = 0;
version = 0;
// We need to grab the redeem script when
// signing p2sh transactions.
@ -369,15 +370,17 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
vector = input.witness;
len = vector.length - 1;
dummy = new Buffer([]);
version = 1;
} else if (bcoin.script.isWitnessPubkeyhash(prev)) {
prev = bcoin.script.createPubkeyhash(prev[1]);
vector = input.witness;
len = vector.length;
dummy = new Buffer([]);
version = 1;
}
// Create our signature.
signature = this.createSignature(index, prev, addr.key, type);
signature = this.createSignature(index, prev, addr.key, type, version);
// Add signatures.
if (bcoin.script.isPubkey(prev)) {

View File

@ -303,14 +303,14 @@ script.verify = function verify(input, witness, output, tx, i, flags) {
}
// Execute the input script
script.execute(input, stack, tx, i, flags);
script.execute(input, stack, tx, i, flags, 0);
// Copy the stack for P2SH
if (flags & constants.flags.VERIFY_P2SH)
copy = stack.slice();
// Execute the previous output script
res = script.execute(output, stack, tx, i, flags);
res = script.execute(output, stack, tx, i, flags, 0);
// Verify the script did not fail as well as the stack values
if (!res || stack.length === 0 || !script.bool(stack.pop()))
@ -354,7 +354,7 @@ script.verify = function verify(input, witness, output, tx, i, flags) {
redeem = script.decode(raw);
// Execute the redeem script
res = script.execute(redeem, stack, tx, i, flags);
res = script.execute(redeem, stack, tx, i, flags, 0);
// Verify the script did not fail as well as the stack values
if (!res || stack.length === 0 || !script.bool(stack.pop()))
@ -465,7 +465,7 @@ script.verifyProgram = function verifyProgram(witness, output, tx, i, flags) {
utils.debug(bcoin.script.format(stack));
utils.debug(bcoin.script.format(redeem));
res = script.execute(redeem, stack, tx, i, flags);
res = script.execute(redeem, stack, tx, i, flags, 1);
utils.debug(bcoin.script.format(stack));
@ -581,7 +581,7 @@ script._next = function _next(to, s, pc) {
return -1;
};
script.execute = function execute(data, stack, tx, index, flags, recurse) {
script.execute = function execute(data, stack, tx, index, flags, version, recurse) {
var s = data.slice();
if (flags == null)
@ -1053,7 +1053,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
subscript = script.getSubscript(data, lastSep);
script.removeData(subscript, sig);
hash = tx.signatureHash(index, subscript, type);
hash = tx.signatureHash(index, subscript, type, version);
res = script.checksig(hash, sig, key, flags);
if (o === 'checksigverify') {
@ -1112,7 +1112,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
type = sig[sig.length - 1];
hash = tx.signatureHash(index, subscript, type);
hash = tx.signatureHash(index, subscript, type, version);
res = false;
for (; !res && j < n; j++)
@ -1215,7 +1215,9 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
if (res)
return false;
res = script.execute(evalScript, stack, tx, index, flags, recurse);
res = script.execute(
evalScript, stack, tx, index, flags, version, recurse);
if (!res)
return false;

View File

@ -212,7 +212,15 @@ TX.prototype.getSubscript = function getSubscript(index) {
return bcoin.script.getSubscript(script);
};
TX.prototype.signatureHash = function signatureHash(index, s, type) {
TX.prototype.signatureHash = function signatureHash(index, s, type, version) {
assert(version >= 0 && version <= 1);
if (version === 0)
return this.signatureHashV0(index, s, type);
if (version === 1)
return this.signatureHashV1(index, s, type);
};
TX.prototype.signatureHashV0 = function signatureHashV0(index, s, type) {
var copy = this.clone();
var i, msg, hash;
@ -288,6 +296,98 @@ TX.prototype.signatureHash = function signatureHash(index, s, type) {
return hash;
};
TX.prototype.signatureHashV1 = function signatureHashV1(index, s, type) {
var i, msg, hash, hashPrevouts, hashSequence, hashOutputs;
var size, outputs, output, off, prev;
if (typeof index !== 'number')
index = this.inputs.indexOf(index);
if (typeof type === 'string')
type = constants.hashType[type];
assert(index >= 0 && index < this.inputs.length)
assert(Array.isArray(s));
if (!(type & constants.hashType.anyonecanpay)) {
hashPrevouts = new Buffer(36 * this.inputs.length);
off = 0;
for (i = 0; i < this.inputs.length; i++) {
prev = this.inputs[i].prevout;
off += utils.copy(new Buffer(prev.hash, 'hex'), hashPrevouts, off);
off += utils.writeU32(hashPrevouts, prev.index, off);
}
hashPrevouts = utils.dsha256(hashPrevouts);
} else {
hashPrevouts = new Buffer(32);
hashPrevouts.fill(0);
}
if (!(type & constants.hashType.anyonecanpay)
&& (type & 0x1f) !== constants.hashType.single
&& (type & 0x1f) !== constants.hashType.none) {
hashSequence = new Buffer(4 * this.inputs.length);
off = 0;
for (i = 0; i < this.inputs.length; i++)
off += utils.writeU32(hashSequence, this.inputs[i].sequence, off);
hashSequence = utils.dsha256(hashSequence);
} else {
hashSequence = new Buffer(32);
hashSequence.fill(0);
}
if ((type & 0x1f) !== constants.hashType.single
&& (type & 0x1f) !== constants.hashType.none) {
size = 0;
outputs = [];
for (i = 0; i < this.outputs.length; i++) {
output = bcoin.protocol.framer.output(this.outputs[i]);
size += output.length;
outputs.push(output);
}
hashOutputs = new Buffer(size);
off = 0;
for (i = 0; i < outputs.length; i++)
off += utils.copy(outputs[i], hashOutputs, off);
hashOutputs = utils.dsha256(hashOutputs);
} else if ((type & 0x1f) === constants.hashType.single && index < this.outputs.length) {
hashOutputs = bcoin.protocol.framer.output(this.outputs[index]);
hashOutputs = utils.dsha256(hashOutputs);
} else {
hashOutputs = new Buffer(32);
hashOutputs.fill(0);
}
s = bcoin.script.encode(s);
msg = new Buffer(
4 + 32 + 32 + 36
+ utils.sizeIntv(s.length)
+ s.length
+ 8 + 4 + 32 + 4 + 4);
off = 0;
off += utils.write32(msg, this.version, off);
off += utils.copy(hashPrevouts, msg, off);
off += utils.copy(hashSequence, msg, off);
off += utils.copy(new Buffer(this.inputs[index].prevout.hash, 'hex'), msg, off);
off += utils.writeU32(msg, this.inputs[index].prevout.index, off);
assert(off === 4 + 32 + 32 + 36);
off += utils.writeIntv(msg, s.length, off);
off += utils.copy(s, msg, off);
off += utils.write64(msg, this.inputs[index].output.value, off);
off += utils.writeU32(msg, this.inputs[index].sequence, off);
off += utils.copy(hashOutputs, msg, off);
off += utils.writeU32(msg, this.locktime, off);
assert(off === msg.length - 4);
off += utils.writeU32(msg, type, off);
assert(off === msg.length);
hash = utils.dsha256(msg);
return hash;
};
TX.prototype.normalizedHash = function normalizedHash(enc, force) {
var copy = this.clone();
var i;