extractSigs - verify pubKey & pubKeyHash purported public keys, plus a round of comments

This commit is contained in:
Thomas Kerin 2016-11-12 18:01:54 +01:00
parent c215f350fc
commit b09cf89f97

View File

@ -185,12 +185,19 @@ InSigner.prototype.extractStandard = function (solution, chunks, sigVersion) {
if (solution.type === bscript.types.P2PK) { if (solution.type === bscript.types.P2PK) {
if (bscript.pubKey.input.check(chunks)) { if (bscript.pubKey.input.check(chunks)) {
decoded = bscript.pubKey.input.decode(chunks) decoded = bscript.pubKey.input.decode(chunks)
if (!decoded.pubKey.equals(solution.solvedBy)) {
throw new Error('Key in scriptSig does not match output script key')
}
signatures[0] = decoded.signature signatures[0] = decoded.signature
publicKeys[0] = solution.solvedBy publicKeys[0] = solution.solvedBy
} }
} else if (solution.type === bscript.types.P2PKH) { } else if (solution.type === bscript.types.P2PKH) {
if (bscript.pubKeyHash.input.check(chunks)) { if (bscript.pubKeyHash.input.check(chunks)) {
decoded = bscript.pubKeyHash.input.decode(chunks) decoded = bscript.pubKeyHash.input.decode(chunks)
if (!bcrypto.hash160(decoded.pubKey).equals(solution.solvedBy)) {
throw new Error('Key in scriptSig does not match output script key-hash')
}
signatures[0] = decoded.signature signatures[0] = decoded.signature
publicKeys[0] = decoded.pubKey publicKeys[0] = decoded.pubKey
} }
@ -216,67 +223,75 @@ InSigner.prototype.extractStandard = function (solution, chunks, sigVersion) {
} }
InSigner.prototype.solve = function (opts) { InSigner.prototype.solve = function (opts) {
// Determine scriptPubKey is solvable
var scriptPubKey = solveScript(opts.scriptPubKey) var scriptPubKey = solveScript(opts.scriptPubKey)
if (scriptPubKey.type !== bscript.types.P2SH && ALLOWED_P2SH_SCRIPTS.indexOf(scriptPubKey.type) === -1) { if (scriptPubKey.type !== bscript.types.P2SH && ALLOWED_P2SH_SCRIPTS.indexOf(scriptPubKey.type) === -1) {
throw new Error('txOut script is non-standard') throw new Error('txOut script is non-standard')
} }
var solution = scriptPubKey
var redeemScript var redeemScript
var witnessScript var witnessScript
var value = 0
var sigVersion = Transaction.SIG_V0 var sigVersion = Transaction.SIG_V0
var solution = scriptPubKey var value = 0
if (solution.type === bscript.types.P2SH) { if (solution.type === bscript.types.P2SH) {
var scriptHash = solution.solvedBy var scriptHash = solution.solvedBy
// Redeem script must be provided by opts
if (!(opts.redeemScript instanceof Buffer)) { if (!(opts.redeemScript instanceof Buffer)) {
throw new Error('Redeem script required to solve utxo') throw new Error('Redeem script required to solve utxo')
} }
// Check redeemScript against script-hash
if (!scriptHash.equals(bcrypto.hash160(opts.redeemScript))) { if (!scriptHash.equals(bcrypto.hash160(opts.redeemScript))) {
throw new Error('Redeem script does not match txOut script hash') throw new Error('Redeem script does not match txOut script hash')
} }
// Determine redeemScript is solvable
solution = solveScript(opts.redeemScript) solution = solveScript(opts.redeemScript)
if (ALLOWED_P2SH_SCRIPTS.indexOf(solution.type)) { if (!ALLOWED_P2SH_SCRIPTS.indexOf(solution.type)) {
redeemScript = solution
} else {
throw new Error('Unsupported P2SH script') throw new Error('Unsupported P2SH script')
} }
redeemScript = solution
} }
if (solution.type === bscript.types.P2WPKH) { if (solution.type === bscript.types.P2WPKH) {
// txOutValue is required here
if (!types.Satoshi(opts.value)) { if (!types.Satoshi(opts.value)) {
throw new Error('Value is required for witness-key-hash') throw new Error('Value is required for witness-key-hash')
} }
// We set solution to this to avoid work later, since P2WPKH is a special case of P2PKH
solution = solveScript(bscript.pubKeyHash.output.encode(solution.solvedBy)) solution = solveScript(bscript.pubKeyHash.output.encode(solution.solvedBy))
value = opts.value
sigVersion = Transaction.SIG_V1 sigVersion = Transaction.SIG_V1
value = opts.value
} else if (solution.type === bscript.types.P2WSH) { } else if (solution.type === bscript.types.P2WSH) {
var witnessScriptHash = solution.solvedBy var witnessScriptHash = solution.solvedBy
// Witness script must be provided by opts
if (!(opts.witnessScript instanceof Buffer)) { if (!(opts.witnessScript instanceof Buffer)) {
throw new Error('P2WSH script required to solve utxo') throw new Error('P2WSH script required to solve utxo')
} }
// txOutValue is required here
if (!types.Satoshi(opts.value)) { if (!types.Satoshi(opts.value)) {
throw new Error('Value is required for witness-script-hash') throw new Error('Value is required for witness-script-hash')
} }
if (!bufferEquals(bcrypto.sha256(opts.witnessScript), witnessScriptHash)) { // Check witnessScript against script hash
if (!bcrypto.sha256(opts.witnessScript).equals(witnessScriptHash)) {
throw new Error('Witness script does not match txOut script hash') throw new Error('Witness script does not match txOut script hash')
} }
solution = witnessScript = solveScript(opts.witnessScript) solution = solveScript(opts.witnessScript)
value = opts.value // Determine if witnessScript is solvable
sigVersion = Transaction.SIG_V1 if (SIGNABLE_SCRIPTS.indexOf(solution.type) === -1) {
if (SIGNABLE_SCRIPTS.indexOf(witnessScript.type) === -1) {
throw new Error('witness script is not supported') throw new Error('witness script is not supported')
} }
witnessScript = solution
sigVersion = Transaction.SIG_V1
value = opts.value
} }
this.signScript = solution this.signScript = solution
this.scriptPubKey = scriptPubKey this.scriptPubKey = scriptPubKey
this.value = value
this.sigVersion = sigVersion
this.redeemScript = redeemScript this.redeemScript = redeemScript
this.witnessScript = witnessScript this.witnessScript = witnessScript
this.sigVersion = sigVersion
this.value = value
} }
InSigner.prototype.extractSig = function () { InSigner.prototype.extractSig = function () {
@ -284,20 +299,20 @@ InSigner.prototype.extractSig = function () {
var input = this.tx.ins[this.nIn] var input = this.tx.ins[this.nIn]
var solution = this.scriptPubKey var solution = this.scriptPubKey
var extractChunks = [] var extractChunks = []
var sigVersion = 0
if (solution.canSign) { if (solution.canSign) {
extractChunks = evalPushOnly(input.script) extractChunks = evalPushOnly(input.script)
} }
if (solution.type === bscript.types.P2SH) { if (solution.type === bscript.types.P2SH) {
if (bscript.scriptHash.input.check(input.script)) { if (bscript.scriptHash.input.check(input.script)) {
// If we go to extract a P2SH scriptSig, verify the provided redeemScript
var p2sh = bscript.scriptHash.input.decode(input.script) var p2sh = bscript.scriptHash.input.decode(input.script)
if (!p2sh.redeemScript.equals(this.redeemScript.script)) { if (!p2sh.redeemScript.equals(this.redeemScript.script)) {
throw new Error('Redeem script from scriptSig does not match') throw new Error('Redeem script from scriptSig does not match')
} }
solution = this.redeemScript solution = this.redeemScript
if (solution.canSign) { if (solution.canSign) {
// We only bother if canSign, otherwise we waste time
extractChunks = evalPushOnly(p2sh.redeemScriptSig) extractChunks = evalPushOnly(p2sh.redeemScriptSig)
} }
} }
@ -310,7 +325,6 @@ InSigner.prototype.extractSig = function () {
throw new Error('Public key does not match key-hash') throw new Error('Public key does not match key-hash')
} }
sigVersion = 1
extractChunks = input.witness extractChunks = input.witness
} }
} else if (solution.type === bscript.types.P2WSH) { } else if (solution.type === bscript.types.P2WSH) {
@ -318,14 +332,13 @@ InSigner.prototype.extractSig = function () {
if (!this.witnessScript.equals(input.witness[ input.witness.length - 1 ])) { if (!this.witnessScript.equals(input.witness[ input.witness.length - 1 ])) {
throw new Error('Witness script does not match') throw new Error('Witness script does not match')
} }
sigVersion = 1
solution = input.witnessScript solution = input.witnessScript
extractChunks = input.witness.slice(0, -1) extractChunks = input.witness.slice(0, -1)
} }
} }
if (extractChunks.length > 0) { if (extractChunks.length > 0) {
[this.signatures, this.publicKeys] = this.extractStandard(solution, extractChunks, sigVersion) [this.signatures, this.publicKeys] = this.extractStandard(solution, extractChunks, this.sigVersion)
} }
} }