diff --git a/.gitignore b/.gitignore index d4093e3..1e90d80 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ local.properties # OS .DS_Store jni/bin/* -jni/jvm/bin/* \ No newline at end of file +jni/jvm/bin/* +/jni/src/main/java/fr/acinq/secp256k1/Secp256k1CFunctions.class diff --git a/jni/c/headers/java/fr_acinq_secp256k1_Secp256k1CFunctions.h b/jni/c/headers/java/fr_acinq_secp256k1_Secp256k1CFunctions.h index 750d668..f123f19 100644 --- a/jni/c/headers/java/fr_acinq_secp256k1_Secp256k1CFunctions.h +++ b/jni/c/headers/java/fr_acinq_secp256k1_Secp256k1CFunctions.h @@ -267,6 +267,102 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1mu JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1partial_1sig_1agg (JNIEnv *, jclass, jlong, jbyteArray, jobjectArray); +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_shares_gen + * Signature: (J[[B[B[BI[[B)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1shares_1gen + (JNIEnv *, jclass, jlong, jobjectArray, jbyteArray, jbyteArray, jint, jobjectArray); + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_share_agg + * Signature: (J[[[B[B)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1share_1agg + (JNIEnv *, jclass, jlong, jobjectArray, jbyteArray); + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_share_verify + * Signature: (J[B[B[[B)I + */ +JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1share_1verify + (JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jobjectArray); + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_compute_pubshare + * Signature: (J[B[[[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1compute_1pubshare + (JNIEnv *, jclass, jlong, jbyteArray, jobjectArray); + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_pubkey_tweak + * Signature: (J[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1pubkey_1tweak + (JNIEnv *, jclass, jlong, jbyteArray); + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_pubkey_ec_tweak_add + * Signature: (J[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1pubkey_1ec_1tweak_1add + (JNIEnv *, jclass, jlong, jbyteArray); + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_pubkey_xonly_tweak_add + * Signature: (J[B)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1pubkey_1xonly_1tweak_1add + (JNIEnv *, jclass, jlong, jbyteArray); + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_nonce_gen + * Signature: (J[B[B[B[B[B)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1nonce_1gen + (JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray); + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_nonce_process + * Signature: (J[[B[B[B[B[[B[B[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1nonce_1process + (JNIEnv *, jclass, jlong, jobjectArray, jbyteArray, jbyteArray, jbyteArray, jobjectArray, jbyteArray, jbyteArray); + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_partial_sign + * Signature: (J[B[B[B[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1partial_1sign + (JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jbyteArray, jbyteArray); + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_partial_sig_verify + * Signature: (J[B[B[B[B[B)I + */ +JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1partial_1sig_1verify + (JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray); + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_partial_sig_aggregate + * Signature: (J[B[[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1partial_1sig_1aggregate + (JNIEnv *, jclass, jlong, jbyteArray, jobjectArray); + #ifdef __cplusplus } #endif diff --git a/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c b/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c index cd28ff3..5ec9d51 100644 --- a/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c +++ b/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c @@ -9,6 +9,7 @@ #include "include/secp256k1_recovery.h" #include "include/secp256k1_schnorrsig.h" #include "include/secp256k1_musig.h" +#include "include/secp256k1_frost.h" #include "fr_acinq_secp256k1_Secp256k1CFunctions.h" #define SIG_FORMAT_UNKNOWN 0 @@ -1336,3 +1337,14 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256 copy_bytes_to_java(penv, jpsig, 64, sig64); return jpsig; } + +/* + * Class: fr_acinq_secp256k1_Secp256k1CFunctions + * Method: secp256k1_frost_share_verify + * Signature: (J[B[B[[B)I + */ +JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1share_1verify + (JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jobjectArray) +{ + return 0; +} \ 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 fd49e3e..41f0613 100644 --- a/jni/src/main/java/fr/acinq/secp256k1/Secp256k1CFunctions.java +++ b/jni/src/main/java/fr/acinq/secp256k1/Secp256k1CFunctions.java @@ -106,4 +106,29 @@ public class Secp256k1CFunctions { public static native int secp256k1_musig_partial_sig_verify(long ctx, byte[] psig, byte[] pubnonce, byte[] pubkey, byte[] keyagg_cache, byte[] session); public static native byte[] secp256k1_musig_partial_sig_agg(long ctx, byte[] session, byte[][] psigs); + + public static native byte[][] secp256k1_frost_shares_gen(long ctx, byte[][] vss_commitment, byte[] pok64, byte[] seed32, int total_signers, byte[][] ids33); + + public static native byte[][] secp256k1_frost_share_agg(long ctx, byte[][][] vss_commitments, byte[] id33); + + public static native int secp256k1_frost_share_verify(long ctx, byte[] id33, byte[] share, byte[][] vss_commitment); + + public static native byte[] secp256k1_frost_compute_pubshare(long ctx, byte[] id33, byte[][][] vss_commitments); + + public static native byte[] secp256k1_frost_pubkey_tweak(long ctx, byte[] public_key); + + public static native byte[] secp256k1_frost_pubkey_ec_tweak_add(long ctx, byte[] tweakCache, byte[] tweak32); + + public static native byte[][] secp256k1_frost_pubkey_xonly_tweak_add(long ctx, byte[] tweakCache, byte[] tweak32); + + public static native byte[][] secp256k1_frost_nonce_gen(long ctx, byte[] sessionId32, byte[] share, byte[] msg32, byte[] publicKey, byte[] extraInput32); + + public static native byte[] secp256k1_frost_nonce_process(long ctx, byte[][] pubnonces, byte[] msg32, byte[] publicKey, byte[] id33, byte[][] ids33, byte[] tweakCache, byte[] adaptor); + + public static native byte[] secp256k1_frost_partial_sign(long ctx, byte[] secnonce, byte[] share, byte[] session, byte[] tweak_cache); + + public static native int secp256k1_frost_partial_sig_verify(long ctx, byte[] partialSig, byte[] publicNonce, byte[] publicShare, byte[] session, byte[] tweakCache); + + public static native byte[] secp256k1_frost_partial_sig_aggregate(long ctx, byte[] session, byte[][] partialSignatures); + } diff --git a/jni/src/main/kotlin/fr/acinq/secp256k1/NativeSecp256k1.kt b/jni/src/main/kotlin/fr/acinq/secp256k1/NativeSecp256k1.kt index bcbe03f..aabff3b 100644 --- a/jni/src/main/kotlin/fr/acinq/secp256k1/NativeSecp256k1.kt +++ b/jni/src/main/kotlin/fr/acinq/secp256k1/NativeSecp256k1.kt @@ -129,6 +129,175 @@ public object NativeSecp256k1 : Secp256k1 { return Secp256k1CFunctions.secp256k1_musig_partial_sig_agg(Secp256k1Context.getContext(), session, psigs) } + override fun frostSharesGen( + vssCommitment: Array, + pok64: ByteArray, + seed32: ByteArray, + totalSigners: Int, + ids33: Array + ): Array { + return Secp256k1CFunctions.secp256k1_frost_shares_gen( + Secp256k1Context.getContext(), + vssCommitment, + pok64, + seed32, + totalSigners, + ids33 + ) + } + + override fun frostShareAggregate( + totalShares: Array, + vssCommitments: Array>, + id33: ByteArray + ): Pair { + val result = Secp256k1CFunctions.secp256k1_frost_share_agg( + Secp256k1Context.getContext(), + vssCommitments, + id33 + ) + return Pair( + result[0], // agg_share + result[1] // agg_pk + ) + } + + override fun frostShareVerify( + threshold: Int, + id33: ByteArray, + share: ByteArray, + vssCommitment: Array + ): Int { + return Secp256k1CFunctions.secp256k1_frost_share_verify( + Secp256k1Context.getContext(), + id33, + share, + vssCommitment + ) + } + + override fun frostComputePublicShare( + id33: ByteArray, + vssCommitments: Array> + ): ByteArray { + return Secp256k1CFunctions.secp256k1_frost_compute_pubshare( + Secp256k1Context.getContext(), + id33, + vssCommitments + ) + } + + override fun frostPublicKeyTweak(pk: ByteArray): ByteArray { + return Secp256k1CFunctions.secp256k1_frost_pubkey_tweak( + Secp256k1Context.getContext(), + pk + ) + } + + override fun frostPublicKeyEcTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): ByteArray { + return Secp256k1CFunctions.secp256k1_frost_pubkey_ec_tweak_add( + Secp256k1Context.getContext(), + tweakCache, + tweak32 + ) + } + + override fun frostPublicKeyXonlyTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): Pair { + val result = Secp256k1CFunctions.secp256k1_frost_pubkey_xonly_tweak_add( + Secp256k1Context.getContext(), + tweakCache, + tweak32 + ) + + return Pair( + result[0], // output_pubkey + result[1] // tweak_cache + ) + } + + override fun frostNonceGen( + sessionId32: ByteArray, + share: ByteArray, + msg32: ByteArray, + publicKey: ByteArray, + extraInput32: ByteArray? + ): Pair { + val result = Secp256k1CFunctions.secp256k1_frost_nonce_gen( + Secp256k1Context.getContext(), + sessionId32, + share, + msg32, + publicKey, + extraInput32 + ) + + return Pair( + result[0], // secnonce + result[1] // pubnonce + ) + } + + override fun frostNonceProcess( + publicNonces: Array, + msg32: ByteArray, + publicKey: ByteArray, + id33: ByteArray, + ids33: Array, + tweakCache: ByteArray, + adaptor: ByteArray? + ): ByteArray { + return Secp256k1CFunctions.secp256k1_frost_nonce_process( + Secp256k1Context.getContext(), + publicNonces, + msg32, + publicKey, + id33, + ids33, + tweakCache, + adaptor + ) + } + + override fun frostPartialSign( + secnonce: ByteArray, + share: ByteArray, + session: ByteArray, + tweakCache: ByteArray + ): ByteArray { + return Secp256k1CFunctions.secp256k1_frost_partial_sign( + Secp256k1Context.getContext(), + secnonce, + share, + session, + tweakCache + ) + } + + override fun frostPartialSignatureVerify( + partialSig: ByteArray, + publicNonce: ByteArray, + publicShare: ByteArray, + session: ByteArray, + tweakCache: ByteArray + ): Int { + return Secp256k1CFunctions.secp256k1_frost_partial_sig_verify( + Secp256k1Context.getContext(), + partialSig, + publicNonce, + publicShare, + session, + tweakCache + ) + } + + override fun frostPartialSignatureAggregate(session: ByteArray, partialSignatures: Array): ByteArray { + return Secp256k1CFunctions.secp256k1_frost_partial_sig_aggregate( + Secp256k1Context.getContext(), + session, + partialSignatures + ) + } + override fun cleanup() { return Secp256k1CFunctions.secp256k1_context_destroy(Secp256k1Context.getContext()) } diff --git a/native/build-android.sh b/native/build-android.sh index 83b582c..e4b2d25 100755 --- a/native/build-android.sh +++ b/native/build-android.sh @@ -33,7 +33,7 @@ export STRIP=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/llvm-strip cd secp256k1 ./autogen.sh -./configure CFLAGS=-fpic --host=$TARGET --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no +./configure CFLAGS=-fpic --host=$TARGET --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-module-frost --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no make clean make diff --git a/native/build-ios.sh b/native/build-ios.sh index 8c8e617..3a780fe 100755 --- a/native/build-ios.sh +++ b/native/build-ios.sh @@ -6,7 +6,7 @@ cp xconfigure.sh secp256k1 cd secp256k1 ./autogen.sh -sh xconfigure.sh --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no +sh xconfigure.sh --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-module-frost --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no mkdir -p ../build/ios cp -v _build/universal/ios/* ../build/ios/ diff --git a/native/build.sh b/native/build.sh index edfe426..f75ffe0 100755 --- a/native/build.sh +++ b/native/build.sh @@ -25,7 +25,7 @@ else fi ./autogen.sh -CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" ./configure $CONF_OPTS --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no +CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" ./configure $CONF_OPTS --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-module-frost --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no make clean make diff --git a/native/secp256k1 b/native/secp256k1 index df0bdeb..ac7967d 160000 --- a/native/secp256k1 +++ b/native/secp256k1 @@ -1 +1 @@ -Subproject commit df0bdeb09654ecedc7766dff700719959cf960cb +Subproject commit ac7967d79c0d69fd17aed5107481d2c5d9998cf8 diff --git a/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt b/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt index 4ea9794..91fb7c9 100644 --- a/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt +++ b/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt @@ -271,6 +271,44 @@ public interface Secp256k1 { */ public fun musigPartialSigAgg(session: ByteArray, psigs: Array): ByteArray + public fun frostSharesGen(vssCommitment: Array, pok64: ByteArray, seed32: ByteArray, totalSigners: Int, ids33: Array): Array + + /** + * + * total signers is deduced from the size of the totalShares array. + * threshold is deduced from the vssCommitments (all vssCommitments should have the same length... which is the threshold) + */ + public fun frostShareAggregate(totalShares: Array, vssCommitments: Array>, id33: ByteArray): Pair + + public fun frostShareVerify(threshold: Int, id33: ByteArray, share: ByteArray, vssCommitment: Array): Int + + /** + * + * total signers is deduced from the size of the vssCommitments array. + * threshold is deduced from the vssCommitments (all vssCommitments should have the same length... which is the threshold) + */ + public fun frostComputePublicShare(id33: ByteArray, vssCommitments: Array>): ByteArray + + public fun frostPublicKeyTweak(pk: ByteArray): ByteArray + + public fun frostPublicKeyEcTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): ByteArray + + public fun frostPublicKeyXonlyTweakAdd(tweakCache: ByteArray, tweak32: 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 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 frostPartialSignatureAggregate(session: ByteArray, partialSignatures: Array): ByteArray + /** * Delete the secp256k1 context from dynamic memory. */ @@ -285,6 +323,17 @@ public interface Secp256k1 { public const val MUSIG2_PUBLIC_NONCE_SIZE: Int = 66 public const val MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE: Int = 197 public const val MUSIG2_PUBLIC_SESSION_SIZE: Int = 133 + + public const val FROST_PARTIAL_SIGNATURE_SIZE: Int = 36 + + public const val FROST_SHARE_SIZE: Int = 36 + public const val FROST_TWEAK_CACHE_SIZE: Int = 101 + public const val FROST_SESSION_SIZE: Int = 133 + public const val FROST_SECNONCE_SIZE: Int = 68 + public const val FROST_PUBNONCE_SIZE: Int = 132 + public const val FROST_SERIALIZED_PARTIAL_SIGNATURE_SIZE: Int = 32 + public const val FROST_SERIALIZED_SHARE_SIZE: Int = 32 + public const val FROST_SERIALIZED_PUBNONCE_SIZE: Int = 66 // @formatter:on } } diff --git a/src/nativeInterop/cinterop/libsecp256k1.def b/src/nativeInterop/cinterop/libsecp256k1.def index 8d310d3..931ffec 100644 --- a/src/nativeInterop/cinterop/libsecp256k1.def +++ b/src/nativeInterop/cinterop/libsecp256k1.def @@ -1,7 +1,7 @@ package = secp256k1 -headers = secp256k1.h secp256k1_ecdh.h secp256k1_recovery.h secp256k1_extrakeys.h secp256k1_schnorrsig.h secp256k1_musig.h -headerFilter = secp256k1/** secp256k1_ecdh.h secp256k1_recovery.h secp256k1_extrakeys.h secp256k1_schnorrsig.h secp256k1_musig.h secp256k1.h +headers = secp256k1.h secp256k1_ecdh.h secp256k1_recovery.h secp256k1_extrakeys.h secp256k1_schnorrsig.h secp256k1_musig.h secp256k1_frost.h +headerFilter = secp256k1/** secp256k1_ecdh.h secp256k1_recovery.h secp256k1_extrakeys.h secp256k1_schnorrsig.h secp256k1_musig.h secp256k1_frost.h secp256k1.h staticLibraries.linux = libsecp256k1.a libraryPaths.linux = c/secp256k1/build/linux/ native/build/linux/ native/build/darwin/ diff --git a/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt b/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt index f540ab2..f57fec9 100644 --- a/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt +++ b/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt @@ -1,6 +1,7 @@ package fr.acinq.secp256k1 import kotlinx.cinterop.* +import kotlinx.cinterop.ptr import platform.posix.memcpy import platform.posix.size_tVar import secp256k1.* @@ -41,6 +42,13 @@ public object Secp256k1Native : Secp256k1 { return pub } + private fun MemScope.allocXonlyPublicKey(pubkey: ByteArray): secp256k1_xonly_pubkey { + val natPub = toNat(pubkey) + val pub = alloc() + secp256k1_xonly_pubkey_parse(ctx, pub.ptr, natPub).requireSuccess("secp256k1_xonly_pubkey_parse() failed") + return pub + } + private fun MemScope.allocPublicNonce(pubnonce: ByteArray): secp256k1_musig_pubnonce { val nat = toNat(pubnonce) val nPubnonce = alloc() @@ -454,6 +462,413 @@ public object Secp256k1Native : Secp256k1 { } } + private fun MemScope.allocFrostShare(share: ByteArray): secp256k1_frost_share { + val nat = toNat(share) + val nFrostShare = alloc() + secp256k1_frost_share_parse(ctx, nFrostShare.ptr, nat).requireSuccess("secp256k1_frost_share_parse() failed") + return nFrostShare + } + + private fun MemScope.allocFrostPartialSignature(partialSignature: ByteArray): secp256k1_frost_partial_sig { + val nat = toNat(partialSignature) + val nPartialSignature = alloc() + secp256k1_frost_partial_sig_parse(ctx, nPartialSignature.ptr, nat).requireSuccess("secp256k1_frost_partial_sig_parse() failed") + return nPartialSignature + } + + private fun MemScope.allocFrostPublicNonce(pubnonce: ByteArray): secp256k1_frost_pubnonce { + val nat = toNat(pubnonce) + val nPublicNonce = alloc() + secp256k1_frost_pubnonce_parse(ctx, nPublicNonce.ptr, nat).requireSuccess("secp256k1_frost_pubnonce_parse() failed") + return nPublicNonce + } + + override fun frostSharesGen( + vssCommitment: Array, + pok64: ByteArray, + seed32: ByteArray, + totalSigners: Int, + ids33: Array + ): Array { + val threshold = vssCommitment.size + + TODO("Constraints not yet implemented") + memScoped { + val nShares = allocArray(ids33.size) + + val nVssCommitment = vssCommitment.map { + allocPublicKey(it).ptr + } + val nIds33s = ids33.map { toNat(it) } + + secp256k1_frost_shares_gen( + ctx = ctx, + shares = nShares, + vss_commitment = nVssCommitment.toCValues(), + pok64 = toNat(pok64), + seed32 = toNat(seed32), + threshold = threshold.convert(), + n_participants = ids33.size.convert(), + ids33 = nIds33s.toCValues() + ) + + // TODO: return serialized nShares + } + + } + + private fun MemScope.serializeFrostShare(nFrostShare: secp256k1_frost_share): ByteArray { + val natOutput = allocArray(Secp256k1.FROST_SHARE_SIZE) + secp256k1_frost_share_serialize(ctx, natOutput, nFrostShare.ptr).requireSuccess("secp256k1_frost_share_serialize() failed") + return natOutput.readBytes(Secp256k1.FROST_SERIALIZED_SHARE_SIZE) + } + + override fun frostShareAggregate( + totalShares: Array, + vssCommitments: Array>, + id33: ByteArray + ): Pair { + val threshold = vssCommitments.first().size + val totalShareCount = totalShares.size + + TODO("Constraints not yet implemented") + + memScoped { + val nAggShare = alloc() + val nAggPublicKey = alloc() + + val nTotalShares = totalShares.map { allocFrostShare(it).ptr } + val nVssCommitments = vssCommitments.map { vssCommitment -> + vssCommitment.map { + allocPublicKey(it).ptr + }.toCValues() + } + + secp256k1_frost_share_agg( + ctx = ctx, + agg_share = nAggShare.ptr, + agg_pk = nAggPublicKey.ptr, + shares = nTotalShares.toCValues(), + vss_commitments = nVssCommitments.toTypedArray(), + n_shares = totalShareCount.convert(), + threshold = threshold.convert(), + id33 = toNat(id33) + ) + + return Pair( + serializeFrostShare(nAggShare), + serializeXonlyPubkey(nAggPublicKey) + ) + } + + } + + override fun frostShareVerify( + threshold: Int, + id33: ByteArray, + share: ByteArray, + vssCommitment: Array + ): Int { + TODO("Constraints not yet implemented") + + memScoped { + + val nId33 = toNat(id33); + val nFrostShare = allocFrostShare(share) + val nPubkeys = vssCommitment.map { allocPublicKey(it).ptr } + + return secp256k1_frost_share_verify( + ctx = ctx, + threshold = threshold.convert(), + id33 = nId33, + share = nFrostShare.ptr, + vss_commitment = nPubkeys.toCValues() + ) + } + } + + override fun frostComputePublicShare(id33: ByteArray, vssCommitments: Array>): ByteArray { + + TODO("Constraints not yet implemented") + memScoped { + val nPubshare = alloc() + val totalSigners = vssCommitments.size + val threshold = vssCommitments.first().size + val nVssCommitments = vssCommitments.map { vssCommitment -> + vssCommitment.map { allocPublicKey(it).ptr } + } + secp256k1_frost_compute_pubshare( + ctx = ctx, + pubshare = nPubshare.ptr, + threshold = threshold.convert(), + id33 = toNat(id33), + vss_commitments = nVssCommitments, + n_participants = totalSigners.convert() + ) + + return serializePubkey(nPubshare) + } + } + + override fun frostPublicKeyTweak(pk: ByteArray): ByteArray { + TODO("Constraints not yet implemented") + memScoped { + val nTweakCache = alloc() + val nPublicKey = allocXonlyPublicKey(pk) + + secp256k1_frost_pubkey_tweak( + ctx = ctx, + tweak_cache = nTweakCache.ptr, + agg_pk = nPublicKey.ptr + ) + + return serializeFrostTweakCache(nTweakCache) + } + } + + override fun frostPublicKeyEcTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): ByteArray { + TODO("Constraints not yet implemented") + + memScoped { + val nTweakCache = alloc() + memcpy(nTweakCache.ptr, toNat(tweakCache), Secp256k1.FROST_TWEAK_CACHE_SIZE.toULong()) + val nPublicKey = alloc() + + secp256k1_frost_pubkey_ec_tweak_add( + ctx = ctx, + output_pubkey = nPublicKey.ptr, + tweak_cache = nTweakCache.ptr, + tweak32 = toNat(tweak32) + ) + return serializePubkey(nPublicKey) + } + } + + private fun MemScope.serializeFrostTweakCache(nTweakCache: secp256k1_frost_tweak_cache): ByteArray { + val natOutput = ByteArray(Secp256k1.FROST_TWEAK_CACHE_SIZE) + memcpy(toNat(natOutput), nTweakCache.ptr, Secp256k1.FROST_TWEAK_CACHE_SIZE.toULong()) + return natOutput + } + + override fun frostPublicKeyXonlyTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): Pair { + TODO("Constraints not yet implemented") + + memScoped { + val nPublicKey = alloc() + + val nTweakCache = alloc() + memcpy(nTweakCache.ptr, toNat(tweakCache), Secp256k1.FROST_TWEAK_CACHE_SIZE.toULong()) + + secp256k1_frost_pubkey_xonly_tweak_add( + ctx = ctx, + output_pubkey = nPublicKey.ptr, + tweak_cache = nTweakCache.ptr, + tweak32 = toNat(tweak32) + ) + + return Pair( + serializePubkey(nPublicKey), + serializeFrostTweakCache(nTweakCache) + ) + } + + } + + private fun MemScope.serializeFrostSecnonce(nTweakCache: secp256k1_frost_secnonce): ByteArray { + val natOutput = ByteArray(Secp256k1.FROST_SECNONCE_SIZE) + memcpy(toNat(natOutput), nTweakCache.ptr, Secp256k1.FROST_SECNONCE_SIZE.toULong()) + return natOutput + } + + private fun MemScope.serializeFrostPubnonce(nPubnonce: secp256k1_frost_pubnonce): ByteArray { + val natOutput = allocArray(Secp256k1.FROST_SERIALIZED_PUBNONCE_SIZE) + secp256k1_frost_pubnonce_serialize(ctx, natOutput, nPubnonce.ptr).requireSuccess("secp256k1_frost_pubnonce_serialize() failed") + return natOutput.readBytes(Secp256k1.FROST_SERIALIZED_PUBNONCE_SIZE) + } + + override fun frostNonceGen( + sessionId32: ByteArray, + share: ByteArray, + msg32: ByteArray, + publicKey: ByteArray, + extraInput32: ByteArray? + ): Pair { + TODO("Constraints not yet implemented") + + memScoped { + val nForstSecnonce = alloc() + val nPubnonce = alloc() + + val nShare = allocFrostShare(share) + val nPublicKey = allocXonlyPublicKey(publicKey) + val nExtraInput32 = extraInput32?.let { + toNat(it) + } + + secp256k1_frost_nonce_gen( + ctx = ctx, + secnonce = nForstSecnonce.ptr, + pubnonce = nPubnonce.ptr, + session_id32 = toNat(sessionId32), + agg_share = nShare.ptr, + msg32 = toNat(msg32), + agg_pk = nPublicKey.ptr, + extra_input32 = nExtraInput32 + ) + + return Pair( + serializeFrostSecnonce(nForstSecnonce), + serializeFrostPubnonce(nPubnonce) + ) + } + } + + private fun MemScope.serializeFrostSession(nSession: secp256k1_frost_session): ByteArray { + val natOutput = ByteArray(Secp256k1.FROST_SESSION_SIZE) + memcpy(toNat(natOutput), nSession.ptr, Secp256k1.FROST_SESSION_SIZE.toULong()) + return natOutput + } + + override fun frostNonceProcess( + publicNonces: Array, + msg32: ByteArray, + publicKey: ByteArray, + id33: ByteArray, + ids33: Array, + tweakCache: ByteArray, + adaptor: ByteArray? + ): ByteArray { + TODO("Constraint not yet implemented") + + memScoped { + val nSession = alloc(); + + val nPublicNonces = publicNonces.map { allocFrostPublicNonce(it).ptr } + + val nPublicKey = allocXonlyPublicKey(publicKey) + + val nIds33 = ids33.map { toNat(it) } + + val nTweakCache = alloc() + memcpy(nTweakCache.ptr, toNat(tweakCache), Secp256k1.FROST_TWEAK_CACHE_SIZE.toULong()) + + val nAdaptor = adaptor?.let { + allocPublicKey(it).ptr + } + secp256k1_frost_nonce_process( + ctx = ctx, + session = nSession.ptr, + pubnonces = nPublicNonces.toCValues(), + n_pubnonces = publicNonces.size.convert(), + msg32 = toNat(msg32), + agg_pk = nPublicKey.ptr, + my_id33 = toNat(id33), + ids33 = nIds33.toCValues(), + tweak_cache = nTweakCache.ptr, + adaptor = nAdaptor + ) + + return serializeFrostSession( + nSession = nSession + ) + } + + + } + + private fun MemScope.serializeFrostPartialSignature(nPartialSignature: secp256k1_frost_partial_sig): ByteArray { + val natOutput = allocArray(Secp256k1.FROST_SERIALIZED_PARTIAL_SIGNATURE_SIZE) + secp256k1_frost_partial_sig_serialize(ctx, natOutput, nPartialSignature.ptr).requireSuccess("secp256k1_frost_partial_sig_serialize() failed") + return natOutput.readBytes(Secp256k1.FROST_SERIALIZED_PARTIAL_SIGNATURE_SIZE) + } + + override fun frostPartialSign( + secnonce: ByteArray, + share: ByteArray, + session: ByteArray, + tweakCache: ByteArray + ): ByteArray { + TODO("Constraints not yet implemented") + + memScoped { + val nPartialSignature = alloc(); + + val nSecnonce = alloc() + memcpy(nSecnonce.ptr, toNat(secnonce), Secp256k1.FROST_SECNONCE_SIZE.toULong()) + + val nShare = allocFrostShare(share) + + 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()) + + secp256k1_frost_partial_sign( + ctx, + nPartialSignature.ptr, + nSecnonce.ptr, + nShare.ptr, + nSession.ptr, + nTweakCache.ptr + ) + + return serializeFrostPartialSignature(nPartialSignature) + } + } + + override fun frostPartialSignatureVerify( + partialSig: ByteArray, + publicNonce: ByteArray, + publicShare: ByteArray, + session: ByteArray, + tweakCache: ByteArray + ): Int { + TODO("Constraints not yet implemented") + + memScoped { + val nPartialSignature = allocFrostPartialSignature(partialSig) + val nPublicNonce = allocFrostPublicNonce(publicNonce) + 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()) + + return secp256k1_frost_partial_sig_verify( + ctx, + nPartialSignature.ptr, + nPublicNonce.ptr, + nPublicShare.ptr, + nSession.ptr, + nTweakCache.ptr + ) + } + } + + override fun frostPartialSignatureAggregate(session: ByteArray, partialSignatures: Array): ByteArray { + TODO("Not yet implemented") + + memScoped { + val sig64 = ByteArray(64) + + val nSession = alloc(); + memcpy(nSession.ptr, toNat(session), Secp256k1.FROST_SESSION_SIZE.toULong()) + val nPartialSignatures = partialSignatures.map { allocFrostPartialSignature(it).ptr } + + secp256k1_frost_partial_sig_agg( + ctx, + toNat(sig64), + nSession.ptr, + nPartialSignatures.toCValues(), + partialSignatures.size.convert() + ) + + return sig64 + } + + } + public override fun cleanup() { secp256k1_context_destroy(ctx) }