improve input checks with keys/hashes/redeemscript.

This commit is contained in:
Christopher Jeffrey 2015-12-17 16:53:35 -08:00
parent 6caa6b91dd
commit 6abfc10a28
3 changed files with 82 additions and 52 deletions

View File

@ -762,6 +762,15 @@ script.execute = function execute(s, stack, tx, index) {
return true;
};
script.exec = function(input, output, tx, i) {
var stack = [];
script.execute(input, stack, tx, i);
var res = script.execute(output, stack, tx, i);
if (!res || stack.length === 0 || !utils.isEqual(stack.pop(), [ 1 ]))
return false;
return true;
};
script.multisig = function(keys, m, n) {
if (keys.length < m)
throw new Error('Wrong amount of pubkeys for multisig script');
@ -889,11 +898,13 @@ script.isMultisig = function isMultisig(s, pubs) {
if (!pubs)
return keys;
return m === keys.filter(function(k) {
var total = keys.filter(function(k) {
return pubs.some(function(pub) {
return utils.isEqual(k, pub);
});
}).length;
return total >= m;
};
script.isScripthash = function isScripthash(s, hash) {
@ -903,12 +914,12 @@ script.isScripthash = function isScripthash(s, hash) {
if (s.length !== 3)
return false;
var ret = s[0] === 'hash160' &&
var res = s[0] === 'hash160' &&
Array.isArray(s[1]) &&
s[1].length === 20 &&
s[2] === 'eq';
if (!ret)
if (!res)
return false;
if (hash)
@ -941,29 +952,32 @@ script.standardInput = function standardInput(s) {
|| null;
};
script.isPubkeyInput = function isPubkeyInput(s, key) {
if (key)
throw new Error('Cannot check for pubkey in p2pk input.');
script.isPubkeyInput = function isPubkeyInput(s, key, tx, i) {
if (s.length !== 1 || !Array.isArray(s[0]))
return false;
// return script.isValidSig(s[0]);
// var res = script.isValidSig(s[0]);
var res = 9 <= s[0].length && s[0].length <= 73;
if (!res)
return false;
return 9 <= s[0].length && s[0].length <= 73;
if (key)
return script.exec(s, [key, 'checksig'], tx, i);
return true;
};
script.isPubkeyhashInput = function isPubkeyhashInput(s, key) {
if (s.length !== 2 || !Array.isArray(s[0]) || !Array.isArray(s[1]))
return false;
// var ret = script.isValidSig(s[0]) &&
// var res = script.isValidSig(s[0]) &&
// 33 <= s[1].length && s[1].length <= 65;
var ret = 9 <= s[0].length && s[0].length <= 73 &&
var res = 9 <= s[0].length && s[0].length <= 73 &&
33 <= s[1].length && s[1].length <= 65;
if (!ret)
if (!res)
return false;
if (key)
@ -972,71 +986,50 @@ script.isPubkeyhashInput = function isPubkeyhashInput(s, key) {
return true;
};
script.isMultisigInput = function isMultisigInput(s, pubs) {
script.isMultisigInput = function isMultisigInput(s, pubs, tx, i) {
if (s.length < 3)
return false;
if (!Array.isArray(s[0]) || s[0].length !== 0)
return false;
if (pubs && !Array.isArray(pubs[0]))
pubs = [pubs];
var total = 0;
for (var i = 1; i < s.length; i++) {
var ret = Array.isArray(s[i]) && 33 <= s[i].length && s[i].length <= 65;
if (!ret)
// var res = Array.isArray(s[i]) && script.isValidSig(s[i]);
var res = Array.isArray(s[i]) && 9 <= s[i].length && s[i].length <= 73;
if (!res)
return false;
if (pubs) {
var has = pubs.some(function(pub) {
return utils.isEqual(s[i], pub);
});
if (has)
total++;
}
}
if (!pubs)
return true;
if (pubs && pubs.length >= 2) {
var o = script.multisig(pubs, 2, pubs.length);
return script.exec(s, o, tx, i);
}
return total;
return true;
};
script.isScripthashInput = function isScripthashInput(s, pubs) {
script.isScripthashInput = function isScripthashInput(s, redeem) {
if (s.length < 4)
return false;
if (!Array.isArray(s[0]) || s[0].length !== 0)
return false;
if (pubs && !Array.isArray(pubs[0]))
pubs = [pubs];
var total = 0;
for (var i = 1; i < s.length - 1; i++) {
var ret = Array.isArray(s[i]) && 33 <= s[i].length && s[i].length <= 65;
if (!ret)
// var res = Array.isArray(s[i]) && script.isValidSig(s[i]);
var res = Array.isArray(s[i]) && 9 <= s[i].length && s[i].length <= 73;
if (!res)
return false;
if (pubs) {
var has = pubs.some(function(pub) {
return utils.isEqual(s[i], pub);
});
if (has)
total++;
}
}
var r = Array.isArray(s[s.length - 1]) && s[s.length - 1];
if (r[r.length - 1] !== constants.opcodes.checkmultisig)
return false;
if (!pubs)
return true;
if (redeem)
return utils.isEqual(redeem, r);
// var m = r[0];
// return m === total;
return total;
return true;
};
// https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki

View File

@ -125,18 +125,40 @@ TX.prototype._inputIndex = function _inputIndex(hash, index) {
return -1;
};
TX.prototype.signature = function(input, key, type) {
TX.prototype.signatureHash = function(i, type) {
if (typeof i === 'object')
i = this.inputs.indexOf(i);
if (!type)
type = 'all';
if (typeof type === 'string')
type = constants.hashType[type];
// Get the current input.
var input = this.inputs[i];
// Get the previous output's subscript
var s = input.out.tx.getSubscript(input.out.index);
// Get the hash of the current tx, minus the other inputs, plus the sighash.
var hash = this.subscriptHash(tx.inputs.indexOf(input), s, type);
var hash = this.subscriptHash(i, s, type);
return hash;
};
TX.prototype.signature = function(i, key, type) {
if (typeof i === 'object')
i = this.inputs.indexOf(i);
if (!type)
type = 'all';
if (typeof type === 'string')
type = constants.hashType[type];
// Get the hash of the current tx, minus the other inputs, plus the sighash.
var hash = this.sigHash(i, type);
// Sign the transaction with our one input
var signature = bcoin.ecdsa.sign(hash, key.priv).toDER();

View File

@ -357,6 +357,7 @@ Wallet.validateAddress = Wallet.prototype.validateAddress;
Wallet.prototype.ownOutput = function ownOutput(tx, index) {
var scriptHash = this.getFullHash();
var hash = this.getOwnHash();
var key = this.getOwnPublicKey();
var keys = this.getPublicKeys();
var outputs = tx.outputs.filter(function(output, i) {
@ -365,7 +366,7 @@ Wallet.prototype.ownOutput = function ownOutput(tx, index) {
var s = output.script;
if (bcoin.script.isPubkey(s, hash))
if (bcoin.script.isPubkey(s, key))
return true;
if (bcoin.script.isPubkeyhash(s, hash))
@ -390,19 +391,33 @@ Wallet.prototype.ownInput = function ownInput(tx, index) {
var scriptHash = this.getFullHash();
var hash = this.getOwnHash();
var key = this.getOwnPublicKey();
var redeem = this.getFullPublicKey();
var keys = this.getPublicKeys();
var inputs = tx.inputs.filter(function(input, i) {
if (index !== undefined && index !== i)
return false;
// if (bcoin.script.isPubkeyInput(input.script, key, tx, i))
// return true;
if (bcoin.script.isPubkeyhashInput(input.script, key))
return true;
if (bcoin.script.isScripthashInput(input.script, redeem))
return true;
// if (bcoin.script.isMultisigInput(input.script, key, tx, i))
// return true;
if (!input.out.tx)
return false;
var s = input.out.tx.outputs[input.out.index].script;
if (bcoin.script.isPubkey(s, key))
return true;
if (bcoin.script.isPubkeyhash(s, hash))
return true;