mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-24 23:08:31 +01:00
Fixing bug of finding hash type of the empty digital signature
This commit is contained in:
parent
932705595b
commit
46eb3eb7ea
6 changed files with 38 additions and 22 deletions
|
@ -122,10 +122,13 @@ trait TransactionSignatureChecker extends BitcoinSLogger {
|
|||
scriptPubKey match {
|
||||
case x : P2SHScriptPubKey =>
|
||||
val redeemScript = p2shScriptSignature.redeemScript
|
||||
|
||||
redeemScript match {
|
||||
case y : MultiSignatureScriptPubKey =>
|
||||
//the signatures & pubkeys need to be reversed so that they are evaluated the
|
||||
//same way as if they were getting pushed then popped off of a stack
|
||||
multiSignatureHelper(spendingTransaction, inputIndex, y,
|
||||
p2shScriptSignature.signatures.toList, p2shScriptSignature.publicKeys.toList, requireStrictDEREncoding, y.requiredSigs)
|
||||
p2shScriptSignature.signatures.toList.reverse, p2shScriptSignature.publicKeys.toList.reverse, requireStrictDEREncoding, y.requiredSigs)
|
||||
case _ : P2PKHScriptPubKey | _ : P2PKScriptPubKey | _ : P2SHScriptPubKey | _ : NonStandardScriptPubKey | EmptyScriptPubKey =>
|
||||
throw new RuntimeException("Don't know how to implement this scriptPubKeys in a redeemScript")
|
||||
}
|
||||
|
@ -160,9 +163,12 @@ trait TransactionSignatureChecker extends BitcoinSLogger {
|
|||
multiSignatureScript : MultiSignatureScriptSignature, requireStrictDEREncoding : Boolean) : Boolean = {
|
||||
scriptPubKey match {
|
||||
case x : MultiSignatureScriptPubKey =>
|
||||
//the signatures & pubkeys need to be reversed so that they are evaluated the
|
||||
//same way as if they were getting pushed then popped off of a stack
|
||||
logger.info("multisig public keys: " + x.publicKeys)
|
||||
multiSignatureHelper(spendingTransaction,inputIndex,x,multiSignatureScript.signatures.toList,
|
||||
x.publicKeys.toList,requireStrictDEREncoding,x.requiredSigs)
|
||||
logger.info("multisig sigs: " + multiSignatureScript.signatures)
|
||||
multiSignatureHelper(spendingTransaction,inputIndex,x,multiSignatureScript.signatures.toList.reverse,
|
||||
x.publicKeys.toList.reverse,requireStrictDEREncoding,x.requiredSigs)
|
||||
case x : P2PKHScriptPubKey =>
|
||||
logger.warn("Trying to check if a multisignature scriptSig spends a p2pkh scriptPubKey properly - this is trivially false")
|
||||
false
|
||||
|
@ -218,6 +224,7 @@ trait TransactionSignatureChecker extends BitcoinSLogger {
|
|||
private def multiSignatureHelper(spendingTransaction : Transaction, inputIndex : Int, scriptPubKey : MultiSignatureScriptPubKey,
|
||||
sigs : List[ECDigitalSignature], pubKeys : List[ECPublicKey], requireStrictDEREncoding : Boolean,
|
||||
requiredSigs : Long) : Boolean = {
|
||||
logger.info("Signatures inside of helper: " + sigs)
|
||||
logger.info("public keys inside of helper: " + pubKeys)
|
||||
if (sigs.size > pubKeys.size) {
|
||||
//this is how bitcoin core treats this. If there are ever any more
|
||||
|
|
|
@ -64,12 +64,8 @@ trait MultiSignatureScriptPubKey extends ScriptPubKey {
|
|||
def requiredSigs = {
|
||||
val asmWithoutPushOps = asm.filterNot(_.isInstanceOf[BytesToPushOntoStack])
|
||||
val opCheckMultiSigIndex = if (asm.indexOf(OP_CHECKMULTISIG) != -1) asmWithoutPushOps.indexOf(OP_CHECKMULTISIG) else asmWithoutPushOps.indexOf(OP_CHECKMULTISIGVERIFY)
|
||||
logger.debug("OP_CHECKMULTISIG index: " + opCheckMultiSigIndex)
|
||||
logger.debug("Max sigs: " + maxSigs)
|
||||
logger.debug("asm filter push ops: " + asmWithoutPushOps)
|
||||
//magic number 2 represents the maxSig operation and the OP_CHECKMULTISIG operation at the end of the asm
|
||||
val numSigsRequired = asmWithoutPushOps(opCheckMultiSigIndex - maxSigs.toInt - 2)
|
||||
logger.debug("num sigs required: " + numSigsRequired)
|
||||
numSigsRequired match {
|
||||
case x : ScriptNumber => x.num
|
||||
case _ => throw new RuntimeException("The first element of the multisignature pubkey must be a script number operation\n" +
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package org.scalacoin.protocol.script
|
||||
|
||||
import org.scalacoin.crypto.{ECPublicKey, ECFactory, ECDigitalSignature}
|
||||
import org.scalacoin.crypto.{EmptyDigitalSignature, ECPublicKey, ECFactory, ECDigitalSignature}
|
||||
import org.scalacoin.marshallers.script.{RawScriptSignatureParser, RawScriptPubKeyParser, ScriptParser}
|
||||
import org.scalacoin.marshallers.transaction.TransactionElement
|
||||
|
||||
import org.scalacoin.script.constant._
|
||||
import org.scalacoin.script.crypto.{OP_CHECKMULTISIG, HashType, HashTypeFactory}
|
||||
import org.scalacoin.script.crypto.{SIGHASH_ALL, OP_CHECKMULTISIG, HashType, HashTypeFactory}
|
||||
import org.scalacoin.util.{BitcoinSLogger, BitcoinSUtil}
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
|
@ -39,9 +39,10 @@ sealed trait ScriptSignature extends TransactionElement with ScriptSignatureFact
|
|||
* @return
|
||||
*/
|
||||
def hashType(digitalSignature: ECDigitalSignature) = {
|
||||
require(HashTypeFactory.fromByte(digitalSignature.bytes.last).isDefined,
|
||||
"Hash type could not be read for this scriptSig: " + digitalSignature.hex)
|
||||
HashTypeFactory.fromByte(digitalSignature.bytes.last).get
|
||||
digitalSignature match {
|
||||
case EmptyDigitalSignature => SIGHASH_ALL
|
||||
case sig : ECDigitalSignature => HashTypeFactory.fromByte(digitalSignature.bytes.last).get
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,8 +157,8 @@ trait MultiSignatureScriptSignature extends ScriptSignature {
|
|||
* @return
|
||||
*/
|
||||
def signatures : Seq[ECDigitalSignature] = {
|
||||
asm.filter(_.isInstanceOf[ScriptConstant])
|
||||
.filterNot(_.isInstanceOf[ScriptNumberOperation])
|
||||
asm.tail.filter(_.isInstanceOf[ScriptConstant])
|
||||
/* .filterNot(_.isInstanceOf[BytesToPushOntoStack])*/
|
||||
.map(sig => ECFactory.digitalSignature(sig.hex))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,4 +58,6 @@ class MultiSignatureScriptPubKeyTest extends FlatSpec with MustMatchers {
|
|||
))
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.scalacoin.protocol.script
|
||||
|
||||
import org.scalacoin.crypto.{EmptyDigitalSignature, ECFactory}
|
||||
import org.scalacoin.script.constant.{ScriptConstantImpl, BytesToPushOntoStackImpl, OP_0}
|
||||
import org.scalacoin.util.TransactionTestUtil
|
||||
import org.scalatest.{MustMatchers, FlatSpec}
|
||||
|
||||
|
@ -13,4 +15,12 @@ class MultiSignatureScriptSignatureTest extends FlatSpec with MustMatchers {
|
|||
val scriptSig = spendingTx.inputs(inputIndex).scriptSignature
|
||||
scriptSig.signatures.size must be (2)
|
||||
}
|
||||
|
||||
it must "give us the empty signature back when it is encoded as an OP_0 (this pushes an empty signature onto the stack)" in {
|
||||
val multiSigScriptSignature = ScriptSignatureFactory.fromAsm(List(OP_0, BytesToPushOntoStackImpl(71),
|
||||
ScriptConstantImpl("30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201"), OP_0))
|
||||
multiSigScriptSignature.signatures must be (Seq(
|
||||
ECFactory.digitalSignature("30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201"),
|
||||
EmptyDigitalSignature))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,18 +85,18 @@ class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterp
|
|||
val source = scala.io.Source.fromFile("src/test/scala/org/scalacoin/script/interpreter/script_valid.json")
|
||||
|
||||
//use this to represent a single test case from script_valid.json
|
||||
/* val lines =
|
||||
val lines =
|
||||
"""
|
||||
|
|
||||
|[[
|
||||
"0 0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",
|
||||
"2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT",
|
||||
"STRICTENC",
|
||||
"2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but second signature invalid. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid signature."
|
||||
]]
|
||||
""".stripMargin*/
|
||||
| "0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0",
|
||||
| "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
|
||||
| "DERSIG",
|
||||
| "BIP66 example 12, with DERSIG"
|
||||
|]]
|
||||
""".stripMargin
|
||||
|
||||
val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close()
|
||||
//val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close()
|
||||
val json = lines.parseJson
|
||||
val testCasesOpt : Seq[Option[CoreTestCase]] = json.convertTo[Seq[Option[CoreTestCase]]]
|
||||
val testCases : Seq[CoreTestCase] = testCasesOpt.flatten
|
||||
|
|
Loading…
Add table
Reference in a new issue