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; 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) { script.multisig = function(keys, m, n) {
if (keys.length < m) if (keys.length < m)
throw new Error('Wrong amount of pubkeys for multisig script'); throw new Error('Wrong amount of pubkeys for multisig script');
@ -889,11 +898,13 @@ script.isMultisig = function isMultisig(s, pubs) {
if (!pubs) if (!pubs)
return keys; return keys;
return m === keys.filter(function(k) { var total = keys.filter(function(k) {
return pubs.some(function(pub) { return pubs.some(function(pub) {
return utils.isEqual(k, pub); return utils.isEqual(k, pub);
}); });
}).length; }).length;
return total >= m;
}; };
script.isScripthash = function isScripthash(s, hash) { script.isScripthash = function isScripthash(s, hash) {
@ -903,12 +914,12 @@ script.isScripthash = function isScripthash(s, hash) {
if (s.length !== 3) if (s.length !== 3)
return false; return false;
var ret = s[0] === 'hash160' && var res = s[0] === 'hash160' &&
Array.isArray(s[1]) && Array.isArray(s[1]) &&
s[1].length === 20 && s[1].length === 20 &&
s[2] === 'eq'; s[2] === 'eq';
if (!ret) if (!res)
return false; return false;
if (hash) if (hash)
@ -941,29 +952,32 @@ script.standardInput = function standardInput(s) {
|| null; || null;
}; };
script.isPubkeyInput = function isPubkeyInput(s, key) { script.isPubkeyInput = function isPubkeyInput(s, key, tx, i) {
if (key)
throw new Error('Cannot check for pubkey in p2pk input.');
if (s.length !== 1 || !Array.isArray(s[0])) if (s.length !== 1 || !Array.isArray(s[0]))
return false; 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) { script.isPubkeyhashInput = function isPubkeyhashInput(s, key) {
if (s.length !== 2 || !Array.isArray(s[0]) || !Array.isArray(s[1])) if (s.length !== 2 || !Array.isArray(s[0]) || !Array.isArray(s[1]))
return false; return false;
// var ret = script.isValidSig(s[0]) && // var res = script.isValidSig(s[0]) &&
// 33 <= s[1].length && s[1].length <= 65; // 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; 33 <= s[1].length && s[1].length <= 65;
if (!ret) if (!res)
return false; return false;
if (key) if (key)
@ -972,71 +986,50 @@ script.isPubkeyhashInput = function isPubkeyhashInput(s, key) {
return true; return true;
}; };
script.isMultisigInput = function isMultisigInput(s, pubs) { script.isMultisigInput = function isMultisigInput(s, pubs, tx, i) {
if (s.length < 3) if (s.length < 3)
return false; return false;
if (!Array.isArray(s[0]) || s[0].length !== 0) if (!Array.isArray(s[0]) || s[0].length !== 0)
return false; return false;
if (pubs && !Array.isArray(pubs[0]))
pubs = [pubs];
var total = 0;
for (var i = 1; i < s.length; i++) { for (var i = 1; i < s.length; i++) {
var ret = Array.isArray(s[i]) && 33 <= s[i].length && s[i].length <= 65; // var res = Array.isArray(s[i]) && script.isValidSig(s[i]);
if (!ret) var res = Array.isArray(s[i]) && 9 <= s[i].length && s[i].length <= 73;
if (!res)
return false; return false;
if (pubs) {
var has = pubs.some(function(pub) {
return utils.isEqual(s[i], pub);
});
if (has)
total++;
}
} }
if (!pubs) if (pubs && pubs.length >= 2) {
return true; 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) if (s.length < 4)
return false; return false;
if (!Array.isArray(s[0]) || s[0].length !== 0) if (!Array.isArray(s[0]) || s[0].length !== 0)
return false; return false;
if (pubs && !Array.isArray(pubs[0]))
pubs = [pubs];
var total = 0;
for (var i = 1; i < s.length - 1; i++) { for (var i = 1; i < s.length - 1; i++) {
var ret = Array.isArray(s[i]) && 33 <= s[i].length && s[i].length <= 65; // var res = Array.isArray(s[i]) && script.isValidSig(s[i]);
if (!ret) var res = Array.isArray(s[i]) && 9 <= s[i].length && s[i].length <= 73;
if (!res)
return false; 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]; var r = Array.isArray(s[s.length - 1]) && s[s.length - 1];
if (r[r.length - 1] !== constants.opcodes.checkmultisig) if (r[r.length - 1] !== constants.opcodes.checkmultisig)
return false; return false;
if (!pubs) if (redeem)
return true; return utils.isEqual(redeem, r);
// var m = r[0]; return true;
// return m === total;
return total;
}; };
// https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki // 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; 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) if (!type)
type = 'all'; type = 'all';
if (typeof type === 'string') if (typeof type === 'string')
type = constants.hashType[type]; type = constants.hashType[type];
// Get the current input.
var input = this.inputs[i];
// Get the previous output's subscript // Get the previous output's subscript
var s = input.out.tx.getSubscript(input.out.index); var s = input.out.tx.getSubscript(input.out.index);
// Get the hash of the current tx, minus the other inputs, plus the sighash. // 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 // Sign the transaction with our one input
var signature = bcoin.ecdsa.sign(hash, key.priv).toDER(); 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) { Wallet.prototype.ownOutput = function ownOutput(tx, index) {
var scriptHash = this.getFullHash(); var scriptHash = this.getFullHash();
var hash = this.getOwnHash(); var hash = this.getOwnHash();
var key = this.getOwnPublicKey();
var keys = this.getPublicKeys(); var keys = this.getPublicKeys();
var outputs = tx.outputs.filter(function(output, i) { var outputs = tx.outputs.filter(function(output, i) {
@ -365,7 +366,7 @@ Wallet.prototype.ownOutput = function ownOutput(tx, index) {
var s = output.script; var s = output.script;
if (bcoin.script.isPubkey(s, hash)) if (bcoin.script.isPubkey(s, key))
return true; return true;
if (bcoin.script.isPubkeyhash(s, hash)) if (bcoin.script.isPubkeyhash(s, hash))
@ -390,19 +391,33 @@ Wallet.prototype.ownInput = function ownInput(tx, index) {
var scriptHash = this.getFullHash(); var scriptHash = this.getFullHash();
var hash = this.getOwnHash(); var hash = this.getOwnHash();
var key = this.getOwnPublicKey(); var key = this.getOwnPublicKey();
var redeem = this.getFullPublicKey();
var keys = this.getPublicKeys(); var keys = this.getPublicKeys();
var inputs = tx.inputs.filter(function(input, i) { var inputs = tx.inputs.filter(function(input, i) {
if (index !== undefined && index !== i) if (index !== undefined && index !== i)
return false; return false;
// if (bcoin.script.isPubkeyInput(input.script, key, tx, i))
// return true;
if (bcoin.script.isPubkeyhashInput(input.script, key)) if (bcoin.script.isPubkeyhashInput(input.script, key))
return true; 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) if (!input.out.tx)
return false; return false;
var s = input.out.tx.outputs[input.out.index].script; var s = input.out.tx.outputs[input.out.index].script;
if (bcoin.script.isPubkey(s, key))
return true;
if (bcoin.script.isPubkeyhash(s, hash)) if (bcoin.script.isPubkeyhash(s, hash))
return true; return true;