Browse Source

transaction: start to use new sighash for nested witness

patch-2
Braydon Fuller 9 years ago
parent
commit
93002249da
  1. 9
      lib/script/script.js
  2. 52
      lib/transaction/input/multisigscripthash.js
  3. 8
      lib/transaction/sighashwitness.js
  4. 33
      test/transaction/input/multisigscripthash.js
  5. 3
      test/transaction/transaction.js

9
lib/script/script.js

@ -689,6 +689,15 @@ Script.prototype._addBuffer = function(buf, prepend) {
return this;
};
Script.prototype.hasCodeseparators = function() {
for (var i = 0; i < this.chunks.length; i++) {
if (this.chunks[i].opcodenum === Opcode.OP_CODESEPARATOR) {
return true;
}
}
return false;
};
Script.prototype.removeCodeseparators = function() {
var chunks = [];
for (var i = 0; i < this.chunks.length; i++) {

52
lib/transaction/input/multisigscripthash.js

@ -11,6 +11,8 @@ var $ = require('../../util/preconditions');
var Script = require('../../script');
var Signature = require('../../crypto/signature');
var Sighash = require('../sighash');
var SighashWitness = require('../sighashwitness');
var BufferWriter = require('../../encoding/bufferwriter');
var BufferUtil = require('../../util/buffer');
var TransactionSignature = require('../signature');
@ -74,6 +76,24 @@ MultiSigScriptHashInput.prototype._serializeSignatures = function() {
});
};
MultiSigScriptHashInput.prototype.getScriptCode = function() {
var writer = new BufferWriter();
if (!this.script.hasCodeseparators()) {
writer.writeVarintNum(this._scriptBuffer.length);
writer.write(this._scriptBuffer);
} else {
throw new Error('@TODO');
}
return writer.toBuffer();
};
MultiSigScriptHashInput.prototype.getSatoshisBuffer = function() {
$.checkState(this.output instanceof Output);
$.checkState(this.output._satoshisBN);
var buffer = new BufferWriter().writeUInt64LEBN(this.output._satoshisBN).toBuffer();
return buffer;
};
MultiSigScriptHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype) {
$.checkState(this.output instanceof Output);
sigtype = sigtype || Signature.SIGHASH_ALL;
@ -82,12 +102,20 @@ MultiSigScriptHashInput.prototype.getSignatures = function(transaction, privateK
var results = [];
_.each(this.publicKeys, function(publicKey) {
if (publicKey.toString() === privateKey.publicKey.toString()) {
var signature;
if (self.nestedWitness) {
var scriptCode = self.getScriptCode();
var satoshisBuffer = self.getSatoshisBuffer();
signature = SighashWitness.sign(transaction, privateKey, sigtype, index, scriptCode, satoshisBuffer);
} else {
signature = Sighash.sign(transaction, privateKey, sigtype, index, self.redeemScript);
}
results.push(new TransactionSignature({
publicKey: privateKey.publicKey,
prevTxId: self.prevTxId,
outputIndex: self.outputIndex,
inputIndex: index,
signature: Sighash.sign(transaction, privateKey, sigtype, index, self.redeemScript),
signature: signature,
sigtype: sigtype
}));
}
@ -159,15 +187,29 @@ MultiSigScriptHashInput.prototype.publicKeysWithoutSignature = function() {
};
MultiSigScriptHashInput.prototype.isValidSignature = function(transaction, signature) {
// FIXME: Refactor signature so this is not necessary
signature.signature.nhashtype = signature.sigtype;
return Sighash.verify(
if (this.nestedWitness) {
signature.signature.nhashtype = signature.sigtype;
var scriptCode = this.getScriptCode();
var satoshisBuffer = this.getSatoshisBuffer();
return SighashWitness.verify(
transaction,
signature.signature,
signature.publicKey,
signature.inputIndex,
scriptCode,
satoshisBuffer
);
} else {
// FIXME: Refactor signature so this is not necessary
signature.signature.nhashtype = signature.sigtype;
return Sighash.verify(
transaction,
signature.signature,
signature.publicKey,
signature.inputIndex,
this.redeemScript
);
);
}
};
MultiSigScriptHashInput.OPCODES_SIZE = 7; // serialized size (<=3) + 0 .. N .. M OP_CHECKMULTISIG

8
lib/transaction/sighashwitness.js

@ -111,8 +111,8 @@ var sighash = function sighash(transaction, sighashType, inputNumber, scriptCode
* @param {Script} subscript
* @return {Signature}
*/
function sign(transaction, privateKey, sighashType, inputIndex, subscript) {
var hashbuf = sighash(transaction, sighashType, inputIndex, subscript);
function sign(transaction, privateKey, sighashType, inputIndex, scriptCode, satoshisBuffer) {
var hashbuf = sighash(transaction, sighashType, inputIndex, scriptCode, satoshisBuffer);
var sig = ECDSA.sign(hashbuf, privateKey, 'little').set({
nhashtype: sighashType
});
@ -130,10 +130,10 @@ function sign(transaction, privateKey, sighashType, inputIndex, subscript) {
* @param {Script} subscript
* @return {boolean}
*/
function verify(transaction, signature, publicKey, inputIndex, subscript) {
function verify(transaction, signature, publicKey, inputIndex, scriptCode, satoshisBuffer) {
$.checkArgument(!_.isUndefined(transaction));
$.checkArgument(!_.isUndefined(signature) && !_.isUndefined(signature.nhashtype));
var hashbuf = sighash(transaction, signature.nhashtype, inputIndex, subscript);
var hashbuf = sighash(transaction, signature.nhashtype, inputIndex, scriptCode, satoshisBuffer);
return ECDSA.verify(hashbuf, signature, publicKey, 'little');
}

33
test/transaction/input/multisigscripthash.js

@ -111,4 +111,37 @@ describe('MultiSigScriptHashInput', function() {
var roundtrip = new MultiSigScriptHashInput(input.toObject());
roundtrip.toObject().should.deep.equal(input.toObject());
});
it('will get the scriptCode for nested witness', function() {
var address = Address.createMultisig([public1, public2, public3], 2, 'testnet', true);
var utxo = {
address: address.toString(),
txId: '66e64ef8a3b384164b78453fa8c8194de9a473ba14f89485a0e433699daec140',
outputIndex: 0,
script: new Script(address),
satoshis: 1000000
};
var transaction = new Transaction()
.from(utxo, [public1, public2, public3], 2, true)
.to(address, 1000000);
var input = transaction.inputs[0];
var scriptCode = input.getScriptCode();
scriptCode.toString('hex').should.equal('2200206aac01b83b1537afe2aa96d13a339b8a109b05f6eaf37d5840fe5f227daedacc');
});
it('will get the satoshis buffer for nested witness', function() {
var address = Address.createMultisig([public1, public2, public3], 2, 'testnet', true);
var utxo = {
address: address.toString(),
txId: '66e64ef8a3b384164b78453fa8c8194de9a473ba14f89485a0e433699daec140',
outputIndex: 0,
script: new Script(address),
satoshis: 1000000
};
var transaction = new Transaction()
.from(utxo, [public1, public2, public3], 2, true)
.to(address, 1000000);
var input = transaction.inputs[0];
var satoshisBuffer = input.getSatoshisBuffer();
satoshisBuffer.toString('hex').should.equal('40420f0000000000');
});
});

3
test/transaction/transaction.js

@ -1266,7 +1266,7 @@ describe('Transaction', function() {
address: address.toString(),
txId: '72a0b3d6dcbba9d2ae74c11eec05cdfc2a03e1a01b3bbb09af0cc2dc8c3dbefa',
outputIndex: 0,
script: Script.buildScriptHashOut(address).toString(),
script: Script.buildScriptHashOut(address).toHex(),
satoshis: 1e8
};
it('will sign with nested p2sh witness program', function() {
@ -1277,6 +1277,7 @@ describe('Transaction', function() {
.change('DF8MrzMiDkTvT4qpeCAdW6Y37WGgbo9Cmu')
.sign(privateKey1)
.sign(privateKey2);
// TODO: check correct signature
});
});
});

Loading…
Cancel
Save