bitcore/lib/transaction/sighash.js

113 lines
3.3 KiB
JavaScript
Raw Normal View History

'use strict';
var buffer = require('buffer');
var Signature = require('../crypto/signature');
var Script = require('../script');
var Output = require('./output');
var BufferReader = require('../encoding/bufferreader');
var BufferWriter = require('../encoding/bufferwriter');
var BN = require('../crypto/bn');
var Hash = require('../crypto/hash');
var ECDSA = require('../crypto/ecdsa');
2014-12-15 14:50:34 -08:00
var $ = require('../util/preconditions');
var SIGHASH_SINGLE_BUG = '0000000000000000000000000000000000000000000000000000000000000001';
var BITS_64_ON = 'ffffffffffffffff';
/**
* Returns a buffer of length 32 bytes with the hash that needs to be signed
* for OP_CHECKSIG.
*
* @param {Transaction} transaction the transaction to sign
* @param {number} sighashType the type of the hash
* @param {number} inputNumber the input index for the signature
* @param {Script} subscript the script that will be signed
*/
2014-12-15 22:11:55 -08:00
var sighash = function sighash(transaction, sighashType, inputNumber, subscript) {
var Transaction = require('./transaction');
var Input = require('./input');
var i;
// Copy transaction
var txcopy = Transaction.shallowCopy(transaction);
// Copy script
subscript = new Script(subscript);
subscript.removeCodeseparators();
for (i = 0; i < txcopy.inputs.length; i++) {
// Blank signatures for other inputs
txcopy.inputs[i] = new Input(txcopy.inputs[i]).setScript(Script.empty());
}
2014-12-15 22:11:55 -08:00
txcopy.inputs[inputNumber] = new Input(txcopy.inputs[inputNumber]).setScript(subscript);
if ((sighashType & 31) === Signature.SIGHASH_NONE ||
2014-12-15 22:11:55 -08:00
(sighashType & 31) === Signature.SIGHASH_SINGLE) {
// clear all sequenceNumbers
for (i = 0; i < txcopy.inputs.length; i++) {
if (i !== inputNumber) {
txcopy.inputs[i].sequenceNumber = 0;
}
}
}
if ((sighashType & 31) === Signature.SIGHASH_NONE) {
txcopy.outputs = [];
} else if ((sighashType & 31) === Signature.SIGHASH_SINGLE) {
// The SIGHASH_SINGLE bug.
// https://bitcointalk.org/index.php?topic=260595.0
if (inputNumber > txcopy.outputs.length - 1) {
return new Buffer(SIGHASH_SINGLE_BUG, 'hex');
}
if (txcopy.outputs.length <= inputNumber) {
throw new Error('Missing output to sign');
}
txcopy.outputs.length = inputNumber + 1;
for (i = 0; i < inputNumber; i++) {
txcopy.outputs[i] = new Output({
satoshis: BN().fromBuffer(new buffer.Buffer(BITS_64_ON, 'hex')),
script: Script.empty()
});
}
}
if (sighashType & Signature.SIGHASH_ANYONECANPAY) {
txcopy.inputs = [txcopy.inputs[inputNumber]];
}
var buf = BufferWriter()
.write(txcopy.toBuffer())
.writeInt32LE(sighashType)
.toBuffer();
2014-12-15 22:11:55 -08:00
var ret = Hash.sha256sha256(buf);
ret = new BufferReader(ret).readReverse();
return ret;
};
2014-12-15 22:11:55 -08:00
var sign = function sign(transaction, keypair, nhashtype, nin, subscript) {
var hashbuf = sighash(transaction, nhashtype, nin, subscript);
2014-12-15 22:11:55 -08:00
var sig = ECDSA.sign(hashbuf, keypair, 'little').set({
nhashtype: nhashtype
});
return sig;
2014-12-15 22:11:55 -08:00
};
2014-12-15 22:11:55 -08:00
var verify = function verify(transaction, sig, pubkey, nin, subscript) {
2014-12-15 14:50:34 -08:00
$.checkArgument(transaction);
$.checkArgument(sig && sig.nhashtype);
var hashbuf = sighash(transaction, sig.nhashtype, nin, subscript);
return ECDSA.verify(hashbuf, sig, pubkey, 'little');
2014-12-15 22:11:55 -08:00
};
module.exports = {
sighash: sighash,
sign: sign,
verify: verify
};