Android implementation

This commit is contained in:
Salomon BRYS 2020-06-26 20:50:32 +02:00
parent 08b6d16836
commit ff37b86ff3
15 changed files with 303 additions and 72 deletions

1
.gitignore vendored
View File

@ -9,6 +9,7 @@ build/
.gradle .gradle
local.properties local.properties
.gradletasknamecache .gradletasknamecache
.cxx
# OS # OS
.DS_Store .DS_Store

View File

@ -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
}
} }

View File

@ -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
View 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

View File

@ -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

View File

@ -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"

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="fr.acinq.secp256k1">
</manifest>

View 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
)

View 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")
}
}

View File

@ -0,0 +1,4 @@
package fr.acinq.secp256k1
class Placeholder {}

View File

@ -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 {

View File

@ -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()
} }

View File

@ -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
} }
} }

View File

@ -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 {