#include #include #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 jseed32, jint jthreshold, jint jn_participants, jobjectArray jids33) { secp256k1_context *ctx = (secp256k1_context *)jctx; // This is what gets returned secp256k1_frost_share shares[jn_participants]; secp256k1_pubkey vss_commitment[jthreshold]; unsigned char pok64[64]; size_t size; // This is what gets passed jbyte *pubkeyBytes; unsigned char seed32[32]; if (jseed32 != NULL) { size = (*penv)->GetArrayLength(penv, jseed32); CHECKRESULT(size != 32, "invalid seed32 size"); copy_bytes_from_java(penv, jseed32, size, seed32); } const jbyte *ids33[jn_participants]; // Copy over data from jids33 if (jids33 != NULL) { size = (*penv)->GetArrayLength(penv, jids33); CHECKRESULT(size != jn_participants, "invalid ids33 size"); 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); } } int result = 0; result = secp256k1_frost_shares_gen( ctx, shares, vss_commitment, pok64, seed32, jthreshold, jn_participants, ids33 ); (*penv)->ReleaseByteArrayElements(penv, jseed32, seed32, 0); CHECKRESULT(!result, "secp256k1_frost_shares_gen failed"); jbyte* jpok64; jobjectArray output = (*penv)->NewObjectArray(penv, 3, jobjectArray, NULL); output[0] = (*penv)->NewObjectArray(penv, jn_participants, jbyteArray, NULL); output[1] = (*penv)->NewObjectArray(penv, jthreshold, jbyteArray, NULL); output[2] = (*penv)->NewObjectArray(penv, 1, jbyteArray, NULL); // TODO: Copy over the required data... 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 jobjectArray 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; 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 ); jobjectArray output = (*penv)->NewObjectArray(penv, 2, jbyteArray, NULL); jaggregate_share = (*penv)->NewByteArray(penv, 64); copy_bytes_to_java(penv, jaggregate_share, 64, aggregate_share); output[0] = (*penv)->NewByteArray(penv, 32); pub = (*penv)->GetByteArrayElements(penv, output[0], 0); result = secp256k1_frost_share_serialize(ctx, (unsigned char *)pub, &aggregate_share); (*penv)->ReleaseByteArrayElements(penv, output[0], pub, 0); CHECKRESULT(!result, "secp256k1_frost_share_serialize failed"); output[1] = (*penv)->NewByteArray(penv, 32); pub = (*penv)->GetByteArrayElements(penv, output[1], 0); result = secp256k1_xonly_pubkey_serialize(ctx, (unsigned char *)pub, &aggregate_public_key); (*penv)->ReleaseByteArrayElements(penv, output[1], pub, 0); CHECKRESULT(!result, "secp256k1_xonly_pubkey_serialize failed"); return output; } /* * 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; share = calloc(1, sizeof(secp256k1_frost_share)); 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)); id33 = (*penv)->GetByteArrayElements(penv, jid33, 0); vss_commitment = calloc(1, sizeof(secp256k1_pubkey)); 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; 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; 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);; if (jctx == 0) return NULL; if (jtweak_cache == 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_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 jobjectArray 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);; if (jctx == 0) return NULL; if (jtweak_cache == 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_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_musig_keyagg_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 jobjectArray 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; size_t size; 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]; 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 (jshare != NULL) { share = calloc(1, sizeof(secp256k1_frost_share)); 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"); // TODO: copy nonce result... // 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; } /* * 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; count = (*penv)->GetArrayLength(penv, jpubnonces); CHECKRESULT(count <= 0, "public nonces count cannot be 0"); 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)); } if (jmsg32 != NULL) { 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); // Copy over data from jids33 if (jids33 != NULL) { 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); } } 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, &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; copy_bytes_from_java(penv, jsecnonce, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE, secnonce.data); if (jagg_share != NULL) { agg_share = calloc(1, sizeof(secp256k1_frost_share)); size = (*penv)->GetArrayLength(penv, jagg_share); CHECKRESULT1(size != sizeof(secp256k1_frost_share), "invalid agg_share size", free_shares(shares, count)); 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); CHECKRESULT1(!result, "secp256k1_frost_share_parse failed", free_shares(shares, count)); } 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); 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, &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; 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); 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; 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; }