Android & JVM loader in their own modules
This commit is contained in:
		
							parent
							
								
									9e1fc5d5ff
								
							
						
					
					
						commit
						1d9d57ca0a
					
				
							
								
								
									
										259
									
								
								build.gradle.kts
									
									
									
									
									
								
							
							
						
						
									
										259
									
								
								build.gradle.kts
									
									
									
									
									
								
							| @ -1,8 +1,21 @@ | |||||||
| plugins { | plugins { | ||||||
|     kotlin("multiplatform") version "1.4-M2-mt" |     kotlin("multiplatform") version "1.4-M2-mt" | ||||||
|     id("com.android.library") version "4.0.0" | //    `maven-publish` | ||||||
|     `maven-publish` |  | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | buildscript { | ||||||
|  |     repositories { | ||||||
|  |         google() | ||||||
|  |         maven("https://dl.bintray.com/kotlin/kotlin-eap") | ||||||
|  |         jcenter() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     dependencies { | ||||||
|  |         classpath("com.android.tools.build:gradle:4.0.0") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | allprojects { | ||||||
|     group = "fr.acinq.secp256k1" |     group = "fr.acinq.secp256k1" | ||||||
|     version = "0.2.1-1.4-M2" |     version = "0.2.1-1.4-M2" | ||||||
| 
 | 
 | ||||||
| @ -11,6 +24,7 @@ repositories { | |||||||
|         google() |         google() | ||||||
|         maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") |         maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") | ||||||
|     } |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| val currentOs = org.gradle.internal.os.OperatingSystem.current() | val currentOs = org.gradle.internal.os.OperatingSystem.current() | ||||||
| 
 | 
 | ||||||
| @ -29,60 +43,40 @@ 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" | ||||||
|         } |         } | ||||||
|         (tasks[compilations["main"].processResourcesTaskName] as ProcessResources).apply{ |         compilations["main"].dependencies { | ||||||
|             dependsOn("copyJni") |             implementation(kotlin("stdlib-jdk8")) | ||||||
|             from(buildDir.resolve("jniResources")) |  | ||||||
|         } |         } | ||||||
|         compilations["main"].defaultSourceSet.dependsOn(jvmAndAndroidMain) |  | ||||||
|         compilations["test"].dependencies { |         compilations["test"].dependencies { | ||||||
|  |             implementation(project(":jni")) | ||||||
|  |             implementation(kotlin("stdlib-jdk8")) | ||||||
|             implementation(kotlin("test-junit")) |             implementation(kotlin("test-junit")) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     android { |     fun org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget.secp256k1CInterop(target: String) { | ||||||
|         publishLibraryVariants("release", "debug") |  | ||||||
|         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() { |  | ||||||
|         compilations["main"].cinterops { |         compilations["main"].cinterops { | ||||||
|             val libsecp256k1 by creating { |             val libsecp256k1 by creating { | ||||||
|                 includeDirs.headerFilterOnly(project.file("native/secp256k1/include/")) |                 includeDirs.headerFilterOnly(project.file("native/secp256k1/include/")) | ||||||
|                 tasks[interopProcessingTaskName].dependsOn("buildSecp256k1Ios") |                 tasks[interopProcessingTaskName].dependsOn(":native:buildSecp256k1${target.capitalize()}") | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     val nativeMain by sourceSets.creating { dependsOn(commonMain) } |     val nativeMain by sourceSets.creating { dependsOn(commonMain) } | ||||||
| 
 | 
 | ||||||
|     linuxX64 { |     linuxX64("linux") { | ||||||
|         secp256k1CInterop() |         secp256k1CInterop("linux") | ||||||
|         // https://youtrack.jetbrains.com/issue/KT-39396 |         // https://youtrack.jetbrains.com/issue/KT-39396 | ||||||
|         compilations["main"].kotlinOptions.freeCompilerArgs += listOf("-include-binary", "$rootDir/native/build/linux/libsecp256k1.a") |         compilations["main"].kotlinOptions.freeCompilerArgs += listOf("-include-binary", "$rootDir/native/build/linux/libsecp256k1.a") | ||||||
|         compilations["main"].defaultSourceSet.dependsOn(nativeMain) |         compilations["main"].defaultSourceSet.dependsOn(nativeMain) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ios { |     ios { | ||||||
|         secp256k1CInterop() |         secp256k1CInterop("ios") | ||||||
|         // https://youtrack.jetbrains.com/issue/KT-39396 |         // https://youtrack.jetbrains.com/issue/KT-39396 | ||||||
|         compilations["main"].kotlinOptions.freeCompilerArgs += listOf("-include-binary", "$rootDir/native/build/ios/libsecp256k1.a") |         compilations["main"].kotlinOptions.freeCompilerArgs += listOf("-include-binary", "$rootDir/native/build/ios/libsecp256k1.a") | ||||||
|         compilations["main"].defaultSourceSet.dependsOn(nativeMain) |         compilations["main"].defaultSourceSet.dependsOn(nativeMain) | ||||||
| @ -120,166 +114,43 @@ afterEvaluate { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| android { | //publishing { | ||||||
|     defaultConfig { | //    val snapshotName: String? by project | ||||||
|         compileSdkVersion(30) | //    val snapshotNumber: String? by project | ||||||
|         minSdkVersion(21) | // | ||||||
|         testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | //    val bintrayUsername: String? = (properties["bintrayUsername"] as String?) ?: System.getenv("BINTRAY_USER") | ||||||
|         externalNativeBuild { | //    val bintrayApiKey: String? = (properties["bintrayApiKey"] as String?) ?: System.getenv("BINTRAY_APIKEY") | ||||||
|             cmake {} | //    if (bintrayUsername == null || bintrayApiKey == null) logger.warn("Skipping bintray configuration as bintrayUsername or bintrayApiKey is not defined") | ||||||
|         } | //    else { | ||||||
|     } | //        val btRepo = if (snapshotNumber != null) "snapshots" else "libs" | ||||||
| 
 | //        repositories { | ||||||
|     compileOptions { | //            maven { | ||||||
|         sourceCompatibility = JavaVersion.VERSION_1_8 | //                name = "bintray" | ||||||
|         targetCompatibility = JavaVersion.VERSION_1_8 | //                setUrl("https://api.bintray.com/maven/acinq/$btRepo/${project.name}/;publish=0") | ||||||
|     } | //                credentials { | ||||||
| 
 | //                    username = bintrayUsername | ||||||
|     externalNativeBuild { | //                    password = bintrayApiKey | ||||||
|         cmake { | //                } | ||||||
|             setPath("src/androidMain/CMakeLists.txt") | //            } | ||||||
|         } | //        } | ||||||
|     } | //    } | ||||||
|     ndkVersion = "21.3.6528147" | // | ||||||
| 
 | //    publications.withType<MavenPublication>().configureEach { | ||||||
|     sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") | //        if (snapshotName != null && snapshotNumber != null) version = "${project.version}-${snapshotName}-${snapshotNumber}" | ||||||
| 
 | //        pom { | ||||||
|     afterEvaluate { | //            description.set("Bitcoin's secp256k1 library ported to Kotlin/Multiplatform for JVM, Android, iOS & Linux") | ||||||
|         tasks.withType<com.android.build.gradle.tasks.factory.AndroidUnitTest>().all { | //            url.set("https://github.com/ACINQ/secp256k1-kmp") | ||||||
|             enabled = false | //            licenses { | ||||||
|         } | //                name.set("Apache License v2.0") | ||||||
|     } | //                url.set("https://www.apache.org/licenses/LICENSE-2.0") | ||||||
| } | //            } | ||||||
| 
 | //            issueManagement { | ||||||
| val buildSecp256k1 by tasks.creating { group = "build" } | //                system.set("Github") | ||||||
| sealed class Cross { | //                url.set("https://github.com/ACINQ/secp256k1-kmp/issues") | ||||||
|     abstract fun cmd(target: String, nativeDir: File): List<String> | //            } | ||||||
|     class DockCross(val cross: String) : Cross() { | //            scm { | ||||||
|         override fun cmd(target: String, nativeDir: File): List<String> = listOf("./dockcross-$cross", "bash", "-c", "CROSS=1 TARGET=$target ./build.sh") | //                connection.set("https://github.com/ACINQ/secp256k1-kmp.git") | ||||||
|     } | //            } | ||||||
|     class MultiArch(val crossTriple: String) : Cross() { | //        } | ||||||
|         override fun cmd(target: String, nativeDir: File): List<String> { | //    } | ||||||
|             val uid = Runtime.getRuntime().exec("id -u").inputStream.use { it.reader().readText() }.trim().toInt() | //} | ||||||
|             return listOf( |  | ||||||
|                 "docker", "run", "--rm", "-v", "${nativeDir.absolutePath}:/workdir", |  | ||||||
|                 "-e", "CROSS_TRIPLE=$crossTriple", "-e", "TARGET=$target", "-e", "TO_UID=$uid", "-e", "CROSS=1", |  | ||||||
|                 "multiarch/crossbuild", "./build.sh" |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| fun creatingBuildSecp256k1(target: String, cross: Cross?) = tasks.creating(Exec::class) { |  | ||||||
|     group = "build" |  | ||||||
|     buildSecp256k1.dependsOn(this) |  | ||||||
| 
 |  | ||||||
|     inputs.files(projectDir.resolve("native/build.sh")) |  | ||||||
|     outputs.dir(projectDir.resolve("native/build/$target")) |  | ||||||
| 
 |  | ||||||
|     workingDir = projectDir.resolve("native") |  | ||||||
|     environment("TARGET", target) |  | ||||||
|     commandLine((cross?.cmd(target, workingDir) ?: emptyList()) + "./build.sh") |  | ||||||
| } |  | ||||||
| val buildSecp256k1Darwin by creatingBuildSecp256k1("darwin", if (currentOs.isMacOsX) null else Cross.MultiArch("x86_64-apple-darwin")) |  | ||||||
| val buildSecp256k1Linux by creatingBuildSecp256k1("linux", if (currentOs.isLinux) null else Cross.DockCross("linux-x64")) |  | ||||||
| val buildSecp256k1Mingw by creatingBuildSecp256k1("mingw", if (currentOs.isWindows) null else Cross.DockCross("windows-x64")) |  | ||||||
| 
 |  | ||||||
| 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) { |  | ||||||
|     group = "build" |  | ||||||
|     buildSecp256k1.dependsOn(this) |  | ||||||
| 
 |  | ||||||
|     onlyIf { currentOs.isMacOsX } |  | ||||||
| 
 |  | ||||||
|     inputs.files(projectDir.resolve("native/build-ios.sh")) |  | ||||||
|     outputs.dir(projectDir.resolve("native/build/ios")) |  | ||||||
| 
 |  | ||||||
|     workingDir = projectDir.resolve("native") |  | ||||||
|     commandLine("./build-ios.sh") |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| val buildSecp256k1Android by tasks.creating { |  | ||||||
|     group = "build" |  | ||||||
|     buildSecp256k1.dependsOn(this) |  | ||||||
| } |  | ||||||
| fun creatingBuildSecp256k1Android(arch: String) = tasks.creating(Exec::class) { |  | ||||||
|     group = "build" |  | ||||||
|     buildSecp256k1Android.dependsOn(this) |  | ||||||
| 
 |  | ||||||
|     inputs.files(projectDir.resolve("native/build-android.sh")) |  | ||||||
|     outputs.dir(projectDir.resolve("native/build/android/$arch")) |  | ||||||
| 
 |  | ||||||
|     workingDir = projectDir.resolve("native") |  | ||||||
| 
 |  | ||||||
|     val toolchain = when { |  | ||||||
|         currentOs.isLinux -> "linux-x86_64" |  | ||||||
|         currentOs.isMacOsX -> "darwin-x86_64" |  | ||||||
|         currentOs.isWindows -> "windows-x86_64" |  | ||||||
|         else -> error("No Android toolchain defined for this OS: $currentOs") |  | ||||||
|     } |  | ||||||
|     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")) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| publishing { |  | ||||||
|     val snapshotName: String? by project |  | ||||||
|     val snapshotNumber: String? by project |  | ||||||
| 
 |  | ||||||
|     val bintrayUsername: String? = (properties["bintrayUsername"] as String?) ?: System.getenv("BINTRAY_USER") |  | ||||||
|     val bintrayApiKey: String? = (properties["bintrayApiKey"] as String?) ?: System.getenv("BINTRAY_APIKEY") |  | ||||||
|     if (bintrayUsername == null || bintrayApiKey == null) logger.warn("Skipping bintray configuration as bintrayUsername or bintrayApiKey is not defined") |  | ||||||
|     else { |  | ||||||
|         val btRepo = if (snapshotNumber != null) "snapshots" else "libs" |  | ||||||
|         repositories { |  | ||||||
|             maven { |  | ||||||
|                 name = "bintray" |  | ||||||
|                 setUrl("https://api.bintray.com/maven/acinq/$btRepo/${project.name}/;publish=0") |  | ||||||
|                 credentials { |  | ||||||
|                     username = bintrayUsername |  | ||||||
|                     password = bintrayApiKey |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     publications.withType<MavenPublication>().configureEach { |  | ||||||
|         if (snapshotName != null && snapshotNumber != null) version = "${project.version}-${snapshotName}-${snapshotNumber}" |  | ||||||
|         pom { |  | ||||||
|             description.set("Bitcoin's secp256k1 library ported to Kotlin/Multiplatform for JVM, Android, iOS & Linux") |  | ||||||
|             url.set("https://github.com/ACINQ/secp256k1-kmp") |  | ||||||
|             licenses { |  | ||||||
|                 name.set("Apache License v2.0") |  | ||||||
|                 url.set("https://www.apache.org/licenses/LICENSE-2.0") |  | ||||||
|             } |  | ||||||
|             issueManagement { |  | ||||||
|                 system.set("Github") |  | ||||||
|                 url.set("https://github.com/ACINQ/secp256k1-kmp/issues") |  | ||||||
|             } |  | ||||||
|             scm { |  | ||||||
|                 connection.set("https://github.com/ACINQ/secp256k1-kmp.git") |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | |||||||
							
								
								
									
										103
									
								
								jni/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								jni/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | |||||||
|  | plugins { | ||||||
|  |     kotlin("multiplatform") // version "1.4-M2-mt" | ||||||
|  |     id("com.android.library") | ||||||
|  |     `maven-publish` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | val currentOs = org.gradle.internal.os.OperatingSystem.current() | ||||||
|  | 
 | ||||||
|  | kotlin { | ||||||
|  |     explicitApi() | ||||||
|  | 
 | ||||||
|  |     val commonMain by sourceSets.getting { | ||||||
|  |         dependencies { | ||||||
|  |             implementation(kotlin("stdlib-common")) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     val commonTest by sourceSets.getting { | ||||||
|  |         dependencies { | ||||||
|  |             implementation(kotlin("test-common")) | ||||||
|  |             implementation(kotlin("test-annotations-common")) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     jvm { | ||||||
|  |         compilations.all { | ||||||
|  |             kotlinOptions.jvmTarget = "1.8" | ||||||
|  |         } | ||||||
|  |         (tasks[compilations["main"].processResourcesTaskName] as ProcessResources).apply { | ||||||
|  |             dependsOn("copyJni") | ||||||
|  |             from(buildDir.resolve("jniResources")) | ||||||
|  |         } | ||||||
|  |         compilations["main"].dependencies { | ||||||
|  |             implementation(kotlin("stdlib-jdk8")) | ||||||
|  |         } | ||||||
|  |         compilations["test"].dependencies { | ||||||
|  |             implementation(kotlin("test-junit")) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     android { | ||||||
|  |         publishLibraryVariants("release", "debug") | ||||||
|  |         compilations.all { | ||||||
|  |             kotlinOptions.jvmTarget = "1.8" | ||||||
|  |         } | ||||||
|  |         sourceSets["androidMain"].dependencies { | ||||||
|  |             implementation(kotlin("stdlib-jdk8")) | ||||||
|  |         } | ||||||
|  |         sourceSets["androidTest"].dependencies { | ||||||
|  |             implementation(kotlin("test-junit")) | ||||||
|  |             implementation("androidx.test.ext:junit:1.1.1") | ||||||
|  |             implementation("androidx.test.espresso:espresso-core:3.2.0") | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     sourceSets.all { | ||||||
|  |         languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | android { | ||||||
|  |     defaultConfig { | ||||||
|  |         compileSdkVersion(30) | ||||||
|  |         minSdkVersion(21) | ||||||
|  |         testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||||||
|  |         externalNativeBuild { | ||||||
|  |             cmake {} | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     compileOptions { | ||||||
|  |         sourceCompatibility = JavaVersion.VERSION_1_8 | ||||||
|  |         targetCompatibility = JavaVersion.VERSION_1_8 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     externalNativeBuild { | ||||||
|  |         cmake { | ||||||
|  |             setPath("src/androidMain/CMakeLists.txt") | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     ndkVersion = "21.3.6528147" | ||||||
|  | 
 | ||||||
|  |     sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") | ||||||
|  | 
 | ||||||
|  |     afterEvaluate { | ||||||
|  |         tasks.withType<com.android.build.gradle.tasks.factory.AndroidUnitTest>().all { | ||||||
|  |             enabled = false | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | val copyJni by tasks.creating(Sync::class) { | ||||||
|  |     dependsOn(":native:buildSecp256k1Jvm") | ||||||
|  |     from(rootDir.resolve("native/build/linux/libsecp256k1-jni.so")) { rename { "libsecp256k1-jni-linux-x86_64.so" } } | ||||||
|  |     from(rootDir.resolve("native/build/darwin/libsecp256k1-jni.dylib")) { rename { "libsecp256k1-jni-darwin-x86_64.dylib" } } | ||||||
|  |     from(rootDir.resolve("native/build/mingw/secp256k1-jni.dll")) { rename { "secp256k1-jni-mingw-x86_64.dll" } } | ||||||
|  |     into(buildDir.resolve("jniResources/fr/acinq/secp256k1/jni/native")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | afterEvaluate { | ||||||
|  |     configure(listOf("Debug", "Release").map { tasks["externalNativeBuild$it"] }) { | ||||||
|  |         dependsOn(":native:buildSecp256k1Android") | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								jni/src/androidMain/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								jni/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 | ||||||
|  | ) | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | package fr.acinq.secp256k1.jni | ||||||
|  | 
 | ||||||
|  | public actual object NativeSecp256k1Loader { | ||||||
|  | 
 | ||||||
|  |     @JvmStatic | ||||||
|  |     @Synchronized | ||||||
|  |     @Throws(Exception::class) | ||||||
|  |     actual fun load() { | ||||||
|  |         System.loadLibrary("secp256k1-jni") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,10 @@ | |||||||
|  | package fr.acinq.secp256k1.jni | ||||||
|  | 
 | ||||||
|  | import kotlin.jvm.JvmStatic | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | public expect object NativeSecp256k1Loader { | ||||||
|  | 
 | ||||||
|  |     public fun load() | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -15,7 +15,7 @@ | |||||||
|  */ |  */ | ||||||
| package org.bitcoin | package org.bitcoin | ||||||
| 
 | 
 | ||||||
| import fr.acinq.secp256k1.Secp256k1Loader.initialize | import kotlin.jvm.JvmStatic | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * This class holds the context reference used in native methods |  * This class holds the context reference used in native methods | ||||||
| @ -0,0 +1,211 @@ | |||||||
|  | package fr.acinq.secp256k1.jni | ||||||
|  | 
 | ||||||
|  | import java.io.* | ||||||
|  | import java.util.* | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  | * Set the system properties, org.sqlite.lib.path, org.sqlite.lib.name, | ||||||
|  | * appropriately so that the SQLite JDBC driver can find *.dll, *.jnilib and | ||||||
|  | * *.so files, according to the current OS (win, linux, mac). | ||||||
|  | * The library files are automatically extracted from this project's package (JAR). | ||||||
|  | * usage: call [.initialize] before using SQLite JDBC driver. | ||||||
|  | * | ||||||
|  | * @author leo | ||||||
|  | */ | ||||||
|  | public actual object NativeSecp256k1Loader { | ||||||
|  |    private var extracted = false | ||||||
|  | 
 | ||||||
|  |    /** | ||||||
|  |     * Loads secp256k1 native library. | ||||||
|  |     * | ||||||
|  |     * @return True if secp256k1 native library is successfully loaded; false otherwise. | ||||||
|  |     * @throws Exception if loading fails | ||||||
|  |     */ | ||||||
|  |    @JvmStatic | ||||||
|  |    @Synchronized | ||||||
|  |    @Throws(Exception::class) | ||||||
|  |    public actual fun load() { | ||||||
|  |        // only cleanup before the first extract | ||||||
|  |        if (!extracted) { | ||||||
|  |            cleanup() | ||||||
|  |        } | ||||||
|  |        loadSecp256k1NativeLibrary() | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    private val tempDir: File | ||||||
|  |        get() = File( | ||||||
|  |            System.getProperty( | ||||||
|  |                "fr.acinq.secp256k1.tmpdir", | ||||||
|  |                System.getProperty("java.io.tmpdir") | ||||||
|  |            ) | ||||||
|  |        ) | ||||||
|  | 
 | ||||||
|  |    /** | ||||||
|  |     * Deleted old native libraries e.g. on Windows the DLL file is not removed | ||||||
|  |     * on VM-Exit (bug #80) | ||||||
|  |     */ | ||||||
|  |    @JvmStatic | ||||||
|  |    public fun cleanup() { | ||||||
|  |        val tempFolder = tempDir.absolutePath | ||||||
|  |        val dir = File(tempFolder) | ||||||
|  |        val nativeLibFiles = dir.listFiles(object : FilenameFilter { | ||||||
|  |            private val searchPattern = "secp256k1-" | ||||||
|  |            override fun accept(dir: File, name: String): Boolean { | ||||||
|  |                return name.startsWith(searchPattern) && !name.endsWith(".lck") | ||||||
|  |            } | ||||||
|  |        }) | ||||||
|  |        if (nativeLibFiles != null) { | ||||||
|  |            for (nativeLibFile in nativeLibFiles) { | ||||||
|  |                val lckFile = File(nativeLibFile.absolutePath + ".lck") | ||||||
|  |                if (!lckFile.exists()) { | ||||||
|  |                    try { | ||||||
|  |                        nativeLibFile.delete() | ||||||
|  |                    } catch (e: SecurityException) { | ||||||
|  |                        System.err.println("Failed to delete old native lib" + e.message) | ||||||
|  |                    } | ||||||
|  |                } | ||||||
|  |            } | ||||||
|  |        } | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    @Throws(IOException::class) | ||||||
|  |    private fun InputStream.contentsEquals(other: InputStream): Boolean { | ||||||
|  |        val bufThis = this as? BufferedInputStream | ||||||
|  |            ?: BufferedInputStream(this) | ||||||
|  |        val bufOther = other as? BufferedInputStream | ||||||
|  |            ?: BufferedInputStream(other) | ||||||
|  |        var ch = bufThis.read() | ||||||
|  |        while (ch != -1) { | ||||||
|  |            val ch2 = bufOther.read() | ||||||
|  |            if (ch != ch2) return false | ||||||
|  |            ch = bufThis.read() | ||||||
|  |        } | ||||||
|  |        val ch2 = bufOther.read() | ||||||
|  |        return ch2 == -1 | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    /** | ||||||
|  |     * Extracts and loads the specified library file to the target folder | ||||||
|  |     * | ||||||
|  |     * @param libDir Library path. | ||||||
|  |     * @param libFileName       Library name. | ||||||
|  |     * @param targetDirectory          Target folder. | ||||||
|  |     * @return | ||||||
|  |     */ | ||||||
|  |    private fun extractAndLoadLibraryFile(libDir: String, libFileName: String, targetDirectory: String): Boolean { | ||||||
|  |        val libPath = "$libDir/$libFileName" | ||||||
|  |        // Include architecture name in temporary filename in order to avoid conflicts | ||||||
|  |        // when multiple JVMs with different architectures running at the same time | ||||||
|  |        val uuid = UUID.randomUUID().toString() | ||||||
|  |        val extractedLibFileName = String.format("secp256k1-%s-%s", uuid, libFileName) | ||||||
|  |        val extractedLckFileName = "$extractedLibFileName.lck" | ||||||
|  |        val extractedLibFile = File(targetDirectory, extractedLibFileName) | ||||||
|  |        val extractedLckFile = File(targetDirectory, extractedLckFileName) | ||||||
|  |        return try { | ||||||
|  |            // Extract a native library file into the target directory | ||||||
|  |            val reader = NativeSecp256k1Loader::class.java.getResourceAsStream(libPath) | ||||||
|  |            if (!extractedLckFile.exists()) { | ||||||
|  |                FileOutputStream(extractedLckFile).close() | ||||||
|  |            } | ||||||
|  |            val writer = FileOutputStream(extractedLibFile) | ||||||
|  |            try { | ||||||
|  |                val buffer = ByteArray(8192) | ||||||
|  |                var bytesRead = reader.read(buffer) | ||||||
|  |                while (bytesRead != -1) { | ||||||
|  |                    writer.write(buffer, 0, bytesRead) | ||||||
|  |                    bytesRead = reader.read(buffer) | ||||||
|  |                } | ||||||
|  |            } finally { | ||||||
|  |                // Delete the extracted lib file on JVM exit. | ||||||
|  |                extractedLibFile.deleteOnExit() | ||||||
|  |                extractedLckFile.deleteOnExit() | ||||||
|  |                writer.close() | ||||||
|  |                reader.close() | ||||||
|  |            } | ||||||
|  | 
 | ||||||
|  |            // Set executable (x) flag to enable Java to load the native library | ||||||
|  |            extractedLibFile.setReadable(true) | ||||||
|  |            extractedLibFile.setWritable(true, true) | ||||||
|  |            extractedLibFile.setExecutable(true) | ||||||
|  | 
 | ||||||
|  |            // Check whether the contents are properly copied from the resource folder | ||||||
|  |            NativeSecp256k1Loader::class.java.getResourceAsStream(libPath).use { nativeIn -> | ||||||
|  |                FileInputStream(extractedLibFile).use { extractedLibIn -> | ||||||
|  |                    if (!nativeIn.contentsEquals(extractedLibIn)) { | ||||||
|  |                        throw RuntimeException( | ||||||
|  |                            String.format( | ||||||
|  |                                "Failed to write a native library file at %s", | ||||||
|  |                                extractedLibFile | ||||||
|  |                            ) | ||||||
|  |                        ) | ||||||
|  |                    } | ||||||
|  |                } | ||||||
|  |            } | ||||||
|  | 
 | ||||||
|  |            loadNativeLibrary(targetDirectory, extractedLibFileName) | ||||||
|  |        } catch (e: IOException) { | ||||||
|  |            System.err.println(e.message) | ||||||
|  |            false | ||||||
|  |        } | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    /** | ||||||
|  |     * Loads native library using the given path and name of the library. | ||||||
|  |     * | ||||||
|  |     * @param path Path of the native library. | ||||||
|  |     * @param name Name  of the native library. | ||||||
|  |     * @return True for successfully loading; false otherwise. | ||||||
|  |     */ | ||||||
|  |    private fun loadNativeLibrary(path: String, name: String): Boolean { | ||||||
|  |        val libPath = File(path, name) | ||||||
|  |        return if (libPath.exists()) { | ||||||
|  |            try { | ||||||
|  |                System.load(File(path, name).absolutePath) | ||||||
|  |                true | ||||||
|  |            } catch (e: UnsatisfiedLinkError) { | ||||||
|  |                System.err.println("Failed to load native library:$name. osinfo: ${OSInfo.nativeSuffix}") | ||||||
|  |                System.err.println(e) | ||||||
|  |                false | ||||||
|  |            } | ||||||
|  |        } else { | ||||||
|  |            false | ||||||
|  |        } | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    /** | ||||||
|  |     * Loads secp256k1 native library using given path and name of the library. | ||||||
|  |     * | ||||||
|  |     * @throws | ||||||
|  |     */ | ||||||
|  |    private fun loadSecp256k1NativeLibrary() { | ||||||
|  |        if (extracted) { | ||||||
|  |            return | ||||||
|  |        } | ||||||
|  | 
 | ||||||
|  |        // Try loading library from fr.acinq.secp256k1.lib.path library path */ | ||||||
|  |        val libraryPath = System.getProperty("fr.acinq.secp256k1.lib.path") | ||||||
|  |        val libraryName = System.getProperty("fr.acinq.secp256k1.lib.name") ?: System.mapLibraryName("secp256k1-jni-${OSInfo.nativeSuffix}") | ||||||
|  |        if (libraryPath != null) { | ||||||
|  |            if (loadNativeLibrary(libraryPath, libraryName)) { | ||||||
|  |                extracted = true | ||||||
|  |                return | ||||||
|  |            } | ||||||
|  |        } | ||||||
|  | 
 | ||||||
|  |        // Load the os-dependent library from the jar file | ||||||
|  |        val packagePath = NativeSecp256k1Loader::class.java.getPackage().name.replace("\\.".toRegex(), "/") | ||||||
|  |        val embeddedLibraryPath = "/$packagePath/native" | ||||||
|  |        val hasNativeLib = NativeSecp256k1Loader::class.java.getResource("$embeddedLibraryPath/$libraryName") != null | ||||||
|  |        if (!hasNativeLib) { | ||||||
|  |            error("No native library found: at $embeddedLibraryPath/$libraryName") | ||||||
|  |        } | ||||||
|  | 
 | ||||||
|  |        // Try extracting the library from jar | ||||||
|  |        if (extractAndLoadLibraryFile(embeddedLibraryPath, libraryName, tempDir.absolutePath)) { | ||||||
|  |            extracted = true | ||||||
|  |            return | ||||||
|  |        } | ||||||
|  |        extracted = false | ||||||
|  |        return | ||||||
|  |    } | ||||||
|  | } | ||||||
							
								
								
									
										214
									
								
								jni/src/jvmMain/kotlin/fr/acinq/secp256k1/jni/OSInfo.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								jni/src/jvmMain/kotlin/fr/acinq/secp256k1/jni/OSInfo.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,214 @@ | |||||||
|  | package fr.acinq.secp256k1.jni | ||||||
|  | 
 | ||||||
|  | import java.io.ByteArrayOutputStream | ||||||
|  | import java.io.IOException | ||||||
|  | import java.util.* | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  | * Provides OS name and architecture name. | ||||||
|  | * | ||||||
|  | * @author leo | ||||||
|  | */ | ||||||
|  | @Suppress("DuplicatedCode") | ||||||
|  | internal object OSInfo { | ||||||
|  |    private val archMapping = HashMap<String, String>() | ||||||
|  |    private const val X86 = "x86" | ||||||
|  |    private const val X86_64 = "x86_64" | ||||||
|  |    private const val IA64_32 = "ia64_32" | ||||||
|  |    private const val IA64 = "ia64" | ||||||
|  |    private const val PPC = "ppc" | ||||||
|  |    private const val PPC64 = "ppc64" | ||||||
|  | 
 | ||||||
|  |    @JvmStatic val nativeSuffix: String get() = "$os-$arch" | ||||||
|  | 
 | ||||||
|  |    @JvmStatic val os: String get() = translateOSName(System.getProperty("os.name")) | ||||||
|  | 
 | ||||||
|  |    @JvmStatic val hardwareName: String get() = | ||||||
|  |        try { | ||||||
|  |            val p = Runtime.getRuntime().exec("uname -m") | ||||||
|  |            p.waitFor() | ||||||
|  |            val input = p.inputStream | ||||||
|  |            input.use { | ||||||
|  |                val b = ByteArrayOutputStream() | ||||||
|  |                val buf = ByteArray(32) | ||||||
|  |                var readLen = it.read(buf, 0, buf.size) | ||||||
|  |                while (readLen >= 0) { | ||||||
|  |                    b.write(buf, 0, readLen) | ||||||
|  |                    readLen = it.read(buf, 0, buf.size) | ||||||
|  |                } | ||||||
|  |                b.toString() | ||||||
|  |            } | ||||||
|  |        } catch (e: Throwable) { | ||||||
|  |            System.err.println("Error while running uname -m: " + e.message) | ||||||
|  |            "unknown" | ||||||
|  |        } | ||||||
|  | 
 | ||||||
|  |    @JvmStatic | ||||||
|  |    private fun resolveArmArchType(): String { | ||||||
|  |        if (System.getProperty("os.name").contains("Linux")) { | ||||||
|  |            val armType = hardwareName | ||||||
|  |            // armType (uname -m) can be armv5t, armv5te, armv5tej, armv5tejl, armv6, armv7, armv7l, aarch64, i686// ignored: fall back to "arm" arch (soft-float ABI) | ||||||
|  |            // ignored: fall back to "arm" arch (soft-float ABI) | ||||||
|  |            // determine if first JVM found uses ARM hard-float ABI | ||||||
|  |            when { | ||||||
|  |                armType.startsWith("armv6") -> { | ||||||
|  |                    // Raspberry PI | ||||||
|  |                    return "armv6" | ||||||
|  |                } | ||||||
|  |                armType.startsWith("armv7") -> { | ||||||
|  |                    // Generic | ||||||
|  |                    return "armv7" | ||||||
|  |                } | ||||||
|  |                armType.startsWith("armv5") -> { | ||||||
|  |                    // Use armv5, soft-float ABI | ||||||
|  |                    return "arm" | ||||||
|  |                } | ||||||
|  |                armType == "aarch64" -> { | ||||||
|  |                    // Use arm64 | ||||||
|  |                    return "arm64" | ||||||
|  |                } | ||||||
|  | 
 | ||||||
|  |                // Java 1.8 introduces a system property to determine armel or armhf | ||||||
|  |                // http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8005545 | ||||||
|  | 
 | ||||||
|  |                // For java7, we stil need to if run some shell commands to determine ABI of JVM | ||||||
|  |                else -> { | ||||||
|  |                    val abi = System.getProperty("sun.arch.abi") | ||||||
|  |                    if (abi != null && abi.startsWith("gnueabihf")) { | ||||||
|  |                        return "armv7" | ||||||
|  |                    } | ||||||
|  | 
 | ||||||
|  |                    // For java7, we stil need to if run some shell commands to determine ABI of JVM | ||||||
|  |                    val javaHome = System.getProperty("java.home") | ||||||
|  |                    try { | ||||||
|  |                        // determine if first JVM found uses ARM hard-float ABI | ||||||
|  |                        var exitCode = Runtime.getRuntime().exec("which readelf").waitFor() | ||||||
|  |                        if (exitCode == 0) { | ||||||
|  |                            val cmdarray = arrayOf( | ||||||
|  |                                "/bin/sh", "-c", "find '" + javaHome + | ||||||
|  |                                        "' -name 'libjvm.so' | head -1 | xargs readelf -A | " + | ||||||
|  |                                        "grep 'Tag_ABI_VFP_args: VFP registers'" | ||||||
|  |                            ) | ||||||
|  |                            exitCode = Runtime.getRuntime().exec(cmdarray).waitFor() | ||||||
|  |                            if (exitCode == 0) { | ||||||
|  |                                return "armv7" | ||||||
|  |                            } | ||||||
|  |                        } else { | ||||||
|  |                            System.err.println( | ||||||
|  |                                "WARNING! readelf not found. Cannot check if running on an armhf system, " + | ||||||
|  |                                        "armel architecture will be presumed." | ||||||
|  |                            ) | ||||||
|  |                        } | ||||||
|  |                    } catch (e: IOException) { | ||||||
|  |                        // ignored: fall back to "arm" arch (soft-float ABI) | ||||||
|  |                    } catch (e: InterruptedException) { | ||||||
|  |                        // ignored: fall back to "arm" arch (soft-float ABI) | ||||||
|  |                    } | ||||||
|  |                } | ||||||
|  |            } | ||||||
|  | 
 | ||||||
|  |            // Java 1.8 introduces a system property to determine armel or armhf | ||||||
|  |            // http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8005545 | ||||||
|  |            val abi = System.getProperty("sun.arch.abi") | ||||||
|  |            if (abi != null && abi.startsWith("gnueabihf")) { | ||||||
|  |                return "armv7" | ||||||
|  |            } | ||||||
|  | 
 | ||||||
|  |            // For java7, we stil need to if run some shell commands to determine ABI of JVM | ||||||
|  |            val javaHome = System.getProperty("java.home") | ||||||
|  |            try { | ||||||
|  |                // determine if first JVM found uses ARM hard-float ABI | ||||||
|  |                var exitCode = Runtime.getRuntime().exec("which readelf").waitFor() | ||||||
|  |                if (exitCode == 0) { | ||||||
|  |                    val cmdarray = arrayOf( | ||||||
|  |                        "/bin/sh", "-c", "find '" + javaHome + | ||||||
|  |                                "' -name 'libjvm.so' | head -1 | xargs readelf -A | " + | ||||||
|  |                                "grep 'Tag_ABI_VFP_args: VFP registers'" | ||||||
|  |                    ) | ||||||
|  |                    exitCode = Runtime.getRuntime().exec(cmdarray).waitFor() | ||||||
|  |                    if (exitCode == 0) { | ||||||
|  |                        return "armv7" | ||||||
|  |                    } | ||||||
|  |                } else { | ||||||
|  |                    System.err.println( | ||||||
|  |                        "WARNING! readelf not found. Cannot check if running on an armhf system, " + | ||||||
|  |                                "armel architecture will be presumed." | ||||||
|  |                    ) | ||||||
|  |                } | ||||||
|  |            } catch (e: IOException) { | ||||||
|  |                // ignored: fall back to "arm" arch (soft-float ABI) | ||||||
|  |            } catch (e: InterruptedException) { | ||||||
|  |                // ignored: fall back to "arm" arch (soft-float ABI) | ||||||
|  |            } | ||||||
|  |        } | ||||||
|  |        // Use armv5, soft-float ABI | ||||||
|  |        return "arm" | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    // For Android | ||||||
|  |    @JvmStatic | ||||||
|  |    val arch: String? | ||||||
|  |        get() { | ||||||
|  |            val systemOsArch = System.getProperty("os.arch") | ||||||
|  |            val osArch = | ||||||
|  |                if (systemOsArch.startsWith("arm")) { | ||||||
|  |                    resolveArmArchType() | ||||||
|  |                } else { | ||||||
|  |                    val lc = systemOsArch.toLowerCase(Locale.US) | ||||||
|  |                    if (archMapping.containsKey(lc)) return archMapping[lc] | ||||||
|  |                    systemOsArch | ||||||
|  |                } | ||||||
|  |            return translateArchNameToFolderName(osArch) | ||||||
|  |        } | ||||||
|  | 
 | ||||||
|  |    @JvmStatic | ||||||
|  |    fun translateOSName(osName: String): String = | ||||||
|  |        when { | ||||||
|  |            osName.contains("Windows") -> "mingw" | ||||||
|  |            osName.contains("Mac") || osName.contains("Darwin") -> "darwin" | ||||||
|  |            osName.contains("Linux") -> "linux" | ||||||
|  |            osName.contains("AIX") -> "aix" | ||||||
|  |            else -> osName.replace("\\W".toRegex(), "") | ||||||
|  |        } | ||||||
|  | 
 | ||||||
|  |    @JvmStatic | ||||||
|  |    fun translateArchNameToFolderName(archName: String): String = archName.replace("\\W".toRegex(), "") | ||||||
|  | 
 | ||||||
|  |    init { | ||||||
|  |        // x86 mappings | ||||||
|  |        archMapping[X86] = X86 | ||||||
|  |        archMapping["i386"] = X86 | ||||||
|  |        archMapping["i486"] = X86 | ||||||
|  |        archMapping["i586"] = X86 | ||||||
|  |        archMapping["i686"] = X86 | ||||||
|  |        archMapping["pentium"] = X86 | ||||||
|  | 
 | ||||||
|  |        // x86_64 mappings | ||||||
|  |        archMapping[X86_64] = X86_64 | ||||||
|  |        archMapping["amd64"] = X86_64 | ||||||
|  |        archMapping["em64t"] = X86_64 | ||||||
|  |        archMapping["universal"] = X86_64 // Needed for openjdk7 in Mac | ||||||
|  | 
 | ||||||
|  |        // Itenium 64-bit mappings | ||||||
|  |        archMapping[IA64] = IA64 | ||||||
|  |        archMapping["ia64w"] = IA64 | ||||||
|  | 
 | ||||||
|  |        // Itenium 32-bit mappings, usually an HP-UX construct | ||||||
|  |        archMapping[IA64_32] = IA64_32 | ||||||
|  |        archMapping["ia64n"] = IA64_32 | ||||||
|  | 
 | ||||||
|  |        // PowerPC mappings | ||||||
|  |        archMapping[PPC] = PPC | ||||||
|  |        archMapping["power"] = PPC | ||||||
|  |        archMapping["powerpc"] = PPC | ||||||
|  |        archMapping["power_pc"] = PPC | ||||||
|  |        archMapping["power_rs"] = PPC | ||||||
|  | 
 | ||||||
|  |        // TODO: PowerPC 64bit mappings | ||||||
|  |        archMapping[PPC64] = PPC64 | ||||||
|  |        archMapping["power64"] = PPC64 | ||||||
|  |        archMapping["powerpc64"] = PPC64 | ||||||
|  |        archMapping["power_pc64"] = PPC64 | ||||||
|  |        archMapping["power_rs64"] = PPC64 | ||||||
|  |    } | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								native/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								native/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | |||||||
|  | evaluationDependsOn(":jni") | ||||||
|  | 
 | ||||||
|  | val currentOs = org.gradle.internal.os.OperatingSystem.current() | ||||||
|  | 
 | ||||||
|  | val buildSecp256k1 by tasks.creating { group = "build" } | ||||||
|  | 
 | ||||||
|  | sealed class Cross { | ||||||
|  |     abstract fun cmd(target: String, nativeDir: File): List<String> | ||||||
|  |     class DockCross(val cross: String) : Cross() { | ||||||
|  |         override fun cmd(target: String, nativeDir: File): List<String> = listOf("./dockcross-$cross", "bash", "-c", "CROSS=1 TARGET=$target ./build.sh") | ||||||
|  |     } | ||||||
|  |     class MultiArch(val crossTriple: String) : Cross() { | ||||||
|  |         override fun cmd(target: String, nativeDir: File): List<String> { | ||||||
|  |             val uid = Runtime.getRuntime().exec("id -u").inputStream.use { it.reader().readText() }.trim().toInt() | ||||||
|  |             return listOf( | ||||||
|  |                 "docker", "run", "--rm", "-v", "${nativeDir.absolutePath}:/workdir", | ||||||
|  |                 "-e", "CROSS_TRIPLE=$crossTriple", "-e", "TARGET=$target", "-e", "TO_UID=$uid", "-e", "CROSS=1", | ||||||
|  |                 "multiarch/crossbuild", "./build.sh" | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | val buildSecp256k1Jvm by tasks.creating { | ||||||
|  |     group = "build" | ||||||
|  |     buildSecp256k1.dependsOn(this) | ||||||
|  | } | ||||||
|  | fun creatingBuildSecp256k1(target: String, cross: Cross?) = tasks.creating(Exec::class) { | ||||||
|  |     group = "build" | ||||||
|  |     buildSecp256k1Jvm.dependsOn(this) | ||||||
|  | 
 | ||||||
|  |     inputs.files(projectDir.resolve("build.sh")) | ||||||
|  |     outputs.dir(projectDir.resolve("build/$target")) | ||||||
|  | 
 | ||||||
|  |     workingDir = projectDir | ||||||
|  |     environment("TARGET", target) | ||||||
|  |     commandLine((cross?.cmd(target, workingDir) ?: emptyList()) + "./build.sh") | ||||||
|  | } | ||||||
|  | val buildSecp256k1Darwin by creatingBuildSecp256k1("darwin", if (currentOs.isMacOsX) null else Cross.MultiArch("x86_64-apple-darwin")) | ||||||
|  | val buildSecp256k1Linux by creatingBuildSecp256k1("linux", if (currentOs.isLinux) null else Cross.DockCross("linux-x64")) | ||||||
|  | val buildSecp256k1Mingw by creatingBuildSecp256k1("mingw", if (currentOs.isWindows) null else Cross.DockCross("windows-x64")) | ||||||
|  | 
 | ||||||
|  | val buildSecp256k1Ios by tasks.creating(Exec::class) { | ||||||
|  |     group = "build" | ||||||
|  |     buildSecp256k1.dependsOn(this) | ||||||
|  | 
 | ||||||
|  |     onlyIf { currentOs.isMacOsX } | ||||||
|  | 
 | ||||||
|  |     inputs.files(projectDir.resolve("build-ios.sh")) | ||||||
|  |     outputs.dir(projectDir.resolve("build/ios")) | ||||||
|  | 
 | ||||||
|  |     workingDir = projectDir | ||||||
|  |     commandLine("./build-ios.sh") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | val buildSecp256k1Android by tasks.creating { | ||||||
|  |     group = "build" | ||||||
|  |     buildSecp256k1.dependsOn(this) | ||||||
|  | } | ||||||
|  | fun creatingBuildSecp256k1Android(arch: String) = tasks.creating(Exec::class) { | ||||||
|  |     group = "build" | ||||||
|  |     buildSecp256k1Android.dependsOn(this) | ||||||
|  | 
 | ||||||
|  |     inputs.files(projectDir.resolve("build-android.sh")) | ||||||
|  |     outputs.dir(projectDir.resolve("build/android/$arch")) | ||||||
|  | 
 | ||||||
|  |     workingDir = projectDir | ||||||
|  | 
 | ||||||
|  |     val toolchain = when { | ||||||
|  |         currentOs.isLinux -> "linux-x86_64" | ||||||
|  |         currentOs.isMacOsX -> "darwin-x86_64" | ||||||
|  |         currentOs.isWindows -> "windows-x86_64" | ||||||
|  |         else -> error("No Android toolchain defined for this OS: $currentOs") | ||||||
|  |     } | ||||||
|  |     environment("TOOLCHAIN", toolchain) | ||||||
|  |     environment("ARCH", arch) | ||||||
|  |     environment("ANDROID_NDK", (project(":jni").extensions["android"] as com.android.build.gradle.LibraryExtension).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") | ||||||
|  | 
 | ||||||
|  | val clean by tasks.creating { | ||||||
|  |     doLast { | ||||||
|  |         delete(projectDir.resolve("build")) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -5,12 +5,10 @@ pluginManagement { | |||||||
|         gradlePluginPortal() |         gradlePluginPortal() | ||||||
|         jcenter() |         jcenter() | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     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" | ||||||
| 
 | 
 | ||||||
|  | include( | ||||||
|  |     ":native", | ||||||
|  |     ":jni" | ||||||
|  | ) | ||||||
| @ -1,14 +0,0 @@ | |||||||
| 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 |  | ||||||
| ) |  | ||||||
| @ -1,15 +0,0 @@ | |||||||
| 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") |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -17,7 +17,6 @@ | |||||||
| package fr.acinq.secp256k1 | package fr.acinq.secp256k1 | ||||||
| 
 | 
 | ||||||
| import kotlin.jvm.JvmStatic | import kotlin.jvm.JvmStatic | ||||||
| import kotlin.jvm.Synchronized |  | ||||||
| 
 | 
 | ||||||
| public enum class SigFormat(internal val size: Int) { COMPACT(64), DER(72) } | public enum class SigFormat(internal val size: Int) { COMPACT(64), DER(72) } | ||||||
| 
 | 
 | ||||||
| @ -25,37 +24,54 @@ public enum class PubKeyFormat(internal val size: Int) { COMPRESSED(33), UNCOMPR | |||||||
| 
 | 
 | ||||||
| public expect object Secp256k1 { | public expect object Secp256k1 { | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean |     public fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun sign(data: ByteArray, sec: ByteArray, format: SigFormat): ByteArray |     public fun sign(data: ByteArray, sec: ByteArray, format: SigFormat): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun signatureNormalize(sig: ByteArray, format: SigFormat): Pair<ByteArray, Boolean> |     public fun signatureNormalize(sig: ByteArray, format: SigFormat): Pair<ByteArray, Boolean> | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun secKeyVerify(seckey: ByteArray): Boolean |     public fun secKeyVerify(seckey: ByteArray): Boolean | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun computePubkey(seckey: ByteArray, format: PubKeyFormat): ByteArray |     public fun computePubkey(seckey: ByteArray, format: PubKeyFormat): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun parsePubkey(pubkey: ByteArray, format: PubKeyFormat): ByteArray |     public fun parsePubkey(pubkey: ByteArray, format: PubKeyFormat): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun cleanup() |     public fun cleanup() | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun privKeyNegate(privkey: ByteArray): ByteArray |     public fun privKeyNegate(privkey: ByteArray): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray |     public fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray |     public fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun pubKeyNegate(pubkey: ByteArray): ByteArray |     public fun pubKeyNegate(pubkey: ByteArray): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray |     public fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray |     public fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray |     public fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray |     public fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, format: PubKeyFormat): ByteArray |     public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, format: PubKeyFormat): ByteArray | ||||||
| 
 | 
 | ||||||
|  |     @JvmStatic | ||||||
|     public fun randomize(seed: ByteArray): Boolean |     public fun randomize(seed: ByteArray): Boolean | ||||||
| } | } | ||||||
| @ -1,228 +0,0 @@ | |||||||
| package fr.acinq.secp256k1 |  | ||||||
| 
 |  | ||||||
| import java.io.ByteArrayOutputStream |  | ||||||
| import java.io.IOException |  | ||||||
| import java.util.* |  | ||||||
| 
 |  | ||||||
| /*-------------------------------------------------------------------------- |  | ||||||
|  *  Copyright 2008 Taro L. Saito |  | ||||||
|  * |  | ||||||
|  *  Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
|  *  you may not use this file except in compliance with the License. |  | ||||||
|  *  You may obtain a copy of the License at |  | ||||||
|  * |  | ||||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
|  * |  | ||||||
|  *  Unless required by applicable law or agreed to in writing, software |  | ||||||
|  *  distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
|  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
|  *  See the License for the specific language governing permissions and |  | ||||||
|  *  limitations under the License. |  | ||||||
|  *--------------------------------------------------------------------------*/ /** |  | ||||||
|  * Provides OS name and architecture name. |  | ||||||
|  * |  | ||||||
|  * @author leo |  | ||||||
|  */ |  | ||||||
| @Suppress("DuplicatedCode") |  | ||||||
| internal object OSInfo { |  | ||||||
|     private val archMapping = HashMap<String, String>() |  | ||||||
|     private const val X86 = "x86" |  | ||||||
|     private const val X86_64 = "x86_64" |  | ||||||
|     private const val IA64_32 = "ia64_32" |  | ||||||
|     private const val IA64 = "ia64" |  | ||||||
|     private const val PPC = "ppc" |  | ||||||
|     private const val PPC64 = "ppc64" |  | ||||||
| 
 |  | ||||||
|     @JvmStatic val nativeSuffix: String get() = "$os-$arch" |  | ||||||
| 
 |  | ||||||
|     @JvmStatic val os: String get() = translateOSName(System.getProperty("os.name")) |  | ||||||
| 
 |  | ||||||
|     @JvmStatic val hardwareName: String get() = |  | ||||||
|         try { |  | ||||||
|             val p = Runtime.getRuntime().exec("uname -m") |  | ||||||
|             p.waitFor() |  | ||||||
|             val input = p.inputStream |  | ||||||
|             input.use { |  | ||||||
|                 val b = ByteArrayOutputStream() |  | ||||||
|                 val buf = ByteArray(32) |  | ||||||
|                 var readLen = it.read(buf, 0, buf.size) |  | ||||||
|                 while (readLen >= 0) { |  | ||||||
|                     b.write(buf, 0, readLen) |  | ||||||
|                     readLen = it.read(buf, 0, buf.size) |  | ||||||
|                 } |  | ||||||
|                 b.toString() |  | ||||||
|             } |  | ||||||
|         } catch (e: Throwable) { |  | ||||||
|             System.err.println("Error while running uname -m: " + e.message) |  | ||||||
|             "unknown" |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     @JvmStatic |  | ||||||
|     private fun resolveArmArchType(): String { |  | ||||||
|         if (System.getProperty("os.name").contains("Linux")) { |  | ||||||
|             val armType = hardwareName |  | ||||||
|             // armType (uname -m) can be armv5t, armv5te, armv5tej, armv5tejl, armv6, armv7, armv7l, aarch64, i686// ignored: fall back to "arm" arch (soft-float ABI) |  | ||||||
|             // ignored: fall back to "arm" arch (soft-float ABI) |  | ||||||
|             // determine if first JVM found uses ARM hard-float ABI |  | ||||||
|             when { |  | ||||||
|                 armType.startsWith("armv6") -> { |  | ||||||
|                     // Raspberry PI |  | ||||||
|                     return "armv6" |  | ||||||
|                 } |  | ||||||
|                 armType.startsWith("armv7") -> { |  | ||||||
|                     // Generic |  | ||||||
|                     return "armv7" |  | ||||||
|                 } |  | ||||||
|                 armType.startsWith("armv5") -> { |  | ||||||
|                     // Use armv5, soft-float ABI |  | ||||||
|                     return "arm" |  | ||||||
|                 } |  | ||||||
|                 armType == "aarch64" -> { |  | ||||||
|                     // Use arm64 |  | ||||||
|                     return "arm64" |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 // Java 1.8 introduces a system property to determine armel or armhf |  | ||||||
|                 // http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8005545 |  | ||||||
| 
 |  | ||||||
|                 // For java7, we stil need to if run some shell commands to determine ABI of JVM |  | ||||||
|                 else -> { |  | ||||||
|                     val abi = System.getProperty("sun.arch.abi") |  | ||||||
|                     if (abi != null && abi.startsWith("gnueabihf")) { |  | ||||||
|                         return "armv7" |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     // For java7, we stil need to if run some shell commands to determine ABI of JVM |  | ||||||
|                     val javaHome = System.getProperty("java.home") |  | ||||||
|                     try { |  | ||||||
|                         // determine if first JVM found uses ARM hard-float ABI |  | ||||||
|                         var exitCode = Runtime.getRuntime().exec("which readelf").waitFor() |  | ||||||
|                         if (exitCode == 0) { |  | ||||||
|                             val cmdarray = arrayOf( |  | ||||||
|                                 "/bin/sh", "-c", "find '" + javaHome + |  | ||||||
|                                         "' -name 'libjvm.so' | head -1 | xargs readelf -A | " + |  | ||||||
|                                         "grep 'Tag_ABI_VFP_args: VFP registers'" |  | ||||||
|                             ) |  | ||||||
|                             exitCode = Runtime.getRuntime().exec(cmdarray).waitFor() |  | ||||||
|                             if (exitCode == 0) { |  | ||||||
|                                 return "armv7" |  | ||||||
|                             } |  | ||||||
|                         } else { |  | ||||||
|                             System.err.println( |  | ||||||
|                                 "WARNING! readelf not found. Cannot check if running on an armhf system, " + |  | ||||||
|                                         "armel architecture will be presumed." |  | ||||||
|                             ) |  | ||||||
|                         } |  | ||||||
|                     } catch (e: IOException) { |  | ||||||
|                         // ignored: fall back to "arm" arch (soft-float ABI) |  | ||||||
|                     } catch (e: InterruptedException) { |  | ||||||
|                         // ignored: fall back to "arm" arch (soft-float ABI) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Java 1.8 introduces a system property to determine armel or armhf |  | ||||||
|             // http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8005545 |  | ||||||
|             val abi = System.getProperty("sun.arch.abi") |  | ||||||
|             if (abi != null && abi.startsWith("gnueabihf")) { |  | ||||||
|                 return "armv7" |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // For java7, we stil need to if run some shell commands to determine ABI of JVM |  | ||||||
|             val javaHome = System.getProperty("java.home") |  | ||||||
|             try { |  | ||||||
|                 // determine if first JVM found uses ARM hard-float ABI |  | ||||||
|                 var exitCode = Runtime.getRuntime().exec("which readelf").waitFor() |  | ||||||
|                 if (exitCode == 0) { |  | ||||||
|                     val cmdarray = arrayOf( |  | ||||||
|                         "/bin/sh", "-c", "find '" + javaHome + |  | ||||||
|                                 "' -name 'libjvm.so' | head -1 | xargs readelf -A | " + |  | ||||||
|                                 "grep 'Tag_ABI_VFP_args: VFP registers'" |  | ||||||
|                     ) |  | ||||||
|                     exitCode = Runtime.getRuntime().exec(cmdarray).waitFor() |  | ||||||
|                     if (exitCode == 0) { |  | ||||||
|                         return "armv7" |  | ||||||
|                     } |  | ||||||
|                 } else { |  | ||||||
|                     System.err.println( |  | ||||||
|                         "WARNING! readelf not found. Cannot check if running on an armhf system, " + |  | ||||||
|                                 "armel architecture will be presumed." |  | ||||||
|                     ) |  | ||||||
|                 } |  | ||||||
|             } catch (e: IOException) { |  | ||||||
|                 // ignored: fall back to "arm" arch (soft-float ABI) |  | ||||||
|             } catch (e: InterruptedException) { |  | ||||||
|                 // ignored: fall back to "arm" arch (soft-float ABI) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         // Use armv5, soft-float ABI |  | ||||||
|         return "arm" |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // For Android |  | ||||||
|     @JvmStatic |  | ||||||
|     val arch: String? |  | ||||||
|         get() { |  | ||||||
|             val systemOsArch = System.getProperty("os.arch") |  | ||||||
|             val osArch = |  | ||||||
|                 if (systemOsArch.startsWith("arm")) { |  | ||||||
|                     resolveArmArchType() |  | ||||||
|                 } else { |  | ||||||
|                     val lc = systemOsArch.toLowerCase(Locale.US) |  | ||||||
|                     if (archMapping.containsKey(lc)) return archMapping[lc] |  | ||||||
|                     systemOsArch |  | ||||||
|                 } |  | ||||||
|             return translateArchNameToFolderName(osArch) |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     @JvmStatic |  | ||||||
|     fun translateOSName(osName: String): String = |  | ||||||
|         when { |  | ||||||
|             osName.contains("Windows") -> "mingw" |  | ||||||
|             osName.contains("Mac") || osName.contains("Darwin") -> "darwin" |  | ||||||
|             osName.contains("Linux") -> "linux" |  | ||||||
|             osName.contains("AIX") -> "aix" |  | ||||||
|             else -> osName.replace("\\W".toRegex(), "") |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     @JvmStatic |  | ||||||
|     fun translateArchNameToFolderName(archName: String): String = archName.replace("\\W".toRegex(), "") |  | ||||||
| 
 |  | ||||||
|     init { |  | ||||||
|         // x86 mappings |  | ||||||
|         archMapping[X86] = X86 |  | ||||||
|         archMapping["i386"] = X86 |  | ||||||
|         archMapping["i486"] = X86 |  | ||||||
|         archMapping["i586"] = X86 |  | ||||||
|         archMapping["i686"] = X86 |  | ||||||
|         archMapping["pentium"] = X86 |  | ||||||
| 
 |  | ||||||
|         // x86_64 mappings |  | ||||||
|         archMapping[X86_64] = X86_64 |  | ||||||
|         archMapping["amd64"] = X86_64 |  | ||||||
|         archMapping["em64t"] = X86_64 |  | ||||||
|         archMapping["universal"] = X86_64 // Needed for openjdk7 in Mac |  | ||||||
| 
 |  | ||||||
|         // Itenium 64-bit mappings |  | ||||||
|         archMapping[IA64] = IA64 |  | ||||||
|         archMapping["ia64w"] = IA64 |  | ||||||
| 
 |  | ||||||
|         // Itenium 32-bit mappings, usually an HP-UX construct |  | ||||||
|         archMapping[IA64_32] = IA64_32 |  | ||||||
|         archMapping["ia64n"] = IA64_32 |  | ||||||
| 
 |  | ||||||
|         // PowerPC mappings |  | ||||||
|         archMapping[PPC] = PPC |  | ||||||
|         archMapping["power"] = PPC |  | ||||||
|         archMapping["powerpc"] = PPC |  | ||||||
|         archMapping["power_pc"] = PPC |  | ||||||
|         archMapping["power_rs"] = PPC |  | ||||||
| 
 |  | ||||||
|         // TODO: PowerPC 64bit mappings |  | ||||||
|         archMapping[PPC64] = PPC64 |  | ||||||
|         archMapping["power64"] = PPC64 |  | ||||||
|         archMapping["powerpc64"] = PPC64 |  | ||||||
|         archMapping["power_pc64"] = PPC64 |  | ||||||
|         archMapping["power_rs64"] = PPC64 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -17,15 +17,18 @@ | |||||||
| package fr.acinq.secp256k1 | package fr.acinq.secp256k1 | ||||||
| 
 | 
 | ||||||
| import org.bitcoin.NativeSecp256k1 | import org.bitcoin.NativeSecp256k1 | ||||||
| 
 | import java.lang.IllegalStateException | ||||||
| internal expect object Secp256k1Loader { |  | ||||||
|     fun initialize() |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| public actual object Secp256k1 { | public actual object Secp256k1 { | ||||||
| 
 | 
 | ||||||
|     init { |     init { | ||||||
|         Secp256k1Loader.initialize() |         try { | ||||||
|  |             val cls = Class.forName("fr.acinq.secp256k1.jni.NativeSecp256k1Loader") | ||||||
|  |             val load = cls.getMethod("load") | ||||||
|  |             load.invoke(null) | ||||||
|  |         } catch (ex: ClassNotFoundException) { | ||||||
|  |             throw IllegalStateException("Could not load native Secp256k1 JNI library. Have you added the JNI dependency?", ex) | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public actual fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean = NativeSecp256k1.verify(data, signature, pub) |     public actual fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean = NativeSecp256k1.verify(data, signature, pub) | ||||||
| @ -1,218 +0,0 @@ | |||||||
| package fr.acinq.secp256k1 |  | ||||||
| 
 |  | ||||||
| import java.io.* |  | ||||||
| import java.util.* |  | ||||||
| 
 |  | ||||||
| /*-------------------------------------------------------------------------- |  | ||||||
|  *  Copyright 2007 Taro L. Saito |  | ||||||
|  * |  | ||||||
|  *  Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
|  *  you may not use this file except in compliance with the License. |  | ||||||
|  *  You may obtain a copy of the License at |  | ||||||
|  * |  | ||||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
|  * |  | ||||||
|  *  Unless required by applicable law or agreed to in writing, software |  | ||||||
|  *  distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
|  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
|  *  See the License for the specific language governing permissions and |  | ||||||
|  *  limitations under the License. |  | ||||||
|  *--------------------------------------------------------------------------*/ /** |  | ||||||
|  * Set the system properties, org.sqlite.lib.path, org.sqlite.lib.name, |  | ||||||
|  * appropriately so that the SQLite JDBC driver can find *.dll, *.jnilib and |  | ||||||
|  * *.so files, according to the current OS (win, linux, mac). |  | ||||||
|  * The library files are automatically extracted from this project's package (JAR). |  | ||||||
|  * usage: call [.initialize] before using SQLite JDBC driver. |  | ||||||
|  * |  | ||||||
|  * @author leo |  | ||||||
|  */ |  | ||||||
| internal actual object Secp256k1Loader { |  | ||||||
|     private var extracted = false |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Loads secp256k1 native library. |  | ||||||
|      * |  | ||||||
|      * @return True if secp256k1 native library is successfully loaded; false otherwise. |  | ||||||
|      * @throws Exception if loading fails |  | ||||||
|      */ |  | ||||||
|     @JvmStatic |  | ||||||
|     @Synchronized |  | ||||||
|     @Throws(Exception::class) |  | ||||||
|     actual fun initialize() { |  | ||||||
|         // only cleanup before the first extract |  | ||||||
|         if (!extracted) { |  | ||||||
|             cleanup() |  | ||||||
|         } |  | ||||||
|         loadSecp256k1NativeLibrary() |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private val tempDir: File |  | ||||||
|         get() = File(System.getProperty("fr.acinq.secp256k1.tmpdir", System.getProperty("java.io.tmpdir"))) |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Deleted old native libraries e.g. on Windows the DLL file is not removed |  | ||||||
|      * on VM-Exit (bug #80) |  | ||||||
|      */ |  | ||||||
|     @JvmStatic |  | ||||||
|     fun cleanup() { |  | ||||||
|         val tempFolder = tempDir.absolutePath |  | ||||||
|         val dir = File(tempFolder) |  | ||||||
|         val nativeLibFiles = dir.listFiles(object : FilenameFilter { |  | ||||||
|             private val searchPattern = "secp256k1-" |  | ||||||
|             override fun accept(dir: File, name: String): Boolean { |  | ||||||
|                 return name.startsWith(searchPattern) && !name.endsWith(".lck") |  | ||||||
|             } |  | ||||||
|         }) |  | ||||||
|         if (nativeLibFiles != null) { |  | ||||||
|             for (nativeLibFile in nativeLibFiles) { |  | ||||||
|                 val lckFile = File(nativeLibFile.absolutePath + ".lck") |  | ||||||
|                 if (!lckFile.exists()) { |  | ||||||
|                     try { |  | ||||||
|                         nativeLibFile.delete() |  | ||||||
|                     } catch (e: SecurityException) { |  | ||||||
|                         System.err.println("Failed to delete old native lib" + e.message) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Throws(IOException::class) |  | ||||||
|     private fun InputStream.contentsEquals(other: InputStream): Boolean { |  | ||||||
|         val bufThis = this as? BufferedInputStream ?: BufferedInputStream(this) |  | ||||||
|         val bufOther = other as? BufferedInputStream ?: BufferedInputStream(other) |  | ||||||
|         var ch = bufThis.read() |  | ||||||
|         while (ch != -1) { |  | ||||||
|             val ch2 = bufOther.read() |  | ||||||
|             if (ch != ch2) return false |  | ||||||
|             ch = bufThis.read() |  | ||||||
|         } |  | ||||||
|         val ch2 = bufOther.read() |  | ||||||
|         return ch2 == -1 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Extracts and loads the specified library file to the target folder |  | ||||||
|      * |  | ||||||
|      * @param libDir Library path. |  | ||||||
|      * @param libFileName       Library name. |  | ||||||
|      * @param targetDirectory          Target folder. |  | ||||||
|      * @return |  | ||||||
|      */ |  | ||||||
|     private fun extractAndLoadLibraryFile(libDir: String, libFileName: String, targetDirectory: String): Boolean { |  | ||||||
|         val libPath = "$libDir/$libFileName" |  | ||||||
|         // Include architecture name in temporary filename in order to avoid conflicts |  | ||||||
|         // when multiple JVMs with different architectures running at the same time |  | ||||||
|         val uuid = UUID.randomUUID().toString() |  | ||||||
|         val extractedLibFileName = String.format("secp256k1-%s-%s", uuid, libFileName) |  | ||||||
|         val extractedLckFileName = "$extractedLibFileName.lck" |  | ||||||
|         val extractedLibFile = File(targetDirectory, extractedLibFileName) |  | ||||||
|         val extractedLckFile = File(targetDirectory, extractedLckFileName) |  | ||||||
|         return try { |  | ||||||
|             // Extract a native library file into the target directory |  | ||||||
|             val reader = Secp256k1Loader::class.java.getResourceAsStream(libPath) |  | ||||||
|             if (!extractedLckFile.exists()) { |  | ||||||
|                 FileOutputStream(extractedLckFile).close() |  | ||||||
|             } |  | ||||||
|             val writer = FileOutputStream(extractedLibFile) |  | ||||||
|             try { |  | ||||||
|                 val buffer = ByteArray(8192) |  | ||||||
|                 var bytesRead = reader.read(buffer) |  | ||||||
|                 while (bytesRead != -1) { |  | ||||||
|                     writer.write(buffer, 0, bytesRead) |  | ||||||
|                     bytesRead = reader.read(buffer) |  | ||||||
|                 } |  | ||||||
|             } finally { |  | ||||||
|                 // Delete the extracted lib file on JVM exit. |  | ||||||
|                 extractedLibFile.deleteOnExit() |  | ||||||
|                 extractedLckFile.deleteOnExit() |  | ||||||
|                 writer.close() |  | ||||||
|                 reader.close() |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Set executable (x) flag to enable Java to load the native library |  | ||||||
|             extractedLibFile.setReadable(true) |  | ||||||
|             extractedLibFile.setWritable(true, true) |  | ||||||
|             extractedLibFile.setExecutable(true) |  | ||||||
| 
 |  | ||||||
|             // Check whether the contents are properly copied from the resource folder |  | ||||||
|             Secp256k1Loader::class.java.getResourceAsStream(libPath).use { nativeIn -> |  | ||||||
|                 FileInputStream(extractedLibFile).use { extractedLibIn -> |  | ||||||
|                     if (!nativeIn.contentsEquals(extractedLibIn)) { |  | ||||||
|                         throw RuntimeException( |  | ||||||
|                             String.format( |  | ||||||
|                                 "Failed to write a native library file at %s", |  | ||||||
|                                 extractedLibFile |  | ||||||
|                             ) |  | ||||||
|                         ) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             loadNativeLibrary(targetDirectory, extractedLibFileName) |  | ||||||
|         } catch (e: IOException) { |  | ||||||
|             System.err.println(e.message) |  | ||||||
|             false |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Loads native library using the given path and name of the library. |  | ||||||
|      * |  | ||||||
|      * @param path Path of the native library. |  | ||||||
|      * @param name Name  of the native library. |  | ||||||
|      * @return True for successfully loading; false otherwise. |  | ||||||
|      */ |  | ||||||
|     private fun loadNativeLibrary(path: String, name: String): Boolean { |  | ||||||
|         val libPath = File(path, name) |  | ||||||
|         return if (libPath.exists()) { |  | ||||||
|             try { |  | ||||||
|                 System.load(File(path, name).absolutePath) |  | ||||||
|                 true |  | ||||||
|             } catch (e: UnsatisfiedLinkError) { |  | ||||||
|                 System.err.println("Failed to load native library:$name. osinfo: ${OSInfo.nativeSuffix}") |  | ||||||
|                 System.err.println(e) |  | ||||||
|                 false |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             false |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Loads secp256k1 native library using given path and name of the library. |  | ||||||
|      * |  | ||||||
|      * @throws |  | ||||||
|      */ |  | ||||||
|     private fun loadSecp256k1NativeLibrary() { |  | ||||||
|         if (extracted) { |  | ||||||
|             return |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Try loading library from fr.acinq.secp256k1.lib.path library path */ |  | ||||||
|         val libraryPath = System.getProperty("fr.acinq.secp256k1.lib.path") |  | ||||||
|         val libraryName = System.getProperty("fr.acinq.secp256k1.lib.name") ?: System.mapLibraryName("secp256k1-jni-${OSInfo.nativeSuffix}") |  | ||||||
|         if (libraryPath != null) { |  | ||||||
|             if (loadNativeLibrary(libraryPath, libraryName)) { |  | ||||||
|                 extracted = true |  | ||||||
|                 return |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Load the os-dependent library from the jar file |  | ||||||
|         val packagePath = Secp256k1Loader::class.java.getPackage().name.replace("\\.".toRegex(), "/") |  | ||||||
|         val embeddedLibraryPath = "/$packagePath/native" |  | ||||||
|         val hasNativeLib = Secp256k1Loader::class.java.getResource("$embeddedLibraryPath/$libraryName") != null |  | ||||||
|         if (!hasNativeLib) { |  | ||||||
|             error("No native library found: at $embeddedLibraryPath/$libraryName") |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Try extracting the library from jar |  | ||||||
|         if (extractAndLoadLibraryFile(embeddedLibraryPath, libraryName, tempDir.absolutePath)) { |  | ||||||
|             extracted = true |  | ||||||
|             return |  | ||||||
|         } |  | ||||||
|         extracted = false |  | ||||||
|         return |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										565
									
								
								src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										565
									
								
								src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,565 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2013 Google Inc. | ||||||
|  |  * Copyright 2014-2016 the libsecp256k1 contributors | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *    http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | package org.bitcoin | ||||||
|  | 
 | ||||||
|  | import org.bitcoin.NativeSecp256k1Util.AssertFailException | ||||||
|  | import java.math.BigInteger | ||||||
|  | import java.nio.ByteBuffer | ||||||
|  | import java.nio.ByteOrder | ||||||
|  | import java.util.concurrent.locks.Lock | ||||||
|  | import java.util.concurrent.locks.ReentrantReadWriteLock | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * | ||||||
|  |  * This class holds native methods to handle ECDSA verification. | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  * You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1 | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  * To build secp256k1 for use with bitcoinj, run | ||||||
|  |  * `./configure --enable-jni --enable-experimental --enable-module-ecdh` | ||||||
|  |  * and `make` then copy `.libs/libsecp256k1.so` to your system library path | ||||||
|  |  * or point the JVM to the folder containing it with -Djava.library.path | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | public object NativeSecp256k1 { | ||||||
|  |     private val rwl = ReentrantReadWriteLock() | ||||||
|  |     private val r: Lock = rwl.readLock() | ||||||
|  |     private val w: Lock = rwl.writeLock() | ||||||
|  |     private val nativeECDSABuffer = ThreadLocal<ByteBuffer?>() | ||||||
|  | 
 | ||||||
|  |     private fun pack(vararg buffers: ByteArray): ByteBuffer { | ||||||
|  |         var size = 0 | ||||||
|  |         for (i in buffers.indices) { | ||||||
|  |             size += buffers[i].size | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         val byteBuff = nativeECDSABuffer.get()?.takeIf { it.capacity() >= size } | ||||||
|  |             ?: ByteBuffer.allocateDirect(size).also { | ||||||
|  |                 it.order(ByteOrder.nativeOrder()) | ||||||
|  |                 nativeECDSABuffer.set(it) | ||||||
|  |             } | ||||||
|  |         byteBuff.rewind() | ||||||
|  |         for (i in buffers.indices) { | ||||||
|  |             byteBuff.put(buffers[i]) | ||||||
|  |         } | ||||||
|  |         return byteBuff | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Verifies the given secp256k1 signature in native code. | ||||||
|  |      * Calling when enabled == false is undefined (probably library not loaded) | ||||||
|  |      * | ||||||
|  |      * @param data      The data which was signed, must be exactly 32 bytes | ||||||
|  |      * @param signature The signature | ||||||
|  |      * @param pub       The public key which did the signing | ||||||
|  |      * @return true if the signature is valid | ||||||
|  |      * @throws AssertFailException in case of failure | ||||||
|  |      */ | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean { | ||||||
|  |         require(data.size == 32 && signature.size <= 520 && pub.size <= 520) | ||||||
|  |         val byteBuff = pack(data, signature, pub) | ||||||
|  |         r.lock() | ||||||
|  |         return try { | ||||||
|  |             secp256k1_ecdsa_verify( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext(), | ||||||
|  |                 signature.size, | ||||||
|  |                 pub.size | ||||||
|  |             ) == 1 | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * libsecp256k1 Create an ECDSA signature. | ||||||
|  |      * | ||||||
|  |      * @param data    Message hash, 32 bytes | ||||||
|  |      * @param sec     Secret key, 32 bytes | ||||||
|  |      * @param compact True for compact signature, false for DER | ||||||
|  |      * @return a signature, or an empty array is signing failed | ||||||
|  |      * @throws AssertFailException in case of failure | ||||||
|  |      */ | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun sign(data: ByteArray, sec: ByteArray, compact: Boolean): ByteArray { | ||||||
|  |         require(data.size == 32 && sec.size <= 32) | ||||||
|  |         val byteBuff = pack(data, sec) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_ecdsa_sign( | ||||||
|  |                 byteBuff, | ||||||
|  |                 compact, | ||||||
|  |                 Secp256k1Context.getContext() | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val sigArr = retByteArray[0] | ||||||
|  |         val sigLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals( | ||||||
|  |             sigArr.size, | ||||||
|  |             sigLen, | ||||||
|  |             "Got bad signature length." | ||||||
|  |         ) | ||||||
|  |         return if (retVal == 0) ByteArray(0) else sigArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun signatureNormalize(sig: ByteArray, compact: Boolean): Pair<ByteArray, Boolean> { | ||||||
|  |         require(sig.size == 64 || sig.size in 70..73) | ||||||
|  |         val byteBuff = pack(sig) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_ecdsa_normalize( | ||||||
|  |                 byteBuff, | ||||||
|  |                 sig.size, | ||||||
|  |                 compact, | ||||||
|  |                 Secp256k1Context.getContext() | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val sigArr = retByteArray[0] | ||||||
|  |         val sigLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() | ||||||
|  |         val retBool = BigInteger(byteArrayOf(retByteArray[1][2])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals( | ||||||
|  |             sigArr.size, | ||||||
|  |             sigLen, | ||||||
|  |             "Got bad signature length." | ||||||
|  |         ) | ||||||
|  |         return (if (retVal == 0) ByteArray(0) else sigArr) to (retBool == 1) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid | ||||||
|  |      * | ||||||
|  |      * @param seckey ECDSA Secret key, 32 bytes | ||||||
|  |      * @return true if seckey is valid | ||||||
|  |      */ | ||||||
|  |     @JvmStatic | ||||||
|  |     public fun secKeyVerify(seckey: ByteArray): Boolean { | ||||||
|  |         require(seckey.size == 32) | ||||||
|  |         val byteBuff = pack(seckey) | ||||||
|  |         r.lock() | ||||||
|  |         return try { | ||||||
|  |             secp256k1_ec_seckey_verify( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext() | ||||||
|  |             ) == 1 | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * libsecp256k1 Compute Pubkey - computes public key from secret key | ||||||
|  |      * | ||||||
|  |      * @param seckey ECDSA Secret key, 32 bytes | ||||||
|  |      * @throws AssertFailException if parameters are not valid | ||||||
|  |      * @return the corresponding public key (uncompressed) | ||||||
|  |      */ | ||||||
|  |     //TODO add a 'compressed' arg | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun computePubkey(seckey: ByteArray, compressed: Boolean): ByteArray { | ||||||
|  |         require(seckey.size == 32) | ||||||
|  |         val byteBuff = pack(seckey) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_ec_pubkey_create( | ||||||
|  |                 byteBuff, | ||||||
|  |                 compressed, | ||||||
|  |                 Secp256k1Context.getContext() | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val pubArr = retByteArray[0] | ||||||
|  |         val pubLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals(pubArr.size, pubLen, "Got bad pubkey length.") | ||||||
|  |         return if (retVal == 0) ByteArray(0) else pubArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @param pubkey public key | ||||||
|  |      * @return the input public key (uncompressed) if valid, or an empty array | ||||||
|  |      * @throws AssertFailException in case of failure | ||||||
|  |      */ | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun parsePubkey(pubkey: ByteArray, compressed: Boolean): ByteArray { | ||||||
|  |         require(pubkey.size == 33 || pubkey.size == 65) | ||||||
|  |         val byteBuff = pack(pubkey) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_ec_pubkey_parse( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext(), | ||||||
|  |                 pubkey.size, | ||||||
|  |                 compressed | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val pubArr = retByteArray[0] | ||||||
|  |         BigInteger(byteArrayOf(retByteArray[1][0])).toInt() | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals( | ||||||
|  |             pubArr.size, | ||||||
|  |             if (compressed) 33 else 65, | ||||||
|  |             "Got bad pubkey length." | ||||||
|  |         ) | ||||||
|  |         return if (retVal == 0) ByteArray(0) else pubArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * libsecp256k1 Cleanup - This destroys the secp256k1 context object | ||||||
|  |      * This should be called at the end of the program for proper cleanup of the context. | ||||||
|  |      */ | ||||||
|  |     @JvmStatic | ||||||
|  |     @Synchronized | ||||||
|  |     public fun cleanup() { | ||||||
|  |         w.lock() | ||||||
|  |         try { | ||||||
|  |             secp256k1_destroy_context(Secp256k1Context.getContext()) | ||||||
|  |         } finally { | ||||||
|  |             w.unlock() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun privKeyNegate(privkey: ByteArray): ByteArray { | ||||||
|  |         require(privkey.size == 32) | ||||||
|  |         val byteBuff = pack(privkey) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_privkey_negate( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext() | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val privArr = retByteArray[0] | ||||||
|  |         val privLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals( | ||||||
|  |             privArr.size, | ||||||
|  |             privLen, | ||||||
|  |             "Got bad privkey length." | ||||||
|  |         ) | ||||||
|  |         NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") | ||||||
|  |         return privArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it | ||||||
|  |      * | ||||||
|  |      * @param privkey 32-byte seckey | ||||||
|  |      * @param tweak   some bytes to tweak with | ||||||
|  |      * @return privkey * tweak | ||||||
|  |      * @throws AssertFailException in case of failure | ||||||
|  |      */ | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray { | ||||||
|  |         require(privkey.size == 32) | ||||||
|  |         val byteBuff = pack(privkey, tweak) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_privkey_tweak_mul( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext() | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val privArr = retByteArray[0] | ||||||
|  |         val privLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals( | ||||||
|  |             privArr.size, | ||||||
|  |             privLen, | ||||||
|  |             "Got bad privkey length." | ||||||
|  |         ) | ||||||
|  |         NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") | ||||||
|  |         return privArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it | ||||||
|  |      * | ||||||
|  |      * @param privkey 32-byte seckey | ||||||
|  |      * @param tweak  some bytes to tweak with | ||||||
|  |      * @return privkey + tweak | ||||||
|  |      * @throws AssertFailException in case of failure | ||||||
|  |      */ | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray { | ||||||
|  |         require(privkey.size == 32) | ||||||
|  |         val byteBuff = pack(privkey, tweak) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_privkey_tweak_add( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext() | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val privArr = retByteArray[0] | ||||||
|  |         val privLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals(privArr.size, privLen, "Got bad pubkey length.") | ||||||
|  |         NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") | ||||||
|  |         return privArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun pubKeyNegate(pubkey: ByteArray): ByteArray { | ||||||
|  |         require(pubkey.size == 33 || pubkey.size == 65) | ||||||
|  |         val byteBuff = pack(pubkey) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_pubkey_negate( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext(), | ||||||
|  |                 pubkey.size | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val pubArr = retByteArray[0] | ||||||
|  |         val pubLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals(pubArr.size, pubLen, "Got bad pubkey length.") | ||||||
|  |         NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") | ||||||
|  |         return pubArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it | ||||||
|  |      * | ||||||
|  |      * @param tweak  some bytes to tweak with | ||||||
|  |      * @param pubkey 32-byte seckey | ||||||
|  |      * @return pubkey + tweak | ||||||
|  |      * @throws AssertFailException in case of failure | ||||||
|  |      */ | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray { | ||||||
|  |         require(pubkey.size == 33 || pubkey.size == 65) | ||||||
|  |         val byteBuff = pack(pubkey, tweak) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_pubkey_tweak_add( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext(), | ||||||
|  |                 pubkey.size | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val pubArr = retByteArray[0] | ||||||
|  |         val pubLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals(pubArr.size, pubLen, "Got bad pubkey length.") | ||||||
|  |         NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") | ||||||
|  |         return pubArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it | ||||||
|  |      * | ||||||
|  |      * @param tweak  some bytes to tweak with | ||||||
|  |      * @param pubkey 32-byte seckey | ||||||
|  |      * @return pubkey * tweak | ||||||
|  |      * @throws AssertFailException in case of failure | ||||||
|  |      */ | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray { | ||||||
|  |         require(pubkey.size == 33 || pubkey.size == 65) | ||||||
|  |         val byteBuff = pack(pubkey, tweak) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_pubkey_tweak_mul( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext(), | ||||||
|  |                 pubkey.size | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val pubArr = retByteArray[0] | ||||||
|  |         val pubLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals(pubArr.size, pubLen, "Got bad pubkey length.") | ||||||
|  |         NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") | ||||||
|  |         return pubArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray { | ||||||
|  |         require(pubkey1.size == 33 || pubkey1.size == 65) | ||||||
|  |         require(pubkey2.size == 33 || pubkey2.size == 65) | ||||||
|  |         val byteBuff = pack(pubkey1, pubkey2) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_ec_pubkey_add( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext(), | ||||||
|  |                 pubkey1.size, | ||||||
|  |                 pubkey2.size | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val pubArr = retByteArray[0] | ||||||
|  |         val pubLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals(pubkey1.size, pubLen, "Got bad pubkey length.") | ||||||
|  |         NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") | ||||||
|  |         return pubArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * libsecp256k1 create ECDH secret - constant time ECDH calculation | ||||||
|  |      * | ||||||
|  |      * @param seckey byte array of secret key used in exponentiaion | ||||||
|  |      * @param pubkey byte array of public key used in exponentiaion | ||||||
|  |      * @return ecdh(sedckey, pubkey) | ||||||
|  |      * @throws AssertFailException in case of failure | ||||||
|  |      */ | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray { | ||||||
|  |         require(seckey.size <= 32 && pubkey.size <= 65) | ||||||
|  |         val byteBuff = pack(seckey, pubkey) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_ecdh( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext(), | ||||||
|  |                 pubkey.size | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val resArr = retByteArray[0] | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals(resArr.size, 32, "Got bad result length.") | ||||||
|  |         NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") | ||||||
|  |         return resArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JvmStatic | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, compressed: Boolean): ByteArray { | ||||||
|  |         require(sig.size == 64) | ||||||
|  |         require(message.size == 32) | ||||||
|  |         val byteBuff = pack(sig, message) | ||||||
|  |         val retByteArray: Array<ByteArray> | ||||||
|  |         r.lock() | ||||||
|  |         retByteArray = try { | ||||||
|  |             secp256k1_ecdsa_recover( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext(), | ||||||
|  |                 recid, | ||||||
|  |                 compressed | ||||||
|  |             ) | ||||||
|  |         } finally { | ||||||
|  |             r.unlock() | ||||||
|  |         } | ||||||
|  |         val resArr = retByteArray[0] | ||||||
|  |         val retVal = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() | ||||||
|  |         NativeSecp256k1Util.assertEquals( | ||||||
|  |             resArr.size, | ||||||
|  |             if (compressed) 33 else 65, | ||||||
|  |             "Got bad result length." | ||||||
|  |         ) | ||||||
|  |         NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") | ||||||
|  |         return resArr | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * libsecp256k1 randomize - updates the context randomization | ||||||
|  |      * | ||||||
|  |      * @param seed 32-byte random seed | ||||||
|  |      * @return true if successful | ||||||
|  |      * @throws AssertFailException in case of failure | ||||||
|  |      */ | ||||||
|  |     @JvmStatic | ||||||
|  |     @Synchronized | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     public fun randomize(seed: ByteArray): Boolean { | ||||||
|  |         require(seed.size == 32) | ||||||
|  |         val byteBuff = pack(seed) | ||||||
|  |         w.lock() | ||||||
|  |         return try { | ||||||
|  |             secp256k1_context_randomize( | ||||||
|  |                 byteBuff, | ||||||
|  |                 Secp256k1Context.getContext() | ||||||
|  |             ) == 1 | ||||||
|  |         } finally { | ||||||
|  |             w.unlock() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JvmStatic private external fun secp256k1_context_randomize(byteBuff: ByteBuffer, context: Long): Int | ||||||
|  |     @JvmStatic private external fun secp256k1_privkey_negate(byteBuff: ByteBuffer, context: Long): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_privkey_tweak_add(byteBuff: ByteBuffer, context: Long): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_privkey_tweak_mul(byteBuff: ByteBuffer, context: Long): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_pubkey_negate(byteBuff: ByteBuffer, context: Long, pubLen: Int): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_pubkey_tweak_add(byteBuff: ByteBuffer, context: Long, pubLen: Int): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_pubkey_tweak_mul(byteBuff: ByteBuffer, context: Long, pubLen: Int): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_destroy_context(context: Long) | ||||||
|  |     @JvmStatic private external fun secp256k1_ecdsa_verify(byteBuff: ByteBuffer, context: Long, sigLen: Int, pubLen: Int): Int | ||||||
|  |     @JvmStatic private external fun secp256k1_ecdsa_sign(byteBuff: ByteBuffer, compact: Boolean, context: Long): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_ecdsa_normalize(byteBuff: ByteBuffer, sigLen: Int, compact: Boolean, context: Long): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_ec_seckey_verify(byteBuff: ByteBuffer, context: Long): Int | ||||||
|  |     @JvmStatic private external fun secp256k1_ec_pubkey_create(byteBuff: ByteBuffer, compressed: Boolean, context: Long): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_ec_pubkey_parse(byteBuff: ByteBuffer, context: Long, inputLen: Int, compressed: Boolean): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_ec_pubkey_add(byteBuff: ByteBuffer, context: Long, lent1: Int, len2: Int): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_ecdh(byteBuff: ByteBuffer, context: Long, inputLen: Int): Array<ByteArray> | ||||||
|  |     @JvmStatic private external fun secp256k1_ecdsa_recover(byteBuff: ByteBuffer, context: Long, recid: Int, compressed: Boolean): Array<ByteArray> | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1Util.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1Util.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2014-2016 the libsecp256k1 contributors | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *    http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | package org.bitcoin | ||||||
|  | 
 | ||||||
|  | import kotlin.jvm.Throws | ||||||
|  | import java.lang.Exception | ||||||
|  | 
 | ||||||
|  | internal object NativeSecp256k1Util { | ||||||
|  |     @Throws(AssertFailException::class) | ||||||
|  |     fun assertEquals(val1: Int, val2: Int, message: String) { | ||||||
|  |         if (val1 != val2) throw AssertFailException("FAIL: $message") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     class AssertFailException(message: String?) : Exception(message) | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								src/jvmMain/kotlin/org/bitcoin/Secp256k1Context.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/jvmMain/kotlin/org/bitcoin/Secp256k1Context.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2014-2016 the libsecp256k1 contributors | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *    http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | package org.bitcoin | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * This class holds the context reference used in native methods | ||||||
|  |  * to handle ECDSA operations. | ||||||
|  |  */ | ||||||
|  | public object Secp256k1Context { | ||||||
|  |     @JvmStatic | ||||||
|  |     public val isEnabled: Boolean //true if the library is loaded | ||||||
|  |     private val context: Long //ref to pointer to context obj | ||||||
|  | 
 | ||||||
|  |     @JvmStatic | ||||||
|  |     public fun getContext(): Long { | ||||||
|  |         return if (!isEnabled) -1 else context //sanity check | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JvmStatic private external fun secp256k1_init_context(): Long | ||||||
|  | 
 | ||||||
|  |     init { //static initializer | ||||||
|  |         isEnabled = true | ||||||
|  |         context = | ||||||
|  |             secp256k1_init_context() | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user