diff --git a/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala b/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala index accdb0af1c..2dd577223c 100644 --- a/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala +++ b/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala @@ -45,9 +45,9 @@ trait TransactionSignatureChecker extends BitcoinSLogger { logger.error("Signature did not have a low s value") ScriptValidationFailureHighSValue } else if (ScriptFlagUtil.requireStrictEncoding(flags) && signature.bytes.nonEmpty && - !HashType.hashTypes.contains(HashType(signature.bytes.last))) { - logger.error("signature: " + signature.bytes) - logger.error("Hash type was not defined on the signature") + !HashType.isDefinedHashtypeSignature(signature)) { + logger.error("signature: " + signature.hex) + logger.error("Hash type was not defined on the signature, got: " + signature.bytes.last) ScriptValidationFailureHashType } else if (pubKeyEncodedCorrectly.isDefined) { val err = pubKeyEncodedCorrectly.get diff --git a/src/main/scala/org/bitcoins/core/script/crypto/HashType.scala b/src/main/scala/org/bitcoins/core/script/crypto/HashType.scala index 337374ad59..a10f765ee9 100644 --- a/src/main/scala/org/bitcoins/core/script/crypto/HashType.scala +++ b/src/main/scala/org/bitcoins/core/script/crypto/HashType.scala @@ -1,5 +1,6 @@ package org.bitcoins.core.script.crypto +import org.bitcoins.core.crypto.ECDigitalSignature import org.bitcoins.core.number.Int32 import org.bitcoins.core.util.Factory @@ -68,6 +69,8 @@ object HashType extends Factory[HashType] { lazy val hashTypes = Seq(sigHashAll, sigHashNone, sigHashSingle, sigHashAnyoneCanPay, sigHashNoneAnyoneCanPay, sigHashAllAnyoneCanPay, sigHashSingleAnyoneCanPay) + lazy val hashTypeBytes: Seq[Byte] = Seq(sigHashAllByte, sigHashSingleByte, sigHashNoneByte, sigHashAnyoneCanPayByte, + sigHashNoneAnyoneCanPayByte, sigHashSingleAnyoneCanPayByte, sigHashAllAnyoneCanPayByte) def apply(num : Int32) : HashType = fromNumber(num) def apply(int : Int) : HashType = HashType(Int32(int)) @@ -105,7 +108,6 @@ object HashType extends Factory[HashType] { val sigHashSingle: SIGHASH_SINGLE = SIGHASH_SINGLE(Int32(sigHashSingleByte)) - val sigHashAllAnyoneCanPayByte = (HashType.sigHashAllByte | HashType.sigHashAnyoneCanPayByte).toByte val sigHashAllAnyoneCanPayNum = (Int32(sigHashAllByte) | sigHashAnyoneCanPayNum) @@ -123,6 +125,15 @@ object HashType extends Factory[HashType] { val sigHashSingleAnyoneCanPayNum = (Int32(sigHashSingleByte) | sigHashAnyoneCanPayNum) val sigHashSingleAnyoneCanPay = SIGHASH_SINGLE_ANYONECANPAY(sigHashSingleAnyoneCanPayNum) + + /** + * Checks if the given digital signature has a valid hash type + * Mimics this functionality inside of Bitcoin Core + * https://github.com/bitcoin/bitcoin/blob/b83264d9c7a8ddb79f64bd9540caddc8632ef31f/src/script/interpreter.cpp#L186 + */ + def isDefinedHashtypeSignature(sig: ECDigitalSignature): Boolean = { + sig.bytes.nonEmpty && hashTypeBytes.contains(sig.bytes.last) + } } /** diff --git a/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala b/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala index ddaa326bd9..c6c0a1d2da 100644 --- a/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala +++ b/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala @@ -13,6 +13,7 @@ import org.scalacheck.{Prop, Properties} * Created by chris on 7/25/16. */ class TransactionSignatureCreatorSpec extends Properties("TransactionSignatureCreatorSpec") with BitcoinSLogger { + property("Must generate a valid signature for a p2pk transaction") = Prop.forAll(TransactionGenerators.signedP2PKTransaction) { case (txSignatureComponent: TransactionSignatureComponent, _) =>