mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-18 21:34:39 +01:00
2024 11 16 rm isdummysig (#5771)
* WIP: Remove isDummySignature * Add ECDigitalSignature.LOW_R_SIZE, use it in ECDigitalSignature.dummyLowR * Regenerated dlc_test.json and dlc_tx_test.json to add hash type to dummy ecdsa signatures in static test vectors * Regenerated dlc_test.json and dlc_tx_test.json to add hash type to dummy ecdsa signatures in static test vectors * Fix InputInfoTest maxWitnessLengths checks to be >= * Fix docs
This commit is contained in:
parent
fc4802d4b0
commit
bb0e40f05b
@ -554,8 +554,7 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
||||
privKey,
|
||||
HashType.sigHashAll
|
||||
),
|
||||
transaction,
|
||||
isDummySignature = false
|
||||
transaction
|
||||
)
|
||||
|
||||
signedTx match {
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -341,16 +341,17 @@ class RawTxSignerTest extends BitcoinSUnitTest {
|
||||
forAll(CreditingTxGen.inputsAndOutputs(), ScriptGenerators.scriptPubKey) {
|
||||
case ((creditingTxsInfo, destinations), (changeSPK, _)) =>
|
||||
val fee = SatoshisPerVirtualByte(Satoshis(1000))
|
||||
|
||||
val hashType = HashType.sigHashAll
|
||||
val dummySpendingInfos = creditingTxsInfo.map { spendingInfo =>
|
||||
val inputInfo = spendingInfo.inputInfo
|
||||
|
||||
val mockSigners =
|
||||
inputInfo.pubKeys.take(inputInfo.requiredSigs).map(Sign.dummySign)
|
||||
|
||||
inputInfo.toSpendingInfo(
|
||||
EmptyTransaction,
|
||||
mockSigners,
|
||||
HashType.sigHashAll
|
||||
hashType
|
||||
)
|
||||
}
|
||||
|
||||
@ -364,10 +365,11 @@ class RawTxSignerTest extends BitcoinSUnitTest {
|
||||
val tx = RawTxSigner.sign(
|
||||
utx,
|
||||
dummySpendingInfos.toVector,
|
||||
RawTxSigner.emptyInvariant,
|
||||
dummySign = true
|
||||
RawTxSigner.emptyInvariant
|
||||
)
|
||||
|
||||
val dummyLowRHashType =
|
||||
ECDigitalSignature.dummyLowR.appendHashType(hashType)
|
||||
// Can't use BitcoinScriptUtil.verifyScript because it will pass for things
|
||||
// with EmptyScriptPubKeys or Multisig with 0 required sigs
|
||||
tx match {
|
||||
@ -377,17 +379,18 @@ class RawTxSignerTest extends BitcoinSUnitTest {
|
||||
assert(
|
||||
btx.inputs.forall(
|
||||
_.scriptSignature.signatures.forall(
|
||||
_ == ECDigitalSignature.dummyLowR
|
||||
_ == dummyLowRHashType
|
||||
)
|
||||
)
|
||||
),
|
||||
s"btx.inputs.scriptSigs=${btx.inputs.map(_.scriptSignature)}"
|
||||
)
|
||||
case wtx: WitnessTransaction =>
|
||||
assert(
|
||||
wtx.witness.witnesses.forall {
|
||||
case p2wsh: P2WSHWitnessV0 =>
|
||||
p2wsh.signatures.forall(_ == ECDigitalSignature.dummyLowR)
|
||||
p2wsh.signatures.forall(_ == dummyLowRHashType)
|
||||
case p2wpkh: P2WPKHWitnessV0 =>
|
||||
p2wpkh.signature == ECDigitalSignature.dummyLowR
|
||||
p2wpkh.signature == dummyLowRHashType
|
||||
case EmptyScriptWitness =>
|
||||
true
|
||||
|
||||
|
@ -53,7 +53,7 @@ class SignerTest extends BitcoinSUnitTest {
|
||||
p2wpkh.hashType
|
||||
)
|
||||
assertThrows[UnsupportedOperationException](
|
||||
BitcoinSigner.sign(spendingInfo, tx, isDummySignature = false)
|
||||
BitcoinSigner.sign(spendingInfo, tx)
|
||||
)
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ class SignerTest extends BitcoinSUnitTest {
|
||||
val p2sh = GenUtil.sample(CreditingTxGen.p2shOutput)
|
||||
val tx = GenUtil.sample(TransactionGenerators.baseTransaction)
|
||||
assertThrows[IllegalArgumentException](
|
||||
BitcoinSigner.sign(p2sh, tx, isDummySignature = false)
|
||||
BitcoinSigner.sign(p2sh, tx)
|
||||
)
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ class SignerTest extends BitcoinSUnitTest {
|
||||
.asInstanceOf[ScriptSignatureParams[P2WPKHV0InputInfo]]
|
||||
val tx = GenUtil.sample(TransactionGenerators.baseTransaction)
|
||||
assertThrows[IllegalArgumentException] {
|
||||
P2WPKHSigner.sign(dumbSpendingInfo, tx, isDummySignature = false, p2wpkh)
|
||||
P2WPKHSigner.sign(dumbSpendingInfo, tx, p2wpkh)
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ class SignerTest extends BitcoinSUnitTest {
|
||||
.asInstanceOf[ScriptSignatureParams[P2WSHV0InputInfo]]
|
||||
val tx = GenUtil.sample(TransactionGenerators.baseTransaction)
|
||||
assertThrows[IllegalArgumentException] {
|
||||
P2WSHSigner.sign(dumbSpendingInfo, tx, isDummySignature = false, p2wsh)
|
||||
P2WSHSigner.sign(dumbSpendingInfo, tx, p2wsh)
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,20 +99,18 @@ class SignerTest extends BitcoinSUnitTest {
|
||||
fee,
|
||||
changeSPK
|
||||
)
|
||||
|
||||
val signedTx =
|
||||
RawTxSigner.sign(unsignedTx, creditingTxsInfos.toVector, fee)
|
||||
|
||||
val singleSigs: Vector[Vector[ECDigitalSignature]] = {
|
||||
val singleInfosVec: Vector[Vector[ECSignatureParams[InputInfo]]] =
|
||||
val singleInfosVec: Vector[Vector[ECSignatureParams[InputInfo]]] = {
|
||||
creditingTxsInfos.toVector.map(_.toSingles)
|
||||
}
|
||||
singleInfosVec.map { singleInfos =>
|
||||
singleInfos.map { singleInfo =>
|
||||
val keyAndSig =
|
||||
BitcoinSigner.signSingle(
|
||||
singleInfo,
|
||||
unsignedTx,
|
||||
isDummySignature = false
|
||||
unsignedTx
|
||||
)
|
||||
|
||||
keyAndSig.signature
|
||||
@ -144,7 +142,6 @@ class SignerTest extends BitcoinSUnitTest {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
assert(sigs.length == expectedSigs.length)
|
||||
assert(sigs.forall(expectedSigs.contains))
|
||||
}
|
||||
@ -251,7 +248,7 @@ class SignerTest extends BitcoinSUnitTest {
|
||||
unsignedTx.lockTime,
|
||||
EmptyWitness.fromInputs(unsignedTx.inputs)
|
||||
)
|
||||
BitcoinSigner.signSingle(singleInfo, wtx, isDummySignature = false)
|
||||
BitcoinSigner.signSingle(singleInfo, wtx)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -233,13 +233,13 @@ class InputInfoTest extends BitcoinSUnitTest {
|
||||
)
|
||||
|
||||
val maxWitnessLen = BitcoinSigner
|
||||
.sign(scriptSigParams, unsignedTx = dummyTx, isDummySignature = true)
|
||||
.sign(scriptSigParams, unsignedTx = dummyTx)
|
||||
.transaction match {
|
||||
case wtx: WitnessTransaction => wtx.witness.head.byteSize.toInt
|
||||
case _: NonWitnessTransaction => 0
|
||||
}
|
||||
|
||||
assert(scriptSigParams.maxWitnessLen == maxWitnessLen)
|
||||
assert(scriptSigParams.maxWitnessLen >= maxWitnessLen)
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,7 +259,7 @@ class InputInfoTest extends BitcoinSUnitTest {
|
||||
)
|
||||
|
||||
val maxScriptSig = BitcoinSigner
|
||||
.sign(scriptSigParams, unsignedTx = dummyTx, isDummySignature = true)
|
||||
.sign(scriptSigParams, unsignedTx = dummyTx)
|
||||
.transaction
|
||||
.inputs
|
||||
.head
|
||||
@ -268,7 +268,7 @@ class InputInfoTest extends BitcoinSUnitTest {
|
||||
assert(
|
||||
InputInfo.maxScriptSigLen(
|
||||
scriptSigParams.inputInfo
|
||||
) == maxScriptSig.byteSize,
|
||||
) >= maxScriptSig.byteSize,
|
||||
maxScriptSig.hex
|
||||
)
|
||||
}
|
||||
|
@ -460,7 +460,7 @@ object DLCTxSigner {
|
||||
case (sigsT, SpendingInfoWithSerialId(utxo, _)) =>
|
||||
sigsT.flatMap { sigs =>
|
||||
val sigComponent =
|
||||
BitcoinSigner.sign(utxo, fundingTx, isDummySignature = false)
|
||||
BitcoinSigner.sign(utxo, fundingTx)
|
||||
val witnessT =
|
||||
sigComponent.transaction match {
|
||||
case wtx: WitnessTransaction =>
|
||||
|
@ -152,10 +152,7 @@ object TxUtil {
|
||||
|
||||
val utx = withFinalizer.buildTx()
|
||||
|
||||
RawTxSigner.sign(utx,
|
||||
dummySpendingInfos,
|
||||
RawTxSigner.emptyInvariant,
|
||||
dummySign = true)
|
||||
RawTxSigner.sign(utx, dummySpendingInfos, RawTxSigner.emptyInvariant)
|
||||
}
|
||||
|
||||
/** Inserts script signatures and (potentially) witness data to a given
|
||||
@ -183,7 +180,7 @@ object TxUtil {
|
||||
|
||||
val tx =
|
||||
BitcoinSigner
|
||||
.sign(mockSpendingInfo, utx, isDummySignature = true)
|
||||
.sign(mockSpendingInfo, utx)
|
||||
.transaction
|
||||
|
||||
val witnessOpt = tx match {
|
||||
|
@ -221,16 +221,12 @@ case class PSBT(
|
||||
* Function or private key used to sign the PSBT
|
||||
* @param conditionalPath
|
||||
* Represents the spending branch being taken in a ScriptPubKey's execution
|
||||
* @param isDummySignature
|
||||
* Do not sign the tx for real, just use a dummy signature, this is useful
|
||||
* for fee estimation
|
||||
* @return
|
||||
*/
|
||||
def sign(
|
||||
inputIndex: Int,
|
||||
signer: Sign,
|
||||
conditionalPath: ConditionalPath = ConditionalPath.NoCondition,
|
||||
isDummySignature: Boolean = false): PSBT = {
|
||||
conditionalPath: ConditionalPath = ConditionalPath.NoCondition): PSBT = {
|
||||
require(
|
||||
inputMaps.size == 1 || !inputMaps(inputIndex).isBIP143Vulnerable,
|
||||
"This input map is susceptible to the BIP 143 vulnerability, add the non-witness utxo to be safe"
|
||||
@ -239,8 +235,7 @@ case class PSBT(
|
||||
BitcoinSigner.sign(psbt = this,
|
||||
inputIndex = inputIndex,
|
||||
signer = signer,
|
||||
conditionalPath = conditionalPath,
|
||||
isDummySignature = isDummySignature)
|
||||
conditionalPath = conditionalPath)
|
||||
}
|
||||
|
||||
/** Takes the InputPSBTMap at the given index and returns a
|
||||
|
@ -905,7 +905,7 @@ object InputPSBTMap extends PSBTMapFactory[InputPSBTRecord, InputPSBTMap] {
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction): InputPSBTMap = {
|
||||
val sigComponent = BitcoinSigner
|
||||
.sign(spendingInfo, unsignedTx, isDummySignature = false)
|
||||
.sign(spendingInfo, unsignedTx)
|
||||
|
||||
val utxos = spendingInfo.inputInfo match {
|
||||
case _: UnassignedSegwitNativeInputInfo =>
|
||||
@ -941,9 +941,7 @@ object InputPSBTMap extends PSBTMapFactory[InputPSBTRecord, InputPSBTMap] {
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction): InputPSBTMap = {
|
||||
val sigs = spendingInfo.toSingles.map { spendingInfoSingle =>
|
||||
BitcoinSigner.signSingle(spendingInfoSingle,
|
||||
unsignedTx,
|
||||
isDummySignature = false)
|
||||
BitcoinSigner.signSingle(spendingInfoSingle, unsignedTx)
|
||||
}
|
||||
|
||||
val builder = Vector.newBuilder[InputPSBTRecord]
|
||||
|
@ -50,7 +50,7 @@ object RawTxSigner {
|
||||
def sign(
|
||||
utx: Transaction,
|
||||
utxoInfos: Vector[ScriptSignatureParams[InputInfo]]): Transaction = {
|
||||
sign(utx, utxoInfos, emptyInvariant, dummySign = false)
|
||||
sign(utx, utxoInfos, emptyInvariant)
|
||||
}
|
||||
|
||||
def sign(
|
||||
@ -66,7 +66,7 @@ object RawTxSigner {
|
||||
|
||||
val invariants = feeInvariant(expectedFeeRate)
|
||||
|
||||
sign(utx, utxoInfos, invariants, dummySign = false)
|
||||
sign(utx, utxoInfos, invariants)
|
||||
}
|
||||
|
||||
def sign(
|
||||
@ -79,7 +79,7 @@ object RawTxSigner {
|
||||
|
||||
val invariants = addFeeRateInvariant(expectedFeeRate, userInvariants)
|
||||
|
||||
sign(utx, utxoInfos, invariants, dummySign = false)
|
||||
sign(utx, utxoInfos, invariants)
|
||||
}
|
||||
|
||||
def sign(
|
||||
@ -91,10 +91,7 @@ object RawTxSigner {
|
||||
|
||||
val invariants = addFeeRateInvariant(expectedFeeRate, userInvariants)
|
||||
|
||||
sign(txWithInfo.finalizedTx,
|
||||
txWithInfo.infos,
|
||||
invariants,
|
||||
dummySign = false)
|
||||
sign(txWithInfo.finalizedTx, txWithInfo.infos, invariants)
|
||||
}
|
||||
|
||||
def sign(
|
||||
@ -102,8 +99,7 @@ object RawTxSigner {
|
||||
utxoInfos: Vector[ScriptSignatureParams[InputInfo]],
|
||||
invariants: (
|
||||
Vector[ScriptSignatureParams[InputInfo]],
|
||||
Transaction) => Boolean,
|
||||
dummySign: Boolean): Transaction = {
|
||||
Transaction) => Boolean): Transaction = {
|
||||
require(
|
||||
utxoInfos.length == utx.inputs.length,
|
||||
s"Must provide exactly one UTXOSatisfyingInfo per input, ${utxoInfos.length} != ${utx.inputs.length}")
|
||||
@ -126,7 +122,7 @@ object RawTxSigner {
|
||||
|
||||
val inputsAndWitnesses = utxoInfos.map { utxo =>
|
||||
val txSigComp =
|
||||
BitcoinSigner.sign(utxo, utx, isDummySignature = dummySign)
|
||||
BitcoinSigner.sign(utxo, utx)
|
||||
val scriptWitnessOpt = TxSigComponent.getScriptWitness(txSigComp)
|
||||
|
||||
(txSigComp.input, scriptWitnessOpt)
|
||||
|
@ -19,22 +19,16 @@ sealed abstract class SignerUtils {
|
||||
unsignedTx: Transaction,
|
||||
signingInfo: InputSigningInfo[InputInfo],
|
||||
sign: (ByteVector, HashType) => ECDigitalSignature,
|
||||
hashType: HashType,
|
||||
isDummySignature: Boolean): ECDigitalSignature = {
|
||||
if (isDummySignature) {
|
||||
ECDigitalSignature.dummyLowR
|
||||
} else {
|
||||
TransactionSignatureCreator.createSig(unsignedTx,
|
||||
signingInfo,
|
||||
sign,
|
||||
hashType)
|
||||
}
|
||||
hashType: HashType): ECDigitalSignature = {
|
||||
TransactionSignatureCreator.createSig(unsignedTx,
|
||||
signingInfo,
|
||||
sign,
|
||||
hashType)
|
||||
}
|
||||
|
||||
def signSingle(
|
||||
spendingInfo: ECSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean): PartialSignature = {
|
||||
unsignedTx: Transaction): PartialSignature = {
|
||||
|
||||
val tx = spendingInfo.inputInfo match {
|
||||
case _: SegwitV0NativeInputInfo | _: P2SHNestedSegwitV0InputInfo |
|
||||
@ -48,8 +42,7 @@ sealed abstract class SignerUtils {
|
||||
unsignedTx = tx,
|
||||
signingInfo = spendingInfo,
|
||||
sign = spendingInfo.signer.signLowRWithHashType,
|
||||
hashType = spendingInfo.hashType,
|
||||
isDummySignature = isDummySignature
|
||||
hashType = spendingInfo.hashType
|
||||
)
|
||||
|
||||
PartialSignature(spendingInfo.signer.publicKey, signature)
|
||||
@ -90,19 +83,14 @@ sealed abstract class Signer[-InputType <: InputInfo] extends SignerUtils {
|
||||
* \- The information required for signing
|
||||
* @param unsignedTx
|
||||
* the external Transaction that needs an input signed
|
||||
* @param isDummySignature
|
||||
* \- do not sign the tx for real, just use a dummy signature this is
|
||||
* useful for fee estimation
|
||||
* @return
|
||||
*/
|
||||
def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputType],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean): TxSigComponent = {
|
||||
unsignedTx: Transaction): TxSigComponent = {
|
||||
sign(
|
||||
spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingInfoToSatisfy = spendingInfo
|
||||
)
|
||||
}
|
||||
@ -113,9 +101,6 @@ sealed abstract class Signer[-InputType <: InputInfo] extends SignerUtils {
|
||||
* \- The information required for signing
|
||||
* @param unsignedTx
|
||||
* the external Transaction that needs an input signed
|
||||
* @param isDummySignature
|
||||
* \- do not sign the tx for real, just use a dummy signature this is
|
||||
* useful for fee estimation
|
||||
* @param spendingInfoToSatisfy
|
||||
* \- specifies the NewSpendingInfo whose ScriptPubKey needs a
|
||||
* ScriptSignature to be generated
|
||||
@ -124,7 +109,6 @@ sealed abstract class Signer[-InputType <: InputInfo] extends SignerUtils {
|
||||
def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ScriptSignatureParams[InputType]): TxSigComponent
|
||||
|
||||
/** Creates a BaseTxSigComponent by replacing the unsignedTx input at
|
||||
@ -160,15 +144,13 @@ object BitcoinSigner extends SignerUtils {
|
||||
|
||||
def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean): TxSigComponent = {
|
||||
sign(spendingInfo, unsignedTx, isDummySignature, spendingInfo)
|
||||
unsignedTx: Transaction): TxSigComponent = {
|
||||
sign(spendingInfo, unsignedTx, spendingInfo)
|
||||
}
|
||||
|
||||
def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ScriptSignatureParams[InputInfo])
|
||||
: TxSigComponent = {
|
||||
def spendingFrom[Info <: InputInfo](
|
||||
@ -178,55 +160,29 @@ object BitcoinSigner extends SignerUtils {
|
||||
|
||||
spendingInfoToSatisfy.inputInfo match {
|
||||
case empty: EmptyInputInfo =>
|
||||
EmptySigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingFrom(empty))
|
||||
EmptySigner.sign(spendingInfo, unsignedTx, spendingFrom(empty))
|
||||
case p2pk: P2PKInputInfo =>
|
||||
P2PKSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingFrom(p2pk))
|
||||
P2PKSigner.sign(spendingInfo, unsignedTx, spendingFrom(p2pk))
|
||||
case p2pkh: P2PKHInputInfo =>
|
||||
P2PKHSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingFrom(p2pkh))
|
||||
P2PKHSigner.sign(spendingInfo, unsignedTx, spendingFrom(p2pkh))
|
||||
case p2pKWithTimeout: P2PKWithTimeoutInputInfo =>
|
||||
P2PKWithTimeoutSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingFrom(p2pKWithTimeout))
|
||||
case p2sh: P2SHInputInfo =>
|
||||
P2SHSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingFrom(p2sh))
|
||||
P2SHSigner.sign(spendingInfo, unsignedTx, spendingFrom(p2sh))
|
||||
case multiSig: MultiSignatureInputInfo =>
|
||||
MultiSigSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingFrom(multiSig))
|
||||
MultiSigSigner.sign(spendingInfo, unsignedTx, spendingFrom(multiSig))
|
||||
case lockTime: LockTimeInputInfo =>
|
||||
LockTimeSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingFrom(lockTime))
|
||||
LockTimeSigner.sign(spendingInfo, unsignedTx, spendingFrom(lockTime))
|
||||
case conditional: ConditionalInputInfo =>
|
||||
ConditionalSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingFrom(conditional))
|
||||
case p2wpkh: P2WPKHV0InputInfo =>
|
||||
P2WPKHSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingFrom(p2wpkh))
|
||||
P2WPKHSigner.sign(spendingInfo, unsignedTx, spendingFrom(p2wpkh))
|
||||
case pw2sh: P2WSHV0InputInfo =>
|
||||
P2WSHSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingFrom(pw2sh))
|
||||
P2WSHSigner.sign(spendingInfo, unsignedTx, spendingFrom(pw2sh))
|
||||
case _: UnassignedSegwitNativeInputInfo =>
|
||||
throw new UnsupportedOperationException("Unsupported Segwit version")
|
||||
}
|
||||
@ -240,9 +196,6 @@ object BitcoinSigner extends SignerUtils {
|
||||
* Index of input to sign
|
||||
* @param signer
|
||||
* Function or private key used to sign the PSBT
|
||||
* @param isDummySignature
|
||||
* Do not sign the tx for real, just use a dummy signature, this is useful
|
||||
* for fee estimation
|
||||
* @param conditionalPath
|
||||
* Represents the spending branch being taken in a ScriptPubKey's execution
|
||||
* @return
|
||||
@ -251,8 +204,7 @@ object BitcoinSigner extends SignerUtils {
|
||||
psbt: PSBT,
|
||||
inputIndex: Int,
|
||||
signer: Sign,
|
||||
conditionalPath: ConditionalPath = ConditionalPath.NoCondition,
|
||||
isDummySignature: Boolean = false): PSBT = {
|
||||
conditionalPath: ConditionalPath = ConditionalPath.NoCondition): PSBT = {
|
||||
// if already signed by this signer
|
||||
if (
|
||||
psbt
|
||||
@ -305,7 +257,7 @@ object BitcoinSigner extends SignerUtils {
|
||||
}
|
||||
|
||||
val partialSignature =
|
||||
signSingle(spendingInfo, txToSign, isDummySignature)
|
||||
signSingle(spendingInfo, txToSign)
|
||||
|
||||
psbt.addSignature(partialSignature, inputIndex)
|
||||
}
|
||||
@ -323,14 +275,13 @@ sealed abstract class RawSingleKeyBitcoinSigner[-InputType <: RawInputInfo]
|
||||
override def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ScriptSignatureParams[InputType])
|
||||
: TxSigComponent = {
|
||||
val (_, output, inputIndex, _) =
|
||||
relevantInfo(spendingInfo, unsignedTx)
|
||||
|
||||
val partialSignature =
|
||||
signSingle(spendingInfo.toSingle(0), unsignedTx, isDummySignature)
|
||||
signSingle(spendingInfo.toSingle(0), unsignedTx)
|
||||
|
||||
val scriptSig =
|
||||
keyAndSigToScriptSig(partialSignature.pubKey.toPublicKey,
|
||||
@ -352,7 +303,6 @@ sealed abstract class EmptySigner extends Signer[EmptyInputInfo] {
|
||||
override def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ScriptSignatureParams[EmptyInputInfo])
|
||||
: TxSigComponent = {
|
||||
val (_, output, inputIndex, _) = relevantInfo(spendingInfo, unsignedTx)
|
||||
@ -415,14 +365,13 @@ sealed abstract class MultiSigSigner extends Signer[MultiSignatureInputInfo] {
|
||||
override def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ScriptSignatureParams[MultiSignatureInputInfo])
|
||||
: TxSigComponent = {
|
||||
val (_, output, inputIndex, _) =
|
||||
relevantInfo(spendingInfo, unsignedTx)
|
||||
|
||||
val keysAndSigs = spendingInfo.toSingles.map { spendingInfoSingle =>
|
||||
signSingle(spendingInfoSingle, unsignedTx, isDummySignature)
|
||||
signSingle(spendingInfoSingle, unsignedTx)
|
||||
}
|
||||
|
||||
val signatures = keysAndSigs.map(_.signature)
|
||||
@ -444,7 +393,6 @@ sealed abstract class P2SHSigner extends Signer[P2SHInputInfo] {
|
||||
override def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ScriptSignatureParams[P2SHInputInfo])
|
||||
: TxSigComponent = {
|
||||
if (spendingInfoToSatisfy != spendingInfo) {
|
||||
@ -466,7 +414,7 @@ sealed abstract class P2SHSigner extends Signer[P2SHInputInfo] {
|
||||
|
||||
val signedTx =
|
||||
BitcoinSigner
|
||||
.sign(nestedSpendingInfo, updatedTx, isDummySignature)
|
||||
.sign(nestedSpendingInfo, updatedTx)
|
||||
.transaction
|
||||
|
||||
val i = signedTx.inputs(inputIndex.toInt)
|
||||
@ -509,7 +457,6 @@ sealed abstract class P2WPKHSigner extends Signer[P2WPKHV0InputInfo] {
|
||||
override def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ScriptSignatureParams[P2WPKHV0InputInfo])
|
||||
: TxSigComponent = {
|
||||
if (spendingInfoToSatisfy != spendingInfo) {
|
||||
@ -551,8 +498,7 @@ sealed abstract class P2WPKHSigner extends Signer[P2WPKHV0InputInfo] {
|
||||
doSign(unsignedTx,
|
||||
spendingInfo,
|
||||
signer.signLowRWithHashType,
|
||||
hashType,
|
||||
isDummySignature)
|
||||
hashType)
|
||||
|
||||
val scriptWitness = P2WPKHWitnessV0(pubKey, signature)
|
||||
val signedTxWitness =
|
||||
@ -567,7 +513,7 @@ sealed abstract class P2WPKHSigner extends Signer[P2WPKHV0InputInfo] {
|
||||
case btx: NonWitnessTransaction =>
|
||||
val wtx = WitnessTransaction.toWitnessTx(btx)
|
||||
|
||||
sign(spendingInfoToSatisfy, wtx, isDummySignature)
|
||||
sign(spendingInfoToSatisfy, wtx)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -579,7 +525,6 @@ sealed abstract class P2WSHSigner extends Signer[P2WSHV0InputInfo] {
|
||||
override def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ScriptSignatureParams[P2WSHV0InputInfo])
|
||||
: TxSigComponent = {
|
||||
if (spendingInfoToSatisfy != spendingInfo) {
|
||||
@ -595,10 +540,8 @@ sealed abstract class P2WSHSigner extends Signer[P2WSHV0InputInfo] {
|
||||
val nestedSpendingInfo = spendingInfoToSatisfy.copy(
|
||||
inputInfo = spendingInfoToSatisfy.inputInfo.nestedInputInfo)
|
||||
|
||||
val signedSigComponent = BitcoinSigner.sign(spendingInfo,
|
||||
wtx,
|
||||
isDummySignature,
|
||||
nestedSpendingInfo)
|
||||
val signedSigComponent =
|
||||
BitcoinSigner.sign(spendingInfo, wtx, nestedSpendingInfo)
|
||||
|
||||
val scriptWit =
|
||||
P2WSHWitnessV0(
|
||||
@ -623,16 +566,12 @@ sealed abstract class LockTimeSigner extends Signer[LockTimeInputInfo] {
|
||||
override def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ScriptSignatureParams[LockTimeInputInfo])
|
||||
: TxSigComponent = {
|
||||
val nestedSpendingInfo = spendingInfoToSatisfy.copy(
|
||||
inputInfo = spendingInfoToSatisfy.inputInfo.nestedInputInfo)
|
||||
|
||||
BitcoinSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
nestedSpendingInfo)
|
||||
BitcoinSigner.sign(spendingInfo, unsignedTx, nestedSpendingInfo)
|
||||
}
|
||||
}
|
||||
object LockTimeSigner extends LockTimeSigner
|
||||
@ -645,7 +584,6 @@ sealed abstract class ConditionalSigner extends Signer[ConditionalInputInfo] {
|
||||
override def sign(
|
||||
spendingInfo: ScriptSignatureParams[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: ScriptSignatureParams[ConditionalInputInfo])
|
||||
: TxSigComponent = {
|
||||
val (_, output, inputIndex, _) = relevantInfo(spendingInfo, unsignedTx)
|
||||
@ -653,10 +591,8 @@ sealed abstract class ConditionalSigner extends Signer[ConditionalInputInfo] {
|
||||
val nestedSpendingInfo = spendingInfoToSatisfy.copy(
|
||||
inputInfo = spendingInfoToSatisfy.inputInfo.nestedInputInfo)
|
||||
|
||||
val missingOpSigComponent = BitcoinSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
nestedSpendingInfo)
|
||||
val missingOpSigComponent =
|
||||
BitcoinSigner.sign(spendingInfo, unsignedTx, nestedSpendingInfo)
|
||||
|
||||
val scriptSig =
|
||||
ConditionalScriptSignature(missingOpSigComponent.scriptSignature,
|
||||
|
@ -197,7 +197,8 @@ object InputInfo {
|
||||
info: InputInfo,
|
||||
forP2WSH: Boolean): ScriptSigLenAndStackHeight = {
|
||||
val boolSize = if (forP2WSH) 2 else 1
|
||||
|
||||
val dummyLowRHashType =
|
||||
ECDigitalSignature.dummyLowR.appendHashType(HashType.sigHashAll)
|
||||
info match {
|
||||
case _: SegwitV0NativeInputInfo | _: UnassignedSegwitNativeInputInfo =>
|
||||
ScriptSigLenAndStackHeight(0, 0)
|
||||
@ -218,25 +219,24 @@ object InputInfo {
|
||||
ScriptSigLenAndStackHeight(boolSize, 1)
|
||||
case _: P2PKInputInfo =>
|
||||
ScriptSigLenAndStackHeight(
|
||||
P2PKScriptSignature(
|
||||
ECDigitalSignature.dummyLowR).asmBytes.length.toInt,
|
||||
P2PKScriptSignature(dummyLowRHashType).asmBytes.length.toInt,
|
||||
1)
|
||||
case _: P2PKHInputInfo =>
|
||||
ScriptSigLenAndStackHeight(
|
||||
P2PKHScriptSignature(ECDigitalSignature.dummyLowR,
|
||||
P2PKHScriptSignature(dummyLowRHashType,
|
||||
ECPublicKey.dummy).asmBytes.length.toInt,
|
||||
2)
|
||||
case info: P2PKWithTimeoutInputInfo =>
|
||||
ScriptSigLenAndStackHeight(
|
||||
P2PKWithTimeoutScriptSignature(
|
||||
info.isBeforeTimeout,
|
||||
ECDigitalSignature.dummyLowR).asmBytes.length.toInt,
|
||||
2)
|
||||
ScriptSigLenAndStackHeight(P2PKWithTimeoutScriptSignature(
|
||||
info.isBeforeTimeout,
|
||||
dummyLowRHashType
|
||||
).asmBytes.length.toInt,
|
||||
2)
|
||||
case info: MultiSignatureInputInfo =>
|
||||
ScriptSigLenAndStackHeight(
|
||||
MultiSignatureScriptSignature(
|
||||
Vector.fill(info.requiredSigs)(
|
||||
ECDigitalSignature.dummyLowR)).asmBytes.length.toInt,
|
||||
dummyLowRHashType)).asmBytes.length.toInt,
|
||||
1 + info.requiredSigs
|
||||
)
|
||||
case info: ConditionalInputInfo =>
|
||||
|
@ -94,7 +94,7 @@ case class ECDigitalSignature(bytes: ByteVector) extends DigitalSignature {
|
||||
}
|
||||
|
||||
object ECDigitalSignature extends Factory[ECDigitalSignature] {
|
||||
|
||||
val LOW_R_SIZE: Byte = 70
|
||||
val empty: ECDigitalSignature = {
|
||||
val bytes: ByteVector = ByteVector.empty
|
||||
new ECDigitalSignature(bytes) {
|
||||
@ -121,7 +121,7 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] {
|
||||
* likely when using low r signing
|
||||
*/
|
||||
val dummyLowR: ECDigitalSignature = {
|
||||
val bytes: ByteVector = ByteVector(Array.fill(71)(0.toByte))
|
||||
val bytes: ByteVector = ByteVector(Array.fill(LOW_R_SIZE)(0.toByte))
|
||||
new ECDigitalSignature(bytes) {
|
||||
override def r: BigInt = empty.r
|
||||
override def s: BigInt = r
|
||||
|
@ -182,7 +182,7 @@ trait Sign extends AsyncSign {
|
||||
CryptoUtil.cryptoContext match {
|
||||
case CryptoContext.BCrypto => sig
|
||||
case CryptoContext.LibSecp256k1 | CryptoContext.BouncyCastle =>
|
||||
if (sig.bytes.length <= 70) {
|
||||
if (sig.bytes.length <= ECDigitalSignature.LOW_R_SIZE) {
|
||||
sig
|
||||
} else {
|
||||
signLowR(bytes, startAt + 1)
|
||||
@ -283,7 +283,9 @@ object Sign {
|
||||
}
|
||||
|
||||
def dummySign(publicKey: ECPublicKey): Sign = {
|
||||
constant(ECDigitalSignature.empty, publicKey, SchnorrDigitalSignature.dummy)
|
||||
constant(ECDigitalSignature.dummyLowR,
|
||||
publicKey,
|
||||
SchnorrDigitalSignature.dummy)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,13 +108,11 @@ sealed abstract class Signer[-InputType <: InputInfo] {
|
||||
|
||||
def sign(
|
||||
spendingInfo: UTXOSatisfyingInfo[InputType],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean)(
|
||||
unsignedTx: Transaction)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
sign(
|
||||
spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingInfoToSatisfy = spendingInfo
|
||||
)
|
||||
}
|
||||
@ -122,14 +120,12 @@ sealed abstract class Signer[-InputType <: InputInfo] {
|
||||
def sign(
|
||||
spendingInfo: UTXOSatisfyingInfo[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: UTXOSatisfyingInfo[InputType])(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent]
|
||||
|
||||
def signSingle(
|
||||
spendingInfo: UTXOSigningInfo[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean)(
|
||||
unsignedTx: Transaction)(
|
||||
implicit ec: ExecutionContext): Future[PartialSignature] = ???
|
||||
}
|
||||
sealed abstract class RawSingleKeyBitcoinSigner[-InputType <: RawInputInfo]
|
||||
@ -143,7 +139,6 @@ sealed abstract class RawSingleKeyBitcoinSigner[-InputType <: RawInputInfo]
|
||||
override def sign(
|
||||
spendingInfo: UTXOSatisfyingInfo[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: UTXOSatisfyingInfo[InputType])(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = ???
|
||||
}
|
||||
@ -171,23 +166,20 @@ object RawScriptUTXOSpendingInfoSingle {
|
||||
object BitcoinSigner {
|
||||
def sign(
|
||||
spendingInfo: UTXOSatisfyingInfo[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean)(
|
||||
unsignedTx: Transaction)(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
sign(spendingInfo, unsignedTx, isDummySignature, spendingInfo)
|
||||
sign(spendingInfo, unsignedTx, spendingInfo)
|
||||
}
|
||||
|
||||
def sign(
|
||||
spendingInfo: UTXOSatisfyingInfo[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: UTXOSatisfyingInfo[InputInfo])(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = ???
|
||||
|
||||
def signSingle(
|
||||
spendingInfo: UTXOSigningInfo[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean)(
|
||||
unsignedTx: Transaction)(
|
||||
implicit ec: ExecutionContext): Future[PartialSignature] = ???
|
||||
}
|
||||
|
||||
@ -203,7 +195,6 @@ def hashType: HashType = ???
|
||||
def beforeTimeout: Boolean = ???
|
||||
def spendingInfo: UTXOSatisfyingInfo[InputInfo] = ???
|
||||
def unsignedTx: Transaction = ???
|
||||
def isDummySignature: Boolean = ???
|
||||
def min: Int = ???
|
||||
def max: Int = ???
|
||||
implicit def ec: ExecutionContext = ???
|
||||
@ -603,14 +594,13 @@ sealed abstract class MultiSigSigner extends Signer[MultiSignatureInputInfo] {
|
||||
override def sign(
|
||||
spendingInfo: UTXOSatisfyingInfo[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: UTXOSatisfyingInfo[MultiSignatureInputInfo])(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
val (_, output, inputIndex, _) =
|
||||
relevantInfo(spendingInfo, unsignedTx)
|
||||
|
||||
val keysAndSigsF = spendingInfo.toSingles.map { spendingInfoSingle =>
|
||||
signSingle(spendingInfoSingle, unsignedTx, isDummySignature)
|
||||
signSingle(spendingInfoSingle, unsignedTx)
|
||||
}
|
||||
|
||||
val signaturesF = Future.sequence(keysAndSigsF).map(_.map(_.signature))
|
||||
@ -642,7 +632,6 @@ sealed abstract class ConditionalSigner extends Signer[ConditionalInputInfo] {
|
||||
override def sign(
|
||||
spendingInfo: UTXOSatisfyingInfo[InputInfo],
|
||||
unsignedTx: Transaction,
|
||||
isDummySignature: Boolean,
|
||||
spendingInfoToSatisfy: UTXOSatisfyingInfo[ConditionalInputInfo])(
|
||||
implicit ec: ExecutionContext): Future[TxSigComponent] = {
|
||||
val (_, output, inputIndex, _) = relevantInfo(spendingInfo, unsignedTx)
|
||||
@ -652,7 +641,6 @@ sealed abstract class ConditionalSigner extends Signer[ConditionalInputInfo] {
|
||||
|
||||
val missingOpSigComponentF = BitcoinSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
nestedSpendingInfo)
|
||||
|
||||
val scriptSigF = missingOpSigComponentF.map { sigComponent =>
|
||||
@ -679,7 +667,6 @@ We must now add the new signing functionality from the previous step to the gene
|
||||
case p2pKWithTimeout: P2PKWithTimeoutInputInfo =>
|
||||
P2PKWithTimeoutSigner.sign(spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature,
|
||||
spendingFrom(p2pKWithTimeout))
|
||||
//...
|
||||
}
|
||||
@ -761,8 +748,7 @@ Lastly, we need to construct a generator that returns both a `ScriptPubKey` and
|
||||
hashType
|
||||
)
|
||||
val txSigComponentF = P2PKWithTimeoutSigner.sign(spendingInfo,
|
||||
spendingTx,
|
||||
isDummySignature = false)
|
||||
spendingTx)
|
||||
val txSigComponent = Await.result(txSigComponentF, timeout)
|
||||
val signedScriptSig =
|
||||
txSigComponent.scriptSignature.asInstanceOf[ConditionalScriptSignature]
|
||||
|
@ -127,8 +127,7 @@ val spendingInfoSingle = ECSignatureParams(
|
||||
// Then we can sign the transaction
|
||||
val signature = BitcoinSigner.signSingle(
|
||||
spendingInfo = spendingInfoSingle,
|
||||
unsignedTx = unsignedTransaction,
|
||||
isDummySignature = false)
|
||||
unsignedTx = unsignedTransaction)
|
||||
|
||||
// We can then add the signature to the PSBT
|
||||
// Note: this signature could be produced by us or another party
|
||||
|
@ -627,8 +627,7 @@ sealed abstract class ScriptGenerators {
|
||||
)
|
||||
txSigComponent = P2PKSigner.sign(
|
||||
spendingInfo,
|
||||
spendingTx,
|
||||
isDummySignature = false
|
||||
spendingTx
|
||||
)
|
||||
// add the signature to the scriptSig instead of having an empty scriptSig
|
||||
signedScriptSig =
|
||||
@ -670,8 +669,7 @@ sealed abstract class ScriptGenerators {
|
||||
)
|
||||
txSigComponent = P2PKHSigner.sign(
|
||||
spendingInfo,
|
||||
unsignedTx,
|
||||
isDummySignature = false
|
||||
unsignedTx
|
||||
)
|
||||
signedScriptSig =
|
||||
txSigComponent.scriptSignature
|
||||
@ -705,8 +703,7 @@ sealed abstract class ScriptGenerators {
|
||||
)
|
||||
val txSigComponent = P2PKWithTimeoutSigner.sign(
|
||||
spendingInfo,
|
||||
spendingTx,
|
||||
isDummySignature = false
|
||||
spendingTx
|
||||
)
|
||||
val signedScriptSig =
|
||||
txSigComponent.scriptSignature.asInstanceOf[ConditionalScriptSignature]
|
||||
@ -757,7 +754,7 @@ sealed abstract class ScriptGenerators {
|
||||
hashType
|
||||
)
|
||||
txSigComponent =
|
||||
MultiSigSigner.sign(spendingInfo, spendingTx, isDummySignature = false)
|
||||
MultiSigSigner.sign(spendingInfo, spendingTx)
|
||||
signedScriptSig =
|
||||
txSigComponent.scriptSignature
|
||||
.asInstanceOf[MultiSignatureScriptSignature]
|
||||
|
Loading…
Reference in New Issue
Block a user