correct segwit signing.
This commit is contained in:
parent
3fcc7d5b07
commit
0e3aa32677
@ -699,8 +699,10 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
|
|||||||
utils.debug('Block has invalid inputs: %s (%s/%d)',
|
utils.debug('Block has invalid inputs: %s (%s/%d)',
|
||||||
block.rhash, tx.rhash, j);
|
block.rhash, tx.rhash, j);
|
||||||
utils.debug(input);
|
utils.debug(input);
|
||||||
utils.debug('Signature Hash: %s',
|
utils.debug('Signature Hash v0: %s',
|
||||||
utils.toHex(tx.signatureHash(j, input.output.script, 'all')));
|
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.debug('Raw Script: %s',
|
||||||
utils.toHex(input.output.script._raw || []));
|
utils.toHex(input.output.script._raw || []));
|
||||||
utils.debug('Reserialized Script: %s',
|
utils.debug('Reserialized Script: %s',
|
||||||
|
|||||||
@ -305,7 +305,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
|
|||||||
return true;
|
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;
|
var prev, hash, signature;
|
||||||
|
|
||||||
if (typeof index !== 'number')
|
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
|
// Get the hash of the current tx, minus the other
|
||||||
// inputs, plus the sighash type.
|
// 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
|
// Sign the transaction with our one input
|
||||||
signature = bcoin.script.sign(hash, key, type);
|
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) {
|
MTX.prototype.signInput = function signInput(index, addr, type) {
|
||||||
var input, prev, signature, ki, signatures, i;
|
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')
|
if (typeof index !== 'number')
|
||||||
index = this.inputs.indexOf(index);
|
index = this.inputs.indexOf(index);
|
||||||
@ -350,6 +350,7 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
|
|||||||
vector = input.script;
|
vector = input.script;
|
||||||
len = vector.length;
|
len = vector.length;
|
||||||
dummy = 0;
|
dummy = 0;
|
||||||
|
version = 0;
|
||||||
|
|
||||||
// We need to grab the redeem script when
|
// We need to grab the redeem script when
|
||||||
// signing p2sh transactions.
|
// signing p2sh transactions.
|
||||||
@ -369,15 +370,17 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
|
|||||||
vector = input.witness;
|
vector = input.witness;
|
||||||
len = vector.length - 1;
|
len = vector.length - 1;
|
||||||
dummy = new Buffer([]);
|
dummy = new Buffer([]);
|
||||||
|
version = 1;
|
||||||
} else if (bcoin.script.isWitnessPubkeyhash(prev)) {
|
} else if (bcoin.script.isWitnessPubkeyhash(prev)) {
|
||||||
prev = bcoin.script.createPubkeyhash(prev[1]);
|
prev = bcoin.script.createPubkeyhash(prev[1]);
|
||||||
vector = input.witness;
|
vector = input.witness;
|
||||||
len = vector.length;
|
len = vector.length;
|
||||||
dummy = new Buffer([]);
|
dummy = new Buffer([]);
|
||||||
|
version = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create our signature.
|
// Create our signature.
|
||||||
signature = this.createSignature(index, prev, addr.key, type);
|
signature = this.createSignature(index, prev, addr.key, type, version);
|
||||||
|
|
||||||
// Add signatures.
|
// Add signatures.
|
||||||
if (bcoin.script.isPubkey(prev)) {
|
if (bcoin.script.isPubkey(prev)) {
|
||||||
|
|||||||
@ -303,14 +303,14 @@ script.verify = function verify(input, witness, output, tx, i, flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute the input script
|
// Execute the input script
|
||||||
script.execute(input, stack, tx, i, flags);
|
script.execute(input, stack, tx, i, flags, 0);
|
||||||
|
|
||||||
// Copy the stack for P2SH
|
// Copy the stack for P2SH
|
||||||
if (flags & constants.flags.VERIFY_P2SH)
|
if (flags & constants.flags.VERIFY_P2SH)
|
||||||
copy = stack.slice();
|
copy = stack.slice();
|
||||||
|
|
||||||
// Execute the previous output script
|
// 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
|
// Verify the script did not fail as well as the stack values
|
||||||
if (!res || stack.length === 0 || !script.bool(stack.pop()))
|
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);
|
redeem = script.decode(raw);
|
||||||
|
|
||||||
// Execute the redeem script
|
// 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
|
// Verify the script did not fail as well as the stack values
|
||||||
if (!res || stack.length === 0 || !script.bool(stack.pop()))
|
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(stack));
|
||||||
utils.debug(bcoin.script.format(redeem));
|
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));
|
utils.debug(bcoin.script.format(stack));
|
||||||
|
|
||||||
@ -581,7 +581,7 @@ script._next = function _next(to, s, pc) {
|
|||||||
return -1;
|
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();
|
var s = data.slice();
|
||||||
|
|
||||||
if (flags == null)
|
if (flags == null)
|
||||||
@ -1053,7 +1053,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
|
|||||||
subscript = script.getSubscript(data, lastSep);
|
subscript = script.getSubscript(data, lastSep);
|
||||||
script.removeData(subscript, sig);
|
script.removeData(subscript, sig);
|
||||||
|
|
||||||
hash = tx.signatureHash(index, subscript, type);
|
hash = tx.signatureHash(index, subscript, type, version);
|
||||||
|
|
||||||
res = script.checksig(hash, sig, key, flags);
|
res = script.checksig(hash, sig, key, flags);
|
||||||
if (o === 'checksigverify') {
|
if (o === 'checksigverify') {
|
||||||
@ -1112,7 +1112,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
|
|||||||
|
|
||||||
type = sig[sig.length - 1];
|
type = sig[sig.length - 1];
|
||||||
|
|
||||||
hash = tx.signatureHash(index, subscript, type);
|
hash = tx.signatureHash(index, subscript, type, version);
|
||||||
|
|
||||||
res = false;
|
res = false;
|
||||||
for (; !res && j < n; j++)
|
for (; !res && j < n; j++)
|
||||||
@ -1215,7 +1215,9 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
|
|||||||
if (res)
|
if (res)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
res = script.execute(evalScript, stack, tx, index, flags, recurse);
|
res = script.execute(
|
||||||
|
evalScript, stack, tx, index, flags, version, recurse);
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
102
lib/bcoin/tx.js
102
lib/bcoin/tx.js
@ -212,7 +212,15 @@ TX.prototype.getSubscript = function getSubscript(index) {
|
|||||||
return bcoin.script.getSubscript(script);
|
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 copy = this.clone();
|
||||||
var i, msg, hash;
|
var i, msg, hash;
|
||||||
|
|
||||||
@ -288,6 +296,98 @@ TX.prototype.signatureHash = function signatureHash(index, s, type) {
|
|||||||
return hash;
|
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) {
|
TX.prototype.normalizedHash = function normalizedHash(enc, force) {
|
||||||
var copy = this.clone();
|
var copy = this.clone();
|
||||||
var i;
|
var i;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user