Compare commits
24 Commits
v0.7.0
...
snapshot/i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0364ec762e | ||
|
|
aadffabe42 | ||
|
|
8e17e7030a | ||
|
|
929e2cda40 | ||
|
|
41eac9273f | ||
|
|
161da89ee1 | ||
|
|
3706a546a2 | ||
|
|
ffcaaf1b64 | ||
|
|
6ef94df247 | ||
|
|
5169073a92 | ||
|
|
317e086cba | ||
|
|
7c7aabba80 | ||
|
|
b6823cbda6 | ||
|
|
d50d9060c2 | ||
|
|
6fedb1577c | ||
|
|
94bb2d67cf | ||
|
|
bf05a001fe | ||
|
|
d9e5fda600 | ||
|
|
8c984678be | ||
|
|
840de25c5f | ||
|
|
cec3fb385f | ||
|
|
d59def1c79 | ||
|
|
52d73951e6 | ||
|
|
08669500b6 |
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV
|
echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV
|
||||||
echo "ANDROID_NDK_VERSION=21.4.7075529" >> $GITHUB_ENV
|
echo "ANDROID_NDK_VERSION=25.2.9519653" >> $GITHUB_ENV
|
||||||
- name: Cached Android NDK
|
- name: Cached Android NDK
|
||||||
if: matrix.os != 'windows-latest'
|
if: matrix.os != 'windows-latest'
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
@@ -96,10 +96,9 @@ jobs:
|
|||||||
uses: reactivecircus/android-emulator-runner@v2
|
uses: reactivecircus/android-emulator-runner@v2
|
||||||
with:
|
with:
|
||||||
api-level: 27
|
api-level: 27
|
||||||
emulator-build: 7425822 # workaround to emulator bug: https://github.com/ReactiveCircus/android-emulator-runner/issues/160
|
|
||||||
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
||||||
ndk: ${{ env.ANDROID_NDK_VERSION }}
|
ndk: ${{ env.ANDROID_NDK_VERSION }}
|
||||||
cmake: 3.10.2.4988404
|
cmake: 3.22.1
|
||||||
script: ./gradlew connectedCheck
|
script: ./gradlew connectedCheck
|
||||||
- name: Publish Linux
|
- name: Publish Linux
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
|||||||
5
.github/workflows/snapshot.yml
vendored
5
.github/workflows/snapshot.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV
|
echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV
|
||||||
echo "ANDROID_NDK_VERSION=21.4.7075529" >> $GITHUB_ENV
|
echo "ANDROID_NDK_VERSION=25.2.9519653" >> $GITHUB_ENV
|
||||||
- name: Cached Android NDK
|
- name: Cached Android NDK
|
||||||
if: matrix.os != 'windows-latest'
|
if: matrix.os != 'windows-latest'
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
@@ -105,10 +105,9 @@ jobs:
|
|||||||
uses: reactivecircus/android-emulator-runner@v2
|
uses: reactivecircus/android-emulator-runner@v2
|
||||||
with:
|
with:
|
||||||
api-level: 27
|
api-level: 27
|
||||||
-build: 7425822 # workaround to emulator bug: https://github.com/ReactiveCircus/android-emulator-runner/issues/160
|
|
||||||
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
||||||
ndk: ${{ env.ANDROID_NDK_VERSION }}
|
ndk: ${{ env.ANDROID_NDK_VERSION }}
|
||||||
cmake: 3.10.2.4988404
|
cmake: 3.22.1
|
||||||
script: ./gradlew connectedCheck
|
script: ./gradlew connectedCheck
|
||||||
- name: Publish Linux
|
- name: Publish Linux
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
|||||||
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
@@ -48,7 +48,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV
|
echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV
|
||||||
echo "ANDROID_NDK_VERSION=21.4.7075529" >> $GITHUB_ENV
|
echo "ANDROID_NDK_VERSION=25.2.9519653" >> $GITHUB_ENV
|
||||||
- name: Cached Android NDK
|
- name: Cached Android NDK
|
||||||
if: matrix.os != 'windows-latest'
|
if: matrix.os != 'windows-latest'
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
@@ -111,8 +111,7 @@ jobs:
|
|||||||
uses: reactivecircus/android-emulator-runner@v2
|
uses: reactivecircus/android-emulator-runner@v2
|
||||||
with:
|
with:
|
||||||
api-level: 27
|
api-level: 27
|
||||||
emulator-build: 7425822 # workaround to emulator bug: https://github.com/ReactiveCircus/android-emulator-runner/issues/160
|
|
||||||
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
||||||
ndk: ${{ env.ANDROID_NDK_VERSION }}
|
ndk: ${{ env.ANDROID_NDK_VERSION }}
|
||||||
cmake: 3.10.2.4988404
|
cmake: 3.22.1
|
||||||
script: ./gradlew connectedCheck
|
script: ./gradlew connectedCheck
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -1,4 +1,4 @@
|
|||||||
[](http://kotlinlang.org)
|
[](http://kotlinlang.org)
|
||||||
[](https://search.maven.org/search?q=g:fr.acinq.secp256k1%20a:secp256k1-kmp*)
|
[](https://search.maven.org/search?q=g:fr.acinq.secp256k1%20a:secp256k1-kmp*)
|
||||||

|

|
||||||
[](https://github.com/ACINQ/secp256k1-kmp/blob/master/LICENSE)
|
[](https://github.com/ACINQ/secp256k1-kmp/blob/master/LICENSE)
|
||||||
@@ -30,19 +30,19 @@ kotlin {
|
|||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("stdlib-common"))
|
implementation(kotlin("stdlib-common"))
|
||||||
implementation(kotlin("fr.acinq.secp256k1:secp256k1-kmp:$secp256k1_version"))
|
implementation("fr.acinq.secp256k1:secp256k1-kmp:$secp256k1_version")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jvmMain by getting {
|
val jvmMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("stdlib"))
|
implementation(kotlin("stdlib"))
|
||||||
implementation(kotlin("fr.acinq.secp256k1:secp256k1-kmp-jni-jvm:$secp256k1_version"))
|
implementation("fr.acinq.secp256k1:secp256k1-kmp-jni-jvm:$secp256k1_version")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val androidMain by getting {
|
val androidMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("stdlib"))
|
implementation(kotlin("stdlib"))
|
||||||
implementation(kotlin("fr.acinq.secp256k1:secp256k1-kmp-jni-android:$secp256k1_version"))
|
implementation("fr.acinq.secp256k1:secp256k1-kmp-jni-android:$secp256k1_version")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,9 +58,9 @@ Native targets include libsecp256k1, called through KMP's c-interop, simply add
|
|||||||
The JVM library uses JNI bindings for libsecp256k1, which is much faster than BouncyCastle. It will extract and load native bindings for your operating system in a temporary directory.
|
The JVM library uses JNI bindings for libsecp256k1, which is much faster than BouncyCastle. It will extract and load native bindings for your operating system in a temporary directory.
|
||||||
|
|
||||||
JNI libraries are included for:
|
JNI libraries are included for:
|
||||||
- Linux 64 bits
|
- Linux 64 bits (x86_64 and arm64)
|
||||||
- Windows 64 bits
|
- Windows 64 bits (x86_64)
|
||||||
- Macos 64 bits
|
- Macos 64 bits (x86_64 and arm64)
|
||||||
|
|
||||||
Along this library, you **must** specify which JNI native library to use in your dependency manager:
|
Along this library, you **must** specify which JNI native library to use in your dependency manager:
|
||||||
|
|
||||||
@@ -138,4 +138,4 @@ To extend this library and support methods that have been added to specific vers
|
|||||||
|
|
||||||
You may also need to modify build files if you need to compile [secp256k1](https://github.com/bitcoin-core/secp256k1) with custom options
|
You may also need to modify build files if you need to compile [secp256k1](https://github.com/bitcoin-core/secp256k1) with custom options
|
||||||
|
|
||||||
We use [secp256k1](https://github.com/bitcoin-core/secp256k1) through git submodules so you may also need to change what they point to
|
We use [secp256k1](https://github.com/bitcoin-core/secp256k1) through git submodules so you may also need to change what they point to
|
||||||
|
|||||||
@@ -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.6.21"
|
kotlin("multiplatform") version "1.8.21"
|
||||||
id("org.jetbrains.dokka") version "1.6.21"
|
id("org.jetbrains.dokka") version "1.8.10"
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,14 +15,14 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("com.android.tools.build:gradle:4.2.2")
|
classpath("com.android.tools.build:gradle:7.3.1")
|
||||||
classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.6.21")
|
classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.8.10")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "fr.acinq.secp256k1"
|
group = "fr.acinq.secp256k1"
|
||||||
version = "0.7.0"
|
version = "0.12.0-SNAPSHOT"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
@@ -157,6 +157,7 @@ allprojects {
|
|||||||
Platform.js -> "js"
|
Platform.js -> "js"
|
||||||
Platform.native -> "native"
|
Platform.native -> "native"
|
||||||
Platform.common -> "common"
|
Platform.common -> "common"
|
||||||
|
Platform.wasm -> "wasm"
|
||||||
}
|
}
|
||||||
displayName.set(platformName)
|
displayName.set(platformName)
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,9 @@ dependencies {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
compileSdkVersion(30)
|
compileSdk = 33
|
||||||
minSdkVersion(21)
|
minSdk = 21
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
|
||||||
cmake {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
@@ -30,10 +27,12 @@ android {
|
|||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
|
version = "3.22.1"
|
||||||
path("src/main/CMakeLists.txt")
|
path("src/main/CMakeLists.txt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ndkVersion = "21.4.7075529"
|
|
||||||
|
ndkVersion = "25.2.9519653"
|
||||||
|
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
tasks.withType<com.android.build.gradle.tasks.factory.AndroidUnitTest>().all {
|
tasks.withType<com.android.build.gradle.tasks.factory.AndroidUnitTest>().all {
|
||||||
@@ -43,8 +42,8 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
configure(listOf("Debug", "Release").map { tasks["externalNativeBuild$it"] }) {
|
tasks.filter { it.name.startsWith("configureCMake") }.forEach {
|
||||||
dependsOn(":native:buildSecp256k1Android")
|
it.dependsOn(":native:buildSecp256k1Android")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.10.0)
|
cmake_minimum_required(VERSION 3.10.0)
|
||||||
|
|
||||||
|
project(secp256k1jni)
|
||||||
|
|
||||||
add_library( secp256k1-jni SHARED
|
add_library( secp256k1-jni SHARED
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../../c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c
|
${CMAKE_CURRENT_LIST_DIR}/../../../c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c
|
||||||
)
|
)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -12,8 +12,12 @@ dependencies {
|
|||||||
val copyJni by tasks.creating(Sync::class) {
|
val copyJni by tasks.creating(Sync::class) {
|
||||||
onlyIf { org.gradle.internal.os.OperatingSystem.current().isMacOsX }
|
onlyIf { org.gradle.internal.os.OperatingSystem.current().isMacOsX }
|
||||||
dependsOn(":jni:jvm:buildNativeHost")
|
dependsOn(":jni:jvm:buildNativeHost")
|
||||||
|
val arch = when (System.getProperty("os.arch")) {
|
||||||
|
"aarch64" -> "aarch64"
|
||||||
|
else -> "x86_64"
|
||||||
|
}
|
||||||
from(rootDir.resolve("jni/jvm/build/darwin/libsecp256k1-jni.dylib"))
|
from(rootDir.resolve("jni/jvm/build/darwin/libsecp256k1-jni.dylib"))
|
||||||
into(buildDir.resolve("jniResources/fr/acinq/secp256k1/jni/native/darwin-x86_64"))
|
into(buildDir.resolve("jniResources/fr/acinq/secp256k1/jni/native/darwin-$arch"))
|
||||||
}
|
}
|
||||||
|
|
||||||
(tasks["processResources"] as ProcessResources).apply {
|
(tasks["processResources"] as ProcessResources).apply {
|
||||||
|
|||||||
@@ -19,18 +19,16 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
TARGET=$SYS-linux-android
|
TARGET=$SYS-linux-android
|
||||||
TOOLTARGET=$TARGET
|
|
||||||
if [ "$SYS" == "armv7a" ]; then
|
if [ "$SYS" == "armv7a" ]; then
|
||||||
TARGET=armv7a-linux-androideabi
|
TARGET=armv7a-linux-androideabi
|
||||||
TOOLTARGET=arm-linux-androideabi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export CC=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/${TARGET}21-clang
|
export CC=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/${TARGET}21-clang
|
||||||
export LD=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/$TOOLTARGET-ld
|
export LD=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/ld
|
||||||
export AR=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/$TOOLTARGET-ar
|
export AR=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/llvm-ar
|
||||||
export AS=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/$TOOLTARGET-as
|
export AS=$CC
|
||||||
export RANLIB=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/$TOOLTARGET-ranlib
|
export RANLIB=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/llvm-ranlib
|
||||||
export STRIP=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/$TOOLTARGET-strip
|
export STRIP=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/llvm-strip
|
||||||
|
|
||||||
cd secp256k1
|
cd secp256k1
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ if [ "$TARGET" == "mingw" ]; then
|
|||||||
elif [ "$TARGET" == "linux" ]; then
|
elif [ "$TARGET" == "linux" ]; then
|
||||||
CONF_OPTS="CFLAGS=-fPIC"
|
CONF_OPTS="CFLAGS=-fPIC"
|
||||||
elif [ "$TARGET" == "darwin" ]; then
|
elif [ "$TARGET" == "darwin" ]; then
|
||||||
CONF_OPTS="--host=x86_64-w64-darwin"
|
CONF_OPTS=""
|
||||||
else
|
else
|
||||||
echo "Unknown TARGET=$TARGET"
|
echo "Unknown TARGET=$TARGET"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
Submodule native/secp256k1 updated: 44c2452fd3...199d27cea3
@@ -27,7 +27,9 @@ You must edit `secp256k1-kmp-staging-upload.sh` and add your sonatype credential
|
|||||||
## Adding custom JNI bindings
|
## Adding custom JNI bindings
|
||||||
|
|
||||||
Github CI currently generates JNI bindings for Windows x64, Linux x64 and iOS x64. But it is possible to add custom bindings to JNI packages before
|
Github CI currently generates JNI bindings for Windows x64, Linux x64 and iOS x64. But it is possible to add custom bindings to JNI packages before
|
||||||
they are published to maven central. This is how we add linux arm64 bindings:
|
they are published to maven central.
|
||||||
|
|
||||||
|
This is how we add linux arm64 bindings:
|
||||||
- compile JNI bindings for Linux Arm64 (on a Linux Arm64 machine, cross-compilation is not supported)
|
- compile JNI bindings for Linux Arm64 (on a Linux Arm64 machine, cross-compilation is not supported)
|
||||||
- git clone --recursive https://github.com/ACINQ/secp256k1-kmp.git
|
- git clone --recursive https://github.com/ACINQ/secp256k1-kmp.git
|
||||||
- cd secp256k1-kmp
|
- cd secp256k1-kmp
|
||||||
@@ -37,6 +39,19 @@ they are published to maven central. This is how we add linux arm64 bindings:
|
|||||||
- JNI library is: jni/jvm/build/linux/libsecp256k1-jni.so
|
- JNI library is: jni/jvm/build/linux/libsecp256k1-jni.so
|
||||||
- copy libsecp256k1-jni.so to fr/acinq/secp256k1/jni/native/linux-aarch64/libsecp256k1-jni.so
|
- copy libsecp256k1-jni.so to fr/acinq/secp256k1/jni/native/linux-aarch64/libsecp256k1-jni.so
|
||||||
- run `secp256k1-kmp-add-linuxarm64.sh` and specify either `release` or `snapshot` and the `VERSION` environment variable, for example:
|
- run `secp256k1-kmp-add-linuxarm64.sh` and specify either `release` or `snapshot` and the `VERSION` environment variable, for example:
|
||||||
- VERSION=0.6.4-SNAPSHOT ./secp256k1-kmp-add-linuxarm64.sh snapshot
|
- VERSION=0.9.0-SNAPSHOT ./secp256k1-kmp-add-linuxarm64.sh snapshot
|
||||||
- VERSION=0.6.3 ./secp256k1-kmp-add-linuxarm64.sh release
|
- VERSION=0.9.0 ./secp256k1-kmp-add-linuxarm64.sh release
|
||||||
|
|
||||||
|
This is how we add macos arm64 (M1/M2) bindings:
|
||||||
|
- compile JNI bindings for macos Arm64 (on a macos Arm64 machine, cross-compilation is not supported)
|
||||||
|
- git clone --recursive https://github.com/ACINQ/secp256k1-kmp.git
|
||||||
|
- cd secp256k1-kmp
|
||||||
|
- TARGET=darwin ./native/build.sh
|
||||||
|
- mkdir -p jni/jvm/build/darwin
|
||||||
|
- TARGET=darwin ./jni/jvm/build.sh
|
||||||
|
- JNI library is: jni/jvm/build/darwin/libsecp256k1-jni.dylib
|
||||||
|
- copy libsecp256k1-jni.dylib to fr/acinq/secp256k1/jni/native/darwin-aarch64/libsecp256k1-jni.dylib
|
||||||
|
- run `secp256k1-kmp-add-darwinaarch64.sh` and specify either `release` or `snapshot` and the `VERSION` environment variable, for example:
|
||||||
|
- VERSION=0.9.0-SNAPSHOT ./secp256k1-kmp-add-darwinaarch64.sh snapshot
|
||||||
|
- VERSION=0.9.0 ./secp256k1-kmp-add-darwinaarch64.sh release
|
||||||
|
|
||||||
|
|||||||
17
publishing/secp256k1-kmp-add-darwinaarch64.sh
Executable file
17
publishing/secp256k1-kmp-add-darwinaarch64.sh
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash -x
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]
|
||||||
|
then
|
||||||
|
echo "specify either snapshot or release"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# add aarch64 (ARM64) library to the darwin jar
|
||||||
|
if [ -e fr/acinq/secp256k1/jni/native/darwin-aarch64/libsecp256k1-jni.dylib ]
|
||||||
|
then
|
||||||
|
jar -uf $1/fr/acinq/secp256k1/secp256k1-kmp-jni-jvm-darwin/$VERSION/secp256k1-kmp-jni-jvm-darwin-$VERSION.jar fr || exit
|
||||||
|
else
|
||||||
|
libsecp256k1-jni.dylib for arch64 is missing
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
@@ -2,52 +2,64 @@
|
|||||||
|
|
||||||
GROUP_ID=fr.acinq.secp256k1
|
GROUP_ID=fr.acinq.secp256k1
|
||||||
ARTIFACT_ID_BASE=secp256k1-kmp
|
ARTIFACT_ID_BASE=secp256k1-kmp
|
||||||
VERSION=0.6.3-SNAPSHOT
|
|
||||||
|
if [[ -z "${VERSION}" ]]; then
|
||||||
|
echo "VERSION is not defined"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
cd snapshot
|
cd snapshot
|
||||||
pushd .
|
pushd .
|
||||||
cd fr/acinq/secp256k1/secp256k1-kmp/$VERSION
|
cd fr/acinq/secp256k1/secp256k1-kmp/$VERSION
|
||||||
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-$VERSION.pom \
|
-DpomFile=$ARTIFACT_ID_BASE-$VERSION.pom \
|
||||||
-Dfile=$ARTIFACT_ID_BASE-$VERSION.jar \
|
-Dfile=$ARTIFACT_ID_BASE-$VERSION.jar \
|
||||||
-Dfiles=$ARTIFACT_ID_BASE-$VERSION.module,$ARTIFACT_ID_BASE-$VERSION-kotlin-tooling-metadata.json \
|
-Dfiles=$ARTIFACT_ID_BASE-$VERSION.module,$ARTIFACT_ID_BASE-$VERSION-kotlin-tooling-metadata.json \
|
||||||
-Dtypes=module,json \
|
-Dtypes=module,json \
|
||||||
-Dclassifiers=,kotlin-tooling-metadata \
|
-Dclassifiers=,kotlin-tooling-metadata \
|
||||||
-Dsources=$ARTIFACT_ID_BASE-$VERSION-sources.jar \
|
-Dsources=$ARTIFACT_ID_BASE-$VERSION-sources.jar \
|
||||||
-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
|
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
|
||||||
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 == iosx64 ] || [ $i == linux ]; 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 \
|
-Dfiles=$ARTIFACT_ID_BASE-$i-$VERSION-metadata.jar,$ARTIFACT_ID_BASE-$i-$VERSION.module,$ARTIFACT_ID_BASE-$i-$VERSION-cinterop-libsecp256k1.klib \
|
||||||
-Dfiles=$ARTIFACT_ID_BASE-$i-$VERSION.module,$ARTIFACT_ID_BASE-$i-$VERSION-cinterop-libsecp256k1.klib \
|
-Dtypes=jar,module,klib \
|
||||||
-Dtypes=module,klib \
|
-Dclassifiers=metadata,,cinterop-libsecp256k1 \
|
||||||
-Dclassifiers=,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 == jni-android ]; 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.aar \
|
-Dfiles=$ARTIFACT_ID_BASE-$i-$VERSION.module,$ARTIFACT_ID_BASE-$i-$VERSION-cinterop-libsecp256k1.klib \
|
||||||
-Dfiles=$ARTIFACT_ID_BASE-$i-$VERSION.module \
|
-Dtypes=module,klib \
|
||||||
-Dtypes=module \
|
-Dclassifiers=,cinterop-libsecp256k1 \
|
||||||
-Dclassifiers= \
|
-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 == jni-android ]; then
|
||||||
else
|
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.aar \
|
||||||
-Dfile=$ARTIFACT_ID_BASE-$i-$VERSION.jar \
|
-Dfiles=$ARTIFACT_ID_BASE-$i-$VERSION.module \
|
||||||
-Dfiles=$ARTIFACT_ID_BASE-$i-$VERSION.module \
|
-Dtypes=module \
|
||||||
-Dtypes=module \
|
-Dclassifiers= \
|
||||||
-Dclassifiers= \
|
-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
|
else
|
||||||
fi
|
mvn deploy:deploy-file -DrepositoryId=ossrh -Durl=https://oss.sonatype.org/content/repositories/snapshots/ \
|
||||||
popd
|
-DpomFile=$ARTIFACT_ID_BASE-$i-$VERSION.pom \
|
||||||
pushd .
|
-Dfile=$ARTIFACT_ID_BASE-$i-$VERSION.jar \
|
||||||
|
-Dfiles=$ARTIFACT_ID_BASE-$i-$VERSION.module \
|
||||||
|
-Dtypes=module \
|
||||||
|
-Dclassifiers= \
|
||||||
|
-Dsources=$ARTIFACT_ID_BASE-$i-$VERSION-sources.jar \
|
||||||
|
-Djavadoc=$ARTIFACT_ID_BASE-$i-$VERSION-javadoc.jar
|
||||||
|
fi
|
||||||
|
popd
|
||||||
|
pushd .
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -3,6 +3,13 @@ pluginManagement {
|
|||||||
google()
|
google()
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
}
|
}
|
||||||
|
resolutionStrategy {
|
||||||
|
eachPlugin {
|
||||||
|
if (requested.id.namespace == "com.android" || requested.id.name == "kotlin-android-extensions") {
|
||||||
|
useModule("com.android.tools.build:gradle:7.3.1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rootProject.name = "secp256k1-kmp"
|
rootProject.name = "secp256k1-kmp"
|
||||||
|
|
||||||
|
|||||||
@@ -166,7 +166,17 @@ public interface Secp256k1 {
|
|||||||
|
|
||||||
internal expect fun getSecpk256k1(): Secp256k1
|
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() : super()
|
||||||
public constructor(message: String?) : super(message)
|
public constructor(message: String?) : super(message)
|
||||||
}
|
}
|
||||||
@@ -4,15 +4,67 @@ import kotlinx.cinterop.*
|
|||||||
import platform.posix.size_tVar
|
import platform.posix.size_tVar
|
||||||
import secp256k1.*
|
import secp256k1.*
|
||||||
|
|
||||||
@OptIn(ExperimentalUnsignedTypes::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 {
|
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 = 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 {
|
private fun MemScope.allocSignature(input: ByteArray): secp256k1_ecdsa_signature {
|
||||||
val sig = alloc<secp256k1_ecdsa_signature>()
|
val sig = alloc<secp256k1_ecdsa_signature>()
|
||||||
@@ -58,167 +110,209 @@ 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)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nPubkey = allocPublicKey(pubkey)
|
memScoped {
|
||||||
val nMessage = toNat(message)
|
val nPubkey = allocPublicKey(pubkey)
|
||||||
val nSig = allocSignature(signature)
|
val nMessage = toNat(message)
|
||||||
return secp256k1_ecdsa_verify(ctx, nSig.ptr, nMessage, nPubkey.ptr) == 1
|
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 {
|
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)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nPrivkey = toNat(privkey)
|
memScoped {
|
||||||
val nMessage = toNat(message)
|
val nPrivkey = toNat(privkey)
|
||||||
val nSig = alloc<secp256k1_ecdsa_signature>()
|
val nMessage = toNat(message)
|
||||||
secp256k1_ecdsa_sign(ctx, nSig.ptr, nMessage, nPrivkey, null, null).requireSuccess("secp256k1_ecdsa_sign() failed")
|
val nSig = alloc<secp256k1_ecdsa_signature>()
|
||||||
return serializeSignature(nSig)
|
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> {
|
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)}" }
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nSig = allocSignature(sig)
|
memScoped {
|
||||||
val isHighS = secp256k1_ecdsa_signature_normalize(ctx, nSig.ptr, nSig.ptr)
|
val nSig = allocSignature(sig)
|
||||||
return Pair(serializeSignature(nSig), isHighS == 1)
|
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 {
|
public override fun secKeyVerify(privkey: ByteArray): Boolean {
|
||||||
if (privkey.size != 32) return false
|
if (privkey.size != 32) return false
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nPrivkey = toNat(privkey)
|
memScoped {
|
||||||
return secp256k1_ec_seckey_verify(ctx, nPrivkey) == 1
|
val nPrivkey = toNat(privkey)
|
||||||
|
val result = 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)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nPrivkey = toNat(privkey)
|
memScoped {
|
||||||
val nPubkey = alloc<secp256k1_pubkey>()
|
val nPrivkey = toNat(privkey)
|
||||||
secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nPrivkey).requireSuccess("secp256k1_ec_pubkey_create() failed")
|
val nPubkey = alloc<secp256k1_pubkey>()
|
||||||
return serializePubkey(nPubkey)
|
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 {
|
public override fun pubkeyParse(pubkey: ByteArray): ByteArray {
|
||||||
require(pubkey.size == 33 || pubkey.size == 65)
|
require(pubkey.size == 33 || pubkey.size == 65)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nPubkey = allocPublicKey(pubkey)
|
memScoped {
|
||||||
return serializePubkey(nPubkey)
|
val nPubkey = allocPublicKey(pubkey)
|
||||||
|
val result = 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)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val negated = privkey.copyOf()
|
memScoped {
|
||||||
val negPriv = toNat(negated)
|
val negated = privkey.copyOf()
|
||||||
secp256k1_ec_seckey_negate(ctx, negPriv).requireSuccess("secp256k1_ec_seckey_negate() failed")
|
val negPriv = toNat(negated)
|
||||||
return 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 {
|
public override fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||||
require(privkey.size == 32)
|
require(privkey.size == 32)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val added = privkey.copyOf()
|
memScoped {
|
||||||
val natAdd = toNat(added)
|
val added = privkey.copyOf()
|
||||||
val natTweak = toNat(tweak)
|
val natAdd = toNat(added)
|
||||||
secp256k1_ec_seckey_tweak_add(ctx, natAdd, natTweak).requireSuccess("secp256k1_ec_seckey_tweak_add() failed")
|
val natTweak = toNat(tweak)
|
||||||
return added
|
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 {
|
public override fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||||
require(privkey.size == 32)
|
require(privkey.size == 32)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val multiplied = privkey.copyOf()
|
memScoped {
|
||||||
val natMul = toNat(multiplied)
|
val multiplied = privkey.copyOf()
|
||||||
val natTweak = toNat(tweak)
|
val natMul = toNat(multiplied)
|
||||||
secp256k1_ec_privkey_tweak_mul(ctx, natMul, natTweak).requireSuccess("secp256k1_ec_privkey_tweak_mul() failed")
|
val natTweak = toNat(tweak)
|
||||||
return multiplied
|
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 {
|
public override fun pubKeyNegate(pubkey: ByteArray): ByteArray {
|
||||||
require(pubkey.size == 33 || pubkey.size == 65)
|
require(pubkey.size == 33 || pubkey.size == 65)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nPubkey = allocPublicKey(pubkey)
|
memScoped {
|
||||||
secp256k1_ec_pubkey_negate(ctx, nPubkey.ptr).requireSuccess("secp256k1_ec_pubkey_negate() failed")
|
val nPubkey = allocPublicKey(pubkey)
|
||||||
return serializePubkey(nPubkey)
|
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 {
|
public override fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||||
require(pubkey.size == 33 || pubkey.size == 65)
|
require(pubkey.size == 33 || pubkey.size == 65)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nPubkey = allocPublicKey(pubkey)
|
memScoped {
|
||||||
val nTweak = toNat(tweak)
|
val nPubkey = allocPublicKey(pubkey)
|
||||||
secp256k1_ec_pubkey_tweak_add(ctx, nPubkey.ptr, nTweak).requireSuccess("secp256k1_ec_pubkey_tweak_add() failed")
|
val nTweak = toNat(tweak)
|
||||||
return serializePubkey(nPubkey)
|
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 {
|
public override fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||||
require(pubkey.size == 33 || pubkey.size == 65)
|
require(pubkey.size == 33 || pubkey.size == 65)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nPubkey = allocPublicKey(pubkey)
|
memScoped {
|
||||||
val nTweak = toNat(tweak)
|
val nPubkey = allocPublicKey(pubkey)
|
||||||
secp256k1_ec_pubkey_tweak_mul(ctx, nPubkey.ptr, nTweak).requireSuccess("secp256k1_ec_pubkey_tweak_mul() failed")
|
val nTweak = toNat(tweak)
|
||||||
return serializePubkey(nPubkey)
|
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 {
|
public override fun pubKeyCombine(pubkeys: Array<ByteArray>): ByteArray {
|
||||||
pubkeys.forEach { require(it.size == 33 || it.size == 65) }
|
pubkeys.forEach { require(it.size == 33 || it.size == 65) }
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nPubkeys = pubkeys.map { allocPublicKey(it).ptr }
|
memScoped {
|
||||||
val combined = alloc<secp256k1_pubkey>()
|
val nPubkeys = pubkeys.map { allocPublicKey(it).ptr }
|
||||||
secp256k1_ec_pubkey_combine(ctx, combined.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess("secp256k1_ec_pubkey_combine() failed")
|
val combined = alloc<secp256k1_pubkey>()
|
||||||
return serializePubkey(combined)
|
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 {
|
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)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nPubkey = allocPublicKey(pubkey)
|
memScoped {
|
||||||
val nPrivkey = toNat(privkey)
|
val nPubkey = allocPublicKey(pubkey)
|
||||||
val output = allocArray<UByteVar>(32)
|
val nPrivkey = toNat(privkey)
|
||||||
secp256k1_ecdh(ctx, output, nPubkey.ptr, nPrivkey, null, null).requireSuccess("secp256k1_ecdh() failed")
|
val output = allocArray<UByteVar>(32)
|
||||||
return output.readBytes(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 {
|
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)
|
||||||
memScoped {
|
// we do not check that recid is valid, which should trigger our illegal callback handler to throw a Secp256k1IllegalCallbackException
|
||||||
val nSig = toNat(sig)
|
// require(recid in 0..3)
|
||||||
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")
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nMessage = toNat(message)
|
memScoped {
|
||||||
val pubkey = alloc<secp256k1_pubkey>()
|
val nSig = toNat(sig)
|
||||||
secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess("secp256k1_ecdsa_recover() failed")
|
val rSig = alloc<secp256k1_ecdsa_recoverable_signature>()
|
||||||
return serializePubkey(pubkey)
|
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 {
|
public override fun compact2der(sig: ByteArray): ByteArray {
|
||||||
require(sig.size == 64)
|
require(sig.size == 64)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nSig = allocSignature(sig)
|
memScoped {
|
||||||
val natOutput = allocArray<UByteVar>(73)
|
val nSig = allocSignature(sig)
|
||||||
val len = alloc<size_tVar>()
|
val natOutput = allocArray<UByteVar>(73)
|
||||||
len.value = 73.convert()
|
val len = alloc<size_tVar>()
|
||||||
secp256k1_ecdsa_signature_serialize_der(ctx, natOutput, len.ptr, nSig.ptr).requireSuccess("secp256k1_ecdsa_signature_serialize_der() failed")
|
len.value = 73.convert()
|
||||||
return natOutput.readBytes(len.value.toInt())
|
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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,13 +320,15 @@ public object Secp256k1Native : Secp256k1 {
|
|||||||
require(signature.size == 64)
|
require(signature.size == 64)
|
||||||
require(data.size == 32)
|
require(data.size == 32)
|
||||||
require(pub.size == 32)
|
require(pub.size == 32)
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nPub = toNat(pub)
|
memScoped {
|
||||||
val pubkey = alloc<secp256k1_xonly_pubkey>()
|
val nPub = toNat(pub)
|
||||||
secp256k1_xonly_pubkey_parse(ctx, pubkey.ptr, nPub).requireSuccess("secp256k1_xonly_pubkey_parse() failed")
|
val pubkey = alloc<secp256k1_xonly_pubkey>()
|
||||||
val nData = toNat(data)
|
secp256k1_xonly_pubkey_parse(ctx, pubkey.ptr, nPub).requireSuccess(callbackHandler, "secp256k1_xonly_pubkey_parse() failed")
|
||||||
val nSig = toNat(signature)
|
val nData = toNat(data)
|
||||||
return secp256k1_schnorrsig_verify(ctx, nSig, nData, 32, pubkey.ptr) == 1
|
val nSig = toNat(signature)
|
||||||
|
return secp256k1_schnorrsig_verify(ctx, nSig, nData, 32u, pubkey.ptr) == 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,15 +336,17 @@ public object Secp256k1Native : Secp256k1 {
|
|||||||
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) }
|
||||||
memScoped {
|
CallbackHandler(ctx).use { callbackHandler ->
|
||||||
val nSec = toNat(sec)
|
memScoped {
|
||||||
val nData = toNat(data)
|
val nSec = toNat(sec)
|
||||||
val nAuxrand32 = auxrand32?.let { toNat(it) }
|
val nData = toNat(data)
|
||||||
val nSig = allocArray<UByteVar>(64)
|
val nAuxrand32 = auxrand32?.let { toNat(it) }
|
||||||
val keypair = alloc<secp256k1_keypair>()
|
val nSig = allocArray<UByteVar>(64)
|
||||||
secp256k1_keypair_create(ctx, keypair.ptr, nSec).requireSuccess("secp256k1_keypair_create() failed")
|
val keypair = alloc<secp256k1_keypair>()
|
||||||
secp256k1_schnorrsig_sign32(ctx, nSig, nData, keypair.ptr, nAuxrand32).requireSuccess("secp256k1_ecdsa_sign() failed")
|
secp256k1_keypair_create(ctx, keypair.ptr, nSec).requireSuccess(callbackHandler, "secp256k1_keypair_create() failed")
|
||||||
return nSig.readBytes(64)
|
secp256k1_schnorrsig_sign32(ctx, nSig, nData, keypair.ptr, nAuxrand32).requireSuccess(callbackHandler, "secp256k1_ecdsa_sign() failed")
|
||||||
|
return nSig.readBytes(64)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package fr.acinq.secp256k1
|
|
||||||
|
|
||||||
import org.junit.Test
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
|
|
||||||
|
|
||||||
class AndroidTest {}
|
|
||||||
@@ -275,6 +275,11 @@ 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
|
||||||
|
|||||||
Reference in New Issue
Block a user