From e69e1e5ad1e3f5845b472e43a9236f975808043e Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Fri, 1 Nov 2024 11:46:26 -0500 Subject: [PATCH] 2024 10 31 digitalsignature (#5752) * Add DigitalSignature, extend it with ECDigitaSignature,SchnorrDigitalSignature * WIP: Remove EmptyDigitalSignature case object in favor of val * Fix byte representation of ECDigitalSignature.emptyDigitalSignature * Simplify names to ECDigitalSignature.{empty, dummy, dummyLowR} * Fix docs --- .../TransactionSignatureCreatorTest.scala | 15 ++-- .../core/crypto/TxSigComponentTest.scala | 12 +-- .../core/protocol/dlc/DLCMessageTest.scala | 2 +- .../core/protocol/ln/LnInvoiceUnitTest.scala | 2 +- .../transaction/TransactionWitnessSpec.scala | 7 +- .../core/wallet/builder/RawTxSignerTest.scala | 14 ++-- .../core/protocol/script/ScriptWitness.scala | 6 +- .../core/protocol/transaction/TxUtil.scala | 10 +-- .../org/bitcoins/core/psbt/PSBTRecord.scala | 2 +- .../bitcoins/core/wallet/signer/Signer.scala | 4 +- .../bitcoins/core/wallet/utxo/InputInfo.scala | 17 ++-- .../crypto/DERSignatureUtilTest.scala | 2 +- .../crypto/ECDigitalSignatureTest.scala | 4 +- .../bitcoins/crypto/BouncyCastleUtil.scala | 15 ++-- .../bitcoins/crypto/DERSignatureUtil.scala | 8 +- .../bitcoins/crypto/DigitalSignature.scala | 3 + .../bitcoins/crypto/ECDigitalSignature.scala | 81 ++++++++++--------- .../crypto/SchnorrDigitalSignature.scala | 4 +- .../main/scala/org/bitcoins/crypto/Sign.scala | 4 +- docs/core/adding-spks.md | 8 +- .../testkitcore/gen/ScriptGenerators.scala | 3 +- .../testkit/wallet/DLCWalletUtil.scala | 2 +- 22 files changed, 111 insertions(+), 114 deletions(-) create mode 100644 crypto/src/main/scala/org/bitcoins/crypto/DigitalSignature.scala diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala index aecdd7934c..543e1f27eb 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala @@ -12,12 +12,7 @@ import org.bitcoins.core.script.util.PreviousOutputMap import org.bitcoins.core.wallet.builder.StandardNonInteractiveFinalizer import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte import org.bitcoins.core.wallet.utxo.{ECSignatureParams, P2PKHInputInfo} -import org.bitcoins.crypto.{ - ECDigitalSignature, - ECPrivateKey, - EmptyDigitalSignature, - HashType -} +import org.bitcoins.crypto.{ECDigitalSignature, ECPrivateKey, HashType} import org.bitcoins.testkitcore.util.TransactionTestUtil import org.bitcoins.testkitcore.gen.{CreditingTxGen, ScriptGenerators} import org.bitcoins.testkitcore.util.BitcoinSJvmTest @@ -302,7 +297,8 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { val scriptPubKey = MultiSignatureScriptPubKey(1, Seq(publicKey)) val (creditingTx, outputIndex) = TransactionTestUtil.buildCreditingTransaction(scriptPubKey) - val scriptSig = MultiSignatureScriptSignature(Seq(EmptyDigitalSignature)) + val scriptSig = + MultiSignatureScriptSignature(Seq(ECDigitalSignature.empty)) val (spendingTx, inputIndex) = TransactionTestUtil.buildSpendingTransaction( creditingTx, @@ -355,7 +351,8 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { val scriptPubKey = P2SHScriptPubKey(redeemScript) val (creditingTx, outputIndex) = TransactionTestUtil.buildCreditingTransaction(scriptPubKey) - val scriptSig = MultiSignatureScriptSignature(Seq(EmptyDigitalSignature)) + val scriptSig = + MultiSignatureScriptSignature(Seq(ECDigitalSignature.empty)) val (spendingTx, inputIndex) = TransactionTestUtil.buildSpendingTransaction( @@ -406,7 +403,7 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { val scriptPubKey = P2SHScriptPubKey(redeemScript) val (creditingTx, outputIndex) = TransactionTestUtil.buildCreditingTransaction(scriptPubKey) - val scriptSig = MultiSignatureScriptSignature(Seq(EmptyDigitalSignature)) + val scriptSig = MultiSignatureScriptSignature(Seq(ECDigitalSignature.empty)) val (spendingTx, inputIndex) = TransactionTestUtil.buildSpendingTransaction( diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/TxSigComponentTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/TxSigComponentTest.scala index 0258e9d7bd..5a22c03a55 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/TxSigComponentTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/TxSigComponentTest.scala @@ -3,13 +3,9 @@ package org.bitcoins.core.crypto import org.bitcoins.core.currency.Satoshis import org.bitcoins.core.number.UInt32 import org.bitcoins.core.policy.Policy -import org.bitcoins.core.protocol.script._ -import org.bitcoins.core.protocol.transaction._ -import org.bitcoins.crypto.{ - DoubleSha256Digest, - DummyECDigitalSignature, - ECPublicKey -} +import org.bitcoins.core.protocol.script.* +import org.bitcoins.core.protocol.transaction.* +import org.bitcoins.crypto.{DoubleSha256Digest, ECDigitalSignature, ECPublicKey} import org.bitcoins.testkitcore.util.BitcoinSUnitTest class TxSigComponentTest extends BitcoinSUnitTest { @@ -64,7 +60,7 @@ class TxSigComponentTest extends BitcoinSUnitTest { Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey)), UInt32.zero, TransactionWitness( - Vector(P2WPKHWitnessV0(pubKey, DummyECDigitalSignature)) + Vector(P2WPKHWitnessV0(pubKey, ECDigitalSignature.dummy)) ) ) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala index 07a5de7534..2eddf18f01 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala @@ -46,7 +46,7 @@ class DLCMessageTest extends BitcoinSJvmTest { ) val dummySig: PartialSignature = - PartialSignature(dummyPubKey, DummyECDigitalSignature) + PartialSignature(dummyPubKey, ECDigitalSignature.empty) it must "not allow a negative collateral for a DLCOffer" in { assertThrows[IllegalArgumentException]( diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceUnitTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceUnitTest.scala index 293842d2bb..4c58b2fc67 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceUnitTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceUnitTest.scala @@ -488,7 +488,7 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { it must "fail to create an invoice if the digital signature is invalid" in { intercept[IllegalArgumentException] { - val sig = EmptyDigitalSignature + val sig = ECDigitalSignature.empty val tags = LnTaggedFields( paymentHash = paymentTag, diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionWitnessSpec.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionWitnessSpec.scala index 679043a87d..ad9a72d869 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionWitnessSpec.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionWitnessSpec.scala @@ -1,7 +1,7 @@ package org.bitcoins.core.protocol.transaction -import org.bitcoins.core.protocol.script._ -import org.bitcoins.crypto.{DummyECDigitalSignature, ECPrivateKey} +import org.bitcoins.core.protocol.script.* +import org.bitcoins.crypto.{ECDigitalSignature, ECPrivateKey} import org.bitcoins.testkitcore.gen.WitnessGenerators import org.bitcoins.testkitcore.util.BitcoinSUnitTest import org.scalacheck.Prop @@ -21,7 +21,8 @@ class TransactionWitnessSpec extends BitcoinSUnitTest { it must "be able to resize a witness to the given index" in { val empty = EmptyWitness.fromN(0) val pubKey = ECPrivateKey.freshPrivateKey.publicKey - val p2pkh = P2PKHScriptSignature(DummyECDigitalSignature, pubKey) + val p2pkh = + P2PKHScriptSignature(ECDigitalSignature.dummy, pubKey) val scriptWit = P2WPKHWitnessV0.fromP2PKHScriptSig(p2pkh) val updated = empty.updated(2, scriptWit) diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxSignerTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxSignerTest.scala index c6ae376767..b2fa44f017 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxSignerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxSignerTest.scala @@ -2,8 +2,8 @@ package org.bitcoins.core.wallet.builder import org.bitcoins.core.currency.{Bitcoins, CurrencyUnits, Satoshis} import org.bitcoins.core.number.UInt32 -import org.bitcoins.core.protocol.script._ -import org.bitcoins.core.protocol.transaction._ +import org.bitcoins.core.protocol.script.* +import org.bitcoins.core.protocol.transaction.* import org.bitcoins.core.script.constant.ScriptNumber import org.bitcoins.core.util.BitcoinScriptUtil import org.bitcoins.core.wallet.fee.{SatoshisPerByte, SatoshisPerVirtualByte} @@ -15,12 +15,12 @@ import org.bitcoins.core.wallet.utxo.{ } import org.bitcoins.crypto.{ DoubleSha256DigestBE, + ECDigitalSignature, ECPrivateKey, HashType, - LowRDummyECDigitalSignature, Sign } -import org.bitcoins.testkitcore.Implicits._ +import org.bitcoins.testkitcore.Implicits.* import org.bitcoins.testkitcore.gen.{CreditingTxGen, ScriptGenerators} import org.bitcoins.testkitcore.util.BitcoinSUnitTest @@ -377,7 +377,7 @@ class RawTxSignerTest extends BitcoinSUnitTest { assert( btx.inputs.forall( _.scriptSignature.signatures.forall( - _ == LowRDummyECDigitalSignature + _ == ECDigitalSignature.dummyLowR ) ) ) @@ -385,9 +385,9 @@ class RawTxSignerTest extends BitcoinSUnitTest { assert( wtx.witness.witnesses.forall { case p2wsh: P2WSHWitnessV0 => - p2wsh.signatures.forall(_ == LowRDummyECDigitalSignature) + p2wsh.signatures.forall(_ == ECDigitalSignature.dummyLowR) case p2wpkh: P2WPKHWitnessV0 => - p2wpkh.signature == LowRDummyECDigitalSignature + p2wpkh.signature == ECDigitalSignature.dummyLowR case EmptyScriptWitness => true diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptWitness.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptWitness.scala index 3590f9eae4..0fc2c07636 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptWitness.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptWitness.scala @@ -51,7 +51,7 @@ sealed abstract class P2WPKHWitnessV0 extends ScriptWitnessV0 { def signature: ECDigitalSignature = stack(1) match { - case ByteVector.empty => EmptyDigitalSignature + case ByteVector.empty => ECDigitalSignature.empty case nonEmpty: ByteVector => ECDigitalSignature(nonEmpty) } @@ -69,11 +69,11 @@ object P2WPKHWitnessV0 { private[bitcoins] def apply( pubKeyBytes: ECPublicKeyBytes): P2WPKHWitnessV0 = { - P2WPKHWitnessV0(pubKeyBytes, EmptyDigitalSignature) + P2WPKHWitnessV0(pubKeyBytes, ECDigitalSignature.empty) } def apply(pubKey: ECPublicKey): P2WPKHWitnessV0 = { - P2WPKHWitnessV0(pubKey, EmptyDigitalSignature) + P2WPKHWitnessV0(pubKey, ECDigitalSignature.empty) } private[bitcoins] def apply( diff --git a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TxUtil.scala b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TxUtil.scala index 2a06d24468..0c50aa984b 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TxUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TxUtil.scala @@ -3,7 +3,7 @@ package org.bitcoins.core.protocol.transaction import org.bitcoins.core.currency.{CurrencyUnit, CurrencyUnits, Satoshis} import org.bitcoins.core.number.UInt32 import org.bitcoins.core.policy.Policy -import org.bitcoins.core.protocol.script._ +import org.bitcoins.core.protocol.script.* import org.bitcoins.core.script.control.OP_RETURN import org.bitcoins.core.wallet.builder.{ AddWitnessDataFinalizer, @@ -13,8 +13,8 @@ import org.bitcoins.core.wallet.builder.{ } import org.bitcoins.core.wallet.fee.FeeUnit import org.bitcoins.core.wallet.signer.BitcoinSigner -import org.bitcoins.core.wallet.utxo._ -import org.bitcoins.crypto.{DummyECDigitalSignature, HashType, Sign} +import org.bitcoins.core.wallet.utxo.* +import org.bitcoins.crypto.{ECDigitalSignature, HashType, Sign} import scala.annotation.tailrec import scala.util.{Failure, Success, Try} @@ -173,8 +173,8 @@ object TxUtil { case (inputInfo, index) => val mockSigners = inputInfo.pubKeys.take(inputInfo.requiredSigs).map { pubKey => - Sign(_ => DummyECDigitalSignature, - (_, _) => DummyECDigitalSignature, + Sign(_ => ECDigitalSignature.dummy, + (_, _) => ECDigitalSignature.dummy, pubKey) } diff --git a/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala b/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala index 76d38a1d46..43284c30cd 100644 --- a/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala +++ b/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala @@ -181,7 +181,7 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { def dummyPartialSig( pubKey: ECPublicKey = ECPublicKey.freshPublicKey): PartialSignature = { - PartialSignature(pubKey, DummyECDigitalSignature) + PartialSignature(pubKey, ECDigitalSignature.dummy) } override def fromBytes(bytes: ByteVector): PartialSignature = diff --git a/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala b/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala index 10415e971e..75b82b05ac 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala @@ -22,7 +22,7 @@ sealed abstract class SignerUtils { hashType: HashType, isDummySignature: Boolean): ECDigitalSignature = { if (isDummySignature) { - DummyECDigitalSignature + ECDigitalSignature.dummy } else { TransactionSignatureCreator.createSig(sigComponent, sign, hashType) } @@ -35,7 +35,7 @@ sealed abstract class SignerUtils { hashType: HashType, isDummySignature: Boolean): ECDigitalSignature = { if (isDummySignature) { - LowRDummyECDigitalSignature + ECDigitalSignature.dummyLowR } else { TransactionSignatureCreator.createSig(unsignedTx, signingInfo, diff --git a/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputInfo.scala b/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputInfo.scala index c0016e38a5..323f3bafe4 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputInfo.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputInfo.scala @@ -3,15 +3,15 @@ package org.bitcoins.core.wallet.utxo import org.bitcoins.core.currency.CurrencyUnit import org.bitcoins.core.number.UInt64 import org.bitcoins.core.protocol.CompactSizeUInt -import org.bitcoins.core.protocol.script._ -import org.bitcoins.core.protocol.transaction._ +import org.bitcoins.core.protocol.script.* +import org.bitcoins.core.protocol.transaction.* import org.bitcoins.core.script.constant.{OP_TRUE, ScriptConstant} import org.bitcoins.core.util.{BitcoinScriptUtil, BytesUtil} import org.bitcoins.crypto.{ + ECDigitalSignature, ECPublicKey, ECPublicKeyBytes, HashType, - LowRDummyECDigitalSignature, NetworkElement, Sign } @@ -216,25 +216,26 @@ object InputInfo { case _: P2PKInputInfo => ScriptSigLenAndStackHeight( P2PKScriptSignature( - LowRDummyECDigitalSignature).asmBytes.length.toInt, + ECDigitalSignature.dummyLowR).asmBytes.length.toInt, 1) case _: P2PKHInputInfo => ScriptSigLenAndStackHeight( - P2PKHScriptSignature(LowRDummyECDigitalSignature, + P2PKHScriptSignature(ECDigitalSignature.dummyLowR, ECPublicKey.dummy).asmBytes.length.toInt, 2) case info: P2PKWithTimeoutInputInfo => ScriptSigLenAndStackHeight( P2PKWithTimeoutScriptSignature( info.isBeforeTimeout, - LowRDummyECDigitalSignature).asmBytes.length.toInt, + ECDigitalSignature.dummyLowR).asmBytes.length.toInt, 2) case info: MultiSignatureInputInfo => ScriptSigLenAndStackHeight( MultiSignatureScriptSignature( Vector.fill(info.requiredSigs)( - LowRDummyECDigitalSignature)).asmBytes.length.toInt, - 1 + info.requiredSigs) + ECDigitalSignature.dummyLowR)).asmBytes.length.toInt, + 1 + info.requiredSigs + ) case info: ConditionalInputInfo => val ScriptSigLenAndStackHeight(maxLen, stackHeight) = maxScriptSigLenAndStackHeight(info.nestedInputInfo, forP2WSH) diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/DERSignatureUtilTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/DERSignatureUtilTest.scala index 744ea68637..4e5a591ead 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/DERSignatureUtilTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/DERSignatureUtilTest.scala @@ -96,7 +96,7 @@ class DERSignatureUtilTest extends BitcoinSCryptoTest { DERSignatureUtil.isValidSignatureEncoding(ECDigitalSignature("")) must be( true ) - DERSignatureUtil.isValidSignatureEncoding(EmptyDigitalSignature) must be( + DERSignatureUtil.isValidSignatureEncoding(ECDigitalSignature.empty) must be( true ) } diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/ECDigitalSignatureTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/ECDigitalSignatureTest.scala index d4819e1e91..069c303e25 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/ECDigitalSignatureTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/ECDigitalSignatureTest.scala @@ -37,8 +37,8 @@ class ECDigitalSignatureTest extends BitcoinSCryptoTest { } it must "say that the empty digital signatures r,s values are both 0" in { - EmptyDigitalSignature.r must be(0) - EmptyDigitalSignature.s must be(0) + ECDigitalSignature.empty.r must be(0) + ECDigitalSignature.empty.s must be(0) } it must "create an empty digital signature when given 0 in hex or byte format" in { diff --git a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleUtil.scala b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleUtil.scala index a395ef75fc..b2ac142eaf 100644 --- a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleUtil.scala +++ b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleUtil.scala @@ -144,14 +144,13 @@ object BouncyCastleUtil { val signer = new ECDSASigner signer.init(false, publicKeyParams) - signature match { - case EmptyDigitalSignature => - signer.verifySignature(data.toArray, - java.math.BigInteger.valueOf(0), - java.math.BigInteger.valueOf(0)) - case _: ECDigitalSignature => - val (r, s) = signature.decodeSignature - signer.verifySignature(data.toArray, r.bigInteger, s.bigInteger) + if (signature == ECDigitalSignature.empty) { + signer.verifySignature(data.toArray, + java.math.BigInteger.valueOf(0), + java.math.BigInteger.valueOf(0)) + } else { + val (r, s) = signature.decodeSignature + signer.verifySignature(data.toArray, r.bigInteger, s.bigInteger) } } resultTry.getOrElse(false) diff --git a/crypto/src/main/scala/org/bitcoins/crypto/DERSignatureUtil.scala b/crypto/src/main/scala/org/bitcoins/crypto/DERSignatureUtil.scala index a73631dba4..d6abff309f 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/DERSignatureUtil.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/DERSignatureUtil.scala @@ -83,10 +83,10 @@ sealed abstract class DERSignatureUtil { * boolean indicating whether the signature was der encoded or not */ def isValidSignatureEncoding(signature: ECDigitalSignature): Boolean = { - signature match { - case EmptyDigitalSignature => true - case signature: ECDigitalSignature => - isValidSignatureEncoding(signature.bytes) + if (ECDigitalSignature.empty == signature) { + true + } else { + isValidSignatureEncoding(signature.bytes) } } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/DigitalSignature.scala b/crypto/src/main/scala/org/bitcoins/crypto/DigitalSignature.scala new file mode 100644 index 0000000000..f2ff48f8f9 --- /dev/null +++ b/crypto/src/main/scala/org/bitcoins/crypto/DigitalSignature.scala @@ -0,0 +1,3 @@ +package org.bitcoins.crypto + +abstract class DigitalSignature extends NetworkElement diff --git a/crypto/src/main/scala/org/bitcoins/crypto/ECDigitalSignature.scala b/crypto/src/main/scala/org/bitcoins/crypto/ECDigitalSignature.scala index 903587c849..2d483af040 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/ECDigitalSignature.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/ECDigitalSignature.scala @@ -4,7 +4,7 @@ import scodec.bits.ByteVector /** Created by chris on 2/26/16. */ -sealed abstract class ECDigitalSignature extends NetworkElement { +case class ECDigitalSignature(bytes: ByteVector) extends DigitalSignature { require(r.signum == 1 || r.signum == 0, s"r must not be negative, got $r") require(s.signum == 1 || s.signum == 0, s"s must not be negative, got $s") @@ -14,8 +14,6 @@ sealed abstract class ECDigitalSignature extends NetworkElement { case _ => other.equals(this) } - def bytes: ByteVector - def isEmpty: Boolean = bytes.isEmpty override def toString: String = "ECDigitalSignature(" + hex + ")" @@ -95,53 +93,56 @@ sealed abstract class ECDigitalSignature extends NetworkElement { } } -case object EmptyDigitalSignature extends ECDigitalSignature { - override val bytes: ByteVector = ByteVector.empty - override def r: BigInt = java.math.BigInteger.valueOf(0) - override def s: BigInt = r -} - -/** The point of this case object is to help with fee estimation an average - * [[ECDigitalSignature]] is 72 bytes in size Technically this number can vary, - * 72 bytes is the most likely though according to - * https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm - */ -case object DummyECDigitalSignature extends ECDigitalSignature { - override val bytes: ByteVector = ByteVector(Array.fill(72)(0.toByte)) - override def r: BigInt = EmptyDigitalSignature.r - override def s: BigInt = r -} - -/** The point of this case object is to help with fee estimation when using low - * r signing. Technically this number can vary, 71 bytes is the most likely - * when using low r signing - */ -case object LowRDummyECDigitalSignature extends ECDigitalSignature { - override val bytes: ByteVector = ByteVector(Array.fill(71)(0.toByte)) - override def r: BigInt = EmptyDigitalSignature.r - override def s: BigInt = r -} - object ECDigitalSignature extends Factory[ECDigitalSignature] { - private case class ECDigitalSignatureImpl(bytes: ByteVector) - extends ECDigitalSignature + val empty: ECDigitalSignature = { + val bytes: ByteVector = ByteVector.empty + new ECDigitalSignature(bytes) { + override def r: BigInt = java.math.BigInteger.valueOf(0) + override def s: BigInt = r + } + } + + /** The point of this case object is to help with fee estimation an average + * [[ECDigitalSignature]] is 72 bytes in size Technically this number can + * vary, 72 bytes is the most likely though according to + * https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm + */ + val dummy: ECDigitalSignature = { + val bytes: ByteVector = ByteVector(Array.fill(72)(0.toByte)) + new ECDigitalSignature(bytes) { + override def r: BigInt = BigInt(0) + override def s: BigInt = r + } + } + + /** The point of this case object is to help with fee estimation when using + * low r signing. Technically this number can vary, 71 bytes is the most + * likely when using low r signing + */ + val dummyLowR: ECDigitalSignature = { + val bytes: ByteVector = ByteVector(Array.fill(71)(0.toByte)) + new ECDigitalSignature(bytes) { + override def r: BigInt = empty.r + override def s: BigInt = r + } + } override def fromBytes(bytes: ByteVector): ECDigitalSignature = { // this represents the empty signature - if (bytes.size == 1 && bytes.head == 0x0) EmptyDigitalSignature - else if (bytes.size == 0) - EmptyDigitalSignature - else if (bytes == DummyECDigitalSignature.bytes) - DummyECDigitalSignature - else if (bytes == LowRDummyECDigitalSignature.bytes) - LowRDummyECDigitalSignature + if (bytes.size == 1 && bytes.head == 0x0) empty + else if (bytes.size == 0) { + empty + } else if (bytes == dummy.bytes) + dummy + else if (bytes == dummyLowR.bytes) + dummyLowR else { // make sure the signature follows BIP62's low-s value // https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures // bitcoinj implementation // https://github.com/bitcoinj/bitcoinj/blob/1e66b9a8e38d9ad425507bf5f34d64c5d3d23bb8/core/src/main/java/org/bitcoinj/core/ECKey.java#L551 - ECDigitalSignatureImpl(bytes) + new ECDigitalSignature(bytes) } } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/SchnorrDigitalSignature.scala b/crypto/src/main/scala/org/bitcoins/crypto/SchnorrDigitalSignature.scala index fd61e81cb4..21b4348695 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/SchnorrDigitalSignature.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/SchnorrDigitalSignature.scala @@ -3,8 +3,8 @@ package org.bitcoins.crypto import scodec.bits.ByteVector case class SchnorrDigitalSignature(rx: SchnorrNonce, sig: FieldElement) - extends NetworkElement { - override def bytes: ByteVector = rx.bytes ++ sig.bytes + extends DigitalSignature { + override val bytes: ByteVector = rx.bytes ++ sig.bytes } object SchnorrDigitalSignature extends Factory[SchnorrDigitalSignature] { diff --git a/crypto/src/main/scala/org/bitcoins/crypto/Sign.scala b/crypto/src/main/scala/org/bitcoins/crypto/Sign.scala index 99fd2486c8..448af2a0e7 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/Sign.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/Sign.scala @@ -109,7 +109,7 @@ object AsyncSign { * server */ def dummySign(publicKey: ECPublicKey): AsyncSign = { - constant(EmptyDigitalSignature, publicKey) + constant(ECDigitalSignature.empty, publicKey) } } @@ -217,7 +217,7 @@ object Sign { } def dummySign(publicKey: ECPublicKey): Sign = { - constant(EmptyDigitalSignature, publicKey) + constant(ECDigitalSignature.empty, publicKey) } } diff --git a/docs/core/adding-spks.md b/docs/core/adding-spks.md index 211e96ebfa..7ac5863bef 100644 --- a/docs/core/adding-spks.md +++ b/docs/core/adding-spks.md @@ -7,7 +7,7 @@ title: Adding New Script Types /* In order to allow the code in this document to be compiled, we must add these * imports here in this invisible, executed code block. We must also not import any * sealed traits that get extended as this will cause errors, and so instead we define - * new ones in this invisible code block of the same names and add implicit conversions + * new ones in this invisible code block of the same names a nd add implicit conversions * where needed so that our fake type can be returned anywhere the real one is expected * and vice-versa. We also add defs to traits where there are overrides to avoid errors, * as well as defs for all vals that are out of scope in code executed below. @@ -15,12 +15,12 @@ title: Adding New Script Types * Note that as this code is never used outside of simply defining things below (only * compiled), we can use ??? everywhere where implementations are expected. * - * Also note that when defining our "new" traits in the actual doc, they must be put in + * Also note that when defining our "new" traits in the actual doc, they must be put in * silent mode rather than compile-only mode to make them accessible to the rest of the doc. */ import org.bitcoins.crypto._ -import org.bitcoins.core.crypto._ +import org.bitcoins.core.crypto._ import org.bitcoins.core.script.constant._ import org.bitcoins.core.script.control._ import org.bitcoins.core.script.crypto._ @@ -746,7 +746,7 @@ Lastly, we need to construct a generator that returns both a `ScriptPubKey` and hashType <- CryptoGenerators.hashType } yield { val emptyScriptSig = P2PKWithTimeoutScriptSignature(beforeTimeout = true, - EmptyDigitalSignature) + ECDigitalSignature.empty) val (creditingTx, outputIndex) = TransactionGenerators.buildCreditingTransaction(spk) val (spendingTx, inputIndex) = TransactionGenerators diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ScriptGenerators.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ScriptGenerators.scala index 040ad77989..04c3b42a85 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ScriptGenerators.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ScriptGenerators.scala @@ -22,7 +22,6 @@ import org.bitcoins.crypto.{ ECDigitalSignature, ECPrivateKey, ECPublicKey, - EmptyDigitalSignature, HashType } import org.scalacheck.Gen @@ -745,7 +744,7 @@ sealed abstract class ScriptGenerators { publicKeys = privateKeys.map(_.publicKey) multiSigScriptPubKey = MultiSignatureScriptPubKey(requiredSigs, publicKeys) - emptyDigitalSignatures = privateKeys.map(_ => EmptyDigitalSignature) + emptyDigitalSignatures = privateKeys.map(_ => ECDigitalSignature.empty) scriptSig = MultiSignatureScriptSignature(emptyDigitalSignatures) (creditingTx, outputIndex) = TransactionGenerators diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala index 0847ee59d7..ec98125518 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala @@ -183,7 +183,7 @@ object DLCWalletUtil extends BitcoinSLogger { lazy val dummyKey2: ECPublicKey = ECPublicKey.freshPublicKey lazy val dummyPartialSig: PartialSignature = - PartialSignature(dummyKey, DummyECDigitalSignature) + PartialSignature(dummyKey, ECDigitalSignature.dummy) lazy val minimalPartialSig: PartialSignature = { PartialSignature(dummyKey, ECDigitalSignature.minimalEncodedZeroSig)