sighashing.
This commit is contained in:
parent
b356790136
commit
41eab6e27c
148
lib/bcoin/tx.js
148
lib/bcoin/tx.js
@ -176,18 +176,33 @@ TX.prototype._inputIndex = function _inputIndex(hash, index) {
|
||||
return -1;
|
||||
};
|
||||
|
||||
TX.prototype.signatureHash = function signatureHash(index, s, type, version) {
|
||||
TX.prototype.signatureHash = function signatureHash(index, prev, type, version) {
|
||||
assert(version >= 0 && version <= 1);
|
||||
|
||||
// Traditional sighashing
|
||||
if (version === 0)
|
||||
return this.signatureHashV0(index, s, type);
|
||||
return this.signatureHashV0(index, prev, type);
|
||||
|
||||
// Segwit sighashing
|
||||
if (version === 1)
|
||||
return this.signatureHashV1(index, s, type);
|
||||
return this.signatureHashV1(index, prev, type);
|
||||
};
|
||||
|
||||
TX.prototype.signatureHashV0 = function signatureHashV0(index, s, type) {
|
||||
var i, msg, hash;
|
||||
TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
var p = new BufferWriter();
|
||||
var i, copy;
|
||||
|
||||
var copy = {
|
||||
if (typeof index !== 'number')
|
||||
index = this.inputs.indexOf(index);
|
||||
|
||||
if (typeof type === 'string')
|
||||
type = constants.hashType[type];
|
||||
|
||||
assert(index >= 0 && index < copy.inputs.length);
|
||||
assert(prev instanceof bcoin.script);
|
||||
|
||||
// Clone the transaction.
|
||||
copy = {
|
||||
version: this.version,
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
@ -210,31 +225,16 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, s, type) {
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof index !== 'number')
|
||||
index = this.inputs.indexOf(index);
|
||||
|
||||
if (typeof type === 'string')
|
||||
type = constants.hashType[type];
|
||||
|
||||
assert(index >= 0 && index < copy.inputs.length);
|
||||
assert(s instanceof bcoin.script);
|
||||
|
||||
// Disable this for now. We allow null hash types
|
||||
// because bitcoind allows empty signatures. On
|
||||
// another note, we allow all weird sighash types
|
||||
// if strictenc is not enabled.
|
||||
// assert(utils.isFinite(type));
|
||||
|
||||
// Remove all signatures.
|
||||
for (i = 0; i < copy.inputs.length; i++)
|
||||
copy.inputs[i].script = new Script([]);
|
||||
|
||||
// Set our input to previous output's script
|
||||
copy.inputs[index].script = s;
|
||||
copy.inputs[index].script = prev;
|
||||
|
||||
if ((type & 0x1f) === constants.hashType.none) {
|
||||
// Drop all outputs. We don't want to sign them.
|
||||
copy.outputs = [];
|
||||
copy.outputs.length = 0;
|
||||
|
||||
// Allow input sequence updates for other inputs.
|
||||
for (i = 0; i < copy.inputs.length; i++) {
|
||||
@ -271,20 +271,16 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, s, type) {
|
||||
copy.inputs.length = 1;
|
||||
}
|
||||
|
||||
copy = bcoin.protocol.framer.tx(copy);
|
||||
// Render the copy and append the hashtype.
|
||||
bcoin.protocol.framer.tx(copy, p);
|
||||
p.writeU32(type);
|
||||
|
||||
msg = new Buffer(copy.length + 4);
|
||||
utils.copy(copy, msg, 0);
|
||||
utils.writeU32(msg, type, copy.length);
|
||||
|
||||
hash = utils.dsha256(msg);
|
||||
|
||||
return hash;
|
||||
return utils.dsha256(p.render());
|
||||
};
|
||||
|
||||
TX.prototype.signatureHashV1 = function signatureHashV1(index, s, type) {
|
||||
var i, msg, hash, hashPrevouts, hashSequence, hashOutputs;
|
||||
var size, outputs, output, off, prev;
|
||||
TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, type) {
|
||||
var p = new BufferWriter();
|
||||
var i, prevout, hashPrevouts, hashSequence, hashOutputs;
|
||||
|
||||
if (typeof index !== 'number')
|
||||
index = this.inputs.indexOf(index);
|
||||
@ -293,85 +289,57 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, s, type) {
|
||||
type = constants.hashType[type];
|
||||
|
||||
assert(index >= 0 && index < this.inputs.length);
|
||||
assert(s instanceof bcoin.script);
|
||||
assert(prev instanceof bcoin.script);
|
||||
|
||||
if (!(type & constants.hashType.anyonecanpay)) {
|
||||
hashPrevouts = new Buffer(36 * this.inputs.length);
|
||||
off = 0;
|
||||
hashPrevouts = new BufferWriter();
|
||||
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);
|
||||
prevout = this.inputs[i].prevout;
|
||||
hashPrevouts.writeHash(prevout.hash);
|
||||
hashPrevouts.writeU32(prevout.index);
|
||||
}
|
||||
hashPrevouts = utils.dsha256(hashPrevouts);
|
||||
hashPrevouts = utils.dsha256(hashPrevouts.render());
|
||||
} else {
|
||||
hashPrevouts = new Buffer(32);
|
||||
hashPrevouts.fill(0);
|
||||
hashPrevouts = utils.slice(constants.zeroHash);
|
||||
}
|
||||
|
||||
if (!(type & constants.hashType.anyonecanpay)
|
||||
&& (type & 0x1f) !== constants.hashType.single
|
||||
&& (type & 0x1f) !== constants.hashType.none) {
|
||||
hashSequence = new Buffer(4 * this.inputs.length);
|
||||
off = 0;
|
||||
hashSequence = new BufferWriter();
|
||||
for (i = 0; i < this.inputs.length; i++)
|
||||
off += utils.writeU32(hashSequence, this.inputs[i].sequence, off);
|
||||
hashSequence = utils.dsha256(hashSequence);
|
||||
p.writeU32(this.inputs[i].sequence);
|
||||
hashSequence = utils.dsha256(hashSequence.render());
|
||||
} else {
|
||||
hashSequence = new Buffer(32);
|
||||
hashSequence.fill(0);
|
||||
hashSequence = utils.slice(constants.zeroHash);
|
||||
}
|
||||
|
||||
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);
|
||||
hashOutputs = new BufferWriter();
|
||||
for (i = 0; i < this.outputs.length; i++)
|
||||
bcoin.protocol.framer.output(this.outputs[i], hashOutputs);
|
||||
hashOutputs = utils.dsha256(hashOutputs.render());
|
||||
} 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);
|
||||
hashOutputs = utils.slice(constants.zeroHash);
|
||||
}
|
||||
|
||||
s = s.encode();
|
||||
p.write32(this.version);
|
||||
p.writeBytes(hashPrevouts);
|
||||
p.writeBytes(hashSequence);
|
||||
p.writeHash(this.inputs[index].prevout.hash);
|
||||
p.writeU32(this.inputs[index].prevout.index);
|
||||
p.writeVarBytes(prev.encode());
|
||||
p.write64(this.inputs[index].output.value);
|
||||
p.writeU32(this.inputs[index].sequence);
|
||||
p.writeBytes(hashOutputs);
|
||||
p.writeU32(this.locktime);
|
||||
p.writeU32(type);
|
||||
|
||||
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;
|
||||
return utils.dsha256(p.render());
|
||||
};
|
||||
|
||||
TX.prototype.verify = function verify(index, force, flags) {
|
||||
|
||||
@ -52,6 +52,12 @@ BufferWriter.prototype.render = function render() {
|
||||
return data;
|
||||
};
|
||||
|
||||
BufferWriter.prototype.destroy = function destroy() {
|
||||
this.data.length = 0;
|
||||
delete this.data;
|
||||
delete this.written;
|
||||
};
|
||||
|
||||
BufferWriter.prototype.writeU8 = function writeU8(value) {
|
||||
this.written += 1;
|
||||
this.data.push(['u8', value]);
|
||||
@ -171,6 +177,13 @@ BufferWriter.prototype.writeUIntv = function writeUIntv(value) {
|
||||
this.data.push(['varint', value]);
|
||||
};
|
||||
|
||||
BufferWriter.prototype.fill = function fill(value, size) {
|
||||
var buf = new Buffer(size);
|
||||
buf.fill(value);
|
||||
this.written += buf.length;
|
||||
this.data.push(['bytes', buf]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user