Fixing bug with signature serialization - if we have more inputs than outputs & we are using SIGHASH_SINGLE the errorHash is signed

This commit is contained in:
Chris Stewart 2016-05-06 16:41:59 -05:00
parent e867dbee53
commit 245815b4d4
3 changed files with 23 additions and 6 deletions

View file

@ -47,6 +47,11 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper with Bit
* @return
*/
def serializeForSignature(spendingTransaction : Transaction, inputIndex : Int, script : ScriptPubKey, hashType : HashType) : Seq[Byte] = {
logger.debug("Serializing for signature")
// Clear input scripts in preparation for signing. If we're signing a fresh
// transaction that step isn't very helpful, but it doesn't add much cost relative to the actual
// EC math so we'll do it anyway.
@ -147,9 +152,20 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper with Bit
* @param hashType
* @return
*/
def hashForSignature(spendingTransction : Transaction, inputIndex : Int, script : ScriptPubKey, hashType : HashType) : Seq[Byte] = {
val serializedTxForSignature = serializeForSignature(spendingTransction,inputIndex,script,hashType)
CryptoUtil.doubleSHA256(serializedTxForSignature)
def hashForSignature(spendingTransaction : Transaction, inputIndex : Int, script : ScriptPubKey, hashType : HashType) : Seq[Byte] = {
//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 >= 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 >= 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)
CryptoUtil.doubleSHA256(serializedTxForSignature)
}
}
/**

View file

@ -49,14 +49,14 @@ class TransactionTest extends FlatSpec with MustMatchers with BitcoinSLogger {
//use this to represent a single test case from script_valid.json
/* val lines =
val lines =
"""
|[
|[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]],
|"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"]
|]
""".stripMargin*/
val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close()
""".stripMargin
//val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close()
val json = lines.parseJson
val testCasesOpt : Seq[Option[CoreTransactionTestCase]] = json.convertTo[Seq[Option[CoreTransactionTestCase]]]
val testCases : Seq[CoreTransactionTestCase] = testCasesOpt.flatten

View file

@ -17,6 +17,7 @@ trait CoreTransactionTestCase {
def scriptPubKeys : Seq[ScriptPubKey] = creditingTxsInfo.map(_._2)
def creditingTxsInfo : Seq[(TransactionOutPoint, ScriptPubKey)]
def spendingTx : Transaction
def flags : Seq[ScriptFlag]