mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-24 23:08:31 +01:00
Adding code to implement the script flag NULLDUMMy, changing how mulsignature script sigs are assigned in the factory. Now it can be ANY script number operation. When the script is evaluated it checks the NULLDUMMY flag and if the scriptsig starts with an OP_0
This commit is contained in:
parent
2a1f8742ce
commit
ff0b117c0e
3 changed files with 49 additions and 44 deletions
|
@ -158,7 +158,6 @@ trait MultiSignatureScriptSignature extends ScriptSignature {
|
|||
*/
|
||||
def signatures : Seq[ECDigitalSignature] = {
|
||||
asm.tail.filter(_.isInstanceOf[ScriptConstant])
|
||||
/* .filterNot(_.isInstanceOf[BytesToPushOntoStack])*/
|
||||
.map(sig => ECFactory.digitalSignature(sig.hex))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import org.scalacoin.crypto._
|
|||
import org.scalacoin.protocol.script._
|
||||
import org.scalacoin.protocol.transaction.Transaction
|
||||
import org.scalacoin.script.control.{ControlOperationsInterpreter, OP_VERIFY}
|
||||
import org.scalacoin.script.flag.ScriptVerifyDerSig
|
||||
import org.scalacoin.script.flag.{ScriptVerifyNullDummy, ScriptVerifyDerSig}
|
||||
import org.scalacoin.script.{ScriptProgramFactory, ScriptProgramImpl, ScriptProgram}
|
||||
import org.scalacoin.script.constant._
|
||||
import org.scalacoin.util.{BitcoinSLogger, BitcoinSUtil, CryptoUtil}
|
||||
|
@ -170,46 +170,52 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger
|
|||
require(program.script.headOption.isDefined && program.script.head == OP_CHECKMULTISIG, "Script top must be OP_CHECKMULTISIG")
|
||||
require(program.stack.size > 2, "Stack must contain at least 3 items for OP_CHECKMULTISIG")
|
||||
|
||||
val isValidSignatures = TransactionSignatureChecker.checkSignature(program)
|
||||
if (program.flags.contains(ScriptVerifyNullDummy) && program.scriptSignature.asm.head != OP_0) {
|
||||
logger.warn("Script flag null dummy was set however the first element in the script signature was not an OP_0")
|
||||
ScriptProgramFactory.factory(program,false)
|
||||
} else {
|
||||
val isValidSignatures = TransactionSignatureChecker.checkSignature(program)
|
||||
|
||||
//these next lines remove the appropriate stack/script values after the signatures have been checked
|
||||
val nPossibleSignatures : Int = program.stack.head match {
|
||||
case s : ScriptNumber => s.num.toInt
|
||||
case _ => throw new RuntimeException("n must be a script number for OP_CHECKMULTISIG")
|
||||
}
|
||||
logger.debug("nPossibleSignatures: " + nPossibleSignatures)
|
||||
val stackWithoutPubKeys = program.stack.tail.slice(nPossibleSignatures,program.stack.tail.size)
|
||||
val mRequiredSignatures : Int = stackWithoutPubKeys.head match {
|
||||
case s: ScriptNumber => s.num.toInt
|
||||
case _ => throw new RuntimeException("m must be a script number for OP_CHECKMULTISIG")
|
||||
}
|
||||
logger.debug("mRequiredSignatures: " + mRequiredSignatures )
|
||||
//these next lines remove the appropriate stack/script values after the signatures have been checked
|
||||
val nPossibleSignatures : Int = program.stack.head match {
|
||||
case s : ScriptNumber => s.num.toInt
|
||||
case _ => throw new RuntimeException("n must be a script number for OP_CHECKMULTISIG")
|
||||
}
|
||||
logger.debug("nPossibleSignatures: " + nPossibleSignatures)
|
||||
val stackWithoutPubKeys = program.stack.tail.slice(nPossibleSignatures,program.stack.tail.size)
|
||||
val mRequiredSignatures : Int = stackWithoutPubKeys.head match {
|
||||
case s: ScriptNumber => s.num.toInt
|
||||
case _ => throw new RuntimeException("m must be a script number for OP_CHECKMULTISIG")
|
||||
}
|
||||
logger.debug("mRequiredSignatures: " + mRequiredSignatures )
|
||||
|
||||
//+1 is for the fact that we have the # of sigs + the script token indicating the # of sigs
|
||||
val signaturesScriptTokens : Seq[ScriptToken] = program.stack.tail.slice(nPossibleSignatures + 1, nPossibleSignatures + mRequiredSignatures + 1)
|
||||
val signatures = signaturesScriptTokens.map(token => ECFactory.digitalSignature(token.bytes))
|
||||
logger.debug("Signatures on the stack: " + signatures)
|
||||
//+1 is for bug in OP_CHECKMULTSIG that requires an extra OP to be pushed onto the stack
|
||||
val stackWithoutPubKeysAndSignatures = stackWithoutPubKeys.tail.slice(mRequiredSignatures+1, stackWithoutPubKeys.tail.size)
|
||||
val restOfStack = stackWithoutPubKeysAndSignatures
|
||||
//+1 is for the fact that we have the # of sigs + the script token indicating the # of sigs
|
||||
val signaturesScriptTokens : Seq[ScriptToken] = program.stack.tail.slice(nPossibleSignatures + 1, nPossibleSignatures + mRequiredSignatures + 1)
|
||||
val signatures = signaturesScriptTokens.map(token => ECFactory.digitalSignature(token.bytes))
|
||||
logger.debug("Signatures on the stack: " + signatures)
|
||||
//+1 is for bug in OP_CHECKMULTSIG that requires an extra OP to be pushed onto the stack
|
||||
val stackWithoutPubKeysAndSignatures = stackWithoutPubKeys.tail.slice(mRequiredSignatures+1, stackWithoutPubKeys.tail.size)
|
||||
val restOfStack = stackWithoutPubKeysAndSignatures
|
||||
|
||||
isValidSignatures match {
|
||||
case SignatureValidationSuccess =>
|
||||
//means that all of the signatures were correctly encoded and
|
||||
//that all of the signatures were valid signatures for the given
|
||||
//public keys
|
||||
ScriptProgramFactory.factory(program, ScriptTrue :: restOfStack, program.script.tail)
|
||||
case SignatureValidationFailureNotStrictDerEncoding =>
|
||||
//this means the script fails immediately
|
||||
//set the valid flag to false on the script
|
||||
//see BIP66 for more information on this
|
||||
//https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki#specification
|
||||
ScriptProgramFactory.factory(program, restOfStack, program.script.tail,false)
|
||||
case SignatureValidationfailureIncorrectSignatures =>
|
||||
//this means that signature verification failed, however all signatures were encoded correctly
|
||||
//just push a ScriptFalse onto the stack
|
||||
ScriptProgramFactory.factory(program, ScriptFalse :: restOfStack, program.script.tail)
|
||||
isValidSignatures match {
|
||||
case SignatureValidationSuccess =>
|
||||
//means that all of the signatures were correctly encoded and
|
||||
//that all of the signatures were valid signatures for the given
|
||||
//public keys
|
||||
ScriptProgramFactory.factory(program, ScriptTrue :: restOfStack, program.script.tail)
|
||||
case SignatureValidationFailureNotStrictDerEncoding =>
|
||||
//this means the script fails immediately
|
||||
//set the valid flag to false on the script
|
||||
//see BIP66 for more information on this
|
||||
//https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki#specification
|
||||
ScriptProgramFactory.factory(program, restOfStack, program.script.tail,false)
|
||||
case SignatureValidationfailureIncorrectSignatures =>
|
||||
//this means that signature verification failed, however all signatures were encoded correctly
|
||||
//just push a ScriptFalse onto the stack
|
||||
ScriptProgramFactory.factory(program, ScriptFalse :: restOfStack, program.script.tail)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 =
|
||||
"""
|
||||
|
|
||||
|[[
|
||||
"0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205",
|
||||
"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
|
||||
"1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901",
|
||||
"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
|
||||
"",
|
||||
"P2PK with undefined hashtype but no STRICTENC"
|
||||
"3-of-3 with nonzero dummy but no NULLDUMMY"
|
||||
]]
|
||||
""".stripMargin
|
||||
""".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