sighashing.

This commit is contained in:
Christopher Jeffrey 2016-03-15 14:14:53 -07:00
parent b356790136
commit 41eab6e27c
2 changed files with 71 additions and 90 deletions

View File

@ -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) {

View File

@ -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
*/