mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 01:40:55 +01:00
2024 11 15 partialsig typeparam (#5770)
* Add DigitalSignature type param to PartialSignature * Remove isDummySignature
This commit is contained in:
parent
bb0e40f05b
commit
80be2f5989
@ -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)
|
||||
|
@ -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]
|
||||
|
@ -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)),
|
||||
|
@ -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]] =
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -554,7 +554,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
||||
privKey,
|
||||
HashType.sigHashAll
|
||||
),
|
||||
transaction
|
||||
transaction,
|
||||
privKey.signLowRWithHashType
|
||||
)
|
||||
|
||||
signedTx match {
|
||||
|
@ -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 = {
|
||||
|
@ -129,7 +129,7 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest {
|
||||
TransactionSignatureCreator.createSig(
|
||||
transaction,
|
||||
signingInfo,
|
||||
privateKey,
|
||||
privateKey.signLowRWithHashType,
|
||||
HashType.sigHashAll
|
||||
)
|
||||
txSignature.r must be(expectedSig.r)
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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]
|
||||
|
@ -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}")
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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]
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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 = {
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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).<>(
|
||||
|
@ -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]]
|
||||
)
|
||||
|
@ -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] = ???
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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]
|
||||
|
@ -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())
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
)
|
||||
}
|
||||
|
@ -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}"
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user