diff --git a/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c b/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c index d73865b..c6d21a8 100644 --- a/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c +++ b/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c @@ -1648,7 +1648,412 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256 * 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, jbyteArray) + (JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jtweak_cache, jbyteArray jtweak32) { - // TODO: Implement secp256k1_frost_pubkey_ec_tweak_add + 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 keyagg 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 keyagg 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[[B[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, jbyteArray jmsg32, jbyteArray jpubkey, jbyteArray jmy_id33, jobjectArray jids33, jbyteArray jtweak_cache, jbyteArray jadaptor) +{ + secp256k1_context *ctx = (secp256k1_context *)jctx; + + secp256k1_frost_session session; + + // TODO: Implement logic for the secp256k1_frost_nonce_process + +} + +/* + * 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); + // TODO: CHECKRESULT1(size != fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE, "invalid public nonce size", free_nonces(pubnonces, 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); + // TODO: 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 keyagg 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; } \ No newline at end of file