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:
Chris Stewart 2024-11-17 07:45:24 -06:00 committed by GitHub
parent fc4802d4b0
commit bb0e40f05b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 2847 additions and 2947 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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