JVM implementation
This commit is contained in:
commit
54abe2a397
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Build
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Idea
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.gradle
|
||||||
|
local.properties
|
||||||
|
.gradletasknamecache
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "native/secp256k1"]
|
||||||
|
path = native/secp256k1
|
||||||
|
url = https://github.com/bitcoin-core/secp256k1.git
|
88
build.gradle.kts
Normal file
88
build.gradle.kts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform") version "1.4-M2-mt"
|
||||||
|
}
|
||||||
|
group = "fr.acinq.phoenix"
|
||||||
|
version = "1.0-1.4-M2"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
|
maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
|
}
|
||||||
|
|
||||||
|
val currentOs = org.gradle.internal.os.OperatingSystem.current()
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
explicitApi()
|
||||||
|
|
||||||
|
jvm {
|
||||||
|
compilations.all {
|
||||||
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// linuxX64()
|
||||||
|
// ios()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val commonTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val jvmMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-jdk8"))
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val jvmTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val buildSecp256k1 by tasks.creating { group = "build" }
|
||||||
|
fun creatingBuildSecp256k1(target: String, cross: String? = null, env: String = "", configuration: Task.() -> Unit = {}) = tasks.creating {
|
||||||
|
group = "build"
|
||||||
|
buildSecp256k1.dependsOn(this)
|
||||||
|
|
||||||
|
inputs.files(projectDir.resolve("native/build.sh"))
|
||||||
|
outputs.dir(projectDir.resolve("native/build/$target"))
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
exec {
|
||||||
|
workingDir = projectDir.resolve("native")
|
||||||
|
environment("TARGET", target)
|
||||||
|
if (cross == null) commandLine("./build.sh")
|
||||||
|
else commandLine("./dockcross-$cross", "bash", "-c", "TARGET=$target ./build.sh")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration()
|
||||||
|
}
|
||||||
|
|
||||||
|
val buildSecp256k1Darwin by creatingBuildSecp256k1("darwin")
|
||||||
|
val buildSecp256k1Linux by creatingBuildSecp256k1("linux", cross = if (currentOs.isMacOsX) "linux-x64" else null)
|
||||||
|
val buildSecp256k1Mingw by creatingBuildSecp256k1("mingw", cross = "windows-x64", env = "CONF_OPTS=--host=x86_64-w64-mingw32")
|
||||||
|
|
||||||
|
val 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"))
|
||||||
|
}
|
||||||
|
|
||||||
|
(tasks[kotlin.jvm().compilations["main"].processResourcesTaskName] as ProcessResources).apply{
|
||||||
|
dependsOn(copyJni)
|
||||||
|
from(buildDir.resolve("jniResources"))
|
||||||
|
}
|
1
gradle.properties
Normal file
1
gradle.properties
Normal file
@ -0,0 +1 @@
|
|||||||
|
kotlin.code.style=official
|
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
15
native/build-ios.sh
Normal file
15
native/build-ios.sh
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cp xconfigure.sh secp256k1
|
||||||
|
|
||||||
|
cd secp256k1
|
||||||
|
|
||||||
|
./autogen.sh
|
||||||
|
sh xconfigure.sh --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
|
||||||
|
|
||||||
|
mkdir -p ../build/ios
|
||||||
|
cp -v _build/universal/* ../build/ios/
|
||||||
|
|
||||||
|
rm -rf _build
|
||||||
|
make clean
|
41
native/build.sh
Executable file
41
native/build.sh
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
[[ -z "$TARGET" ]] && echo "Please set the PLATFORM variable" && exit 1
|
||||||
|
|
||||||
|
cd secp256k1
|
||||||
|
|
||||||
|
if [ "$TARGET" == "mingw" ]; then
|
||||||
|
CONF_OPTS="CFLAGS=-fpic --host=x86_64-w64-mingw32"
|
||||||
|
elif [ "$TARGET" == "linux" ]; then
|
||||||
|
CONF_OPTS="CFLAGS=-fpic"
|
||||||
|
fi
|
||||||
|
|
||||||
|
./autogen.sh
|
||||||
|
./configure $CONF_OPTS --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
|
||||||
|
make clean
|
||||||
|
make
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
mkdir -p build/$TARGET
|
||||||
|
cp -r secp256k1/.libs/libsecp256k1.a build/$TARGET/
|
||||||
|
|
||||||
|
GCC=gcc
|
||||||
|
JNI_HEADERS=$TARGET
|
||||||
|
|
||||||
|
if [ "$TARGET" == "linux" ]; then
|
||||||
|
OUTFILE=libsecp256k1-jni.so
|
||||||
|
elif [ "$TARGET" == "darwin" ]; then
|
||||||
|
OUTFILE=libsecp256k1-jni.dylib
|
||||||
|
ADD_LIB=-lgmp
|
||||||
|
elif [ "$TARGET" == "mingw" ]; then
|
||||||
|
OUTFILE=secp256k1-jni.dll
|
||||||
|
GCC=/usr/src/mxe/usr/bin/x86_64-w64-mingw32.static-gcc
|
||||||
|
JNI_HEADERS=linux
|
||||||
|
GCC_OPTS="-fpic"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $GCC -shared $GCC_OPTS -o build/$TARGET/$OUTFILE jni/src/org_bitcoin_NativeSecp256k1.c jni/src/org_bitcoin_Secp256k1Context.c -Ijni/headers/ -Ijni/headers/$JNI_HEADERS/ -Isecp256k1/ -lsecp256k1 -Lbuild/$TARGET/ $ADD_LIB
|
||||||
|
|
||||||
|
$GCC -shared $GCC_OPTS -o build/$TARGET/$OUTFILE jni/src/org_bitcoin_NativeSecp256k1.c jni/src/org_bitcoin_Secp256k1Context.c -Ijni/headers/ -Ijni/headers/$JNI_HEADERS/ -Isecp256k1/ -lsecp256k1 -Lbuild/$TARGET/ $ADD_LIB
|
256
native/dockcross-linux-x64
Executable file
256
native/dockcross-linux-x64
Executable file
@ -0,0 +1,256 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
DEFAULT_DOCKCROSS_IMAGE=dockcross/linux-x64:latest
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Helpers
|
||||||
|
#
|
||||||
|
err() {
|
||||||
|
echo -e >&2 ERROR: $@\\n
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
err $@
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
has() {
|
||||||
|
# eg. has command update
|
||||||
|
local kind=$1
|
||||||
|
local name=$2
|
||||||
|
|
||||||
|
type -t $kind:$name | grep -q function
|
||||||
|
}
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Command handlers
|
||||||
|
#
|
||||||
|
command:update-image() {
|
||||||
|
docker pull $FINAL_IMAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
help:update-image() {
|
||||||
|
echo Pull the latest $FINAL_IMAGE .
|
||||||
|
}
|
||||||
|
|
||||||
|
command:update-script() {
|
||||||
|
if cmp -s <( docker run --rm $FINAL_IMAGE ) $0; then
|
||||||
|
echo $0 is up to date
|
||||||
|
else
|
||||||
|
echo -n Updating $0 '... '
|
||||||
|
docker run --rm $FINAL_IMAGE > $0 && echo ok
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
help:update-image() {
|
||||||
|
echo Update $0 from $FINAL_IMAGE .
|
||||||
|
}
|
||||||
|
|
||||||
|
command:update() {
|
||||||
|
command:update-image
|
||||||
|
command:update-script
|
||||||
|
}
|
||||||
|
|
||||||
|
help:update() {
|
||||||
|
echo Pull the latest $FINAL_IMAGE, and then update $0 from that.
|
||||||
|
}
|
||||||
|
|
||||||
|
command:help() {
|
||||||
|
if [[ $# != 0 ]]; then
|
||||||
|
if ! has command $1; then
|
||||||
|
err \"$1\" is not an dockcross command
|
||||||
|
command:help
|
||||||
|
elif ! has help $1; then
|
||||||
|
err No help found for \"$1\"
|
||||||
|
else
|
||||||
|
help:$1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cat >&2 <<ENDHELP
|
||||||
|
Usage: dockcross [options] [--] command [args]
|
||||||
|
|
||||||
|
By default, run the given *command* in an dockcross Docker container.
|
||||||
|
|
||||||
|
The *options* can be one of:
|
||||||
|
|
||||||
|
--args|-a Extra args to the *docker run* command
|
||||||
|
--image|-i Docker cross-compiler image to use
|
||||||
|
--config|-c Bash script to source before running this script
|
||||||
|
|
||||||
|
|
||||||
|
Additionally, there are special update commands:
|
||||||
|
|
||||||
|
update-image
|
||||||
|
update-script
|
||||||
|
update
|
||||||
|
|
||||||
|
For update command help use: $0 help <command>
|
||||||
|
ENDHELP
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Option processing
|
||||||
|
#
|
||||||
|
special_update_command=''
|
||||||
|
while [[ $# != 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
|
||||||
|
--args|-a)
|
||||||
|
ARG_ARGS="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
|
||||||
|
--config|-c)
|
||||||
|
ARG_CONFIG="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
|
||||||
|
--image|-i)
|
||||||
|
ARG_IMAGE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
update|update-image|update-script)
|
||||||
|
special_update_command=$1
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
err Unknown option \"$1\"
|
||||||
|
command:help
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# The precedence for options is:
|
||||||
|
# 1. command-line arguments
|
||||||
|
# 2. environment variables
|
||||||
|
# 3. defaults
|
||||||
|
|
||||||
|
# Source the config file if it exists
|
||||||
|
DEFAULT_DOCKCROSS_CONFIG=~/.dockcross
|
||||||
|
FINAL_CONFIG=${ARG_CONFIG-${DOCKCROSS_CONFIG-$DEFAULT_DOCKCROSS_CONFIG}}
|
||||||
|
|
||||||
|
[[ -f "$FINAL_CONFIG" ]] && source "$FINAL_CONFIG"
|
||||||
|
|
||||||
|
# Set the docker image
|
||||||
|
FINAL_IMAGE=${ARG_IMAGE-${DOCKCROSS_IMAGE-$DEFAULT_DOCKCROSS_IMAGE}}
|
||||||
|
|
||||||
|
# Handle special update command
|
||||||
|
if [ "$special_update_command" != "" ]; then
|
||||||
|
case $special_update_command in
|
||||||
|
|
||||||
|
update)
|
||||||
|
command:update
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
|
||||||
|
update-image)
|
||||||
|
command:update-image
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
|
||||||
|
update-script)
|
||||||
|
command:update-script
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set the docker run extra args (if any)
|
||||||
|
FINAL_ARGS=${ARG_ARGS-${DOCKCROSS_ARGS}}
|
||||||
|
|
||||||
|
# Bash on Ubuntu on Windows
|
||||||
|
UBUNTU_ON_WINDOWS=$([ -e /proc/version ] && grep -l Microsoft /proc/version || echo "")
|
||||||
|
# MSYS, Git Bash, etc.
|
||||||
|
MSYS=$([ -e /proc/version ] && grep -l MINGW /proc/version || echo "")
|
||||||
|
|
||||||
|
if [ -z "$UBUNTU_ON_WINDOWS" -a -z "$MSYS" ]; then
|
||||||
|
USER_IDS=(-e BUILDER_UID="$( id -u )" -e BUILDER_GID="$( id -g )" -e BUILDER_USER="$( id -un )" -e BUILDER_GROUP="$( id -gn )")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Change the PWD when working in Docker on Windows
|
||||||
|
if [ -n "$UBUNTU_ON_WINDOWS" ]; then
|
||||||
|
WSL_ROOT="/mnt/"
|
||||||
|
CFG_FILE=/etc/wsl.conf
|
||||||
|
if [ -f "$CFG_FILE" ]; then
|
||||||
|
CFG_CONTENT=$(cat $CFG_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g')
|
||||||
|
eval "$CFG_CONTENT"
|
||||||
|
if [ -n "$root" ]; then
|
||||||
|
WSL_ROOT=$root
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
HOST_PWD=`pwd -P`
|
||||||
|
HOST_PWD=${HOST_PWD/$WSL_ROOT//}
|
||||||
|
elif [ -n "$MSYS" ]; then
|
||||||
|
HOST_PWD=$PWD
|
||||||
|
HOST_PWD=${HOST_PWD/\//}
|
||||||
|
HOST_PWD=${HOST_PWD/\//:\/}
|
||||||
|
else
|
||||||
|
HOST_PWD=$PWD
|
||||||
|
[ -L $HOST_PWD ] && HOST_PWD=$(readlink $HOST_PWD)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mount Additional Volumes
|
||||||
|
if [ -z "$SSH_DIR" ]; then
|
||||||
|
SSH_DIR="$HOME/.ssh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
HOST_VOLUMES=
|
||||||
|
if [ -e "$SSH_DIR" -a -z "$MSYS" ]; then
|
||||||
|
HOST_VOLUMES+="-v $SSH_DIR:/home/$(id -un)/.ssh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Now, finally, run the command in a container
|
||||||
|
#
|
||||||
|
TTY_ARGS=
|
||||||
|
tty -s && [ -z "$MSYS" ] && TTY_ARGS=-ti
|
||||||
|
CONTAINER_NAME=dockcross_$RANDOM
|
||||||
|
docker run $TTY_ARGS --name $CONTAINER_NAME \
|
||||||
|
-v "$HOST_PWD":/work \
|
||||||
|
$HOST_VOLUMES \
|
||||||
|
"${USER_IDS[@]}" \
|
||||||
|
$FINAL_ARGS \
|
||||||
|
$FINAL_IMAGE "$@"
|
||||||
|
run_exit_code=$?
|
||||||
|
|
||||||
|
# Attempt to delete container
|
||||||
|
rm_output=$(docker rm -f $CONTAINER_NAME 2>&1)
|
||||||
|
rm_exit_code=$?
|
||||||
|
if [[ $rm_exit_code != 0 ]]; then
|
||||||
|
if [[ "$CIRCLECI" == "true" ]] && [[ $rm_output == *"Driver btrfs failed to remove"* ]]; then
|
||||||
|
: # Ignore error because of https://circleci.com/docs/docker-btrfs-error/
|
||||||
|
else
|
||||||
|
echo "$rm_output"
|
||||||
|
exit $rm_exit_code
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $run_exit_code
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# This image is not intended to be run manually.
|
||||||
|
#
|
||||||
|
# To create a dockcross helper script for the
|
||||||
|
# dockcross/linux-x64:latest image, run:
|
||||||
|
#
|
||||||
|
# docker run --rm dockcross/linux-x64:latest > dockcross-linux-x64-latest
|
||||||
|
# chmod +x dockcross-linux-x64-latest
|
||||||
|
#
|
||||||
|
# You may then wish to move the dockcross script to your PATH.
|
||||||
|
#
|
||||||
|
################################################################################
|
200
native/dockcross-windows-x64
Executable file
200
native/dockcross-windows-x64
Executable file
@ -0,0 +1,200 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DEFAULT_DOCKCROSS_IMAGE=dockcross/windows-x64
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Helpers
|
||||||
|
#
|
||||||
|
err() {
|
||||||
|
echo -e >&2 ERROR: $@\\n
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
err $@
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
has() {
|
||||||
|
# eg. has command update
|
||||||
|
local kind=$1
|
||||||
|
local name=$2
|
||||||
|
|
||||||
|
type -t $kind:$name | grep -q function
|
||||||
|
}
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Command handlers
|
||||||
|
#
|
||||||
|
command:update-image() {
|
||||||
|
docker pull $FINAL_IMAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
help:update-image() {
|
||||||
|
echo Pull the latest $FINAL_IMAGE .
|
||||||
|
}
|
||||||
|
|
||||||
|
command:update-script() {
|
||||||
|
if cmp -s <( docker run $FINAL_IMAGE ) $0; then
|
||||||
|
echo $0 is up to date
|
||||||
|
else
|
||||||
|
echo -n Updating $0 '... '
|
||||||
|
docker run $FINAL_IMAGE > $0 && echo ok
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
help:update-image() {
|
||||||
|
echo Update $0 from $FINAL_IMAGE .
|
||||||
|
}
|
||||||
|
|
||||||
|
command:update() {
|
||||||
|
command:update-image
|
||||||
|
command:update-script
|
||||||
|
}
|
||||||
|
|
||||||
|
help:update() {
|
||||||
|
echo Pull the latest $FINAL_IMAGE, and then update $0 from that.
|
||||||
|
}
|
||||||
|
|
||||||
|
command:help() {
|
||||||
|
if [[ $# != 0 ]]; then
|
||||||
|
if ! has command $1; then
|
||||||
|
err \"$1\" is not an dockcross command
|
||||||
|
command:help
|
||||||
|
elif ! has help $1; then
|
||||||
|
err No help found for \"$1\"
|
||||||
|
else
|
||||||
|
help:$1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cat >&2 <<ENDHELP
|
||||||
|
Usage: dockcross [options] [--] command [args]
|
||||||
|
|
||||||
|
By default, run the given *command* in an dockcross Docker container.
|
||||||
|
|
||||||
|
The *options* can be one of:
|
||||||
|
|
||||||
|
--args|-a Extra args to the *docker run* command
|
||||||
|
--image|-i Docker cross-compiler image to use
|
||||||
|
--config|-c Bash script to source before running this script
|
||||||
|
|
||||||
|
|
||||||
|
Additionally, there are special update commands:
|
||||||
|
|
||||||
|
update-image
|
||||||
|
update-script
|
||||||
|
update
|
||||||
|
|
||||||
|
For update command help use: $0 help <command>
|
||||||
|
ENDHELP
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Option processing
|
||||||
|
#
|
||||||
|
special_update_command=''
|
||||||
|
while [[ $# != 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
|
||||||
|
--)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
|
||||||
|
--args|-a)
|
||||||
|
ARG_ARGS="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
|
||||||
|
--config|-c)
|
||||||
|
ARG_CONFIG="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
|
||||||
|
--image|-i)
|
||||||
|
ARG_IMAGE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
update|update-image|update-script)
|
||||||
|
special_update_command=$1
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
err Unknown option \"$1\"
|
||||||
|
command:help
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# The precedence for options is:
|
||||||
|
# 1. command-line arguments
|
||||||
|
# 2. environment variables
|
||||||
|
# 3. defaults
|
||||||
|
|
||||||
|
# Source the config file if it exists
|
||||||
|
DEFAULT_DOCKCROSS_CONFIG=~/.dockcross
|
||||||
|
FINAL_CONFIG=${ARG_CONFIG-${DOCKCROSS_CONFIG-$DEFAULT_DOCKCROSS_CONFIG}}
|
||||||
|
|
||||||
|
[[ -f "$FINAL_CONFIG" ]] && source "$FINAL_CONFIG"
|
||||||
|
|
||||||
|
# Set the docker image
|
||||||
|
FINAL_IMAGE=${ARG_IMAGE-${DOCKCROSS_IMAGE-$DEFAULT_DOCKCROSS_IMAGE}}
|
||||||
|
|
||||||
|
# Handle special update command
|
||||||
|
if [ "$special_update_command" != "" ]; then
|
||||||
|
case $special_update_command in
|
||||||
|
|
||||||
|
update)
|
||||||
|
command:update
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
|
||||||
|
update-image)
|
||||||
|
command:update-image
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
|
||||||
|
update-script)
|
||||||
|
command:update-script
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set the docker run extra args (if any)
|
||||||
|
FINAL_ARGS=${ARG_ARGS-${DOCKCROSS_ARGS}}
|
||||||
|
|
||||||
|
# If we are not running via boot2docker
|
||||||
|
if [ -z $DOCKER_HOST ]; then
|
||||||
|
USER_IDS=(-e BUILDER_UID="$( id -u )" -e BUILDER_GID="$( id -g )" -e BUILDER_USER="$( id -un )" -e BUILDER_GROUP="$( id -gn )")
|
||||||
|
fi
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Now, finally, run the command in a container
|
||||||
|
#
|
||||||
|
docker run --rm \
|
||||||
|
-v $PWD:/work \
|
||||||
|
"${USER_IDS[@]}" \
|
||||||
|
$FINAL_ARGS \
|
||||||
|
$FINAL_IMAGE "$@"
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# This image is not intended to be run manually.
|
||||||
|
#
|
||||||
|
# To create a dockcross helper script for the
|
||||||
|
# dockcross/linux-armv7 image, run:
|
||||||
|
#
|
||||||
|
# docker run --rm dockcross/linux-armv7 > dockcross-linux-armv7
|
||||||
|
# chmod +x dockcross-linux-armv7
|
||||||
|
#
|
||||||
|
# You may then wish to move the dockcross script to your PATH.
|
||||||
|
#
|
||||||
|
################################################################################
|
23
native/jni/headers/darwin/jni_md.h
Normal file
23
native/jni/headers/darwin/jni_md.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* @(#)jni_md.h 1.19 05/11/17
|
||||||
|
*
|
||||||
|
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _JAVASOFT_JNI_MD_H_
|
||||||
|
#define _JAVASOFT_JNI_MD_H_
|
||||||
|
|
||||||
|
#define JNIEXPORT __attribute__((visibility("default")))
|
||||||
|
#define JNIIMPORT
|
||||||
|
#define JNICALL
|
||||||
|
|
||||||
|
#if defined(__LP64__) && __LP64__ /* for -Wundef */
|
||||||
|
typedef int jint;
|
||||||
|
#else
|
||||||
|
typedef long jint;
|
||||||
|
#endif
|
||||||
|
typedef long long jlong;
|
||||||
|
typedef signed char jbyte;
|
||||||
|
|
||||||
|
#endif /* !_JAVASOFT_JNI_MD_H_ */
|
1959
native/jni/headers/jni.h
Normal file
1959
native/jni/headers/jni.h
Normal file
File diff suppressed because it is too large
Load Diff
24
native/jni/headers/linux/jni_md.h
Normal file
24
native/jni/headers/linux/jni_md.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* %W% %E%
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _JAVASOFT_JNI_MD_H_
|
||||||
|
#define _JAVASOFT_JNI_MD_H_
|
||||||
|
|
||||||
|
#define JNIEXPORT __attribute__((__visibility__("default")))
|
||||||
|
#define JNIIMPORT
|
||||||
|
#define JNICALL
|
||||||
|
|
||||||
|
typedef int jint;
|
||||||
|
#ifdef _LP64 /* 64-bit Solaris */
|
||||||
|
typedef long jlong;
|
||||||
|
#else
|
||||||
|
typedef long long jlong;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef signed char jbyte;
|
||||||
|
|
||||||
|
#endif /* !_JAVASOFT_JNI_MD_H_ */
|
19
native/jni/headers/mingw/jni_md.h
Normal file
19
native/jni/headers/mingw/jni_md.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* @(#)jni_md.h 1.14 03/12/19
|
||||||
|
*
|
||||||
|
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _JAVASOFT_JNI_MD_H_
|
||||||
|
#define _JAVASOFT_JNI_MD_H_
|
||||||
|
|
||||||
|
#define JNIEXPORT __declspec(dllexport)
|
||||||
|
#define JNIIMPORT __declspec(dllimport)
|
||||||
|
#define JNICALL __stdcall
|
||||||
|
|
||||||
|
typedef long jint;
|
||||||
|
typedef int64_t jlong;
|
||||||
|
typedef signed char jbyte;
|
||||||
|
|
||||||
|
#endif /* !_JAVASOFT_JNI_MD_H_ */
|
630
native/jni/src/org_bitcoin_NativeSecp256k1.c
Normal file
630
native/jni/src/org_bitcoin_NativeSecp256k1.c
Normal file
@ -0,0 +1,630 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "org_bitcoin_NativeSecp256k1.h"
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
#include "include/secp256k1_ecdh.h"
|
||||||
|
#include "include/secp256k1_recovery.h"
|
||||||
|
|
||||||
|
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||||
|
(JNIEnv* env, jclass classObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
|
||||||
|
jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx);
|
||||||
|
|
||||||
|
(void)classObject;(void)env;
|
||||||
|
|
||||||
|
return ctx_clone_l;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
|
||||||
|
const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return secp256k1_context_randomize(ctx, seed);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
|
||||||
|
(JNIEnv* env, jclass classObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
|
||||||
|
secp256k1_context_destroy(ctx);
|
||||||
|
|
||||||
|
(void)classObject;(void)env;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
|
||||||
|
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* sigdata = { (unsigned char*) (data + 32) };
|
||||||
|
const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) };
|
||||||
|
|
||||||
|
secp256k1_ecdsa_signature sig;
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
if (siglen == 64) {
|
||||||
|
ret = secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigdata);
|
||||||
|
} else {
|
||||||
|
ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
unsigned char* secKey = (unsigned char*) (data + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray sigArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
secp256k1_ecdsa_signature sig;
|
||||||
|
|
||||||
|
int ret = secp256k1_ecdsa_sign(ctx, &sig, data, secKey, NULL, NULL);
|
||||||
|
|
||||||
|
unsigned char outputSer[72];
|
||||||
|
size_t outputLen = 72;
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, &sig ); (void)ret2;
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
sigArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
unsigned char* secKey = (unsigned char*) (data + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray sigArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
secp256k1_ecdsa_signature sig[72];
|
||||||
|
|
||||||
|
int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL);
|
||||||
|
|
||||||
|
unsigned char outputSer[64];
|
||||||
|
size_t outputLen = 64;
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
int ret2 = secp256k1_ecdsa_signature_serialize_compact(ctx,outputSer, sig ); (void)ret2;
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
sigArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return secp256k1_ec_seckey_verify(ctx, secKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray pubkeyArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey);
|
||||||
|
|
||||||
|
unsigned char outputSer[65];
|
||||||
|
size_t outputLen = 65;
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
pubkeyArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint inputlen)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
const unsigned char* pubkeydata = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray pubkeyArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, inputlen);
|
||||||
|
|
||||||
|
unsigned char outputSer[65];
|
||||||
|
size_t outputLen = 65;
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey, SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
pubkeyArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1negate
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray privArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
int privkeylen = 32;
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_privkey_negate(ctx, privkey);
|
||||||
|
|
||||||
|
intsarray[0] = privkeylen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
privArray = (*env)->NewByteArray(env, privkeylen);
|
||||||
|
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, privArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* tweak = (unsigned char*) (privkey + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray privArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
int privkeylen = 32;
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak);
|
||||||
|
|
||||||
|
intsarray[0] = privkeylen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
privArray = (*env)->NewByteArray(env, privkeylen);
|
||||||
|
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, privArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* tweak = (unsigned char*) (privkey + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray privArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
int privkeylen = 32;
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak);
|
||||||
|
|
||||||
|
intsarray[0] = privkeylen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
privArray = (*env)->NewByteArray(env, privkeylen);
|
||||||
|
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, privArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1negate
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray pubArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
unsigned char outputSer[65];
|
||||||
|
size_t outputLen = publen;
|
||||||
|
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
ret = secp256k1_ec_pubkey_negate(ctx, &pubkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey, publen == 33 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
pubArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/
|
||||||
|
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* tweak = (unsigned char*) (pkey + publen);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray pubArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
unsigned char outputSer[65];
|
||||||
|
size_t outputLen = 65;
|
||||||
|
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
pubArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* tweak = (unsigned char*) (pkey + publen);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray pubArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
unsigned char outputSer[65];
|
||||||
|
size_t outputLen = 65;
|
||||||
|
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
|
||||||
|
|
||||||
|
if ( ret ) {
|
||||||
|
ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
pubArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1add
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen1, jint publen2)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
const unsigned char* pubdata1 = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* pubdata2 = (const unsigned char*) (pubdata1 + publen1);
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray pubArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
secp256k1_pubkey pubkey1, pubkey2;
|
||||||
|
const secp256k1_pubkey *pubkeys[2];
|
||||||
|
unsigned char outputSer[65];
|
||||||
|
size_t outputLen = 65;
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey1, pubdata1, publen1);
|
||||||
|
if (ret) {
|
||||||
|
ret = secp256k1_ec_pubkey_parse(ctx, &pubkey2, pubdata2, publen2);
|
||||||
|
}
|
||||||
|
secp256k1_pubkey result;
|
||||||
|
if (ret) {
|
||||||
|
pubkeys[0] = &pubkey1;
|
||||||
|
pubkeys[1] = &pubkey2;
|
||||||
|
ret = secp256k1_ec_pubkey_combine(ctx, &result, pubkeys, 2);
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
ret = secp256k1_ec_pubkey_serialize(ctx, outputSer, &outputLen, &result, SECP256K1_EC_UNCOMPRESSED );
|
||||||
|
}
|
||||||
|
intsarray[0] = outputLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
pubArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* pubdata = (const unsigned char*) (secdata + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray outArray, intsByteArray;
|
||||||
|
unsigned char intsarray[1];
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
unsigned char nonce_res[32];
|
||||||
|
size_t outputLen = 32;
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
ret = secp256k1_ecdh(
|
||||||
|
ctx,
|
||||||
|
nonce_res,
|
||||||
|
&pubkey,
|
||||||
|
secdata,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
outArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, outArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 1);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdsa_recover
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1recover
|
||||||
|
(JNIEnv *env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint recid)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||||
|
const unsigned char* sigdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* msgdata = (const unsigned char*)(sigdata + 64);
|
||||||
|
secp256k1_ecdsa_recoverable_signature sig;
|
||||||
|
secp256k1_pubkey pub;
|
||||||
|
unsigned char outputSer[65];
|
||||||
|
size_t outputLen = 65;
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray pubArray, intsByteArray;
|
||||||
|
unsigned char intsarray[1];
|
||||||
|
|
||||||
|
int ret = secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &sig, sigdata, recid);
|
||||||
|
if (ret) {
|
||||||
|
ret = secp256k1_ecdsa_recover(ctx, &pub, &sig, msgdata);
|
||||||
|
if (ret) {
|
||||||
|
ret = secp256k1_ec_pubkey_serialize(ctx, outputSer, &outputLen, &pub, SECP256K1_EC_UNCOMPRESSED );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
intsarray[0] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
pubArray = (*env)->NewByteArray(env, outputLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 1);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
157
native/jni/src/org_bitcoin_NativeSecp256k1.h
Normal file
157
native/jni/src/org_bitcoin_NativeSecp256k1.h
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
/* Header for class org_bitcoin_NativeSecp256k1 */
|
||||||
|
|
||||||
|
#ifndef _Included_org_bitcoin_NativeSecp256k1
|
||||||
|
#define _Included_org_bitcoin_NativeSecp256k1
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ctx_clone
|
||||||
|
* Signature: (J)J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||||
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_context_randomize
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_privkey_negate
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1negate
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_privkey_tweak_add
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_privkey_tweak_mul
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_pubkey_negate
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1negate
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_pubkey_tweak_add
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_pubkey_tweak_mul
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_destroy_context
|
||||||
|
* Signature: (J)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
|
||||||
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdsa_verify
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JII)I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdsa_sign
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdsa_sign_compact
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ec_seckey_verify
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ec_pubkey_create
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ec_pubkey_parse
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ec_pubkey_add
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JII)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1add
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdh
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdsa_recover
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1recover
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
15
native/jni/src/org_bitcoin_Secp256k1Context.c
Normal file
15
native/jni/src/org_bitcoin_Secp256k1Context.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "org_bitcoin_Secp256k1Context.h"
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
|
||||||
|
(JNIEnv* env, jclass classObject)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||||
|
|
||||||
|
(void)classObject;(void)env;
|
||||||
|
|
||||||
|
return (uintptr_t)ctx;
|
||||||
|
}
|
||||||
|
|
22
native/jni/src/org_bitcoin_Secp256k1Context.h
Normal file
22
native/jni/src/org_bitcoin_Secp256k1Context.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
#include "include/secp256k1.h"
|
||||||
|
/* Header for class org_bitcoin_Secp256k1Context */
|
||||||
|
|
||||||
|
#ifndef _Included_org_bitcoin_Secp256k1Context
|
||||||
|
#define _Included_org_bitcoin_Secp256k1Context
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_Secp256k1Context
|
||||||
|
* Method: secp256k1_init_context
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
|
||||||
|
(JNIEnv *, jclass);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
1
native/secp256k1
Submodule
1
native/secp256k1
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit dbd41db16a0e91b2566820898a3ab2d7dad4fe00
|
77
native/xconfigure.sh
Normal file
77
native/xconfigure.sh
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Build for iOS 64bit-ARM variants and iOS Simulator
|
||||||
|
# - Place the script at project root
|
||||||
|
# - Customize MIN_IOS_VERSION and other flags as needed
|
||||||
|
#
|
||||||
|
# Test Environment
|
||||||
|
# - macOS 10.14.6
|
||||||
|
# - iOS 13.1
|
||||||
|
# - Xcode 11.1
|
||||||
|
#
|
||||||
|
|
||||||
|
Build() {
|
||||||
|
# Ensure -fembed-bitcode builds, as workaround for libtool macOS bug
|
||||||
|
export MACOSX_DEPLOYMENT_TARGET="10.4"
|
||||||
|
# Get the correct toolchain for target platforms
|
||||||
|
export CC=$(xcrun --find --sdk "${SDK}" clang)
|
||||||
|
export CXX=$(xcrun --find --sdk "${SDK}" clang++)
|
||||||
|
export CPP=$(xcrun --find --sdk "${SDK}" cpp)
|
||||||
|
export CFLAGS="${HOST_FLAGS} ${OPT_FLAGS}"
|
||||||
|
export CXXFLAGS="${HOST_FLAGS} ${OPT_FLAGS}"
|
||||||
|
export LDFLAGS="${HOST_FLAGS}"
|
||||||
|
|
||||||
|
EXEC_PREFIX="${PLATFORMS}/${PLATFORM}"
|
||||||
|
./configure \
|
||||||
|
--host="${CHOST}" \
|
||||||
|
--prefix="${PREFIX}" \
|
||||||
|
--exec-prefix="${EXEC_PREFIX}" \
|
||||||
|
--enable-static \
|
||||||
|
--disable-shared \
|
||||||
|
"$@"
|
||||||
|
# Avoid Xcode loading dylibs even when staticlibs exist
|
||||||
|
|
||||||
|
make clean
|
||||||
|
mkdir -p "${PLATFORMS}" &> /dev/null
|
||||||
|
make -j"${MAKE_JOBS}"
|
||||||
|
make install
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Cross building with configure args $@"
|
||||||
|
|
||||||
|
# Locations
|
||||||
|
ScriptDir="$( cd "$( dirname "$0" )" && pwd )"
|
||||||
|
cd - &> /dev/null
|
||||||
|
PREFIX="${ScriptDir}"/_build
|
||||||
|
PLATFORMS="${PREFIX}"/platforms
|
||||||
|
UNIVERSAL="${PREFIX}"/universal
|
||||||
|
|
||||||
|
# Compiler options
|
||||||
|
OPT_FLAGS="-O3 -g3 -fembed-bitcode"
|
||||||
|
MAKE_JOBS=8
|
||||||
|
MIN_IOS_VERSION=10.0
|
||||||
|
|
||||||
|
# Build for platforms
|
||||||
|
SDK="iphoneos"
|
||||||
|
PLATFORM="arm"
|
||||||
|
PLATFORM_ARM=${PLATFORM}
|
||||||
|
ARCH_FLAGS="-arch arm64 -arch arm64e" # -arch armv7 -arch armv7s
|
||||||
|
HOST_FLAGS="${ARCH_FLAGS} -miphoneos-version-min=${MIN_IOS_VERSION} -isysroot $(xcrun --sdk ${SDK} --show-sdk-path)"
|
||||||
|
CHOST="arm-apple-darwin"
|
||||||
|
Build "$@"
|
||||||
|
|
||||||
|
SDK="iphonesimulator"
|
||||||
|
PLATFORM="x86_64-sim"
|
||||||
|
PLATFORM_ISIM=${PLATFORM}
|
||||||
|
ARCH_FLAGS="-arch x86_64"
|
||||||
|
HOST_FLAGS="${ARCH_FLAGS} -mios-simulator-version-min=${MIN_IOS_VERSION} -isysroot $(xcrun --sdk ${SDK} --show-sdk-path)"
|
||||||
|
CHOST="x86_64-apple-darwin"
|
||||||
|
Build "$@"
|
||||||
|
|
||||||
|
# Create universal binary
|
||||||
|
cd "${PLATFORMS}/${PLATFORM_ARM}/lib"
|
||||||
|
LIB_NAME=`find . -iname *.a`
|
||||||
|
cd -
|
||||||
|
mkdir -p "${UNIVERSAL}" &> /dev/null
|
||||||
|
lipo -create -output "${UNIVERSAL}/${LIB_NAME}" "${PLATFORMS}/${PLATFORM_ARM}/lib/${LIB_NAME}" "${PLATFORMS}/${PLATFORM_ISIM}/lib/${LIB_NAME}"
|
14
settings.gradle.kts
Normal file
14
settings.gradle.kts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
maven {
|
||||||
|
url = uri("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
|
}
|
||||||
|
maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
|
maven("https://plugins.gradle.org/m2/")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
rootProject.name = "secp256k1-kmp"
|
||||||
|
|
59
src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt
Normal file
59
src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 ACINQ SAS
|
||||||
|
*
|
||||||
|
* 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 fr.acinq.secp256k1
|
||||||
|
|
||||||
|
import kotlin.jvm.JvmStatic
|
||||||
|
import kotlin.jvm.Synchronized
|
||||||
|
|
||||||
|
public expect object Secp256k1 {
|
||||||
|
|
||||||
|
public fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean
|
||||||
|
|
||||||
|
public fun sign(data: ByteArray, sec: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun signCompact(data: ByteArray, sec: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun secKeyVerify(seckey: ByteArray): Boolean
|
||||||
|
|
||||||
|
public fun computePubkey(seckey: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun parsePubkey(pubkey: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun cleanup()
|
||||||
|
|
||||||
|
public fun cloneContext(): Long
|
||||||
|
|
||||||
|
public fun privKeyNegate(privkey: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun pubKeyNegate(pubkey: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray
|
||||||
|
|
||||||
|
public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray
|
||||||
|
|
||||||
|
public fun randomize(seed: ByteArray): Boolean
|
||||||
|
}
|
284
src/commonTest/kotlin/fr/acinq/secp256k1/Secp256k1Test.kt
Normal file
284
src/commonTest/kotlin/fr/acinq/secp256k1/Secp256k1Test.kt
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
package fr.acinq.secp256k1
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class holds test cases defined for testing this library.
|
||||||
|
*/
|
||||||
|
class Secp256k1Test {
|
||||||
|
//TODO improve comments/add more tests
|
||||||
|
/**
|
||||||
|
* This tests verify() for a valid signature
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testVerifyPos() {
|
||||||
|
var result: Boolean
|
||||||
|
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
|
||||||
|
val sig: ByteArray = Hex.decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase())
|
||||||
|
val pub: ByteArray = Hex.decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase())
|
||||||
|
result = Secp256k1.verify(data, sig, pub)
|
||||||
|
assertEquals(result, true, "testVerifyPos")
|
||||||
|
val sigCompact: ByteArray = Hex.decode("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase())
|
||||||
|
result = Secp256k1.verify(data, sigCompact, pub)
|
||||||
|
assertEquals(result, true, "testVerifyPos")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests verify() for a non-valid signature
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testVerifyNeg() {
|
||||||
|
var result: Boolean
|
||||||
|
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()) //sha256hash of "testing"
|
||||||
|
val sig: ByteArray = Hex.decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase())
|
||||||
|
val pub: ByteArray = Hex.decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase())
|
||||||
|
result = Secp256k1.verify(data, sig, pub)
|
||||||
|
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||||
|
assertEquals(result, false, "testVerifyNeg")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests secret key verify() for a valid secretkey
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testSecKeyVerifyPos() {
|
||||||
|
var result: Boolean
|
||||||
|
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
|
||||||
|
result = Secp256k1.secKeyVerify(sec)
|
||||||
|
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||||
|
assertEquals(result, true, "testSecKeyVerifyPos")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests secret key verify() for an invalid secretkey
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testSecKeyVerifyNeg() {
|
||||||
|
var result: Boolean
|
||||||
|
val sec: ByteArray = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase())
|
||||||
|
result = Secp256k1.secKeyVerify(sec)
|
||||||
|
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||||
|
assertEquals(result, false, "testSecKeyVerifyNeg")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests public key create() for a valid secretkey
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testPubKeyCreatePos() {
|
||||||
|
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
|
||||||
|
val resultArr: ByteArray = Secp256k1.computePubkey(sec)
|
||||||
|
val pubkeyString: String = Hex.encode(resultArr).toUpperCase()
|
||||||
|
assertEquals(
|
||||||
|
pubkeyString,
|
||||||
|
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6",
|
||||||
|
"testPubKeyCreatePos"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests public key create() for a invalid secretkey
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testPubKeyCreateNeg() {
|
||||||
|
val sec: ByteArray = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase())
|
||||||
|
val resultArr: ByteArray = Secp256k1.computePubkey(sec)
|
||||||
|
val pubkeyString: String = Hex.encode(resultArr).toUpperCase()
|
||||||
|
assertEquals(pubkeyString, "", "testPubKeyCreateNeg")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPubKeyNegatePos() {
|
||||||
|
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
|
||||||
|
val pubkey: ByteArray = Secp256k1.computePubkey(sec)
|
||||||
|
val pubkeyString: String = Hex.encode(pubkey).toUpperCase()
|
||||||
|
assertEquals(
|
||||||
|
pubkeyString,
|
||||||
|
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6",
|
||||||
|
"testPubKeyCreatePos"
|
||||||
|
)
|
||||||
|
val pubkey1: ByteArray = Secp256k1.pubKeyNegate(pubkey)
|
||||||
|
val pubkeyString1: String = Hex.encode(pubkey1).toUpperCase()
|
||||||
|
assertEquals(
|
||||||
|
pubkeyString1,
|
||||||
|
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2DDEFC12B6B8E73968536514302E69ED1DDB24B999EFEE79C12D03AB17E79E1989",
|
||||||
|
"testPubKeyNegatePos"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests public key create() for a valid secretkey
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testPubKeyParse() {
|
||||||
|
val pub: ByteArray = Hex.decode("02C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D".toLowerCase())
|
||||||
|
val resultArr: ByteArray = Secp256k1.parsePubkey(pub)
|
||||||
|
val pubkeyString: String = Hex.encode(resultArr).toUpperCase()
|
||||||
|
assertEquals(
|
||||||
|
pubkeyString,
|
||||||
|
"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6",
|
||||||
|
"testPubKeyAdd"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPubKeyAdd() {
|
||||||
|
val pub1: ByteArray = Hex.decode("041b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f70beaf8f588b541507fed6a642c5ab42dfdf8120a7f639de5122d47a69a8e8d1".toLowerCase())
|
||||||
|
val pub2: ByteArray = Hex.decode("044d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d07662a3eada2d0fe208b6d257ceb0f064284662e857f57b66b54c198bd310ded36d0".toLowerCase())
|
||||||
|
val pub3: ByteArray = Secp256k1.pubKeyAdd(pub1, pub2)
|
||||||
|
val pubkeyString: String = Hex.encode(pub3).toUpperCase()
|
||||||
|
assertEquals(
|
||||||
|
pubkeyString,
|
||||||
|
"04531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE3379E92C265E71E481BA82A84675A47AC705A200FCD524E92D93B0E7386F26A5458",
|
||||||
|
"testPubKeyAdd"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests sign() for a valid secretkey
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testSignPos() {
|
||||||
|
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
|
||||||
|
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
|
||||||
|
val resultArr: ByteArray = Secp256k1.sign(data, sec)
|
||||||
|
val sigString: String = Hex.encode(resultArr).toUpperCase()
|
||||||
|
assertEquals(
|
||||||
|
sigString,
|
||||||
|
"30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9",
|
||||||
|
"testSignPos"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests sign() for a invalid secretkey
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testSignNeg() {
|
||||||
|
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
|
||||||
|
val sec: ByteArray = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase())
|
||||||
|
val resultArr: ByteArray = Secp256k1.sign(data, sec)
|
||||||
|
val sigString: String = Hex.encode(resultArr)
|
||||||
|
assertEquals(sigString, "", "testSignNeg")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSignCompactPos() {
|
||||||
|
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
|
||||||
|
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
|
||||||
|
val resultArr: ByteArray = Secp256k1.signCompact(data, sec)
|
||||||
|
val sigString: String = Hex.encode(resultArr).toUpperCase()
|
||||||
|
assertEquals(
|
||||||
|
sigString,
|
||||||
|
"182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A21C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9",
|
||||||
|
"testSignCompactPos"
|
||||||
|
)
|
||||||
|
//assertEquals( sigString, "30 44 02 20 182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A2 02 20 1C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPrivKeyTweakNegate() {
|
||||||
|
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
|
||||||
|
val sec1: ByteArray = Secp256k1.privKeyNegate(sec)
|
||||||
|
assertEquals(
|
||||||
|
Hex.encode(sec1).toUpperCase(),
|
||||||
|
"981A9A7DD677A622518DA068D66D5F824E5F22F084B8A0E2F195B5662F300C11",
|
||||||
|
"testPrivKeyNegate"
|
||||||
|
)
|
||||||
|
val sec2: ByteArray = Secp256k1.privKeyNegate(sec1)
|
||||||
|
assertTrue(sec.contentEquals(sec2))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-add
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testPrivKeyTweakAdd_1() {
|
||||||
|
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
|
||||||
|
val data: ByteArray = Hex.decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()) //sha256hash of "tweak"
|
||||||
|
val resultArr: ByteArray = Secp256k1.privKeyTweakAdd(sec, data)
|
||||||
|
val sigString: String = Hex.encode(resultArr).toUpperCase()
|
||||||
|
assertEquals(sigString, "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3", "testPrivKeyAdd_1")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-mul
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testPrivKeyTweakMul_1() {
|
||||||
|
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
|
||||||
|
val data: ByteArray = Hex.decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()) //sha256hash of "tweak"
|
||||||
|
val resultArr: ByteArray = Secp256k1.privKeyTweakMul(sec, data)
|
||||||
|
val sigString: String = Hex.encode(resultArr).toUpperCase()
|
||||||
|
assertEquals(sigString, "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC", "testPrivKeyMul_1")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-add uncompressed
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testPrivKeyTweakAdd_2() {
|
||||||
|
val pub: ByteArray = Hex.decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase())
|
||||||
|
val data: ByteArray = Hex.decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()) //sha256hash of "tweak"
|
||||||
|
val resultArr: ByteArray = Secp256k1.pubKeyTweakAdd(pub, data)
|
||||||
|
val sigString: String = Hex.encode(resultArr).toUpperCase()
|
||||||
|
assertEquals(
|
||||||
|
sigString,
|
||||||
|
"0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF",
|
||||||
|
"testPrivKeyAdd_2"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-mul uncompressed
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testPrivKeyTweakMul_2() {
|
||||||
|
val pub: ByteArray = Hex.decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase())
|
||||||
|
val data: ByteArray = Hex.decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()) //sha256hash of "tweak"
|
||||||
|
val resultArr: ByteArray = Secp256k1.pubKeyTweakMul(pub, data)
|
||||||
|
val sigString: String = Hex.encode(resultArr).toUpperCase()
|
||||||
|
assertEquals(
|
||||||
|
sigString,
|
||||||
|
"04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589",
|
||||||
|
"testPrivKeyMul_2"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests seed randomization
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testRandomize() {
|
||||||
|
val seed: ByteArray = Hex.decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()) //sha256hash of "random"
|
||||||
|
val result: Boolean = Secp256k1.randomize(seed)
|
||||||
|
assertEquals(result, true, "testRandomize")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCreateECDHSecret() {
|
||||||
|
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
|
||||||
|
val pub: ByteArray = Hex.decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase())
|
||||||
|
val resultArr: ByteArray = Secp256k1.createECDHSecret(sec, pub)
|
||||||
|
val ecdhString: String = Hex.encode(resultArr).toUpperCase()
|
||||||
|
assertEquals(
|
||||||
|
ecdhString,
|
||||||
|
"2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043",
|
||||||
|
"testCreateECDHSecret"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEcdsaRecover() {
|
||||||
|
val data: ByteArray = Hex.decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()) //sha256hash of "testing"
|
||||||
|
val sec: ByteArray = Hex.decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase())
|
||||||
|
val pub: ByteArray = Secp256k1.computePubkey(sec)
|
||||||
|
val sig: ByteArray = Secp256k1.signCompact(data, sec)
|
||||||
|
val pub0: ByteArray = Secp256k1.ecdsaRecover(sig, data, 0)
|
||||||
|
val pub1: ByteArray = Secp256k1.ecdsaRecover(sig, data, 1)
|
||||||
|
assertTrue(pub.contentEquals(pub0) || pub.contentEquals(pub1), "testEcdsaRecover")
|
||||||
|
}
|
||||||
|
}
|
47
src/commonTest/kotlin/fr/acinq/secp256k1/utils.kt
Normal file
47
src/commonTest/kotlin/fr/acinq/secp256k1/utils.kt
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package fr.acinq.secp256k1
|
||||||
|
|
||||||
|
import kotlin.jvm.JvmStatic
|
||||||
|
|
||||||
|
object Hex {
|
||||||
|
private val hexCode = arrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f')
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun decode(hex: String): ByteArray {
|
||||||
|
val input = hex.filterNot { it.isWhitespace() }
|
||||||
|
val offset = when {
|
||||||
|
input.length >= 2 && input[0] == '0' && input[1] == 'x' -> 2
|
||||||
|
input.length >= 2 && input[0] == '0' && input[1] == 'X' -> 2
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
val len = input.length - offset
|
||||||
|
require(len % 2 == 0)
|
||||||
|
val out = ByteArray(len / 2)
|
||||||
|
|
||||||
|
fun hexToBin(ch: Char): Int = when (ch) {
|
||||||
|
in '0'..'9' -> ch - '0'
|
||||||
|
in 'a'..'f' -> ch - 'a' + 10
|
||||||
|
in 'A'..'F' -> ch - 'A' + 10
|
||||||
|
else -> throw IllegalArgumentException("illegal hex character: $ch")
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in out.indices) {
|
||||||
|
out[i] = (hexToBin(input[offset + 2 * i]) * 16 + hexToBin(input[offset + 2 * i + 1])).toByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun encode(input: ByteArray, offset: Int, len: Int): String {
|
||||||
|
val r = StringBuilder(len * 2)
|
||||||
|
for (i in 0 until len) {
|
||||||
|
val b = input[offset + i]
|
||||||
|
r.append(hexCode[(b.toInt() shr 4) and 0xF])
|
||||||
|
r.append(hexCode[b.toInt() and 0xF])
|
||||||
|
}
|
||||||
|
return r.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun encode(input: ByteArray): String = encode(input, 0, input.size)
|
||||||
|
}
|
228
src/jvmMain/kotlin/fr/acinq/secp256k1/OSInfo.kt
Normal file
228
src/jvmMain/kotlin/fr/acinq/secp256k1/OSInfo.kt
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
64
src/jvmMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt
Normal file
64
src/jvmMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 ACINQ SAS
|
||||||
|
*
|
||||||
|
* 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 fr.acinq.secp256k1
|
||||||
|
|
||||||
|
import org.bitcoin.NativeSecp256k1
|
||||||
|
import java.math.BigInteger
|
||||||
|
|
||||||
|
public actual object Secp256k1 {
|
||||||
|
|
||||||
|
init {
|
||||||
|
Secp256k1Loader.initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
public actual fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean = NativeSecp256k1.verify(data, signature, pub)
|
||||||
|
|
||||||
|
public actual fun sign(data: ByteArray, sec: ByteArray): ByteArray = NativeSecp256k1.sign(data, sec)
|
||||||
|
|
||||||
|
public actual fun signCompact(data: ByteArray, sec: ByteArray): ByteArray = NativeSecp256k1.signCompact(data, sec)
|
||||||
|
|
||||||
|
public actual fun secKeyVerify(seckey: ByteArray): Boolean = NativeSecp256k1.secKeyVerify(seckey)
|
||||||
|
|
||||||
|
public actual fun computePubkey(seckey: ByteArray): ByteArray = NativeSecp256k1.computePubkey(seckey)
|
||||||
|
|
||||||
|
public actual fun parsePubkey(pubkey: ByteArray): ByteArray = NativeSecp256k1.parsePubkey(pubkey)
|
||||||
|
|
||||||
|
public actual fun cleanup(): Unit = NativeSecp256k1.cleanup()
|
||||||
|
|
||||||
|
public actual fun cloneContext(): Long = NativeSecp256k1.cloneContext()
|
||||||
|
|
||||||
|
public actual fun privKeyNegate(privkey: ByteArray): ByteArray = NativeSecp256k1.privKeyNegate(privkey)
|
||||||
|
|
||||||
|
public actual fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray = NativeSecp256k1.privKeyTweakMul(privkey, tweak)
|
||||||
|
|
||||||
|
public actual fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray = NativeSecp256k1.privKeyTweakAdd(privkey, tweak)
|
||||||
|
|
||||||
|
public actual fun pubKeyNegate(pubkey: ByteArray): ByteArray = NativeSecp256k1.pubKeyNegate(pubkey)
|
||||||
|
|
||||||
|
public actual fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray = NativeSecp256k1.pubKeyTweakAdd(pubkey, tweak)
|
||||||
|
|
||||||
|
public actual fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray = NativeSecp256k1.pubKeyTweakMul(pubkey, tweak)
|
||||||
|
|
||||||
|
public actual fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray = NativeSecp256k1.pubKeyAdd(pubkey1, pubkey2)
|
||||||
|
|
||||||
|
public actual fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray = NativeSecp256k1.createECDHSecret(seckey, pubkey)
|
||||||
|
|
||||||
|
public actual fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray = NativeSecp256k1.ecdsaRecover(sig, message, recid)
|
||||||
|
|
||||||
|
public actual fun randomize(seed: ByteArray): Boolean = NativeSecp256k1.randomize(seed)
|
||||||
|
|
||||||
|
}
|
219
src/jvmMain/kotlin/fr/acinq/secp256k1/Secp256k1Loader.kt
Normal file
219
src/jvmMain/kotlin/fr/acinq/secp256k1/Secp256k1Loader.kt
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
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
|
||||||
|
*/
|
||||||
|
public 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)
|
||||||
|
public fun initialize(): Boolean {
|
||||||
|
// only cleanup before the first extract
|
||||||
|
if (!extracted) {
|
||||||
|
cleanup()
|
||||||
|
}
|
||||||
|
loadSecp256k1NativeLibrary()
|
||||||
|
return extracted
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = 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
|
||||||
|
}
|
||||||
|
}
|
508
src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1.kt
Normal file
508
src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1.kt
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* @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): 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, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 Create an ECDSA signature.
|
||||||
|
*
|
||||||
|
* @param data Message hash, 32 bytes
|
||||||
|
* @param sec Secret key, 32 bytes
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Return values
|
||||||
|
* @return a signature, or an empty array is signing failed
|
||||||
|
* @throws AssertFailException in case of failure
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@Throws(AssertFailException::class)
|
||||||
|
public fun signCompact(data: ByteArray, sec: ByteArray): ByteArray {
|
||||||
|
require(data.size == 32 && sec.size <= 32)
|
||||||
|
val byteBuff = pack(data, sec)
|
||||||
|
val retByteArray: Array<ByteArray>
|
||||||
|
r.lock()
|
||||||
|
retByteArray = try {
|
||||||
|
secp256k1_ecdsa_sign_compact(byteBuff, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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): ByteArray {
|
||||||
|
require(seckey.size == 32)
|
||||||
|
val byteBuff = pack(seckey)
|
||||||
|
val retByteArray: Array<ByteArray>
|
||||||
|
r.lock()
|
||||||
|
retByteArray = try {
|
||||||
|
secp256k1_ec_pubkey_create(byteBuff, 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): 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)
|
||||||
|
} 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, 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
|
||||||
|
public fun cloneContext(): Long {
|
||||||
|
r.lock()
|
||||||
|
return try {
|
||||||
|
secp256k1_ctx_clone(Secp256k1Context.getContext())
|
||||||
|
} finally {
|
||||||
|
r.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(65, 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): 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)
|
||||||
|
} finally {
|
||||||
|
r.unlock()
|
||||||
|
}
|
||||||
|
val resArr = retByteArray[0]
|
||||||
|
val retVal = BigInteger(byteArrayOf(retByteArray[1][0])).toInt()
|
||||||
|
NativeSecp256k1Util.assertEquals(resArr.size, 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_ctx_clone(context: Long): Long
|
||||||
|
@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, context: Long): Array<ByteArray>
|
||||||
|
@JvmStatic private external fun secp256k1_ecdsa_sign_compact(byteBuff: ByteBuffer, 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, context: Long): Array<ByteArray>
|
||||||
|
@JvmStatic private external fun secp256k1_ec_pubkey_parse(
|
||||||
|
byteBuff: ByteBuffer,
|
||||||
|
context: Long,
|
||||||
|
inputLen: Int
|
||||||
|
): 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): 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)
|
||||||
|
}
|
56
src/jvmMain/kotlin/org/bitcoin/Secp256k1Context.kt
Normal file
56
src/jvmMain/kotlin/org/bitcoin/Secp256k1Context.kt
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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 fr.acinq.secp256k1.Secp256k1Loader.initialize
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
var isEnabled = true
|
||||||
|
var contextRef: Long = -1
|
||||||
|
try {
|
||||||
|
if ("The Android Project" == System.getProperty("java.vm.vendor")) {
|
||||||
|
System.loadLibrary("secp256k1")
|
||||||
|
} else {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
contextRef = secp256k1_init_context()
|
||||||
|
} catch (e: UnsatisfiedLinkError) {
|
||||||
|
println("Cannot load secp256k1 native library: $e")
|
||||||
|
isEnabled = false
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("Cannot load secp256k1 native library: $e")
|
||||||
|
isEnabled = false
|
||||||
|
}
|
||||||
|
this.isEnabled = isEnabled
|
||||||
|
this.context = contextRef
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user