Compare commits
5 Commits
snapshot/m
...
snapshot/i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0364ec762e | ||
|
|
aadffabe42 | ||
|
|
8e17e7030a | ||
|
|
929e2cda40 | ||
|
|
41eac9273f |
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -86,7 +86,7 @@ jobs:
|
||||
- name: Check Linux
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
shell: bash
|
||||
run: ./gradlew linuxX64Test
|
||||
run: ./gradlew linuxTest
|
||||
- name: Check iOS
|
||||
if: matrix.os == 'macOS-latest'
|
||||
shell: bash
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
- name: Publish Linux
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
shell: bash
|
||||
run: ./gradlew publishLinuxX64PublicationToMavenLocal :jni:jvm:linux:publishJvmPublicationToMavenLocal
|
||||
run: ./gradlew publishLinuxPublicationToMavenLocal :jni:jvm:linux:publishJvmPublicationToMavenLocal
|
||||
- name: Publish Windows
|
||||
if: matrix.os == 'windows-latest'
|
||||
shell: msys2 {0}
|
||||
|
||||
4
.github/workflows/snapshot.yml
vendored
4
.github/workflows/snapshot.yml
vendored
@@ -95,7 +95,7 @@ jobs:
|
||||
- name: Check Linux
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
shell: bash
|
||||
run: ./gradlew linuxX64Test
|
||||
run: ./gradlew linuxTest
|
||||
- name: Check iOS
|
||||
if: matrix.os == 'macOS-latest'
|
||||
shell: bash
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
- name: Publish Linux
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
shell: bash
|
||||
run: ./gradlew publishLinuxX64PublicationToMavenLocal :jni:jvm:linux:publishJvmPublicationToMavenLocal -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }}
|
||||
run: ./gradlew publishLinuxPublicationToMavenLocal :jni:jvm:linux:publishJvmPublicationToMavenLocal -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }}
|
||||
- name: Publish Windows
|
||||
if: matrix.os == 'windows-latest'
|
||||
shell: msys2 {0}
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -101,7 +101,7 @@ jobs:
|
||||
- name: Check Linux
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
shell: bash
|
||||
run: ./gradlew linuxX64Test
|
||||
run: ./gradlew linuxTest
|
||||
- name: Check iOS
|
||||
if: matrix.os == 'macOS-latest'
|
||||
shell: bash
|
||||
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "native/secp256k1"]
|
||||
path = native/secp256k1
|
||||
url = https://github.com/jonasnick/secp256k1.git
|
||||
url = https://github.com/bitcoin-core/secp256k1.git
|
||||
|
||||
@@ -3,8 +3,8 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.dokka.Platform
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform") version "1.9.21"
|
||||
id("org.jetbrains.dokka") version "1.9.10"
|
||||
kotlin("multiplatform") version "1.8.21"
|
||||
id("org.jetbrains.dokka") version "1.8.10"
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@ buildscript {
|
||||
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:7.3.1")
|
||||
classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.9.10")
|
||||
classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.8.10")
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group = "fr.acinq.secp256k1"
|
||||
version = "0.13.0-MUSIG2-SNAPSHOT"
|
||||
version = "0.12.0-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
google()
|
||||
@@ -52,22 +52,20 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
val nativeMain by sourceSets.creating
|
||||
val nativeMain by sourceSets.creating { dependsOn(commonMain) }
|
||||
|
||||
linuxX64 {
|
||||
linuxX64("linux") {
|
||||
secp256k1CInterop("host")
|
||||
compilations["main"].defaultSourceSet.dependsOn(nativeMain)
|
||||
// https://youtrack.jetbrains.com/issue/KT-39396
|
||||
compilations["main"].kotlinOptions.freeCompilerArgs += listOf("-include-binary", "$rootDir/native/build/linux/libsecp256k1.a")
|
||||
}
|
||||
|
||||
iosX64 {
|
||||
secp256k1CInterop("ios")
|
||||
}
|
||||
|
||||
iosArm64 {
|
||||
secp256k1CInterop("ios")
|
||||
}
|
||||
|
||||
iosSimulatorArm64 {
|
||||
ios {
|
||||
secp256k1CInterop("ios")
|
||||
compilations["main"].defaultSourceSet.dependsOn(nativeMain)
|
||||
// https://youtrack.jetbrains.com/issue/KT-39396
|
||||
compilations["main"].kotlinOptions.freeCompilerArgs += listOf("-include-binary", "$rootDir/native/build/ios/libsecp256k1.a")
|
||||
}
|
||||
|
||||
sourceSets.all {
|
||||
@@ -82,9 +80,9 @@ allprojects {
|
||||
val currentOs = OperatingSystem.current()
|
||||
val targets = when {
|
||||
currentOs.isLinux -> listOf()
|
||||
currentOs.isMacOsX -> listOf("linuxX64")
|
||||
currentOs.isWindows -> listOf("linuxX64")
|
||||
else -> listOf("linuxX64")
|
||||
currentOs.isMacOsX -> listOf("linux")
|
||||
currentOs.isWindows -> listOf("linux")
|
||||
else -> listOf("linux")
|
||||
}.mapNotNull { kotlin.targets.findByName(it) as? KotlinNativeTarget }
|
||||
|
||||
configure(targets) {
|
||||
|
||||
@@ -6,10 +6,11 @@ import fr.acinq.secp256k1.NativeSecp256k1
|
||||
import java.util.*
|
||||
|
||||
public object NativeSecp256k1AndroidLoader {
|
||||
|
||||
@JvmStatic
|
||||
@Synchronized
|
||||
@Throws(Exception::class)
|
||||
public fun load(): Secp256k1 {
|
||||
fun load(): Secp256k1 {
|
||||
try {
|
||||
System.loadLibrary("secp256k1-jni")
|
||||
return NativeSecp256k1
|
||||
@@ -26,4 +27,5 @@ public object NativeSecp256k1AndroidLoader {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,34 +7,6 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FLAGS_TYPE_CONTEXT
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FLAGS_TYPE_CONTEXT 1L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FLAGS_TYPE_COMPRESSION
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FLAGS_TYPE_COMPRESSION 2L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FLAGS_BIT_CONTEXT_VERIFY
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FLAGS_BIT_CONTEXT_VERIFY 256L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FLAGS_BIT_CONTEXT_SIGN
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FLAGS_BIT_CONTEXT_SIGN 512L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FLAGS_BIT_COMPRESSION
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_FLAGS_BIT_COMPRESSION 256L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_CONTEXT_VERIFY
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_CONTEXT_VERIFY 257L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_CONTEXT_SIGN
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_CONTEXT_SIGN 513L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_CONTEXT_NONE
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_CONTEXT_NONE 1L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_EC_COMPRESSED
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_EC_COMPRESSED 258L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_EC_UNCOMPRESSED
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_EC_UNCOMPRESSED 2L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE 66L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE 132L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_KEYAGG_CACHE_SIZE
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_KEYAGG_CACHE_SIZE 197L
|
||||
#undef fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE
|
||||
#define fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SESSION_SIZE 133L
|
||||
/*
|
||||
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
|
||||
* Method: secp256k1_context_create
|
||||
@@ -195,78 +167,6 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1schnorrsig_1verify
|
||||
(JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* 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 *, jclass, jlong, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* 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 *, jclass, jlong, jobjectArray);
|
||||
|
||||
/*
|
||||
* 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 *, jclass, jlong, jobjectArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
|
||||
* Method: secp256k1_musig_pubkey_ec_tweak_add
|
||||
* Signature: (J[B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1pubkey_1ec_1tweak_1add
|
||||
(JNIEnv *, jclass, jlong, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* 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 *, jclass, jlong, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* 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 *, jclass, jlong, jbyteArray, jbyteArray, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: fr_acinq_secp256k1_Secp256k1CFunctions
|
||||
* Method: secp256k1_musig_partial_sign
|
||||
* Signature: (J[B[B[B[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1partial_1sign
|
||||
(JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* 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 *, jclass, jlong, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* 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 *, jclass, jlong, jbyteArray, jobjectArray);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "include/secp256k1_ecdh.h"
|
||||
#include "include/secp256k1_recovery.h"
|
||||
#include "include/secp256k1_schnorrsig.h"
|
||||
#include "include/secp256k1_musig.h"
|
||||
#include "fr_acinq_secp256k1_Secp256k1CFunctions.h"
|
||||
|
||||
#define SIG_FORMAT_UNKNOWN 0
|
||||
@@ -24,26 +23,75 @@ void JNI_ThrowByName(JNIEnv *penv, const char *name, const char *msg)
|
||||
(*penv)->DeleteLocalRef(penv, cls);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* secp256k1 uses callbacks for errors that are either hw pbs or bugs in the calling library, for example
|
||||
* passing parameters with values that are explicitly defined as illegal in the API, and should never be called for normal operations
|
||||
* But if they are, default behaviour is to print an error to stderr and abort which is not what we want especially in mobile apps
|
||||
* => we set up string pointers in every method, and custom callback that will set them to the message passed in by sec256k1's callbacks, which
|
||||
* we turn into specific Sec256k1 exceptions
|
||||
*/
|
||||
#define SETUP_ERROR_CALLBACKS \
|
||||
char *error_callback_message = NULL; \
|
||||
char *illegal_callback_message = NULL; \
|
||||
secp256k1_context_set_error_callback(ctx, my_error_callback_fn, &error_callback_message); \
|
||||
secp256k1_context_set_illegal_callback(ctx, my_illegal_callback_fn, &illegal_callback_message);
|
||||
|
||||
#define CHECKRESULT(errorcheck, message) \
|
||||
{ \
|
||||
if (errorcheck) \
|
||||
{ \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1Exception", message); \
|
||||
return 0; \
|
||||
} \
|
||||
#define CHECKRESULT(errorcheck, message) \
|
||||
{ \
|
||||
if (error_callback_message) \
|
||||
{ \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1ErrorCallbackException", error_callback_message); \
|
||||
return 0; \
|
||||
} \
|
||||
if (illegal_callback_message) \
|
||||
{ \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1IllegalCallbackException", illegal_callback_message); \
|
||||
return 0; \
|
||||
} \
|
||||
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; \
|
||||
} \
|
||||
#define CHECKRESULT1(errorcheck, message, dosomething) \
|
||||
{ \
|
||||
if (error_callback_message) \
|
||||
{ \
|
||||
dosomething; \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1ErrorCallbackException", error_callback_message); \
|
||||
return 0; \
|
||||
} \
|
||||
if (illegal_callback_message) \
|
||||
{ \
|
||||
dosomething; \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1IllegalCallbackException", illegal_callback_message); \
|
||||
return 0; \
|
||||
} \
|
||||
if (errorcheck) \
|
||||
{ \
|
||||
JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1Exception", message); \
|
||||
return 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
void my_illegal_callback_fn(const char *str, void *data)
|
||||
{
|
||||
if (data != NULL)
|
||||
{
|
||||
*(char **)data = str;
|
||||
}
|
||||
}
|
||||
|
||||
void my_error_callback_fn(const char *str, void *data)
|
||||
{
|
||||
if (data != NULL)
|
||||
{
|
||||
*(char **)data = str;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: fr_acinq_bitcoin_Secp256k1Bindings
|
||||
* Method: secp256k1_context_create
|
||||
@@ -85,6 +133,8 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
|
||||
if ((*penv)->GetArrayLength(penv, jseckey) != 32)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
|
||||
result = secp256k1_ec_seckey_verify(ctx, (unsigned char *)seckey);
|
||||
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
|
||||
@@ -109,6 +159,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
if (jpubkey == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
size = (*penv)->GetArrayLength(penv, jpubkey);
|
||||
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
|
||||
|
||||
@@ -145,6 +197,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
if (jctx == 0)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
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);
|
||||
@@ -179,6 +233,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
if (jseckey == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
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);
|
||||
@@ -229,6 +285,8 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
|
||||
if (jpubkey == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
sigSize = (*penv)->GetArrayLength(penv, jsig);
|
||||
int sigFormat = GetSignatureFormat(sigSize);
|
||||
CHECKRESULT(sigFormat == SIG_FORMAT_UNKNOWN, "invalid signature size");
|
||||
@@ -286,6 +344,8 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
|
||||
if (jsigout == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
size = (*penv)->GetArrayLength(penv, jsigin);
|
||||
sigFormat = GetSignatureFormat(size);
|
||||
CHECKRESULT(sigFormat == SIG_FORMAT_UNKNOWN, "invalid signature size");
|
||||
@@ -329,6 +389,9 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
return 0;
|
||||
if (jseckey == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
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);
|
||||
@@ -355,6 +418,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
if (jpubkey == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
size = (*penv)->GetArrayLength(penv, jpubkey);
|
||||
CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
|
||||
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
|
||||
@@ -392,6 +457,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
if (jtweak == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
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);
|
||||
@@ -423,6 +490,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
if (jtweak == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
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");
|
||||
@@ -464,6 +533,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
if (jtweak == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
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);
|
||||
@@ -495,6 +566,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
if (jtweak == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
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");
|
||||
@@ -549,9 +622,10 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
if (jpubkeys == NULL)
|
||||
return NULL;
|
||||
|
||||
count = (*penv)->GetArrayLength(penv, jpubkeys);
|
||||
CHECKRESULT(count < 1, "pubkey array cannot be empty")
|
||||
pubkeys = calloc(count, sizeof(secp256k1_pubkey *));
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
count = (*penv)->GetArrayLength(penv, jpubkeys);
|
||||
pubkeys = calloc(count, sizeof(secp256k1_pubkey *));
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
@@ -598,6 +672,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
if (jpubkey == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "invalid private key size");
|
||||
|
||||
size = (*penv)->GetArrayLength(penv, jpubkey);
|
||||
@@ -639,7 +715,11 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
return NULL;
|
||||
if (jmsg == NULL)
|
||||
return NULL;
|
||||
CHECKRESULT(recid < 0 || recid > 3, "invalid recovery id");
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
// we do not check that recid is valid, which should trigger our illegal callback handler to throw a Secp256k1IllegalCallbackException
|
||||
// CHECKRESULT(recid < 0 || recid > 3, "recid must be 0, 1, 2 or 3")
|
||||
|
||||
sigSize = (*penv)->GetArrayLength(penv, jsig);
|
||||
int sigFormat = GetSignatureFormat(sigSize);
|
||||
@@ -687,7 +767,6 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
secp256k1_context *ctx = (secp256k1_context *)jctx;
|
||||
jbyte *sig;
|
||||
secp256k1_ecdsa_signature signature;
|
||||
;
|
||||
unsigned char der[73];
|
||||
size_t size;
|
||||
int result = 0;
|
||||
@@ -696,6 +775,9 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
return 0;
|
||||
if (jsig == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
CHECKRESULT((*penv)->GetArrayLength(penv, jsig) != 64, "invalid signature size");
|
||||
|
||||
size = (*penv)->GetArrayLength(penv, jsig);
|
||||
@@ -735,6 +817,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
|
||||
if (jseckey == NULL)
|
||||
return NULL;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
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)
|
||||
@@ -788,6 +872,8 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1sc
|
||||
if (jpubkey == NULL)
|
||||
return 0;
|
||||
|
||||
SETUP_ERROR_CALLBACKS
|
||||
|
||||
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");
|
||||
@@ -804,537 +890,3 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1sc
|
||||
(*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 session_id 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, &combined, jkeyaggcache == NULL ? NULL : &keyaggcache, (const secp256k1_pubkey *const *)pubkeys, count);
|
||||
free_pubkeys(pubkeys, count);
|
||||
CHECKRESULT(!result, "secp256k1_musig_pubkey_agg failed");
|
||||
|
||||
size = 32;
|
||||
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, jbyteArray jadaptor)
|
||||
{
|
||||
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 nonce 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);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -29,14 +29,6 @@ public class Secp256k1CFunctions {
|
||||
public static final int SECP256K1_EC_COMPRESSED = (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION);
|
||||
public static final int SECP256K1_EC_UNCOMPRESSED = (SECP256K1_FLAGS_TYPE_COMPRESSION);
|
||||
|
||||
public static final int SECP256K1_MUSIG_PUBLIC_NONCE_SIZE = 66;
|
||||
|
||||
public static final int SECP256K1_MUSIG_SECRET_NONCE_SIZE = 132;
|
||||
|
||||
public static final int SECP256K1_MUSIG_KEYAGG_CACHE_SIZE = 197;
|
||||
|
||||
public static final int SECP256K1_MUSIG_SESSION_SIZE = 133;
|
||||
|
||||
public static native long secp256k1_context_create(int flags);
|
||||
|
||||
public static native void secp256k1_context_destroy(long ctx);
|
||||
@@ -76,22 +68,4 @@ public class Secp256k1CFunctions {
|
||||
public static native byte[] secp256k1_schnorrsig_sign(long ctx, byte[] msg, byte[] seckey, byte[] aux_rand32);
|
||||
|
||||
public static native int secp256k1_schnorrsig_verify(long ctx, byte[] sig, byte[] msg, byte[] pubkey);
|
||||
|
||||
public static native byte[] secp256k1_musig_nonce_gen(long ctx, byte[] session_id32, byte[] seckey, byte[] pubkey, byte[] msg32, byte[] keyagg_cache, byte[] extra_input32);
|
||||
|
||||
public static native byte[] secp256k1_musig_nonce_agg(long ctx, byte[][] nonces);
|
||||
|
||||
public static native byte[] secp256k1_musig_pubkey_agg(long ctx, byte[][] pubkeys, byte[] keyagg_cache);
|
||||
|
||||
public static native byte[] secp256k1_musig_pubkey_ec_tweak_add(long ctx, byte[] keyagg_cache, byte[] tweak32);
|
||||
|
||||
public static native byte[] secp256k1_musig_pubkey_xonly_tweak_add(long ctx, byte[] keyagg_cache, byte[] tweak32);
|
||||
|
||||
public static native byte[] secp256k1_musig_nonce_process(long ctx, byte[] aggnonce, byte[] msg32, byte[] keyagg_cache, byte[] adaptor);
|
||||
|
||||
public static native byte[] secp256k1_musig_partial_sign(long ctx, byte[] secnonce, byte[] privkey, byte[] keyagg_cache, byte[] session);
|
||||
|
||||
public static native int secp256k1_musig_partial_sig_verify(long ctx, byte[] psig, byte[] pubnonce, byte[] pubkey, byte[] keyagg_cache, byte[] session);
|
||||
|
||||
public static native byte[] secp256k1_musig_partial_sig_agg(long ctx, byte[] session, byte[][] psigs);
|
||||
}
|
||||
|
||||
@@ -92,42 +92,6 @@ public object NativeSecp256k1 : Secp256k1 {
|
||||
return Secp256k1CFunctions.secp256k1_schnorrsig_sign(Secp256k1Context.getContext(), data, sec, auxrand32)
|
||||
}
|
||||
|
||||
override fun musigNonceGen(session_id32: ByteArray, seckey: ByteArray?, pubkey: ByteArray, msg32: ByteArray?, keyagg_cache: ByteArray?, extra_input32: ByteArray?): ByteArray {
|
||||
return Secp256k1CFunctions.secp256k1_musig_nonce_gen(Secp256k1Context.getContext(), session_id32, seckey, pubkey, msg32, keyagg_cache, extra_input32)
|
||||
}
|
||||
|
||||
override fun musigNonceAgg(pubnonces: Array<ByteArray>): ByteArray {
|
||||
return Secp256k1CFunctions.secp256k1_musig_nonce_agg(Secp256k1Context.getContext(), pubnonces)
|
||||
}
|
||||
|
||||
override fun musigPubkeyAdd(pubkeys: Array<ByteArray>, keyagg_cache: ByteArray?): ByteArray {
|
||||
return Secp256k1CFunctions.secp256k1_musig_pubkey_agg(Secp256k1Context.getContext(), pubkeys, keyagg_cache)
|
||||
}
|
||||
|
||||
override fun musigPubkeyTweakAdd(keyagg_cache: ByteArray, tweak32: ByteArray): ByteArray {
|
||||
return Secp256k1CFunctions.secp256k1_musig_pubkey_ec_tweak_add(Secp256k1Context.getContext(), keyagg_cache, tweak32)
|
||||
}
|
||||
|
||||
override fun musigPubkeyXonlyTweakAdd(keyagg_cache: ByteArray, tweak32: ByteArray): ByteArray {
|
||||
return Secp256k1CFunctions.secp256k1_musig_pubkey_xonly_tweak_add(Secp256k1Context.getContext(), keyagg_cache, tweak32)
|
||||
}
|
||||
|
||||
override fun musigNonceProcess(aggnonce: ByteArray, msg32: ByteArray, keyagg_cache: ByteArray, adaptor: ByteArray?): ByteArray {
|
||||
return Secp256k1CFunctions.secp256k1_musig_nonce_process(Secp256k1Context.getContext(), aggnonce, msg32, keyagg_cache, adaptor)
|
||||
}
|
||||
|
||||
override fun musigPartialSign(secnonce: ByteArray, privkey: ByteArray, keyagg_cache: ByteArray, session: ByteArray): ByteArray {
|
||||
return Secp256k1CFunctions.secp256k1_musig_partial_sign(Secp256k1Context.getContext(), secnonce, privkey, keyagg_cache, session)
|
||||
}
|
||||
|
||||
override fun musigPartialSigVerify(psig: ByteArray, pubnonce: ByteArray, pubkey: ByteArray, keyagg_cache: ByteArray, session: ByteArray): Int {
|
||||
return Secp256k1CFunctions.secp256k1_musig_partial_sig_verify(Secp256k1Context.getContext(), psig, pubnonce, pubkey, keyagg_cache, session)
|
||||
}
|
||||
|
||||
override fun musigPartialSigAgg(session: ByteArray, psigs: Array<ByteArray>): ByteArray {
|
||||
return Secp256k1CFunctions.secp256k1_musig_partial_sig_agg(Secp256k1Context.getContext(), session, psigs)
|
||||
}
|
||||
|
||||
override fun cleanup() {
|
||||
return Secp256k1CFunctions.secp256k1_context_destroy(Secp256k1Context.getContext())
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export STRIP=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/llvm-strip
|
||||
cd secp256k1
|
||||
|
||||
./autogen.sh
|
||||
./configure CFLAGS=-fpic --host=$TARGET --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
|
||||
./configure CFLAGS=-fpic --host=$TARGET --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
|
||||
make clean
|
||||
make
|
||||
|
||||
|
||||
@@ -6,13 +6,10 @@ cp xconfigure.sh secp256k1
|
||||
cd secp256k1
|
||||
|
||||
./autogen.sh
|
||||
sh xconfigure.sh --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
|
||||
sh xconfigure.sh --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
|
||||
|
||||
mkdir -p ../build/ios
|
||||
cp -v _build/universal/ios/* ../build/ios/
|
||||
|
||||
mkdir -p ../build/iosSimulatorArm64
|
||||
cp -v _build/universal/iosSimulatorArm64/* ../build/iosSimulatorArm64/
|
||||
cp -v _build/universal/* ../build/ios/
|
||||
|
||||
rm -rf _build
|
||||
make clean
|
||||
|
||||
@@ -23,7 +23,7 @@ else
|
||||
fi
|
||||
|
||||
./autogen.sh
|
||||
./configure $CONF_OPTS --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
|
||||
./configure $CONF_OPTS --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
|
||||
make clean
|
||||
make
|
||||
|
||||
|
||||
Submodule native/secp256k1 updated: eaf1e78d2d...199d27cea3
@@ -69,22 +69,9 @@ HOST_FLAGS="${ARCH_FLAGS} -mios-simulator-version-min=${MIN_IOS_VERSION} -isysro
|
||||
CHOST="x86_64-apple-darwin"
|
||||
Build "$@"
|
||||
|
||||
## Build for iphone M1/M2/Mx simulators
|
||||
SDK="iphonesimulator"
|
||||
PLATFORM="arm64-sim"
|
||||
PLATFORM_SIM_ARM=${PLATFORM}
|
||||
ARCH_FLAGS="-arch arm64"
|
||||
HOST_FLAGS="${ARCH_FLAGS} -mios-simulator-version-min=${MIN_IOS_VERSION} -isysroot $(xcrun --sdk ${SDK} --show-sdk-path)"
|
||||
CHOST="arm-apple-darwin"
|
||||
Build "$@"
|
||||
|
||||
# Create universal binary
|
||||
cd "${PLATFORMS}/${PLATFORM_ARM}/lib"
|
||||
LIB_NAME=`find . -iname *.a`
|
||||
cd -
|
||||
mkdir -p "${UNIVERSAL}/ios" &> /dev/null
|
||||
mkdir -p "${UNIVERSAL}/iosSimulatorArm64" &> /dev/null
|
||||
lipo -create -output "${UNIVERSAL}/ios/${LIB_NAME}" "${PLATFORMS}/${PLATFORM_ARM}/lib/${LIB_NAME}" "${PLATFORMS}/${PLATFORM_ISIM}/lib/${LIB_NAME}"
|
||||
|
||||
# create a specific library for arm64 simulator: it cannot be included in the lib above which already contains an arm64 lib
|
||||
lipo -create -output "${UNIVERSAL}/iosSimulatorArm64/${LIB_NAME}" "${PLATFORMS}/${PLATFORM_SIM_ARM}/lib/${LIB_NAME}"
|
||||
mkdir -p "${UNIVERSAL}" &> /dev/null
|
||||
lipo -create -output "${UNIVERSAL}/${LIB_NAME}" "${PLATFORMS}/${PLATFORM_ARM}/lib/${LIB_NAME}" "${PLATFORMS}/${PLATFORM_ISIM}/lib/${LIB_NAME}"
|
||||
|
||||
@@ -21,9 +21,9 @@ mvn deploy:deploy-file -DrepositoryId=ossrh -Durl=https://oss.sonatype.org/conte
|
||||
-Djavadoc=$ARTIFACT_ID_BASE-$VERSION-javadoc.jar
|
||||
popd
|
||||
pushd .
|
||||
for i in iosarm64 iossimulatorarm64 iosx64 jni-android jni-common jni-jvm-darwin jni-jvm-extract jni-jvm-linux jni-jvm-mingw jni-jvm jvm linuxx64; do
|
||||
for i in iosarm64 iosx64 jni-android jni-common jni-jvm-darwin jni-jvm-extract jni-jvm-linux jni-jvm-mingw jni-jvm jvm linux; do
|
||||
cd fr/acinq/secp256k1/secp256k1-kmp-$i/$VERSION
|
||||
if [ $i == iosarm64 ] || [ $i == iossimulatorarm64 ] || [ $i == iosx64 ]; then
|
||||
if [ $i == iosarm64 ] || [ $i == iosx64 ]; then
|
||||
mvn deploy:deploy-file -DrepositoryId=ossrh -Durl=https://oss.sonatype.org/content/repositories/snapshots/ \
|
||||
-DpomFile=$ARTIFACT_ID_BASE-$i-$VERSION.pom \
|
||||
-Dfile=$ARTIFACT_ID_BASE-$i-$VERSION.klib \
|
||||
@@ -32,7 +32,7 @@ for i in iosarm64 iossimulatorarm64 iosx64 jni-android jni-common jni-jvm-darwin
|
||||
-Dclassifiers=metadata,,cinterop-libsecp256k1 \
|
||||
-Dsources=$ARTIFACT_ID_BASE-$i-$VERSION-sources.jar \
|
||||
-Djavadoc=$ARTIFACT_ID_BASE-$i-$VERSION-javadoc.jar
|
||||
elif [ $i == linuxx64 ]; then
|
||||
elif [ $i == linux ]; then
|
||||
mvn deploy:deploy-file -DrepositoryId=ossrh -Durl=https://oss.sonatype.org/content/repositories/snapshots/ \
|
||||
-DpomFile=$ARTIFACT_ID_BASE-$i-$VERSION.pom \
|
||||
-Dfile=$ARTIFACT_ID_BASE-$i-$VERSION.klib \
|
||||
|
||||
@@ -153,25 +153,6 @@ public interface Secp256k1 {
|
||||
}
|
||||
}
|
||||
|
||||
public fun musigNonceGen(session_id32: ByteArray, seckey: ByteArray?, pubkey: ByteArray, msg32: ByteArray?, keyagg_cache: ByteArray?, extra_input32: ByteArray?): ByteArray
|
||||
|
||||
public fun musigNonceAgg(pubnonces: Array<ByteArray>): ByteArray
|
||||
|
||||
public fun musigPubkeyAdd(pubkeys: Array<ByteArray>, keyagg_cache: ByteArray?): ByteArray
|
||||
|
||||
public fun musigPubkeyTweakAdd(keyagg_cache: ByteArray, tweak32: ByteArray): ByteArray
|
||||
|
||||
public fun musigPubkeyXonlyTweakAdd(keyagg_cache: ByteArray, tweak32: ByteArray): ByteArray
|
||||
|
||||
public fun musigNonceProcess(aggnonce: ByteArray, msg32: ByteArray, keyagg_cache: ByteArray, adaptor: ByteArray?): ByteArray
|
||||
|
||||
public fun musigPartialSign(secnonce: ByteArray, privkey: ByteArray, keyagg_cache: ByteArray, session: ByteArray): ByteArray
|
||||
|
||||
public fun musigPartialSigVerify(psig: ByteArray, pubnonce: ByteArray, pubkey: ByteArray, keyagg_cache: ByteArray, session: ByteArray): Int
|
||||
|
||||
public fun musigPartialSigAgg(session: ByteArray, psigs: Array<ByteArray>): ByteArray
|
||||
|
||||
|
||||
/**
|
||||
* Delete the secp256k1 context from dynamic memory.
|
||||
*/
|
||||
@@ -180,19 +161,22 @@ public interface Secp256k1 {
|
||||
public companion object : Secp256k1 by getSecpk256k1() {
|
||||
@JvmStatic
|
||||
public fun get(): Secp256k1 = this
|
||||
|
||||
// @formatter:off
|
||||
public const val MUSIG2_SECRET_NONCE_SIZE: Int = 132
|
||||
public const val MUSIG2_PUBLIC_NONCE_SIZE: Int = 66
|
||||
public const val MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE: Int = 197
|
||||
public const val MUSIG2_PUBLIC_SESSION_SIZE: Int = 133
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
|
||||
internal expect fun getSecpk256k1(): Secp256k1
|
||||
|
||||
public class Secp256k1Exception : RuntimeException {
|
||||
public open class Secp256k1Exception : RuntimeException {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
}
|
||||
|
||||
public class Secp256k1ErrorCallbackException : Secp256k1Exception {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
}
|
||||
|
||||
public class Secp256k1IllegalCallbackException : Secp256k1Exception {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
package = secp256k1
|
||||
|
||||
headers = secp256k1.h secp256k1_ecdh.h secp256k1_recovery.h secp256k1_extrakeys.h secp256k1_schnorrsig.h secp256k1_musig.h
|
||||
headerFilter = secp256k1/** secp256k1_ecdh.h secp256k1_recovery.h secp256k1_extrakeys.h secp256k1_schnorrsig.h secp256k1_musig.h secp256k1.h
|
||||
headers = secp256k1.h secp256k1_ecdh.h secp256k1_recovery.h secp256k1_extrakeys.h secp256k1_schnorrsig.h
|
||||
headerFilter = secp256k1/** secp256k1_ecdh.h secp256k1_recovery.h secp256k1_extrakeys.h secp256k1_schnorrsig.h secp256k1.h
|
||||
|
||||
staticLibraries.linux = libsecp256k1.a
|
||||
libraryPaths.linux = c/secp256k1/build/linux/ native/build/linux/ native/build/darwin/
|
||||
libraryPaths.linux = c/secp256k1/build/linux/
|
||||
linkerOpts.linux = -L/usr/lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/local/lib
|
||||
|
||||
staticLibraries.ios = libsecp256k1.a
|
||||
libraryPaths.ios_x64 = c/secp256k1/build/ios/ /usr/local/lib native/build/ios/
|
||||
libraryPaths.ios_arm64 = c/secp256k1/build/ios/ /usr/local/lib native/build/ios/
|
||||
libraryPaths.ios_simulator_arm64 = c/secp256k1/build/ios/ /usr/local/lib native/build/iosSimulatorArm64/
|
||||
libraryPaths.ios = c/secp256k1/build/ios/ /usr/local/lib
|
||||
linkerOpts.ios = -framework Security -framework Foundation
|
||||
|
||||
@@ -1,19 +1,70 @@
|
||||
package fr.acinq.secp256k1
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import platform.posix.memcpy
|
||||
import platform.posix.size_tVar
|
||||
import secp256k1.*
|
||||
|
||||
@OptIn(ExperimentalUnsignedTypes::class, ExperimentalForeignApi::class)
|
||||
private typealias Secp256k1CallbackHandler = (String) -> Unit
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private class CallbackHandler(ctx: CPointer<secp256k1_context>) : AutoCloseable {
|
||||
var illegalCallBackMessage: String? = null
|
||||
val illegalHandler: Secp256k1CallbackHandler = { x: String -> illegalCallBackMessage = x }
|
||||
val illegalCallbackRef = StableRef.create(illegalHandler)
|
||||
var errorCallBackMessage: String? = null
|
||||
val errorHandler: Secp256k1CallbackHandler = { x: String -> errorCallBackMessage = x }
|
||||
val errorCallbackRef = StableRef.create(errorHandler)
|
||||
|
||||
init {
|
||||
secp256k1_context_set_error_callback(
|
||||
ctx, staticCFunction { buffer: CPointer<ByteVar>?, data: COpaquePointer? ->
|
||||
if (data != null) {
|
||||
val callback = data.asStableRef<Secp256k1CallbackHandler>().get()
|
||||
callback(buffer?.toKString() ?: "error callback triggered")
|
||||
}
|
||||
},
|
||||
errorCallbackRef.asCPointer()
|
||||
)
|
||||
secp256k1_context_set_illegal_callback(
|
||||
ctx, staticCFunction { buffer: CPointer<ByteVar>?, data: COpaquePointer? ->
|
||||
if (data != null) {
|
||||
val callback = data.asStableRef<Secp256k1CallbackHandler>().get()
|
||||
callback(buffer?.toKString() ?: "illegal callback triggered")
|
||||
}
|
||||
},
|
||||
illegalCallbackRef.asCPointer()
|
||||
)
|
||||
}
|
||||
|
||||
fun checkForErrors() {
|
||||
errorCallBackMessage?.let { throw Secp256k1ErrorCallbackException(it) }
|
||||
illegalCallBackMessage?.let { throw Secp256k1IllegalCallbackException(it) }
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
// StableRef instances have to be disposed of manually
|
||||
illegalCallbackRef.dispose()
|
||||
errorCallbackRef.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalUnsignedTypes::class, ExperimentalStdlibApi::class)
|
||||
public object Secp256k1Native : Secp256k1 {
|
||||
|
||||
private val ctx: CPointer<secp256k1_context> by lazy {
|
||||
|
||||
secp256k1_context_create((SECP256K1_FLAGS_TYPE_CONTEXT or SECP256K1_FLAGS_BIT_CONTEXT_SIGN or SECP256K1_FLAGS_BIT_CONTEXT_VERIFY).toUInt())
|
||||
?: error("Could not create secp256k1 context")
|
||||
}
|
||||
|
||||
private fun Int.requireSuccess(message: String): Int = if (this != 1) throw Secp256k1Exception(message) else this
|
||||
private fun Int.requireSuccess(message: String): Int {
|
||||
return if (this != 1) throw Secp256k1Exception(message) else this
|
||||
}
|
||||
|
||||
private fun Int.requireSuccess(callbackHandler: CallbackHandler, message: String): Int {
|
||||
callbackHandler.checkForErrors()
|
||||
return if (this != 1) throw Secp256k1Exception(message) else this
|
||||
}
|
||||
|
||||
private fun MemScope.allocSignature(input: ByteArray): secp256k1_ecdsa_signature {
|
||||
val sig = alloc<secp256k1_ecdsa_signature>()
|
||||
@@ -41,20 +92,6 @@ public object Secp256k1Native : Secp256k1 {
|
||||
return pub
|
||||
}
|
||||
|
||||
private fun MemScope.allocPublicNonce(pubnonce: ByteArray): secp256k1_musig_pubnonce {
|
||||
val nat = toNat(pubnonce)
|
||||
val nPubnonce = alloc<secp256k1_musig_pubnonce>()
|
||||
secp256k1_musig_pubnonce_parse(ctx, nPubnonce.ptr, nat).requireSuccess("secp256k1_musig_pubnonce_parse() failed")
|
||||
return nPubnonce
|
||||
}
|
||||
|
||||
private fun MemScope.allocPartialSig(psig: ByteArray): secp256k1_musig_partial_sig {
|
||||
val nat = toNat(psig)
|
||||
val nPsig = alloc<secp256k1_musig_partial_sig>()
|
||||
secp256k1_musig_partial_sig_parse(ctx, nPsig.ptr, nat).requireSuccess("secp256k1_musig_partial_sig_parse() failed")
|
||||
return nPsig
|
||||
}
|
||||
|
||||
private fun MemScope.serializePubkey(pubkey: secp256k1_pubkey): ByteArray {
|
||||
val serialized = allocArray<UByteVar>(65)
|
||||
val outputLen = alloc<size_tVar>()
|
||||
@@ -63,24 +100,6 @@ public object Secp256k1Native : Secp256k1 {
|
||||
return serialized.readBytes(outputLen.value.convert())
|
||||
}
|
||||
|
||||
private fun MemScope.serializeXonlyPubkey(pubkey: secp256k1_xonly_pubkey): ByteArray {
|
||||
val serialized = allocArray<UByteVar>(32)
|
||||
secp256k1_xonly_pubkey_serialize(ctx, serialized, pubkey.ptr).requireSuccess("secp256k1_xonly_pubkey_serialize() failed")
|
||||
return serialized.readBytes(32)
|
||||
}
|
||||
|
||||
private fun MemScope.serializePubnonce(pubnonce: secp256k1_musig_pubnonce): ByteArray {
|
||||
val serialized = allocArray<UByteVar>(Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
|
||||
secp256k1_musig_pubnonce_serialize(ctx, serialized, pubnonce.ptr).requireSuccess("secp256k1_musig_pubnonce_serialize() failed")
|
||||
return serialized.readBytes(Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
|
||||
}
|
||||
|
||||
private fun MemScope.serializeAggnonce(aggnonce: secp256k1_musig_aggnonce): ByteArray {
|
||||
val serialized = allocArray<UByteVar>(Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
|
||||
secp256k1_musig_aggnonce_serialize(ctx, serialized, aggnonce.ptr).requireSuccess("secp256k1_musig_aggnonce_serialize() failed")
|
||||
return serialized.readBytes(Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
|
||||
}
|
||||
|
||||
private fun DeferScope.toNat(bytes: ByteArray): CPointer<UByteVar> {
|
||||
val ubytes = bytes.asUByteArray()
|
||||
val pinned = ubytes.pin()
|
||||
@@ -91,173 +110,209 @@ public object Secp256k1Native : Secp256k1 {
|
||||
public override fun verify(signature: ByteArray, message: ByteArray, pubkey: ByteArray): Boolean {
|
||||
require(message.size == 32)
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nMessage = toNat(message)
|
||||
val nSig = allocSignature(signature)
|
||||
return secp256k1_ecdsa_verify(ctx, nSig.ptr, nMessage, nPubkey.ptr) == 1
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nMessage = toNat(message)
|
||||
val nSig = allocSignature(signature)
|
||||
val verify = secp256k1_ecdsa_verify(ctx, nSig.ptr, nMessage, nPubkey.ptr)
|
||||
callbackHandler.checkForErrors()
|
||||
return verify == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun sign(message: ByteArray, privkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
require(message.size == 32)
|
||||
memScoped {
|
||||
val nPrivkey = toNat(privkey)
|
||||
val nMessage = toNat(message)
|
||||
val nSig = alloc<secp256k1_ecdsa_signature>()
|
||||
secp256k1_ecdsa_sign(ctx, nSig.ptr, nMessage, nPrivkey, null, null).requireSuccess("secp256k1_ecdsa_sign() failed")
|
||||
return serializeSignature(nSig)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPrivkey = toNat(privkey)
|
||||
val nMessage = toNat(message)
|
||||
val nSig = alloc<secp256k1_ecdsa_signature>()
|
||||
secp256k1_ecdsa_sign(ctx, nSig.ptr, nMessage, nPrivkey, null, null).requireSuccess(callbackHandler, "secp256k1_ecdsa_sign() failed")
|
||||
return serializeSignature(nSig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun signatureNormalize(sig: ByteArray): Pair<ByteArray, Boolean> {
|
||||
require(sig.size >= 64){ "invalid signature ${Hex.encode(sig)}" }
|
||||
memScoped {
|
||||
val nSig = allocSignature(sig)
|
||||
val isHighS = secp256k1_ecdsa_signature_normalize(ctx, nSig.ptr, nSig.ptr)
|
||||
return Pair(serializeSignature(nSig), isHighS == 1)
|
||||
require(sig.size >= 64) { "invalid signature ${Hex.encode(sig)}" }
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nSig = allocSignature(sig)
|
||||
val isHighS = secp256k1_ecdsa_signature_normalize(ctx, nSig.ptr, nSig.ptr)
|
||||
callbackHandler.checkForErrors()
|
||||
return Pair(serializeSignature(nSig), isHighS == 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun secKeyVerify(privkey: ByteArray): Boolean {
|
||||
if (privkey.size != 32) return false
|
||||
memScoped {
|
||||
val nPrivkey = toNat(privkey)
|
||||
return secp256k1_ec_seckey_verify(ctx, nPrivkey) == 1
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPrivkey = toNat(privkey)
|
||||
val result = secp256k1_ec_seckey_verify(ctx, nPrivkey) == 1
|
||||
callbackHandler.checkForErrors()
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubkeyCreate(privkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
memScoped {
|
||||
val nPrivkey = toNat(privkey)
|
||||
val nPubkey = alloc<secp256k1_pubkey>()
|
||||
secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nPrivkey).requireSuccess("secp256k1_ec_pubkey_create() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPrivkey = toNat(privkey)
|
||||
val nPubkey = alloc<secp256k1_pubkey>()
|
||||
secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nPrivkey).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_create() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubkeyParse(pubkey: ByteArray): ByteArray {
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
return serializePubkey(nPubkey)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val result = serializePubkey(nPubkey)
|
||||
callbackHandler.checkForErrors()
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun privKeyNegate(privkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
memScoped {
|
||||
val negated = privkey.copyOf()
|
||||
val negPriv = toNat(negated)
|
||||
secp256k1_ec_seckey_negate(ctx, negPriv).requireSuccess("secp256k1_ec_seckey_negate() failed")
|
||||
return negated
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val negated = privkey.copyOf()
|
||||
val negPriv = toNat(negated)
|
||||
secp256k1_ec_seckey_negate(ctx, negPriv).requireSuccess(callbackHandler, "secp256k1_ec_seckey_negate() failed")
|
||||
return negated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
require(tweak.size == 32)
|
||||
memScoped {
|
||||
val added = privkey.copyOf()
|
||||
val natAdd = toNat(added)
|
||||
val natTweak = toNat(tweak)
|
||||
secp256k1_ec_seckey_tweak_add(ctx, natAdd, natTweak).requireSuccess("secp256k1_ec_seckey_tweak_add() failed")
|
||||
return added
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val added = privkey.copyOf()
|
||||
val natAdd = toNat(added)
|
||||
val natTweak = toNat(tweak)
|
||||
secp256k1_ec_seckey_tweak_add(ctx, natAdd, natTweak).requireSuccess(callbackHandler, "secp256k1_ec_seckey_tweak_add() failed")
|
||||
return added
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
require(tweak.size == 32)
|
||||
memScoped {
|
||||
val multiplied = privkey.copyOf()
|
||||
val natMul = toNat(multiplied)
|
||||
val natTweak = toNat(tweak)
|
||||
secp256k1_ec_privkey_tweak_mul(ctx, natMul, natTweak).requireSuccess("secp256k1_ec_privkey_tweak_mul() failed")
|
||||
return multiplied
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val multiplied = privkey.copyOf()
|
||||
val natMul = toNat(multiplied)
|
||||
val natTweak = toNat(tweak)
|
||||
secp256k1_ec_privkey_tweak_mul(ctx, natMul, natTweak).requireSuccess(callbackHandler, "secp256k1_ec_privkey_tweak_mul() failed")
|
||||
return multiplied
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubKeyNegate(pubkey: ByteArray): ByteArray {
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
secp256k1_ec_pubkey_negate(ctx, nPubkey.ptr).requireSuccess("secp256k1_ec_pubkey_negate() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
secp256k1_ec_pubkey_negate(ctx, nPubkey.ptr).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_negate() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
require(tweak.size == 32)
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nTweak = toNat(tweak)
|
||||
secp256k1_ec_pubkey_tweak_add(ctx, nPubkey.ptr, nTweak).requireSuccess("secp256k1_ec_pubkey_tweak_add() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nTweak = toNat(tweak)
|
||||
secp256k1_ec_pubkey_tweak_add(ctx, nPubkey.ptr, nTweak).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_tweak_add() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
require(tweak.size == 32)
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nTweak = toNat(tweak)
|
||||
secp256k1_ec_pubkey_tweak_mul(ctx, nPubkey.ptr, nTweak).requireSuccess("secp256k1_ec_pubkey_tweak_mul() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nTweak = toNat(tweak)
|
||||
secp256k1_ec_pubkey_tweak_mul(ctx, nPubkey.ptr, nTweak).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_tweak_mul() failed")
|
||||
return serializePubkey(nPubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun pubKeyCombine(pubkeys: Array<ByteArray>): ByteArray {
|
||||
require(pubkeys.isNotEmpty())
|
||||
pubkeys.forEach { require(it.size == 33 || it.size == 65) }
|
||||
memScoped {
|
||||
val nPubkeys = pubkeys.map { allocPublicKey(it).ptr }
|
||||
val combined = alloc<secp256k1_pubkey>()
|
||||
secp256k1_ec_pubkey_combine(ctx, combined.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess("secp256k1_ec_pubkey_combine() failed")
|
||||
return serializePubkey(combined)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkeys = pubkeys.map { allocPublicKey(it).ptr }
|
||||
val combined = alloc<secp256k1_pubkey>()
|
||||
secp256k1_ec_pubkey_combine(ctx, combined.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_combine() failed")
|
||||
return serializePubkey(combined)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun ecdh(privkey: ByteArray, pubkey: ByteArray): ByteArray {
|
||||
require(privkey.size == 32)
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nPrivkey = toNat(privkey)
|
||||
val output = allocArray<UByteVar>(32)
|
||||
secp256k1_ecdh(ctx, output, nPubkey.ptr, nPrivkey, null, null).requireSuccess("secp256k1_ecdh() failed")
|
||||
return output.readBytes(32)
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nPrivkey = toNat(privkey)
|
||||
val output = allocArray<UByteVar>(32)
|
||||
secp256k1_ecdh(ctx, output, nPubkey.ptr, nPrivkey, null, null).requireSuccess(callbackHandler, "secp256k1_ecdh() failed")
|
||||
return output.readBytes(32)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray {
|
||||
require(sig.size == 64)
|
||||
require(message.size == 32)
|
||||
require(recid in 0..3)
|
||||
memScoped {
|
||||
val nSig = toNat(sig)
|
||||
val rSig = alloc<secp256k1_ecdsa_recoverable_signature>()
|
||||
secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, rSig.ptr, nSig, recid).requireSuccess("secp256k1_ecdsa_recoverable_signature_parse_compact() failed")
|
||||
val nMessage = toNat(message)
|
||||
val pubkey = alloc<secp256k1_pubkey>()
|
||||
secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess("secp256k1_ecdsa_recover() failed")
|
||||
return serializePubkey(pubkey)
|
||||
// we do not check that recid is valid, which should trigger our illegal callback handler to throw a Secp256k1IllegalCallbackException
|
||||
// require(recid in 0..3)
|
||||
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nSig = toNat(sig)
|
||||
val rSig = alloc<secp256k1_ecdsa_recoverable_signature>()
|
||||
secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, rSig.ptr, nSig, recid).requireSuccess(callbackHandler, "secp256k1_ecdsa_recoverable_signature_parse_compact() failed")
|
||||
val nMessage = toNat(message)
|
||||
val pubkey = alloc<secp256k1_pubkey>()
|
||||
secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess(callbackHandler, "secp256k1_ecdsa_recover() failed")
|
||||
return serializePubkey(pubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override fun compact2der(sig: ByteArray): ByteArray {
|
||||
require(sig.size == 64)
|
||||
memScoped {
|
||||
val nSig = allocSignature(sig)
|
||||
val natOutput = allocArray<UByteVar>(73)
|
||||
val len = alloc<size_tVar>()
|
||||
len.value = 73.convert()
|
||||
secp256k1_ecdsa_signature_serialize_der(ctx, natOutput, len.ptr, nSig.ptr).requireSuccess("secp256k1_ecdsa_signature_serialize_der() failed")
|
||||
return natOutput.readBytes(len.value.toInt())
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nSig = allocSignature(sig)
|
||||
val natOutput = allocArray<UByteVar>(73)
|
||||
val len = alloc<size_tVar>()
|
||||
len.value = 73.convert()
|
||||
secp256k1_ecdsa_signature_serialize_der(ctx, natOutput, len.ptr, nSig.ptr).requireSuccess(callbackHandler, "secp256k1_ecdsa_signature_serialize_der() failed")
|
||||
return natOutput.readBytes(len.value.toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,13 +320,15 @@ public object Secp256k1Native : Secp256k1 {
|
||||
require(signature.size == 64)
|
||||
require(data.size == 32)
|
||||
require(pub.size == 32)
|
||||
memScoped {
|
||||
val nPub = toNat(pub)
|
||||
val pubkey = alloc<secp256k1_xonly_pubkey>()
|
||||
secp256k1_xonly_pubkey_parse(ctx, pubkey.ptr, nPub).requireSuccess("secp256k1_xonly_pubkey_parse() failed")
|
||||
val nData = toNat(data)
|
||||
val nSig = toNat(signature)
|
||||
return secp256k1_schnorrsig_verify(ctx, nSig, nData, 32u, pubkey.ptr) == 1
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nPub = toNat(pub)
|
||||
val pubkey = alloc<secp256k1_xonly_pubkey>()
|
||||
secp256k1_xonly_pubkey_parse(ctx, pubkey.ptr, nPub).requireSuccess(callbackHandler, "secp256k1_xonly_pubkey_parse() failed")
|
||||
val nData = toNat(data)
|
||||
val nSig = toNat(signature)
|
||||
return secp256k1_schnorrsig_verify(ctx, nSig, nData, 32u, pubkey.ptr) == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,174 +336,25 @@ public object Secp256k1Native : Secp256k1 {
|
||||
require(sec.size == 32)
|
||||
require(data.size == 32)
|
||||
auxrand32?.let { require(it.size == 32) }
|
||||
memScoped {
|
||||
val nSec = toNat(sec)
|
||||
val nData = toNat(data)
|
||||
val nAuxrand32 = auxrand32?.let { toNat(it) }
|
||||
val nSig = allocArray<UByteVar>(64)
|
||||
val keypair = alloc<secp256k1_keypair>()
|
||||
secp256k1_keypair_create(ctx, keypair.ptr, nSec).requireSuccess("secp256k1_keypair_create() failed")
|
||||
secp256k1_schnorrsig_sign32(ctx, nSig, nData, keypair.ptr, nAuxrand32).requireSuccess("secp256k1_ecdsa_sign() failed")
|
||||
return nSig.readBytes(64)
|
||||
}
|
||||
}
|
||||
|
||||
override fun musigNonceGen(session_id32: ByteArray, seckey: ByteArray?, pubkey: ByteArray, msg32: ByteArray?, keyagg_cache: ByteArray?, extra_input32: ByteArray?): ByteArray {
|
||||
require(session_id32.size == 32)
|
||||
seckey?.let { require(it.size == 32) }
|
||||
msg32?.let { require(it.size == 32) }
|
||||
keyagg_cache?.let { require(it.size == Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE) }
|
||||
extra_input32?.let { require(it.size == 32) }
|
||||
|
||||
val nonce = memScoped {
|
||||
val secret_nonce = alloc<secp256k1_musig_secnonce>()
|
||||
val public_nonce = alloc<secp256k1_musig_pubnonce>()
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nKeyAggCache = keyagg_cache?.let {
|
||||
val n = alloc<secp256k1_musig_keyagg_cache>()
|
||||
memcpy(n.ptr, toNat(it), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
|
||||
n
|
||||
CallbackHandler(ctx).use { callbackHandler ->
|
||||
memScoped {
|
||||
val nSec = toNat(sec)
|
||||
val nData = toNat(data)
|
||||
val nAuxrand32 = auxrand32?.let { toNat(it) }
|
||||
val nSig = allocArray<UByteVar>(64)
|
||||
val keypair = alloc<secp256k1_keypair>()
|
||||
secp256k1_keypair_create(ctx, keypair.ptr, nSec).requireSuccess(callbackHandler, "secp256k1_keypair_create() failed")
|
||||
secp256k1_schnorrsig_sign32(ctx, nSig, nData, keypair.ptr, nAuxrand32).requireSuccess(callbackHandler, "secp256k1_ecdsa_sign() failed")
|
||||
return nSig.readBytes(64)
|
||||
}
|
||||
secp256k1_musig_nonce_gen(ctx, secret_nonce.ptr, public_nonce.ptr, toNat(session_id32), seckey?.let { toNat(it) }, nPubkey.ptr, msg32?.let { toNat(it) },nKeyAggCache?.ptr, extra_input32?.let { toNat(it) }).requireSuccess("secp256k1_musig_nonce_gen() failed")
|
||||
val nPubnonce = allocArray<UByteVar>(Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
|
||||
secp256k1_musig_pubnonce_serialize(ctx, nPubnonce, public_nonce.ptr).requireSuccess("secp256k1_musig_pubnonce_serialize failed")
|
||||
secret_nonce.ptr.readBytes(Secp256k1.MUSIG2_SECRET_NONCE_SIZE) + nPubnonce.readBytes(Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
|
||||
}
|
||||
return nonce
|
||||
}
|
||||
|
||||
override fun musigNonceAgg(pubnonces: Array<ByteArray>): ByteArray {
|
||||
require(pubnonces.isNotEmpty())
|
||||
pubnonces.forEach { require(it.size == Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE) }
|
||||
memScoped {
|
||||
val nPubnonces = pubnonces.map { allocPublicNonce(it).ptr }
|
||||
val combined = alloc<secp256k1_musig_aggnonce>()
|
||||
secp256k1_musig_nonce_agg(ctx, combined.ptr, nPubnonces.toCValues(), pubnonces.size.convert()).requireSuccess("secp256k1_musig_nonce_agg() failed")
|
||||
return serializeAggnonce(combined)
|
||||
}
|
||||
}
|
||||
|
||||
override fun musigPubkeyAdd(pubkeys: Array<ByteArray>, keyagg_cache: ByteArray?): ByteArray {
|
||||
require(pubkeys.isNotEmpty())
|
||||
pubkeys.forEach { require(it.size == 33 || it.size == 65) }
|
||||
keyagg_cache?.let { require(it.size == Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE) }
|
||||
memScoped {
|
||||
val nPubkeys = pubkeys.map { allocPublicKey(it).ptr }
|
||||
val combined = alloc<secp256k1_xonly_pubkey>()
|
||||
val nKeyAggCache = keyagg_cache?.let {
|
||||
val n = alloc<secp256k1_musig_keyagg_cache>()
|
||||
memcpy(n.ptr, toNat(it), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
|
||||
n
|
||||
}
|
||||
secp256k1_musig_pubkey_agg(ctx, combined.ptr, nKeyAggCache?.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess("secp256k1_musig_nonce_agg() failed")
|
||||
val agg = serializeXonlyPubkey(combined)
|
||||
keyagg_cache?.let { blob -> nKeyAggCache?.let { memcpy(toNat(blob), it.ptr, Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong()) } }
|
||||
return agg
|
||||
}
|
||||
}
|
||||
|
||||
override fun musigPubkeyTweakAdd(keyagg_cache: ByteArray, tweak32: ByteArray): ByteArray {
|
||||
require(keyagg_cache.size == Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE)
|
||||
require(tweak32.size == 32)
|
||||
memScoped {
|
||||
val nKeyAggCache = alloc<secp256k1_musig_keyagg_cache>()
|
||||
memcpy(nKeyAggCache.ptr, toNat(keyagg_cache), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
|
||||
val nPubkey = alloc<secp256k1_pubkey>()
|
||||
secp256k1_musig_pubkey_ec_tweak_add(ctx, nPubkey.ptr, nKeyAggCache.ptr, toNat(tweak32)).requireSuccess("secp256k1_musig_pubkey_ec_tweak_add() failed")
|
||||
memcpy(toNat(keyagg_cache), nKeyAggCache.ptr, Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
|
||||
return serializePubkey(nPubkey)
|
||||
}
|
||||
}
|
||||
|
||||
override fun musigPubkeyXonlyTweakAdd(keyagg_cache: ByteArray, tweak32: ByteArray): ByteArray {
|
||||
require(keyagg_cache.size == Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE)
|
||||
require(tweak32.size == 32)
|
||||
memScoped {
|
||||
val nKeyAggCache = alloc<secp256k1_musig_keyagg_cache>()
|
||||
memcpy(nKeyAggCache.ptr, toNat(keyagg_cache), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
|
||||
val nPubkey = alloc<secp256k1_pubkey>()
|
||||
secp256k1_musig_pubkey_xonly_tweak_add(ctx, nPubkey.ptr, nKeyAggCache.ptr, toNat(tweak32)).requireSuccess("secp256k1_musig_pubkey_xonly_tweak_add() failed")
|
||||
memcpy(toNat(keyagg_cache), nKeyAggCache.ptr, Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
|
||||
return serializePubkey(nPubkey)
|
||||
}
|
||||
}
|
||||
|
||||
override fun musigNonceProcess(aggnonce: ByteArray, msg32: ByteArray, keyagg_cache: ByteArray, adaptor: ByteArray?): ByteArray {
|
||||
require(aggnonce.size == Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
|
||||
require(keyagg_cache.size == Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE)
|
||||
require(msg32.size == 32)
|
||||
memScoped {
|
||||
val nKeyAggCache = alloc<secp256k1_musig_keyagg_cache>()
|
||||
memcpy(nKeyAggCache.ptr, toNat(keyagg_cache), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
|
||||
val nSession = alloc<secp256k1_musig_session>()
|
||||
val nAggnonce = alloc<secp256k1_musig_aggnonce>()
|
||||
secp256k1_musig_aggnonce_parse(ctx, nAggnonce.ptr, toNat(aggnonce)).requireSuccess("secp256k1_musig_aggnonce_parse() failed")
|
||||
secp256k1_musig_nonce_process(ctx, nSession.ptr, nAggnonce.ptr, toNat(msg32), nKeyAggCache.ptr).requireSuccess("secp256k1_musig_nonce_process() failed")
|
||||
val session = ByteArray(Secp256k1.MUSIG2_PUBLIC_SESSION_SIZE)
|
||||
memcpy(toNat(session), nSession.ptr, Secp256k1.MUSIG2_PUBLIC_SESSION_SIZE.toULong())
|
||||
return session
|
||||
}
|
||||
}
|
||||
|
||||
override fun musigPartialSign(secnonce: ByteArray, privkey: ByteArray, keyagg_cache: ByteArray, session: ByteArray): ByteArray {
|
||||
require(secnonce.size == Secp256k1.MUSIG2_SECRET_NONCE_SIZE)
|
||||
require(privkey.size == 32)
|
||||
require(keyagg_cache.size == Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE)
|
||||
require(session.size == Secp256k1.MUSIG2_PUBLIC_SESSION_SIZE)
|
||||
|
||||
memScoped {
|
||||
val nSecnonce = alloc<secp256k1_musig_secnonce>()
|
||||
memcpy(nSecnonce.ptr, toNat(secnonce), Secp256k1.MUSIG2_SECRET_NONCE_SIZE.toULong())
|
||||
val nKeypair = alloc<secp256k1_keypair>()
|
||||
secp256k1_keypair_create(ctx, nKeypair.ptr, toNat(privkey))
|
||||
val nPsig = alloc<secp256k1_musig_partial_sig>()
|
||||
val nKeyAggCache = alloc<secp256k1_musig_keyagg_cache>()
|
||||
memcpy(nKeyAggCache.ptr, toNat(keyagg_cache), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
|
||||
val nSession = alloc<secp256k1_musig_session>()
|
||||
memcpy(nSession.ptr, toNat(session), Secp256k1.MUSIG2_PUBLIC_SESSION_SIZE.toULong())
|
||||
secp256k1_musig_partial_sign(ctx, nPsig.ptr, nSecnonce.ptr, nKeypair.ptr, nKeyAggCache.ptr, nSession.ptr).requireSuccess("secp256k1_musig_partial_sign failed")
|
||||
val psig = ByteArray(32)
|
||||
secp256k1_musig_partial_sig_serialize(ctx, toNat(psig), nPsig.ptr).requireSuccess("secp256k1_musig_partial_sig_serialize() failed")
|
||||
return psig
|
||||
}
|
||||
}
|
||||
|
||||
override fun musigPartialSigVerify(psig: ByteArray, pubnonce: ByteArray, pubkey: ByteArray, keyagg_cache: ByteArray, session: ByteArray): Int {
|
||||
require(psig.size == 32)
|
||||
require(pubnonce.size == Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
|
||||
require(pubkey.size == 33 || pubkey.size == 65)
|
||||
require(keyagg_cache.size == Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE)
|
||||
require(session.size == Secp256k1.MUSIG2_PUBLIC_SESSION_SIZE)
|
||||
|
||||
memScoped {
|
||||
val nPSig = allocPartialSig(psig)
|
||||
val nPubnonce = allocPublicNonce(pubnonce)
|
||||
val nPubkey = allocPublicKey(pubkey)
|
||||
val nKeyAggCache = alloc<secp256k1_musig_keyagg_cache>()
|
||||
memcpy(nKeyAggCache.ptr, toNat(keyagg_cache), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
|
||||
val nSession = alloc<secp256k1_musig_session>()
|
||||
memcpy(nSession.ptr, toNat(session), Secp256k1.MUSIG2_PUBLIC_SESSION_SIZE.toULong())
|
||||
return secp256k1_musig_partial_sig_verify(ctx, nPSig.ptr, nPubnonce.ptr, nPubkey.ptr, nKeyAggCache.ptr, nSession.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
override fun musigPartialSigAgg(session: ByteArray, psigs: Array<ByteArray>): ByteArray {
|
||||
require(session.size == Secp256k1.MUSIG2_PUBLIC_SESSION_SIZE)
|
||||
require(psigs.isNotEmpty())
|
||||
psigs.forEach { require(it.size == 32) }
|
||||
memScoped {
|
||||
val nSession = alloc<secp256k1_musig_session>()
|
||||
memcpy(nSession.ptr, toNat(session), Secp256k1.MUSIG2_PUBLIC_SESSION_SIZE.toULong())
|
||||
val nPsigs = psigs.map { allocPartialSig(it).ptr }
|
||||
val sig64 = ByteArray(64)
|
||||
secp256k1_musig_partial_sig_agg(ctx, toNat(sig64), nSession.ptr, nPsigs.toCValues(), psigs.size.convert()).requireSuccess("secp256k1_musig_partial_sig_agg() failed")
|
||||
return sig64
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override fun cleanup() {
|
||||
secp256k1_context_destroy(ctx)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
internal actual fun getSecpk256k1(): Secp256k1 = Secp256k1Native
|
||||
|
||||
@@ -36,14 +36,14 @@ kotlin {
|
||||
}
|
||||
|
||||
if (includeAndroid) {
|
||||
androidTarget {
|
||||
android {
|
||||
compilations.all {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
||||
sourceSets["androidMain"].dependencies {
|
||||
implementation(project(":jni:android"))
|
||||
}
|
||||
sourceSets["androidUnitTest"].dependencies {
|
||||
sourceSets["androidTest"].dependencies {
|
||||
implementation(kotlin("test-junit"))
|
||||
implementation("androidx.test.ext:junit:1.1.2")
|
||||
implementation("androidx.test.espresso:espresso-core:3.3.0")
|
||||
@@ -51,18 +51,17 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
linuxX64()
|
||||
iosX64()
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
linuxX64("linux")
|
||||
|
||||
ios()
|
||||
}
|
||||
|
||||
val includeAndroid = System.getProperty("includeAndroid")?.toBoolean() ?: true
|
||||
if (includeAndroid) {
|
||||
extensions.configure<com.android.build.gradle.LibraryExtension>("android") {
|
||||
defaultConfig {
|
||||
compileSdk =30
|
||||
minSdk = 21
|
||||
compileSdkVersion(30)
|
||||
minSdkVersion(21)
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
|
||||
@@ -275,6 +275,11 @@ class Secp256k1Test {
|
||||
val pub0 = Secp256k1.ecdsaRecover(sig, message, 0)
|
||||
val pub1 = Secp256k1.ecdsaRecover(sig, message, 1)
|
||||
assertTrue(pub.contentEquals(pub0) || pub.contentEquals(pub1))
|
||||
|
||||
// this is a special case, ecdsaRecover explicitly does not check that recid is valid, which triggers our illegal callback handler
|
||||
assertFailsWith(Secp256k1IllegalCallbackException::class) {
|
||||
Secp256k1.ecdsaRecover(sig, message, 4)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -352,151 +357,6 @@ class Secp256k1Test {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMusig2GenerateNonce() {
|
||||
val pubkey = Hex.decode("02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9")
|
||||
val sessionId = Hex.decode("0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F")
|
||||
val nonce = Secp256k1.musigNonceGen(sessionId, null, pubkey, null, null, null)
|
||||
val pubnonce = Hex.encode(nonce.copyOfRange(132, 132 + 66)).uppercase()
|
||||
assertEquals("02C96E7CB1E8AA5DAC64D872947914198F607D90ECDE5200DE52978AD5DED63C000299EC5117C2D29EDEE8A2092587C3909BE694D5CFF0667D6C02EA4059F7CD9786", pubnonce)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMusig2AggregateNonce() {
|
||||
val nonces = listOf(
|
||||
"020151C80F435648DF67A22B749CD798CE54E0321D034B92B709B567D60A42E66603BA47FBC1834437B3212E89A84D8425E7BF12E0245D98262268EBDCB385D50641",
|
||||
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B833",
|
||||
"020151C80F435648DF67A22B749CD798CE54E0321D034B92B709B567D60A42E6660279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
|
||||
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60379BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
|
||||
"04FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B833",
|
||||
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B831",
|
||||
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A602FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30"
|
||||
).map { Hex.decode(it) }
|
||||
val agg1 = Secp256k1.musigNonceAgg(arrayOf(nonces[0], nonces[1]))
|
||||
assertEquals("035FE1873B4F2967F52FEA4A06AD5A8ECCBE9D0FD73068012C894E2E87CCB5804B024725377345BDE0E9C33AF3C43C0A29A9249F2F2956FA8CFEB55C8573D0262DC8", Hex.encode(agg1).uppercase())
|
||||
|
||||
val agg2 = Secp256k1.musigNonceAgg(arrayOf(nonces[2], nonces[3]))
|
||||
assertEquals("035FE1873B4F2967F52FEA4A06AD5A8ECCBE9D0FD73068012C894E2E87CCB5804B000000000000000000000000000000000000000000000000000000000000000000", Hex.encode(agg2).uppercase())
|
||||
|
||||
assertFails {
|
||||
Secp256k1.musigNonceAgg(arrayOf(nonces[0], nonces[4]))
|
||||
}
|
||||
assertFails {
|
||||
Secp256k1.musigNonceAgg(arrayOf(nonces[5], nonces[1]))
|
||||
}
|
||||
assertFails {
|
||||
Secp256k1.musigNonceAgg(arrayOf(nonces[6], nonces[1]))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMusig2AggregatePubkey() {
|
||||
val pubkeys = listOf(
|
||||
"02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
|
||||
"03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||
"023590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66",
|
||||
"020000000000000000000000000000000000000000000000000000000000000005",
|
||||
"02FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30",
|
||||
"04F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
|
||||
"03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9"
|
||||
|
||||
).map { Hex.decode(it) }
|
||||
|
||||
val agg1 = Secp256k1.musigPubkeyAdd(arrayOf(pubkeys[0], pubkeys[1], pubkeys[2]), null)
|
||||
assertEquals("90539EEDE565F5D054F32CC0C220126889ED1E5D193BAF15AEF344FE59D4610C", Hex.encode(agg1).uppercase())
|
||||
val cache = ByteArray(197)
|
||||
val agg2 = Secp256k1.musigPubkeyAdd(arrayOf(pubkeys[0], pubkeys[1], pubkeys[2]), cache)
|
||||
assertEquals("90539EEDE565F5D054F32CC0C220126889ED1E5D193BAF15AEF344FE59D4610C", Hex.encode(agg2).uppercase())
|
||||
|
||||
val agg3 = Secp256k1.musigPubkeyAdd(arrayOf(pubkeys[2], pubkeys[1], pubkeys[0]), null)
|
||||
assertEquals("6204DE8B083426DC6EAF9502D27024D53FC826BF7D2012148A0575435DF54B2B", Hex.encode(agg3).uppercase())
|
||||
|
||||
val agg4 = Secp256k1.musigPubkeyAdd(arrayOf(pubkeys[0], pubkeys[0], pubkeys[0]), null)
|
||||
assertEquals("B436E3BAD62B8CD409969A224731C193D051162D8C5AE8B109306127DA3AA935", Hex.encode(agg4).uppercase())
|
||||
|
||||
val agg5 = Secp256k1.musigPubkeyAdd(arrayOf(pubkeys[0], pubkeys[0], pubkeys[1], pubkeys[1]), null)
|
||||
assertEquals("69BC22BFA5D106306E48A20679DE1D7389386124D07571D0D872686028C26A3E", Hex.encode(agg5).uppercase())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMusig2TweakPubkeys() {
|
||||
val pubkeys = listOf(
|
||||
"031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||
"024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766",
|
||||
"02531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337"
|
||||
).map { Hex.decode(it) }.toTypedArray()
|
||||
val cache = ByteArray(197)
|
||||
val agg1 = Secp256k1.musigPubkeyAdd(pubkeys, cache)
|
||||
assertEquals("b6d830642403fc82511aca5ff98a5e76fcef0f89bffc1aadbe78ee74cd5a5716", Hex.encode(agg1))
|
||||
val agg2 = Secp256k1.musigPubkeyTweakAdd(cache, Hex.decode("7468697320636f756c64206265206120424950333220747765616b2e2e2e2e00"))
|
||||
assertEquals("04791e4f22a21f19bd9798eceab92ad2ccc18f2d6660e91ae4c0709aaebf1aa9023701f468b0eddf8973495a5327f2169d9c6a50eb6a0f87c0fbee90a4067eb230", Hex.encode(agg2))
|
||||
val agg3 = Secp256k1.musigPubkeyXonlyTweakAdd(cache, Hex.decode("7468697320636f756c64206265206120746170726f6f7420747765616b2e2e00"))
|
||||
assertEquals("04537a081a8d32ff700ca86aaa77a423e9b8d1480938076b645c68ee39d263c93948026928799b2d942cb5851db397015b26b1759de1b9ab2c691ced64a2eef836", Hex.encode(agg3))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMusig2SigningSession() {
|
||||
val privkeys = listOf(
|
||||
"0101010101010101010101010101010101010101010101010101010101010101",
|
||||
"0202020202020202020202020202020202020202020202020202020202020202",
|
||||
).map { Hex.decode(it) }.toTypedArray()
|
||||
val pubkeys = privkeys.map { Secp256k1.pubkeyCreate(it) }
|
||||
|
||||
val sessionId = Hex.decode("0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F")
|
||||
val nonces = pubkeys.map { Secp256k1.musigNonceGen(sessionId, null, it, null, null, null) }
|
||||
val secnonces = nonces.map { it.copyOfRange(0, 132) }
|
||||
val pubnonces = nonces.map { it.copyOfRange(132, 132 + 66) }
|
||||
val aggnonce = Secp256k1.musigNonceAgg(pubnonces.toTypedArray())
|
||||
|
||||
val caches = (0 until 2).map { ByteArray(197) }
|
||||
val aggpubkey = Secp256k1.musigPubkeyAdd(pubkeys.toTypedArray(), caches[0])
|
||||
Secp256k1.musigPubkeyAdd(pubkeys.toTypedArray(), caches[1])
|
||||
|
||||
val msg32 = Hex.decode("0303030303030303030303030303030303030303030303030303030303030303")
|
||||
val sessions = (0 until 2).map { Secp256k1.musigNonceProcess(aggnonce, msg32, caches[it], null) }
|
||||
val psigs = (0 until 2).map {
|
||||
val psig = Secp256k1.musigPartialSign(secnonces[it], privkeys[it], caches[it], sessions[it])
|
||||
val check = Secp256k1.musigPartialSigVerify(psig, pubnonces[it], pubkeys[it], caches[it], sessions[it])
|
||||
assertEquals(1, check)
|
||||
psig
|
||||
}
|
||||
val sig = Secp256k1.musigPartialSigAgg(sessions[0], psigs.toTypedArray())
|
||||
val check = Secp256k1.verifySchnorr(sig, msg32, aggpubkey)
|
||||
assertTrue(check)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInvalidArguments() {
|
||||
assertFails {
|
||||
Secp256k1.pubkeyCreate(ByteArray(32))
|
||||
}
|
||||
assertFails {
|
||||
Secp256k1.pubkeyCreate(Hex.decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
|
||||
}
|
||||
assertFails {
|
||||
Secp256k1.pubkeyParse(ByteArray(33))
|
||||
}
|
||||
assertFails {
|
||||
Secp256k1.pubkeyParse(Hex.decode("03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
|
||||
}
|
||||
assertFails {
|
||||
Secp256k1.pubKeyCombine(arrayOf())
|
||||
}
|
||||
assertFails {
|
||||
Secp256k1.pubKeyCombine(arrayOf(ByteArray(0)))
|
||||
}
|
||||
assertFails {
|
||||
Secp256k1.signSchnorr(ByteArray(0), Hex.decode("0101010101010101010101010101010101010101010101010101010101010101"), null)
|
||||
}
|
||||
assertFails {
|
||||
Secp256k1.ecdsaRecover(
|
||||
Hex.decode("01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"),
|
||||
Hex.decode("0202020202020202020202020202020202020202020202020202020202020202"),
|
||||
-1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fuzzEcdsaSignVerify() {
|
||||
val random = Random.Default
|
||||
|
||||
Reference in New Issue
Block a user