Use frost in Secp256k1 native logic

This commit is contained in:
kngako 2024-08-04 23:53:28 +02:00
parent 4826863644
commit 3c01a2aad4
12 changed files with 774 additions and 7 deletions

1
.gitignore vendored
View File

@ -15,3 +15,4 @@ local.properties
.DS_Store
jni/bin/*
jni/jvm/bin/*
/jni/src/main/java/fr/acinq/secp256k1/Secp256k1CFunctions.class

View File

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

View File

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

View File

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

View File

@ -129,6 +129,175 @@ public object NativeSecp256k1 : Secp256k1 {
return Secp256k1CFunctions.secp256k1_musig_partial_sig_agg(Secp256k1Context.getContext(), session, psigs)
}
override fun frostSharesGen(
vssCommitment: Array<ByteArray>,
pok64: ByteArray,
seed32: ByteArray,
totalSigners: Int,
ids33: Array<ByteArray>
): Array<ByteArray> {
return Secp256k1CFunctions.secp256k1_frost_shares_gen(
Secp256k1Context.getContext(),
vssCommitment,
pok64,
seed32,
totalSigners,
ids33
)
}
override fun frostShareAggregate(
totalShares: Array<ByteArray>,
vssCommitments: Array<Array<ByteArray>>,
id33: ByteArray
): Pair<ByteArray, ByteArray> {
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<ByteArray>
): Int {
return Secp256k1CFunctions.secp256k1_frost_share_verify(
Secp256k1Context.getContext(),
id33,
share,
vssCommitment
)
}
override fun frostComputePublicShare(
id33: ByteArray,
vssCommitments: Array<Array<ByteArray>>
): 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<ByteArray, ByteArray> {
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<ByteArray, ByteArray> {
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<ByteArray>,
msg32: ByteArray,
publicKey: ByteArray,
id33: ByteArray,
ids33: Array<ByteArray>,
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>): ByteArray {
return Secp256k1CFunctions.secp256k1_frost_partial_sig_aggregate(
Secp256k1Context.getContext(),
session,
partialSignatures
)
}
override fun cleanup() {
return Secp256k1CFunctions.secp256k1_context_destroy(Secp256k1Context.getContext())
}

View File

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

View File

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

View File

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

@ -1 +1 @@
Subproject commit df0bdeb09654ecedc7766dff700719959cf960cb
Subproject commit ac7967d79c0d69fd17aed5107481d2c5d9998cf8

View File

@ -271,6 +271,44 @@ public interface Secp256k1 {
*/
public fun musigPartialSigAgg(session: ByteArray, psigs: Array<ByteArray>): ByteArray
public fun frostSharesGen(vssCommitment: Array<ByteArray>, pok64: ByteArray, seed32: ByteArray, totalSigners: Int, ids33: Array<ByteArray>): Array<ByteArray>
/**
*
* 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<ByteArray>, vssCommitments: Array<Array<ByteArray>>, id33: ByteArray): Pair<ByteArray, ByteArray>
public fun frostShareVerify(threshold: Int, id33: ByteArray, share: ByteArray, vssCommitment: Array<ByteArray>): 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<Array<ByteArray>>): ByteArray
public fun frostPublicKeyTweak(pk: ByteArray): ByteArray
public fun frostPublicKeyEcTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): ByteArray
public fun frostPublicKeyXonlyTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): Pair<ByteArray, ByteArray>
public fun frostNonceGen(sessionId32: ByteArray, share: ByteArray, msg32: ByteArray, publicKey: ByteArray, extraInput32: ByteArray?): Pair<ByteArray, ByteArray>
/**
*
* threshold can be deduced from the size of the pubnonces array.
*/
public fun frostNonceProcess(publicNonces: Array<ByteArray>, msg32: ByteArray, publicKey: ByteArray, id33: ByteArray, ids33: Array<ByteArray>, 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>): 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
}
}

View File

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

View File

@ -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>()
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<secp256k1_musig_pubnonce>()
@ -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>()
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>()
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>()
secp256k1_frost_pubnonce_parse(ctx, nPublicNonce.ptr, nat).requireSuccess("secp256k1_frost_pubnonce_parse() failed")
return nPublicNonce
}
override fun frostSharesGen(
vssCommitment: Array<ByteArray>,
pok64: ByteArray,
seed32: ByteArray,
totalSigners: Int,
ids33: Array<ByteArray>
): Array<ByteArray> {
val threshold = vssCommitment.size
TODO("Constraints not yet implemented")
memScoped {
val nShares = allocArray<secp256k1_frost_share>(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<UByteVar>(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<ByteArray>,
vssCommitments: Array<Array<ByteArray>>,
id33: ByteArray
): Pair<ByteArray, ByteArray> {
val threshold = vssCommitments.first().size
val totalShareCount = totalShares.size
TODO("Constraints not yet implemented")
memScoped {
val nAggShare = alloc<secp256k1_frost_share>()
val nAggPublicKey = alloc<secp256k1_xonly_pubkey>()
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<ByteArray>
): 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<Array<ByteArray>>): ByteArray {
TODO("Constraints not yet implemented")
memScoped {
val nPubshare = alloc<secp256k1_pubkey>()
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<secp256k1_frost_tweak_cache>()
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<secp256k1_frost_tweak_cache>()
memcpy(nTweakCache.ptr, toNat(tweakCache), Secp256k1.FROST_TWEAK_CACHE_SIZE.toULong())
val nPublicKey = alloc<secp256k1_pubkey>()
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<ByteArray, ByteArray> {
TODO("Constraints not yet implemented")
memScoped {
val nPublicKey = alloc<secp256k1_pubkey>()
val nTweakCache = alloc<secp256k1_frost_tweak_cache>()
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<UByteVar>(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<ByteArray, ByteArray> {
TODO("Constraints not yet implemented")
memScoped {
val nForstSecnonce = alloc<secp256k1_frost_secnonce>()
val nPubnonce = alloc<secp256k1_frost_pubnonce>()
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<ByteArray>,
msg32: ByteArray,
publicKey: ByteArray,
id33: ByteArray,
ids33: Array<ByteArray>,
tweakCache: ByteArray,
adaptor: ByteArray?
): ByteArray {
TODO("Constraint not yet implemented")
memScoped {
val nSession = alloc<secp256k1_frost_session>();
val nPublicNonces = publicNonces.map { allocFrostPublicNonce(it).ptr }
val nPublicKey = allocXonlyPublicKey(publicKey)
val nIds33 = ids33.map { toNat(it) }
val nTweakCache = alloc<secp256k1_frost_tweak_cache>()
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<UByteVar>(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<secp256k1_frost_partial_sig>();
val nSecnonce = alloc<secp256k1_frost_secnonce>()
memcpy(nSecnonce.ptr, toNat(secnonce), Secp256k1.FROST_SECNONCE_SIZE.toULong())
val nShare = allocFrostShare(share)
val nSession = alloc<secp256k1_frost_session>()
memcpy(nSession.ptr, toNat(session), Secp256k1.FROST_SESSION_SIZE.toULong())
val nTweakCache = alloc<secp256k1_frost_tweak_cache>()
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<secp256k1_frost_session>()
memcpy(nSession.ptr, toNat(session), Secp256k1.FROST_SESSION_SIZE.toULong())
val nTweakCache = alloc<secp256k1_frost_tweak_cache>()
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>): ByteArray {
TODO("Not yet implemented")
memScoped {
val sig64 = ByteArray(64)
val nSession = alloc<secp256k1_frost_session>();
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)
}