Compare commits
No commits in common. "frost" and "master" have entirely different histories.
3
.gitignore
vendored
3
.gitignore
vendored
@ -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
2
.gitmodules
vendored
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
@ -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 {
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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/
|
||||
|
@ -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
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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/
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -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`() {
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"aggregate_public_key": "bd5561ef6dbff52d3f73b8cb0c065328988b71d3386d23890744a0dd6ad27c15",
|
||||
"tweak_cache": "40252e41157cd26adda0440789236d38d3718b982853060ccbb8733f2df5bf6def6155bdeefcc6b83fe690d621b793b08f5b1562a7bef628c4db33f2d0b3f3bf2f541aaa000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"ec_tweak_add": "0444536a3cc348adb38660f06de15a6168c06d11a0ad00ca6ea34ff58a8300e2cc086d50550ee52f1d0334e31dfc67fa55201541078d89dcf79bf0c46a53e3af9b"
|
||||
}
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user