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