5 Commits

Author SHA1 Message Date
Fabrice Drouin
f5e1655ff0 Set version to 0.13.0 (#98) 2024-01-23 16:46:55 +01:00
Fabrice Drouin
8ba5d4652e Use kotlin 1.9 (#92)
Use kotlin 1.9
2024-01-23 15:44:06 +01:00
Fabrice Drouin
e94e41b896 Update secp256k1 to version 0.4.1 (#96)
Use secp256k1 0.4.1
2024-01-02 11:16:36 +01:00
Fabrice Drouin
1a4c8b37cb Release 0.12.0 (#95) 2023-12-13 16:40:32 +01:00
Fabrice Drouin
f242b4ffe8 Check arguments passed to secp256k1 methods (#94)
* Check arguments passed to secp256k1 methods

Illegal arguments will trigger an internal callback that prints to stderr and calls abort.
We already check arguments in our JNI and kotlin native code but had missed 2 checks (recid in ecdsaRecover, empty arrays in pubkeyCombine).

* Implement the same "tweak" checks in the native code and JNI code

The native code was missing checks on the "tweak" size (which must be 32 bytes)
2023-12-13 13:42:14 +01:00
15 changed files with 708 additions and 910 deletions

View File

@@ -58,15 +58,11 @@ jobs:
base-devel base-devel
autotools autotools
mingw-w64-x86_64-gcc mingw-w64-x86_64-gcc
- name: Set up JDK 8
uses: actions/setup-java@v1
with:
java-version: 8
- name: Setup Android - name: Setup Android
if: matrix.os != 'windows-latest' if: matrix.os != 'windows-latest'
shell: bash shell: bash
run: | run: |
$ANDROID_HOME/tools/bin/sdkmanager "ndk;$ANDROID_NDK_VERSION" ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "ndk;$ANDROID_NDK_VERSION"
- name: Setup Android - name: Setup Android
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'
shell: msys2 {0} shell: msys2 {0}
@@ -86,7 +82,7 @@ jobs:
- name: Check Linux - name: Check Linux
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
shell: bash shell: bash
run: ./gradlew linuxTest run: ./gradlew linuxX64Test
- name: Check iOS - name: Check iOS
if: matrix.os == 'macOS-latest' if: matrix.os == 'macOS-latest'
shell: bash shell: bash
@@ -103,7 +99,7 @@ jobs:
- name: Publish Linux - name: Publish Linux
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
shell: bash shell: bash
run: ./gradlew publishLinuxPublicationToMavenLocal :jni:jvm:linux:publishJvmPublicationToMavenLocal run: ./gradlew publishLinuxX64PublicationToMavenLocal :jni:jvm:linux:publishJvmPublicationToMavenLocal
- name: Publish Windows - name: Publish Windows
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'
shell: msys2 {0} shell: msys2 {0}

View File

@@ -67,15 +67,11 @@ jobs:
base-devel base-devel
autotools autotools
mingw-w64-x86_64-gcc mingw-w64-x86_64-gcc
- name: Set up JDK 8
uses: actions/setup-java@v1
with:
java-version: 8
- name: Setup Android - name: Setup Android
if: matrix.os != 'windows-latest' if: matrix.os != 'windows-latest'
shell: bash shell: bash
run: | run: |
$ANDROID_HOME/tools/bin/sdkmanager "ndk;$ANDROID_NDK_VERSION" ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "ndk;$ANDROID_NDK_VERSION"
- name: Setup Android - name: Setup Android
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'
shell: msys2 {0} shell: msys2 {0}
@@ -95,7 +91,7 @@ jobs:
- name: Check Linux - name: Check Linux
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
shell: bash shell: bash
run: ./gradlew linuxTest run: ./gradlew linuxX64Test
- name: Check iOS - name: Check iOS
if: matrix.os == 'macOS-latest' if: matrix.os == 'macOS-latest'
shell: bash shell: bash
@@ -112,7 +108,7 @@ jobs:
- name: Publish Linux - name: Publish Linux
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
shell: bash shell: bash
run: ./gradlew publishLinuxPublicationToMavenLocal :jni:jvm:linux:publishJvmPublicationToMavenLocal -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }} run: ./gradlew publishLinuxX64PublicationToMavenLocal :jni:jvm:linux:publishJvmPublicationToMavenLocal -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }}
- name: Publish Windows - name: Publish Windows
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'
shell: msys2 {0} shell: msys2 {0}

View File

@@ -73,15 +73,11 @@ jobs:
base-devel base-devel
autotools autotools
mingw-w64-x86_64-gcc mingw-w64-x86_64-gcc
- name: Set up JDK 8
uses: actions/setup-java@v1
with:
java-version: 8
- name: Setup Android - name: Setup Android
if: matrix.os != 'windows-latest' if: matrix.os != 'windows-latest'
shell: bash shell: bash
run: | run: |
$ANDROID_HOME/tools/bin/sdkmanager "ndk;$ANDROID_NDK_VERSION" ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "ndk;$ANDROID_NDK_VERSION"
- name: Setup Android - name: Setup Android
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'
shell: msys2 {0} shell: msys2 {0}
@@ -101,7 +97,7 @@ jobs:
- name: Check Linux - name: Check Linux
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
shell: bash shell: bash
run: ./gradlew linuxTest run: ./gradlew linuxX64Test
- name: Check iOS - name: Check iOS
if: matrix.os == 'macOS-latest' if: matrix.os == 'macOS-latest'
shell: bash shell: bash

View File

@@ -3,8 +3,8 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.dokka.Platform import org.jetbrains.dokka.Platform
plugins { plugins {
kotlin("multiplatform") version "1.8.21" kotlin("multiplatform") version "1.9.22"
id("org.jetbrains.dokka") version "1.8.10" id("org.jetbrains.dokka") version "1.9.10"
`maven-publish` `maven-publish`
} }
@@ -16,13 +16,13 @@ buildscript {
dependencies { dependencies {
classpath("com.android.tools.build:gradle:7.3.1") classpath("com.android.tools.build:gradle:7.3.1")
classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.8.10") classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.9.10")
} }
} }
allprojects { allprojects {
group = "fr.acinq.secp256k1" group = "fr.acinq.secp256k1"
version = "0.12.0-SNAPSHOT" version = "0.13.0"
repositories { repositories {
google() google()
@@ -52,20 +52,22 @@ kotlin {
} }
} }
val nativeMain by sourceSets.creating { dependsOn(commonMain) } val nativeMain by sourceSets.creating
linuxX64("linux") { linuxX64 {
secp256k1CInterop("host") 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")
} }
ios { iosX64 {
secp256k1CInterop("ios")
}
iosArm64 {
secp256k1CInterop("ios")
}
iosSimulatorArm64 {
secp256k1CInterop("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 { sourceSets.all {
@@ -80,9 +82,9 @@ allprojects {
val currentOs = OperatingSystem.current() val currentOs = OperatingSystem.current()
val targets = when { val targets = when {
currentOs.isLinux -> listOf() currentOs.isLinux -> listOf()
currentOs.isMacOsX -> listOf("linux") currentOs.isMacOsX -> listOf("linuxX64")
currentOs.isWindows -> listOf("linux") currentOs.isWindows -> listOf("linuxX64")
else -> listOf("linux") else -> listOf("linuxX64")
}.mapNotNull { kotlin.targets.findByName(it) as? KotlinNativeTarget } }.mapNotNull { kotlin.targets.findByName(it) as? KotlinNativeTarget }
configure(targets) { configure(targets) {

View File

@@ -6,11 +6,10 @@ import fr.acinq.secp256k1.NativeSecp256k1
import java.util.* import java.util.*
public object NativeSecp256k1AndroidLoader { public object NativeSecp256k1AndroidLoader {
@JvmStatic @JvmStatic
@Synchronized @Synchronized
@Throws(Exception::class) @Throws(Exception::class)
fun load(): Secp256k1 { public fun load(): Secp256k1 {
try { try {
System.loadLibrary("secp256k1-jni") System.loadLibrary("secp256k1-jni")
return NativeSecp256k1 return NativeSecp256k1
@@ -27,5 +26,4 @@ public object NativeSecp256k1AndroidLoader {
} }
} }
} }

View File

@@ -14,82 +14,28 @@
#define SIG_FORMAT_COMPACT 1 #define SIG_FORMAT_COMPACT 1
#define SIG_FORMAT_DER 2 #define SIG_FORMAT_DER 2
void JNI_ThrowByName(JNIEnv *penv, const char *name, const char *msg) void JNI_ThrowByName(JNIEnv *penv, const char* name, const char* msg)
{
jclass cls = (*penv)->FindClass(penv, name);
if (cls != NULL)
{ {
jclass cls = (*penv)->FindClass(penv, name);
if (cls != NULL) {
(*penv)->ThrowNew(penv, cls, msg); (*penv)->ThrowNew(penv, cls, msg);
(*penv)->DeleteLocalRef(penv, cls); (*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) \ #define CHECKRESULT(errorcheck, message) { \
{ \ if (errorcheck) { \
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); \ JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1Exception", message); \
return 0; \ return 0; \
} \ } \
} }
#define CHECKRESULT1(errorcheck, message, dosomething) \ #define CHECKRESULT1(errorcheck, message, dosomething) { \
{ \ if (errorcheck) { \
if (error_callback_message) \
{ \
dosomething; \ 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); \ JNI_ThrowByName(penv, "fr/acinq/secp256k1/Secp256k1Exception", message); \
return 0; \ 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;
}
} }
/* /*
@@ -97,9 +43,10 @@ void my_error_callback_fn(const char *str, void *data)
* Method: secp256k1_context_create * Method: secp256k1_context_create
* Signature: (I)J * Signature: (I)J
*/ */
JNIEXPORT jlong JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1context_1create(JNIEnv *penv, jclass clazz, jint flags) JNIEXPORT jlong JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1context_1create
(JNIEnv *penv, jclass clazz, jint flags)
{ {
return (jlong)secp256k1_context_create(flags); return (jlong) secp256k1_context_create(flags);
} }
/* /*
@@ -107,11 +54,11 @@ JNIEXPORT jlong JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1c
* Method: secp256k1_context_destroy * Method: secp256k1_context_destroy
* Signature: (J)V * Signature: (J)V
*/ */
JNIEXPORT void JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1context_1destroy(JNIEnv *penv, jclass clazz, jlong ctx) JNIEXPORT void JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1context_1destroy
(JNIEnv *penv, jclass clazz, jlong ctx)
{ {
if (ctx != 0) if (ctx != 0) {
{ secp256k1_context_destroy((secp256k1_context*)ctx);
secp256k1_context_destroy((secp256k1_context *)ctx);
} }
} }
@@ -120,23 +67,19 @@ JNIEXPORT void JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1co
* Method: secp256k1_ec_seckey_verify * Method: secp256k1_ec_seckey_verify
* Signature: (J[B)I * Signature: (J[B)I
*/ */
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1seckey_1verify(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey) JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1seckey_1verify
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *seckey; jbyte *seckey;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return 0;
return 0; if (jseckey == NULL) return 0;
if (jseckey == NULL) if ((*penv)->GetArrayLength(penv, jseckey) != 32) return 0;
return 0;
if ((*penv)->GetArrayLength(penv, jseckey) != 32)
return 0;
SETUP_ERROR_CALLBACKS
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0); seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
result = secp256k1_ec_seckey_verify(ctx, (unsigned char *)seckey); result = secp256k1_ec_seckey_verify(ctx, (unsigned char*)seckey);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0); (*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
return result; return result;
} }
@@ -146,33 +89,30 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
* Method: secp256k1_ec_pubkey_parse * Method: secp256k1_ec_pubkey_parse
* Signature: (J[B)[B * Signature: (J[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1parse(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1parse
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *pubkeyBytes; jbyte *pubkeyBytes;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
size_t size; size_t size;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return 0;
return 0; if (jpubkey == NULL) return 0;
if (jpubkey == NULL)
return 0;
SETUP_ERROR_CALLBACKS
size = (*penv)->GetArrayLength(penv, jpubkey); size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size"); CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
pubkeyBytes = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pubkeyBytes = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pubkeyBytes, size); result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char*) pubkeyBytes, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkeyBytes, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkeyBytes, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
size = 65; size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65); jpubkey = (*penv)->NewByteArray(penv, 65);
pubkeyBytes = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pubkeyBytes = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pubkeyBytes, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED); result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char*) pubkeyBytes, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkeyBytes, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkeyBytes, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey; return jpubkey;
@@ -183,31 +123,28 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_ec_pubkey_create * Method: secp256k1_ec_pubkey_create
* Signature: (J[B)[B * Signature: (J[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1create(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1create
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *seckey, *pubkey; jbyte *seckey, *pubkey;
secp256k1_pubkey pub; secp256k1_pubkey pub;
int result = 0; int result = 0;
size_t len; size_t len;
jbyteArray jpubkey = 0; jbyteArray jpubkey = 0;
if (jseckey == NULL) if (jseckey == NULL) return NULL;
return NULL; if (jctx == 0) return NULL;
if (jctx == 0)
return NULL;
SETUP_ERROR_CALLBACKS
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0); seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
result = secp256k1_ec_pubkey_create(ctx, &pub, (unsigned char *)seckey); result = secp256k1_ec_pubkey_create(ctx, &pub, (unsigned char*)seckey);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0); (*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_create failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_create failed");
jpubkey = (*penv)->NewByteArray(penv, 65); jpubkey = (*penv)->NewByteArray(penv, 65);
pubkey = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pubkey = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
len = 65; len = 65;
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pubkey, &len, &pub, SECP256K1_EC_UNCOMPRESSED); result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char*)pubkey, &len, &pub, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkey, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkey, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey; return jpubkey;
@@ -218,36 +155,32 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_ecdsa_sign * Method: secp256k1_ecdsa_sign
* Signature: (J[B[B)[B * Signature: (J[B[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1sign(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jmsg, jbyteArray jseckey) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1sign
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jmsg, jbyteArray jseckey)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *seckey, *msg, *sig; jbyte *seckey, *msg, *sig;
secp256k1_ecdsa_signature signature; secp256k1_ecdsa_signature signature;
int result = 0; int result = 0;
jbyteArray jsig; jbyteArray jsig;
if (jctx == 0) if (jctx == 0) return NULL;
return NULL; if (jmsg == NULL) return NULL;
if (jmsg == NULL) if (jseckey == NULL) return NULL;
return NULL;
if (jseckey == NULL)
return NULL;
SETUP_ERROR_CALLBACKS
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message key must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message key must be 32 bytes");
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0); seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
msg = (*penv)->GetByteArrayElements(penv, jmsg, 0); msg = (*penv)->GetByteArrayElements(penv, jmsg, 0);
result = secp256k1_ecdsa_sign(ctx, &signature, (unsigned char *)msg, (unsigned char *)seckey, NULL, NULL); result = secp256k1_ecdsa_sign(ctx, &signature, (unsigned char*)msg, (unsigned char*)seckey, NULL, NULL);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0); (*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
(*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0); (*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_sign failed"); CHECKRESULT(!result, "secp256k1_ecdsa_sign failed");
jsig = (*penv)->NewByteArray(penv, 64); jsig = (*penv)->NewByteArray(penv, 64);
sig = (*penv)->GetByteArrayElements(penv, jsig, 0); sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
result = secp256k1_ecdsa_signature_serialize_compact(ctx, (unsigned char *)sig, &signature); result = secp256k1_ecdsa_signature_serialize_compact(ctx, (unsigned char*)sig, &signature);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0); (*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_serialize_compact failed"); CHECKRESULT(!result, "secp256k1_ecdsa_signature_serialize_compact failed");
return jsig; return jsig;
@@ -255,10 +188,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
int GetSignatureFormat(size_t size) int GetSignatureFormat(size_t size)
{ {
if (size == 64) if (size == 64) return SIG_FORMAT_COMPACT;
return SIG_FORMAT_COMPACT; if (size < 64) return SIG_FORMAT_UNKNOWN;
if (size < 64)
return SIG_FORMAT_UNKNOWN;
return SIG_FORMAT_DER; return SIG_FORMAT_DER;
} }
@@ -267,25 +198,20 @@ int GetSignatureFormat(size_t size)
* Method: secp256k1_ecdsa_verify * Method: secp256k1_ecdsa_verify
* Signature: (J[B[B[B)I * Signature: (J[B[B[B)I
*/ */
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1verify(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jbyteArray jpubkey) JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1verify
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jbyteArray jpubkey)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *pub, *msg, *sig; jbyte *pub, *msg, *sig;
secp256k1_ecdsa_signature signature; secp256k1_ecdsa_signature signature;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
size_t sigSize, pubSize; size_t sigSize, pubSize;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return 0;
return 0; if (jsig == NULL) return 0;
if (jsig == NULL) if (jmsg == NULL) return 0;
return 0; if (jpubkey == NULL) return 0;
if (jmsg == NULL)
return 0;
if (jpubkey == NULL)
return 0;
SETUP_ERROR_CALLBACKS
sigSize = (*penv)->GetArrayLength(penv, jsig); sigSize = (*penv)->GetArrayLength(penv, jsig);
int sigFormat = GetSignatureFormat(sigSize); int sigFormat = GetSignatureFormat(sigSize);
@@ -297,27 +223,26 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes");
sig = (*penv)->GetByteArrayElements(penv, jsig, 0); sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
switch (sigFormat) switch(sigFormat) {
{
case SIG_FORMAT_COMPACT: case SIG_FORMAT_COMPACT:
result = secp256k1_ecdsa_signature_parse_compact(ctx, &signature, (unsigned char *)sig); result = secp256k1_ecdsa_signature_parse_compact(ctx, &signature, (unsigned char*)sig);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0); (*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_compact failed"); CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_compact failed");
break; break;
case SIG_FORMAT_DER: case SIG_FORMAT_DER:
result = secp256k1_ecdsa_signature_parse_der(ctx, &signature, (unsigned char *)sig, sigSize); result = secp256k1_ecdsa_signature_parse_der(ctx, &signature, (unsigned char*)sig, sigSize);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0); (*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_der failed"); CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_der failed");
break; break;
} }
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pub, pubSize); result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char*)pub, pubSize);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
msg = (*penv)->GetByteArrayElements(penv, jmsg, 0); msg = (*penv)->GetByteArrayElements(penv, jmsg, 0);
result = secp256k1_ecdsa_verify(ctx, &signature, (unsigned char *)msg, &pubkey); result = secp256k1_ecdsa_verify(ctx, &signature, (unsigned char*)msg, &pubkey);
(*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0); (*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0);
return result; return result;
} }
@@ -327,9 +252,10 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
* Method: secp256k1_ecdsa_signature_normalize * Method: secp256k1_ecdsa_signature_normalize
* Signature: (J[B[B)I * Signature: (J[B[B)I
*/ */
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1signature_1normalize(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsigin, jbyteArray jsigout) JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1signature_1normalize
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsigin, jbyteArray jsigout)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *sig; jbyte *sig;
secp256k1_ecdsa_signature signature_in, signature_out; secp256k1_ecdsa_signature signature_in, signature_out;
size_t size; size_t size;
@@ -337,14 +263,9 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
int return_value = 0; int return_value = 0;
int sigFormat = SIG_FORMAT_UNKNOWN; int sigFormat = SIG_FORMAT_UNKNOWN;
if (jctx == 0) if (jctx == 0) return 0;
return 0; if (jsigin == NULL) return 0;
if (jsigin == NULL) if (jsigout == NULL) return 0;
return 0;
if (jsigout == NULL)
return 0;
SETUP_ERROR_CALLBACKS
size = (*penv)->GetArrayLength(penv, jsigin); size = (*penv)->GetArrayLength(penv, jsigin);
sigFormat = GetSignatureFormat(size); sigFormat = GetSignatureFormat(size);
@@ -352,22 +273,21 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
CHECKRESULT((*penv)->GetArrayLength(penv, jsigout) != 64, "output signature length must be 64 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jsigout) != 64, "output signature length must be 64 bytes");
sig = (*penv)->GetByteArrayElements(penv, jsigin, 0); sig = (*penv)->GetByteArrayElements(penv, jsigin, 0);
switch (sigFormat) switch(sigFormat) {
{
case SIG_FORMAT_COMPACT: case SIG_FORMAT_COMPACT:
result = secp256k1_ecdsa_signature_parse_compact(ctx, &signature_in, (unsigned char *)sig); result = secp256k1_ecdsa_signature_parse_compact(ctx, &signature_in, (unsigned char*)sig);
(*penv)->ReleaseByteArrayElements(penv, jsigin, sig, 0); (*penv)->ReleaseByteArrayElements(penv, jsigin, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_compact failed"); CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_compact failed");
break; break;
case SIG_FORMAT_DER: case SIG_FORMAT_DER:
result = secp256k1_ecdsa_signature_parse_der(ctx, &signature_in, (unsigned char *)sig, size); result = secp256k1_ecdsa_signature_parse_der(ctx, &signature_in, (unsigned char*)sig, size);
(*penv)->ReleaseByteArrayElements(penv, jsigin, sig, 0); (*penv)->ReleaseByteArrayElements(penv, jsigin, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_der failed"); CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_der failed");
break; break;
} }
return_value = secp256k1_ecdsa_signature_normalize(ctx, &signature_out, &signature_in); return_value = secp256k1_ecdsa_signature_normalize(ctx, &signature_out, &signature_in);
sig = (*penv)->GetByteArrayElements(penv, jsigout, 0); sig = (*penv)->GetByteArrayElements(penv, jsigout, 0);
result = secp256k1_ecdsa_signature_serialize_compact(ctx, (unsigned char *)sig, &signature_out); result = secp256k1_ecdsa_signature_serialize_compact(ctx, (unsigned char*)sig, &signature_out);
(*penv)->ReleaseByteArrayElements(penv, jsigout, sig, 0); (*penv)->ReleaseByteArrayElements(penv, jsigout, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_serialize_compact failed"); CHECKRESULT(!result, "secp256k1_ecdsa_signature_serialize_compact failed");
@@ -379,22 +299,18 @@ JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec
* Method: secp256k1_ec_privkey_negate * Method: secp256k1_ec_privkey_negate
* Signature: (J[B)[B * Signature: (J[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1negate(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1negate
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *seckey; jbyte *seckey;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return 0;
return 0; if (jseckey == NULL) return 0;
if (jseckey == NULL)
return 0;
SETUP_ERROR_CALLBACKS
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0); seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
result = secp256k1_ec_seckey_negate(ctx, (unsigned char *)seckey); result = secp256k1_ec_seckey_negate(ctx, (unsigned char*)seckey);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0); (*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
CHECKRESULT(!result, "secp256k1_ec_seckey_negate failed"); CHECKRESULT(!result, "secp256k1_ec_seckey_negate failed");
return jseckey; return jseckey;
@@ -405,25 +321,22 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_ec_pubkey_negate * Method: secp256k1_ec_pubkey_negate
* Signature: (J[B)[B * Signature: (J[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1negate(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1negate
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *pub; jbyte *pub;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
size_t size; size_t size;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return 0;
return 0; if (jpubkey == NULL) return 0;
if (jpubkey == NULL)
return 0;
SETUP_ERROR_CALLBACKS
size = (*penv)->GetArrayLength(penv, jpubkey); size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size"); CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pub, size); result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char*)pub, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
@@ -433,7 +346,7 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
size = 65; size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65); jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED); result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char*)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey; return jpubkey;
@@ -444,26 +357,22 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_ec_privkey_tweak_add * Method: secp256k1_ec_privkey_tweak_add
* Signature: (J[B[B)[B * Signature: (J[B[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1tweak_1add(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jtweak) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1tweak_1add
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jtweak)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *seckey, *tweak; jbyte *seckey, *tweak;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return NULL;
return NULL; if (jseckey == NULL) return NULL;
if (jseckey == NULL) if (jtweak == NULL) return NULL;
return NULL;
if (jtweak == NULL)
return NULL;
SETUP_ERROR_CALLBACKS
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes");
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0); seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0); tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0);
result = secp256k1_ec_seckey_tweak_add(ctx, (unsigned char *)seckey, (unsigned char *)tweak); result = secp256k1_ec_seckey_tweak_add(ctx, (unsigned char*)seckey, (unsigned char*)tweak);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0); (*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
(*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0); (*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0);
CHECKRESULT(!result, "secp256k1_ec_seckey_tweak_add failed"); CHECKRESULT(!result, "secp256k1_ec_seckey_tweak_add failed");
@@ -475,41 +384,37 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_ec_pubkey_tweak_add * Method: secp256k1_ec_pubkey_tweak_add
* Signature: (J[B[B)[B * Signature: (J[B[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1tweak_1add(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey, jbyteArray jtweak) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1tweak_1add
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey, jbyteArray jtweak)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *pub, *tweak; jbyte *pub, *tweak;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
size_t size; size_t size;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return NULL;
return NULL; if (jpubkey == NULL) return NULL;
if (jpubkey == NULL) if (jtweak == NULL) return NULL;
return NULL;
if (jtweak == NULL)
return NULL;
SETUP_ERROR_CALLBACKS
size = (*penv)->GetArrayLength(penv, jpubkey); size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size"); CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes");
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pub, size); result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char*)pub, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0); tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0);
result = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, (unsigned char *)tweak); result = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, (unsigned char*)tweak);
(*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0); (*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_tweak_add failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_tweak_add failed");
size = 65; size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65); jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED); result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char*)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey; return jpubkey;
@@ -520,26 +425,22 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_ec_privkey_tweak_mul * Method: secp256k1_ec_privkey_tweak_mul
* Signature: (J[B[B)[B * Signature: (J[B[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1tweak_1mul(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jtweak) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1privkey_1tweak_1mul
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jtweak)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *seckey, *tweak; jbyte *seckey, *tweak;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return NULL;
return NULL; if (jseckey == NULL) return NULL;
if (jseckey == NULL) if (jtweak == NULL) return NULL;
return NULL;
if (jtweak == NULL)
return NULL;
SETUP_ERROR_CALLBACKS
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes");
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0); seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0); tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0);
result = secp256k1_ec_seckey_tweak_mul(ctx, (unsigned char *)seckey, (unsigned char *)tweak); result = secp256k1_ec_seckey_tweak_mul(ctx, (unsigned char*)seckey, (unsigned char*)tweak);
CHECKRESULT(!result, "secp256k1_ec_seckey_tweak_mul failed"); CHECKRESULT(!result, "secp256k1_ec_seckey_tweak_mul failed");
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0); (*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
(*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0); (*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0);
@@ -551,40 +452,36 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_ec_pubkey_tweak_mul * Method: secp256k1_ec_pubkey_tweak_mul
* Signature: (J[B[B)[B * Signature: (J[B[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1tweak_1mul(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey, jbyteArray jtweak) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1tweak_1mul
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jpubkey, jbyteArray jtweak)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *pub, *tweak; jbyte *pub, *tweak;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
size_t size; size_t size;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return NULL;
return NULL; if (jpubkey == NULL) return NULL;
if (jpubkey == NULL) if (jtweak == NULL) return NULL;
return NULL;
if (jtweak == NULL)
return NULL;
SETUP_ERROR_CALLBACKS
size = (*penv)->GetArrayLength(penv, jpubkey); size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size"); CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jtweak) != 32, "tweak must be 32 bytes");
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pub, size); result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char*)pub, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0); tweak = (*penv)->GetByteArrayElements(penv, jtweak, 0);
result = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, (unsigned char *)tweak); result = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, (unsigned char*)tweak);
(*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0); (*penv)->ReleaseByteArrayElements(penv, jtweak, tweak, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_tweak_mul failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_tweak_mul failed");
size = 65; size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65); jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED); result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char*)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey; return jpubkey;
@@ -593,10 +490,8 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
void free_pubkeys(secp256k1_pubkey **pubkeys, size_t count) void free_pubkeys(secp256k1_pubkey **pubkeys, size_t count)
{ {
size_t i; size_t i;
for (i = 0; i < count; i++) for(i = 0; i < count; i++) {
{ if (pubkeys[i] != NULL) free(pubkeys[i]);
if (pubkeys[i] != NULL)
free(pubkeys[i]);
} }
free(pubkeys); free(pubkeys);
} }
@@ -606,9 +501,10 @@ void free_pubkeys(secp256k1_pubkey **pubkeys, size_t count)
* Method: secp256k1_ec_pubkey_combine * Method: secp256k1_ec_pubkey_combine
* Signature: (J[[B)[B * Signature: (J[[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1combine(JNIEnv *penv, jclass clazz, jlong jctx, jobjectArray jpubkeys) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ec_1pubkey_1combine
(JNIEnv *penv, jclass clazz, jlong jctx, jobjectArray jpubkeys)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *pub; jbyte *pub;
secp256k1_pubkey **pubkeys; secp256k1_pubkey **pubkeys;
secp256k1_pubkey combined; secp256k1_pubkey combined;
@@ -617,35 +513,31 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
size_t i; size_t i;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return NULL;
return NULL; if (jpubkeys == NULL) return NULL;
if (jpubkeys == NULL)
return NULL;
SETUP_ERROR_CALLBACKS
count = (*penv)->GetArrayLength(penv, jpubkeys); count = (*penv)->GetArrayLength(penv, jpubkeys);
pubkeys = calloc(count, sizeof(secp256k1_pubkey *)); CHECKRESULT(count < 1, "pubkey array cannot be empty")
pubkeys = calloc(count, sizeof(secp256k1_pubkey*));
for (i = 0; i < count; i++) for(i = 0; i < count; i++) {
{
pubkeys[i] = calloc(1, sizeof(secp256k1_pubkey)); pubkeys[i] = calloc(1, sizeof(secp256k1_pubkey));
jpubkey = (jbyteArray)(*penv)->GetObjectArrayElement(penv, jpubkeys, i); jpubkey = (jbyteArray) (*penv)->GetObjectArrayElement(penv, jpubkeys, i);
size = (*penv)->GetArrayLength(penv, jpubkey); size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT1((size != 33) && (size != 65), "invalid public key size", free_pubkeys(pubkeys, count)); CHECKRESULT1((size != 33) && (size != 65), "invalid public key size", free_pubkeys(pubkeys, count));
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, pubkeys[i], (unsigned char *)pub, size); result = secp256k1_ec_pubkey_parse(ctx, pubkeys[i], (unsigned char*)pub, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT1(!result, "secp256k1_ec_pubkey_parse failed", free_pubkeys(pubkeys, count)); CHECKRESULT1(!result, "secp256k1_ec_pubkey_parse failed", free_pubkeys(pubkeys, count));
} }
result = secp256k1_ec_pubkey_combine(ctx, &combined, (const secp256k1_pubkey *const *)pubkeys, count); result = secp256k1_ec_pubkey_combine(ctx, &combined, (const secp256k1_pubkey * const *)pubkeys, count);
free_pubkeys(pubkeys, count); free_pubkeys(pubkeys, count);
CHECKRESULT(!result, "secp256k1_ec_pubkey_combine failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_combine failed");
size = 65; size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65); jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pub, &size, &combined, SECP256K1_EC_UNCOMPRESSED); result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char*)pub, &size, &combined, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey; return jpubkey;
@@ -656,37 +548,33 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_ecdh * Method: secp256k1_ecdh
* Signature: (J[B[B)[B * Signature: (J[B[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdh(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jpubkey) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdh
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jseckey, jbyteArray jpubkey)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *seckeyBytes, *pubkeyBytes, *output; jbyte* seckeyBytes, *pubkeyBytes, *output;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
jbyteArray joutput; jbyteArray joutput;
size_t size; size_t size;
int result; int result;
if (jctx == 0) if (jctx == 0) return NULL;
return NULL; if (jseckey == NULL) return NULL;
if (jseckey == NULL) if (jpubkey == NULL) return NULL;
return NULL;
if (jpubkey == NULL)
return NULL;
SETUP_ERROR_CALLBACKS
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "invalid private key size"); CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "invalid private key size");
size = (*penv)->GetArrayLength(penv, jpubkey); size = (*penv)->GetArrayLength(penv, jpubkey);
CHECKRESULT((size != 33) && (size != 65), "invalid public key size"); CHECKRESULT((size != 33) && (size != 65), "invalid public key size");
pubkeyBytes = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pubkeyBytes = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char *)pubkeyBytes, size); result = secp256k1_ec_pubkey_parse(ctx, &pubkey, (unsigned char*)pubkeyBytes, size);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkeyBytes, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pubkeyBytes, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
seckeyBytes = (*penv)->GetByteArrayElements(penv, jseckey, 0); seckeyBytes = (*penv)->GetByteArrayElements(penv, jseckey, 0);
joutput = (*penv)->NewByteArray(penv, 32); joutput = (*penv)->NewByteArray(penv, 32);
output = (*penv)->GetByteArrayElements(penv, joutput, 0); output = (*penv)->GetByteArrayElements(penv, joutput, 0);
result = secp256k1_ecdh(ctx, (unsigned char *)output, &pubkey, (unsigned char *)seckeyBytes, NULL, NULL); result = secp256k1_ecdh(ctx, (unsigned char*)output, &pubkey, (unsigned char*)seckeyBytes, NULL, NULL);
(*penv)->ReleaseByteArrayElements(penv, joutput, output, 0); (*penv)->ReleaseByteArrayElements(penv, joutput, output, 0);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckeyBytes, 0); (*penv)->ReleaseByteArrayElements(penv, jseckey, seckeyBytes, 0);
return joutput; return joutput;
@@ -697,10 +585,11 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_ecdsa_recover * Method: secp256k1_ecdsa_recover
* Signature: (J[B[BI)[B * Signature: (J[B[BI)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1recover(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jint recid) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1ecdsa_1recover
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jint recid)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *sig, *msg, *pub; jbyte* sig, *msg, *pub;
jbyteArray jpubkey; jbyteArray jpubkey;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
secp256k1_ecdsa_recoverable_signature signature; secp256k1_ecdsa_recoverable_signature signature;
@@ -709,32 +598,24 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
size_t sigSize, size; size_t sigSize, size;
int result; int result;
if (jctx == 0) if (jctx == 0) return NULL;
return NULL; if (jsig == NULL) return NULL;
if (jsig == NULL) if (jmsg == NULL) return NULL;
return NULL; CHECKRESULT(recid < 0 || recid > 3, "invalid recovery id");
if (jmsg == NULL)
return NULL;
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); sigSize = (*penv)->GetArrayLength(penv, jsig);
int sigFormat = GetSignatureFormat(sigSize); int sigFormat = GetSignatureFormat(sigSize);
CHECKRESULT(sigFormat == SIG_FORMAT_UNKNOWN, "invalid signature size"); CHECKRESULT(sigFormat == SIG_FORMAT_UNKNOWN, "invalid signature size");
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes");
sig = (*penv)->GetByteArrayElements(penv, jsig, 0); sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
switch (sigFormat) switch(sigFormat) {
{
case SIG_FORMAT_COMPACT: case SIG_FORMAT_COMPACT:
result = secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &signature, (unsigned char *)sig, recid); result = secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &signature, (unsigned char*)sig, recid);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0); (*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_recoverable_signature_parse_compact failed"); CHECKRESULT(!result, "secp256k1_ecdsa_recoverable_signature_parse_compact failed");
break; break;
case SIG_FORMAT_DER: case SIG_FORMAT_DER:
result = secp256k1_ecdsa_signature_parse_der(ctx, &dummy, (unsigned char *)sig, sigSize); result = secp256k1_ecdsa_signature_parse_der(ctx, &dummy, (unsigned char*)sig, sigSize);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0); (*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_der failed"); CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_der failed");
result = secp256k1_ecdsa_signature_serialize_compact(ctx, dummyBytes, &dummy); result = secp256k1_ecdsa_signature_serialize_compact(ctx, dummyBytes, &dummy);
@@ -744,14 +625,14 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
break; break;
} }
msg = (*penv)->GetByteArrayElements(penv, jmsg, 0); msg = (*penv)->GetByteArrayElements(penv, jmsg, 0);
result = secp256k1_ecdsa_recover(ctx, &pubkey, &signature, (unsigned char *)msg); result = secp256k1_ecdsa_recover(ctx, &pubkey, &signature, (unsigned char*)msg);
(*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0); (*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_recover failed"); CHECKRESULT(!result, "secp256k1_ecdsa_recover failed");
size = 65; size = 65;
jpubkey = (*penv)->NewByteArray(penv, 65); jpubkey = (*penv)->NewByteArray(penv, 65);
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char *)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED); result = secp256k1_ec_pubkey_serialize(ctx, (unsigned char*)pub, &size, &pubkey, SECP256K1_EC_UNCOMPRESSED);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_serialize failed");
return jpubkey; return jpubkey;
@@ -762,27 +643,23 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_compact_to_der * Method: secp256k1_compact_to_der
* Signature: (J[B)[B * Signature: (J[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1compact_1to_1der(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1compact_1to_1der
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *sig; jbyte *sig;
secp256k1_ecdsa_signature signature; secp256k1_ecdsa_signature signature;;
unsigned char der[73]; unsigned char der[73];
size_t size; size_t size;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return 0;
return 0; if (jsig == NULL) return 0;
if (jsig == NULL)
return 0;
SETUP_ERROR_CALLBACKS
CHECKRESULT((*penv)->GetArrayLength(penv, jsig) != 64, "invalid signature size"); CHECKRESULT((*penv)->GetArrayLength(penv, jsig) != 64, "invalid signature size");
size = (*penv)->GetArrayLength(penv, jsig); size = (*penv)->GetArrayLength(penv, jsig);
sig = (*penv)->GetByteArrayElements(penv, jsig, 0); sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
result = secp256k1_ecdsa_signature_parse_compact(ctx, &signature, (unsigned char *)sig); result = secp256k1_ecdsa_signature_parse_compact(ctx, &signature, (unsigned char*)sig);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0); (*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_compact failed"); CHECKRESULT(!result, "secp256k1_ecdsa_signature_parse_compact failed");
@@ -801,28 +678,23 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_schnorrsig_sign * Method: secp256k1_schnorrsig_sign
* Signature: (J[B[B[B)[B * Signature: (J[B[B[B)[B
*/ */
JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1schnorrsig_1sign(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jmsg, jbyteArray jseckey, jbyteArray jauxrand32) JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1schnorrsig_1sign
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jmsg, jbyteArray jseckey, jbyteArray jauxrand32)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *seckey, *msg, *sig, *auxrand32 = NULL; jbyte *seckey, *msg, *sig, *auxrand32 = NULL;
secp256k1_keypair keypair; secp256k1_keypair keypair;
unsigned char signature[64]; unsigned char signature[64];
int result = 0; int result = 0;
jbyteArray jsig; jbyteArray jsig;
if (jctx == 0) if (jctx == 0) return NULL;
return NULL; if (jmsg == NULL) return NULL;
if (jmsg == NULL) if (jseckey == NULL) return NULL;
return NULL;
if (jseckey == NULL)
return NULL;
SETUP_ERROR_CALLBACKS
CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jseckey) != 32, "secret key must be 32 bytes");
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes");
if (jauxrand32 != 0) if (jauxrand32 != 0) {
{
CHECKRESULT((*penv)->GetArrayLength(penv, jauxrand32) != 32, "auxiliary random data must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jauxrand32) != 32, "auxiliary random data must be 32 bytes");
} }
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0); seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
@@ -831,15 +703,13 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
CHECKRESULT(!result, "secp256k1_keypair_create failed"); CHECKRESULT(!result, "secp256k1_keypair_create failed");
msg = (*penv)->GetByteArrayElements(penv, jmsg, 0); msg = (*penv)->GetByteArrayElements(penv, jmsg, 0);
if (jauxrand32 != 0) if (jauxrand32 != 0) {
{
auxrand32 = (*penv)->GetByteArrayElements(penv, jauxrand32, 0); auxrand32 = (*penv)->GetByteArrayElements(penv, jauxrand32, 0);
} }
result = secp256k1_schnorrsig_sign32(ctx, signature, (unsigned char *)msg, &keypair, auxrand32); result = secp256k1_schnorrsig_sign32(ctx, signature, (unsigned char*)msg, &keypair, auxrand32);
(*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0); (*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0);
if (auxrand32 != 0) if (auxrand32 != 0) {
{
(*penv)->ReleaseByteArrayElements(penv, jauxrand32, auxrand32, 0); (*penv)->ReleaseByteArrayElements(penv, jauxrand32, auxrand32, 0);
} }
CHECKRESULT(!result, "secp256k1_schnorrsig_sign failed"); CHECKRESULT(!result, "secp256k1_schnorrsig_sign failed");
@@ -856,36 +726,31 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
* Method: secp256k1_schnorrsig_verify * Method: secp256k1_schnorrsig_verify
* Signature: (J[B[B[B)I * Signature: (J[B[B[B)I
*/ */
JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1schnorrsig_1verify(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jbyteArray jpubkey) JNIEXPORT jint JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1schnorrsig_1verify
(JNIEnv *penv, jclass clazz, jlong jctx, jbyteArray jsig, jbyteArray jmsg, jbyteArray jpubkey)
{ {
secp256k1_context *ctx = (secp256k1_context *)jctx; secp256k1_context* ctx = (secp256k1_context *)jctx;
jbyte *pub, *msg, *sig; jbyte *pub, *msg, *sig;
secp256k1_xonly_pubkey pubkey; secp256k1_xonly_pubkey pubkey;
int result = 0; int result = 0;
if (jctx == 0) if (jctx == 0) return 0;
return 0; if (jsig == NULL) return 0;
if (jsig == NULL) if (jmsg == NULL) return 0;
return 0; if (jpubkey == NULL) return 0;
if (jmsg == NULL)
return 0;
if (jpubkey == NULL)
return 0;
SETUP_ERROR_CALLBACKS
CHECKRESULT((*penv)->GetArrayLength(penv, jsig) != 64, "signature must be 64 bytes"); 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, jpubkey) != 32, "public key must be 32 bytes");
CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes"); CHECKRESULT((*penv)->GetArrayLength(penv, jmsg) != 32, "message must be 32 bytes");
pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0); pub = (*penv)->GetByteArrayElements(penv, jpubkey, 0);
result = secp256k1_xonly_pubkey_parse(ctx, &pubkey, (unsigned char *)pub); result = secp256k1_xonly_pubkey_parse(ctx, &pubkey, (unsigned char*)pub);
(*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0); (*penv)->ReleaseByteArrayElements(penv, jpubkey, pub, 0);
CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed"); CHECKRESULT(!result, "secp256k1_ec_pubkey_parse failed");
sig = (*penv)->GetByteArrayElements(penv, jsig, 0); sig = (*penv)->GetByteArrayElements(penv, jsig, 0);
msg = (*penv)->GetByteArrayElements(penv, jmsg, 0); msg = (*penv)->GetByteArrayElements(penv, jmsg, 0);
result = secp256k1_schnorrsig_verify(ctx, (unsigned char *)sig, (unsigned char *)msg, 32, &pubkey); result = secp256k1_schnorrsig_verify(ctx, (unsigned char*)sig, (unsigned char*)msg, 32, &pubkey);
(*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0); (*penv)->ReleaseByteArrayElements(penv, jsig, sig, 0);
(*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0); (*penv)->ReleaseByteArrayElements(penv, jmsg, msg, 0);
return result; return result;

View File

@@ -9,7 +9,10 @@ cd secp256k1
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 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 mkdir -p ../build/ios
cp -v _build/universal/* ../build/ios/ cp -v _build/universal/ios/* ../build/ios/
mkdir -p ../build/iosSimulatorArm64
cp -v _build/universal/iosSimulatorArm64/* ../build/iosSimulatorArm64/
rm -rf _build rm -rf _build
make clean make clean

View File

@@ -69,9 +69,22 @@ HOST_FLAGS="${ARCH_FLAGS} -mios-simulator-version-min=${MIN_IOS_VERSION} -isysro
CHOST="x86_64-apple-darwin" CHOST="x86_64-apple-darwin"
Build "$@" 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 # Create universal binary
cd "${PLATFORMS}/${PLATFORM_ARM}/lib" cd "${PLATFORMS}/${PLATFORM_ARM}/lib"
LIB_NAME=`find . -iname *.a` LIB_NAME=`find . -iname *.a`
cd - cd -
mkdir -p "${UNIVERSAL}" &> /dev/null mkdir -p "${UNIVERSAL}/ios" &> /dev/null
lipo -create -output "${UNIVERSAL}/${LIB_NAME}" "${PLATFORMS}/${PLATFORM_ARM}/lib/${LIB_NAME}" "${PLATFORMS}/${PLATFORM_ISIM}/lib/${LIB_NAME}" 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}"

View File

@@ -21,9 +21,9 @@ mvn deploy:deploy-file -DrepositoryId=ossrh -Durl=https://oss.sonatype.org/conte
-Djavadoc=$ARTIFACT_ID_BASE-$VERSION-javadoc.jar -Djavadoc=$ARTIFACT_ID_BASE-$VERSION-javadoc.jar
popd popd
pushd . pushd .
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 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
cd fr/acinq/secp256k1/secp256k1-kmp-$i/$VERSION cd fr/acinq/secp256k1/secp256k1-kmp-$i/$VERSION
if [ $i == iosarm64 ] || [ $i == iosx64 ]; then if [ $i == iosarm64 ] || [ $i == iossimulatorarm64 ] || [ $i == iosx64 ]; then
mvn deploy:deploy-file -DrepositoryId=ossrh -Durl=https://oss.sonatype.org/content/repositories/snapshots/ \ mvn deploy:deploy-file -DrepositoryId=ossrh -Durl=https://oss.sonatype.org/content/repositories/snapshots/ \
-DpomFile=$ARTIFACT_ID_BASE-$i-$VERSION.pom \ -DpomFile=$ARTIFACT_ID_BASE-$i-$VERSION.pom \
-Dfile=$ARTIFACT_ID_BASE-$i-$VERSION.klib \ -Dfile=$ARTIFACT_ID_BASE-$i-$VERSION.klib \
@@ -32,7 +32,7 @@ for i in iosarm64 iosx64 jni-android jni-common jni-jvm-darwin jni-jvm-extract j
-Dclassifiers=metadata,,cinterop-libsecp256k1 \ -Dclassifiers=metadata,,cinterop-libsecp256k1 \
-Dsources=$ARTIFACT_ID_BASE-$i-$VERSION-sources.jar \ -Dsources=$ARTIFACT_ID_BASE-$i-$VERSION-sources.jar \
-Djavadoc=$ARTIFACT_ID_BASE-$i-$VERSION-javadoc.jar -Djavadoc=$ARTIFACT_ID_BASE-$i-$VERSION-javadoc.jar
elif [ $i == linux ]; then elif [ $i == linuxx64 ]; then
mvn deploy:deploy-file -DrepositoryId=ossrh -Durl=https://oss.sonatype.org/content/repositories/snapshots/ \ mvn deploy:deploy-file -DrepositoryId=ossrh -Durl=https://oss.sonatype.org/content/repositories/snapshots/ \
-DpomFile=$ARTIFACT_ID_BASE-$i-$VERSION.pom \ -DpomFile=$ARTIFACT_ID_BASE-$i-$VERSION.pom \
-Dfile=$ARTIFACT_ID_BASE-$i-$VERSION.klib \ -Dfile=$ARTIFACT_ID_BASE-$i-$VERSION.klib \

View File

@@ -166,17 +166,7 @@ public interface Secp256k1 {
internal expect fun getSecpk256k1(): Secp256k1 internal expect fun getSecpk256k1(): Secp256k1
public open class Secp256k1Exception : RuntimeException { public 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() : super()
public constructor(message: String?) : super(message) public constructor(message: String?) : super(message)
} }

View File

@@ -3,8 +3,12 @@ package = secp256k1
headers = secp256k1.h secp256k1_ecdh.h secp256k1_recovery.h secp256k1_extrakeys.h secp256k1_schnorrsig.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 headerFilter = secp256k1/** secp256k1_ecdh.h secp256k1_recovery.h secp256k1_extrakeys.h secp256k1_schnorrsig.h secp256k1.h
libraryPaths.linux = c/secp256k1/build/linux/ staticLibraries.linux = libsecp256k1.a
libraryPaths.linux = c/secp256k1/build/linux/ native/build/linux/ native/build/darwin/
linkerOpts.linux = -L/usr/lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/local/lib linkerOpts.linux = -L/usr/lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/local/lib
libraryPaths.ios = c/secp256k1/build/ios/ /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/
linkerOpts.ios = -framework Security -framework Foundation linkerOpts.ios = -framework Security -framework Foundation

View File

@@ -4,67 +4,15 @@ import kotlinx.cinterop.*
import platform.posix.size_tVar import platform.posix.size_tVar
import secp256k1.* import secp256k1.*
private typealias Secp256k1CallbackHandler = (String) -> Unit @OptIn(ExperimentalUnsignedTypes::class, ExperimentalForeignApi::class)
@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 { public object Secp256k1Native : Secp256k1 {
private val ctx: CPointer<secp256k1_context> by lazy { 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()) 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") ?: error("Could not create secp256k1 context")
} }
private fun Int.requireSuccess(message: String): Int { private fun Int.requireSuccess(message: String): Int = if (this != 1) throw Secp256k1Exception(message) else this
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 { private fun MemScope.allocSignature(input: ByteArray): secp256k1_ecdsa_signature {
val sig = alloc<secp256k1_ecdsa_signature>() val sig = alloc<secp256k1_ecdsa_signature>()
@@ -110,245 +58,205 @@ public object Secp256k1Native : Secp256k1 {
public override fun verify(signature: ByteArray, message: ByteArray, pubkey: ByteArray): Boolean { public override fun verify(signature: ByteArray, message: ByteArray, pubkey: ByteArray): Boolean {
require(message.size == 32) require(message.size == 32)
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nPubkey = allocPublicKey(pubkey) val nPubkey = allocPublicKey(pubkey)
val nMessage = toNat(message) val nMessage = toNat(message)
val nSig = allocSignature(signature) val nSig = allocSignature(signature)
val verify = secp256k1_ecdsa_verify(ctx, nSig.ptr, nMessage, nPubkey.ptr) return secp256k1_ecdsa_verify(ctx, nSig.ptr, nMessage, nPubkey.ptr) == 1
callbackHandler.checkForErrors()
return verify == 1
}
} }
} }
public override fun sign(message: ByteArray, privkey: ByteArray): ByteArray { public override fun sign(message: ByteArray, privkey: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
require(message.size == 32) require(message.size == 32)
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nPrivkey = toNat(privkey) val nPrivkey = toNat(privkey)
val nMessage = toNat(message) val nMessage = toNat(message)
val nSig = alloc<secp256k1_ecdsa_signature>() val nSig = alloc<secp256k1_ecdsa_signature>()
secp256k1_ecdsa_sign(ctx, nSig.ptr, nMessage, nPrivkey, null, null).requireSuccess(callbackHandler, "secp256k1_ecdsa_sign() failed") secp256k1_ecdsa_sign(ctx, nSig.ptr, nMessage, nPrivkey, null, null).requireSuccess("secp256k1_ecdsa_sign() failed")
return serializeSignature(nSig) return serializeSignature(nSig)
} }
} }
}
public override fun signatureNormalize(sig: ByteArray): Pair<ByteArray, Boolean> { public override fun signatureNormalize(sig: ByteArray): Pair<ByteArray, Boolean> {
require(sig.size >= 64) { "invalid signature ${Hex.encode(sig)}" } require(sig.size >= 64){ "invalid signature ${Hex.encode(sig)}" }
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nSig = allocSignature(sig) val nSig = allocSignature(sig)
val isHighS = secp256k1_ecdsa_signature_normalize(ctx, nSig.ptr, nSig.ptr) val isHighS = secp256k1_ecdsa_signature_normalize(ctx, nSig.ptr, nSig.ptr)
callbackHandler.checkForErrors()
return Pair(serializeSignature(nSig), isHighS == 1) return Pair(serializeSignature(nSig), isHighS == 1)
} }
} }
}
public override fun secKeyVerify(privkey: ByteArray): Boolean { public override fun secKeyVerify(privkey: ByteArray): Boolean {
if (privkey.size != 32) return false if (privkey.size != 32) return false
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nPrivkey = toNat(privkey) val nPrivkey = toNat(privkey)
val result = secp256k1_ec_seckey_verify(ctx, nPrivkey) == 1 return secp256k1_ec_seckey_verify(ctx, nPrivkey) == 1
callbackHandler.checkForErrors()
return result
}
} }
} }
public override fun pubkeyCreate(privkey: ByteArray): ByteArray { public override fun pubkeyCreate(privkey: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nPrivkey = toNat(privkey) val nPrivkey = toNat(privkey)
val nPubkey = alloc<secp256k1_pubkey>() val nPubkey = alloc<secp256k1_pubkey>()
secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nPrivkey).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_create() failed") secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nPrivkey).requireSuccess("secp256k1_ec_pubkey_create() failed")
return serializePubkey(nPubkey) return serializePubkey(nPubkey)
} }
} }
}
public override fun pubkeyParse(pubkey: ByteArray): ByteArray { public override fun pubkeyParse(pubkey: ByteArray): ByteArray {
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nPubkey = allocPublicKey(pubkey) val nPubkey = allocPublicKey(pubkey)
val result = serializePubkey(nPubkey) return serializePubkey(nPubkey)
callbackHandler.checkForErrors()
return result
}
} }
} }
public override fun privKeyNegate(privkey: ByteArray): ByteArray { public override fun privKeyNegate(privkey: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val negated = privkey.copyOf() val negated = privkey.copyOf()
val negPriv = toNat(negated) val negPriv = toNat(negated)
secp256k1_ec_seckey_negate(ctx, negPriv).requireSuccess(callbackHandler, "secp256k1_ec_seckey_negate() failed") secp256k1_ec_seckey_negate(ctx, negPriv).requireSuccess("secp256k1_ec_seckey_negate() failed")
return negated return negated
} }
} }
}
public override fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray { public override fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
CallbackHandler(ctx).use { callbackHandler -> require(tweak.size == 32)
memScoped { memScoped {
val added = privkey.copyOf() val added = privkey.copyOf()
val natAdd = toNat(added) val natAdd = toNat(added)
val natTweak = toNat(tweak) val natTweak = toNat(tweak)
secp256k1_ec_seckey_tweak_add(ctx, natAdd, natTweak).requireSuccess(callbackHandler, "secp256k1_ec_seckey_tweak_add() failed") secp256k1_ec_seckey_tweak_add(ctx, natAdd, natTweak).requireSuccess("secp256k1_ec_seckey_tweak_add() failed")
return added return added
} }
} }
}
public override fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray { public override fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
CallbackHandler(ctx).use { callbackHandler -> require(tweak.size == 32)
memScoped { memScoped {
val multiplied = privkey.copyOf() val multiplied = privkey.copyOf()
val natMul = toNat(multiplied) val natMul = toNat(multiplied)
val natTweak = toNat(tweak) val natTweak = toNat(tweak)
secp256k1_ec_privkey_tweak_mul(ctx, natMul, natTweak).requireSuccess(callbackHandler, "secp256k1_ec_privkey_tweak_mul() failed") secp256k1_ec_privkey_tweak_mul(ctx, natMul, natTweak).requireSuccess("secp256k1_ec_privkey_tweak_mul() failed")
return multiplied return multiplied
} }
} }
}
public override fun pubKeyNegate(pubkey: ByteArray): ByteArray { public override fun pubKeyNegate(pubkey: ByteArray): ByteArray {
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nPubkey = allocPublicKey(pubkey) val nPubkey = allocPublicKey(pubkey)
secp256k1_ec_pubkey_negate(ctx, nPubkey.ptr).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_negate() failed") secp256k1_ec_pubkey_negate(ctx, nPubkey.ptr).requireSuccess("secp256k1_ec_pubkey_negate() failed")
return serializePubkey(nPubkey) return serializePubkey(nPubkey)
} }
} }
}
public override fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray { public override fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray {
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler -> require(tweak.size == 32)
memScoped { memScoped {
val nPubkey = allocPublicKey(pubkey) val nPubkey = allocPublicKey(pubkey)
val nTweak = toNat(tweak) val nTweak = toNat(tweak)
secp256k1_ec_pubkey_tweak_add(ctx, nPubkey.ptr, nTweak).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_tweak_add() failed") secp256k1_ec_pubkey_tweak_add(ctx, nPubkey.ptr, nTweak).requireSuccess("secp256k1_ec_pubkey_tweak_add() failed")
return serializePubkey(nPubkey) return serializePubkey(nPubkey)
} }
} }
}
public override fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray { public override fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray {
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler -> require(tweak.size == 32)
memScoped { memScoped {
val nPubkey = allocPublicKey(pubkey) val nPubkey = allocPublicKey(pubkey)
val nTweak = toNat(tweak) val nTweak = toNat(tweak)
secp256k1_ec_pubkey_tweak_mul(ctx, nPubkey.ptr, nTweak).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_tweak_mul() failed") secp256k1_ec_pubkey_tweak_mul(ctx, nPubkey.ptr, nTweak).requireSuccess("secp256k1_ec_pubkey_tweak_mul() failed")
return serializePubkey(nPubkey) return serializePubkey(nPubkey)
} }
} }
}
public override fun pubKeyCombine(pubkeys: Array<ByteArray>): ByteArray { public override fun pubKeyCombine(pubkeys: Array<ByteArray>): ByteArray {
require(pubkeys.isNotEmpty())
pubkeys.forEach { require(it.size == 33 || it.size == 65) } pubkeys.forEach { require(it.size == 33 || it.size == 65) }
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nPubkeys = pubkeys.map { allocPublicKey(it).ptr } val nPubkeys = pubkeys.map { allocPublicKey(it).ptr }
val combined = alloc<secp256k1_pubkey>() val combined = alloc<secp256k1_pubkey>()
secp256k1_ec_pubkey_combine(ctx, combined.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_combine() failed") secp256k1_ec_pubkey_combine(ctx, combined.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess("secp256k1_ec_pubkey_combine() failed")
return serializePubkey(combined) return serializePubkey(combined)
} }
} }
}
public override fun ecdh(privkey: ByteArray, pubkey: ByteArray): ByteArray { public override fun ecdh(privkey: ByteArray, pubkey: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nPubkey = allocPublicKey(pubkey) val nPubkey = allocPublicKey(pubkey)
val nPrivkey = toNat(privkey) val nPrivkey = toNat(privkey)
val output = allocArray<UByteVar>(32) val output = allocArray<UByteVar>(32)
secp256k1_ecdh(ctx, output, nPubkey.ptr, nPrivkey, null, null).requireSuccess(callbackHandler, "secp256k1_ecdh() failed") secp256k1_ecdh(ctx, output, nPubkey.ptr, nPrivkey, null, null).requireSuccess("secp256k1_ecdh() failed")
return output.readBytes(32) return output.readBytes(32)
} }
} }
}
public override fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray { public override fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray {
require(sig.size == 64) require(sig.size == 64)
require(message.size == 32) require(message.size == 32)
// we do not check that recid is valid, which should trigger our illegal callback handler to throw a Secp256k1IllegalCallbackException require(recid in 0..3)
// require(recid in 0..3)
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nSig = toNat(sig) val nSig = toNat(sig)
val rSig = alloc<secp256k1_ecdsa_recoverable_signature>() 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") secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, rSig.ptr, nSig, recid).requireSuccess("secp256k1_ecdsa_recoverable_signature_parse_compact() failed")
val nMessage = toNat(message) val nMessage = toNat(message)
val pubkey = alloc<secp256k1_pubkey>() val pubkey = alloc<secp256k1_pubkey>()
secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess(callbackHandler, "secp256k1_ecdsa_recover() failed") secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess("secp256k1_ecdsa_recover() failed")
return serializePubkey(pubkey) return serializePubkey(pubkey)
} }
} }
}
public override fun compact2der(sig: ByteArray): ByteArray { public override fun compact2der(sig: ByteArray): ByteArray {
require(sig.size == 64) require(sig.size == 64)
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nSig = allocSignature(sig) val nSig = allocSignature(sig)
val natOutput = allocArray<UByteVar>(73) val natOutput = allocArray<UByteVar>(73)
val len = alloc<size_tVar>() val len = alloc<size_tVar>()
len.value = 73.convert() len.value = 73.convert()
secp256k1_ecdsa_signature_serialize_der(ctx, natOutput, len.ptr, nSig.ptr).requireSuccess(callbackHandler, "secp256k1_ecdsa_signature_serialize_der() failed") secp256k1_ecdsa_signature_serialize_der(ctx, natOutput, len.ptr, nSig.ptr).requireSuccess("secp256k1_ecdsa_signature_serialize_der() failed")
return natOutput.readBytes(len.value.toInt()) return natOutput.readBytes(len.value.toInt())
} }
} }
}
override fun verifySchnorr(signature: ByteArray, data: ByteArray, pub: ByteArray): Boolean { override fun verifySchnorr(signature: ByteArray, data: ByteArray, pub: ByteArray): Boolean {
require(signature.size == 64) require(signature.size == 64)
require(data.size == 32) require(data.size == 32)
require(pub.size == 32) require(pub.size == 32)
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nPub = toNat(pub) val nPub = toNat(pub)
val pubkey = alloc<secp256k1_xonly_pubkey>() val pubkey = alloc<secp256k1_xonly_pubkey>()
secp256k1_xonly_pubkey_parse(ctx, pubkey.ptr, nPub).requireSuccess(callbackHandler, "secp256k1_xonly_pubkey_parse() failed") secp256k1_xonly_pubkey_parse(ctx, pubkey.ptr, nPub).requireSuccess("secp256k1_xonly_pubkey_parse() failed")
val nData = toNat(data) val nData = toNat(data)
val nSig = toNat(signature) val nSig = toNat(signature)
return secp256k1_schnorrsig_verify(ctx, nSig, nData, 32u, pubkey.ptr) == 1 return secp256k1_schnorrsig_verify(ctx, nSig, nData, 32u, pubkey.ptr) == 1
} }
} }
}
override fun signSchnorr(data: ByteArray, sec: ByteArray, auxrand32: ByteArray?): ByteArray { override fun signSchnorr(data: ByteArray, sec: ByteArray, auxrand32: ByteArray?): ByteArray {
require(sec.size == 32) require(sec.size == 32)
require(data.size == 32) require(data.size == 32)
auxrand32?.let { require(it.size == 32) } auxrand32?.let { require(it.size == 32) }
CallbackHandler(ctx).use { callbackHandler ->
memScoped { memScoped {
val nSec = toNat(sec) val nSec = toNat(sec)
val nData = toNat(data) val nData = toNat(data)
val nAuxrand32 = auxrand32?.let { toNat(it) } val nAuxrand32 = auxrand32?.let { toNat(it) }
val nSig = allocArray<UByteVar>(64) val nSig = allocArray<UByteVar>(64)
val keypair = alloc<secp256k1_keypair>() val keypair = alloc<secp256k1_keypair>()
secp256k1_keypair_create(ctx, keypair.ptr, nSec).requireSuccess(callbackHandler, "secp256k1_keypair_create() failed") secp256k1_keypair_create(ctx, keypair.ptr, nSec).requireSuccess("secp256k1_keypair_create() failed")
secp256k1_schnorrsig_sign32(ctx, nSig, nData, keypair.ptr, nAuxrand32).requireSuccess(callbackHandler, "secp256k1_ecdsa_sign() failed") secp256k1_schnorrsig_sign32(ctx, nSig, nData, keypair.ptr, nAuxrand32).requireSuccess("secp256k1_ecdsa_sign() failed")
return nSig.readBytes(64) return nSig.readBytes(64)
} }
} }
}
public override fun cleanup() { public override fun cleanup() {
secp256k1_context_destroy(ctx) secp256k1_context_destroy(ctx)

View File

@@ -1,4 +1,3 @@
plugins { plugins {
kotlin("multiplatform") kotlin("multiplatform")
if (System.getProperty("includeAndroid")?.toBoolean() == true) { if (System.getProperty("includeAndroid")?.toBoolean() == true) {
@@ -36,14 +35,14 @@ kotlin {
} }
if (includeAndroid) { if (includeAndroid) {
android { androidTarget {
compilations.all { compilations.all {
kotlinOptions.jvmTarget = "1.8" kotlinOptions.jvmTarget = "1.8"
} }
sourceSets["androidMain"].dependencies { sourceSets["androidMain"].dependencies {
implementation(project(":jni:android")) implementation(project(":jni:android"))
} }
sourceSets["androidTest"].dependencies { sourceSets["androidUnitTest"].dependencies {
implementation(kotlin("test-junit")) implementation(kotlin("test-junit"))
implementation("androidx.test.ext:junit:1.1.2") implementation("androidx.test.ext:junit:1.1.2")
implementation("androidx.test.espresso:espresso-core:3.3.0") implementation("androidx.test.espresso:espresso-core:3.3.0")
@@ -51,17 +50,18 @@ kotlin {
} }
} }
linuxX64("linux") linuxX64()
iosX64()
ios() iosArm64()
iosSimulatorArm64()
} }
val includeAndroid = System.getProperty("includeAndroid")?.toBoolean() ?: true val includeAndroid = System.getProperty("includeAndroid")?.toBoolean() ?: true
if (includeAndroid) { if (includeAndroid) {
extensions.configure<com.android.build.gradle.LibraryExtension>("android") { extensions.configure<com.android.build.gradle.LibraryExtension>("android") {
defaultConfig { defaultConfig {
compileSdkVersion(30) compileSdk = 30
minSdkVersion(21) minSdk = 21
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }

View File

@@ -275,11 +275,6 @@ class Secp256k1Test {
val pub0 = Secp256k1.ecdsaRecover(sig, message, 0) val pub0 = Secp256k1.ecdsaRecover(sig, message, 0)
val pub1 = Secp256k1.ecdsaRecover(sig, message, 1) val pub1 = Secp256k1.ecdsaRecover(sig, message, 1)
assertTrue(pub.contentEquals(pub0) || pub.contentEquals(pub1)) 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 @Test
@@ -357,6 +352,38 @@ class Secp256k1Test {
} }
} }
@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 @Test
fun fuzzEcdsaSignVerify() { fun fuzzEcdsaSignVerify() {
val random = Random.Default val random = Random.Default