diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedPSBT.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedPSBT.scala index 54151d6c75..32518a3225 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedPSBT.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedPSBT.scala @@ -1,14 +1,14 @@ package org.bitcoins.commons.jsonmodels -import org.bitcoins.commons.jsonmodels.SerializedTransaction._ -import org.bitcoins.commons.serializers.JsonSerializers._ +import org.bitcoins.commons.jsonmodels.SerializedTransaction.* +import org.bitcoins.commons.serializers.JsonSerializers.* import org.bitcoins.core.crypto.ExtPublicKey import org.bitcoins.core.number.UInt32 import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature -import org.bitcoins.core.psbt._ +import org.bitcoins.core.psbt.* import org.bitcoins.core.script.constant.ScriptToken -import org.bitcoins.crypto.HashType -import play.api.libs.json._ +import org.bitcoins.crypto.{DigitalSignature, HashType} +import play.api.libs.json.* import scodec.bits.ByteVector case class SerializedPSBT( @@ -29,7 +29,7 @@ case class SerializedPSBTGlobalMap( case class SerializedPSBTInputMap( nonWitnessUtxo: Option[SerializedTransaction], witnessUtxo: Option[SerializedTransactionOutput], - signatures: Option[Vector[PartialSignature]], + signatures: Option[Vector[PartialSignature[DigitalSignature]]], sigHashType: Option[HashType], redeemScript: Option[Vector[ScriptToken]], witScript: Option[Vector[ScriptToken]], @@ -68,7 +68,7 @@ object SerializedPSBT { val witnessUtxo = input.witnessUTXOOpt.map(rec => decodeTransactionOutput(rec.witnessUTXO, index)) - val sigs = input.partialSignatures + val sigs = input.partialSignatures[DigitalSignature] val sigsOpt = if (sigs.nonEmpty) Some(sigs) else None val hashType = input.sigHashTypeOpt.map(_.hashType) val redeemScript = input.redeemScriptOpt.map(_.redeemScript.asm.toVector) diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala index 1e54acc0a8..71bcb15327 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala @@ -848,8 +848,10 @@ object JsonSerializers { implicit val serializedPSBTGlobalWrites: Writes[SerializedPSBTGlobalMap] = Json.writes[SerializedPSBTGlobalMap] - implicit val serializedPSBTInputWrites: Writes[SerializedPSBTInputMap] = + implicit val serializedPSBTInputWrites: Writes[SerializedPSBTInputMap] = { + import JsonWriters.PartialSignatureWrites Json.writes[SerializedPSBTInputMap] + } implicit val serializedPSBTOutputWrites: Writes[SerializedPSBTOutputMap] = Json.writes[SerializedPSBTOutputMap] diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonWriters.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonWriters.scala index 8a9f19064c..05dc34d87b 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonWriters.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonWriters.scala @@ -257,9 +257,10 @@ object JsonWriters { } implicit object PartialSignatureWrites - extends Writes[InputPSBTRecord.PartialSignature] { + extends Writes[InputPSBTRecord.PartialSignature[DigitalSignature]] { - override def writes(o: InputPSBTRecord.PartialSignature): JsValue = + override def writes( + o: InputPSBTRecord.PartialSignature[DigitalSignature]): JsValue = JsObject( Seq( ("pubkey", JsString(o.pubKey.hex)), diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/Picklers.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/Picklers.scala index 102fa8da5f..9dc8c3cc6d 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/Picklers.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/Picklers.scala @@ -140,7 +140,7 @@ object Picklers { : ReadWriter[SchnorrDigitalSignature] = readwriter[String].bimap(_.hex, SchnorrDigitalSignature.fromHex) - implicit val partialSignaturePickler: ReadWriter[PartialSignature] = + implicit val partialSignaturePickler: ReadWriter[PartialSignature[?]] = readwriter[String].bimap(_.hex, PartialSignature.fromHex) implicit val lnMessageDLCOfferTLVPickler: ReadWriter[LnMessage[DLCOfferTLV]] = diff --git a/app/cli/src/main/scala/org/bitcoins/cli/CliReaders.scala b/app/cli/src/main/scala/org/bitcoins/cli/CliReaders.scala index b7468b3c58..dac77dd521 100644 --- a/app/cli/src/main/scala/org/bitcoins/cli/CliReaders.scala +++ b/app/cli/src/main/scala/org/bitcoins/cli/CliReaders.scala @@ -291,11 +291,11 @@ object CliReaders { str => SchnorrDigitalSignature.fromHex(str.trim) } - implicit val partialSigReads: Read[PartialSignature] = - new Read[PartialSignature] { + implicit val partialSigReads: Read[PartialSignature[DigitalSignature]] = + new Read[PartialSignature[DigitalSignature]] { override def arity: Int = 1 - override def reads: String => PartialSignature = + override def reads: String => PartialSignature[DigitalSignature] = PartialSignature.fromHex } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala index 64220aea83..d0002b1e47 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala @@ -554,7 +554,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { privKey, HashType.sigHashAll ), - transaction + transaction, + privKey.signLowRWithHashType ) signedTx match { diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTLVGen.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTLVGen.scala index c7b7206788..318187a84a 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTLVGen.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTLVGen.scala @@ -212,7 +212,7 @@ object DLCTLVGen { def partialSig( pubKey: ECPublicKey = ECPublicKey.freshPublicKey, sigHashByte: Boolean = true - ): PartialSignature = { + ): PartialSignature[ECDigitalSignature] = { PartialSignature(pubKey, ecdsaSig(sigHashByte)) } @@ -236,7 +236,7 @@ object DLCTLVGen { def refundSigs( fundingPubKey: ECPublicKey = ECPublicKey.freshPublicKey - ): PartialSignature = { + ): PartialSignature[ECDigitalSignature] = { partialSig(fundingPubKey, sigHashByte = false) } @@ -367,7 +367,7 @@ object DLCTLVGen { changeAddress: BitcoinAddress = address(), changeSerialId: UInt64 = DLCMessage.genSerialId(), cetSignatures: CETSignatures = cetSigs(), - refundSignatures: PartialSignature = refundSigs(), + refundSignatures: PartialSignature[ECDigitalSignature] = refundSigs(), tempContractId: Sha256Digest = hash() ): DLCAccept = { DLCAccept( @@ -393,7 +393,7 @@ object DLCTLVGen { changeAddress: BitcoinAddress = address(), changeSerialId: UInt64 = DLCMessage.genSerialId(), cetSignatures: CETSignatures = cetSigs(), - refundSignatures: PartialSignature = refundSigs(), + refundSignatures: PartialSignature[ECDigitalSignature] = refundSigs(), tempContractId: Sha256Digest = hash() ): DLCAcceptTLV = { dlcAccept( @@ -499,7 +499,7 @@ object DLCTLVGen { def dlcSign( cetSignatures: CETSignatures = cetSigs(), - refundSignatures: PartialSignature = refundSigs(), + refundSignatures: PartialSignature[ECDigitalSignature] = refundSigs(), fundingSignatures: FundingSignatures = fundingSigs(), contractId: ByteVector = hash().bytes ): DLCSign = { @@ -508,7 +508,7 @@ object DLCTLVGen { def dlcSignTLV( cetSignatures: CETSignatures = cetSigs(), - refundSignatures: PartialSignature = refundSigs(), + refundSignatures: PartialSignature[ECDigitalSignature] = refundSigs(), fundingSignatures: FundingSignatures = fundingSigs(), contractId: ByteVector = hash().bytes ): DLCSignTLV = { @@ -522,7 +522,7 @@ object DLCTLVGen { def dlcSignParsingTestVector( cetSignatures: CETSignatures = cetSigs(), - refundSignatures: PartialSignature = refundSigs(), + refundSignatures: PartialSignature[ECDigitalSignature] = refundSigs(), fundingSignatures: FundingSignatures = fundingSigs(), contractId: ByteVector = hash().bytes ): DLCParsingTestVector = { diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala index b68d0958c5..a8dd8d12b7 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala @@ -129,7 +129,7 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { TransactionSignatureCreator.createSig( transaction, signingInfo, - privateKey, + privateKey.signLowRWithHashType, HashType.sigHashAll ) txSignature.r must be(expectedSig.r) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala index 2eddf18f01..90699327b4 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala @@ -45,7 +45,7 @@ class DLCMessageTest extends BitcoinSJvmTest { Vector(EnumOutcome(dummyStr)) ) - val dummySig: PartialSignature = + val dummySig: PartialSignature[ECDigitalSignature] = PartialSignature(dummyPubKey, ECDigitalSignature.empty) it must "not allow a negative collateral for a DLCOffer" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/signer/SignerTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/signer/SignerTest.scala index 78357bdf00..87c528fa66 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/signer/SignerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/signer/SignerTest.scala @@ -110,7 +110,8 @@ class SignerTest extends BitcoinSUnitTest { val keyAndSig = BitcoinSigner.signSingle( singleInfo, - unsignedTx + unsignedTx, + singleInfo.signer.signLowRWithHashType ) keyAndSig.signature @@ -235,7 +236,7 @@ class SignerTest extends BitcoinSUnitTest { changeSPK ) - val singleSigs: Vector[Vector[PartialSignature]] = { + val singleSigs: Vector[Vector[PartialSignature[ECDigitalSignature]]] = { val singleInfosVec: Vector[Vector[ECSignatureParams[InputInfo]]] = creditingTxsInfos.toVector.map(_.toSingles) singleInfosVec.map { singleInfos => @@ -248,7 +249,9 @@ class SignerTest extends BitcoinSUnitTest { unsignedTx.lockTime, EmptyWitness.fromInputs(unsignedTx.inputs) ) - BitcoinSigner.signSingle(singleInfo, wtx) + BitcoinSigner.signSingle(singleInfo, + wtx, + singleInfo.signer.signLowRWithHashType) } } diff --git a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala index 8d63ffaceb..ca24a4e206 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala @@ -10,7 +10,6 @@ import org.bitcoins.core.protocol.script.{ TaprootKeyPath } import org.bitcoins.core.protocol.transaction.TransactionOutput -import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature import org.bitcoins.core.script.constant.ScriptToken import org.bitcoins.core.script.flag.{ScriptFlag, ScriptFlagUtil} import org.bitcoins.core.script.result.{ @@ -35,33 +34,23 @@ trait TransactionSignatureChecker { txSignatureComponent: TxSigComponent, pubKeyBytes: ECPublicKeyBytes, signature: ECDigitalSignature): TransactionSignatureCheckerResult = - checkSignature(txSignatureComponent, - PartialSignature(pubKeyBytes, signature)) + checkSignature(txSignatureComponent = txSignatureComponent, + script = txSignatureComponent.output.scriptPubKey.asm.toList, + pubKey = pubKeyBytes, + signature = signature) def checkSignature( txSignatureComponent: TxSigComponent, pubKey: ECPublicKey, - signature: ECDigitalSignature): TransactionSignatureCheckerResult = - checkSignature(txSignatureComponent, PartialSignature(pubKey, signature)) - - def checkSignature( - txSignatureComponent: TxSigComponent, - partialSignature: PartialSignature): TransactionSignatureCheckerResult = { - checkSignature(txSignatureComponent, - txSignatureComponent.output.scriptPubKey.asm.toList, - partialSignature.pubKey, - partialSignature.signature) + signature: ECDigitalSignature): TransactionSignatureCheckerResult = { + checkSignature( + txSignatureComponent = txSignatureComponent, + script = txSignatureComponent.output.scriptPubKey.asm.toList, + pubKey = pubKey.toPublicKeyBytes(), + signature = signature + ) } - def checkSignature( - txSignatureComponent: TxSigComponent, - script: Seq[ScriptToken], - partialSignature: PartialSignature): TransactionSignatureCheckerResult = - checkSignature(txSignatureComponent, - script, - partialSignature.pubKey, - partialSignature.signature) - /** @param txSigComponent * @param schnorrSignature * @param pubKey diff --git a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCreator.scala b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCreator.scala index cf4885f4d1..6883341365 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCreator.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCreator.scala @@ -90,25 +90,6 @@ sealed abstract class TransactionSignatureCreator { } } - /** Creates a signature from a tx signature component - * - * @param privateKey - * the private key which we are signing the hash with - * @param hashType - * the procedure to use for hashing to transaction - * @return - */ - def createSig( - spendingTransaction: Transaction, - signingInfo: InputSigningInfo[InputInfo], - privateKey: ECPrivateKey, - hashType: HashType): ECDigitalSignature = { - createSig(spendingTransaction, - signingInfo, - privateKey.signWithHashType, - hashType) - } - /** This is intended to be a low level hardware wallet API. At a fundamental * level, a hardware wallet expects a scodec.bits.ByteVector as input, and * returns an [[ECDigitalSignature]] if it is able to sign the @@ -122,11 +103,11 @@ sealed abstract class TransactionSignatureCreator { * @return * the digital signature returned by the hardware wallet */ - def createSig( + def createSig[Sig <: DigitalSignature]( spendingTransaction: Transaction, signingInfo: InputSigningInfo[InputInfo], - sign: (ByteVector, HashType) => ECDigitalSignature, - hashType: HashType): ECDigitalSignature = { + sign: (ByteVector, HashType) => Sig, + hashType: HashType): Sig = { val hash = TransactionSignatureSerializer.hashForSignature( spendingTransaction = spendingTransaction, signingInfo = signingInfo, diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCExecutor.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCExecutor.scala index ba74c9f6a0..37ab9399ec 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCExecutor.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCExecutor.scala @@ -3,12 +3,12 @@ package org.bitcoins.core.protocol.dlc.execution import org.bitcoins.core.currency.CurrencyUnit import org.bitcoins.core.protocol.dlc.build.DLCTxBuilder import org.bitcoins.core.protocol.dlc.compute.{CETCalculator, DLCUtil} -import org.bitcoins.core.protocol.dlc.models._ +import org.bitcoins.core.protocol.dlc.models.* import org.bitcoins.core.protocol.dlc.sign.DLCTxSigner import org.bitcoins.core.protocol.transaction.{Transaction, WitnessTransaction} import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature import org.bitcoins.core.util.Indexed -import org.bitcoins.crypto.{AdaptorSign, ECPublicKey} +import org.bitcoins.crypto.{AdaptorSign, ECDigitalSignature, ECPublicKey} import scala.util.{Success, Try} @@ -22,7 +22,7 @@ case class DLCExecutor(signer: DLCTxSigner) { */ def setupDLCOffer( cetSigs: CETSignatures, - refundSig: PartialSignature): Try[SetupDLC] = { + refundSig: PartialSignature[ECDigitalSignature]): Try[SetupDLC] = { require(isInitiator, "You should call setupDLCAccept") setupDLC(cetSigs, refundSig, None, None) @@ -34,7 +34,7 @@ case class DLCExecutor(signer: DLCTxSigner) { */ def setupDLCAccept( cetSigs: CETSignatures, - refundSig: PartialSignature, + refundSig: PartialSignature[ECDigitalSignature], fundingSigs: FundingSignatures, cetsOpt: Option[Vector[WitnessTransaction]]): Try[SetupDLC] = { require(!isInitiator, "You should call setupDLCOffer") @@ -47,7 +47,7 @@ case class DLCExecutor(signer: DLCTxSigner) { */ def setupDLC( cetSigs: CETSignatures, - refundSig: PartialSignature, + refundSig: PartialSignature[ECDigitalSignature], fundingSigsOpt: Option[FundingSignatures], cetsOpt: Option[Vector[WitnessTransaction]]): Try[SetupDLC] = { if (!isInitiator) { @@ -114,7 +114,8 @@ case class DLCExecutor(signer: DLCTxSigner) { RefundDLCOutcome(fundingTx, refundTx) } - def executeRefundDLC(refundSig: PartialSignature): RefundDLCOutcome = { + def executeRefundDLC( + refundSig: PartialSignature[ECDigitalSignature]): RefundDLCOutcome = { val refundTx = signer.completeRefundTx(refundSig) val fundingTx = signer.builder.buildFundingTx RefundDLCOutcome(fundingTx, refundTx) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCMessage.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCMessage.scala index a3888b83b5..2a06509d67 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCMessage.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCMessage.scala @@ -196,7 +196,7 @@ object DLCMessage { changeAddress: BitcoinAddress, payoutSerialId: UInt64, changeSerialId: UInt64, - refundSig: PartialSignature, + refundSig: PartialSignature[ECDigitalSignature], negotiationFields: DLCAccept.NegotiationFields, tempContractId: Sha256Digest) { @@ -229,7 +229,8 @@ object DLCMessage { negotiationFields: DLCAccept.NegotiationFields, tempContractId: Sha256Digest) { - def withRefundSigs(refundSig: PartialSignature): DLCAcceptWithoutCetSigs = { + def withRefundSigs(refundSig: PartialSignature[ECDigitalSignature]) + : DLCAcceptWithoutCetSigs = { DLCAcceptWithoutCetSigs( totalCollateral = totalCollateral, pubKeys = pubKeys, @@ -245,7 +246,7 @@ object DLCMessage { def withSigs( cetSigs: CETSignatures, - refundSig: PartialSignature): DLCAccept = { + refundSig: PartialSignature[ECDigitalSignature]): DLCAccept = { DLCAccept( collateral = totalCollateral, pubKeys = pubKeys, @@ -269,7 +270,7 @@ object DLCMessage { payoutSerialId: UInt64, changeSerialId: UInt64, cetSigs: CETSignatures, - refundSig: PartialSignature, + refundSig: PartialSignature[ECDigitalSignature], negotiationFields: DLCAccept.NegotiationFields, tempContractId: Sha256Digest, isExternalAddress: Boolean = false) @@ -428,7 +429,7 @@ object DLCMessage { case class DLCSign( cetSigs: CETSignatures, - refundSig: PartialSignature, + refundSig: PartialSignature[ECDigitalSignature], fundingSigs: FundingSignatures, contractId: ByteVector) extends DLCMessage { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/sign/DLCTxSigner.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/sign/DLCTxSigner.scala index f1b146321e..3a49d661c6 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/sign/DLCTxSigner.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/sign/DLCTxSigner.scala @@ -200,12 +200,13 @@ case class DLCTxSigner( } /** Creates this party's signature of the refund transaction */ - lazy val signRefundTx: PartialSignature = { + lazy val signRefundTx: PartialSignature[ECDigitalSignature] = { DLCTxSigner.signRefundTx(cetSigningInfo, builder.buildRefundTx) } /** Constructs the signed refund transaction given remote's signature */ - def completeRefundTx(remoteSig: PartialSignature): WitnessTransaction = { + def completeRefundTx( + remoteSig: PartialSignature[ECDigitalSignature]): WitnessTransaction = { val localSig = signRefundTx DLCTxSigner.completeRefundTx(localSig, @@ -414,7 +415,7 @@ object DLCTxSigner { def signRefundTx( refundSigningInfo: ECSignatureParams[P2WSHV0InputInfo], refundTx: WitnessTransaction - ): PartialSignature = { + ): PartialSignature[ECDigitalSignature] = { val fundingPubKey = refundSigningInfo.signer.publicKey val sig = TransactionSignatureCreator.createSig( @@ -428,8 +429,8 @@ object DLCTxSigner { // TODO: Without PSBTs def completeRefundTx( - localSig: PartialSignature, - remoteSig: PartialSignature, + localSig: PartialSignature[ECDigitalSignature], + remoteSig: PartialSignature[ECDigitalSignature], fundingMultiSig: MultiSignatureScriptPubKey, fundingTx: Transaction, uRefundTx: WitnessTransaction): WitnessTransaction = { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/verify/DLCSignatureVerifier.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/verify/DLCSignatureVerifier.scala index 4ec4196da0..8711188d55 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/verify/DLCSignatureVerifier.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/verify/DLCSignatureVerifier.scala @@ -17,7 +17,12 @@ import org.bitcoins.core.protocol.transaction.{Transaction, WitnessTransaction} import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature import org.bitcoins.core.psbt.PSBT import org.bitcoins.core.util.{FutureUtil, Indexed} -import org.bitcoins.crypto.{ECAdaptorSignature, ECPublicKey, HashType} +import org.bitcoins.crypto.{ + ECAdaptorSignature, + ECDigitalSignature, + ECPublicKey, + HashType +} import scodec.bits.ByteVector import scala.concurrent.{ExecutionContext, Future} @@ -76,7 +81,7 @@ case class DLCSignatureVerifier(builder: DLCTxBuilder, isInitiator: Boolean) { } /** Verifies remote's refund signature */ - def verifyRefundSig(sig: PartialSignature): Boolean = { + def verifyRefundSig(sig: PartialSignature[ECDigitalSignature]): Boolean = { val refundTx = builder.buildRefundTx DLCSignatureVerifier.validateRefundSignature(sig, @@ -114,7 +119,7 @@ object DLCSignatureVerifier { } def validateRefundSignature( - refundSig: PartialSignature, + refundSig: PartialSignature[ECDigitalSignature], fundingTx: Transaction, fundOutputIndex: Int, refundTx: WitnessTransaction diff --git a/core/src/main/scala/org/bitcoins/core/protocol/tlv/TLV.scala b/core/src/main/scala/org/bitcoins/core/protocol/tlv/TLV.scala index 713b0b92f0..0aad17abc3 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/tlv/TLV.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/tlv/TLV.scala @@ -2051,7 +2051,7 @@ case class DLCAcceptTLV( negotiationFields.bytes } - val refundPartialSignature: PartialSignature = { + val refundPartialSignature: PartialSignature[ECDigitalSignature] = { PartialSignature(fundingPubKey, refundSignature) } } @@ -2108,7 +2108,8 @@ case class DLCSignTLV( fundingSignatures.bytes } - def getPartialSignature(fundingPubKey: ECPublicKey): PartialSignature = { + def getPartialSignature( + fundingPubKey: ECPublicKey): PartialSignature[ECDigitalSignature] = { PartialSignature(fundingPubKey, refundSignature) } } diff --git a/core/src/main/scala/org/bitcoins/core/psbt/PSBT.scala b/core/src/main/scala/org/bitcoins/core/psbt/PSBT.scala index ef463b5854..e4c3581d2c 100644 --- a/core/src/main/scala/org/bitcoins/core/psbt/PSBT.scala +++ b/core/src/main/scala/org/bitcoins/core/psbt/PSBT.scala @@ -690,18 +690,20 @@ case class PSBT( PSBT(globalMap, newInputMaps, outputMaps) } - def addSignature( + def addSignature[Sig <: DigitalSignature]( pubKey: ECPublicKey, - sig: ECDigitalSignature, + sig: Sig, inputIndex: Int): PSBT = - addSignature(PartialSignature(pubKey, sig), inputIndex) + addSignature(PartialSignature(pubKey.toPublicKeyBytes(), sig), inputIndex) - def addSignature(partialSignature: PartialSignature, inputIndex: Int): PSBT = + def addSignature[Sig <: DigitalSignature]( + partialSignature: PartialSignature[Sig], + inputIndex: Int): PSBT = addSignatures(Vector(partialSignature), inputIndex) /** Adds all the PartialSignatures to the input map at the given index */ - def addSignatures( - partialSignatures: Vector[PartialSignature], + def addSignatures[Sig <: DigitalSignature]( + partialSignatures: Vector[PartialSignature[Sig]], inputIndex: Int): PSBT = { require( inputIndex < inputMaps.size, diff --git a/core/src/main/scala/org/bitcoins/core/psbt/PSBTKeyId.scala b/core/src/main/scala/org/bitcoins/core/psbt/PSBTKeyId.scala index cf017f6451..04d536a010 100644 --- a/core/src/main/scala/org/bitcoins/core/psbt/PSBTKeyId.scala +++ b/core/src/main/scala/org/bitcoins/core/psbt/PSBTKeyId.scala @@ -1,6 +1,6 @@ package org.bitcoins.core.psbt -import org.bitcoins.crypto.Factory +import org.bitcoins.crypto.{DigitalSignature, Factory} import scodec.bits.ByteVector /** A PSBTKeyId refers to the first byte of a key that signifies which kind of @@ -74,7 +74,7 @@ object PSBTInputKeyId extends PSBTKeyIdFactory[PSBTInputKeyId] { byte match { case NonWitnessUTXOKeyId.byte => NonWitnessUTXOKeyId case WitnessUTXOKeyId.byte => WitnessUTXOKeyId - case PartialSignatureKeyId.byte => PartialSignatureKeyId + case PartialSignatureKeyId.byte => PartialSignatureKeyId() case SigHashTypeKeyId.byte => SigHashTypeKeyId case RedeemScriptKeyId.byte => RedeemScriptKeyId case WitnessScriptKeyId.byte => WitnessScriptKeyId @@ -106,9 +106,14 @@ object PSBTInputKeyId extends PSBTKeyIdFactory[PSBTInputKeyId] { type RecordType = InputPSBTRecord.WitnessUTXO } - case object PartialSignatureKeyId extends PSBTInputKeyId { + case class PartialSignatureKeyId[Sig <: DigitalSignature]() + extends PSBTInputKeyId { override val byte: Byte = 0x02.byteValue - type RecordType = InputPSBTRecord.PartialSignature + type RecordType = InputPSBTRecord.PartialSignature[Sig] + } + + object PartialSignatureKeyId { + val byte: Byte = PartialSignatureKeyId().byte } case object SigHashTypeKeyId extends PSBTInputKeyId { diff --git a/core/src/main/scala/org/bitcoins/core/psbt/PSBTMap.scala b/core/src/main/scala/org/bitcoins/core/psbt/PSBTMap.scala index 297ec64131..f68cbf5ef1 100644 --- a/core/src/main/scala/org/bitcoins/core/psbt/PSBTMap.scala +++ b/core/src/main/scala/org/bitcoins/core/psbt/PSBTMap.scala @@ -2,12 +2,12 @@ package org.bitcoins.core.psbt import org.bitcoins.core.byteVectorOrdering import org.bitcoins.core.number.UInt32 -import org.bitcoins.core.protocol.script._ -import org.bitcoins.core.protocol.transaction._ +import org.bitcoins.core.protocol.script.* +import org.bitcoins.core.protocol.transaction.* import org.bitcoins.core.util.SeqWrapper import org.bitcoins.core.wallet.signer.BitcoinSigner -import org.bitcoins.core.wallet.utxo._ -import org.bitcoins.crypto.{HashType, _} +import org.bitcoins.core.wallet.utxo.* +import org.bitcoins.crypto.* import scodec.bits.ByteVector import scala.annotation.tailrec @@ -234,7 +234,7 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) case multi: MultiSignatureScriptPubKey => if (partialSignatures.size < multi.requiredSigs) { val keys = multi.publicKeys.filterNot(key => - partialSignatures.exists(_.pubKey == key)) + partialSignatures[ECDigitalSignature].exists(_.pubKey == key)) keys.map(key => CryptoUtil.sha256Hash160(key.bytes)).toVector } else Vector.empty case p2wpkh: P2WPKHWitnessSPKV0 => @@ -301,8 +301,9 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) getRecords(WitnessUTXOKeyId).headOption } - def partialSignatures: Vector[PartialSignature] = { - getRecords(PartialSignatureKeyId) + def partialSignatures[Sig <: DigitalSignature] + : Vector[PartialSignature[Sig]] = { + getRecords(PartialSignatureKeyId[Sig]()) } def sigHashTypeOpt: Option[SigHashType] = { @@ -440,17 +441,19 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) * @return * None if the requirement is not met */ - def collectSigs( + def collectSigs[Sig <: DigitalSignature]( required: Int, - constructScriptSig: Seq[PartialSignature] => ScriptSignature) + constructScriptSig: Seq[PartialSignature[Sig]] => ScriptSignature) : Try[InputPSBTMap] = { - val sigs = getRecords(PartialSignatureKeyId) + val sigs = getRecords(PartialSignatureKeyId[Sig]()) if (sigs.length != required) { Failure(new IllegalArgumentException( s"Could not collect $required signatures when only the following were present: $sigs")) } else { - val scriptSig = constructScriptSig( - sigs.map(sig => PartialSignature(sig.pubKey, sig.signature))) + val scriptSig = constructScriptSig(sigs.map { + case sig: PartialSignature[Sig] => + PartialSignature(sig.pubKey, sig.signature) + }) val newInputMap = wipeAndAdd(scriptSig) @@ -504,15 +507,16 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) } case _: P2WPKHWitnessSPKV0 => val sigOpt = - getRecords(PartialSignatureKeyId).headOption - toTry(sigOpt, "there is no partial signature record").map { sig => - val witness = P2WPKHWitnessV0(sig.pubKey, sig.signature) - val scriptSig = EmptyScriptSignature - wipeAndAdd(scriptSig, Some(witness)) + getRecords(PartialSignatureKeyId[ECDigitalSignature]()).headOption + toTry(sigOpt, "there is no partial signature record").map { + case sig: PartialSignature[ECDigitalSignature] => + val witness = P2WPKHWitnessV0(sig.pubKey, sig.signature) + val scriptSig = EmptyScriptSignature + wipeAndAdd(scriptSig, Some(witness)) } case p2pkWithTimeout: P2PKWithTimeoutScriptPubKey => val sigOpt = - getRecords(PartialSignatureKeyId).headOption + getRecords(PartialSignatureKeyId[ECDigitalSignature]()).headOption toTry(sigOpt, "there is no partial signature record").flatMap { sig => if (sig.pubKey == p2pkWithTimeout.pubKey) { val scriptSig = P2PKWithTimeoutScriptSignature(beforeTimeout = true, @@ -591,7 +595,7 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) // Find the conditional leaf with the pubkeys for which sigs are provided // Hashes are used since we only have the pubkey hash in the p2pkh case - val sigs = getRecords(PartialSignatureKeyId) + val sigs = getRecords(PartialSignatureKeyId[SchnorrDigitalSignature]()) val hashes = sigs.map(sig => CryptoUtil.sha256Hash160(sig.pubKey.bytes)) addLeaves(conditional, Vector.empty) val leaves = builder.result() @@ -622,15 +626,16 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) case locktime: LockTimeScriptPubKey => finalize(locktime.nestedScriptPubKey) case _: P2PKHScriptPubKey => - collectSigs( + collectSigs[ECDigitalSignature]( required = 1, sigs => P2PKHScriptSignature(sigs.head.signature, sigs.head.pubKey)) case _: P2PKScriptPubKey => - collectSigs(required = 1, - sigs => P2PKScriptSignature(sigs.head.signature)) + collectSigs[ECDigitalSignature]( + required = 1, + sigs => P2PKScriptSignature(sigs.head.signature)) case multiSig: MultiSignatureScriptPubKey => - def generateScriptSig( - sigs: Seq[PartialSignature]): MultiSignatureScriptSignature = { + def generateScriptSig(sigs: Seq[PartialSignature[ECDigitalSignature]]) + : MultiSignatureScriptSignature = { val sortedSigs = sigs .map { partialSig => (partialSig.signature, @@ -941,7 +946,26 @@ object InputPSBTMap extends PSBTMapFactory[InputPSBTRecord, InputPSBTMap] { spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction): InputPSBTMap = { val sigs = spendingInfo.toSingles.map { spendingInfoSingle => - BitcoinSigner.signSingle(spendingInfoSingle, unsignedTx) + spendingInfoSingle.inputInfo.scriptPubKey match { + case _: NonWitnessScriptPubKey => + BitcoinSigner.signSingle( + spendingInfoSingle, + unsignedTx, + spendingInfoSingle.signer.signLowRWithHashType) + case _: WitnessScriptPubKeyV0 => + BitcoinSigner.signSingle( + spendingInfoSingle, + unsignedTx, + spendingInfoSingle.signer.signLowRWithHashType) + case _: TaprootScriptPubKey => + BitcoinSigner.signSingle( + spendingInfoSingle, + unsignedTx, + spendingInfoSingle.signer.schnorrSignWithHashType) + case u: UnassignedWitnessScriptPubKey => + sys.error(s"Cannot sign unsupported witSPK=$u") + } + } val builder = Vector.newBuilder[InputPSBTRecord] diff --git a/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala b/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala index 43284c30cd..28f79c5b48 100644 --- a/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala +++ b/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala @@ -157,47 +157,53 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { override val value: ByteVector = witnessUTXO.bytes } - case class PartialSignature( + case class PartialSignature[Sig <: DigitalSignature]( pubKey: ECPublicKeyBytes, - signature: ECDigitalSignature) + signature: Sig) extends InputPSBTRecord { require(pubKey.byteSize == 33, s"pubKey must be 33 bytes, got: ${pubKey.byteSize}") - override type KeyId = PartialSignatureKeyId.type + override type KeyId = PartialSignatureKeyId[DigitalSignature] override val key: ByteVector = ByteVector(PartialSignatureKeyId.byte) ++ pubKey.bytes override val value: ByteVector = signature.bytes } - object PartialSignature extends Factory[PartialSignature] { + object PartialSignature extends Factory[PartialSignature[DigitalSignature]] { def apply( pubKey: ECPublicKey, - signature: ECDigitalSignature): PartialSignature = { + signature: ECDigitalSignature): PartialSignature[ECDigitalSignature] = { PartialSignature(pubKey.toPublicKeyBytes(), signature) } - def dummyPartialSig( - pubKey: ECPublicKey = ECPublicKey.freshPublicKey): PartialSignature = { + def apply(pubKey: ECPublicKey, signature: SchnorrDigitalSignature) + : PartialSignature[SchnorrDigitalSignature] = { + PartialSignature(pubKey.toPublicKeyBytes(), signature) + } + + def dummyPartialSig(pubKey: ECPublicKey = ECPublicKey.freshPublicKey) + : PartialSignature[ECDigitalSignature] = { PartialSignature(pubKey, ECDigitalSignature.dummy) } - override def fromBytes(bytes: ByteVector): PartialSignature = + override def fromBytes( + bytes: ByteVector): PartialSignature[DigitalSignature] = InputPSBTRecord(bytes) match { - case partialSignature: PartialSignature => + case partialSignature: PartialSignature[DigitalSignature] @unchecked => partialSignature case other: InputPSBTRecord => throw new IllegalArgumentException( s"Invalid PartialSignature encoding, got: $other") } - def vecFromBytes(bytes: ByteVector): Vector[PartialSignature] = { + def vecFromBytes(bytes: ByteVector): Vector[PartialSignature[?]] = { @scala.annotation.tailrec def loop( remainingBytes: ByteVector, - accum: Vector[PartialSignature]): Vector[PartialSignature] = { + accum: Vector[PartialSignature[?]]): Vector[PartialSignature[?]] = { if (remainingBytes.isEmpty) { accum } else { @@ -211,7 +217,7 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { loop(bytes, Vector.empty) } - def vecFromHex(hex: String): Vector[PartialSignature] = { + def vecFromHex(hex: String): Vector[PartialSignature[?]] = { vecFromBytes(BytesUtil.decodeHex(hex)) } } @@ -419,10 +425,15 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { s"The key must only contain the 1 byte type, got: ${key.size}") WitnessUTXO(TransactionOutput.fromBytes(value)) - case PartialSignatureKeyId => + case PartialSignatureKeyId() => val pubKey = ECPublicKey(key.tail) - val sig = ECDigitalSignature(value) - PartialSignature(pubKey, sig) + if (value.length == 64 || value.length == 65) { + val sig = SchnorrDigitalSignature(value) + PartialSignature(pubKey.toPublicKeyBytes(), sig) + } else { + val sig = ECDigitalSignature(value) + PartialSignature(pubKey.toPublicKeyBytes(), sig) + } case SigHashTypeKeyId => require(key.size == 1, s"The key must only contain the 1 byte type, got: ${key.size}") diff --git a/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala b/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala index 1d5ad1fe3f..819ef28256 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala @@ -15,20 +15,22 @@ import scodec.bits.ByteVector sealed abstract class SignerUtils { - def doSign( + def doSign[Sig <: DigitalSignature]( unsignedTx: Transaction, signingInfo: InputSigningInfo[InputInfo], - sign: (ByteVector, HashType) => ECDigitalSignature, - hashType: HashType): ECDigitalSignature = { + sign: (ByteVector, HashType) => Sig, + hashType: HashType): Sig = { TransactionSignatureCreator.createSig(unsignedTx, signingInfo, sign, hashType) } - def signSingle( + def signSingle[Sig <: DigitalSignature]( spendingInfo: ECSignatureParams[InputInfo], - unsignedTx: Transaction): PartialSignature = { + unsignedTx: Transaction, + signWithHashType: (ByteVector, HashType) => Sig) + : PartialSignature[Sig] = { val tx = spendingInfo.inputInfo match { case _: SegwitV0NativeInputInfo | _: P2SHNestedSegwitV0InputInfo | @@ -38,14 +40,15 @@ sealed abstract class SignerUtils { unsignedTx } - val signature = doSign( + val signature: Sig = doSign( unsignedTx = tx, signingInfo = spendingInfo, - sign = spendingInfo.signer.signLowRWithHashType, + sign = signWithHashType, hashType = spendingInfo.hashType ) - PartialSignature(spendingInfo.signer.publicKey, signature) + PartialSignature(spendingInfo.signer.publicKey.toPublicKeyBytes(), + signature) } protected val flags: Seq[ScriptFlag] = Policy.standardFlags @@ -206,12 +209,11 @@ object BitcoinSigner extends SignerUtils { signer: Sign, conditionalPath: ConditionalPath = ConditionalPath.NoCondition): PSBT = { // if already signed by this signer - if ( - psbt - .inputMaps(inputIndex) - .partialSignatures - .exists(_.pubKey.toPublicKey == signer.publicKey) - ) { + val partialSigs = psbt + .inputMaps(inputIndex) + .partialSignatures + val isSigned = partialSigs.exists(_.pubKey.toPublicKey == signer.publicKey) + if (isSigned) { throw new IllegalArgumentException( "Input has already been signed with this key") } @@ -222,9 +224,9 @@ object BitcoinSigner extends SignerUtils { .inputMaps(inputIndex) .toUTXOSigningInfo(tx.inputs(inputIndex), signer, conditionalPath) - val txToSign = spendingInfo.output.scriptPubKey match { - case _: WitnessScriptPubKey => - tx match { + val partialSignature = spendingInfo.output.scriptPubKey match { + case _: WitnessScriptPubKeyV0 => + val txToSign = tx match { case btx: NonWitnessTransaction => val witnesses = psbt.inputMaps.map { map => map.witnessScriptOpt.map(scriptWit => @@ -253,12 +255,15 @@ object BitcoinSigner extends SignerUtils { wtx } } - case _: ScriptPubKey => tx + signSingle(spendingInfo, txToSign, signer.signLowRWithHashType) + case _: TaprootScriptPubKey => + signSingle(spendingInfo, tx, signer.schnorrSignWithHashType) + case _: NonWitnessScriptPubKey => + signSingle(spendingInfo, tx, signer.signLowRWithHashType) + case u: UnassignedWitnessScriptPubKey => + sys.error(s"Cannot sign unsupported witSPK=$u") } - val partialSignature = - signSingle(spendingInfo, txToSign) - psbt.addSignature(partialSignature, inputIndex) } } @@ -280,8 +285,9 @@ sealed abstract class RawSingleKeyBitcoinSigner[-InputType <: RawInputInfo] val (_, output, inputIndex, _) = relevantInfo(spendingInfo, unsignedTx) + val single = spendingInfo.toSingle(0) val partialSignature = - signSingle(spendingInfo.toSingle(0), unsignedTx) + signSingle(single, unsignedTx, single.signer.signLowRWithHashType) val scriptSig = keyAndSigToScriptSig(partialSignature.pubKey.toPublicKey, @@ -371,7 +377,9 @@ sealed abstract class MultiSigSigner extends Signer[MultiSignatureInputInfo] { relevantInfo(spendingInfo, unsignedTx) val keysAndSigs = spendingInfo.toSingles.map { spendingInfoSingle => - signSingle(spendingInfoSingle, unsignedTx) + signSingle(spendingInfoSingle, + unsignedTx, + spendingInfoSingle.signer.signLowRWithHashType) } val signatures = keysAndSigs.map(_.signature) diff --git a/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputSigningInfo.scala b/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputSigningInfo.scala index b8fb946021..025b27e2c8 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputSigningInfo.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputSigningInfo.scala @@ -68,7 +68,7 @@ case class ScriptSignatureParams[+InputType <: InputInfo]( def signer: Sign = { require( signers.length == 1, - "This method is for spending infos with a single signer, if you mean signers.head be explicit") + s"This method is for spending infos with a single signer, if you mean signers.head be explicit, signers=$signers") signers.head } diff --git a/db-commons/src/main/scala/org/bitcoins/db/DbCommonsColumnMappers.scala b/db-commons/src/main/scala/org/bitcoins/db/DbCommonsColumnMappers.scala index b8fe2409bf..2c40ffcb98 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/DbCommonsColumnMappers.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/DbCommonsColumnMappers.scala @@ -423,18 +423,32 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { ) } - implicit val partialSigMapper: BaseColumnType[PartialSignature] = { + implicit val partialSigMapper + : BaseColumnType[PartialSignature[DigitalSignature]] = { MappedColumnType - .base[PartialSignature, String](_.hex, PartialSignature.fromHex) + .base[PartialSignature[DigitalSignature], String]( + _.hex, + PartialSignature.fromHex) } - implicit val partialSigsMapper: BaseColumnType[Vector[PartialSignature]] = { + implicit val ecPartialSigMapper + : BaseColumnType[PartialSignature[ECDigitalSignature]] = { MappedColumnType - .base[Vector[PartialSignature], String]( + .base[PartialSignature[ECDigitalSignature], String]( + _.hex, + PartialSignature + .fromHex(_) + .asInstanceOf[PartialSignature[ECDigitalSignature]]) + } + + implicit val partialSigsMapper + : BaseColumnType[Vector[PartialSignature[DigitalSignature]]] = { + MappedColumnType + .base[Vector[PartialSignature[DigitalSignature]], String]( _.foldLeft("")(_ ++ _.hex), hex => if (hex.isEmpty) Vector.empty - else InputPSBTMap(hex ++ "00").partialSignatures + else InputPSBTMap(hex ++ "00").partialSignatures[DigitalSignature] ) } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala index da09aa6e52..6ca3b9ce6d 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala @@ -31,6 +31,7 @@ import org.bitcoins.core.wallet.utxo.{ } import org.bitcoins.crypto.{ DoubleSha256DigestBE, + ECDigitalSignature, SchnorrDigitalSignature, Sha256Digest } @@ -396,7 +397,7 @@ case class DLCTransactionProcessing( private def buildSignMessage( dlcDb: DLCDb, sigDbs: Vector[DLCCETSignaturesDb], - offerRefundSig: PartialSignature, + offerRefundSig: PartialSignature[ECDigitalSignature], fundingInputDbs: Vector[DLCFundingInputDb] ): DLCSign = { { diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDb.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDb.scala index 38793c1695..813a398167 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDb.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDb.scala @@ -28,7 +28,7 @@ case class DLCAcceptDb( tempContractId: Sha256Digest, fundingInputs: Vector[DLCFundingInput], outcomeSigs: Vector[(ECPublicKey, ECAdaptorSignature)], - refundSig: PartialSignature + refundSig: PartialSignature[ECDigitalSignature] ): DLCAccept = { val pubKeys = DLCPublicKeys(fundingKey, payoutAddress) diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDAO.scala index 47a1ebd70c..f9c9e87052 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDAO.scala @@ -2,7 +2,7 @@ package org.bitcoins.dlc.wallet.models import org.bitcoins.core.api.dlc.wallet.db.DLCDb import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature -import org.bitcoins.crypto.Sha256Digest +import org.bitcoins.crypto.{ECDigitalSignature, Sha256Digest} import org.bitcoins.db.{CRUD, SlickUtil} import org.bitcoins.dlc.wallet.DLCAppConfig import slick.lifted.{ForeignKeyQuery, ProvenShape} @@ -71,9 +71,11 @@ case class DLCRefundSigsDAO()(implicit def dlcId: Rep[Sha256Digest] = column("dlc_id", O.PrimaryKey) - def accepterSig: Rep[PartialSignature] = column("accepter_sig") + def accepterSig: Rep[PartialSignature[ECDigitalSignature]] = column( + "accepter_sig") - def initiatorSig: Rep[Option[PartialSignature]] = column("initiator_sig") + def initiatorSig: Rep[Option[PartialSignature[ECDigitalSignature]]] = + column("initiator_sig") def * : ProvenShape[DLCRefundSigsDb] = (dlcId, accepterSig, initiatorSig).<>( diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDb.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDb.scala index bbd581f5b2..04fd7c6ea4 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDb.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDb.scala @@ -1,10 +1,10 @@ package org.bitcoins.dlc.wallet.models import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature -import org.bitcoins.crypto.Sha256Digest +import org.bitcoins.crypto.{ECDigitalSignature, Sha256Digest} case class DLCRefundSigsDb( dlcId: Sha256Digest, - accepterSig: PartialSignature, - initiatorSig: Option[PartialSignature] + accepterSig: PartialSignature[ECDigitalSignature], + initiatorSig: Option[PartialSignature[ECDigitalSignature]] ) diff --git a/docs/core/adding-spks.md b/docs/core/adding-spks.md index 006e5320b6..90332d9ad2 100644 --- a/docs/core/adding-spks.md +++ b/docs/core/adding-spks.md @@ -126,7 +126,7 @@ sealed abstract class Signer[-InputType <: InputInfo] { def signSingle( spendingInfo: UTXOSigningInfo[InputInfo], unsignedTx: Transaction)( - implicit ec: ExecutionContext): Future[PartialSignature] = ??? + implicit ec: ExecutionContext): Future[PartialSignature[ECDigitalSignature]] = ??? } sealed abstract class RawSingleKeyBitcoinSigner[-InputType <: RawInputInfo] extends Signer[InputType] { @@ -180,7 +180,7 @@ object BitcoinSigner { def signSingle( spendingInfo: UTXOSigningInfo[InputInfo], unsignedTx: Transaction)( - implicit ec: ExecutionContext): Future[PartialSignature] = ??? + implicit ec: ExecutionContext): Future[PartialSignature[ECDigitalSignature]] = ??? } def asm: Seq[ScriptToken] = ??? diff --git a/docs/core/psbts.md b/docs/core/psbts.md index b745c91ed3..785a06eb47 100644 --- a/docs/core/psbts.md +++ b/docs/core/psbts.md @@ -127,7 +127,8 @@ val spendingInfoSingle = ECSignatureParams( // Then we can sign the transaction val signature = BitcoinSigner.signSingle( spendingInfo = spendingInfoSingle, - unsignedTx = unsignedTransaction) + unsignedTx = unsignedTransaction, + privKey0.signLowRWithHashType) // We can then add the signature to the PSBT // Note: this signature could be produced by us or another party diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTest.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTest.scala index 8341c98517..c201c67a78 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTest.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTest.scala @@ -699,22 +699,27 @@ trait DLCTest { publishTransaction: Transaction => Future[?] )(implicit ec: ExecutionContext): Future[(SetupDLC, SetupDLC)] = { val offerSigReceiveP = { - Promise[(CETSignatures, PartialSignature)]() + Promise[(CETSignatures, PartialSignature[ECDigitalSignature])]() } - val sendAcceptSigs: (CETSignatures, PartialSignature) => Future[Unit] = { - case (cetSigs: CETSignatures, refundSig: PartialSignature) => + val sendAcceptSigs: ( + CETSignatures, + PartialSignature[ECDigitalSignature]) => Future[Unit] = { + case (cetSigs: CETSignatures, + refundSig: PartialSignature[ECDigitalSignature]) => val _ = offerSigReceiveP.success((cetSigs, refundSig)) FutureUtil.unit } val acceptSigReceiveP = { - Promise[(CETSignatures, PartialSignature, FundingSignatures)]() + Promise[(CETSignatures, + PartialSignature[ECDigitalSignature], + FundingSignatures)]() } val sendOfferSigs = { ( cetSigs: CETSignatures, - refundSig: PartialSignature, + refundSig: PartialSignature[ECDigitalSignature], fundingSigs: FundingSignatures ) => val _ = acceptSigReceiveP.success((cetSigs, refundSig, fundingSigs)) diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/TestDLCClient.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/TestDLCClient.scala index e52c57a1b1..b8822af89f 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/TestDLCClient.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/TestDLCClient.scala @@ -74,8 +74,12 @@ case class TestDLCClient( * from them */ def setupDLCAccept( - sendSigs: (CETSignatures, PartialSignature) => Future[Unit], - getSigs: Future[(CETSignatures, PartialSignature, FundingSignatures)] + sendSigs: ( + CETSignatures, + PartialSignature[ECDigitalSignature]) => Future[Unit], + getSigs: Future[(CETSignatures, + PartialSignature[ECDigitalSignature], + FundingSignatures)] ): Future[SetupDLC] = { require(!isInitiator, "You should call setupDLCOffer") @@ -98,10 +102,10 @@ case class TestDLCClient( * signed funding transaction */ def setupDLCOffer( - getSigs: Future[(CETSignatures, PartialSignature)], + getSigs: Future[(CETSignatures, PartialSignature[ECDigitalSignature])], sendSigs: ( CETSignatures, - PartialSignature, + PartialSignature[ECDigitalSignature], FundingSignatures ) => Future[Unit], getFundingTx: Future[Transaction] diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/PSBTGenerators.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/PSBTGenerators.scala index 7e695f6509..9ed5988701 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/PSBTGenerators.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/PSBTGenerators.scala @@ -148,7 +148,7 @@ object PSBTGenerators { val newInputsMaps = psbt.inputMaps.map { map => InputPSBTMap( map.elements.filterNot(element => - PSBTInputKeyId.fromBytes(element.key) == PartialSignatureKeyId) + PSBTInputKeyId.fromBytes(element.key) == PartialSignatureKeyId()) ) } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BytesUtil.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BytesUtil.scala index f6c1373c4c..cebd5e69cc 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BytesUtil.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BytesUtil.scala @@ -23,7 +23,8 @@ object BytesUtil { ECDigitalSignature(flipAtIndex(signature.bytes, 60)) } - def flipBit(partialSignature: PartialSignature): PartialSignature = { + def flipBit(partialSignature: PartialSignature[ECDigitalSignature]) + : PartialSignature[ECDigitalSignature] = { partialSignature.copy(signature = flipBit(partialSignature.signature)) } @@ -63,8 +64,8 @@ object BytesUtil { def flipBit( cetSigs: CETSignatures, - refundSig: PartialSignature - ): (CETSignatures, PartialSignature) = { + refundSig: PartialSignature[ECDigitalSignature] + ): (CETSignatures, PartialSignature[ECDigitalSignature]) = { val badOutcomeSigs = cetSigs.outcomeSigs.map { case (outcome, sig) => outcome -> flipBit(sig) } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/BytesUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/BytesUtil.scala index a9abd2a5ef..a4fb3a59d9 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/BytesUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/BytesUtil.scala @@ -8,7 +8,12 @@ import org.bitcoins.core.protocol.script.{ ScriptWitnessV0 } import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature -import org.bitcoins.crypto.{ECAdaptorSignature, ECDigitalSignature} +import org.bitcoins.crypto.{ + DigitalSignature, + ECAdaptorSignature, + ECDigitalSignature, + SchnorrDigitalSignature +} import scodec.bits.ByteVector object BytesUtil { @@ -23,8 +28,19 @@ object BytesUtil { ECDigitalSignature(flipAtIndex(signature.bytes, 60)) } - def flipBit(partialSignature: PartialSignature): PartialSignature = { - partialSignature.copy(signature = flipBit(partialSignature.signature)) + def flipBit(signature: SchnorrDigitalSignature): SchnorrDigitalSignature = { + SchnorrDigitalSignature(flipAtIndex(signature.bytes, 60)) + } + + def flipBit[Sig <: DigitalSignature]( + partialSignature: PartialSignature[Sig]): PartialSignature[Sig] = { + val s = partialSignature.signature match { + case e: ECDigitalSignature => flipBit(e).asInstanceOf[Sig] + case s: SchnorrDigitalSignature => flipBit(s).asInstanceOf[Sig] + case d: DigitalSignature => + sys.error(s"Cannot flip bit on unknown digital signature type=$d") + } + partialSignature.copy(signature = s) } def flipBit(adaptorSignature: ECAdaptorSignature): ECAdaptorSignature = { @@ -63,8 +79,8 @@ object BytesUtil { def flipBit( cetSigs: CETSignatures, - refundSig: PartialSignature - ): (CETSignatures, PartialSignature) = { + refundSig: PartialSignature[ECDigitalSignature] + ): (CETSignatures, PartialSignature[ECDigitalSignature]) = { val badOutcomeSigs = cetSigs.outcomeSigs.map { case (outcome, sig) => outcome -> flipBit(sig) } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala index ec98125518..ac2ba93d61 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala @@ -182,10 +182,10 @@ object DLCWalletUtil extends BitcoinSLogger { lazy val dummyKey2: ECPublicKey = ECPublicKey.freshPublicKey - lazy val dummyPartialSig: PartialSignature = + lazy val dummyPartialSig: PartialSignature[ECDigitalSignature] = PartialSignature(dummyKey, ECDigitalSignature.dummy) - lazy val minimalPartialSig: PartialSignature = { + lazy val minimalPartialSig: PartialSignature[ECDigitalSignature] = { PartialSignature(dummyKey, ECDigitalSignature.minimalEncodedZeroSig) } diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala index 343ab04668..2e640173a8 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala @@ -6,13 +6,13 @@ import org.bitcoins.core.api.wallet.db.{AddressDb, TransactionDbHelper} import org.bitcoins.core.hd.HDChainType.{Change, External} import org.bitcoins.core.hd.{AddressType, HDAccount, HDChainType} import org.bitcoins.core.protocol.BitcoinAddress -import org.bitcoins.core.protocol.script._ +import org.bitcoins.core.protocol.script.* import org.bitcoins.core.util.FutureUtil -import org.bitcoins.crypto.{CryptoUtil, ECPublicKey} +import org.bitcoins.crypto.{CryptoUtil, ECDigitalSignature, ECPublicKey} import org.bitcoins.keymanager.{DecryptedMnemonic, WalletStorage} import org.bitcoins.testkit.chain.MockChainQueryApi import org.bitcoins.testkit.wallet.BitcoinSWalletTest -import org.bitcoins.testkitcore.util.TransactionTestUtil._ +import org.bitcoins.testkitcore.util.TransactionTestUtil.* import org.scalatest.FutureOutcome import org.scalatest.compatible.Assertion @@ -238,7 +238,8 @@ class WalletUnitTest extends BitcoinSWalletTest { } yield { assert(signed != psbt) assert( - signed.inputMaps.head.partialSignatures + signed.inputMaps.head + .partialSignatures[ECDigitalSignature] .exists(_.pubKey.toPublicKey == walletKey) ) } @@ -264,7 +265,8 @@ class WalletUnitTest extends BitcoinSWalletTest { } yield { assert(signed != psbt) assert( - signed.inputMaps.head.partialSignatures + signed.inputMaps.head + .partialSignatures[ECDigitalSignature] .exists(_.pubKey.toPublicKey == walletKey) ) } @@ -290,7 +292,8 @@ class WalletUnitTest extends BitcoinSWalletTest { } yield { assert(signed != psbt) assert( - signed.inputMaps.head.partialSignatures + signed.inputMaps.head + .partialSignatures[ECDigitalSignature] .exists(_.pubKey.toPublicKey == walletKey) ) } @@ -317,7 +320,8 @@ class WalletUnitTest extends BitcoinSWalletTest { } yield { assert(signed != psbt) assert( - signed.inputMaps.head.partialSignatures + signed.inputMaps.head + .partialSignatures[ECDigitalSignature] .exists(_.pubKey.toPublicKey == walletKey) ) } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/SendFundsHandlingHandling.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/SendFundsHandlingHandling.scala index 7a173ef5f2..af126f8cb9 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/SendFundsHandlingHandling.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/SendFundsHandlingHandling.scala @@ -47,7 +47,7 @@ import org.bitcoins.core.wallet.fee.{ SatoshisPerVirtualByte } import org.bitcoins.core.wallet.utxo.{AddressTag, TxoState} -import org.bitcoins.crypto.{CryptoUtil, DoubleSha256DigestBE} +import org.bitcoins.crypto.{CryptoUtil, DigitalSignature, DoubleSha256DigestBE} import org.bitcoins.wallet.config.WalletAppConfig import org.bitcoins.wallet.models.{ AccountDAO, @@ -560,11 +560,12 @@ case class SendFundsHandlingHandling( keyPaths.foldLeft(withData) { (accum, hdPath) => val sign = keyManager.toSign(hdPath) // Only sign if that key doesn't have a signature yet - if ( - !input.partialSignatures.exists( + val sigExists = input + .partialSignatures[DigitalSignature] + .exists( _.pubKey.toPublicKey == sign.publicKey ) - ) { + if (!sigExists) { logger.debug( s"Signing input $index with key ${sign.publicKey.hex}" )