11package fr .acinq .bitcoin .scalacompat
22
3- import fr .acinq .bitcoin .ScriptTree
4- import fr .acinq .bitcoin .crypto .musig2 .{IndividualNonce , SecretNonce }
3+ import fr .acinq .bitcoin .crypto .musig2
54import fr .acinq .bitcoin .scalacompat .Crypto .{PrivateKey , PublicKey , XonlyPublicKey }
65import fr .acinq .bitcoin .scalacompat .KotlinUtils ._
6+ import fr .acinq .secp256k1 .Secp256k1
7+ import scodec .bits .ByteVector
78
89import scala .jdk .CollectionConverters .SeqHasAsJava
910
1011object Musig2 {
1112
13+ /**
14+ * Musig2 secret nonce, that should be treated as a private opaque blob.
15+ * This nonce must never be persisted or reused across signing sessions.
16+ */
17+ case class SecretNonce (inner : musig2.SecretNonce )
18+
19+ /**
20+ * Musig2 public nonce, that must be shared with other participants in the signing session.
21+ * It contains two elliptic curve points, but should be treated as an opaque blob.
22+ */
23+ case class IndividualNonce (data : ByteVector ) {
24+ require(data.size == Secp256k1 .MUSIG2_PUBLIC_NONCE_SIZE , " invalid musig2 public nonce size" )
25+ }
26+
27+ /** A locally-generated nonce, for which both the secret and public parts are known. */
28+ case class LocalNonce (secretNonce : SecretNonce , publicNonce : IndividualNonce )
29+
1230 /**
1331 * Aggregate the public keys of a musig2 session into a single public key.
1432 * Note that this function doesn't apply any tweak: when used for taproot, it computes the internal public key, not
1533 * the public key exposed in the script (which is tweaked with the script tree).
1634 *
1735 * @param publicKeys public keys of all participants: callers must verify that all public keys are valid.
1836 */
19- def aggregateKeys (publicKeys : Seq [PublicKey ]): XonlyPublicKey = XonlyPublicKey (fr.acinq.bitcoin.crypto. musig2.Musig2 .aggregateKeys(publicKeys.map(scala2kmp).asJava))
37+ def aggregateKeys (publicKeys : Seq [PublicKey ]): XonlyPublicKey = XonlyPublicKey (musig2.Musig2 .aggregateKeys(publicKeys.map(scala2kmp).asJava))
2038
2139 /**
22- * @param sessionId a random, unique session ID.
23- * @param signingKey either the signer's private key or public key
24- * @param publicKeys public keys of all participants: callers must verify that all public keys are valid.
25- * @param message_opt (optional) message that will be signed, if already known.
40+ * @param sessionId a random, unique session ID.
41+ * @param signingKey either the signer's private key or public key
42+ * @param publicKeys public keys of all participants: callers must verify that all public keys are valid.
43+ * @param message_opt (optional) message that will be signed, if already known.
2644 * @param extraInput_opt (optional) additional random data.
2745 */
28- def generateNonce (sessionId : ByteVector32 , signingKey : Either [PrivateKey , PublicKey ], publicKeys : Seq [PublicKey ], message_opt : Option [ByteVector32 ], extraInput_opt : Option [ByteVector32 ]): ( SecretNonce , IndividualNonce ) = {
29- val nonce = fr.acinq.bitcoin.crypto. musig2.Musig2 .generateNonce(sessionId, either2keitherkmp(signingKey.map(scala2kmp).left.map(scala2kmp)), publicKeys.map(scala2kmp).asJava, message_opt.map(scala2kmp).orNull, extraInput_opt.map(scala2kmp).orNull)
30- ( nonce.getFirst, nonce.getSecond)
46+ def generateNonce (sessionId : ByteVector32 , signingKey : Either [PrivateKey , PublicKey ], publicKeys : Seq [PublicKey ], message_opt : Option [ByteVector32 ], extraInput_opt : Option [ByteVector32 ]): LocalNonce = {
47+ val nonce = musig2.Musig2 .generateNonce(sessionId, either2keitherkmp(signingKey.map(scala2kmp).left.map(scala2kmp)), publicKeys.map(scala2kmp).asJava, message_opt.map(scala2kmp).orNull, extraInput_opt.map(scala2kmp).orNull)
48+ LocalNonce ( SecretNonce ( nonce.getFirst), IndividualNonce ( nonce.getSecond.getData) )
3149 }
3250
3351 /**
@@ -37,9 +55,9 @@ object Musig2 {
3755 * @param message_opt (optional) message that will be signed, if already known.
3856 * @param extraInput_opt (optional) additional random data.
3957 */
40- def generateNonceWithCounter (nonRepeatingCounter : Long , privateKey : PrivateKey , publicKeys : Seq [PublicKey ], message_opt : Option [ByteVector32 ], extraInput_opt : Option [ByteVector32 ]): ( SecretNonce , IndividualNonce ) = {
41- val nonce = fr.acinq.bitcoin.crypto. musig2.Musig2 .generateNonceWithCounter(nonRepeatingCounter, privateKey, publicKeys.map(scala2kmp).asJava, message_opt.map(scala2kmp).orNull, extraInput_opt.map(scala2kmp).orNull)
42- ( nonce.getFirst, nonce.getSecond)
58+ def generateNonceWithCounter (nonRepeatingCounter : Long , privateKey : PrivateKey , publicKeys : Seq [PublicKey ], message_opt : Option [ByteVector32 ], extraInput_opt : Option [ByteVector32 ]): LocalNonce = {
59+ val nonce = musig2.Musig2 .generateNonceWithCounter(nonRepeatingCounter, privateKey, publicKeys.map(scala2kmp).asJava, message_opt.map(scala2kmp).orNull, extraInput_opt.map(scala2kmp).orNull)
60+ LocalNonce ( SecretNonce ( nonce.getFirst), IndividualNonce ( nonce.getSecond.getData) )
4361 }
4462
4563 /**
@@ -55,7 +73,7 @@ object Musig2 {
5573 * @param scriptTree_opt tapscript tree of the taproot input, if it has script paths.
5674 */
5775 def signTaprootInput (privateKey : PrivateKey , tx : Transaction , inputIndex : Int , inputs : Seq [TxOut ], publicKeys : Seq [PublicKey ], secretNonce : SecretNonce , publicNonces : Seq [IndividualNonce ], scriptTree_opt : Option [ScriptTree ]): Either [Throwable , ByteVector32 ] = {
58- fr.acinq.bitcoin.crypto. musig2.Musig2 .signTaprootInput(privateKey, tx, inputIndex, inputs.map(scala2kmp).asJava, publicKeys.map(scala2kmp).asJava, secretNonce, publicNonces.asJava, scriptTree_opt.orNull).map(kmp2scala)
76+ musig2.Musig2 .signTaprootInput(privateKey, tx, inputIndex, inputs.map(scala2kmp).asJava, publicKeys.map(scala2kmp).asJava, secretNonce.inner , publicNonces.map(n => new musig2. IndividualNonce (n.data.toArray)). asJava, scriptTree_opt.map(scala2kmp) .orNull).map(kmp2scala)
5977 }
6078
6179 /**
@@ -73,7 +91,7 @@ object Musig2 {
7391 * @return true if the partial signature is valid.
7492 */
7593 def verifyTaprootSignature (partialSig : ByteVector32 , nonce : IndividualNonce , publicKey : PublicKey , tx : Transaction , inputIndex : Int , inputs : Seq [TxOut ], publicKeys : Seq [PublicKey ], publicNonces : Seq [IndividualNonce ], scriptTree_opt : Option [ScriptTree ]): Boolean = {
76- fr.acinq.bitcoin.crypto. musig2.Musig2 .verify(partialSig, nonce, publicKey, tx, inputIndex, inputs.map(scala2kmp).asJava, publicKeys.map(scala2kmp).asJava, publicNonces.asJava, scriptTree_opt.orNull)
94+ musig2.Musig2 .verify(partialSig, new musig2. IndividualNonce ( nonce.data.toArray) , publicKey, tx, inputIndex, inputs.map(scala2kmp).asJava, publicKeys.map(scala2kmp).asJava, publicNonces.map(n => new musig2. IndividualNonce (n.data.toArray)). asJava, scriptTree_opt.map(scala2kmp) .orNull)
7795 }
7896
7997 /**
@@ -88,7 +106,7 @@ object Musig2 {
88106 * @param scriptTree_opt tapscript tree of the taproot input, if it has script paths.
89107 */
90108 def aggregateTaprootSignatures (partialSigs : Seq [ByteVector32 ], tx : Transaction , inputIndex : Int , inputs : Seq [TxOut ], publicKeys : Seq [PublicKey ], publicNonces : Seq [IndividualNonce ], scriptTree_opt : Option [ScriptTree ]): Either [Throwable , ByteVector64 ] = {
91- fr.acinq.bitcoin.crypto. musig2.Musig2 .aggregateTaprootSignatures(partialSigs.map(scala2kmp).asJava, tx, inputIndex, inputs.map(scala2kmp).asJava, publicKeys.map(scala2kmp).asJava, publicNonces.asJava, scriptTree_opt.orNull).map(kmp2scala)
109+ musig2.Musig2 .aggregateTaprootSignatures(partialSigs.map(scala2kmp).asJava, tx, inputIndex, inputs.map(scala2kmp).asJava, publicKeys.map(scala2kmp).asJava, publicNonces.map(n => new musig2. IndividualNonce (n.data.toArray)). asJava, scriptTree_opt.map(scala2kmp) .orNull).map(kmp2scala)
92110 }
93111
94112}
0 commit comments