diff --git a/jni/c/headers/java/fr_acinq_secp256k1_Secp256k1CFunctions.h b/jni/c/headers/java/fr_acinq_secp256k1_Secp256k1CFunctions.h index 727d991..3981929 100644 --- a/jni/c/headers/java/fr_acinq_secp256k1_Secp256k1CFunctions.h +++ b/jni/c/headers/java/fr_acinq_secp256k1_Secp256k1CFunctions.h @@ -270,10 +270,10 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256 /* * Class: fr_acinq_secp256k1_Secp256k1CFunctions * Method: secp256k1_frost_shares_gen - * Signature: (J[B[BII[[B)[[[B + * Signature: (J[BII[[B)[[[B */ JNIEXPORT jobjectArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1shares_1gen - (JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jint, jint, jobjectArray); + (JNIEnv *, jclass, jlong, jbyteArray, jint, jint, jobjectArray); /* * Class: fr_acinq_secp256k1_Secp256k1CFunctions diff --git a/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c b/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c index 5ec9d51..3e460f1 100644 --- a/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c +++ b/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c @@ -1340,11 +1340,47 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256 /* * Class: fr_acinq_secp256k1_Secp256k1CFunctions - * Method: secp256k1_frost_share_verify - * Signature: (J[B[B[[B)I + * Method: secp256k1_frost_shares_gen + * Signature: (J[B[BII[[B)[[[B */ -JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1share_1verify - (JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jobjectArray) +JNIEXPORT jobjectArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1shares_1gen(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseed32, jint jthreshold, jint n_participants, jobjectArray jids33) { - return 0; + secp256k1_context *ctx = (secp256k1_context *)jctx; + // This is what gets returned + secp256k1_frost_share shares[n_participants]; + secp256k1_pubkey vss_commitment[n_participants]; + unsigned char pok64[64]; + + // This is what gets passed + unsigned char seed32[32]; + + const unsigned char *ids[n_participants]; + + int result = 0; + + result = secp256k1_frost_shares_gen( + ctx, + shares, + vss_commitment, + jpok64, + jseed32, + jthreshold, + n_participants, + jids33 + ); + + CHECKRESULT(!result, "secp256k1_frost_shares_gen failed"); + + jobjectArray output = (*penv)->NewObjectArray(penv, 3, jbyteArray, NULL); + + jnonce = (*penv)->NewByteArray(penv, sizeof(shares)); + nonce_ptr = (*penv)->GetByteArrayElements(penv, jnonce, 0); + memcpy(nonce_ptr, nonce, sizeof(nonce)); + (*penv)->ReleaseByteArrayElements(penv, jnonce, nonce_ptr, 0); + + output[0]; + output[1]; + output[2]; + + return output; } \ No newline at end of file diff --git a/jni/src/main/java/fr/acinq/secp256k1/Secp256k1CFunctions.java b/jni/src/main/java/fr/acinq/secp256k1/Secp256k1CFunctions.java index 7ae8da8..d798063 100644 --- a/jni/src/main/java/fr/acinq/secp256k1/Secp256k1CFunctions.java +++ b/jni/src/main/java/fr/acinq/secp256k1/Secp256k1CFunctions.java @@ -264,9 +264,10 @@ public class Secp256k1CFunctions { * this function returns 0. For uniformly random 32-byte arrays the * chance of being invalid is negligible (around 1 in 2^128). * - * @return output_pubkey: pointer to a public key to store the result. Will be set - * to an invalid value if this function returns 0. If you - * do not need it, this arg can be NULL. + * @return + * [0] output_pubkey: pointer to a public key to store the result. Will be set to an invalid value if this + * function returns 0. If you do not need it, this arg can be NULL. + * [1] tweak_cache: pointer to a `frost_tweak_cache` struct initialized by `frost_pubkey_tweak` */ public static native byte[][] secp256k1_frost_pubkey_xonly_tweak_add(long ctx, byte[] tweakCache, byte[] tweak32); @@ -348,7 +349,7 @@ public class Secp256k1CFunctions { * @param tweak_cache pointer to frost_tweak_cache struct (can be NULL) * * @return - * pointer to struct to store the partial signature + * partial_sig: pointer to struct to store the partial signature * TODO: [1] secnonce: pointer to the secnonce struct created in frost_nonce_gen that has been never used in a * partial_sign call before * @@ -377,6 +378,7 @@ public class Secp256k1CFunctions { * `secp256k1_frost_compute_pubshare` * @param session pointer to the session that was created with `frost_nonce_process` * @param tweakCache pointer to frost_tweak_cache struct (can be NULL) + * * @return 0 if the arguments are invalid or the partial signature does not verify, 1 otherwise */ public static native int secp256k1_frost_partial_sig_verify(long ctx, byte[] partialSig, byte[] publicNonce, byte[] publicShare, byte[] session, byte[] tweakCache); diff --git a/jni/src/main/kotlin/fr/acinq/secp256k1/NativeSecp256k1.kt b/jni/src/main/kotlin/fr/acinq/secp256k1/NativeSecp256k1.kt index 2adc6da..8234c21 100644 --- a/jni/src/main/kotlin/fr/acinq/secp256k1/NativeSecp256k1.kt +++ b/jni/src/main/kotlin/fr/acinq/secp256k1/NativeSecp256k1.kt @@ -130,24 +130,23 @@ public object NativeSecp256k1 : Secp256k1 { } override fun frostSharesGen( - pok64: ByteArray, seed32: ByteArray, threshold: Int, totalSigners: Int, ids33: Array - ): Pair, Array> { + ): Triple, Array, ByteArray> { val result = Secp256k1CFunctions.secp256k1_frost_shares_gen( Secp256k1Context.getContext(), - pok64, seed32, threshold, totalSigners, ids33 ) - return Pair( + return Triple( result[0], - result[1] + result[1], + result[2].first() // This is bad code... ) } @@ -217,7 +216,7 @@ public object NativeSecp256k1 : Secp256k1 { ) } - override fun frostPublicKeyXonlyTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): Pair { + override fun frostPublicKeyXonlyTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): Pair { val result = Secp256k1CFunctions.secp256k1_frost_pubkey_xonly_tweak_add( Secp256k1Context.getContext(), tweakCache, @@ -232,9 +231,9 @@ public object NativeSecp256k1 : Secp256k1 { override fun frostNonceGen( sessionId32: ByteArray, - share: ByteArray, - msg32: ByteArray, - publicKey: ByteArray, + share: ByteArray?, + msg32: ByteArray?, + publicKey: ByteArray?, extraInput32: ByteArray? ): Pair { val result = Secp256k1CFunctions.secp256k1_frost_nonce_gen( @@ -258,7 +257,7 @@ public object NativeSecp256k1 : Secp256k1 { publicKey: ByteArray, id33: ByteArray, ids33: Array, - tweakCache: ByteArray, + tweakCache: ByteArray?, adaptor: ByteArray? ): ByteArray { return Secp256k1CFunctions.secp256k1_frost_nonce_process( @@ -277,7 +276,7 @@ public object NativeSecp256k1 : Secp256k1 { secnonce: ByteArray, share: ByteArray, session: ByteArray, - tweakCache: ByteArray + tweakCache: ByteArray? ): ByteArray { return Secp256k1CFunctions.secp256k1_frost_partial_sign( Secp256k1Context.getContext(), @@ -293,7 +292,7 @@ public object NativeSecp256k1 : Secp256k1 { publicNonce: ByteArray, publicShare: ByteArray, session: ByteArray, - tweakCache: ByteArray + tweakCache: ByteArray? ): Int { return Secp256k1CFunctions.secp256k1_frost_partial_sig_verify( Secp256k1Context.getContext(), diff --git a/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt b/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt index bb6377d..56c71d3 100644 --- a/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt +++ b/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt @@ -271,7 +271,7 @@ public interface Secp256k1 { */ public fun musigPartialSigAgg(session: ByteArray, psigs: Array): ByteArray - public fun frostSharesGen(pok64: ByteArray, seed32: ByteArray, threshold: Int, totalSigners: Int, ids33: Array): Pair,Array> + public fun frostSharesGen(seed32: ByteArray, threshold: Int, totalSigners: Int, ids33: Array): Triple,Array, ByteArray> /** * @@ -291,21 +291,21 @@ public interface Secp256k1 { public fun frostPublicKeyTweak(xOnlyPublicKey: ByteArray): ByteArray - public fun frostPublicKeyEcTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): ByteArray + public fun frostPublicKeyEcTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): ByteArray? - public fun frostPublicKeyXonlyTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): Pair + public fun frostPublicKeyXonlyTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): Pair - public fun frostNonceGen(sessionId32: ByteArray, share: ByteArray, msg32: ByteArray, publicKey: ByteArray, extraInput32: ByteArray?): Pair + public fun frostNonceGen(sessionId32: ByteArray, share: ByteArray?, msg32: ByteArray?, publicKey: ByteArray?, extraInput32: ByteArray?): Pair /** * * threshold can be deduced from the size of the pubnonces array. */ - public fun frostNonceProcess(publicNonces: Array, msg32: ByteArray, publicKey: ByteArray, id33: ByteArray, ids33: Array, tweakCache: ByteArray, adaptor: ByteArray?): ByteArray + public fun frostNonceProcess(publicNonces: Array, msg32: ByteArray, publicKey: ByteArray, id33: ByteArray, ids33: Array, tweakCache: ByteArray?, adaptor: ByteArray?): ByteArray - public fun frostPartialSign(secnonce: ByteArray, share: ByteArray, session: ByteArray, tweakCache: ByteArray): ByteArray + public fun frostPartialSign(secnonce: ByteArray, share: ByteArray, session: ByteArray, tweakCache: ByteArray?): ByteArray - public fun frostPartialSignatureVerify(partialSig: ByteArray, publicNonce: ByteArray, publicShare: ByteArray, session: ByteArray, tweakCache: ByteArray): Int + public fun frostPartialSignatureVerify(partialSig: ByteArray, publicNonce: ByteArray, publicShare: ByteArray, session: ByteArray, tweakCache: ByteArray?): Int public fun frostPartialSignatureAggregate(session: ByteArray, partialSignatures: Array): ByteArray diff --git a/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt b/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt index 5861489..c8abc1b 100644 --- a/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt +++ b/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt @@ -484,13 +484,11 @@ public object Secp256k1Native : Secp256k1 { } override fun frostSharesGen( - pok64: ByteArray, seed32: ByteArray, threshold: Int, totalSigners: Int, ids33: Array - ): Pair, Array> { - require(pok64.size == 64) + ): Triple, Array, ByteArray> { require(seed32.size == 32) require(threshold > 0) require(threshold <= totalSigners) @@ -500,6 +498,7 @@ public object Secp256k1Native : Secp256k1 { memScoped { val nShares = allocArray(ids33.size) val nVssCommitment = allocArray(threshold) + val pok64 = ByteArray(64) val nIds33s = ids33.map { toNat(it) } @@ -514,9 +513,10 @@ public object Secp256k1Native : Secp256k1 { ids33 = nIds33s.toCValues() ) - return Pair( + return Triple( ids33.indices.map { serializeFrostShare(nShares[it]) }.toTypedArray(), - (0 until threshold).map { serializePubkey(nVssCommitment[it]) }.toTypedArray() + (0 until threshold).map { serializePubkey(nVssCommitment[it]) }.toTypedArray(), + pok64 ) } } @@ -696,7 +696,7 @@ public object Secp256k1Native : Secp256k1 { return natOutput } - override fun frostPublicKeyXonlyTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): Pair { + override fun frostPublicKeyXonlyTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): Pair { require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) require(tweak32.size == 32) @@ -735,15 +735,21 @@ public object Secp256k1Native : Secp256k1 { override fun frostNonceGen( sessionId32: ByteArray, - share: ByteArray, - msg32: ByteArray, - publicKey: ByteArray, + share: ByteArray?, + msg32: ByteArray?, + publicKey: ByteArray?, extraInput32: ByteArray? ): Pair { require(sessionId32.size == 32) - require(share.size == Secp256k1.FROST_SHARE_SIZE) - require(msg32.size == 33) - require(publicKey.size == 33 || publicKey.size == 65) + share?.let { + require(share.size == Secp256k1.FROST_SHARE_SIZE) + } + msg32?.let { + require(msg32.size == 33) + } + publicKey?.let { + require(publicKey.size == 33 || publicKey.size == 65) + } extraInput32?.let { require(it.size == 33) } @@ -752,8 +758,8 @@ public object Secp256k1Native : Secp256k1 { val nFrostSecnonce = alloc() val nPublicNonce = alloc() - val nShare = allocFrostShare(share) - val nPublicKey = allocXonlyPublicKey(publicKey) + val nShare = share?.let { allocFrostShare(it) } + val nPublicKey = publicKey?.let { allocXonlyPublicKey(it) } val nExtraInput32 = extraInput32?.let { toNat(it) } @@ -763,9 +769,9 @@ public object Secp256k1Native : Secp256k1 { secnonce = nFrostSecnonce.ptr, pubnonce = nPublicNonce.ptr, session_id32 = toNat(sessionId32), - agg_share = nShare.ptr, - msg32 = toNat(msg32), - agg_pk = nPublicKey.ptr, + agg_share = nShare?.ptr, + msg32 = msg32?.let { toNat(it) }, + agg_pk = nPublicKey?.ptr, extra_input32 = nExtraInput32 ) @@ -788,7 +794,7 @@ public object Secp256k1Native : Secp256k1 { publicKey: ByteArray, id33: ByteArray, ids33: Array, - tweakCache: ByteArray, + tweakCache: ByteArray?, adaptor: ByteArray? ): ByteArray { publicNonces.forEach { publicNonce -> @@ -799,7 +805,9 @@ public object Secp256k1Native : Secp256k1 { ids33.forEach { require(it.size == 33) } - require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) + tweakCache?.let { + require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) + } adaptor?.let { require(it.size == 33 || it.size == 65) } @@ -813,8 +821,11 @@ public object Secp256k1Native : Secp256k1 { val nIds33 = ids33.map { toNat(it) } - val nTweakCache = alloc() - memcpy(nTweakCache.ptr, toNat(tweakCache), Secp256k1.FROST_TWEAK_CACHE_SIZE.toULong()) + val nTweakCache = tweakCache?.let { + alloc() + }?.also { nTweakCache -> + memcpy(nTweakCache.ptr, toNat(tweakCache) , Secp256k1.FROST_TWEAK_CACHE_SIZE.toULong()) + } val nAdaptor = adaptor?.let { allocPublicKey(it).ptr @@ -828,7 +839,7 @@ public object Secp256k1Native : Secp256k1 { agg_pk = nPublicKey.ptr, my_id33 = toNat(id33), ids33 = nIds33.toCValues(), - tweak_cache = nTweakCache.ptr, + tweak_cache = nTweakCache?.ptr, adaptor = nAdaptor ) @@ -850,12 +861,15 @@ public object Secp256k1Native : Secp256k1 { secnonce: ByteArray, share: ByteArray, session: ByteArray, - tweakCache: ByteArray + tweakCache: ByteArray? ): ByteArray { require(secnonce.size == Secp256k1.FROST_SECNONCE_SIZE) require(share.size == Secp256k1.FROST_SHARE_SIZE) require(session.size == Secp256k1.FROST_SESSION_SIZE) - require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) + tweakCache?.let { + require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) + } + memScoped { val nPartialSignature = alloc(); @@ -868,8 +882,12 @@ public object Secp256k1Native : Secp256k1 { val nSession = alloc() memcpy(nSession.ptr, toNat(session), Secp256k1.FROST_SESSION_SIZE.toULong()) - val nTweakCache = alloc() - memcpy(nTweakCache.ptr, toNat(tweakCache), Secp256k1.FROST_TWEAK_CACHE_SIZE.toULong()) + val nTweakCache = tweakCache?.let { + alloc() + }?.also { nTweakCache -> + memcpy(nTweakCache.ptr, toNat(tweakCache) , Secp256k1.FROST_TWEAK_CACHE_SIZE.toULong()) + } + secp256k1_frost_partial_sign( ctx, @@ -877,7 +895,7 @@ public object Secp256k1Native : Secp256k1 { nSecnonce.ptr, nShare.ptr, nSession.ptr, - nTweakCache.ptr + nTweakCache?.ptr ) return serializeFrostPartialSignature(nPartialSignature) @@ -889,13 +907,16 @@ public object Secp256k1Native : Secp256k1 { publicNonce: ByteArray, publicShare: ByteArray, session: ByteArray, - tweakCache: ByteArray + tweakCache: ByteArray? ): Int { require(partialSig.size == 32) require(publicNonce.size == Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE) require(publicShare.size == 33 || publicShare.size == 65) require(session.size == Secp256k1.FROST_SESSION_SIZE) - require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) + tweakCache?.let { + require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) + } + memScoped { val nPartialSignature = allocFrostPartialSignature(partialSig) @@ -903,8 +924,11 @@ public object Secp256k1Native : Secp256k1 { val nPublicShare = allocPublicKey(publicShare) val nSession = alloc() memcpy(nSession.ptr, toNat(session), Secp256k1.FROST_SESSION_SIZE.toULong()) - val nTweakCache = alloc() - memcpy(nTweakCache.ptr, toNat(tweakCache), Secp256k1.FROST_TWEAK_CACHE_SIZE.toULong()) + val nTweakCache = tweakCache?.let { + alloc() + }?.also { nTweakCache -> + memcpy(nTweakCache.ptr, toNat(tweakCache) , Secp256k1.FROST_TWEAK_CACHE_SIZE.toULong()) + } return secp256k1_frost_partial_sig_verify( ctx, @@ -912,7 +936,7 @@ public object Secp256k1Native : Secp256k1 { nPublicNonce.ptr, nPublicShare.ptr, nSession.ptr, - nTweakCache.ptr + nTweakCache?.ptr ) } }