core: Fix divergence in behavior between TransactionSignatureSerializer.hashForSignature() methods (#5765)

This commit is contained in:
Chris Stewart 2024-11-13 10:03:40 -06:00 committed by GitHub
parent 17f965fd45
commit c5d57de618
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 22 additions and 25 deletions

View File

@ -1,15 +1,16 @@
package org.bitcoins.core.crypto package org.bitcoins.core.crypto
import org.bitcoins.core.number.{Int32, UInt32} import org.bitcoins.core.number.{Int32, UInt32}
import org.bitcoins.core.policy.Policy
import org.bitcoins.core.protocol.CompactSizeUInt import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.script._ import org.bitcoins.core.protocol.script.*
import org.bitcoins.core.protocol.transaction._ import org.bitcoins.core.protocol.transaction.*
import org.bitcoins.core.script.constant.ScriptToken import org.bitcoins.core.script.constant.ScriptToken
import org.bitcoins.core.script.crypto._ import org.bitcoins.core.script.crypto.*
import org.bitcoins.core.serializers.transaction.RawTransactionOutputParser import org.bitcoins.core.serializers.transaction.RawTransactionOutputParser
import org.bitcoins.core.util.{BitcoinScriptUtil, BytesUtil} import org.bitcoins.core.util.{BitcoinScriptUtil, BytesUtil}
import org.bitcoins.core.wallet.utxo.{InputInfo, InputSigningInfo} import org.bitcoins.core.wallet.utxo.{InputInfo, InputSigningInfo}
import org.bitcoins.crypto._ import org.bitcoins.crypto.*
import scodec.bits.ByteVector import scodec.bits.ByteVector
/** Created by chris on 2/16/16. Wrapper that serializes like Transaction, but /** Created by chris on 2/16/16. Wrapper that serializes like Transaction, but
@ -466,27 +467,13 @@ sealed abstract class TransactionSignatureSerializer {
spendingTransaction: Transaction, spendingTransaction: Transaction,
signingInfo: InputSigningInfo[InputInfo], signingInfo: InputSigningInfo[InputInfo],
hashType: HashType, hashType: HashType,
taprootOptions: TaprootSerializationOptions): DoubleSha256Digest = { taprootOptions: TaprootSerializationOptions): HashDigest = {
val inputIndexOpt = val txSigComponent = TxSigComponent(
TxUtil.inputIndexOpt(signingInfo.inputInfo, spendingTransaction) inputInfo = signingInfo.inputInfo,
unsignedTx = spendingTransaction,
if (inputIndexOpt.isEmpty) { outputMap = signingInfo.inputInfo.previousOutputMap,
errorHash flags = Policy.standardFlags)
} else if ( hashForSignature(txSigComponent, hashType, taprootOptions)
(hashType.isInstanceOf[SIGHASH_SINGLE] || hashType
.isInstanceOf[SIGHASH_SINGLE_ANYONECANPAY]) &&
inputIndexOpt.get >= spendingTransaction.outputs.size &&
signingInfo.sigVersion != SigVersionWitnessV0
) {
errorHash
} else {
val serializedTxForSignature =
serializeForSignature(spendingTransaction,
signingInfo,
hashType,
taprootOptions)
CryptoUtil.doubleSHA256(serializedTxForSignature)
}
} }
/** Sets the input's sequence number to zero EXCEPT for the input at /** Sets the input's sequence number to zero EXCEPT for the input at

View File

@ -6,6 +6,7 @@ import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.script.* import org.bitcoins.core.protocol.script.*
import org.bitcoins.core.protocol.transaction.* import org.bitcoins.core.protocol.transaction.*
import org.bitcoins.core.script.constant.{OP_TRUE, ScriptConstant} import org.bitcoins.core.script.constant.{OP_TRUE, ScriptConstant}
import org.bitcoins.core.script.util.PreviousOutputMap
import org.bitcoins.core.util.{BitcoinScriptUtil, BytesUtil} import org.bitcoins.core.util.{BitcoinScriptUtil, BytesUtil}
import org.bitcoins.crypto.{ import org.bitcoins.crypto.{
ECDigitalSignature, ECDigitalSignature,
@ -77,6 +78,8 @@ sealed trait InputInfo {
: ECSignatureParams[this.type] = { : ECSignatureParams[this.type] = {
signerMaterial.copy(inputInfo = this) signerMaterial.copy(inputInfo = this)
} }
def previousOutputMap: PreviousOutputMap
} }
object InputInfo { object InputInfo {
@ -347,6 +350,7 @@ object InputInfo {
sealed trait RawInputInfo extends InputInfo { sealed trait RawInputInfo extends InputInfo {
override def scriptPubKey: RawScriptPubKey override def scriptPubKey: RawScriptPubKey
override def previousOutputMap: PreviousOutputMap = PreviousOutputMap.empty
} }
object RawInputInfo { object RawInputInfo {
@ -422,6 +426,8 @@ case class EmptyInputInfo(outPoint: TransactionOutPoint, amount: CurrencyUnit)
ConditionalPath.NoCondition ConditionalPath.NoCondition
override def pubKeys: Vector[ECPublicKey] = Vector.empty override def pubKeys: Vector[ECPublicKey] = Vector.empty
override def requiredSigs: Int = 0 override def requiredSigs: Int = 0
override def previousOutputMap: PreviousOutputMap = PreviousOutputMap.empty
} }
case class P2PKInputInfo( case class P2PKInputInfo(
@ -550,6 +556,7 @@ case class LockTimeInputInfo(
sealed trait SegwitV0NativeInputInfo extends InputInfo { sealed trait SegwitV0NativeInputInfo extends InputInfo {
def scriptWitness: ScriptWitnessV0 def scriptWitness: ScriptWitnessV0
override def previousOutputMap: PreviousOutputMap = PreviousOutputMap.empty
} }
object SegwitV0NativeInputInfo { object SegwitV0NativeInputInfo {
@ -623,6 +630,7 @@ case class UnassignedSegwitNativeInputInfo(
pubKeys: Vector[ECPublicKey]) pubKeys: Vector[ECPublicKey])
extends InputInfo { extends InputInfo {
override def requiredSigs: Int = pubKeys.length override def requiredSigs: Int = pubKeys.length
override def previousOutputMap: PreviousOutputMap = PreviousOutputMap.empty
} }
sealed trait P2SHInputInfo extends InputInfo { sealed trait P2SHInputInfo extends InputInfo {
@ -637,6 +645,8 @@ sealed trait P2SHInputInfo extends InputInfo {
override def pubKeys: Vector[ECPublicKey] = nestedInputInfo.pubKeys override def pubKeys: Vector[ECPublicKey] = nestedInputInfo.pubKeys
override def requiredSigs: Int = nestedInputInfo.requiredSigs override def requiredSigs: Int = nestedInputInfo.requiredSigs
override def previousOutputMap: PreviousOutputMap = PreviousOutputMap.empty
} }
case class P2SHNonSegwitInputInfo( case class P2SHNonSegwitInputInfo(