secp256k1-kmp/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c
2024-08-18 01:27:04 +02:00

2324 lines
82 KiB
C

#include <string.h>
#include <stdlib.h>
#ifdef WIN32
#define SECP256K1_STATIC // needed on windows when linking to a static version of secp256k1
#endif
#include "include/secp256k1.h"
#include "include/secp256k1_ecdh.h"
#include "include/secp256k1_recovery.h"
#include "include/secp256k1_schnorrsig.h"
#include "include/secp256k1_musig.h"
#include "include/secp256k1_frost.h"
#include "fr_acinq_secp256k1_Secp256k1CFunctions.h"
#define SIG_FORMAT_UNKNOWN 0
#define SIG_FORMAT_COMPACT 1
#define SIG_FORMAT_DER 2
void JNI_ThrowByName(JNIEnv *penv, const char *name, const char *msg)
{
jclass cls = (*penv)->FindClass(penv, name);
if (cls != NULL)
{
(*penv)->ThrowNew(penv, cls, msg);
(*penv)->DeleteLocalRef(penv, cls);
}
}
#define CHECKRESULT(errorcheck, message) \
{ \
if (errorcheck) \
{ \
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1Exception", message); \
return 0; \
} \
}
#define CHECKRESULT1(errorcheck, message, dosomething) \
{ \
if (errorcheck) \
{ \
dosomething; \
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1Exception", message); \
return 0; \
} \
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_context_create
* Signature: (I)J
*/
JNIEXPORT jlong JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1context_1create(JNIEnv *penv, jclass clazz, jint flags)
{
return (jlong)secp256k1_context_create(flags);
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_context_destroy
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1context_1destroy(JNIEnv *penv, jclass clazz, jlong ctx)
{
if (ctx != 0)
{
secp256k1_context_destroy((secp256k1_context *)ctx);
}
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_ec_seckey_verify
* Signature: (J[B)I
*/
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1seckey_1verify(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *seckey;
int result = 0;
if (jctx == 0)
return 0;
if (jseckey == NULL)
return 0;
if ((*penv)->GetArrayLength(penv, jseckey) != 32)
return 0;
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
result = secp256k1_ec_seckey_verify(ctx, (unsigned char *)seckey);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
return result;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ec_pubkey_parse
* Signature: (J[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1parse(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *pubkeyBytes;
secp256k1_pubkey pubkey;
size_t size;
int result = 0;
if (jctx == 0)
return 0;
if (jpubkey == NULL)
return 0;
size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
pubkeyBytes = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pubkeyBytes, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkeyBytes, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65);
pubkeyBytes = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pubkeyBytes, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkeyBytes, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ec_pubkey_create
* Signature: (J[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1create(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *seckey, *pubkey;
secp256k1_pubkey pub;
int result = 0;
size_t len;
jbyteArray jpubkey = 0;
if (jseckey == NULL)
return NULL;
if (jctx == 0)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
result = secp256k1_ec_pubkey_create(ctx, &pub, (unsigned char *)seckey);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_create failed");
jpubkey = (*penv)->NewByteArray(penv, 65);
pubkey = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
len = 65;
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pubkey, &len, &pub, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkey, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ecdsa_sign
* Signature: (J[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1sign(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jmsg, jbyteArray jseckey)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *seckey, *msg, *sig;
secp256k1_ecdsa_signature signature;
int result = 0;
jbyteArray jsig;
if (jctx == 0)
return NULL;
if (jmsg == NULL)
return NULL;
if (jseckey == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message key must be 32 bytes");
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
msg = (*penv)->GetByteArrayElements(penv, jmsg, 0);
result = secp256k1_ecdsa_sign(ctx, &signature, (unsigned char *)msg, (unsigned char *)seckey, NULL, NULL);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
(*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_sign failed");
jsig = (*penv)->NewByteArray(penv, 64);
sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
result = secp256k1_ecdsa_signature_serialize_compact(ctx, (unsigned char *)sig, &signature);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_serialize_compact failed");
return jsig;
}
int GetSignatureFormat(size_t size)
{
if (size == 64)
return SIG_FORMAT_COMPACT;
if (size < 64)
return SIG_FORMAT_UNKNOWN;
return SIG_FORMAT_DER;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ecdsa_verify
* Signature: (J[B[B[B)I
*/
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1verify(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jbyteArray jpubkey)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *pub, *msg, *sig;
secp256k1_ecdsa_signature signature;
secp256k1_pubkey pubkey;
size_t sigSize, pubSize;
int result = 0;
if (jctx == 0)
return 0;
if (jsig == NULL)
return 0;
if (jmsg == NULL)
return 0;
if (jpubkey == NULL)
return 0;
sigSize = (*penv)->GetArrayLength(penv, jsig);
int sigFormat = GetSignatureFormat(sigSize);
CHECKRESULT(sigFormat == SIG_FORMAT_UNKNOWN, "invalid signature size");
pubSize = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((pubSize != 33) && (pubSize != 65), "invalid public key size");
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes");
sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
switch (sigFormat)
{
case SIG_FORMAT_COMPACT:
result = secp256k1_ecdsa_signature_parse_compact(ctx, &signature, (unsigned char *)sig);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_compact failed");
break;
case SIG_FORMAT_DER:
result = secp256k1_ecdsa_signature_parse_der(ctx, &signature, (unsigned char *)sig, sigSize);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_der failed");
break;
}
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pub, pubSize);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
msg = (*penv)->GetByteArrayElements(penv, jmsg, 0);
result = secp256k1_ecdsa_verify(ctx, &signature, (unsigned char *)msg, &pubkey);
(*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0);
return result;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ecdsa_signature_normalize
* Signature: (J[B[B)I
*/
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1signature_1normalize(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsigin, jbyteArray jsigout)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *sig;
secp256k1_ecdsa_signature signature_in, signature_out;
size_t size;
int result = 0;
int return_value = 0;
int sigFormat = SIG_FORMAT_UNKNOWN;
if (jctx == 0)
return 0;
if (jsigin == NULL)
return 0;
if (jsigout == NULL)
return 0;
size = (*penv)->GetArrayLength(penv, jsigin);
sigFormat = GetSignatureFormat(size);
CHECKRESULT(sigFormat == SIG_FORMAT_UNKNOWN, "invalid signature size");
CHECKRESULT((*penv)->GetArrayLength(penv, jsigout) != 64, "output signature length must be 64 bytes");
sig = (*penv)->GetByteArrayElements(penv, jsigin, 0);
switch (sigFormat)
{
case SIG_FORMAT_COMPACT:
result = secp256k1_ecdsa_signature_parse_compact(ctx, &signature_in, (unsigned char *)sig);
(*penv)->ReleaseByteArrayElements(penv, jsigin, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_compact failed");
break;
case SIG_FORMAT_DER:
result = secp256k1_ecdsa_signature_parse_der(ctx, &signature_in, (unsigned char *)sig, size);
(*penv)->ReleaseByteArrayElements(penv, jsigin, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_der failed");
break;
}
return_value = secp256k1_ecdsa_signature_normalize(ctx, &signature_out, &signature_in);
sig = (*penv)->GetByteArrayElements(penv, jsigout, 0);
result = secp256k1_ecdsa_signature_serialize_compact(ctx, (unsigned char *)sig, &signature_out);
(*penv)->ReleaseByteArrayElements(penv, jsigout, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_serialize_compact failed");
return return_value;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ec_privkey_negate
* Signature: (J[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1negate(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *seckey;
int result = 0;
if (jctx == 0)
return 0;
if (jseckey == NULL)
return 0;
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
result = secp256k1_ec_seckey_negate(ctx, (unsigned char *)seckey);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
CHECKRESULT(!result, "secp256k1_ec_seckey_negate failed");
return jseckey;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ec_pubkey_negate
* Signature: (J[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1negate(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *pub;
secp256k1_pubkey pubkey;
size_t size;
int result = 0;
if (jctx == 0)
return 0;
if (jpubkey == NULL)
return 0;
size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pub, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
result = secp256k1_ec_pubkey_negate(ctx, &pubkey);
CHECKRESULT(!result, "secp256k1_ec_pubkey_negate failed");
size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ec_privkey_tweak_add
* Signature: (J[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1tweak_1add(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jtweak)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *seckey, *tweak;
int result = 0;
if (jctx == 0)
return NULL;
if (jseckey == NULL)
return NULL;
if (jtweak == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes");
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0);
result = secp256k1_ec_seckey_tweak_add(ctx, (unsigned char *)seckey, (unsigned char *)tweak);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
(*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0);
CHECKRESULT(!result, "secp256k1_ec_seckey_tweak_add failed");
return jseckey;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ec_pubkey_tweak_add
* Signature: (J[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1tweak_1add(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey, jbyteArray jtweak)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *pub, *tweak;
secp256k1_pubkey pubkey;
size_t size;
int result = 0;
if (jctx == 0)
return NULL;
if (jpubkey == NULL)
return NULL;
if (jtweak == NULL)
return NULL;
size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes");
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pub, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0);
result = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, (unsigned char *)tweak);
(*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_tweak_add failed");
size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ec_privkey_tweak_mul
* Signature: (J[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1tweak_1mul(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jtweak)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *seckey, *tweak;
int result = 0;
if (jctx == 0)
return NULL;
if (jseckey == NULL)
return NULL;
if (jtweak == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes");
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0);
result = secp256k1_ec_seckey_tweak_mul(ctx, (unsigned char *)seckey, (unsigned char *)tweak);
CHECKRESULT(!result, "secp256k1_ec_seckey_tweak_mul failed");
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
(*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0);
return jseckey;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ec_pubkey_tweak_mul
* Signature: (J[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1tweak_1mul(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey, jbyteArray jtweak)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *pub, *tweak;
secp256k1_pubkey pubkey;
size_t size;
int result = 0;
if (jctx == 0)
return NULL;
if (jpubkey == NULL)
return NULL;
if (jtweak == NULL)
return NULL;
size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes");
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pub, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0);
result = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, (unsigned char *)tweak);
(*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_tweak_mul failed");
size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey;
}
void free_pubkeys(secp256k1_pubkey **pubkeys, size_t count)
{
size_t i;
for (i = 0; i < count; i++)
{
if (pubkeys[i] != NULL)
free(pubkeys[i]);
}
free(pubkeys);
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ec_pubkey_combine
* Signature: (J[[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1combine(JNIEnv *penv, jclass clazz, jlong jctx, jobjectArray jpubkeys)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *pub;
secp256k1_pubkey **pubkeys;
secp256k1_pubkey combined;
jbyteArray jpubkey;
size_t size, count;
size_t i;
int result = 0;
if (jctx == 0)
return NULL;
if (jpubkeys == NULL)
return NULL;
count = (*penv)->GetArrayLength(penv, jpubkeys);
CHECKRESULT(count < 1, "pubkey array cannot be empty")
pubkeys = calloc(count, sizeof(secp256k1_pubkey *));
for (i = 0; i < count; i++)
{
pubkeys[i] = calloc(1, sizeof(secp256k1_pubkey));
jpubkey = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jpubkeys, i);
size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT1((size != 33) && (size != 65), "invalid public key size", free_pubkeys(pubkeys, count));
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, pubkeys[i], (unsigned char *)pub, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT1(!result, "secp256k1_ec_pubkey_parse failed", free_pubkeys(pubkeys, count));
}
result = secp256k1_ec_pubkey_combine(ctx, &combined, (const secp256k1_pubkey *const *)pubkeys, count);
free_pubkeys(pubkeys, count);
CHECKRESULT(!result, "secp256k1_ec_pubkey_combine failed");
size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pub, &size, &combined, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ecdh
* Signature: (J[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdh(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jpubkey)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *seckeyBytes, *pubkeyBytes, *output;
secp256k1_pubkey pubkey;
jbyteArray joutput;
size_t size;
int result;
if (jctx == 0)
return NULL;
if (jseckey == NULL)
return NULL;
if (jpubkey == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "invalid private key size");
size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
pubkeyBytes = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pubkeyBytes, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkeyBytes, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
seckeyBytes = (*penv)->GetByteArrayElements(penv, jseckey, 0);
joutput = (*penv)->NewByteArray(penv, 32);
output = (*penv)->GetByteArrayElements(penv, joutput, 0);
result = secp256k1_ecdh(ctx, (unsigned char *)output, &pubkey, (unsigned char *)seckeyBytes, NULL, NULL);
(*penv)->ReleaseByteArrayElements(penv, joutput, output, 0);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckeyBytes, 0);
return joutput;
}
/*
* Class: fr_acinq_bitcoin_Secp256k1Bindings
* Method: secp256k1_ecdsa_recover
* Signature: (J[B[BI)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1recover(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jint recid)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *sig, *msg, *pub;
jbyteArray jpubkey;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_recoverable_signature signature;
secp256k1_ecdsa_signature dummy;
unsigned char dummyBytes[64];
size_t sigSize, size;
int result;
if (jctx == 0)
return NULL;
if (jsig == NULL)
return NULL;
if (jmsg == NULL)
return NULL;
CHECKRESULT(recid < 0 || recid > 3, "invalid recovery id");
sigSize = (*penv)->GetArrayLength(penv, jsig);
int sigFormat = GetSignatureFormat(sigSize);
CHECKRESULT(sigFormat == SIG_FORMAT_UNKNOWN, "invalid signature size");
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes");
sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
switch (sigFormat)
{
case SIG_FORMAT_COMPACT:
result = secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &signature, (unsigned char *)sig, recid);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_recoverable_signature_parse_compact failed");
break;
case SIG_FORMAT_DER:
result = secp256k1_ecdsa_signature_parse_der(ctx, &dummy, (unsigned char *)sig, sigSize);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_der failed");
result = secp256k1_ecdsa_signature_serialize_compact(ctx, dummyBytes, &dummy);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_serialize_compact failed");
result = secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &signature, dummyBytes, recid);
CHECKRESULT(!result, "secp256k1_ecdsa_recoverable_signature_parse_compact failed");
break;
}
msg = (*penv)->GetByteArrayElements(penv, jmsg, 0);
result = secp256k1_ecdsa_recover(ctx, &pubkey, &signature, (unsigned char *)msg);
(*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_recover failed");
size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey;
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_compact_to_der
* Signature: (J[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1compact_1to_1der(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *sig;
secp256k1_ecdsa_signature signature;
unsigned char der[73];
size_t size;
int result = 0;
if (jctx == 0)
return 0;
if (jsig == NULL)
return 0;
CHECKRESULT((*penv)->GetArrayLength(penv, jsig) != 64, "invalid signature size");
size = (*penv)->GetArrayLength(penv, jsig);
sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
result = secp256k1_ecdsa_signature_parse_compact(ctx, &signature, (unsigned char *)sig);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_compact failed");
size = 73;
result = secp256k1_ecdsa_signature_serialize_der(ctx, der, &size, &signature);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_serialize_der failed");
jsig = (*penv)->NewByteArray(penv, size);
sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
memcpy(sig, der, size);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
return jsig;
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_schnorrsig_sign
* Signature: (J[B[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1schnorrsig_1sign(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jmsg, jbyteArray jseckey, jbyteArray jauxrand32)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *seckey, *msg, *sig, *auxrand32 = NULL;
secp256k1_keypair keypair;
unsigned char signature[64];
int result = 0;
jbyteArray jsig;
if (jctx == 0)
return NULL;
if (jmsg == NULL)
return NULL;
if (jseckey == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes");
if (jauxrand32 != 0)
{
CHECKRESULT((*penv)->GetArrayLength(penv, jauxrand32) != 32, "auxiliary random data must be 32 bytes");
}
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
result = secp256k1_keypair_create(ctx, &keypair, seckey);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
CHECKRESULT(!result, "secp256k1_keypair_create failed");
msg = (*penv)->GetByteArrayElements(penv, jmsg, 0);
if (jauxrand32 != 0)
{
auxrand32 = (*penv)->GetByteArrayElements(penv, jauxrand32, 0);
}
result = secp256k1_schnorrsig_sign32(ctx, signature, (unsigned char *)msg, &keypair, auxrand32);
(*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0);
if (auxrand32 != 0)
{
(*penv)->ReleaseByteArrayElements(penv, jauxrand32, auxrand32, 0);
}
CHECKRESULT(!result, "secp256k1_schnorrsig_sign failed");
jsig = (*penv)->NewByteArray(penv, 64);
sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
memcpy(sig, signature, 64);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
return jsig;
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_schnorrsig_verify
* Signature: (J[B[B[B)I
*/
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1schnorrsig_1verify(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jbyteArray jpubkey)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *pub, *msg, *sig;
secp256k1_xonly_pubkey pubkey;
int result = 0;
if (jctx == 0)
return 0;
if (jsig == NULL)
return 0;
if (jmsg == NULL)
return 0;
if (jpubkey == NULL)
return 0;
CHECKRESULT((*penv)->GetArrayLength(penv, jsig) != 64, "signature must be 64 bytes");
CHECKRESULT((*penv)->GetArrayLength(penv, jpubkey) != 32, "public key must be 32 bytes");
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes");
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_xonly_pubkey_parse(ctx, &pubkey, (unsigned char *)pub);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
msg = (*penv)->GetByteArrayElements(penv, jmsg, 0);
result = secp256k1_schnorrsig_verify(ctx, (unsigned char *)sig, (unsigned char *)msg, 32, &pubkey);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
(*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0);
return result;
}
static void copy_bytes_from_java(JNIEnv *penv, jbyteArray source, size_t size, unsigned char *dest)
{
jbyte *ptr = NULL;
if (source == NULL)
return; // nothing to do
ptr = (*penv)->GetByteArrayElements(penv, source, 0);
memcpy(dest, ptr, size);
(*penv)->ReleaseByteArrayElements(penv, source, ptr, 0);
}
static void copy_bytes_to_java(JNIEnv *penv, jbyteArray dest, size_t size, unsigned char *source)
{
jbyte *ptr = (*penv)->GetByteArrayElements(penv, dest, 0);
memcpy(ptr, source, size);
(*penv)->ReleaseByteArrayElements(penv, dest, ptr, 0);
}
// session_id32: ByteArray, seckey: ByteArray?, pubkey: ByteArray, msg32: ByteArray?, keyagg_cache: ByteArray?, extra_input32: ByteArray?
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_musig_nonce_gen
* Signature: (J[B[B[B[B[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1nonce_1gen(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsession_id32, jbyteArray jseckey, jbyteArray jpubkey, jbyteArray jmsg32, jbyteArray jkeyaggcache, jbyteArray jextra_input32)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
int result = 0;
size_t size;
secp256k1_musig_pubnonce pubnonce;
secp256k1_musig_secnonce secnonce;
unsigned char session_id32[32];
jbyte *pubkey_ptr;
secp256k1_pubkey pubkey;
unsigned char seckey[32];
unsigned char msg32[32];
secp256k1_musig_keyagg_cache keyaggcache;
unsigned char extra_input32[32];
jbyteArray jnonce;
jbyte *nonce_ptr = NULL;
unsigned char nonce[fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE + fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE];
if (jctx == 0)
return NULL;
if (jsession_id32 == 0)
return NULL;
size = (*penv)->GetArrayLength(penv, jsession_id32);
CHECKRESULT(size != 32, "invalid session_id size");
copy_bytes_from_java(penv, jsession_id32, size, session_id32);
if (jseckey != NULL)
{
size = (*penv)->GetArrayLength(penv, jseckey);
CHECKRESULT(size != 32, "invalid private key size");
copy_bytes_from_java(penv, jseckey, size, seckey);
}
if (jpubkey == NULL)
return NULL;
size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
pubkey_ptr = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pubkey_ptr, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkey_ptr, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
if (jmsg32 != NULL)
{
size = (*penv)->GetArrayLength(penv, jmsg32);
CHECKRESULT(size != 32, "invalid message size");
copy_bytes_from_java(penv, jmsg32, size, msg32);
}
if (jkeyaggcache != NULL)
{
size = (*penv)->GetArrayLength(penv, jkeyaggcache);
CHECKRESULT(size != sizeof(secp256k1_musig_keyagg_cache), "invalid keyagg cache size");
copy_bytes_from_java(penv, jkeyaggcache, size, keyaggcache.data);
}
if (jextra_input32 != NULL)
{
size = (*penv)->GetArrayLength(penv, jextra_input32);
CHECKRESULT(size != 32, "invalid extra input size");
copy_bytes_from_java(penv, jextra_input32, size, extra_input32);
}
result = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_id32,
jseckey == NULL ? NULL : seckey, &pubkey,
jmsg32 == NULL ? NULL : msg32, jkeyaggcache == NULL ? NULL : &keyaggcache, jextra_input32 == NULL ? NULL : extra_input32);
CHECKRESULT(!result, "secp256k1_musig_nonce_gen failed");
memcpy(nonce, secnonce.data, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE);
result = secp256k1_musig_pubnonce_serialize(ctx, nonce + fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE, &pubnonce);
CHECKRESULT(!result, "secp256k1_musig_pubnonce_serialize failed");
jnonce = (*penv)->NewByteArray(penv, sizeof(nonce));
nonce_ptr = (*penv)->GetByteArrayElements(penv, jnonce, 0);
memcpy(nonce_ptr, nonce, sizeof(nonce));
(*penv)->ReleaseByteArrayElements(penv, jnonce, nonce_ptr, 0);
return jnonce;
}
void free_nonces(secp256k1_musig_pubnonce **nonces, size_t count)
{
size_t i;
for (i = 0; i < count; i++)
{
if (nonces[i] != NULL)
free(nonces[i]);
}
free(nonces);
}
void free_nonces(secp256k1_frost_pubnonce **nonces, size_t count)
{
size_t i;
for (i = 0; i < count; i++)
{
if (nonces[i] != NULL)
free(nonces[i]);
}
free(nonces);
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_musig_nonce_agg
* Signature: (J[[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1nonce_1agg(JNIEnv *penv, jclass clazz, jlong jctx, jobjectArray jnonces)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *in66;
secp256k1_musig_pubnonce **pubnonces;
secp256k1_musig_aggnonce combined;
jbyteArray jnonce;
size_t size, count;
size_t i;
int result = 0;
if (jctx == 0)
return NULL;
if (jnonces == NULL)
return NULL;
count = (*penv)->GetArrayLength(penv, jnonces);
CHECKRESULT(count <= 0, "public nonces count cannot be 0");
pubnonces = calloc(count, sizeof(secp256k1_musig_pubnonce *));
for (i = 0; i < count; i++)
{
pubnonces[i] = calloc(1, sizeof(secp256k1_musig_pubnonce));
jnonce = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jnonces, i);
size = (*penv)->GetArrayLength(penv, jnonce);
CHECKRESULT1(size != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE, "invalid public nonce size", free_nonces(pubnonces, count));
in66 = (*penv)->GetByteArrayElements(penv, jnonce, 0);
result = secp256k1_musig_pubnonce_parse(ctx, pubnonces[i], (unsigned char *)in66);
(*penv)->ReleaseByteArrayElements(penv, jnonce, in66, 0);
CHECKRESULT1(!result, "secp256k1_musig_pubnonce_parse failed", free_nonces(pubnonces, count));
}
result = secp256k1_musig_nonce_agg(ctx, &combined, (const secp256k1_musig_pubnonce *const *)pubnonces, count);
free_nonces(pubnonces, count);
CHECKRESULT(!result, "secp256k1_musig_nonce_agg failed");
jnonce = (*penv)->NewByteArray(penv, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE);
in66 = (*penv)->GetByteArrayElements(penv, jnonce, 0);
result = secp256k1_musig_aggnonce_serialize(ctx, (unsigned char *)in66, &combined);
(*penv)->ReleaseByteArrayElements(penv, jnonce, in66, 0);
CHECKRESULT(!result, "secp256k1_musig_aggnonce_serialize failed");
return jnonce;
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_musig_pubkey_agg
* Signature: (J[[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1pubkey_1agg(JNIEnv *penv, jclass clazz, jlong jctx, jobjectArray jpubkeys, jbyteArray jkeyaggcache)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *pub;
secp256k1_pubkey **pubkeys;
secp256k1_xonly_pubkey combined;
secp256k1_musig_keyagg_cache keyaggcache;
jbyteArray jpubkey;
size_t size, count;
size_t i;
int result = 0;
if (jctx == 0)
return NULL;
if (jpubkeys == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jpubkeys) <= 0, "pubkeys count cannot be 0");
if (jkeyaggcache != NULL)
{
size = (*penv)->GetArrayLength(penv, jkeyaggcache);
CHECKRESULT(size != sizeof(secp256k1_musig_keyagg_cache), "invalid keyagg cache size");
copy_bytes_from_java(penv, jkeyaggcache, size, keyaggcache.data);
}
count = (*penv)->GetArrayLength(penv, jpubkeys);
pubkeys = calloc(count, sizeof(secp256k1_pubkey *));
for (i = 0; i < count; i++)
{
pubkeys[i] = calloc(1, sizeof(secp256k1_pubkey));
jpubkey = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jpubkeys, i);
size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT1((size != 33) && (size != 65), "invalid public key size", free_pubkeys(pubkeys, count));
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, pubkeys[i], (unsigned char *)pub, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT1(!result, "secp256k1_ec_pubkey_parse failed", free_pubkeys(pubkeys, count));
}
result = secp256k1_musig_pubkey_agg(ctx, NULL, &combined, jkeyaggcache == NULL ? NULL : &keyaggcache, (const secp256k1_pubkey *const *)pubkeys, count);
free_pubkeys(pubkeys, count);
CHECKRESULT(!result, "secp256k1_musig_pubkey_agg failed");
jpubkey = (*penv)->NewByteArray(penv, 32);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_xonly_pubkey_serialize(ctx, (unsigned char *)pub, &combined);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_xonly_pubkey_serialize failed");
if (jkeyaggcache != NULL)
{
pub = (*penv)->GetByteArrayElements(penv, jkeyaggcache, 0);
memcpy(pub, keyaggcache.data, sizeof(secp256k1_musig_keyagg_cache));
(*penv)->ReleaseByteArrayElements(penv, jkeyaggcache, pub, 0);
}
return jpubkey;
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_musig_pubkey_ec_tweak_add
* Signature: (J[B[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1pubkey_1ec_1tweak_1add(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jkeyaggcache, jbyteArray jtweak32)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *tweak32, *pub;
secp256k1_pubkey pubkey;
secp256k1_musig_keyagg_cache keyaggcache;
jbyteArray jpubkey;
size_t size;
int result = 0;
if (jctx == 0)
return NULL;
if (jkeyaggcache == NULL)
return NULL;
size = (*penv)->GetArrayLength(penv, jkeyaggcache);
CHECKRESULT(size != sizeof(secp256k1_musig_keyagg_cache), "invalid keyagg cache size");
copy_bytes_from_java(penv, jkeyaggcache, size, keyaggcache.data);
if (jtweak32 == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak32) != 32, "tweak must be 32 bytes");
tweak32 = (*penv)->GetByteArrayElements(penv, jtweak32, 0);
result = secp256k1_musig_pubkey_ec_tweak_add(ctx, &pubkey, &keyaggcache, tweak32);
(*penv)->ReleaseByteArrayElements(penv, jtweak32, tweak32, 0);
CHECKRESULT(!result, "secp256k1_musig_pubkey_ec_tweak_add failed");
jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
size = 65;
result = secp256k1_ec_pubkey_serialize(ctx, pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
pub = (*penv)->GetByteArrayElements(penv, jkeyaggcache, 0);
memcpy(pub, keyaggcache.data, sizeof(secp256k1_musig_keyagg_cache));
(*penv)->ReleaseByteArrayElements(penv, jkeyaggcache, pub, 0);
return jpubkey;
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_musig_pubkey_xonly_tweak_add
* Signature: (J[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1pubkey_1xonly_1tweak_1add(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jkeyaggcache, jbyteArray jtweak32)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *tweak32, *pub;
secp256k1_pubkey pubkey;
secp256k1_musig_keyagg_cache keyaggcache;
jbyteArray jpubkey;
size_t size;
int result = 0;
if (jctx == 0)
return NULL;
if (jkeyaggcache == NULL)
return NULL;
size = (*penv)->GetArrayLength(penv, jkeyaggcache);
CHECKRESULT(size != sizeof(secp256k1_musig_keyagg_cache), "invalid keyagg cache size");
copy_bytes_from_java(penv, jkeyaggcache, size, keyaggcache.data);
if (jtweak32 == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak32) != 32, "tweak must be 32 bytes");
tweak32 = (*penv)->GetByteArrayElements(penv, jtweak32, 0);
result = secp256k1_musig_pubkey_xonly_tweak_add(ctx, &pubkey, &keyaggcache, tweak32);
(*penv)->ReleaseByteArrayElements(penv, jtweak32, tweak32, 0);
CHECKRESULT(!result, "secp256k1_musig_pubkey_xonly_tweak_add failed");
jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
size = 65;
result = secp256k1_ec_pubkey_serialize(ctx, pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
pub = (*penv)->GetByteArrayElements(penv, jkeyaggcache, 0);
memcpy(pub, keyaggcache.data, sizeof(secp256k1_musig_keyagg_cache));
(*penv)->ReleaseByteArrayElements(penv, jkeyaggcache, pub, 0);
return jpubkey;
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_musig_nonce_process
* Signature: (J[B[B[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1nonce_1process(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jaggnonce, jbyteArray jmsg32, jbyteArray jkeyaggcache)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_musig_keyagg_cache keyaggcache;
secp256k1_musig_aggnonce aggnonce;
secp256k1_musig_session session;
unsigned char msg32[32];
jbyteArray jsession;
jbyte *ptr;
size_t size;
int result = 0;
if (jctx == 0)
return NULL;
if (jaggnonce == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jaggnonce) != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE, "invalid nonce size");
if (jmsg32 == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg32) != 32, "invalid message size");
if (jkeyaggcache == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jkeyaggcache) != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_KEYAGG_CACHE_SIZE, "invalid keyagg cache size");
ptr = (*penv)->GetByteArrayElements(penv, jaggnonce, 0);
result = secp256k1_musig_aggnonce_parse(ctx, &aggnonce, ptr);
(*penv)->ReleaseByteArrayElements(penv, jaggnonce, ptr, 0);
CHECKRESULT(!result, "secp256k1_musig_aggnonce_parse failed");
copy_bytes_from_java(penv, jmsg32, 32, msg32);
copy_bytes_from_java(penv, jkeyaggcache, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_KEYAGG_CACHE_SIZE, keyaggcache.data);
result = secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg32, &keyaggcache, NULL);
CHECKRESULT(!result, "secp256k1_musig_nonce_process failed");
jsession = (*penv)->NewByteArray(penv, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE);
copy_bytes_to_java(penv, jsession, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE, session.data);
return jsession;
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_musig_partial_sign
* Signature: (J[B[B[B[B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1partial_1sign(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsecnonce, jbyteArray jprivkey, jbyteArray jkeyaggcache, jbyteArray jsession)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_musig_partial_sig psig;
secp256k1_musig_secnonce secnonce;
unsigned char seckey[32];
secp256k1_keypair keypair;
secp256k1_musig_keyagg_cache keyaggcache;
secp256k1_musig_session session;
jbyteArray jpsig;
jbyte *ptr;
int result = 0;
if (jctx == 0)
return NULL;
if (jsecnonce == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jsecnonce) != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE, "invalid secret nonce size");
if (jprivkey == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jprivkey) != 32, "invalid private key size");
if (jkeyaggcache == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jkeyaggcache) != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_KEYAGG_CACHE_SIZE, "invalid cache size");
if (jsession == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jsession) != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE, "invalid session size");
copy_bytes_from_java(penv, jsecnonce, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE, secnonce.data);
copy_bytes_from_java(penv, jprivkey, 32, seckey);
result = secp256k1_keypair_create(ctx, &keypair, seckey);
CHECKRESULT(!result, "secp256k1_keypair_create failed");
copy_bytes_from_java(penv, jkeyaggcache, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_KEYAGG_CACHE_SIZE, keyaggcache.data);
copy_bytes_from_java(penv, jsession, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE, session.data);
result = secp256k1_musig_partial_sign(ctx, &psig, &secnonce, &keypair, &keyaggcache, &session);
CHECKRESULT(!result, "secp256k1_musig_partial_sign failed");
result = secp256k1_musig_partial_sig_serialize(ctx, seckey, &psig);
CHECKRESULT(!result, "secp256k1_musig_partial_sig_serialize failed");
jpsig = (*penv)->NewByteArray(penv, 32);
copy_bytes_to_java(penv, jpsig, 32, seckey);
return jpsig;
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_musig_partial_sig_verify
* Signature: (J[B[B[B[B[B)I
*/
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1partial_1sig_1verify(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpsig, jbyteArray jpubnonce, jbyteArray jpubkey, jbyteArray jkeyaggcache, jbyteArray jsession)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_musig_partial_sig psig;
secp256k1_musig_pubnonce pubnonce;
secp256k1_pubkey pubkey;
secp256k1_musig_keyagg_cache keyaggcache;
secp256k1_musig_session session;
jbyte *ptr;
int result = 0;
if (jctx == 0)
return 0;
if (jpsig == NULL)
return 0;
CHECKRESULT((*penv)->GetArrayLength(penv, jpsig) != 32, "invalid partial signature size");
if (jpubnonce == NULL)
return 0;
CHECKRESULT((*penv)->GetArrayLength(penv, jpubnonce) != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE, "invalid public nonce size");
if (jpubkey == NULL)
return 0;
CHECKRESULT(((*penv)->GetArrayLength(penv, jpubkey) != 33) && ((*penv)->GetArrayLength(penv, jpubkey) != 65), "invalid public key size");
if (jkeyaggcache == NULL)
return 0;
CHECKRESULT((*penv)->GetArrayLength(penv, jkeyaggcache) != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_KEYAGG_CACHE_SIZE, "invalid cache size");
if (jsession == NULL)
return 0;
CHECKRESULT((*penv)->GetArrayLength(penv, jsession) != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE, "invalid session size");
ptr = (*penv)->GetByteArrayElements(penv, jpsig, 0);
result = secp256k1_musig_partial_sig_parse(ctx, &psig, ptr);
(*penv)->ReleaseByteArrayElements(penv, jpsig, ptr, 0);
CHECKRESULT(!result, "secp256k1_musig_partial_sig_parse failed");
ptr = (*penv)->GetByteArrayElements(penv, jpubnonce, 0);
result = secp256k1_musig_pubnonce_parse(ctx, &pubnonce, ptr);
(*penv)->ReleaseByteArrayElements(penv, jpubnonce, ptr, 0);
CHECKRESULT(!result, "secp256k1_musig_pubnonce_parse failed");
ptr = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, ptr, (*penv)->GetArrayLength(penv, jpubkey));
(*penv)->ReleaseByteArrayElements(penv, jpubkey, ptr, 0);
CHECKRESULT(!result, "secp256k1_musig_pubkey_parse failed");
copy_bytes_from_java(penv, jkeyaggcache, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_KEYAGG_CACHE_SIZE, keyaggcache.data);
copy_bytes_from_java(penv, jsession, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE, session.data);
result = secp256k1_musig_partial_sig_verify(ctx, &psig, &pubnonce, &pubkey, &keyaggcache, &session);
return result;
}
void free_partial_sigs(secp256k1_musig_partial_sig **psigs, size_t count)
{
size_t i;
for (i = 0; i < count; i++)
{
if (psigs[i] != NULL)
free(psigs[i]);
}
free(psigs);
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_musig_partial_sig_agg
* Signature: (J[B[[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1partial_1sig_1agg(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsession, jobjectArray jpsigs)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_musig_session session;
secp256k1_musig_partial_sig **psigs;
unsigned char sig64[64];
secp256k1_musig_keyagg_cache keyaggcache;
jbyteArray jpsig;
jbyte *ptr;
size_t size, count;
size_t i;
int result = 0;
if (jctx == 0)
return NULL;
if (jsession == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jsession) != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE, "invalid session size");
copy_bytes_from_java(penv, jsession, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE, session.data);
if (jpsigs == NULL)
return NULL;
count = (*penv)->GetArrayLength(penv, jpsigs);
CHECKRESULT(count <= 0, "partial sigs count cannot be 0");
psigs = calloc(count, sizeof(secp256k1_musig_partial_sig *));
for (i = 0; i < count; i++)
{
psigs[i] = calloc(1, sizeof(secp256k1_musig_partial_sig));
jpsig = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jpsigs, i);
size = (*penv)->GetArrayLength(penv, jpsig);
CHECKRESULT1(size != 32, "invalid partial signature size", free_partial_sigs(psigs, count));
ptr = (*penv)->GetByteArrayElements(penv, jpsig, 0);
result = secp256k1_musig_partial_sig_parse(ctx, psigs[i], (unsigned char *)ptr);
(*penv)->ReleaseByteArrayElements(penv, jpsig, ptr, 0);
CHECKRESULT1(!result, "secp256k1_musig_partial_sig_parse failed", free_partial_sigs(psigs, count));
}
result = secp256k1_musig_partial_sig_agg(ctx, sig64, &session, (const secp256k1_musig_partial_sig *const *)psigs, count);
free_partial_sigs(psigs, count);
CHECKRESULT(!result, "secp256k1_musig_pubkey_agg failed");
jpsig = (*penv)->NewByteArray(penv, 64);
copy_bytes_to_java(penv, jpsig, 64, sig64);
return jpsig;
}
/*
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
* Method: secp256k1_frost_shares_gen
* Signature: (J[B[BII[[B)[[[B
*/
JNIEXPORT jobjectArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1frost_1shares_1gen
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpok64, jbyteArray jseed32, jint jthreshold, jint jn_participants, jobjectArray jids33)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_frost_share **shares;
secp256k1_pubkey **vss_commitment;
jbyte* pok64;
size_t size;
jbyte *pubkeyBytes;
unsigned char seed32[32];
const jbyte *ids33[jn_participants];
if (jctx == 0)
return NULL;
if (jseed32 == NULL)
return NULL;
if (jids33 == NULL)
return NULL;
CHECKRESULT(jthreshold <= 0, "threshold can't be 0");
CHECKRESULT(jn_participants <= 0, "n_participants can't be 0");
CHECKRESULT(jthreshold > jn_participants, "threshold can't be greater then n_participants");
size = (*penv)->GetArrayLength(penv, jseed32);
CHECKRESULT(size != 32, "invalid seed32 size");
copy_bytes_from_java(penv, jseed32, size, seed32);
size = (*penv)->GetArrayLength(penv, jids33);
CHECKRESULT(size != jn_participants, "invalid ids33 size");
CHECKRESULT((*penv)->GetArrayLength(penv, jpok64) != 64, "pok64 length must be 64 bytes");
shares = calloc(jn_participants, sizeof(secp256k1_frost_share*));
vss_commitment = calloc(jthreshold, sizeof(secp256k1_pubkey*));
for (i = 0; i < jn_participants; i++)
{
jbyteArray id33 = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jids33, i);
// TODO: Check id33 size is 33...
ids33[i] = (*penv)->GetByteArrayElements(penv, id33, 0); // TODO: use setElement
}
int result = 0;
pok64 = (*penv)->GetByteArrayElements(penv, jpok64, 0);
result = secp256k1_frost_shares_gen(
ctx,
shares,
vss_commitment,
(unsigned char *) pok64,
seed32,
jthreshold,
jn_participants,
ids33
);
(*penv)->ReleaseByteArrayElements(penv, jpok64, pok64, 0);
CHECKRESULT(!result, "secp256k1_frost_shares_gen failed");
jobjectArray output = (*penv)->NewObjectArray(penv, 2, jobjectArray, NULL);
jobjectArray jshares = (*penv)->NewObjectArray(penv, jn_participants, jbyteArray, NULL);
// Copy shares into jshares
unsigned char out32[32];
for (i = 0; i < jn_participants; i++)
{
result = secp256k1_frost_share_serialize(ctx, out32, shares[i]);
CHECKRESULT(!result, "secp256k1_frost_share_serialize failed");
jbyteArray jshare = (*penv)->NewByteArray(penv, 32);
copy_bytes_to_java(penv, jshare, 32, out32);
jshares[i] = jshare;
}
output[0] = jshares;
jobjectArray jvss_commitment = (*penv)->NewObjectArray(penv, jthreshold, jbyteArray, NULL);
// Copy vss_commitment into jvss_commitment
for (i = 0; i < jn_participants; i++)
{
// need share object...
result = secp256k1_xonly_pubkey_serialize(ctx, out32, vss_commitment[i]);
CHECKRESULT(!result, "secp256k1_xonly_pubkey_serialize failed");
jbyteArray jpubkey = (*penv)->NewByteArray(penv, 32);
copy_bytes_to_java(penv, jpubkey, 32, out32);
jvss_commitment[i] = jpubkey;
}
output[1] = jvss_commitment;
return output;
}
void free_shares(secp256k1_frost_share **shares, size_t count)
{
size_t i;
for (i = 0; i < count; i++)
{
if (shares[i] != NULL)
free(shares[i]);
}
free(shares);
}
/*
* 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 *penv, jclass clazz, jlong jctx, jobjectArray jshares, jobjectArray jvss_commitments, jint jtotalShareCount, jint jthreshold, jbyteArray jid33)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_frost_share aggregate_share;
jbyteArray jaggregate_share;
secp256k1_xonly_pubkey aggregate_public_key;
jbyteArray jaggregate_public_key;
const secp256k1_frost_share **shares;
jbyteArray jshare;
jbyte *in32;
secp256k1_xonly_pubkey **vss_commitments;
jbyteArray jvss_commitment;
jbyte *pub;
jbyte *id33;
size_t size, count;
jbyteArray jresult;
jbyte *result_ptr = NULL;
unsigned char result_array[32 + 32]; // TODO: Put correct pubnonce
if (jctx == 0)
return NULL;
if (jshares == NULL)
return NULL;
if (jvss_commitments == NULL)
return NULL;
if (jid33 == NULL)
return NULL;
CHECKRESULT(jthreshold <= 0, "threshold can't be 0");
CHECKRESULT(jtotalShareCount <= 0, "totalShareCount can't be 0");
CHECKRESULT(jthreshold > jtotalShareCount, "threshold can't be greater then totalShareCount");
count = (*penv)->GetArrayLength(penv, jnonces);
CHECKRESULT(count != jtotalShareCount, "jshares count should be total share count.");
shares = calloc(count, sizeof(secp256k1_frost_share*));
for (i = 0; i < count; i++)
{
shares[i] = calloc(1, sizeof(secp256k1_frost_share));
jshare = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jshares, i);
size = (*penv)->GetArrayLength(penv, jshare);
CHECKRESULT1(size != sizeof(secp256k1_frost_share), "invalid share size", free_shares(shares, count));
in32 = (*penv)->GetByteArrayElements(penv, jshare, 0);
result = secp256k1_frost_share_parse(ctx, shares[i], (unsigned char *)in32);
(*penv)->ReleaseByteArrayElements(penv, jshare, in32, 0);
CHECKRESULT1(!result, "secp256k1_frost_share_parse failed", free_shares(shares, count));
}
count = (*penv)->GetArrayLength(penv, jvss_commitments);
vss_commitments = calloc(count, sizeof(secp256k1_pubkey *));
for (i = 0; i < count; i++)
{
vss_commitments[i] = calloc(1, sizeof(secp256k1_pubkey));
jvss_commitment = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jvss_commitments, i);
size = (*penv)->GetArrayLength(penv, jvss_commitment);
CHECKRESULT1((size != 33) && (size != 65), "invalid public key size", free_pubkeys(pubkeys, count));
pub = (*penv)->GetByteArrayElements(penv, jvss_commitment, 0);
result = secp256k1_ec_pubkey_parse(ctx, vss_commitments[i], (unsigned char *)pub, size);
(*penv)->ReleaseByteArrayElements(penv, jvss_commitment, pub, 0);
CHECKRESULT1(!result, "secp256k1_ec_pubkey_parse failed", free_pubkeys(vss_commitments, count));
}
id33 = (*penv)->GetByteArrayElements(penv, jid33, 0);
int result = 0;
result = secp256k1_frost_share_agg(
ctx,
&aggregate_share,
&aggregate_public_key,
shares,
vss_commitments,
jtotalShareCount,
jthreshold,
(unsigned char *)id33
);
result = secp256k1_frost_share_serialize(ctx, result_array, &aggregate_share);
CHECKRESULT(!result, "secp256k1_frost_share_serialize failed");
result = secp256k1_xonly_pubkey_serialize(ctx, result_array + 32, &aggregate_public_key);
CHECKRESULT(!result, "secp256k1_xonly_pubkey_serialize failed");
jresult = (*penv)->NewByteArray(penv, sizeof(result_array));
result_ptr = (*penv)->GetByteArrayElements(penv, jresult, 0);
memcpy(result_ptr, result_array, sizeof(result_array));
(*penv)->ReleaseByteArrayElements(penv, jresult, result_ptr, 0);
return jresult;
}
/*
* 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 *penv, jclass clazz, jlong jctx, jint jthreshold, jbyteArray jid33, jbyteArray jshare, jobjectArray jvss_commitment)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_frost_share share;
jbyte *in32;
jbyte *id33;
secp256k1_xonly_pubkey *vss_commitment;
jbyte *jpub;
size_t size, count;
if (jctx == 0)
return NULL;
if (jid33 == NULL)
return NULL;
if (jshare == NULL)
return NULL;
if (jvss_commitment == NULL)
return NULL;
CHECKRESULT(jthreshold <= 0, "threshold can't be 0");
size = (*penv)->GetArrayLength(penv, jshare);
CHECKRESULT1(size != sizeof(secp256k1_frost_share), "invalid share size", free(&share));
in32 = (*penv)->GetByteArrayElements(penv, jshare, 0);
result = secp256k1_frost_share_parse(ctx, &share, (unsigned char *)in32);
(*penv)->ReleaseByteArrayElements(penv, jshare, in32, 0);
CHECKRESULT1(!result, "secp256k1_frost_share_parse failed", free(&share));
id33 = (*penv)->GetByteArrayElements(penv, jid33, 0);
jpub = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jvss_commitment, i);
size = (*penv)->GetArrayLength(penv, jpub);
CHECKRESULT1((size != 33) && (size != 65), "invalid public key size", free_pubkeys(pubkeys, count));
jpub = (*penv)->GetByteArrayElements(penv, jpub, 0);
result = secp256k1_ec_pubkey_parse(ctx, &vss_commitment, (unsigned char *)jpub, size);
(*penv)->ReleaseByteArrayElements(penv, jpub, jpub, 0);
CHECKRESULT1(!result, "secp256k1_ec_pubkey_parse failed", free(vss_commitment));
int result = secp256k1_frost_share_verify(
ctx,
jthreshold,
(unsigned char *)id33,
share,
vss_commitment
);
return result;
}
/*
* 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 *penv, jclass clazz, jlong jctx, jint jthreshold, jbyteArray jid33, jobjectArray jvss_commitments, jint jtotalSignersCount)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_pubkey pubshare;
jbyte *id33;
secp256k1_xonly_pubkey **vss_commitments;
jbyteArray jvss_commitment;
jbyte *jpubkey;
size_t size, count;
if (jctx == 0)
return NULL;
if (jid33 == NULL)
return NULL;
if (jvss_commitments == NULL)
return NULL;
CHECKRESULT(jthreshold <= 0, "threshold can't be 0");
CHECKRESULT(jtotalSignersCount <= 0, "totalSignersCount can't be 0");
CHECKRESULT(jthreshold > jtotalSignersCount, "totalSignersCount can't be greater then n_participants");
id33 = (*penv)->GetByteArrayElements(penv, jid33, 0);
count = (*penv)->GetArrayLength(penv, jvss_commitments);
vss_commitments = calloc(count, sizeof(secp256k1_pubkey *));
for (i = 0; i < count; i++)
{
vss_commitments[i] = calloc(1, sizeof(secp256k1_pubkey));
jvss_commitment = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jvss_commitments, i);
size = (*penv)->GetArrayLength(penv, jvss_commitment);
CHECKRESULT1((size != 33) && (size != 65), "invalid public key size", free_pubkeys(pubkeys, count));
jpubkey = (*penv)->GetByteArrayElements(penv, jvss_commitment, 0);
result = secp256k1_ec_pubkey_parse(ctx, vss_commitments[i], (unsigned char *)jpub, size);
(*penv)->ReleaseByteArrayElements(penv, jvss_commitment, jpub, 0);
CHECKRESULT1(!result, "secp256k1_ec_pubkey_parse failed", free_pubkeys(vss_commitments, count));
}
int result = secp256k1_frost_compute_pubshare(
ctx,
&pubshare,
jthreshold,
(unsigned char *)id33
vss_commitments,
jtotalSignersCount
);
jpubkey = (*penv)->NewByteArray(penv, 65);
jbyte *jpubkeyBytes = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)jpubkeyBytes, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, jpubkeyBytes, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey;
}
/*
* 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 *penv, jclass clazz, jlong jctx, jbyteArray jpublicKey)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_frost_tweak_cache tweak_cache;
secp256k1_xonly_pubkey public_key;
jbyte *pub;
size_t size, count;
if (jctx == 0)
return NULL;
if (jpublicKey == NULL)
return NULL;
pub = (*penv)->GetByteArrayElements(penv, jpublicKey, 0);
result = secp256k1_xonly_pubkey_parse(ctx, &public_key, (unsigned char *)pub);
(*penv)->ReleaseByteArrayElements(penv, jpublicKey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
int result = secp256k1_frost_pubkey_tweak(
ctx,
&tweak_cache,
&public_key
);
CHECKRESULT(!result, "secp256k1_frost_pubkey_tweak failed");
size = sizeof(secp256k1_frost_tweak_cache);
jbyteArray jtweak_cache = (*penv)->NewByteArray(penv, size);
copy_bytes_to_java(penv, jtweak_cache, size, tweak_cache.data);
return jtweak_cache;
}
/*
* 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 *penv, jclass clazz, jlong jctx, jbyteArray jtweak_cache, jbyteArray jtweak32)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *tweak32, *pub;
secp256k1_pubkey pubkey;
jbyteArray jpubkey;
secp256k1_frost_tweak_cache tweak_cache;
jbyte *tweak32 = (*penv)->GetByteArrayElements(penv, jtweak32, 0);;
size_t size, count;
if (jctx == 0)
return NULL;
if (jtweak_cache == NULL)
return NULL;
if (jtweak32 == NULL)
return NULL;
size = (*penv)->GetArrayLength(penv, jtweak_cache);
CHECKRESULT(size != sizeof(secp256k1_frost_tweak_cache), "invalid tweak_cache size");
copy_bytes_from_java(penv, jtweak_cache, size, tweak_cache.data);
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak32) != 32, "tweak must be 32 bytes");
tweak32 = (*penv)->GetByteArrayElements(penv, jtweak32, 0);
int result = secp256k1_frost_pubkey_ec_tweak_add(
ctx,
pubkey,
&tweak_cache,
&public_key
);
(*penv)->ReleaseByteArrayElements(penv, jtweak32, tweak32, 0);
CHECKRESULT(!result, "secp256k1_frost_pubkey_ec_tweak_add failed");
jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
size = 65;
result = secp256k1_ec_pubkey_serialize(ctx, pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
pub = (*penv)->GetByteArrayElements(penv, jtweak_cache, 0);
memcpy(pub, tweak_cache.data, sizeof(secp256k1_frost_tweak_cache));
(*penv)->ReleaseByteArrayElements(penv, jtweak_cache, pub, 0);
return jpubkey;
}
/*
* 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 *penv, jclass clazz, jlong jctx, jbyteArray jtweak_cache, jbyteArray jtweak32)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
jbyte *tweak32, *pub;
secp256k1_pubkey pubkey;
jbyteArray jpubkey;
secp256k1_frost_tweak_cache tweak_cache;
jbyte *tweak32 = (*penv)->GetByteArrayElements(penv, jtweak32, 0);;
size_t size, count;
if (jctx == 0)
return NULL;
if (jtweak_cache == NULL)
return NULL;
if (jtweak32 == NULL)
return NULL;
size = (*penv)->GetArrayLength(penv, jtweak_cache);
CHECKRESULT(size != sizeof(secp256k1_frost_tweak_cache), "invalid tweak_cache size");
copy_bytes_from_java(penv, jtweak_cache, size, tweak_cache.data);
if (jtweak32 == NULL)
return NULL;
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak32) != 32, "tweak must be 32 bytes");
tweak32 = (*penv)->GetByteArrayElements(penv, jtweak32, 0);
int result = secp256k1_frost_pubkey_xonly_tweak_add(
ctx,
&pubkey,
&tweak_cache,
&public_key
);
(*penv)->ReleaseByteArrayElements(penv, jtweak32, tweak32, 0);
CHECKRESULT(!result, "secp256k1_frost_pubkey_xonly_tweak_add failed");
jbyteArray jresult;
jbyte *result_ptr = NULL;
unsigned char result_array[32 + sizeof(secp256k1_frost_tweak_cache)]; // TODO: Put correct pubnonce
jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
size = 65;
result = secp256k1_ec_pubkey_serialize(ctx, pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
pub = (*penv)->GetByteArrayElements(penv, jtweak_cache, 0);
memcpy(pub, tweak_cache.data, sizeof(secp256k1_frost_tweak_cache));
(*penv)->ReleaseByteArrayElements(penv, jtweak_cache, pub, 0);
return jpubkey;
}
/*
* 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 *penv, jclass clazz, jlong jctx, jbyteArray jsession_id32, jbyteArray jshare, jbyteArray jmsg32, jbyteArray jpubkey, jbyteArray jextra_input32)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
int result = 0;
secp256k1_frost_secnonce secnonce;
secp256k1_frost_pubnonce pubnonce;
unsigned char session_id32[32];
secp256k1_frost_share share;
jbyte *in32;
jbyte *pubkey_ptr;
secp256k1_pubkey pubkey;
unsigned char msg32[32];
secp256k1_musig_keyagg_cache keyaggcache;
unsigned char extra_input32[32];
jbyteArray jnonce;
jbyte *nonce_ptr = NULL;
unsigned char nonce[sizeof(secp256k1_frost_secnonce) + sizeof(secp256k1_frost_pubnonce)]; // TODO: Put correct pubnonce
size_t size, count;
if (jctx == 0)
return NULL;
if (jsession_id32 == NULL)
return NULL;
size = (*penv)->GetArrayLength(penv, jsession_id32);
CHECKRESULT(size != 32, "invalid session_id size");
copy_bytes_from_java(penv, jsession_id32, size, session_id32);
if (jshare != NULL) {
size = (*penv)->GetArrayLength(penv, jshare);
// TODO: CHECKRESULT1(size != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE, "invalid public nonce size", free_nonces(pubnonces, count));
in32 = (*penv)->GetByteArrayElements(penv, jshare, 0);
result = secp256k1_frost_share_parse(ctx, &share, (unsigned char *)in32);
(*penv)->ReleaseByteArrayElements(penv, jshare, in32, 0);
// TODO: CHECKRESULT1(!result, "secp256k1_frost_share_parse failed", free_shares(shares, count));
}
if (jmsg32 != NULL)
{
size = (*penv)->GetArrayLength(penv, jmsg32);
CHECKRESULT(size != 32, "invalid message size");
copy_bytes_from_java(penv, jmsg32, size, msg32);
}
if (jpubkey != NULL) {
size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
pubkey_ptr = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pubkey_ptr, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkey_ptr, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
}
if (jextra_input32 != NULL)
{
size = (*penv)->GetArrayLength(penv, jextra_input32);
CHECKRESULT(size != 32, "invalid extra input size");
copy_bytes_from_java(penv, jextra_input32, size, extra_input32);
}
result = secp256k1_frost_nonce_gen(
ctx,
&secnonce,
&pubnonce,
session_id32,
jshare == NULL ? NULL : &share,
jmsg32 == NULL ? NULL : msg32,
jpubkey == NULL ? NULL :pubkey_ptr,
jextra_input32 == NULL ? NULL : extra_input32
);
CHECKRESULT(!result, "secp256k1_frost_nonce_gen failed");
memcpy(nonce, secnonce.data, sizeof(secp256k1_frost_secnonce));
result = secp256k1_frost_pubnonce_serialize(ctx, nonce + sizeof(secp256k1_frost_secnonce), &pubnonce);
CHECKRESULT(!result, "secp256k1_frost_pubnonce_serialize failed");
jnonce = (*penv)->NewByteArray(penv, sizeof(nonce));
nonce_ptr = (*penv)->GetByteArrayElements(penv, jnonce, 0);
memcpy(nonce_ptr, nonce, sizeof(nonce));
(*penv)->ReleaseByteArrayElements(penv, jnonce, nonce_ptr, 0);
return jnonce;
}
/*
* 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 *penv, jclass clazz, jlong jctx, jobjectArray jpubnonces, jint n_pubnonces, jbyteArray jmsg32, jbyteArray jpubkey, jbyteArray jmy_id33, jobjectArray jids33, jbyteArray jtweak_cache, jbyteArray jadaptor)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_frost_session session;
secp256k1_frost_pubnonce **pubnonces;
jbyte *in66, *pub, *id33;;
unsigned char msg32[32];
secp256k1_xonly_pubkey public_key;
const jbyte *ids33[jn_participants];
secp256k1_frost_tweak_cache tweak_cache;
secp256k1_pubkey adaptor;
size_t size, count;
if (jctx == 0)
return NULL;
if (jpubnonces == NULL)
return NULL;
if (jmsg32 == NULL)
return NULL;
if (jpubkey == NULL)
return NULL;
if (jmy_id33 == NULL)
return NULL;
if (jids33 == NULL)
return NULL;
CHECKRESULT(n_pubnonces <= 0, "n_pubnonces can't be 0");
count = (*penv)->GetArrayLength(penv, jpubnonces);
CHECKRESULT(count <= 0, "public nonces count cannot be 0");
CHECKRESULT(n_pubnonces != 0, "n_pubnonces doesn't match public nonces count");
pubnonces = calloc(count, sizeof(secp256k1_frost_pubnonce *));
for (i = 0; i < count; i++)
{
pubnonces[i] = calloc(1, sizeof(secp256k1_frost_pubnonce));
jnonce = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jpubnonces, i);
size = (*penv)->GetArrayLength(penv, jnonce);
CHECKRESULT1(size != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE, "invalid public nonce size", free_nonces(pubnonces, count));
in66 = (*penv)->GetByteArrayElements(penv, jnonce, 0);
result = secp256k1_frost_pubnonce_parse(ctx, pubnonces[i], (unsigned char *)in66);
(*penv)->ReleaseByteArrayElements(penv, jnonce, in66, 0);
CHECKRESULT1(!result, "secp256k1_frost_pubnonce_parse failed", free_nonces(pubnonces, count));
}
size = (*penv)->GetArrayLength(penv, jmsg32);
CHECKRESULT(size != 32, "invalid message size");
copy_bytes_from_java(penv, jmsg32, size, msg32);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_xonly_pubkey_parse(ctx, &public_key, (unsigned char *)pub);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_xonly_pubkey_parse failed");
id33 = (*penv)->GetByteArrayElements(penv, jmy_id33, 0);
size = (*penv)->GetArrayLength(penv, jids33);
CHECKRESULT(size != n_pubnonces, "invalid ids33 size");
for (i = 0; i < n_pubnonces; i++)
{
jbyteArray id33 = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jids33, i);
// TODO: Check id33 size is 33...
ids33[i] = (*penv)->GetByteArrayElements(penv, id33, 0);
}
if (jtweak_cache != NULL)
{
size = (*penv)->GetArrayLength(penv, jtweak_cache);
CHECKRESULT(size != sizeof(secp256k1_frost_tweak_cache), "invalid tweak_cache size");
copy_bytes_from_java(penv, jtweak_cache, size, tweak_cache.data);
}
if (jadaptor != NULL)
{
pub = (*penv)->GetByteArrayElements(penv, jadaptor, 0);
result = secp256k1_ec_pubkey_parse(ctx, &adaptor, (unsigned char *)pub, pubSize);
(*penv)->ReleaseByteArrayElements(penv, jadaptor, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
}
int result = secp256k1_frost_nonce_process(
ctx,
&session,
(const secp256k1_frost_pubnonce *const *)pubnonces,
n_pubnonces,
msg32,
&public_key,
id33,
ids33,
jtweak_cache == NULL ? NULL : &tweak_cache,
jadaptor == NULL ? NULL : &adaptor
);
CHECKRESULT(!result, "secp256k1_frost_nonce_process failed");
size = sizeof(secp256k1_frost_session);
jbyteArray jsession = (*penv)->NewByteArray(penv, size);
copy_bytes_to_java(penv, jsession, size, session.data);
return jsession;
}
/*
* 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 *penv, jclass clazz, jlong jctx, jbyteArray jsecnonce, jbyteArray jagg_share, jbyteArray jsession, jbyteArray jtweak_cache)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_frost_partial_sig partial_sig;
secp256k1_frost_secnonce secnonce;
secp256k1_frost_share agg_share;
jbyte *in32;
secp256k1_frost_session session;
secp256k1_frost_tweak_cache tweak_cache;
jbyteArray jpsig;
jbyte *ptr;
size_t size, count;
if (jctx == 0)
return NULL;
if (jsecnonce == NULL)
return NULL;
if (jagg_share == NULL)
return NULL;
if (jsession == NULL)
return NULL;
copy_bytes_from_java(penv, jsecnonce, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE, secnonce.data);
size = (*penv)->GetArrayLength(penv, jagg_share);
CHECKRESULT(size != sizeof(secp256k1_frost_share), "invalid agg_share size");
in32 = (*penv)->GetByteArrayElements(penv, jagg_share, 0);
result = secp256k1_frost_share_parse(ctx, &agg_share, (unsigned char *)in32);
(*penv)->ReleaseByteArrayElements(penv, jagg_share, in32, 0);
CHECKRESULT(!result, "secp256k1_frost_share_parse failed");
CHECKRESULT((*penv)->GetArrayLength(penv, jsession) != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE, "invalid session size");
copy_bytes_from_java(penv, jsession, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE, session.data);
if (jtweak_cache != NULL)
{
size = (*penv)->GetArrayLength(penv, jtweak_cache);
CHECKRESULT(size != sizeof(secp256k1_frost_tweak_cache), "invalid tweak_cache size");
copy_bytes_from_java(penv, jtweak_cache, size, tweak_cache.data);
}
int result = secp256k1_frost_partial_sign(
ctx,
&partial_sig,
&secnonce,
&agg_share,
&session,
jtweak_cache == NULL ? NULL : &tweak_cache
);
CHECKRESULT(!result, "secp256k1_frost_partial_sign failed");
jpsig = (*penv)->NewByteArray(penv, 32);
ptr = (*penv)->GetByteArrayElements(penv, jpsig, 0);
result = secp256k1_frost_partial_sig_serialize(ctx, (unsigned char *)ptr, &partial_sig);
CHECKRESULT(!result, "secp256k1_frost_partial_sig_serialize failed");
return jpsig;
}
/*
* 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 *penv, jclass clazz, jlong jctx, jbyteArray jpartial_sig, jbyteArray jpubnonce, jbyteArray jpubshare, jbyteArray jsession, jbyteArray jtweak_cache)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
secp256k1_frost_partial_sig partial_sig;
secp256k1_frost_pubnonce pubnonce;
secp256k1_pubkey pubshare;
secp256k1_frost_session session;
secp256k1_frost_tweak_cache tweak_cache;
jbyte *ptr, *pubkeyBytes;
size_t size, count;
if (jctx == 0)
return NULL;
if (jpartial_sig == NULL)
return NULL;
if (jpubnonce == NULL)
return NULL;
if (jpubshare == NULL)
return NULL;
if (jsession == NULL)
return NULL;
ptr = (*penv)->GetByteArrayElements(penv, jpartial_sig, 0);
result = secp256k1_frost_partial_sig_parse(ctx, &partial_sig, ptr);
(*penv)->ReleaseByteArrayElements(penv, jpartial_sig, ptr, 0);
CHECKRESULT(!result, "secp256k1_frost_partial_sig_parse failed");
ptr = (*penv)->GetByteArrayElements(penv, jpubnonce, 0);
result = secp256k1_frost_pubnonce_parse(ctx, &pubnonce, ptr);
(*penv)->ReleaseByteArrayElements(penv, jpubnonce, ptr, 0);
CHECKRESULT(!result, "secp256k1_frost_pubnonce_parse failed");
size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
pubkeyBytes = (*penv)->GetByteArrayElements(penv, jpubshare, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubshare, (unsigned char *)pubkeyBytes, size);
(*penv)->ReleaseByteArrayElements(penv, jpubshare, pubkeyBytes, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
size = (*penv)->GetArrayLength(penv, jsession);
CHECKRESULT(size != sizeof(secp256k1_frost_session), "invalid session size");
copy_bytes_from_java(penv, jsession, size, session.data);
if (jtweak_cache != NULL)
{
size = (*penv)->GetArrayLength(penv, jtweak_cache);
CHECKRESULT(size != sizeof(secp256k1_frost_tweak_cache), "invalid tweak_cache size");
copy_bytes_from_java(penv, jtweak_cache, size, tweak_cache.data);
}
int result = secp256k1_frost_partial_sig_verify(
ctx,
&partial_sig,
&pubnonce,
&pubshare,
&session,
&tweak_cache
);
return result;
}
void free_partial_sigs(secp256k1_frost_partial_sig **psigs, size_t count)
{
size_t i;
for (i = 0; i < count; i++)
{
if (psigs[i] != NULL)
free(psigs[i]);
}
free(psigs);
}
/*
* 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 *penv, jclass clazz, jlong jctx, jbyteArray jsession, jobjectArray jpartial_sigs, jint jn_sigs)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
unsigned char sig64[64];
secp256k1_frost_session session;
secp256k1_frost_partial_sig **psigs;
jbyteArray jpsig;
jbyte *ptr;
size_t size, count;
size_t i;
int result = 0;
if (jctx == 0)
return NULL;
if (jsession == NULL)
return NULL;
if (jpartial_sigs == NULL)
return NULL;
CHECKRESULT(jn_sigs <= 0, "n_sigs can't be 0");
size = (*penv)->GetArrayLength(penv, jsession);
CHECKRESULT(size != sizeof(secp256k1_frost_session), "invalid session size");
copy_bytes_from_java(penv, jsession, size, session.data);
if (jpsigs == NULL)
return NULL;
count = (*penv)->GetArrayLength(penv, jpsigs);
CHECKRESULT(count <= 0, "partial sigs count cannot be 0");
psigs = calloc(count, sizeof(secp256k1_frost_partial_sig *));
for (i = 0; i < count; i++)
{
psigs[i] = calloc(1, sizeof(secp256k1_frost_partial_sig));
jpsig = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jpsigs, i);
size = (*penv)->GetArrayLength(penv, jpsig);
CHECKRESULT1(size != 32, "invalid partial signature size", free_partial_sigs(psigs, count));
ptr = (*penv)->GetByteArrayElements(penv, jpsig, 0);
result = secp256k1_frost_partial_sig_parse(ctx, psigs[i], (unsigned char *)ptr);
(*penv)->ReleaseByteArrayElements(penv, jpsig, ptr, 0);
CHECKRESULT1(!result, "secp256k1_frost_partial_sig_parse failed", free_partial_sigs(psigs, count));
}
result = secp256k1_frost_partial_sig_agg(
ctx,
sig64,
&session,
(const secp256k1_frost_partial_sig *const *)psigs,
jn_sigs
);
free_partial_sigs(psigs, count);
CHECKRESULT(!result, "secp256k1_frost_partial_sig_agg failed");
jpsig = (*penv)->NewByteArray(penv, 64);
copy_bytes_to_java(penv, jpsig, 64, sig64);
return jpsig;
}