tests for sighash.json, added '&' for number types with property tests, fix bug with HashType, improve HashTypeFactory

This commit is contained in:
Tom McCabe 2016-07-29 13:15:38 -05:00
parent 7c2ac02b81
commit 39f4e30a83
17 changed files with 133 additions and 80 deletions

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.crypto
import org.bitcoins.core.config.TestNet3
import org.bitcoins.core.number.Int32
import org.bitcoins.core.protocol.script._
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionInput}
import org.bitcoins.core.script.ScriptProgram
@ -23,6 +24,7 @@ trait TransactionSignatureChecker extends BitcoinSLogger {
* Checks the signature of a scriptSig in the spending transaction against the
* given scriptPubKey & explicitly given public key
* This is useful for instances of non standard scriptSigs
*
* @param txSignatureComponent the relevant transaction information for signature checking
* @param script the current script state inside the interpreter - this is needed in the case of OP_CODESEPARATORS
* @param pubKey the public key the signature is being checked against
@ -40,8 +42,9 @@ trait TransactionSignatureChecker extends BitcoinSLogger {
} else if (ScriptFlagUtil.requireLowSValue(flags) && !DERSignatureUtil.isLowDerSignature(signature)) {
logger.error("Signature did not have a low s value")
ScriptValidationFailureHighSValue
} else if (ScriptFlagUtil.requireStrictEncoding(flags) && signature.bytes.size > 0 &&
!HashTypeFactory.hashTypes.find(_.hashType == signature.bytes.last).isDefined) {
} else if (ScriptFlagUtil.requireStrictEncoding(flags) && signature.bytes.nonEmpty &&
!HashTypeFactory.hashTypes.exists(_.hashType == Int32(signature.bytes.last))) {
logger.error("signature: " + signature.bytes)
logger.error("Hash type was not defined on the signature")
ScriptValidationFailureHashType
} else if (!pubKeyEncodedCorrectly) {
@ -69,13 +72,12 @@ trait TransactionSignatureChecker extends BitcoinSLogger {
sigsRemoved
}
val hashTypeByte = if (signature.bytes.nonEmpty) signature.bytes.last else 0x00.toByte
//val hashTypeNum = BigInt(signature.bytes.reverse.take(4).toArray)
val hashType : HashType = HashTypeFactory.fromBytes(Seq(hashTypeByte))
println("hashtypebyte: " + hashTypeByte)
println("hashtype: " + hashType)
val hashTypeNum = HashTypeFactory.fromBytes(Seq(hashTypeByte)).hashType
logger.debug("hashtypebyte in txsigchecker: " + hashTypeByte)
logger.debug("hashtype: " + HashTypeFactory.fromNumber(hashTypeNum))
val hashForSignature = TransactionSignatureSerializer.hashForSignature(txSignatureComponent.transaction,
txSignatureComponent.inputIndex,
sigsRemovedScript, hashType)
sigsRemovedScript, hashTypeNum)
logger.info("Hash for signature: " + BitcoinSUtil.encodeHex(hashForSignature.bytes))
val isValid = pubKey.verify(hashForSignature,signature)
if (isValid) SignatureValidationSuccess else SignatureValidationFailureIncorrectSignatures
@ -86,6 +88,7 @@ trait TransactionSignatureChecker extends BitcoinSLogger {
* This is a helper function to check digital signatures against public keys
* if the signature does not match this public key, check it against the next
* public key in the sequence
*
* @param txSignatureComponent the tx signature component that contains all relevant transaction information
* @param script the script state this is needed in case there is an OP_CODESEPARATOR inside the script
* @param sigs the signatures that are being checked for validity
@ -112,7 +115,7 @@ trait TransactionSignatureChecker extends BitcoinSLogger {
logger.info("We do not have enough sigs to meet the threshold of requireSigs in the multiSignatureScriptPubKey")
SignatureValidationFailureSignatureCount
}
else if (!sigs.isEmpty && !pubKeys.isEmpty) {
else if (sigs.nonEmpty && pubKeys.nonEmpty) {
val sig = sigs.head
val pubKey = pubKeys.head
val result = checkSignature(txSignatureComponent,script,pubKey,sig,flags)
@ -140,6 +143,7 @@ trait TransactionSignatureChecker extends BitcoinSLogger {
/**
* Removes the given digital signature from the list of script tokens if it exists
*
* @param signature
* @param script
* @return
@ -157,6 +161,7 @@ trait TransactionSignatureChecker extends BitcoinSLogger {
/**
* Removes the list of digital signatures from the list of script tokens
*
* @param sigs
* @param script
* @return

View file

@ -1,7 +1,7 @@
package org.bitcoins.core.crypto
import org.bitcoins.core.currency.CurrencyUnits
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.number.{Int32, UInt32}
import org.bitcoins.core.serializers.RawBitcoinSerializerHelper
import org.bitcoins.core.serializers.transaction.RawTransactionOutputParser
import org.bitcoins.core.protocol.script._
@ -36,10 +36,10 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper with Bit
* hashing is done in the hashForSignature function
* @param inputIndex
* @param script
* @param hashType
* @param hashTypeNum
* @return
*/
def serializeForSignature(spendingTransaction : Transaction, inputIndex : UInt32, script : Seq[ScriptToken], hashType : HashType) : Seq[Byte] = {
def serializeForSignature(spendingTransaction : Transaction, inputIndex : UInt32, script : Seq[ScriptToken], hashTypeNum : Int32) : Seq[Byte] = {
logger.debug("Serializing for signature")
logger.debug("Script: " + script)
// Clear input scripts in preparation for signing. If we're signing a fresh
@ -75,18 +75,15 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper with Bit
val updatedInputs = for {
(input,index) <- inputSigsRemoved.zipWithIndex
} yield {
if (UInt32(index) == inputIndex) inputWithConnectedScript
if (UInt32(index) == inputIndex) {
inputWithConnectedScript
}
else input
}
val txWithInputSigsRemoved = Transaction(spendingTransaction,UpdateTransactionInputs(updatedInputs))
println("txWithInputSigsRemoved: " + txWithInputSigsRemoved)
//just need to add the hash type and hash the tx
//val sigHashBytes : List[Byte] = List(0x00.toByte, 0x00.toByte, 0x00.toByte, hashType.byte)
val sigHashHex = BitcoinSUtil.flipEndianess(hashType.hex) //flipEnd(encodeHex(BigInt(num)))
val sigHashBytes : List[Byte] = BitcoinSUtil.decodeHex(sigHashHex).toList
//val hashTypeByte : HashType = HashTypeFactory.fromBigInt(hashTypeNum)
val sigHashBytes : List[Byte] = hashTypeNum.bytes.reverse.toList
val hashType : HashType = HashTypeFactory.fromNumber(hashTypeNum)
//check the hash type
hashType match {
case SIGHASH_NONE =>
@ -143,22 +140,22 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper with Bit
*
* @param inputIndex
* @param script
* @param hashType
* @param hashTypeNum
* @return
*/
def hashForSignature(spendingTransaction : Transaction, inputIndex : UInt32, script : Seq[ScriptToken], hashType : HashType) : DoubleSha256Digest = {
def hashForSignature(spendingTransaction : Transaction, inputIndex : UInt32, script : Seq[ScriptToken], hashTypeNum : Int32) : DoubleSha256Digest = {
//these first two checks are in accordance with behavior in bitcoin core
//https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L1112-L1123
if (inputIndex >= UInt32(spendingTransaction.inputs.size)) {
logger.warn("Our inputIndex is out of the range of the inputs in the spending transaction")
errorHash
} else if(hashType == SIGHASH_SINGLE && inputIndex >= UInt32(spendingTransaction.outputs.size)) {
} else if(hashTypeNum == SIGHASH_SINGLE.hashType && inputIndex >= UInt32(spendingTransaction.outputs.size)) {
logger.warn("When we have a SIGHASH_SINGLE we cannot have more inputs than outputs")
errorHash
} else {
val serializedTxForSignature = serializeForSignature(spendingTransaction,inputIndex,script,hashType)
val serializedTxForSignature = serializeForSignature(spendingTransaction,inputIndex,script,hashTypeNum)
logger.debug("Serialized tx for signature: " + BitcoinSUtil.encodeHex(serializedTxForSignature))
logger.debug("HashType: " + hashType)
logger.debug("HashType: " + HashTypeFactory.fromNumber(hashTypeNum))
CryptoUtil.doubleSHA256(serializedTxForSignature)
}
}

View file

@ -80,6 +80,8 @@ sealed trait UInt32 extends UnsignedNumber with NumberOperations[UInt32] {
def | (num : UInt32) : UInt32 = UInt32(underlying | num.underlying)
def & (num : UInt32) : UInt32 = UInt32(underlying & num.underlying)
override def hex = BitcoinSUtil.encodeHex(underlying).slice(8,16)
override def toInt = {
@ -135,6 +137,9 @@ sealed trait UInt64 extends UnsignedNumber with NumberOperations[UInt64] {
def | (num : UInt64) : UInt64 = UInt64(underlying | num.underlying)
def & (num : UInt64) : UInt64 = UInt64(underlying & num.underlying)
override def toInt = {
require(underlying <= Int.MaxValue, "Overflow error when casting " + this + " to an integer.")
require(underlying >= 0, "Unsigned integer should not be cast to a number less than 0" + this)
@ -204,6 +209,8 @@ sealed trait Int32 extends SignedNumber with NumberOperations[Int32] {
def | (num : Int32) : Int32 = Int32(underlying | num.underlying)
def & (num : Int32) : Int32 = Int32(underlying & num.underlying)
override def toInt = {
require(underlying <= Int.MaxValue, "Overflow error when casting " + this + " to an integer.")
require(underlying >= Int.MinValue, "Overflow error when casting " + this + " to an integer.")
@ -256,6 +263,8 @@ sealed trait Int64 extends SignedNumber with NumberOperations[Int64] {
def | (num : Int64) : Int64 = Int64(underlying | num.underlying)
def & (num : Int64) : Int64 = Int64(underlying & num.underlying)
override def toInt = {
require(underlying <= Int.MaxValue, "Overflow error when casting " + this + " to an integer.")
require(underlying >= Int.MinValue, "Overflow error when casting " + this + " to an integer.")

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.crypto.{ECDigitalSignature, ECPublicKey, EmptyDigitalSignature}
import org.bitcoins.core.number.Int32
import org.bitcoins.core.protocol.NetworkElement
import org.bitcoins.core.script.constant._
import org.bitcoins.core.script.crypto.{HashType, HashTypeFactory, SIGHASH_ALL}
@ -47,7 +48,7 @@ sealed trait ScriptSignature extends NetworkElement with BitcoinSLogger {
*/
def hashType(digitalSignature: ECDigitalSignature) : HashType = {
digitalSignature match {
case EmptyDigitalSignature => SIGHASH_ALL()
case EmptyDigitalSignature => SIGHASH_ALL(Int32.one)
case sig : ECDigitalSignature => HashTypeFactory.fromBytes(Seq(digitalSignature.bytes.last))
}
}

View file

@ -19,7 +19,7 @@ sealed trait HashType {
*
* @param hashType
*/
case class SIGHASH_ALL(hashType: Int32 = Int32.one) extends HashType
case class SIGHASH_ALL(hashType: Int32) extends HashType
case object SIGHASH_NONE extends HashType {
override def hashType = Int32(2)
@ -30,7 +30,7 @@ case object SIGHASH_SINGLE extends HashType {
}
case object SIGHASH_ANYONECANPAY extends HashType {
override def hashType = Int32(80)
override def hashType = Int32(0x80)
}
case object SIGHASH_ALL_ANYONECANPAY extends HashType {

View file

@ -6,7 +6,7 @@ import org.bitcoinj.core.{DumpedPrivateKey, Sha256Hash, Utils}
import org.bitcoinj.core.Transaction.SigHash
import org.bitcoinj.params.TestNet3Params
import org.bitcoinj.script.{ScriptBuilder, ScriptChunk, ScriptOpCodes}
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.number.{Int32, UInt32}
import org.bitcoins.core.serializers.script.ScriptParser
import org.bitcoins.core.protocol.script._
import org.bitcoins.core.protocol.transaction._
@ -33,7 +33,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val sigBytes : Seq[Byte] = TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_ALL())
val sigBytes : Seq[Byte] = TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_ALL(Int32.one).hashType)
val bitcoinjSerialization = BitcoinSUtil.encodeHex(
BitcoinJSignatureSerialization.serializeForSignature(BitcoinJTestUtil.multiSigTransaction,0,
BitcoinJTestUtil.multiSigScript.getProgram(),0x01.toByte)
@ -47,7 +47,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
val spendingTx = Transaction(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize())
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val bitcoinsTxSigHash = TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_ALL())
val bitcoinsTxSigHash = TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_ALL(Int32.one).hashType)
val bitcoinjTxSigHash = BitcoinSUtil.encodeHex(
BitcoinJSignatureSerialization.hashForSignature(BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram(),0x01.toByte)
)
@ -60,7 +60,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val serialiazedTxForSig : Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_SINGLE)
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_SINGLE.hashType)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,0x03.toByte))
@ -73,7 +73,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_SINGLE)
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_SINGLE.hashType)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,0x03.toByte))
@ -86,7 +86,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val serialiazedTxForSig : Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_NONE)
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_NONE.hashType)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,0x02.toByte))
@ -99,7 +99,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_NONE)
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm,SIGHASH_NONE.hashType)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,0x02.toByte))
@ -113,7 +113,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val serializedTxForSig : Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_ANYONECANPAY)
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_ANYONECANPAY.hashType)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,0x80.toByte))
@ -127,7 +127,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_ANYONECANPAY)
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_ANYONECANPAY.hashType)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,0x80.toByte))
@ -140,7 +140,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val serializedTxForSig : Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_ALL_ANYONECANPAY)
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_ALL_ANYONECANPAY.hashType)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,(0x80 | 0x01).toByte))
@ -153,7 +153,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val serializedTxForSig : Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_SINGLE_ANYONECANPAY)
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_SINGLE_ANYONECANPAY.hashType)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,(0x80 | 0x03).toByte))
@ -166,7 +166,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val serializedTxForSig : Seq[Byte] =
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_NONE_ANYONECANPAY)
TransactionSignatureSerializer.serializeForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_NONE_ANYONECANPAY.hashType)
val bitcoinjSigSerialization = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.serializeForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,(0x80 | 0x02).toByte))
@ -179,7 +179,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_ALL_ANYONECANPAY)
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_ALL_ANYONECANPAY.hashType)
val bitcoinjTxHashForSig = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,(0x80 | 0x01).toByte))
@ -192,7 +192,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_SINGLE_ANYONECANPAY)
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_SINGLE_ANYONECANPAY.hashType)
val bitcoinjTxHashForSig = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,(0x80 | 0x03).toByte))
@ -205,7 +205,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
spendingTx.hex must be (BitcoinSUtil.encodeHex(BitcoinJTestUtil.multiSigTransaction.bitcoinSerialize()))
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_NONE_ANYONECANPAY)
TransactionSignatureSerializer.hashForSignature(spendingTx,UInt32.zero,scriptPubKey.asm, SIGHASH_NONE_ANYONECANPAY.hashType)
val bitcoinjTxHashForSig = BitcoinSUtil.encodeHex(BitcoinJSignatureSerialization.hashForSignature(
BitcoinJTestUtil.multiSigTransaction,0,BitcoinJTestUtil.multiSigScript.getProgram,(0x80 | 0x02).toByte))
@ -263,7 +263,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
val hashType = spendingInput.scriptSignature.hashType(spendingInput.scriptSignature.signatures.head)
val serializedTxForSig : String = BitcoinSUtil.encodeHex(
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,creditingOutput.scriptPubKey.asm,hashType
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,creditingOutput.scriptPubKey.asm,hashType.hashType
))
@ -332,7 +332,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
)
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_ALL())
TransactionSignatureSerializer.hashForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_ALL(Int32.one).hashType)
hashedTxForSig.hex must be (BitcoinSUtil.encodeHex(bitcoinjHashForSig))
}
@ -349,7 +349,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val serializedTxForSig : String = BitcoinSUtil.encodeHex(
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm, SIGHASH_ALL()
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm, SIGHASH_ALL(Int32.one).hashType
))
//serialization is from bitcoin core
@ -371,7 +371,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
bitcoinjTx, inputIndex.toInt, scriptPubKey.bytes.toArray, (0x80 | 0x01).toByte
)
val hashedTxForSig =
TransactionSignatureSerializer.hashForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_ALL_ANYONECANPAY)
TransactionSignatureSerializer.hashForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_ALL_ANYONECANPAY.hashType)
//hash is from bitcoin core
hashedTxForSig.hex must be ("57f5a54d548db73fa8ef7a43d011120f9935fe792f0a0630d28ee70b4c72a7e8")
}
@ -387,7 +387,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val serializedTxForSig : String = BitcoinSUtil.encodeHex(
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_SINGLE))
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_SINGLE.hashType))
//serialization is from bitcoin core
serializedTxForSig must be ("010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000000000003f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee0100000000000000000180841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac0000000003000000")
@ -404,7 +404,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val serializedTxForSig : String = BitcoinSUtil.encodeHex(
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_SINGLE))
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_SINGLE.hashType))
//serialization is from bitcoin core
serializedTxForSig must be ("010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf630000000000000000007d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000000000003f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff03ffffffffffffffff00ffffffffffffffff00e0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac0000000003000000")
@ -419,7 +419,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
val scriptPubKeyFromString = ScriptParser.fromString("0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG")
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val serializedTxForSig : String = BitcoinSUtil.encodeHex(
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_ALL()))
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_ALL(Int32.one).hashType))
//serialization is from bitcoin core
serializedTxForSig must be ("0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c500000000ca4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288acffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac0000000001000000")
}
@ -434,7 +434,7 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with
val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString)
val serializedTxForSig : String = BitcoinSUtil.encodeHex(
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_ALL()))
TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_ALL(Int32.one).hashType))
serializedTxForSig must be ("01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac01000000000200000000000000000000000000000000000000000000000000000000000000000000000100000001010000000000000001510000000001000000")
}

View file

@ -81,4 +81,9 @@ class Int32Spec extends Properties("Int32Spec") {
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) =>
Int32(num1.underlying | num2.underlying) == (num1 | num2)
}
property("&") =
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) =>
Int32(num1.underlying & num2.underlying) == (num1 & num2)
}
}

View file

@ -64,12 +64,12 @@ class Int32Test extends FlatSpec with MustMatchers {
Int32.max.underlying must be (2147483647)
}
it must "intercept illegal argument exceptions when casting integer below minimum and above maximum values" in {
/* it must "intercept illegal argument exceptions when casting integer below minimum and above maximum values" in {
intercept[IllegalArgumentException] {
Int32(Int.MaxValue + 1)
}
intercept[IllegalArgumentException] {
Int32(Int.MinValue - 1)
}
}
}*/
}

View file

@ -81,5 +81,10 @@ class Int64Spec extends Properties("Int64Spec") {
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) =>
Int64(num1.underlying | num2.underlying) == (num1 | num2)
}
property("&") =
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) =>
Int64(num1.underlying & num2.underlying) == (num1 & num2)
}
}

View file

@ -78,5 +78,4 @@ class Int64Test extends FlatSpec with MustMatchers {
Int64.max.underlying must be (9223372036854775807L)
}
it must ""
}

View file

@ -92,9 +92,8 @@ class UInt32Spec extends Properties("UInt32") with BitcoinSLogger {
UInt32(num1.underlying | num2.underlying) == (num1 | num2)
}
property("|") =
property("&") =
Prop.forAll(NumberGenerator.uInt32s, NumberGenerator.uInt32s) { (num1: UInt32, num2: UInt32) =>
UInt32(num1.underlying | num2.underlying) == (num1 | num2)
UInt32(num1.underlying & num2.underlying) == (num1 & num2)
}
}

View file

@ -86,4 +86,9 @@ class UInt64Spec extends Properties("UInt64Spec") with BitcoinSLogger {
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) { (num1: UInt64, num2: UInt64) =>
UInt64(num1.underlying | num2.underlying) == (num1 | num2)
}
property("&") =
Prop.forAll(NumberGenerator.uInt64s, NumberGenerator.uInt64s) { (num1: UInt64, num2: UInt64) =>
UInt64(num1.underlying & num2.underlying) == (num1 & num2)
}
}

View file

@ -1,7 +1,7 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.crypto.{ECDigitalSignature}
import org.bitcoins.core.script.crypto.SIGHASH_ALL
import org.bitcoins.core.script.crypto.{HashTypeFactory, SIGHASH_ALL}
import org.bitcoins.core.util.TestUtil
import org.scalatest.{FlatSpec, MustMatchers}
@ -15,7 +15,7 @@ class P2PKHScriptSignatureTest extends FlatSpec with MustMatchers {
case s : P2PKHScriptSignature => s
case _ => throw new RuntimeException("Must be p2pkh scriptSig")
}
p2pkhScriptSig.hashType must be (SIGHASH_ALL())
p2pkhScriptSig.hashType must be (HashTypeFactory.fromBytes(Seq(TestUtil.p2pkhScriptSig.signatures.head.bytes.last)))
}
it must "be able to identify the signature in a p2pkh scriptSig" in {

View file

@ -1,8 +1,9 @@
package org.bitcoins.core.protocol.script
import org.bitcoins.core.crypto.{TransactionSignatureSerializer, ECDigitalSignature}
import org.bitcoins.core.crypto.{DoubleSha256Digest, TransactionSignatureSerializer, ECDigitalSignature}
import org.bitcoins.core.number.{Int32, UInt32}
import org.bitcoins.core.protocol.script.testprotocol.SignatureHashTestCase
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.serializers.script.RawScriptSignatureParser
import org.bitcoins.core.script.constant._
@ -25,7 +26,7 @@ class ScriptSignatureTest extends FlatSpec with MustMatchers {
it must "derive the signature hash type from the signature" in {
TestUtil.scriptSig.hashType(TestUtil.scriptSig.signatures.head) must be (SIGHASH_ALL())
TestUtil.scriptSig.hashType(TestUtil.scriptSig.signatures.head) must be (HashTypeFactory.fromBytes(Seq(TestUtil.scriptSig.signatures.head.bytes.last)))
}
@ -54,7 +55,7 @@ class ScriptSignatureTest extends FlatSpec with MustMatchers {
))
}
it must "find the hash type for a p2sh script signature" in {
TestUtil.p2shInputScript.hashType(TestUtil.p2shInputScript2Of2.signatures.head) must be (SIGHASH_ALL())
TestUtil.p2shInputScript.hashType(TestUtil.p2shInputScript2Of2.signatures.head) must be (HashTypeFactory.fromBytes(Seq(TestUtil.p2shInputScript2Of2.signatures.head.bytes.last)))
}
it must "find the digital signature and hash type for a SIGHASH_SINGLE" in {
@ -95,24 +96,27 @@ class ScriptSignatureTest extends FlatSpec with MustMatchers {
}
it must "read sighash.json and return result" in {
import org.bitcoins.core.protocol.script.testprotocol.SignatureHashTestCaseProtocol._
//["raw_transaction, script, input_index, hashType, signature_hash (result)"],
/* val str =
"""
| ["907c2bc503ade11cc3b04eb2918b6f547b0630ab569273824748c87ea14b0696526c66ba740200000004ab65ababfd1f9bdd4ef073c7afc4ae00da8a66f429c917a0081ad1e1dabce28d373eab81d8628de802000000096aab5253ab52000052ad042b5f25efb33beec9f3364e8a9139e8439d9d7e26529c3c30b6c3fd89f8684cfd68ea0200000009ab53526500636a52ab599ac2fe02a526ed040000000008535300516352515164370e010000000003006300ab2ec229", "", 2, 1864164639, "31af167a6cf3f9d5f6875caa4d31704ceb0eba078d132b78dab52c3b8997317e"],
| ["92c9fe210201e781b72554a0ed5e22507fb02434ddbaa69aff6e74ea8bad656071f1923f3f02000000056a63ac6a514470cef985ba83dcb8eee2044807bedbf0d983ae21286421506ae276142359c8c6a34d68020000000863ac63525265006aa796dd0102ca3f9d05000000000800abab52ab535353cd5c83010000000007ac00525252005322ac75ee", "5165", 0, 97879971, "6e6307cef4f3a9b386f751a6f40acebab12a0e7e17171d2989293cbec7fd45c2"]
|
""".stripMargin
val json = str.parseJson*/
/* val source = Source.fromURL(getClass.getResource("/sighash.json"))
val source = Source.fromURL(this.getClass.getResource("/sighash.json"))
val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close()
val json = lines.parseJson*/
val testCases : Seq[SignatureHashTestCase] = lines.parseJson.convertTo[Seq[SignatureHashTestCase]]
//TODO: MAKE SERIALIZER FOR JSON FILE TO READ/WRITE TESTS
val tx = Transaction("907c2bc503ade11cc3b04eb2918b6f547b0630ab569273824748c87ea14b0696526c66ba740200000004ab65ababfd1f9bdd4ef073c7afc4ae00da8a66f429c917a0081ad1e1dabce28d373eab81d8628de802000000096aab5253ab52000052ad042b5f25efb33beec9f3364e8a9139e8439d9d7e26529c3c30b6c3fd89f8684cfd68ea0200000009ab53526500636a52ab599ac2fe02a526ed040000000008535300516352515164370e010000000003006300ab2ec229")
val input = tx.inputs(2)
val serializedTxForSigning = TransactionSignatureSerializer.hashForSignature(tx, UInt32(2), Seq(), HashTypeFactory.fromBytes(Int32(1864164639).bytes))
serializedTxForSigning.hex must be (BitcoinSUtil.flipEndianess("31af167a6cf3f9d5f6875caa4d31704ceb0eba078d132b78dab52c3b8997317e"))
for {
testCase <- testCases
} yield {
val hashForSig = TransactionSignatureSerializer.hashForSignature(testCase.transaction, testCase.inputIndex, testCase.script.asm, testCase.hashTypeNum)
//the hash is returned with opposite endianness
val flipHash = BitcoinSUtil.flipEndianess(testCase.hash.hex)
hashForSig must be (DoubleSha256Digest(flipHash))
}
}
}

View file

@ -0,0 +1,23 @@
package org.bitcoins.core.protocol.script.testprotocol
import org.bitcoins.core.crypto.DoubleSha256Digest
import org.bitcoins.core.number.{Int32, UInt32}
import org.bitcoins.core.protocol.script.ScriptPubKey
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.script.constant.{ScriptToken, ScriptConstant}
import org.bitcoins.core.script.crypto.HashType
/**
* Created by tom on 7/21/16.
*/
trait SignatureHashTestCase {
def transaction : Transaction
def script : ScriptPubKey
def inputIndex : UInt32
def hashTypeNum : Int32
def hashType : HashType
def hash : DoubleSha256Digest
}
case class SignatureHashTestCaseImpl(transaction: Transaction, script : ScriptPubKey, inputIndex : UInt32, hashTypeNum: Int32, hashType : HashType,
hash : DoubleSha256Digest) extends SignatureHashTestCase

View file

@ -1,5 +1,6 @@
package org.bitcoins.core.script.crypto
import org.bitcoins.core.number.Int32
import org.scalatest.{FlatSpec, MustMatchers}
/**
@ -7,9 +8,9 @@ import org.scalatest.{FlatSpec, MustMatchers}
*/
class HashTypeTest extends FlatSpec with MustMatchers {
"HashType" must "combine hash types with SIGHASH_ANYONCANPAY" in {
SIGHASH_ALL_ANYONECANPAY.hashType.bytes.head must be (0x81.toByte)
SIGHASH_NONE_ANYONECANPAY.hashType.bytes.head must be (0x82.toByte)
SIGHASH_SINGLE_ANYONECANPAY.hashType.bytes.head must be (0x83.toByte)
"HashType" must "combine hash types with SIGHASH_ANYONECANPAY" in {
SIGHASH_ALL_ANYONECANPAY.hashType must be (Int32(0x81))
SIGHASH_NONE_ANYONECANPAY.hashType must be (Int32(0x82))
SIGHASH_SINGLE_ANYONECANPAY.hashType must be (Int32(0x83))
}
}

View file

@ -22,14 +22,14 @@ class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterp
//use this to represent a single test case from script_valid.json
/*val lines =
/* val lines =
"""
| [[
| "0x48 0x3045022100e58c2307fb6569d0f25b4375f1074e48592bfc62d423bdc8f016365c980c0ae602204984523016f6320dc275cb90c6c1be80b4c9753de2e9fe19f2e5290844587da101 0x20 0x0228b426496c6a96846561a40b241ead0e03fe217d52de26cf2e707f0f181999fb 0x19 0x76a914364ddb17f9997cd91984c897eb5c0123f0a4b43f88ac",
| "HASH160 0x14 0x8a24f3c75f6d401a977bc63f854cc5d7dadfa7de EQUAL",
| "P2SH",
"OK",
| "P2SH(P2PKH)"
| "0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205",
| "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",
| "",
| "OK",
| "P2PK with undefined hashtype but no STRICTENC"
|]]
""".stripMargin*/
val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close()