Android implementation
This commit is contained in:
parent
08b6d16836
commit
ff37b86ff3
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@ build/
|
|||||||
.gradle
|
.gradle
|
||||||
local.properties
|
local.properties
|
||||||
.gradletasknamecache
|
.gradletasknamecache
|
||||||
|
.cxx
|
||||||
|
|
||||||
# OS
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
plugins {
|
plugins {
|
||||||
kotlin("multiplatform") version "1.4-M2-mt"
|
kotlin("multiplatform") version "1.4-M2-mt"
|
||||||
|
id("com.android.library") version "4.0.0"
|
||||||
}
|
}
|
||||||
group = "fr.acinq.phoenix"
|
group = "fr.acinq.phoenix"
|
||||||
version = "1.0-1.4-M2"
|
version = "1.0-1.4-M2"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
google()
|
||||||
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
}
|
}
|
||||||
@ -27,6 +29,13 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val jvmAndAndroidMain by sourceSets.creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-jdk8"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
jvm {
|
jvm {
|
||||||
compilations.all {
|
compilations.all {
|
||||||
kotlinOptions.jvmTarget = "1.8"
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
@ -35,14 +44,24 @@ kotlin {
|
|||||||
dependsOn("copyJni")
|
dependsOn("copyJni")
|
||||||
from(buildDir.resolve("jniResources"))
|
from(buildDir.resolve("jniResources"))
|
||||||
}
|
}
|
||||||
compilations["main"].dependencies {
|
compilations["main"].defaultSourceSet.dependsOn(jvmAndAndroidMain)
|
||||||
implementation(kotlin("stdlib-jdk8"))
|
|
||||||
}
|
|
||||||
compilations["test"].dependencies {
|
compilations["test"].dependencies {
|
||||||
implementation(kotlin("test-junit"))
|
implementation(kotlin("test-junit"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
compilations.all {
|
||||||
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
sourceSets["androidMain"].dependsOn(jvmAndAndroidMain)
|
||||||
|
sourceSets["androidTest"].dependencies {
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
implementation("androidx.test.ext:junit:1.1.1")
|
||||||
|
implementation("androidx.test.espresso:espresso-core:3.2.0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget.secp256k1CInterop() {
|
fun org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget.secp256k1CInterop() {
|
||||||
compilations["main"].cinterops {
|
compilations["main"].cinterops {
|
||||||
val libsecp256k1 by creating {
|
val libsecp256k1 by creating {
|
||||||
@ -75,6 +94,26 @@ kotlin {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
defaultConfig {
|
||||||
|
compileSdkVersion(30)
|
||||||
|
minSdkVersion(21)
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
setPath("src/androidMain/CMakeLists.txt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ndkVersion = "21.3.6528147"
|
||||||
|
|
||||||
|
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||||
|
}
|
||||||
|
|
||||||
val buildSecp256k1 by tasks.creating { group = "build" }
|
val buildSecp256k1 by tasks.creating { group = "build" }
|
||||||
fun creatingBuildSecp256k1(target: String, cross: String? = null, env: String = "", configuration: Task.() -> Unit = {}) = tasks.creating(Exec::class) {
|
fun creatingBuildSecp256k1(target: String, cross: String? = null, env: String = "", configuration: Task.() -> Unit = {}) = tasks.creating(Exec::class) {
|
||||||
group = "build"
|
group = "build"
|
||||||
@ -95,6 +134,14 @@ val buildSecp256k1Darwin by creatingBuildSecp256k1("darwin")
|
|||||||
val buildSecp256k1Linux by creatingBuildSecp256k1("linux", cross = if (currentOs.isMacOsX) "linux-x64" else null)
|
val buildSecp256k1Linux by creatingBuildSecp256k1("linux", cross = if (currentOs.isMacOsX) "linux-x64" else null)
|
||||||
val buildSecp256k1Mingw by creatingBuildSecp256k1("mingw", cross = "windows-x64", env = "CONF_OPTS=--host=x86_64-w64-mingw32")
|
val buildSecp256k1Mingw by creatingBuildSecp256k1("mingw", cross = "windows-x64", env = "CONF_OPTS=--host=x86_64-w64-mingw32")
|
||||||
|
|
||||||
|
val copyJni by tasks.creating(Sync::class) {
|
||||||
|
dependsOn(buildSecp256k1)
|
||||||
|
from(projectDir.resolve("native/build/linux/libsecp256k1-jni.so")) { rename { "libsecp256k1-jni-linux-x86_64.so" } }
|
||||||
|
from(projectDir.resolve("native/build/darwin/libsecp256k1-jni.dylib")) { rename { "libsecp256k1-jni-darwin-x86_64.dylib" } }
|
||||||
|
from(projectDir.resolve("native/build/mingw/secp256k1-jni.dll")) { rename { "secp256k1-jni-mingw-x86_64.dll" } }
|
||||||
|
into(buildDir.resolve("jniResources/fr/acinq/secp256k1/native"))
|
||||||
|
}
|
||||||
|
|
||||||
val buildSecp256k1Ios by tasks.creating(Exec::class) {
|
val buildSecp256k1Ios by tasks.creating(Exec::class) {
|
||||||
group = "build"
|
group = "build"
|
||||||
buildSecp256k1.dependsOn(this)
|
buildSecp256k1.dependsOn(this)
|
||||||
@ -106,10 +153,42 @@ val buildSecp256k1Ios by tasks.creating(Exec::class) {
|
|||||||
commandLine("./build-ios.sh")
|
commandLine("./build-ios.sh")
|
||||||
}
|
}
|
||||||
|
|
||||||
val copyJni by tasks.creating(Sync::class) {
|
val buildSecp256k1Android by tasks.creating { group = "build" }
|
||||||
dependsOn(buildSecp256k1)
|
fun creatingBuildSecp256k1Android(arch: String) = tasks.creating(Exec::class) {
|
||||||
from(projectDir.resolve("native/build/linux/libsecp256k1-jni.so")) { rename { "libsecp256k1-jni-linux-x86_64.so" } }
|
group = "build"
|
||||||
from(projectDir.resolve("native/build/darwin/libsecp256k1-jni.dylib")) { rename { "libsecp256k1-jni-darwin-x86_64.dylib" } }
|
buildSecp256k1Android.dependsOn(this)
|
||||||
from(projectDir.resolve("native/build/mingw/secp256k1-jni.dll")) { rename { "secp256k1-jni-mingw-x86_64.dll" } }
|
|
||||||
into(buildDir.resolve("jniResources/fr/acinq/secp256k1/native"))
|
inputs.files(projectDir.resolve("native/build-android.sh"))
|
||||||
|
outputs.dir(projectDir.resolve("native/build/android/$arch"))
|
||||||
|
|
||||||
|
workingDir = projectDir.resolve("native")
|
||||||
|
|
||||||
|
val toolchain = when {
|
||||||
|
currentOs.isMacOsX -> "darwin-x86_64"
|
||||||
|
else -> error("Cannot build for Android on this OS")
|
||||||
|
}
|
||||||
|
environment("TOOLCHAIN", toolchain)
|
||||||
|
environment("ARCH", arch)
|
||||||
|
environment("ANDROID_NDK", android.ndkDirectory)
|
||||||
|
commandLine("./build-android.sh")
|
||||||
|
}
|
||||||
|
val buildSecp256k1AndroidX86_64 by creatingBuildSecp256k1Android("x86_64")
|
||||||
|
val buildSecp256k1AndroidX86 by creatingBuildSecp256k1Android("x86")
|
||||||
|
val buildSecp256k1AndroidArm64v8a by creatingBuildSecp256k1Android("arm64-v8a")
|
||||||
|
val buildSecp256k1AndroidArmeabiv7a by creatingBuildSecp256k1Android("armeabi-v7a")
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
configure(listOf("Debug", "Release").map { tasks["externalNativeBuild$it"] }) {
|
||||||
|
dependsOn(buildSecp256k1Android)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks["clean"].doLast {
|
||||||
|
delete(projectDir.resolve("native/build"))
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
tasks.withType<com.android.build.gradle.tasks.factory.AndroidUnitTest>().all {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,13 +1,16 @@
|
|||||||
# gradle
|
# gradle
|
||||||
org.gradle.jvmargs=-Xmx1536m
|
org.gradle.jvmargs = -Xmx1536m
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel = true
|
||||||
|
|
||||||
# kotlin
|
# kotlin
|
||||||
kotlin.code.style=official
|
kotlin.code.style = official
|
||||||
kotlin.incremental.multiplatform = true
|
kotlin.incremental.multiplatform = true
|
||||||
kotlin.parallel.tasks.in.project=true
|
kotlin.parallel.tasks.in.project = true
|
||||||
#kotlin.mpp.enableGranularSourceSetsMetadata=true
|
#kotlin.mpp.enableGranularSourceSetsMetadata = true
|
||||||
kotlin.native.enableDependencyPropagation=false
|
kotlin.native.enableDependencyPropagation = false
|
||||||
|
|
||||||
# https://github.com/gradle/gradle/issues/11412
|
# https://github.com/gradle/gradle/issues/11412
|
||||||
systemProp.org.gradle.internal.publish.checksums.insecure=true
|
systemProp.org.gradle.internal.publish.checksums.insecure = true
|
||||||
|
|
||||||
|
# Android
|
||||||
|
android.useAndroidX = true
|
48
native/build-android.sh
Executable file
48
native/build-android.sh
Executable file
@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
ANDROID_NDK=/Users/salomonbrys/Library/Android/sdk/ndk/21.3.6528147
|
||||||
|
TOOLCHAIN=darwin-x86_64
|
||||||
|
|
||||||
|
[[ -z "$ANDROID_NDK" ]] && echo "Please set the ANDROID_NDK variable" && exit 1
|
||||||
|
[[ -z "$ARCH" ]] && echo "Please set the ARCH variable" && exit 1
|
||||||
|
[[ -z "$TOOLCHAIN" ]] && echo "Please set the TOOLCHAIN variable" && exit 1
|
||||||
|
|
||||||
|
if [ "$ARCH" == "x86_64" ]; then
|
||||||
|
SYS=x86_64
|
||||||
|
elif [ "$ARCH" == "x86" ]; then
|
||||||
|
SYS=i686
|
||||||
|
elif [ "$ARCH" == "arm64-v8a" ]; then
|
||||||
|
SYS=aarch64
|
||||||
|
elif [ "$ARCH" == "armeabi-v7a" ]; then
|
||||||
|
SYS=armv7a
|
||||||
|
else
|
||||||
|
echo "Unsupported ARCH: $ARCH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET=$SYS-linux-android
|
||||||
|
TOOLTARGET=$TARGET
|
||||||
|
if [ "$SYS" == "armv7a" ]; then
|
||||||
|
TARGET=armv7a-linux-androideabi
|
||||||
|
TOOLTARGET=arm-linux-androideabi
|
||||||
|
fi
|
||||||
|
|
||||||
|
export CC=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/${TARGET}21-clang
|
||||||
|
export LD=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/$TOOLTARGET-ld
|
||||||
|
export AR=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/$TOOLTARGET-ar
|
||||||
|
export AS=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/$TOOLTARGET-as
|
||||||
|
export RANLIB=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/$TOOLTARGET-ranlib
|
||||||
|
export STRIP=$ANDROID_NDK/toolchains/llvm/prebuilt/$TOOLCHAIN/bin/$TOOLTARGET-strip
|
||||||
|
|
||||||
|
cd secp256k1
|
||||||
|
|
||||||
|
./autogen.sh
|
||||||
|
./configure CFLAGS=-fpic --host=$TARGET --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
|
||||||
|
make clean
|
||||||
|
make
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
mkdir -p build/android/$ARCH
|
||||||
|
cp -v secp256k1/.libs/libsecp256k1.a build/android/$ARCH
|
@ -19,9 +19,9 @@ make
|
|||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
mkdir -p build/$TARGET
|
mkdir -p build/$TARGET
|
||||||
cp -r secp256k1/.libs/libsecp256k1.a build/$TARGET/
|
cp -v secp256k1/.libs/libsecp256k1.a build/$TARGET/
|
||||||
|
|
||||||
GCC=gcc
|
CC=gcc
|
||||||
JNI_HEADERS=$TARGET
|
JNI_HEADERS=$TARGET
|
||||||
|
|
||||||
if [ "$TARGET" == "linux" ]; then
|
if [ "$TARGET" == "linux" ]; then
|
||||||
@ -31,11 +31,9 @@ elif [ "$TARGET" == "darwin" ]; then
|
|||||||
ADD_LIB=-lgmp
|
ADD_LIB=-lgmp
|
||||||
elif [ "$TARGET" == "mingw" ]; then
|
elif [ "$TARGET" == "mingw" ]; then
|
||||||
OUTFILE=secp256k1-jni.dll
|
OUTFILE=secp256k1-jni.dll
|
||||||
GCC=/usr/src/mxe/usr/bin/x86_64-w64-mingw32.static-gcc
|
CC=/usr/src/mxe/usr/bin/x86_64-w64-mingw32.static-gcc
|
||||||
JNI_HEADERS=linux
|
JNI_HEADERS=linux
|
||||||
GCC_OPTS="-fpic"
|
CC_OPTS="-fpic"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo $GCC -shared $GCC_OPTS -o build/$TARGET/$OUTFILE jni/src/org_bitcoin_NativeSecp256k1.c jni/src/org_bitcoin_Secp256k1Context.c -Ijni/headers/ -Ijni/headers/$JNI_HEADERS/ -Isecp256k1/ -lsecp256k1 -Lbuild/$TARGET/ $ADD_LIB
|
$CC -shared $CC_OPTS -o build/$TARGET/$OUTFILE jni/src/org_bitcoin_NativeSecp256k1.c jni/src/org_bitcoin_Secp256k1Context.c -Ijni/headers/ -Ijni/headers/$JNI_HEADERS/ -Isecp256k1/ -lsecp256k1 -Lbuild/$TARGET/ $ADD_LIB
|
||||||
|
|
||||||
$GCC -shared $GCC_OPTS -o build/$TARGET/$OUTFILE jni/src/org_bitcoin_NativeSecp256k1.c jni/src/org_bitcoin_Secp256k1Context.c -Ijni/headers/ -Ijni/headers/$JNI_HEADERS/ -Isecp256k1/ -lsecp256k1 -Lbuild/$TARGET/ $ADD_LIB
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
pluginManagement {
|
pluginManagement {
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
google()
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
maven {
|
maven {
|
||||||
url = uri("https://dl.bintray.com/kotlin/kotlin-eap")
|
url = uri("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
@ -9,6 +10,11 @@ pluginManagement {
|
|||||||
maven("https://plugins.gradle.org/m2/")
|
maven("https://plugins.gradle.org/m2/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolutionStrategy {
|
||||||
|
eachPlugin {
|
||||||
|
if (requested.id.id == "com.android.library") useModule("com.android.tools.build:gradle:${requested.version}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rootProject.name = "secp256k1-kmp"
|
rootProject.name = "secp256k1-kmp"
|
||||||
|
|
||||||
|
3
src/androidMain/AndroidManifest.xml
Normal file
3
src/androidMain/AndroidManifest.xml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest package="fr.acinq.secp256k1">
|
||||||
|
</manifest>
|
14
src/androidMain/CMakeLists.txt
Normal file
14
src/androidMain/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10.0)
|
||||||
|
|
||||||
|
add_library( secp256k1-jni SHARED
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../native/jni/src/org_bitcoin_NativeSecp256k1.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../native/jni/src/org_bitcoin_Secp256k1Context.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories( secp256k1-jni
|
||||||
|
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../../native/secp256k1
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries( secp256k1-jni
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../native/build/android/${ANDROID_ABI}/libsecp256k1.a
|
||||||
|
)
|
15
src/androidMain/kotlin/fr/acinq/secp256k1/Secp256k1Loader.kt
Normal file
15
src/androidMain/kotlin/fr/acinq/secp256k1/Secp256k1Loader.kt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package fr.acinq.secp256k1
|
||||||
|
|
||||||
|
import java.io.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
internal actual object Secp256k1Loader {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@Synchronized
|
||||||
|
@Throws(Exception::class)
|
||||||
|
actual fun initialize() {
|
||||||
|
System.loadLibrary("secp256k1-jni")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
4
src/androidTest/java/fr/acinq/secp256k1/Placeholder.kt
Normal file
4
src/androidTest/java/fr/acinq/secp256k1/Placeholder.kt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
package fr.acinq.secp256k1
|
||||||
|
|
||||||
|
|
||||||
|
class Placeholder {}
|
@ -17,7 +17,10 @@
|
|||||||
package fr.acinq.secp256k1
|
package fr.acinq.secp256k1
|
||||||
|
|
||||||
import org.bitcoin.NativeSecp256k1
|
import org.bitcoin.NativeSecp256k1
|
||||||
import java.math.BigInteger
|
|
||||||
|
internal expect object Secp256k1Loader {
|
||||||
|
fun initialize()
|
||||||
|
}
|
||||||
|
|
||||||
public actual object Secp256k1 {
|
public actual object Secp256k1 {
|
||||||
|
|
@ -78,7 +78,12 @@ public object NativeSecp256k1 {
|
|||||||
val byteBuff = pack(data, signature, pub)
|
val byteBuff = pack(data, signature, pub)
|
||||||
r.lock()
|
r.lock()
|
||||||
return try {
|
return try {
|
||||||
secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.size, pub.size) == 1
|
secp256k1_ecdsa_verify(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext(),
|
||||||
|
signature.size,
|
||||||
|
pub.size
|
||||||
|
) == 1
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
@ -100,14 +105,21 @@ public object NativeSecp256k1 {
|
|||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext())
|
secp256k1_ecdsa_sign(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext()
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
val sigArr = retByteArray[0]
|
val sigArr = retByteArray[0]
|
||||||
val sigLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt()
|
val sigLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt()
|
||||||
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
|
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
|
||||||
NativeSecp256k1Util.assertEquals(sigArr.size, sigLen, "Got bad signature length.")
|
NativeSecp256k1Util.assertEquals(
|
||||||
|
sigArr.size,
|
||||||
|
sigLen,
|
||||||
|
"Got bad signature length."
|
||||||
|
)
|
||||||
return if (retVal == 0) ByteArray(0) else sigArr
|
return if (retVal == 0) ByteArray(0) else sigArr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,14 +142,21 @@ public object NativeSecp256k1 {
|
|||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_ecdsa_sign_compact(byteBuff, Secp256k1Context.getContext())
|
secp256k1_ecdsa_sign_compact(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext()
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
val sigArr = retByteArray[0]
|
val sigArr = retByteArray[0]
|
||||||
val sigLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt()
|
val sigLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt()
|
||||||
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
|
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
|
||||||
NativeSecp256k1Util.assertEquals(sigArr.size, sigLen, "Got bad signature length.")
|
NativeSecp256k1Util.assertEquals(
|
||||||
|
sigArr.size,
|
||||||
|
sigLen,
|
||||||
|
"Got bad signature length."
|
||||||
|
)
|
||||||
return if (retVal == 0) ByteArray(0) else sigArr
|
return if (retVal == 0) ByteArray(0) else sigArr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +172,10 @@ public object NativeSecp256k1 {
|
|||||||
val byteBuff = pack(seckey)
|
val byteBuff = pack(seckey)
|
||||||
r.lock()
|
r.lock()
|
||||||
return try {
|
return try {
|
||||||
secp256k1_ec_seckey_verify(byteBuff, Secp256k1Context.getContext()) == 1
|
secp256k1_ec_seckey_verify(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext()
|
||||||
|
) == 1
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
@ -175,7 +197,10 @@ public object NativeSecp256k1 {
|
|||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext())
|
secp256k1_ec_pubkey_create(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext()
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
@ -199,12 +224,16 @@ public object NativeSecp256k1 {
|
|||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_ec_pubkey_parse(byteBuff, Secp256k1Context.getContext(), pubkey.size)
|
secp256k1_ec_pubkey_parse(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext(),
|
||||||
|
pubkey.size
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
val pubArr = retByteArray[0]
|
val pubArr = retByteArray[0]
|
||||||
val pubLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt()
|
BigInteger(byteArrayOf(retByteArray[1][0])).toInt()
|
||||||
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
|
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
|
||||||
NativeSecp256k1Util.assertEquals(pubArr.size, 65, "Got bad pubkey length.")
|
NativeSecp256k1Util.assertEquals(pubArr.size, 65, "Got bad pubkey length.")
|
||||||
return if (retVal == 0) ByteArray(0) else pubArr
|
return if (retVal == 0) ByteArray(0) else pubArr
|
||||||
@ -233,14 +262,21 @@ public object NativeSecp256k1 {
|
|||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_privkey_negate(byteBuff, Secp256k1Context.getContext())
|
secp256k1_privkey_negate(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext()
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
val privArr = retByteArray[0]
|
val privArr = retByteArray[0]
|
||||||
val privLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF
|
val privLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF
|
||||||
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
|
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
|
||||||
NativeSecp256k1Util.assertEquals(privArr.size, privLen, "Got bad privkey length.")
|
NativeSecp256k1Util.assertEquals(
|
||||||
|
privArr.size,
|
||||||
|
privLen,
|
||||||
|
"Got bad privkey length."
|
||||||
|
)
|
||||||
NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.")
|
NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.")
|
||||||
return privArr
|
return privArr
|
||||||
}
|
}
|
||||||
@ -257,18 +293,25 @@ public object NativeSecp256k1 {
|
|||||||
@Throws(AssertFailException::class)
|
@Throws(AssertFailException::class)
|
||||||
public fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
public fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||||
require(privkey.size == 32)
|
require(privkey.size == 32)
|
||||||
val byteBuff = pack(privkey, tweak!!)
|
val byteBuff = pack(privkey, tweak)
|
||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_privkey_tweak_mul(byteBuff, Secp256k1Context.getContext())
|
secp256k1_privkey_tweak_mul(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext()
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
val privArr = retByteArray[0]
|
val privArr = retByteArray[0]
|
||||||
val privLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF
|
val privLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF
|
||||||
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
|
val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt()
|
||||||
NativeSecp256k1Util.assertEquals(privArr.size, privLen, "Got bad privkey length.")
|
NativeSecp256k1Util.assertEquals(
|
||||||
|
privArr.size,
|
||||||
|
privLen,
|
||||||
|
"Got bad privkey length."
|
||||||
|
)
|
||||||
NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.")
|
NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.")
|
||||||
return privArr
|
return privArr
|
||||||
}
|
}
|
||||||
@ -285,11 +328,14 @@ public object NativeSecp256k1 {
|
|||||||
@Throws(AssertFailException::class)
|
@Throws(AssertFailException::class)
|
||||||
public fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
public fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||||
require(privkey.size == 32)
|
require(privkey.size == 32)
|
||||||
val byteBuff = pack(privkey, tweak!!)
|
val byteBuff = pack(privkey, tweak)
|
||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_privkey_tweak_add(byteBuff, Secp256k1Context.getContext())
|
secp256k1_privkey_tweak_add(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext()
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
@ -309,7 +355,11 @@ public object NativeSecp256k1 {
|
|||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_pubkey_negate(byteBuff, Secp256k1Context.getContext(), pubkey.size)
|
secp256k1_pubkey_negate(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext(),
|
||||||
|
pubkey.size
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
@ -337,7 +387,11 @@ public object NativeSecp256k1 {
|
|||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_pubkey_tweak_add(byteBuff, Secp256k1Context.getContext(), pubkey.size)
|
secp256k1_pubkey_tweak_add(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext(),
|
||||||
|
pubkey.size
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
@ -361,11 +415,15 @@ public object NativeSecp256k1 {
|
|||||||
@Throws(AssertFailException::class)
|
@Throws(AssertFailException::class)
|
||||||
public fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray {
|
public fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray {
|
||||||
require(pubkey.size == 33 || pubkey.size == 65)
|
require(pubkey.size == 33 || pubkey.size == 65)
|
||||||
val byteBuff = pack(pubkey, tweak!!)
|
val byteBuff = pack(pubkey, tweak)
|
||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_pubkey_tweak_mul(byteBuff, Secp256k1Context.getContext(), pubkey.size)
|
secp256k1_pubkey_tweak_mul(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext(),
|
||||||
|
pubkey.size
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
@ -386,7 +444,12 @@ public object NativeSecp256k1 {
|
|||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_ec_pubkey_add(byteBuff, Secp256k1Context.getContext(), pubkey1.size, pubkey2.size)
|
secp256k1_ec_pubkey_add(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext(),
|
||||||
|
pubkey1.size,
|
||||||
|
pubkey2.size
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
@ -414,7 +477,11 @@ public object NativeSecp256k1 {
|
|||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.size)
|
secp256k1_ecdh(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext(),
|
||||||
|
pubkey.size
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
@ -434,7 +501,11 @@ public object NativeSecp256k1 {
|
|||||||
val retByteArray: Array<ByteArray>
|
val retByteArray: Array<ByteArray>
|
||||||
r.lock()
|
r.lock()
|
||||||
retByteArray = try {
|
retByteArray = try {
|
||||||
secp256k1_ecdsa_recover(byteBuff, Secp256k1Context.getContext(), recid)
|
secp256k1_ecdsa_recover(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext(),
|
||||||
|
recid
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
r.unlock()
|
r.unlock()
|
||||||
}
|
}
|
||||||
@ -460,7 +531,10 @@ public object NativeSecp256k1 {
|
|||||||
val byteBuff = pack(seed)
|
val byteBuff = pack(seed)
|
||||||
w.lock()
|
w.lock()
|
||||||
return try {
|
return try {
|
||||||
secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1
|
secp256k1_context_randomize(
|
||||||
|
byteBuff,
|
||||||
|
Secp256k1Context.getContext()
|
||||||
|
) == 1
|
||||||
} finally {
|
} finally {
|
||||||
w.unlock()
|
w.unlock()
|
||||||
}
|
}
|
@ -34,23 +34,7 @@ public object Secp256k1Context {
|
|||||||
@JvmStatic private external fun secp256k1_init_context(): Long
|
@JvmStatic private external fun secp256k1_init_context(): Long
|
||||||
|
|
||||||
init { //static initializer
|
init { //static initializer
|
||||||
var isEnabled = true
|
isEnabled = true
|
||||||
var contextRef: Long = -1
|
context = secp256k1_init_context()
|
||||||
try {
|
|
||||||
if ("The Android Project" == System.getProperty("java.vm.vendor")) {
|
|
||||||
System.loadLibrary("secp256k1")
|
|
||||||
} else {
|
|
||||||
initialize()
|
|
||||||
}
|
|
||||||
contextRef = secp256k1_init_context()
|
|
||||||
} catch (e: UnsatisfiedLinkError) {
|
|
||||||
println("Cannot load secp256k1 native library: $e")
|
|
||||||
isEnabled = false
|
|
||||||
} catch (e: Exception) {
|
|
||||||
println("Cannot load secp256k1 native library: $e")
|
|
||||||
isEnabled = false
|
|
||||||
}
|
|
||||||
this.isEnabled = isEnabled
|
|
||||||
this.context = contextRef
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,7 +26,7 @@ import java.util.*
|
|||||||
*
|
*
|
||||||
* @author leo
|
* @author leo
|
||||||
*/
|
*/
|
||||||
public object Secp256k1Loader {
|
internal actual object Secp256k1Loader {
|
||||||
private var extracted = false
|
private var extracted = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,13 +38,12 @@ public object Secp256k1Loader {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Synchronized
|
@Synchronized
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
public fun initialize(): Boolean {
|
actual fun initialize() {
|
||||||
// only cleanup before the first extract
|
// only cleanup before the first extract
|
||||||
if (!extracted) {
|
if (!extracted) {
|
||||||
cleanup()
|
cleanup()
|
||||||
}
|
}
|
||||||
loadSecp256k1NativeLibrary()
|
loadSecp256k1NativeLibrary()
|
||||||
return extracted
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val tempDir: File
|
private val tempDir: File
|
||||||
@ -55,7 +54,7 @@ public object Secp256k1Loader {
|
|||||||
* on VM-Exit (bug #80)
|
* on VM-Exit (bug #80)
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
public fun cleanup() {
|
fun cleanup() {
|
||||||
val tempFolder = tempDir.absolutePath
|
val tempFolder = tempDir.absolutePath
|
||||||
val dir = File(tempFolder)
|
val dir = File(tempFolder)
|
||||||
val nativeLibFiles = dir.listFiles(object : FilenameFilter {
|
val nativeLibFiles = dir.listFiles(object : FilenameFilter {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user