Compare commits

..

No commits in common. "frost" and "master" have entirely different histories.

23 changed files with 44 additions and 3179 deletions

3
.gitignore vendored
View File

@ -13,6 +13,3 @@ local.properties
# OS
.DS_Store
jni/bin/*
jni/jvm/bin/*
/jni/src/main/java/fr/acinq/secp256k1/Secp256k1CFunctions.class

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "native/secp256k1"]
path = native/secp256k1
url = https://code.sigidli.com/frost/secp256k1-zkp.git
url = https://github.com/jonasnick/secp256k1.git

View File

@ -22,7 +22,7 @@ buildscript {
allprojects {
group = "fr.acinq.secp256k1"
version = "frost-SNAPSHOT"
version = "0.16.0-SNAPSHOT"
repositories {
google()
@ -58,28 +58,25 @@ kotlin {
secp256k1CInterop("host")
}
if (currentOs.isMacOsX) {
macosX64 {
secp256k1CInterop("host")
}
macosArm64 {
secp256k1CInterop("host")
}
iosX64 {
secp256k1CInterop("ios")
}
iosArm64 {
secp256k1CInterop("ios")
}
iosSimulatorArm64 {
secp256k1CInterop("ios")
}
macosX64 {
secp256k1CInterop("host")
}
macosArm64 {
secp256k1CInterop("host")
}
iosX64 {
secp256k1CInterop("ios")
}
iosArm64 {
secp256k1CInterop("ios")
}
iosSimulatorArm64 {
secp256k1CInterop("ios")
}
sourceSets.all {
languageSettings.optIn("kotlin.RequiresOptIn")

View File

@ -35,15 +35,6 @@ extern "C" {
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_KEYAGG_CACHE_SIZE 197L
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE 133L
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FROST_SECRET_NONCE_SIZE
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FROST_SECRET_NONCE_SIZE 68L
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FROST_PUBLIC_NONCE_SIZE
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FROST_PUBLIC_NONCE_SIZE 66L
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FROST_AGGREGATE_SHARE_SIZE
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FROST_AGGREGATE_SHARE_SIZE 32L
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FROST_SESSION_SIZE
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FROST_SESSION_SIZE 133L
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_context_create
@ -276,102 +267,6 @@ 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[BII[[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1shares_1gen
(JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jint, jint, jobjectArray);
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_frost_share_agg
* Signature: (J[[B[[[BII[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1share_1agg
(JNIEnv *, jclass, jlong, jobjectArray, jobjectArray, jint, jint, jbyteArray);
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_frost_share_verify
* Signature: (JI[B[B[[B)I
*/
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1share_1verify
(JNIEnv *, jclass, jlong, jint, jbyteArray, jbyteArray, jobjectArray);
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_frost_compute_pubshare
* Signature: (JI[B[[[BI)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1compute_1pubshare
(JNIEnv *, jclass, jlong, jint, jbyteArray, jobjectArray, jint);
/*
* 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)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1pubkey_1ec_1tweak_1add
(JNIEnv *, jclass, jlong, jbyteArray, jbyteArray);
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_frost_pubkey_xonly_tweak_add
* Signature: (J[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1pubkey_1xonly_1tweak_1add
(JNIEnv *, jclass, jlong, jbyteArray, jbyteArray);
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_frost_nonce_gen
* Signature: (J[B[B[B[B[B)[B
*/
JNIEXPORT jbyteArray 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[[BI[B[B[B[[B[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1nonce_1process
(JNIEnv *, jclass, jlong, jobjectArray, jint, 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_agg
* Signature: (J[B[[BI)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1partial_1sig_1agg
(JNIEnv *, jclass, jlong, jbyteArray, jobjectArray, jint);
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,13 @@
import org.gradle.internal.os.OperatingSystem
plugins {
`java-library`
id("org.jetbrains.dokka")
`maven-publish`
}
val currentOs = OperatingSystem.current()
dependencies {
val publishModeEnabled = rootProject.hasProperty("publishMode") // TODO: Add a -PpublishMode argument to the build script specifically for publishing a release (not when publishing local).
println("publishModeEnabled: $publishModeEnabled")
if (publishModeEnabled || currentOs.isMacOsX) {
api(project(":jni:jvm:darwin"))
}
if (publishModeEnabled || currentOs.isLinux) {
api(project(":jni:jvm:linux"))
}
if (publishModeEnabled || currentOs.isWindows) {
api(project(":jni:jvm:mingw"))
}
api(project(":jni:jvm:darwin"))
api(project(":jni:jvm:linux"))
api(project(":jni:jvm:mingw"))
}
publishing {

View File

@ -106,293 +106,4 @@ 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);
/**
* Creates key shares
*
* To generate a key, each participant generates a share for each other
* participant. For example, in the case of 2 particpants, Alice and Bob, they
* each generate 2 shares, distribute 1 share to each other using a secure
* channel, and keep 1 for themselves.
*
* Each participant must transmit shares over secure channels to each other
* participant.
*
* Each call to this function must have a UNIQUE and uniformly RANDOM seed32
* that must NOT BE REUSED in subsequent calls to this function and
* must be KEPT SECRET (even from other participants).
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param seed32 32-byte random seed as explained above. Must be unique to this call to secp256k1_frost_shares_gen
* and must be uniformly random.
* @param threshold the minimum number of signers required to produce a signature
* @param total_signers the total number of participants
* @param ids33 array of 33-byte participant IDs
*
* @return
* [0] shares: pointer to the key shares
* [1] vss_commitment: pointer to the VSS commitment
* [2] pok64: pointer to the proof of knowledge
*/
public static native byte[] secp256k1_frost_shares_gen(long ctx, byte[] pok64, byte[] seed32, int threshold, int total_signers, byte[][] ids33);
/**
* Aggregates shares
*
* As part of the key generation protocol, each participant receives a share
* from each participant, including a share they "receive" from themselves.
* This function verifies those shares against their VSS commitments,
* aggregates the shares, and then aggregates the commitments to each
* participant's first polynomial coefficient to derive the aggregate public
* key.
*
* If this function returns an error, `secp256k1_frost_share_verify` can be
* called on each share to determine which participants submitted faulty
* shares.
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param shares all key generation shares for the partcipant's index
* @param vss_commitments coefficient commitments of all participants ordered by the x-only pubkeys of the participants
* @param totalShareCount the total number of shares
* @param threshold the minimum number of shares required to produce a signature
* @param id33 the 33-byte ID of the participant whose shares are being aggregated
*
* @return
* [0] agg_share: the aggregated share
* [1] agg_pk: the aggregated x-only public key
*/
public static native byte[] secp256k1_frost_share_agg(long ctx, byte[][] shares, byte[][][] vss_commitments, int totalShareCount, int threshold, byte[] id33);
/**
* Verifies a share received during a key generation session
*
* The signature is verified against the VSS commitment received with the
* share. This is only useful for purposes of determining which share(s) are
* invalid if share_agg returns an error.
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param threshold the minimum number of signers required to produce a signature
* @param id33 the 33-byte participant ID of the share recipient
* @param share pointer to a key generation share
* @param vss_commitment the VSS commitment associated with the share
*
* @return 0 if the arguments are invalid or the share does not verify, 1 otherwise
*/
public static native int secp256k1_frost_share_verify(long ctx, int threshold, byte[] id33, byte[] share, byte[][] vss_commitment);
/**
* Computes a public verification share used for verifying partial signatures
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param threshold the minimum number of signers required to produce a signature
* @param id33 the 33-byte participant ID of the participant whose partial signature will be verified with
* the pubshare
* @param vss_commitments coefficient commitments of all participants
* @param totalSignersCount the total number of participants
*
* @return pubshare: pointer to a struct to store the public verification share
*/
public static native byte[] secp256k1_frost_compute_pubshare(long ctx, int threshold, byte[] id33, byte[][][] vss_commitments, int totalSignersCount);
/**
* Initializes a tweak cache used for applying tweaks to a FROST key
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param public_key the aggregated x-only public key that is the output of `secp256k1_frost_share_agg`
*
* @return tweak_cache: pointer to a frost_tweak_cache struct that is required for key tweaking
*/
public static native byte[] secp256k1_frost_pubkey_tweak(long ctx, byte[] public_key);
/**
* Apply ordinary "EC" tweaking to a public key in a given tweak_cache by
* adding the generator multiplied with `tweak32` to it. This is useful for
* deriving child keys from an aggregate public key via BIP32.
*
* The tweaking method is the same as `secp256k1_ec_pubkey_tweak_add`. So after
* the following pseudocode buf and buf2 have identical contents (absent
* earlier failures).
*
* secp256k1_frost_share_agg(..., xonly_agg_pk, ...)
* secp256k1_frost_pubkey_tweak(..., tweak_cache, xonly_agg_pk)
* secp256k1_frost_pubkey_ec_tweak_add(..., output_pk, tweak_cache, tweak32)
* secp256k1_ec_pubkey_serialize(..., buf, output_pk)
* secp256k1_frost_pubkey_get(..., ec_agg_pk, xonly_agg_pk)
* secp256k1_ec_pubkey_tweak_add(..., ec_agg_pk, tweak32)
* secp256k1_ec_pubkey_serialize(..., buf2, ec_agg_pk)
*
* This function is required if you want to _sign_ for a tweaked aggregate key.
* On the other hand, if you are only computing a public key, but not intending
* to create a signature for it, you can just use
* `secp256k1_ec_pubkey_tweak_add`.
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param tweakCache pointer to a `frost_tweak_cache` struct initialized by `frost_pubkey_tweak`
* @param tweak32 pointer to a 32-byte tweak. If the tweak is invalid according to `secp256k1_ec_seckey_verify`,
* 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.
*/
public static native byte[] secp256k1_frost_pubkey_ec_tweak_add(long ctx, byte[] tweakCache, byte[] tweak32);
/**
* Apply x-only tweaking to a public key in a given tweak_cache by adding the
* generator multiplied with `tweak32` to it. This is useful for creating
* Taproot outputs.
*
* The tweaking method is the same as `secp256k1_xonly_pubkey_tweak_add`. So in
* the following pseudocode xonly_pubkey_tweak_add_check (absent earlier
* failures) returns 1.
*
* secp256k1_frost_share_agg(..., agg_pk, ...)
* secp256k1_frost_pubkey_tweak(..., tweak_cache, agg_pk)
* secp256k1_frost_pubkey_xonly_tweak_add(..., output_pk, tweak_cache, tweak32)
* secp256k1_xonly_pubkey_serialize(..., buf, output_pk)
* secp256k1_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32)
*
* This function is required if you want to _sign_ for a tweaked aggregate key.
* On the other hand, if you are only computing a public key, but not intending
* to create a signature for it, you can just use
* `secp256k1_xonly_pubkey_tweak_add`.
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param tweakCache pointer to a `frost_tweak_cache` struct initialized by `frost_pubkey_tweak`
* @param tweak32 pointer to a 32-byte tweak. If the tweak is invalid according to secp256k1_ec_seckey_verify,
* this function returns 0. For uniformly random 32-byte arrays the
* chance of being invalid is negligible (around 1 in 2^128).
*
* @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);
/**
* Starts a signing session by generating a nonce
*
* This function outputs a secret nonce that will be required for signing and a
* corresponding public nonce that is intended to be sent to other signers.
*
* FROST, like MuSig, differs from regular Schnorr signing in that
* implementers _must_ take special care to not reuse a nonce. This can be
* ensured by following these rules:
*
* 1. Each call to this function must have a UNIQUE session_id32 that must NOT BE
* REUSED in subsequent calls to this function.
* If you do not provide a seckey, session_id32 _must_ be UNIFORMLY RANDOM
* AND KEPT SECRET (even from other signers). If you do provide a seckey,
* session_id32 can instead be a counter (that must never repeat!). However,
* it is recommended to always choose session_id32 uniformly at random.
* 2. If you already know the seckey, message or aggregate public key, they
* can be optionally provided to derive the nonce and increase
* misuse-resistance. The extra_input32 argument can be used to provide
* additional data that does not repeat in normal scenarios, such as the
* current time.
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
* that it is used more than once for signing.
*
* Remember that nonce reuse will leak the secret key!
* Note that using the same agg_share for multiple FROST sessions is fine.
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param sessionId32 a 32-byte session_id32 as explained above. Must be unique to this call to
* secp256k1_frost_nonce_gen and must be uniformly random unless you really know what you
* are doing.
* @param share the aggregated share that will later be used for signing, if already known (can be NULL)
* @param msg32 the 32-byte message that will later be signed, if already known (can be NULL)
* @param publicKey the FROST-aggregated public key (can be NULL)
* @param extraInput32 an optional 32-byte array that is input to the nonce derivation function (can be NULL)
* @return
* [0] secnonce: pointer to a structure to store the secret nonce
* [1] pubnonce: pointer to a structure to store the public nonce
*/
public static native byte[] secp256k1_frost_nonce_gen(long ctx, byte[] sessionId32, byte[] share, byte[] msg32, byte[] publicKey, byte[] extraInput32);
/**
* Takes the public nonces of all signers and computes a session that is
* required for signing and verification of partial signatures. The participant
* IDs can be sorted before combining, but the corresponding pubnonces must be
* resorted as well. All signers must use the same sorting of pubnonces,
* otherwise signing will fail.
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param pubnonces array of pointers to public nonces sent by the signers
* @param msg32 the 32-byte message to sign
* @param publicKey the FROST-aggregated public key
* @param id33 the 33-byte ID of the participant who will use the session for signing
* @param ids33 array of the 33-byte participant IDs of the signers
* @param tweakCache pointer to frost_tweak_cache struct (can be NULL)
* @param adaptor optional pointer to an adaptor point encoded as a public key if this signing session is part
* of an adaptor signature protocol (can be NULL)
*
* @return session: pointer to a struct to store the session
*/
public static native byte[] secp256k1_frost_nonce_process(long ctx, byte[][] pubnonces, int n_pubnonces, byte[] msg32, byte[] publicKey, byte[] id33, byte[][] ids33, byte[] tweakCache, byte[] adaptor);
/**
* Produces a partial signature
*
* This function overwrites the given secnonce with zeros and will abort if given a
* secnonce that is all zeros. This is a best effort attempt to protect against nonce
* reuse. However, this is of course easily defeated if the secnonce has been
* copied (or serialized). Remember that nonce reuse will leak the secret key!
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param secnonce (IS ALSO OUTPUT)pointer to the secnonce struct created in frost_nonce_gen that has been never used in a
* partial_sign call before
* @param share the aggregated share
* @param session pointer to the session that was created with frost_nonce_process
* @param tweak_cache pointer to frost_tweak_cache struct (can be NULL)
*
* @return
* 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
*
*/
public static native byte[] secp256k1_frost_partial_sign(long ctx, byte[] secnonce, byte[] share, byte[] session, byte[] tweak_cache);
/**
* Verifies an individual signer's partial signature
*
* The signature is verified for a specific signing session. In order to avoid
* accidentally verifying a signature from a different or non-existing signing
* session, you must ensure the following:
* 1. The `tweak_cache` argument is identical to the one used to create the
* `session` with `frost_nonce_process`.
* 2. The `pubshare` argument must be the output of
* `secp256k1_frost_compute_pubshare` for the signer's ID.
* 3. The `pubnonce` argument must be identical to the one sent by the
* signer and used to create the `session` with `frost_nonce_process`.
*
* This function can be used to assign blame for a failed signature.
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param partialSig pointer to partial signature to verify, sent by the signer associated with `pubnonce` and `pubkey`
* @param publicNonce public nonce of the signer in the signing session
* @param publicShare public verification share of the signer in the signing session that is the output of
* `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);
/**
* Aggregates partial signatures
*
* @param ctx pointer to a context object (not secp256k1_context_static)
* @param session pointer to the session that was created with frost_nonce_process
* @param partialSignatures array of pointers to partial signatures to aggregate
* @param n_sigs number of elements in the partial_sigs array. Must be greater than 0.
*
* @return sig64: complete (but possibly invalid) Schnorr signature
*/
public static native byte[] secp256k1_frost_partial_sig_agg(long ctx, byte[] session, byte[][] partialSignatures, int n_sigs);
}

View File

@ -129,211 +129,6 @@ public object NativeSecp256k1 : Secp256k1 {
return Secp256k1CFunctions.secp256k1_musig_partial_sig_agg(Secp256k1Context.getContext(), session, psigs)
}
override fun frostSharesGen(
seed32: ByteArray,
threshold: Int,
totalSigners: Int,
ids33: Array<ByteArray>
): Triple<Array<ByteArray>, Array<ByteArray>, ByteArray> {
val pok64 = ByteArray(64)
val result = Secp256k1CFunctions.secp256k1_frost_shares_gen(
Secp256k1Context.getContext(),
pok64,
seed32,
threshold,
totalSigners,
ids33
)
println(Hex.encode(result))
val shares = Array(totalSigners) { index ->
val startIndex = 0 + (index*32);
val endIndex = 31 + (index*32);
result.sliceArray(
startIndex..endIndex
)
}
val sharesOffset = totalSigners*32;
val vssCommitment = Array(threshold) { index ->
val startIndex = sharesOffset + (index*65);
val endIndex = sharesOffset + 64 + (index*65);
result.sliceArray(
startIndex..endIndex
)
}
return Triple(
shares,
vssCommitment,
pok64
)
}
override fun frostShareAggregate(
totalShares: Array<ByteArray>,
vssCommitments: Array<Array<ByteArray>>,
totalShareCount: Int,
threshold: Int,
id33: ByteArray
): Pair<ByteArray, ByteArray> {
val result = Secp256k1CFunctions.secp256k1_frost_share_agg(
Secp256k1Context.getContext(),
totalShares,
vssCommitments,
totalShareCount,
threshold,
id33
)
return Pair(
result.take(Secp256k1.FROST_SERIALIZED_SHARE_SIZE).toByteArray(), // agg_share
result.takeLast(Secp256k1.SERIALIZED_X_ONLY_PUBKEY_SIZE).toByteArray() // agg_pk
)
}
override fun frostShareVerify(
threshold: Int,
id33: ByteArray,
share: ByteArray,
vssCommitment: Array<ByteArray>
): Int {
return Secp256k1CFunctions.secp256k1_frost_share_verify(
Secp256k1Context.getContext(),
threshold,
id33,
share,
vssCommitment
)
}
override fun frostComputePublicShare(
threshold: Int,
id33: ByteArray,
vssCommitments: Array<Array<ByteArray>>,
totalSignersCount: Int
): ByteArray {
return Secp256k1CFunctions.secp256k1_frost_compute_pubshare(
Secp256k1Context.getContext(),
threshold,
id33,
vssCommitments,
totalSignersCount
)
}
override fun frostPublicKeyTweak(xOnlyPublicKey: ByteArray): ByteArray {
return Secp256k1CFunctions.secp256k1_frost_pubkey_tweak(
Secp256k1Context.getContext(),
xOnlyPublicKey
)
}
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): ByteArray? {
return Secp256k1CFunctions.secp256k1_frost_pubkey_xonly_tweak_add(
Secp256k1Context.getContext(),
tweakCache,
tweak32
)
}
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.take(Secp256k1.FROST_SECNONCE_SIZE).toByteArray(), // secnonce
result.takeLast(Secp256k1.FROST_SERIALIZED_PUBNONCE_SIZE).toByteArray() // pubnonce
)
}
override fun frostNonceProcess(
publicNonces: Array<ByteArray>,
threshold: Int,
msg32: ByteArray,
publicKey: ByteArray,
id33: ByteArray,
ids33: Array<ByteArray>,
tweakCache: ByteArray?,
adaptor: ByteArray?
): ByteArray {
return Secp256k1CFunctions.secp256k1_frost_nonce_process(
Secp256k1Context.getContext(),
publicNonces,
threshold,
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>, threshold: Int): ByteArray {
return Secp256k1CFunctions.secp256k1_frost_partial_sig_agg(
Secp256k1Context.getContext(),
session,
partialSignatures,
threshold
)
}
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-module-frost --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-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-module-frost --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-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-module-frost --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-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
make clean
make

@ -1 +1 @@
Subproject commit 69d5e6bdc1ec8b472138aaba9804b93d46f397bb
Subproject commit dd4932b67b573b2366e729e869918b17964f5f83

View File

@ -271,44 +271,6 @@ public interface Secp256k1 {
*/
public fun musigPartialSigAgg(session: ByteArray, psigs: Array<ByteArray>): ByteArray
public fun frostSharesGen(seed32: ByteArray, threshold: Int, totalSigners: Int, ids33: Array<ByteArray>): Triple<Array<ByteArray>,Array<ByteArray>, 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>>, totalShareCount: Int, threshold: Int, 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(threshold: Int, id33: ByteArray, vssCommitments: Array<Array<ByteArray>>, totalSignersCount: Int): ByteArray
public fun frostPublicKeyTweak(xOnlyPublicKey: ByteArray): ByteArray
public fun frostPublicKeyEcTweakAdd(tweakCache: ByteArray, tweak32: ByteArray): ByteArray?
public fun frostPublicKeyXonlyTweakAdd(tweakCache: ByteArray, tweak32: 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>, threshold: Int, 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>, threshold: Int): ByteArray
/**
* Delete the secp256k1 context from dynamic memory.
*/
@ -319,24 +281,10 @@ public interface Secp256k1 {
public fun get(): Secp256k1 = this
// @formatter:off
public const val X_ONLY_PUBKEY_SIZE: Int = 64
public const val SERIALIZED_X_ONLY_PUBKEY_SIZE: Int = 32
public const val MUSIG2_SECRET_NONCE_SIZE: Int = 132
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 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
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
staticLibraries.linux = libsecp256k1.a
libraryPaths.linux = c/secp256k1/build/linux/ native/build/linux/ native/build/darwin/

View File

@ -1,8 +1,6 @@
package fr.acinq.secp256k1
import fr.acinq.secp256k1.Secp256k1Native.toNat
import kotlinx.cinterop.*
import kotlinx.cinterop.ptr
import platform.posix.memcpy
import platform.posix.size_tVar
import secp256k1.*
@ -43,13 +41,6 @@ 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>()
@ -356,7 +347,7 @@ public object Secp256k1Native : Secp256k1 {
memcpy(n.ptr, toNat(it), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
n
}
secp256k1_musig_pubkey_agg(ctx, null, combined.ptr, nKeyAggCache?.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess("secp256k1_musig_nonce_agg() failed")
secp256k1_musig_pubkey_agg(ctx, combined.ptr, nKeyAggCache?.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess("secp256k1_musig_nonce_agg() failed")
val agg = serializeXonlyPubkey(combined)
keyaggCache?.let { blob -> nKeyAggCache?.let { memcpy(toNat(blob), it.ptr, Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong()) } }
return agg
@ -399,7 +390,7 @@ public object Secp256k1Native : Secp256k1 {
val nSession = alloc<secp256k1_musig_session>()
val nAggnonce = alloc<secp256k1_musig_aggnonce>()
secp256k1_musig_aggnonce_parse(ctx, nAggnonce.ptr, toNat(aggnonce)).requireSuccess("secp256k1_musig_aggnonce_parse() failed")
secp256k1_musig_nonce_process(ctx, nSession.ptr, nAggnonce.ptr, toNat(msg32), nKeyAggCache.ptr, null).requireSuccess("secp256k1_musig_nonce_process() failed")
secp256k1_musig_nonce_process(ctx, nSession.ptr, nAggnonce.ptr, toNat(msg32), nKeyAggCache.ptr).requireSuccess("secp256k1_musig_nonce_process() failed")
val session = ByteArray(Secp256k1.MUSIG2_PUBLIC_SESSION_SIZE)
memcpy(toNat(session), nSession.ptr, Secp256k1.MUSIG2_PUBLIC_SESSION_SIZE.toULong())
return session
@ -463,532 +454,6 @@ 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(
seed32: ByteArray,
threshold: Int,
totalSigners: Int,
ids33: Array<ByteArray>
): Triple<Array<ByteArray>, Array<ByteArray>, ByteArray> {
require(seed32.size == 32) { "seed size should be 32" }
require(threshold > 1) { "threshold cannot be less then 1" }
require(threshold <= totalSigners) { "threshold($threshold) cannot be greater then totalSigners ($totalSigners)" }
require(ids33.size == totalSigners) { "ids33 size need to be the same as totalSigners size" }
ids33.forEach { require(it.size == 33) { "id33 size must be 33" } }
memScoped {
val nShares = allocArray<secp256k1_frost_share>(ids33.size)
val nVssCommitment = allocArray<secp256k1_pubkey>(threshold)
val pok64 = ByteArray(64)
val nIds33s = ids33.map { toNat(it) }
secp256k1_frost_shares_gen(
ctx = ctx,
shares = nShares,
vss_commitment = nVssCommitment,
pok64 = toNat(pok64),
seed32 = toNat(seed32),
threshold = threshold.convert(),
n_participants = ids33.size.convert(),
ids33 = nIds33s.toCValues()
)
return Triple(
ids33.indices.map { serializeFrostShare(nShares[it]) }.toTypedArray(),
(0 until threshold).map { serializePubkey(nVssCommitment[it]) }.toTypedArray(),
pok64
)
}
}
private fun MemScope.serializeFrostShare(nFrostShare: secp256k1_frost_share): ByteArray {
val natOutput = allocArray<UByteVar>(Secp256k1.FROST_SERIALIZED_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>>,
totalShareCount: Int,
threshold: Int,
id33: ByteArray
): Pair<ByteArray, ByteArray> {
require(totalShares.size == totalShareCount) { "totalShare array size (${totalShares.size}) should be the same as total share count ($totalShareCount)" }
totalShares.forEach { require(it.size == 32) { "all shares should be of size 32" } }
require(vssCommitments.size == totalShareCount) { "vssCommitments array size ${vssCommitments.size} should be the same as total share count ($totalShareCount)" }
vssCommitments.forEach { vssCommitment ->
require(vssCommitment.size == threshold) { "all vss commitment array size (${vssCommitment.size}) should be the same as the threshold size ($threshold)" }
vssCommitment.forEach { publicKey ->
require(publicKey.size == 33 || publicKey.size == 65) { "vss commitment data size should be 33 or 65" }
}
}
require(threshold > 1) { "threshold should be greater then 1" }
require(threshold <= totalShareCount) { "Threshold can not be greater then the total share count" }
require(id33.size == 33) { "id size should be 33" }
memScoped {
val nAggregateShare = alloc<secp256k1_frost_share>()
val nAggregatePublicKey = alloc<secp256k1_xonly_pubkey>()
val nTotalShares = totalShares.map { allocFrostShare(it).ptr }
val nVssCommitments = allocArray<CPointerVar<secp256k1_pubkey>>(vssCommitments.size)
vssCommitments.forEachIndexed { index, commitments ->
val pubkeyArray = allocArray<secp256k1_pubkey>(commitments.size)
commitments.forEachIndexed { commitmentIndex, pubkeyData ->
if (secp256k1_ec_pubkey_parse(ctx, pubkeyArray[commitmentIndex].ptr, toNat(pubkeyData), pubkeyData.size.convert()) == 0) {
error("Failed to parse public key")
}
}
nVssCommitments[index] = pubkeyArray
}
val result = secp256k1_frost_share_agg(
ctx = ctx,
agg_share = nAggregateShare.ptr,
agg_pk = nAggregatePublicKey.ptr,
shares = nTotalShares.toCValues(),
vss_commitments = nVssCommitments,
n_shares = totalShareCount.convert(),
threshold = threshold.convert(),
id33 = toNat(id33)
)
println("Aggregate Result: $result")
return Pair(
serializeFrostShare(nAggregateShare),
serializeXonlyPubkey(nAggregatePublicKey)
)
}
}
override fun frostShareVerify(
threshold: Int,
id33: ByteArray,
share: ByteArray,
vssCommitment: Array<ByteArray>
): Int {
require(threshold > 1) { "threshold should be greater then 1" }
require(id33.size == 33) { "id size (${id33.size}) should be 33" }
require(share.size == Secp256k1.FROST_SERIALIZED_SHARE_SIZE) { "share size (${share.size}) should be of size ${Secp256k1.FROST_SERIALIZED_SHARE_SIZE}" }
require(vssCommitment.size == threshold) { "vss commitment array size (${vssCommitment.size}) should be the same as the threshold size ($threshold)" }
vssCommitment.forEach { publicKey ->
require(publicKey.size == 33 || publicKey.size == 65) { "vss commitment data size should be 33 or 65" }
}
memScoped {
val nFrostShare = allocFrostShare(share)
val nVssCommitments = allocArray<CPointerVar<secp256k1_pubkey>>(1)
val pubkeyArray = allocArray<secp256k1_pubkey>(vssCommitment.size)
vssCommitment.forEachIndexed { commitmentIndex, pubkeyData ->
if (secp256k1_ec_pubkey_parse(ctx, pubkeyArray[commitmentIndex].ptr, toNat(pubkeyData), pubkeyData.size.convert()) == 0) {
error("Failed to parse public key")
}
}
nVssCommitments[0] = pubkeyArray
return secp256k1_frost_share_verify(
ctx = ctx,
threshold = threshold.convert(),
id33 = toNat(id33),
share = nFrostShare.ptr,
vss_commitment = nVssCommitments
)
}
}
override fun frostComputePublicShare(
threshold: Int,
id33: ByteArray,
vssCommitments: Array<Array<ByteArray>>,
totalSignersCount: Int
): ByteArray {
require(threshold > 1)
require(threshold <= totalSignersCount)
require(id33.size == 33)
require(vssCommitments.size == totalSignersCount)
vssCommitments.forEach { vssCommitment ->
require(vssCommitment.size == threshold)
vssCommitment.forEach { publicKey ->
require(publicKey.size == 33 || publicKey.size == 65)
}
}
memScoped {
val nPublicShare = alloc<secp256k1_pubkey>()
val nVssCommitments = allocArray<CPointerVar<secp256k1_pubkey>>(vssCommitments.size)
vssCommitments.forEachIndexed { index, commitments ->
val pubkeyArray = allocArray<secp256k1_pubkey>(commitments.size)
commitments.forEachIndexed { commitmentIndex, pubkeyData ->
if (secp256k1_ec_pubkey_parse(ctx, pubkeyArray[commitmentIndex].ptr, toNat(pubkeyData), pubkeyData.size.convert()) == 0) {
error("Failed to parse public key")
}
}
nVssCommitments[index] = pubkeyArray
}
val result = secp256k1_frost_compute_pubshare(
ctx = ctx,
pubshare = nPublicShare.ptr,
threshold = threshold.convert(),
id33 = toNat(id33),
vss_commitments = nVssCommitments,
n_participants = totalSignersCount.convert()
)
println("Compute pubshare result: $result")
return serializePubkey(nPublicShare)
}
}
override fun frostPublicKeyTweak(xOnlyPublicKey: ByteArray): ByteArray {
require(xOnlyPublicKey.size == Secp256k1.SERIALIZED_X_ONLY_PUBKEY_SIZE) { "pubkey size (${xOnlyPublicKey.size}) should be ${Secp256k1.SERIALIZED_X_ONLY_PUBKEY_SIZE}" }
memScoped {
val nTweakCache = alloc<secp256k1_frost_tweak_cache>()
val nPublicKey = allocXonlyPublicKey(xOnlyPublicKey)
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 {
require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE)
require(tweak32.size == 32)
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): ByteArray? {
require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE)
require(tweak32.size == 32)
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 serializePubkey(nPublicKey)
}
}
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> {
require(sessionId32.size == 32) { "session id (${sessionId32.size}) size should be 32" }
share?.let {
require(share.size == Secp256k1.FROST_SERIALIZED_SHARE_SIZE) { "share size (${share.size}) should be ${Secp256k1.FROST_SERIALIZED_SHARE_SIZE}" }
}
msg32?.let {
require(msg32.size == 32) { "msg32 (${sessionId32.size}) size should be 32" }
}
publicKey?.let {
require(publicKey.size == 32) { "public key (${publicKey.size}) should be 32" }
}
extraInput32?.let {
require(it.size == 32) { "extraInput32 (${extraInput32.size}) size should be 32" }
}
memScoped {
val nFrostSecnonce = alloc<secp256k1_frost_secnonce>()
val nPublicNonce = alloc<secp256k1_frost_pubnonce>()
val nShare = share?.let { allocFrostShare(it) }
val nPublicKey = publicKey?.let { allocXonlyPublicKey(it) }
val nExtraInput32 = extraInput32?.let {
toNat(it)
}
secp256k1_frost_nonce_gen(
ctx = ctx,
secnonce = nFrostSecnonce.ptr,
pubnonce = nPublicNonce.ptr,
session_id32 = toNat(sessionId32),
agg_share = nShare?.ptr,
msg32 = msg32?.let { toNat(it) },
agg_pk = nPublicKey?.ptr,
extra_input32 = nExtraInput32
)
return Pair(
serializeFrostSecnonce(nFrostSecnonce),
serializeFrostPubnonce(nPublicNonce)
)
}
}
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>,
threshold: Int,
msg32: ByteArray,
publicKey: ByteArray,
id33: ByteArray,
ids33: Array<ByteArray>,
tweakCache: ByteArray?,
adaptor: ByteArray?
): ByteArray {
publicNonces.forEach { publicNonce ->
require(publicNonce.size == Secp256k1.FROST_SERIALIZED_PUBNONCE_SIZE) { "pubnonce size (${publicNonce.size}) size should be ${Secp256k1.FROST_SERIALIZED_PUBNONCE_SIZE}" }
}
require(msg32.size == 32) { "msg32 (${msg32.size}) size should be 32" }
require(publicKey.size == Secp256k1.SERIALIZED_X_ONLY_PUBKEY_SIZE) { "publicKey size (${publicKey.size}) size should be ${Secp256k1.SERIALIZED_X_ONLY_PUBKEY_SIZE}" }
require(ids33.size == threshold) { "ids33 array size much match public nonces array size"}
ids33.forEach {
require(it.size == 33) { "id33 (${it.size}) size should be 33" }
}
tweakCache?.let {
require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) { "tweak cache size (${tweakCache.size}) size should be ${Secp256k1.FROST_TWEAK_CACHE_SIZE}" }
}
adaptor?.let {
require(it.size == 33 || it.size == 65) { "adaptor public key size (${it.size}) should be 33 or 65" }
}
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 = tweakCache?.let {
alloc<secp256k1_frost_tweak_cache>()
}?.also { nTweakCache ->
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 {
require(secnonce.size == Secp256k1.FROST_SECNONCE_SIZE) { "secnonce size (${secnonce.size}) should be of size ${Secp256k1.FROST_SECNONCE_SIZE}" }
require(share.size == Secp256k1.FROST_SERIALIZED_SHARE_SIZE) { "share size (${share.size}) should be of size ${Secp256k1.FROST_SERIALIZED_SHARE_SIZE}" }
require(session.size == Secp256k1.FROST_SESSION_SIZE) { "session size (${share.size}) should be of size ${Secp256k1.FROST_SESSION_SIZE}" }
tweakCache?.let {
require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) { "tweak cache size (${tweakCache.size}) size should be ${Secp256k1.FROST_TWEAK_CACHE_SIZE}" }
}
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 = tweakCache?.let {
alloc<secp256k1_frost_tweak_cache>()
}?.also { nTweakCache ->
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 {
require(partialSig.size == 32) { "partialSig (${partialSig.size}) size should be 32" }
require(publicNonce.size == Secp256k1.FROST_SERIALIZED_PUBNONCE_SIZE) { "public nonce (${publicNonce.size}) size should be ${Secp256k1.FROST_SERIALIZED_PUBNONCE_SIZE}" }
require(publicShare.size == 33 || publicShare.size == 65) { "public share size (${partialSig.size}) should be 33 or 65" }
require(session.size == Secp256k1.FROST_SESSION_SIZE) { "session size (${session.size}) size should be ${Secp256k1.FROST_SESSION_SIZE}" }
tweakCache?.let {
require(tweakCache.size == Secp256k1.FROST_TWEAK_CACHE_SIZE) { "tweak cache size (${tweakCache.size}) size should be ${Secp256k1.FROST_TWEAK_CACHE_SIZE}" }
}
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 = tweakCache?.let {
alloc<secp256k1_frost_tweak_cache>()
}?.also { nTweakCache ->
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>,
threshold: Int
): ByteArray {
require(threshold > 1) { "threshold must be greater then 1" }
require(session.size == Secp256k1.FROST_SESSION_SIZE) { "session size (${session.size}) should be ${Secp256k1.FROST_SESSION_SIZE}" }
require(partialSignatures.size == threshold) { "partialSignatures array size should match the threshold size" }
partialSignatures.forEach { partialSig ->
require(partialSig.size == 32) { "partialSignatures size (${partialSig.size}) should be 32" }
}
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(),
threshold.convert()
)
return sig64
}
}
public override fun cleanup() {
secp256k1_context_destroy(ctx)
}

View File

@ -1,24 +0,0 @@
package fr.acinq.secp256k1
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import org.kodein.memory.file.FileSystem
import org.kodein.memory.file.Path
import org.kodein.memory.file.openReadableFile
import org.kodein.memory.file.resolve
import org.kodein.memory.system.Environment
import org.kodein.memory.text.readString
import org.kodein.memory.use
abstract class BaseTest {
fun resourcesDir() =
Environment.findVariable("TEST_RESOURCES_PATH")?.let { Path(it) }
?: FileSystem.workingDir().resolve("src/commonTest/resources")
fun readData(filename: String): JsonElement {
val file = resourcesDir().resolve(filename)
val raw = file.openReadableFile().use { it.readString() }
val format = Json { ignoreUnknownKeys = true }
return format.parseToJsonElement(raw)
}
}

View File

@ -1,510 +0,0 @@
package fr.acinq.secp256k1
import kotlinx.serialization.json.*
import kotlin.test.*
class FrostTest: BaseTest() {
val msg32 = "this_could_be_the_hash_of_a_msg!".encodeToByteArray()
@Test
fun `frost share generation test cases`() {
val tests = readData("frost/share_gen_vectors.json")
val pubkeys = tests.jsonObject["pubkeys"]!!.jsonArray.map { Hex.decode(it.jsonPrimitive.content) }
tests.jsonObject["valid_share_gen_test_cases"]!!.jsonArray.forEach { validTestCases ->
println("Testing ${validTestCases.jsonObject["seed"]!!.jsonPrimitive.content}") // Hack to slow things down... :(
val keyIndices = validTestCases.jsonObject["key_indices"]!!.jsonArray.map { it.jsonPrimitive.int }
val seed32 = Hex.decode(validTestCases.jsonObject["seed"]!!.jsonPrimitive.content)
val nParticipants = keyIndices.size
val threshold = validTestCases.jsonObject["threshold"]!!.jsonPrimitive.int
val ids33 = keyIndices.map { pubkeys[it] }.toTypedArray()
val result = Secp256k1.frostSharesGen(
seed32,
threshold,
nParticipants,
ids33
)
val expected = validTestCases.jsonObject["expected"]!!;
val expectedShare = expected.jsonObject["frost_share"]!!.jsonArray.map { Hex.decode(it.jsonPrimitive.content) }
val expectedVSSCommitment = expected.jsonObject["vss_commitment"]!!.jsonArray.map { Hex.decode(it.jsonPrimitive.content) }
val expectedPoK64 = Hex.decode(expected.jsonObject["pok64"]!!.jsonPrimitive.content)
result.first.forEachIndexed { index, share ->
assertEquals(
expected = Hex.encode(expectedShare[index]),
actual = Hex.encode(share),
"Unexpected $index:share for $keyIndices test case"
)
}
result.second.forEachIndexed { index, vssCommitment ->
assertEquals(
expected = Hex.encode(expectedVSSCommitment[index]),
actual = Hex.encode(vssCommitment),
"Unexpected $index:vss_commitment for the $keyIndices test case"
)
}
assertEquals(
expected = Hex.encode(expectedPoK64),
actual = Hex.encode(result.third),
message = "Unexpected pok64 for $keyIndices test case"
)
}
}
@Test
fun `frost share generation signers`() {
val tests = readData("frost/share_gen_signers_vectors.json")
val pubkeys = tests.jsonObject["pubkeys"]!!.jsonArray.map { Hex.decode(it.jsonPrimitive.content) }
val signerShareGenTestCase = tests.jsonObject["valid_signers_share_gen_test_case"]!!
val keyIndices = signerShareGenTestCase.jsonObject["key_indices"]!!.jsonArray.map { it.jsonPrimitive.int }
val nParticipants = keyIndices.size
val threshold = signerShareGenTestCase.jsonObject["threshold"]!!.jsonPrimitive.int
val ids33 = keyIndices.map { pubkeys[it] }.toTypedArray()
signerShareGenTestCase.jsonObject["signers"]!!.jsonArray.forEachIndexed { signerIndex, signer ->
val seed32 = Hex.decode(signer.jsonObject["seed"]!!.jsonPrimitive.content)
println("Testing ${signer.jsonObject["seed"]!!.jsonPrimitive.content}") // Hack to slow things down... :(
// There seems to be a bug that causes a crash if we call frost_share_gen too often
val result = Secp256k1.frostSharesGen(
seed32,
threshold,
nParticipants,
ids33
)
val expected = signer.jsonObject["expected"]!!;
val expectedShare = expected.jsonObject["frost_share"]!!.jsonArray.map { Hex.decode(it.jsonPrimitive.content) }
val expectedVSSCommitment = expected.jsonObject["vss_commitment"]!!.jsonArray.map { Hex.decode(it.jsonPrimitive.content) }
val expectedPoK64 = Hex.decode(expected.jsonObject["pok64"]!!.jsonPrimitive.content)
result.first.forEachIndexed { index, share ->
assertEquals(
expected = Hex.encode(expectedShare[index]),
actual = Hex.encode(share),
"Unexpected $signerIndex:signer $index:share for $keyIndices test case"
)
}
result.second.forEachIndexed { index, vssCommitment ->
assertEquals(
expected = Hex.encode(expectedVSSCommitment[index]),
actual = Hex.encode(vssCommitment),
"Unexpected $signerIndex:signer $index:vss_commitment for the $keyIndices test case"
)
}
assertEquals(
expected = Hex.encode(expectedPoK64),
actual = Hex.encode(result.third),
message = "Unexpected $signerIndex:signer pok64 for $keyIndices test case"
)
}
}
@Test
fun `frost share aggregation`() {
val shareGenTests = readData("frost/share_gen_vectors.json")
val tests = readData("frost/share_agg_vectors.json")
val expectedAggregatePublicKey = tests.jsonObject["aggregate_public_key"]!!.jsonPrimitive.content
val publicKeys = shareGenTests.jsonObject["pubkeys"]!!.jsonArray.map { Hex.decode(it.jsonPrimitive.content) }
val signerShareGenTestCase = shareGenTests.jsonObject["valid_signers_share_gen_test_case"]!!;
val keyIndices = signerShareGenTestCase.jsonObject["key_indices"]!!.jsonArray.map { it.jsonPrimitive.int }
val nParticipants = keyIndices.size
val threshold = signerShareGenTestCase.jsonObject["threshold"]!!.jsonPrimitive.int
val ids33 = keyIndices.map { publicKeys[it] }.toTypedArray()
val vssCommitments = signerShareGenTestCase.jsonObject["signers"]!!.jsonArray.map { signer ->
signer.jsonObject["expected"]!!.jsonObject["vss_commitment"]!!.jsonArray.map {
Hex.decode(it.jsonPrimitive.content)
}.toTypedArray()
}
signerShareGenTestCase.jsonObject["signers"]!!.jsonArray.forEachIndexed { index, _ ->
val assignedShares = signerShareGenTestCase.jsonObject["signers"]!!.jsonArray.map {
Hex.decode(
it.jsonObject["expected"]!!.jsonObject["frost_share"]!!.jsonArray[index].jsonPrimitive.content
)
}
val result = Secp256k1.frostShareAggregate(
assignedShares.toTypedArray(),
vssCommitments.toTypedArray(),
nParticipants,
threshold,
ids33[index]
)
val expected = tests.jsonObject["expected"]!!.jsonArray[index];
val expectedAggregateShare = expected.jsonObject["aggregate_share"]!!.jsonPrimitive.content
assertEquals(
expected = expectedAggregateShare,
actual = Hex.encode(result.first),
"Unexpected $index:aggregate_share"
)
assertEquals(
expected = expectedAggregatePublicKey,
actual = Hex.encode(result.second),
"Unexpected $index:aggregate_public_key"
)
}
}
@Test
fun `frost share verify`() {
val shareGenTests = readData("frost/share_gen_vectors.json")
val publicKeys = shareGenTests.jsonObject["pubkeys"]!!.jsonArray.map { Hex.decode(it.jsonPrimitive.content) }
val signerShareGenTestCase = shareGenTests.jsonObject["valid_signers_share_gen_test_case"]!!;
val keyIndices = signerShareGenTestCase.jsonObject["key_indices"]!!.jsonArray.map { it.jsonPrimitive.int }
val threshold = signerShareGenTestCase.jsonObject["threshold"]!!.jsonPrimitive.int
val ids33 = keyIndices.map { publicKeys[it] }.toTypedArray()
val vssCommitments = signerShareGenTestCase.jsonObject["signers"]!!.jsonArray.map { signer ->
signer.jsonObject["expected"]!!.jsonObject["vss_commitment"]!!.jsonArray.map {
Hex.decode(it.jsonPrimitive.content)
}.toTypedArray()
}
signerShareGenTestCase.jsonObject["signers"]!!.jsonArray.forEachIndexed { index, _ ->
val assignedShares = signerShareGenTestCase.jsonObject["signers"]!!.jsonArray.map {
Hex.decode(
it.jsonObject["expected"]!!.jsonObject["frost_share"]!!.jsonArray[index].jsonPrimitive.content
)
}
assertEquals(
expected = 1,
actual = Secp256k1.frostShareVerify(
threshold,
ids33[index],
assignedShares[index],
vssCommitments[index]
),
message = "Couldn't verify share from $index signer"
)
}
}
@Test
fun `frost compute pubshare`() {
val shareGenTests = readData("frost/share_gen_vectors.json")
val tests = readData("frost/share_agg_vectors.json")
val publicKeys = shareGenTests.jsonObject["pubkeys"]!!.jsonArray.map { Hex.decode(it.jsonPrimitive.content) }
val signerShareGenTestCase = shareGenTests.jsonObject["valid_signers_share_gen_test_case"]!!;
val keyIndices = signerShareGenTestCase.jsonObject["key_indices"]!!.jsonArray.map { it.jsonPrimitive.int }
val nParticipants = keyIndices.size
val threshold = signerShareGenTestCase.jsonObject["threshold"]!!.jsonPrimitive.int
val ids33 = keyIndices.map { publicKeys[it] }.toTypedArray()
val vssCommitments = signerShareGenTestCase.jsonObject["signers"]!!.jsonArray.map { signer ->
signer.jsonObject["expected"]!!.jsonObject["vss_commitment"]!!.jsonArray.map {
Hex.decode(it.jsonPrimitive.content)
}.toTypedArray()
}
signerShareGenTestCase.jsonObject["signers"]!!.jsonArray.forEachIndexed { index, _ ->
val expected = tests.jsonObject["expected"]!!.jsonArray[index];
val expectedPublicShare = expected.jsonObject["public_share"]!!.jsonPrimitive.content
assertEquals(
expected = expectedPublicShare,
actual = Hex.encode(
Secp256k1.frostComputePublicShare(
threshold,
ids33[index],
vssCommitments.toTypedArray(),
nParticipants
)
),
message = "Couldn't verify share from $index signer"
)
}
}
// Frost Tweak
@Test
fun `frost pubkey tweak`() {
val tests = readData("frost/share_agg_vectors.json")
val expectedAggregatePublicKey = Hex.decode(
tests.jsonObject["aggregate_public_key"]!!.jsonPrimitive.content
)
val expectedTweakCache = tests.jsonObject["tweak_cache"]!!.jsonPrimitive.content
assertEquals(
expected = expectedTweakCache,
actual = Hex.encode(
Secp256k1.frostPublicKeyTweak(
expectedAggregatePublicKey
)
),
message = "Tweak cache incorrect."
)
}
@Test
fun `frost pubkey ec tweak add`() {
val tests = readData("frost/frost_tweak_vectors.json")
val tweakCache = Hex.decode(
tests.jsonObject["tweak_cache"]!!.jsonPrimitive.content
)
val ordinaryTweak = "this could be a BIP32 tweak.....".encodeToByteArray()
assertEquals(
expected = tests.jsonObject["ec_tweak_add"]!!.jsonPrimitive.content,
actual = Secp256k1.frostPublicKeyEcTweakAdd(
tweakCache,
ordinaryTweak
)?.let {
Hex.encode(
it
)
},
message = "EC Tweak Add incorrect."
)
}
@Test
fun `frost pubkey xonly tweak add`() {
val tests = readData("frost/frost_tweak_vectors.json")
val tweakCache = Hex.decode(
tests.jsonObject["tweak_cache"]!!.jsonPrimitive.content
)
val ordinaryTweak = "this could be a BIP32 tweak.....".encodeToByteArray()
assertEquals(
expected = tests.jsonObject["ec_tweak_add"]!!.jsonPrimitive.content,
// TODO: Return public key
actual = Secp256k1.frostPublicKeyXonlyTweakAdd(
tweakCache,
ordinaryTweak
)?.let {
Hex.encode(
it
)
},
message = "EC Tweak Add incorrect."
)
}
// Frost Sign functionality
@Test
fun `frost nonce gen`() {
val tests = readData("frost/frost_nonce_vectors.json")
val sessionId = Hex.decode(
tests.jsonObject["session_id"]!!.jsonPrimitive.content
)
val aggregatePublicKey = Hex.decode(
tests.jsonObject["aggregate_public_key"]!!.jsonPrimitive.content
)
tests.jsonObject["signers"]!!.jsonArray.forEachIndexed { index, signers ->
val aggregateShare = Hex.decode(
signers.jsonObject["aggregate_share"]!!.jsonPrimitive.content
)
val (secNonce, pubNonce) = Secp256k1.frostNonceGen(
sessionId,
aggregateShare,
msg32,
aggregatePublicKey,
null
)
val expectedSecNonce = signers.jsonObject["secnonce"]!!.jsonPrimitive.content
val expectedPubNonce = signers.jsonObject["pubnonce"]!!.jsonPrimitive.content
assertEquals(
expected = expectedSecNonce,
actual = Hex.encode(secNonce),
message = "Invalid $index:secnonce"
)
assertEquals(
expected = expectedPubNonce,
actual = Hex.encode(pubNonce),
message = "Invalid $index:pubnonce"
)
}
}
@Test
fun `frost nonce process`() {
val tests = readData("frost/frost_nonce_vectors.json")
val threshold = tests.jsonObject["threshold"]!!.jsonPrimitive.int
val pubnonces = tests.jsonObject["signers"]!!.jsonArray.take(threshold).map {
Hex.decode(it.jsonObject["pubnonce"]!!.jsonPrimitive.content)
}
val aggregatePublicKey = Hex.decode(
tests.jsonObject["aggregate_public_key"]!!.jsonPrimitive.content
)
val pubkeys = tests.jsonObject["pubkeys"]!!.jsonArray.take(threshold).map {
Hex.decode(it.jsonPrimitive.content)
}
val tweakCache = Hex.decode(
tests.jsonObject["tweak_cache"]!!.jsonPrimitive.content
)
tests.jsonObject["signers"]!!.jsonArray.take(threshold).forEachIndexed { signerIndex, signer ->
val session = Secp256k1.frostNonceProcess(
pubnonces.toTypedArray(),
threshold,
msg32,
aggregatePublicKey,
pubkeys[signerIndex],
pubkeys.toTypedArray(),
tweakCache,
null
)
assertEquals(
expected = signer.jsonObject["session"]!!.jsonPrimitive.content,
actual = Hex.encode(session),
message = "Invalid $signerIndex:session"
)
}
}
@Test
fun `frost partial sign`() {
val tests = readData("frost/frost_nonce_vectors.json")
val threshold = tests.jsonObject["threshold"]!!.jsonPrimitive.int
val tweakCache = Hex.decode(
tests.jsonObject["tweak_cache"]!!.jsonPrimitive.content
)
tests.jsonObject["signers"]!!.jsonArray.take(threshold).forEachIndexed { signerIndex, signer ->
val secNonce = Hex.decode(
signer.jsonObject["secnonce"]!!.jsonPrimitive.content
)
val aggregateShare = Hex.decode(
signer.jsonObject["aggregate_share"]!!.jsonPrimitive.content
)
val session = Hex.decode(
signer.jsonObject["session"]!!.jsonPrimitive.content
)
val partialSignature = Secp256k1.frostPartialSign(
secNonce,
aggregateShare,
session,
tweakCache
)
assertEquals(
expected = signer.jsonObject["partial_signature"]!!.jsonPrimitive.content,
actual = Hex.encode(partialSignature),
message = "Invalid $signerIndex:partial signature"
)
}
}
@Test
fun `frost partial signature verify`() {
val tests = readData("frost/frost_nonce_vectors.json")
val threshold = tests.jsonObject["threshold"]!!.jsonPrimitive.int
val tweakCache = Hex.decode(
tests.jsonObject["tweak_cache"]!!.jsonPrimitive.content
)
tests.jsonObject["signers"]!!.jsonArray.take(threshold).forEach { signer ->
val partialSignature = Hex.decode(
signer.jsonObject["partial_signature"]!!.jsonPrimitive.content
)
val pubNonce = Hex.decode(
signer.jsonObject["pubnonce"]!!.jsonPrimitive.content
)
val publicShare = Hex.decode(
signer.jsonObject["public_share"]!!.jsonPrimitive.content
)
val session = Hex.decode(
signer.jsonObject["session"]!!.jsonPrimitive.content
)
assertEquals(
expected = 1,
actual = Secp256k1.frostPartialSignatureVerify(
partialSignature,
pubNonce,
publicShare,
session,
tweakCache
),
message = "Failed to verify partial signature"
)
}
}
@Test
fun `frost partial signature aggregation`() {
val tests = readData("frost/frost_nonce_vectors.json")
val threshold = tests.jsonObject["threshold"]!!.jsonPrimitive.int
val partialSignatures = tests.jsonObject["signers"]!!.jsonArray.take(threshold).map {
Hex.decode(it.jsonObject["partial_signature"]!!.jsonPrimitive.content)
}
tests.jsonObject["signers"]!!.jsonArray.take(threshold).forEach { signer ->
val session = Hex.decode(
signer.jsonObject["session"]!!.jsonPrimitive.content
)
val aggregatedSignature = Secp256k1.frostPartialSignatureAggregate(
session,
partialSignatures.toTypedArray(),
threshold
)
assertEquals(
expected = tests.jsonObject["aggregate_signature"]!!.jsonPrimitive.content,
actual = Hex.encode(aggregatedSignature),
message = "Invalid aggregate partial signature"
)
}
}
}

View File

@ -10,7 +10,17 @@ import org.kodein.memory.text.readString
import org.kodein.memory.use
import kotlin.test.*
class Musig2Test: BaseTest() {
class Musig2Test {
fun resourcesDir() =
Environment.findVariable("TEST_RESOURCES_PATH")?.let { Path(it) }
?: FileSystem.workingDir().resolve("src/commonTest/resources")
fun readData(filename: String): JsonElement {
val file = resourcesDir().resolve(filename)
val raw = file.openReadableFile().use { it.readString() }
val format = Json { ignoreUnknownKeys = true }
return format.parseToJsonElement(raw)
}
@Test
fun `aggregate public keys`() {

View File

@ -1,52 +0,0 @@
{
"pubkeys": [
"023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66",
"02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9",
"03935f972da013f80ae011890fa89b67a27b7be6ccb24d3274d18b2d4067f261a9",
"03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659",
"04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9"
],
"threshold": 3,
"aggregate_public_key": "bd5561ef6dbff52d3f73b8cb0c065328988b71d3386d23890744a0dd6ad27c15",
"aggregate_signature": "2fd5bc8fa46b0097f48e0b5734ec557a17a72f8c5989bdf5f387f01b5edc149f02a340d5ca0348b54448aecc67c1bdd532e43f5295a5382e063fe7b4425259ac",
"session_id": "7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671",
"tweak_cache": "40252e41157cd26adda0440789236d38d3718b982853060ccbb8733f2df5bf6def6155bdeefcc6b83fe690d621b793b08f5b1562a7bef628c4db33f2d0b3f3bf2f541aaa000000000000000000000000000000000000000000000000000000000000000000",
"signers": [
{
"partial_signature": "82b98b609479595b861db8704b1b1af5d34defb52fb75023a2fb53a8c66e8ba7",
"session": "5c11a803002fd5bc8fa46b0097f48e0b5734ec557a17a72f8c5989bdf5f387f01b5edc149fe6d54b152392da71ec234b35804aeb36c6829cb0a0201aa7a94ec586a1147f0c18901c3b3d604349539d6cd24a2c1e7a676a7bce95cb810dbc346133c117a7a60000000000000000000000000000000000000000000000000000000000000000",
"secnonce": "847d4625fe87e00f9562351a9b7de8fc2420caba09535db177fc4fbac5b69b84c8700ae143946a0fffff4083d6377ee19a6448a55241160fbc7c793aace02f289a2fec8f",
"pubnonce": "03203a0450540686854df68f6c1d15661772e4d05c4442ee1e437d86842779ef2202d03839fd99faf7a11ccc319a9adc965c5e094ca3728455059a4911ae96192fae",
"aggregate_share": "1cfa28492e84e945343f1167401cdce061202a59e47e050c0c2f7f0c56e8e148",
"public_share": "0493effba7e50d3885bb0c4665149abd4fd13622047412f1da4c0e3754ecb1a9183aaadfdf0f2f82e24641e6ed7a0f7ee22a4a8a47c6d2df66daad37a4880fffe2"
},
{
"partial_signature": "62bb46458d4307cc96280159873fac35285e65049196c0df03954da79e7924e5",
"session": "5c11a803002fd5bc8fa46b0097f48e0b5734ec557a17a72f8c5989bdf5f387f01b5edc149fe6d54b152392da71ec234b35804aeb36c6829cb0a0201aa7a94ec586a1147f0c69b1d2e667d72b4a220100d9229740f24d9891f55f41918a07831d382aeba5e80000000000000000000000000000000000000000000000000000000000000000",
"secnonce": "847d4625e6af707cb69026251afdfc2570a3fbdbbc7e72530354f0777fe2192c6aa8b23969172508dff48f7a21827935cce2ed019c570bb5552f9a3269a8ec34cfd23e2c",
"pubnonce": "035c8f36d2cf868b9ccab3221b3f5eca64d60469a50245d6edc3b4f4bfb4358892023e832dcc0b5b55562ef6f1536679a2e996827747d3b824ca335daf00d51ab788",
"aggregate_share": "dd82fcc1806f1a968228c794a7001c18d209871fb3441bae80fd8229f6a9b0dd",
"public_share": "048482e27b533879d4f3d68bdb2038bf9480d4ce4cc614d7133238e55179c65a175c684afb7f983e60139542b80f0f12815f3194082f07c93e1f87f3cd1b1c0d8b"
},
{
"partial_signature": "1d2e6f2fa846e78d2802f5029566f6a8f1e6c77f839fc7671f81a4f0ada0ea61",
"session": "5c11a803002fd5bc8fa46b0097f48e0b5734ec557a17a72f8c5989bdf5f387f01b5edc149fe6d54b152392da71ec234b35804aeb36c6829cb0a0201aa7a94ec586a1147f0c7c15772acc75c702d2cb960a98c793090de73e18e5fd5dbf08818afcab855fa10000000000000000000000000000000000000000000000000000000000000000",
"secnonce": "847d4625bd32503f81d016175829db4df8475660c77e28cf6dc7bc8b2f6e3fe6f67282b1cf81dcf2dabd867053461cf602f3e3345f42119066f4c493b85a0744ae7beb08",
"pubnonce": "028b80bb46028338d41101deacd7910e09ba148f75d2c01e9f8f767fa9cdcbbc7e02b0cec1ba331750a22bf3bb8d1b724bd2874f7f0c19c70227f64c463c8c6bcab2",
"aggregate_share": "5fe629d5f34fdb3ea2f6e545fc3d2cf1f5ce23a504b144e6ebe928793cc85cb4",
"public_share": "04d71784b58d8958141f8f405d56026f214a736e73f9c1f70776fc2e49f4e90fc0a9396bcc7471a83caf4076a18cb6ab4264aa37174ca19e142259aa5f6bb7fea3"
},
{
"secnonce": "847d4625f2128d893c4b8b62818bbc972d158b0aa96b08dcacba149dd7517b7fc7ddb89b70234941338c242dbca6e27ebf337ae458381ef83bea4ba2baab8df3d7f6b773",
"pubnonce": "030b4d942e88b7674819f3020c290db1162beda60bae05964bb344378166ec61a20221e3e76bfa50c22b98832d451d51e3b7cdef420a2b06e9a29373449aa77aa46c",
"aggregate_share": "71181e5b46742333f12672d85d0e1472770a082f0a62d3d204c9e191fb45ef91",
"public_share": "04ec0fb2b4c1ac2d9b761f32cb2972e6d6fb74ed4195d872aeaaf4306bb64eb465580d03102849363ec49c3d1eecdd239337d0a66cdfc4d74c29c824c0f941832a"
},
{
"secnonce": "847d4625ee1f0f41a485d2399b024b05d9a9b7cbb846cf107dcbfa125a136448cbd20441a5bbea0b8908781249bbd7a5f6c429e1678338d8a2f5a9095a85fd541cb49884",
"pubnonce": "034a67a3dbe320486110fac55f4e7ef4f5c5216766b8e4d635c6f1119a5c5e75a3026ada48e6491d2c9890f65fd3f9d675f644df9224b5beb5fc41b2934bc28d9bcc",
"aggregate_share": "15bc5e3eeb4ec318a718b3015b78e8496cc5ede81c05727936ade625532dce55",
"public_share": "04b3ad3909e919f1a27faff7a3aec8f04a9ca54a065d9774ae37c3b9903ad4a19b71f11e148b549ef168465d065279f773175b254f64573e7ce30f4aba0954be19"
}
]
}

View File

@ -1,5 +0,0 @@
{
"aggregate_public_key": "bd5561ef6dbff52d3f73b8cb0c065328988b71d3386d23890744a0dd6ad27c15",
"tweak_cache": "40252e41157cd26adda0440789236d38d3718b982853060ccbb8733f2df5bf6def6155bdeefcc6b83fe690d621b793b08f5b1562a7bef628c4db33f2d0b3f3bf2f541aaa000000000000000000000000000000000000000000000000000000000000000000",
"ec_tweak_add": "0444536a3cc348adb38660f06de15a6168c06d11a0ad00ca6ea34ff58a8300e2cc086d50550ee52f1d0334e31dfc67fa55201541078d89dcf79bf0c46a53e3af9b"
}

View File

@ -1,26 +0,0 @@
{
"aggregate_public_key": "bd5561ef6dbff52d3f73b8cb0c065328988b71d3386d23890744a0dd6ad27c15",
"tweak_cache": "40252e41157cd26adda0440789236d38d3718b982853060ccbb8733f2df5bf6def6155bdeefcc6b83fe690d621b793b08f5b1562a7bef628c4db33f2d0b3f3bf2f541aaa000000000000000000000000000000000000000000000000000000000000000000",
"expected": [
{
"aggregate_share": "1cfa28492e84e945343f1167401cdce061202a59e47e050c0c2f7f0c56e8e148",
"public_share": "0493effba7e50d3885bb0c4665149abd4fd13622047412f1da4c0e3754ecb1a9183aaadfdf0f2f82e24641e6ed7a0f7ee22a4a8a47c6d2df66daad37a4880fffe2"
},
{
"aggregate_share": "dd82fcc1806f1a968228c794a7001c18d209871fb3441bae80fd8229f6a9b0dd",
"public_share": "048482e27b533879d4f3d68bdb2038bf9480d4ce4cc614d7133238e55179c65a175c684afb7f983e60139542b80f0f12815f3194082f07c93e1f87f3cd1b1c0d8b"
},
{
"aggregate_share": "5fe629d5f34fdb3ea2f6e545fc3d2cf1f5ce23a504b144e6ebe928793cc85cb4",
"public_share": "04d71784b58d8958141f8f405d56026f214a736e73f9c1f70776fc2e49f4e90fc0a9396bcc7471a83caf4076a18cb6ab4264aa37174ca19e142259aa5f6bb7fea3"
},
{
"aggregate_share": "71181e5b46742333f12672d85d0e1472770a082f0a62d3d204c9e191fb45ef91",
"public_share": "04ec0fb2b4c1ac2d9b761f32cb2972e6d6fb74ed4195d872aeaaf4306bb64eb465580d03102849363ec49c3d1eecdd239337d0a66cdfc4d74c29c824c0f941832a"
},
{
"aggregate_share": "15bc5e3eeb4ec318a718b3015b78e8496cc5ede81c05727936ade625532dce55",
"public_share": "04b3ad3909e919f1a27faff7a3aec8f04a9ca54a065d9774ae37c3b9903ad4a19b71f11e148b549ef168465d065279f773175b254f64573e7ce30f4aba0954be19"
}
]
}

View File

@ -1,105 +0,0 @@
{
"pubkeys": [
"023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66",
"02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9",
"03935f972da013f80ae011890fa89b67a27b7be6ccb24d3274d18b2d4067f261a9",
"03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659",
"04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9"
],
"valid_signers_share_gen_test_case": {
"key_indices": [0, 1, 2, 3, 4],
"threshold": 3,
"signers": [
{
"seed": "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F",
"expected": {
"frost_share": [
"9a04e37bc40df0e1c3e05b82e7a7af6b7cdaadf337ec3eaa2b50bb9ffdb2da99",
"8d7b24fa2421a9157ce01b7a900fe4b06dbb922def5d0f8a6b6f420e94310d27",
"8cda987d0a9817ecb544f1ffcd7912006c6406bb95c9a9a45b70d641f6a0300c",
"bf0eaac669eac6ac43d094bb2e07e4fa7fd4b1d317188c690aad7ea211b49bdb",
"00c266074c34720f6d9a8511e4ec82bed44e104f93f20d9bbfbff8e2edf44400"
],
"vss_commitment": [
"04bc2f60d5a7494d506e6517c49db2104b05e087536ccb1cb2730282f469782bb93e2c0029d733beeea75120e831ed71255adde4ddbd0be049419572502d7b73b9",
"04ced2029d64827253175b5382cb327123fd2cdcdb5b2092e66020e9b6ece639f675029e36604347735eef9bf64137474b14d92d2996e67f5721705ee574c916a1",
"044f34156e0a6d49c96298a845fd07a122490dee82b80f090b3214162ed2b030c88a2cec6cac580d63d770f1d2933f21e58ec8d4b94ca1939e590add1616f6ea38"
],
"pok64": "8f63ac15582fd77b4c50eef4ca7f5810e9d31ff86a5e7c0c14483edc076290bcfdb481e5c41b24419c65ac7525560a8d3bbbcc303c8c232d63650252e7aff576"
}
},
{
"seed": "F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0",
"expected": {
"frost_share": [
"7adaa6dbd9df3f0944a516d13b6d7a826a956d05412a9f656b26b36e6507ff0c",
"69cedd07db8a28a4cfd70fcd672b573b842675a9a0222239173c2dcc2f300dd1",
"ca1df886e57b1ede4501a09b2c8e433f4503bdf9627784369650fd76a7ada20c",
"f53e5fb436fae00581f5077cb4736af110d5fe1ceb9c4047852adfea6fa2e8b0",
"8addd4121d313a0458b3649466f27dafadc5cb6dba441f7e1e5c4f2fb62139c0"
],
"vss_commitment": [
"0498fce8a40dd9fc23fd87cc4fecd572bd87a6d961576ba7eef3e140f61655c9ee276942ef761cf0cd2845d1c6f149c73e411c2869ac8e4faeedcc6235d0954460",
"04581308e2c7b7367f5f711a95c6f72a99b53f138cf8eafd6c0119ea038e18b51ec8e1bab854e22c42f56e0ddf6922bcac4064254700194a5a9abcdb619e96e701",
"04ebb8b0c4fcecb70d91b9e65ea897ed8930f6d7b41cdcd150718ebbcef40b50f7fb9817fd425b598e09f3133a9100d513e9ba97bcb26b8ef371ada9669a6ed11f"
],
"pok64": "b2d68140014812cfa83116100deba8a6152a20a243ea73e3e4edf7f25031805f25f3dd78e6d921de1bcebc0d9a57069af905d3f1d613896f6ef69820c601e651"
}
},
{
"seed": "7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671",
"expected": {
"frost_share": [
"7bde839ba686bdadce0dd854f1f71455c2dd9257b2bfd1995a92e7601dc8ebb8",
"15b62e7af6dfbc1035197fa1439b0b93639798e52a52efb964ff8eb118f0218e",
"6a4179474660abdda21b9cb0c7f27f487b18dd96b7a78f24b2b3b2e7d53504f6",
"97c53a07bd8b7a27a1ba83e3be7b913d55d3112a9ece472c0e3ab2f3e18e34df",
"f5bb1c36ec28f1a2845dcfb10af91772609f401d5ab4357a2a23e4c4d4e1be0d"
],
"vss_commitment": [
"046b17a9bca13b4cec2ae589973ab0471915fd77c93374d7d5dfcfacac9da7132bf2d07f55f98caf84927c97fe2946174d73609afe7d9aba0364b0abe2d174d544",
"04abaab1242f669205aa0eb26a876a89cbe80c6c7364b1fba0d095d8181767b96d3d44e5014c2d5a82cc9cf7b9e5ae269e5bc22ffe0212ef1a0b7a2379778be500",
"0415d97c46268a919acbfadcdc0a23fb463d94473787365a6bdd8f5bce95d6d83156448f2582bddcbdbb9bfc58cde1db47e5fb6350530bfb1102b7d0d44a70b5c0"
],
"pok64": "5cca5711ca05df39c82fe518e4afcd2871654bbfe6fed31b97101bfc27e1d0083d1cbc2cb3d3fa7a972bd84c7c025f71042a3a0aec27311732ae8b679bdebda3"
}
},
{
"seed": "F95466D086770E689964664219266FE5ED215C92AE20BAB5C9D79ADDDDF3C0CF",
"expected": {
"frost_share": [
"28b9d1730cd16190c0e9903144bc93f1ea5febf0046a290e00887540c7f726cf",
"d423aafb512cb983b00bdca3e8b398d2f197db8339889b4d0934852f3a0be1cb",
"3d71eab243f39cb2a83ccf78cb611f24544d01dc53a14616cfcf7044f4cfd8c3",
"78b75d47b540a9f29937e7a9187abc31286e7fcafb112c25829ddec7ae73f2d8",
"0a917790664eb85b54b2527449fe445c93a9c384b31ccc8b9ade6638ff55dd96"
],
"vss_commitment": [
"04919b0ecff3c10aebec20d55f6eff6736df2cb9b0e549d633ea1711eea4def643c00c89025bd567b79e7fd808c821bca9e6516542ebd689a06f97f52bb8937b7c",
"041583c3a25ebab0fbddbc9c9c491f889ff1df5991b0963c3c6363c6040eb505f2a9e279987f70d30415ddae2bcace1ccf2f96f1d220016c526a363aebed6c02a8",
"04e53ec77bf28672cb36a527fd5ac2ec90b88ab99dfd54c734b4837ea84759332ff7259e9044af6a9847c9432f023a5c7039f95313d564572a326b0e34b3e2299d"
],
"pok64": "ff6bf4b90faf7a66dc54bfa2cd047be44e1c42622410d6e3a23697d30212d3bde11fc7fb4e61b2bc1e4310ad86089721ba912191d7ca561b9c5dcbcb604116fc"
}
},
{
"seed": "012ABBCB52B3016AC03AD82395A1A415C48B93DEF78718E62A7A90052FE224FB",
"expected": {
"frost_share": [
"638248e2dd3f9a1b9cc2368ce6540aa841d04ae712ce6ccc9a417076aeda779e",
"fc5f214938b6d348504c400783763bc40055c4ad1e7a9f5c0fc2bb8880b9150e",
"613a34d878e85be35e57e6816ee23942ea5e394a5fb88247f748eead74e22f65",
"ac4e7c9132c25867f06e6b13a39c7714982a5dfd7ba8748323900cf05a8f0712",
"89cf905e2f716d0707baa735baa28c096bc6c8561e8f83d11334102e7b4d3774"
],
"vss_commitment": [
"04f63b636f91fda4fa756c64cd34c186e4595a5b4a6ed6351ba0e99961f2a189001f6f708312ed0ac8c1e291d6064e236e265f2b1b561925a29a39c2d3ad9f866b",
"040269fedd5bdb0d7bed5dd50f9fec28415d51694441dc6c5b0b3e2fd577429c40832c6263e9d218f6ae8cc6a87f72d69d3dc0096a8779d7530fec4983ed6c95b1",
"04fa8cf2f9a25d2d5b52872dd27afd89dfff5bad33f3335726fc56b49989f64c041e765acd4719bad295620393b00ec3f1b5420f02bad4794998d5f26c435deee5"
],
"pok64": "6888a2ffd199e69806e2c067befc41bd58de0605407542163031e8d75dd1cf80b7fae9e12c8e618081cf79a84d2a3a293dd260234383e5ab587f4459c5963d15"
}
}
]
}
}

View File

@ -1,182 +0,0 @@
{
"pubkeys": [
"023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66",
"02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9",
"03935f972da013f80ae011890fa89b67a27b7be6ccb24d3274d18b2d4067f261a9",
"03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659",
"04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9"
],
"valid_share_gen_test_cases": [
{
"seed": "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F",
"key_indices": [0, 1, 2, 3, 4],
"threshold": 3,
"expected": {
"frost_share": [
"9a04e37bc40df0e1c3e05b82e7a7af6b7cdaadf337ec3eaa2b50bb9ffdb2da99",
"8d7b24fa2421a9157ce01b7a900fe4b06dbb922def5d0f8a6b6f420e94310d27",
"8cda987d0a9817ecb544f1ffcd7912006c6406bb95c9a9a45b70d641f6a0300c",
"bf0eaac669eac6ac43d094bb2e07e4fa7fd4b1d317188c690aad7ea211b49bdb",
"00c266074c34720f6d9a8511e4ec82bed44e104f93f20d9bbfbff8e2edf44400"
],
"vss_commitment": [
"04bc2f60d5a7494d506e6517c49db2104b05e087536ccb1cb2730282f469782bb93e2c0029d733beeea75120e831ed71255adde4ddbd0be049419572502d7b73b9",
"04ced2029d64827253175b5382cb327123fd2cdcdb5b2092e66020e9b6ece639f675029e36604347735eef9bf64137474b14d92d2996e67f5721705ee574c916a1",
"044f34156e0a6d49c96298a845fd07a122490dee82b80f090b3214162ed2b030c88a2cec6cac580d63d770f1d2933f21e58ec8d4b94ca1939e590add1616f6ea38"
],
"pok64": "8f63ac15582fd77b4c50eef4ca7f5810e9d31ff86a5e7c0c14483edc076290bcfdb481e5c41b24419c65ac7525560a8d3bbbcc303c8c232d63650252e7aff576"
}
},
{
"seed": "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F",
"key_indices": [4, 3, 2, 1, 0],
"threshold": 3,
"expected": {
"frost_share": [
"7f3d4b3c13fe574ce2b24412aff67f19cc3d198b40e6bb57865df4f519ef65fa",
"9a46587ac615fc8afd0bc3a234075fb190f20a951df57ce21c7c7f6331117ab3",
"9188f7516271f4e4d9c71837db17f3a4e9ee1f979ca0245405ed13f88d8d54f2",
"afea9adf149439f663bb787190f7503984e632823607433e7c0d86884ba3ac58",
"11492bef4d7f35e038a1270a3a1a0a55c8e72a313d6086fec4bbdbe0522b9575"
],
"vss_commitment": [
"04ba2dd42da281b300358ed004da8755cc5b93c2ea56c8b79d63492501f2a8e69e4beb0f7a7adb01f2edec1ec84e338db286319f5be9faa82c2ac9ccd976e459eb",
"04d0be30dbc1da6ed9c84e33bf976671b7fadd38ee2243ec1c86780456092b4b5504416548cfae342746b8cde08a3aa3323c338a125031fbb31693e4fa94d4c3d9",
"04146aa11a44a2d2e1c53eb91f274c2145ff9d69d7af27ec85d34fb0df318bc4c9ab75f2d473b03fb133b0d8c1166dd6116c934fa7ff1498df2e6a51650a32940a"
],
"pok64": "c5fc820d0d64d447eec6c5f5eade3c08f2a0dac2fa244be7558247989c71a14dd51bfe784983a84fefc76fd4d049434d88df02b5474c14304150b9dce304e842"
}
},
{
"seed": "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F",
"key_indices": [0, 0, 0],
"threshold": 2,
"expected": {
"frost_share": [
"6a2ca571b1b83fbe65bb589949538f2d4c6cada3aa914232b96160584642262b",
"6a2ca571b1b83fbe65bb589949538f2d4c6cada3aa914232b96160584642262b",
"6a2ca571b1b83fbe65bb589949538f2d4c6cada3aa914232b96160584642262b"
],
"vss_commitment": [
"04a17464b9a1c4e7fb1f22221ba552640d891fdaca04b6a4c9570be4bfb8fdc0c0ca13853d1ea1eccf8e8f81d79d1500dac44a53282f58d17468e358ff78bc7e14",
"04af3c0779299cd72cf5f5dbe919068f4d9d3b525a48665363fa8b1ca26d6908cf477c156e3603f6cfe3d6f394d2a9e9f55e86d7b90a2ad2f0ea62f6ac4bd1f4b2"
],
"pok64": "a006b9b996888d552ce756bf7f217228e487fe510473c08b025ff145ccae6c015265e4f3ca39d488068f385afe0766b636fcbd3a5ac4cdd96f90e704dcce58d7"
}
},
{
"seed": "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F",
"key_indices": [0, 0, 1, 1],
"threshold": 2,
"expected": {
"frost_share": [
"9b84df35de7d30724c5ef2593c40e349e086e43bcbc4534034e0312510e55e6d",
"9b84df35de7d30724c5ef2593c40e349e086e43bcbc4534034e0312510e55e6d",
"ade61b5f4aec435ac0c4ff7ef61280a9f00150f88068cd391be3ea2f50128199",
"ade61b5f4aec435ac0c4ff7ef61280a9f00150f88068cd391be3ea2f50128199"
],
"vss_commitment": [
"04840febfcb959d1425df55ae74b78dbd1f9641438fbc6d5e5fc8a315dfdca30106b8846c149a27b2896a312e598cd4b447b375a46b5787f01ecd0a8b642bf5017",
"04935008aeb03eef3dfee5b9c42d1575dd53c8ab8078cabf38d8bd1768e1ee1f92ffe6bb6997b085104a048cac6ba7d7fa6a57c41c639ebfde516ce6d9292dc84b"
],
"pok64": "9d3c1f08ff8215d65e25ea8678ac923d089f10d7be7a77d2fa2f802174094d62d0f713dd874570ad4bdcbfc17cf02464523387893d85c134f201fee7cdbe3b14"
}
}
],
"valid_signers_share_gen_test_case": {
"key_indices": [0, 1, 2, 3, 4],
"threshold": 3,
"signers": [
{
"seed": "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F",
"expected": {
"frost_share": [
"9a04e37bc40df0e1c3e05b82e7a7af6b7cdaadf337ec3eaa2b50bb9ffdb2da99",
"8d7b24fa2421a9157ce01b7a900fe4b06dbb922def5d0f8a6b6f420e94310d27",
"8cda987d0a9817ecb544f1ffcd7912006c6406bb95c9a9a45b70d641f6a0300c",
"bf0eaac669eac6ac43d094bb2e07e4fa7fd4b1d317188c690aad7ea211b49bdb",
"00c266074c34720f6d9a8511e4ec82bed44e104f93f20d9bbfbff8e2edf44400"
],
"vss_commitment": [
"04bc2f60d5a7494d506e6517c49db2104b05e087536ccb1cb2730282f469782bb93e2c0029d733beeea75120e831ed71255adde4ddbd0be049419572502d7b73b9",
"04ced2029d64827253175b5382cb327123fd2cdcdb5b2092e66020e9b6ece639f675029e36604347735eef9bf64137474b14d92d2996e67f5721705ee574c916a1",
"044f34156e0a6d49c96298a845fd07a122490dee82b80f090b3214162ed2b030c88a2cec6cac580d63d770f1d2933f21e58ec8d4b94ca1939e590add1616f6ea38"
],
"pok64": "8f63ac15582fd77b4c50eef4ca7f5810e9d31ff86a5e7c0c14483edc076290bcfdb481e5c41b24419c65ac7525560a8d3bbbcc303c8c232d63650252e7aff576"
}
},
{
"seed": "F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0",
"expected": {
"frost_share": [
"7adaa6dbd9df3f0944a516d13b6d7a826a956d05412a9f656b26b36e6507ff0c",
"69cedd07db8a28a4cfd70fcd672b573b842675a9a0222239173c2dcc2f300dd1",
"ca1df886e57b1ede4501a09b2c8e433f4503bdf9627784369650fd76a7ada20c",
"f53e5fb436fae00581f5077cb4736af110d5fe1ceb9c4047852adfea6fa2e8b0",
"8addd4121d313a0458b3649466f27dafadc5cb6dba441f7e1e5c4f2fb62139c0"
],
"vss_commitment": [
"0498fce8a40dd9fc23fd87cc4fecd572bd87a6d961576ba7eef3e140f61655c9ee276942ef761cf0cd2845d1c6f149c73e411c2869ac8e4faeedcc6235d0954460",
"04581308e2c7b7367f5f711a95c6f72a99b53f138cf8eafd6c0119ea038e18b51ec8e1bab854e22c42f56e0ddf6922bcac4064254700194a5a9abcdb619e96e701",
"04ebb8b0c4fcecb70d91b9e65ea897ed8930f6d7b41cdcd150718ebbcef40b50f7fb9817fd425b598e09f3133a9100d513e9ba97bcb26b8ef371ada9669a6ed11f"
],
"pok64": "b2d68140014812cfa83116100deba8a6152a20a243ea73e3e4edf7f25031805f25f3dd78e6d921de1bcebc0d9a57069af905d3f1d613896f6ef69820c601e651"
}
},
{
"seed": "7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671",
"expected": {
"frost_share": [
"7bde839ba686bdadce0dd854f1f71455c2dd9257b2bfd1995a92e7601dc8ebb8",
"15b62e7af6dfbc1035197fa1439b0b93639798e52a52efb964ff8eb118f0218e",
"6a4179474660abdda21b9cb0c7f27f487b18dd96b7a78f24b2b3b2e7d53504f6",
"97c53a07bd8b7a27a1ba83e3be7b913d55d3112a9ece472c0e3ab2f3e18e34df",
"f5bb1c36ec28f1a2845dcfb10af91772609f401d5ab4357a2a23e4c4d4e1be0d"
],
"vss_commitment": [
"046b17a9bca13b4cec2ae589973ab0471915fd77c93374d7d5dfcfacac9da7132bf2d07f55f98caf84927c97fe2946174d73609afe7d9aba0364b0abe2d174d544",
"04abaab1242f669205aa0eb26a876a89cbe80c6c7364b1fba0d095d8181767b96d3d44e5014c2d5a82cc9cf7b9e5ae269e5bc22ffe0212ef1a0b7a2379778be500",
"0415d97c46268a919acbfadcdc0a23fb463d94473787365a6bdd8f5bce95d6d83156448f2582bddcbdbb9bfc58cde1db47e5fb6350530bfb1102b7d0d44a70b5c0"
],
"pok64": "5cca5711ca05df39c82fe518e4afcd2871654bbfe6fed31b97101bfc27e1d0083d1cbc2cb3d3fa7a972bd84c7c025f71042a3a0aec27311732ae8b679bdebda3"
}
},
{
"seed": "F95466D086770E689964664219266FE5ED215C92AE20BAB5C9D79ADDDDF3C0CF",
"expected": {
"frost_share": [
"28b9d1730cd16190c0e9903144bc93f1ea5febf0046a290e00887540c7f726cf",
"d423aafb512cb983b00bdca3e8b398d2f197db8339889b4d0934852f3a0be1cb",
"3d71eab243f39cb2a83ccf78cb611f24544d01dc53a14616cfcf7044f4cfd8c3",
"78b75d47b540a9f29937e7a9187abc31286e7fcafb112c25829ddec7ae73f2d8",
"0a917790664eb85b54b2527449fe445c93a9c384b31ccc8b9ade6638ff55dd96"
],
"vss_commitment": [
"04919b0ecff3c10aebec20d55f6eff6736df2cb9b0e549d633ea1711eea4def643c00c89025bd567b79e7fd808c821bca9e6516542ebd689a06f97f52bb8937b7c",
"041583c3a25ebab0fbddbc9c9c491f889ff1df5991b0963c3c6363c6040eb505f2a9e279987f70d30415ddae2bcace1ccf2f96f1d220016c526a363aebed6c02a8",
"04e53ec77bf28672cb36a527fd5ac2ec90b88ab99dfd54c734b4837ea84759332ff7259e9044af6a9847c9432f023a5c7039f95313d564572a326b0e34b3e2299d"
],
"pok64": "ff6bf4b90faf7a66dc54bfa2cd047be44e1c42622410d6e3a23697d30212d3bde11fc7fb4e61b2bc1e4310ad86089721ba912191d7ca561b9c5dcbcb604116fc"
}
},
{
"seed": "012ABBCB52B3016AC03AD82395A1A415C48B93DEF78718E62A7A90052FE224FB",
"expected": {
"frost_share": [
"638248e2dd3f9a1b9cc2368ce6540aa841d04ae712ce6ccc9a417076aeda779e",
"fc5f214938b6d348504c400783763bc40055c4ad1e7a9f5c0fc2bb8880b9150e",
"613a34d878e85be35e57e6816ee23942ea5e394a5fb88247f748eead74e22f65",
"ac4e7c9132c25867f06e6b13a39c7714982a5dfd7ba8748323900cf05a8f0712",
"89cf905e2f716d0707baa735baa28c096bc6c8561e8f83d11334102e7b4d3774"
],
"vss_commitment": [
"04f63b636f91fda4fa756c64cd34c186e4595a5b4a6ed6351ba0e99961f2a189001f6f708312ed0ac8c1e291d6064e236e265f2b1b561925a29a39c2d3ad9f866b",
"040269fedd5bdb0d7bed5dd50f9fec28415d51694441dc6c5b0b3e2fd577429c40832c6263e9d218f6ae8cc6a87f72d69d3dc0096a8779d7530fec4983ed6c95b1",
"04fa8cf2f9a25d2d5b52872dd27afd89dfff5bad33f3335726fc56b49989f64c041e765acd4719bad295620393b00ec3f1b5420f02bad4794998d5f26c435deee5"
],
"pok64": "6888a2ffd199e69806e2c067befc41bd58de0605407542163031e8d75dd1cf80b7fae9e12c8e618081cf79a84d2a3a293dd260234383e5ab587f4459c5963d15"
}
}
]
}
}