2024 11 15 partialsig typeparam (#5770)

* Add DigitalSignature type param to PartialSignature

* Remove isDummySignature
This commit is contained in:
Chris Stewart 2024-11-18 09:15:33 -06:00 committed by GitHub
parent bb0e40f05b
commit 80be2f5989
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 298 additions and 213 deletions

View File

@ -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)

View File

@ -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]

View File

@ -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)),

View File

@ -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]] =

View File

@ -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
}

View File

@ -554,7 +554,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
privKey,
HashType.sigHashAll
),
transaction
transaction,
privKey.signLowRWithHashType
)
signedTx match {

View File

@ -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 = {

View File

@ -129,7 +129,7 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest {
TransactionSignatureCreator.createSig(
transaction,
signingInfo,
privateKey,
privateKey.signLowRWithHashType,
HashType.sigHashAll
)
txSignature.r must be(expectedSig.r)

View File

@ -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 {

View File

@ -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)
}
}

View File

@ -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

View File

@ -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,

View File

@ -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)

View File

@ -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 {

View File

@ -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 = {

View File

@ -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

View File

@ -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)
}
}

View File

@ -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,

View File

@ -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 {

View File

@ -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 =>
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,
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]

View File

@ -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)
if (value.length == 64 || value.length == 65) {
val sig = SchnorrDigitalSignature(value)
PartialSignature(pubKey.toPublicKeyBytes(), sig)
} else {
val sig = ECDigitalSignature(value)
PartialSignature(pubKey, sig)
PartialSignature(pubKey.toPublicKeyBytes(), sig)
}
case SigHashTypeKeyId =>
require(key.size == 1,
s"The key must only contain the 1 byte type, got: ${key.size}")

View File

@ -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
val partialSigs = psbt
.inputMaps(inputIndex)
.partialSignatures
.exists(_.pubKey.toPublicKey == signer.publicKey)
) {
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)

View File

@ -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
}

View File

@ -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]
)
}

View File

@ -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 = {
{

View File

@ -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)

View File

@ -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).<>(

View File

@ -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]]
)

View File

@ -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] = ???

View File

@ -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

View File

@ -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))

View File

@ -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]

View File

@ -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())
)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
)
}

View File

@ -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}"
)