mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-03 09:56:38 -05:00
JNI library
Squashed and rebased. Thanks to @theuni and @faizkhan00 for doing the majority of work here! Also thanks to @btchip for help with debugging and review.
This commit is contained in:
parent
bd2895fdd9
commit
3093576aa4
13 changed files with 2077 additions and 47 deletions
|
@ -6,9 +6,13 @@ addons:
|
||||||
compiler:
|
compiler:
|
||||||
- clang
|
- clang
|
||||||
- gcc
|
- gcc
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- src/java/guava/
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no EXPERIMENTAL=no
|
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no EXPERIMENTAL=no
|
||||||
|
- GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
|
||||||
matrix:
|
matrix:
|
||||||
- SCALAR=32bit RECOVERY=yes
|
- SCALAR=32bit RECOVERY=yes
|
||||||
- SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
|
- SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
|
||||||
|
@ -26,6 +30,7 @@ env:
|
||||||
- BUILD=distcheck
|
- BUILD=distcheck
|
||||||
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
|
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
|
||||||
- EXTRAFLAGS=CFLAGS=-O0
|
- EXTRAFLAGS=CFLAGS=-O0
|
||||||
|
- BUILD=check-java ECDH=yes SCHNORR=yes EXPERIMENTAL=yes
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
include:
|
include:
|
||||||
|
@ -55,6 +60,8 @@ matrix:
|
||||||
packages:
|
packages:
|
||||||
- gcc-multilib
|
- gcc-multilib
|
||||||
- libgmp-dev:i386
|
- libgmp-dev:i386
|
||||||
|
before_install: mkdir -p `dirname $GUAVA_JAR`
|
||||||
|
install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi
|
||||||
before_script: ./autogen.sh
|
before_script: ./autogen.sh
|
||||||
script:
|
script:
|
||||||
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
|
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
|
||||||
|
|
49
Makefile.am
49
Makefile.am
|
@ -1,6 +1,12 @@
|
||||||
ACLOCAL_AMFLAGS = -I build-aux/m4
|
ACLOCAL_AMFLAGS = -I build-aux/m4
|
||||||
|
|
||||||
lib_LTLIBRARIES = libsecp256k1.la
|
lib_LTLIBRARIES = libsecp256k1.la
|
||||||
|
if USE_JNI
|
||||||
|
JNI_LIB = libsecp256k1_jni.la
|
||||||
|
noinst_LTLIBRARIES = $(JNI_LIB)
|
||||||
|
else
|
||||||
|
JNI_LIB =
|
||||||
|
endif
|
||||||
include_HEADERS = include/secp256k1.h
|
include_HEADERS = include/secp256k1.h
|
||||||
noinst_HEADERS =
|
noinst_HEADERS =
|
||||||
noinst_HEADERS += src/scalar.h
|
noinst_HEADERS += src/scalar.h
|
||||||
|
@ -32,6 +38,7 @@ noinst_HEADERS += src/field_5x52_impl.h
|
||||||
noinst_HEADERS += src/field_5x52_int128_impl.h
|
noinst_HEADERS += src/field_5x52_int128_impl.h
|
||||||
noinst_HEADERS += src/field_5x52_asm_impl.h
|
noinst_HEADERS += src/field_5x52_asm_impl.h
|
||||||
noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h
|
noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h
|
||||||
|
noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h
|
||||||
noinst_HEADERS += src/util.h
|
noinst_HEADERS += src/util.h
|
||||||
noinst_HEADERS += src/testrand.h
|
noinst_HEADERS += src/testrand.h
|
||||||
noinst_HEADERS += src/testrand_impl.h
|
noinst_HEADERS += src/testrand_impl.h
|
||||||
|
@ -49,9 +56,11 @@ pkgconfigdir = $(libdir)/pkgconfig
|
||||||
pkgconfig_DATA = libsecp256k1.pc
|
pkgconfig_DATA = libsecp256k1.pc
|
||||||
|
|
||||||
libsecp256k1_la_SOURCES = src/secp256k1.c
|
libsecp256k1_la_SOURCES = src/secp256k1.c
|
||||||
libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
|
libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
|
||||||
libsecp256k1_la_LIBADD = $(SECP_LIBS)
|
libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS)
|
||||||
|
|
||||||
|
libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c
|
||||||
|
libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)
|
||||||
|
|
||||||
noinst_PROGRAMS =
|
noinst_PROGRAMS =
|
||||||
if USE_BENCHMARK
|
if USE_BENCHMARK
|
||||||
|
@ -68,12 +77,42 @@ endif
|
||||||
if USE_TESTS
|
if USE_TESTS
|
||||||
noinst_PROGRAMS += tests
|
noinst_PROGRAMS += tests
|
||||||
tests_SOURCES = src/tests.c
|
tests_SOURCES = src/tests.c
|
||||||
tests_CPPFLAGS = -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
|
tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
|
||||||
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS)
|
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS)
|
||||||
tests_LDFLAGS = -static
|
tests_LDFLAGS = -static
|
||||||
TESTS = tests
|
TESTS = tests
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
JAVAROOT=src/java
|
||||||
|
JAVAORG=org/bitcoin
|
||||||
|
JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar
|
||||||
|
CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA)
|
||||||
|
JAVA_FILES= \
|
||||||
|
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \
|
||||||
|
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \
|
||||||
|
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \
|
||||||
|
$(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java
|
||||||
|
|
||||||
|
if USE_JNI
|
||||||
|
|
||||||
|
$(JAVA_GUAVA):
|
||||||
|
@echo Guava is missing. Fetch it via: \
|
||||||
|
wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@)
|
||||||
|
@false
|
||||||
|
|
||||||
|
.stamp-java: $(JAVA_FILES)
|
||||||
|
@echo Compiling $^
|
||||||
|
$(AM_V_at)$(CLASSPATH_ENV) javac $^
|
||||||
|
@touch $@
|
||||||
|
|
||||||
|
if USE_TESTS
|
||||||
|
|
||||||
|
check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java
|
||||||
|
$(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
if USE_ECMULT_STATIC_PRECOMPUTATION
|
if USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)
|
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)
|
||||||
CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function
|
CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function
|
||||||
|
@ -93,10 +132,10 @@ $(bench_internal_OBJECTS): src/ecmult_static_context.h
|
||||||
src/ecmult_static_context.h: $(gen_context_BIN)
|
src/ecmult_static_context.h: $(gen_context_BIN)
|
||||||
./$(gen_context_BIN)
|
./$(gen_context_BIN)
|
||||||
|
|
||||||
CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h
|
CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java
|
||||||
endif
|
endif
|
||||||
|
|
||||||
EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h
|
EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES)
|
||||||
|
|
||||||
if ENABLE_MODULE_ECDH
|
if ENABLE_MODULE_ECDH
|
||||||
include src/modules/ecdh/Makefile.am.include
|
include src/modules/ecdh/Makefile.am.include
|
||||||
|
|
140
build-aux/m4/ax_jni_include_dir.m4
Normal file
140
build-aux/m4/ax_jni_include_dir.m4
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
# ===========================================================================
|
||||||
|
# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_JNI_INCLUDE_DIR
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# AX_JNI_INCLUDE_DIR finds include directories needed for compiling
|
||||||
|
# programs using the JNI interface.
|
||||||
|
#
|
||||||
|
# JNI include directories are usually in the Java distribution. This is
|
||||||
|
# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in
|
||||||
|
# that order. When this macro completes, a list of directories is left in
|
||||||
|
# the variable JNI_INCLUDE_DIRS.
|
||||||
|
#
|
||||||
|
# Example usage follows:
|
||||||
|
#
|
||||||
|
# AX_JNI_INCLUDE_DIR
|
||||||
|
#
|
||||||
|
# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
|
||||||
|
# do
|
||||||
|
# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR"
|
||||||
|
# done
|
||||||
|
#
|
||||||
|
# If you want to force a specific compiler:
|
||||||
|
#
|
||||||
|
# - at the configure.in level, set JAVAC=yourcompiler before calling
|
||||||
|
# AX_JNI_INCLUDE_DIR
|
||||||
|
#
|
||||||
|
# - at the configure level, setenv JAVAC
|
||||||
|
#
|
||||||
|
# Note: This macro can work with the autoconf M4 macros for Java programs.
|
||||||
|
# This particular macro is not part of the original set of macros.
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Don Anderson <dda@sleepycat.com>
|
||||||
|
#
|
||||||
|
# Copying and distribution of this file, with or without modification, are
|
||||||
|
# permitted in any medium without royalty provided the copyright notice
|
||||||
|
# and this notice are preserved. This file is offered as-is, without any
|
||||||
|
# warranty.
|
||||||
|
|
||||||
|
#serial 10
|
||||||
|
|
||||||
|
AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
|
||||||
|
AC_DEFUN([AX_JNI_INCLUDE_DIR],[
|
||||||
|
|
||||||
|
JNI_INCLUDE_DIRS=""
|
||||||
|
|
||||||
|
if test "x$JAVA_HOME" != x; then
|
||||||
|
_JTOPDIR="$JAVA_HOME"
|
||||||
|
else
|
||||||
|
if test "x$JAVAC" = x; then
|
||||||
|
JAVAC=javac
|
||||||
|
fi
|
||||||
|
AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
|
||||||
|
if test "x$_ACJNI_JAVAC" = xno; then
|
||||||
|
AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME])
|
||||||
|
fi
|
||||||
|
_ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
|
||||||
|
_JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$host_os" in
|
||||||
|
darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
|
||||||
|
_JINC="$_JTOPDIR/Headers";;
|
||||||
|
*) _JINC="$_JTOPDIR/include";;
|
||||||
|
esac
|
||||||
|
_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
|
||||||
|
_AS_ECHO_LOG([_JINC=$_JINC])
|
||||||
|
|
||||||
|
# On Mac OS X 10.6.4, jni.h is a symlink:
|
||||||
|
# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
|
||||||
|
# -> ../../CurrentJDK/Headers/jni.h.
|
||||||
|
|
||||||
|
AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,
|
||||||
|
[
|
||||||
|
if test -f "$_JINC/jni.h"; then
|
||||||
|
ac_cv_jni_header_path="$_JINC"
|
||||||
|
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
|
||||||
|
else
|
||||||
|
_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
|
||||||
|
if test -f "$_JTOPDIR/include/jni.h"; then
|
||||||
|
ac_cv_jni_header_path="$_JTOPDIR/include"
|
||||||
|
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
|
||||||
|
else
|
||||||
|
ac_cv_jni_header_path=none
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# get the likely subdirectories for system specific java includes
|
||||||
|
case "$host_os" in
|
||||||
|
bsdi*) _JNI_INC_SUBDIRS="bsdos";;
|
||||||
|
darwin*) _JNI_INC_SUBDIRS="darwin";;
|
||||||
|
freebsd*) _JNI_INC_SUBDIRS="freebsd";;
|
||||||
|
linux*) _JNI_INC_SUBDIRS="linux genunix";;
|
||||||
|
osf*) _JNI_INC_SUBDIRS="alpha";;
|
||||||
|
solaris*) _JNI_INC_SUBDIRS="solaris";;
|
||||||
|
mingw*) _JNI_INC_SUBDIRS="win32";;
|
||||||
|
cygwin*) _JNI_INC_SUBDIRS="win32";;
|
||||||
|
*) _JNI_INC_SUBDIRS="genunix";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test "x$ac_cv_jni_header_path" != "xnone"; then
|
||||||
|
# add any subdirectories that are present
|
||||||
|
for JINCSUBDIR in $_JNI_INC_SUBDIRS
|
||||||
|
do
|
||||||
|
if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
|
||||||
|
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
# _ACJNI_FOLLOW_SYMLINKS <path>
|
||||||
|
# Follows symbolic links on <path>,
|
||||||
|
# finally setting variable _ACJNI_FOLLOWED
|
||||||
|
# ----------------------------------------
|
||||||
|
AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
|
||||||
|
# find the include directory relative to the javac executable
|
||||||
|
_cur="$1"
|
||||||
|
while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
|
||||||
|
AC_MSG_CHECKING([symlink for $_cur])
|
||||||
|
_slink=`ls -ld "$_cur" | sed 's/.* -> //'`
|
||||||
|
case "$_slink" in
|
||||||
|
/*) _cur="$_slink";;
|
||||||
|
# 'X' avoids triggering unwanted echo options.
|
||||||
|
*) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
|
||||||
|
esac
|
||||||
|
AC_MSG_RESULT([$_cur])
|
||||||
|
done
|
||||||
|
_ACJNI_FOLLOWED="$_cur"
|
||||||
|
])# _ACJNI
|
26
configure.ac
26
configure.ac
|
@ -123,6 +123,11 @@ AC_ARG_ENABLE(module_recovery,
|
||||||
[enable_module_recovery=$enableval],
|
[enable_module_recovery=$enableval],
|
||||||
[enable_module_recovery=no])
|
[enable_module_recovery=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(jni,
|
||||||
|
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
|
||||||
|
[use_jni=$enableval],
|
||||||
|
[use_jni=auto])
|
||||||
|
|
||||||
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
|
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
|
||||||
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
|
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
|
||||||
|
|
||||||
|
@ -323,6 +328,22 @@ if test x"$use_tests" = x"yes"; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test x"$use_jni" != x"no"; then
|
||||||
|
AX_JNI_INCLUDE_DIR
|
||||||
|
if test "x$JNI_INCLUDE_DIRS" = "x"; then
|
||||||
|
if test x"$use_jni" = x"yes"; then
|
||||||
|
AC_MSG_ERROR([jni support explicitly requested but headers were not found])
|
||||||
|
fi
|
||||||
|
AC_MSG_WARN([jni headers not found. jni support disabled])
|
||||||
|
use_jni=no
|
||||||
|
else
|
||||||
|
use_jni=yes
|
||||||
|
for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
|
||||||
|
JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if test x"$set_bignum" = x"gmp"; then
|
if test x"$set_bignum" = x"gmp"; then
|
||||||
SECP_LIBS="$SECP_LIBS $GMP_LIBS"
|
SECP_LIBS="$SECP_LIBS $GMP_LIBS"
|
||||||
SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS"
|
SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS"
|
||||||
|
@ -355,7 +376,10 @@ AC_MSG_NOTICE([Using field implementation: $set_field])
|
||||||
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
|
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
|
||||||
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
|
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
|
||||||
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
|
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
|
||||||
|
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
||||||
|
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
|
||||||
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
|
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
|
||||||
|
AC_MSG_NOTICE([Using jni: $use_jni])
|
||||||
|
|
||||||
if test x"$enable_experimental" = x"yes"; then
|
if test x"$enable_experimental" = x"yes"; then
|
||||||
AC_MSG_NOTICE([******])
|
AC_MSG_NOTICE([******])
|
||||||
|
@ -375,6 +399,7 @@ fi
|
||||||
|
|
||||||
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
|
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
|
||||||
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
|
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
|
||||||
|
AC_SUBST(JNI_INCLUDES)
|
||||||
AC_SUBST(SECP_INCLUDES)
|
AC_SUBST(SECP_INCLUDES)
|
||||||
AC_SUBST(SECP_LIBS)
|
AC_SUBST(SECP_LIBS)
|
||||||
AC_SUBST(SECP_TEST_LIBS)
|
AC_SUBST(SECP_TEST_LIBS)
|
||||||
|
@ -385,6 +410,7 @@ AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_pr
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"])
|
AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"])
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||||
|
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
|
||||||
|
|
||||||
dnl make sure nothing new is exported so that we don't break the cache
|
dnl make sure nothing new is exported so that we don't break the cache
|
||||||
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
|
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
|
||||||
|
|
|
@ -3,8 +3,11 @@ package org.bitcoin;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import static org.bitcoin.NativeSecp256k1Util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class holds native methods to handle ECDSA verification.
|
* This class holds native methods to handle ECDSA verification.
|
||||||
|
@ -12,17 +15,10 @@ import com.google.common.base.Preconditions;
|
||||||
* https://github.com/sipa/secp256k1
|
* https://github.com/sipa/secp256k1
|
||||||
*/
|
*/
|
||||||
public class NativeSecp256k1 {
|
public class NativeSecp256k1 {
|
||||||
public static final boolean enabled;
|
|
||||||
static {
|
|
||||||
boolean isEnabled = true;
|
|
||||||
try {
|
|
||||||
System.loadLibrary("javasecp256k1");
|
|
||||||
} catch (UnsatisfiedLinkError e) {
|
|
||||||
isEnabled = false;
|
|
||||||
}
|
|
||||||
enabled = isEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||||
|
private static final Lock r = rwl.readLock();
|
||||||
|
private static final Lock w = rwl.writeLock();
|
||||||
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
|
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
|
||||||
/**
|
/**
|
||||||
* Verifies the given secp256k1 signature in native code.
|
* Verifies the given secp256k1 signature in native code.
|
||||||
|
@ -32,29 +28,724 @@ public class NativeSecp256k1 {
|
||||||
* @param signature The signature
|
* @param signature The signature
|
||||||
* @param pub The public key which did the signing
|
* @param pub The public key which did the signing
|
||||||
*/
|
*/
|
||||||
public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
|
public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{
|
||||||
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
|
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
|
||||||
|
|
||||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
if (byteBuff == null) {
|
if (byteBuff == null || byteBuff.capacity() < 520) {
|
||||||
byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);
|
byteBuff = ByteBuffer.allocateDirect(520);
|
||||||
byteBuff.order(ByteOrder.nativeOrder());
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
nativeECDSABuffer.set(byteBuff);
|
nativeECDSABuffer.set(byteBuff);
|
||||||
}
|
}
|
||||||
byteBuff.rewind();
|
byteBuff.rewind();
|
||||||
byteBuff.put(data);
|
byteBuff.put(data);
|
||||||
byteBuff.putInt(signature.length);
|
|
||||||
byteBuff.putInt(pub.length);
|
|
||||||
byteBuff.put(signature);
|
byteBuff.put(signature);
|
||||||
byteBuff.put(pub);
|
byteBuff.put(pub);
|
||||||
return secp256k1_ecdsa_verify(byteBuff) == 1;
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param byteBuff signature format is byte[32] data,
|
* recover the given secp256k1 pubkey in native code.
|
||||||
* native-endian int signatureLength, native-endian int pubkeyLength,
|
*
|
||||||
* byte[signatureLength] signature, byte[pubkeyLength] pub
|
* @param data The data which was signed, must be exactly 32 bytes
|
||||||
* @returns 1 for valid signature, anything else for invalid
|
* @param signature The signature
|
||||||
|
* @param compressed whether to recover a compressed pubkey
|
||||||
|
* @param pub The public key which did the signing
|
||||||
*/
|
*/
|
||||||
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff);
|
//TODO recoverCompact()
|
||||||
|
public static byte[] recoverCompact(byte[] data, byte[] signature,int compressed, int recID) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(data.length == 32 && signature.length == 64 && (compressed == 0 || compressed == 1));
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < 32 + 64) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(32 + 64);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(data);
|
||||||
|
byteBuff.put(signature);
|
||||||
|
|
||||||
|
byte[][] retByteArray = null;//secp256k1_ecdsa_recover_compact(byteBuff, Secp256k1Context, compressed, recID);
|
||||||
|
|
||||||
|
byte[] pubArr = retByteArray[0];
|
||||||
|
int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(pubArr.length, pubLen, "Got bad signature length.");
|
||||||
|
|
||||||
|
assertEquals(retVal, 1, "Failed return value check.");
|
||||||
|
|
||||||
|
return pubArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 Create an ECDSA signature.
|
||||||
|
*
|
||||||
|
* @param data Message hash, 32 bytes
|
||||||
|
* @param key Secret key, 32 bytes
|
||||||
|
*
|
||||||
|
* Return values
|
||||||
|
* @param sig byte array of signature
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(32 + 32);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(data);
|
||||||
|
byteBuff.put(sec);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] sigArr = retByteArray[0];
|
||||||
|
int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(sigArr.length, sigLen, "Got bad signature length.");
|
||||||
|
|
||||||
|
return retVal == 0 ? new byte[0] : sigArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
|
||||||
|
*
|
||||||
|
* @param seckey ECDSA Secret key, 32 bytes
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static boolean secKeyVerify(byte[] seckey) {
|
||||||
|
Preconditions.checkArgument(seckey.length == 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < seckey.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(seckey.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(seckey);
|
||||||
|
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
return 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
|
||||||
|
* @param compressed 1 to return compressed key, 0 for uncompressed
|
||||||
|
*
|
||||||
|
* Return values
|
||||||
|
* @param pubkey ECDSA Public key, 33 or 65 bytes
|
||||||
|
*/
|
||||||
|
|
||||||
|
//TODO support 'compressed' arg
|
||||||
|
public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(seckey.length == 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < seckey.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(seckey.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(seckey);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] pubArr = retByteArray[0];
|
||||||
|
int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
return retVal == 0 ? new byte[0]: 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.
|
||||||
|
*/
|
||||||
|
public static synchronized void cleanup() {
|
||||||
|
w.lock();
|
||||||
|
try {
|
||||||
|
secp256k1_destroy_context(Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
w.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 Secret Key Import - Import a secret key in DER format.
|
||||||
|
*
|
||||||
|
* @param seckey DER Sec key
|
||||||
|
* @param compressed Compressed format
|
||||||
|
*/
|
||||||
|
public static byte[] secKeyImport(byte[] seckey) throws AssertFailException{
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < seckey.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(seckey.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(seckey);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_ec_privkey_import(byteBuff,Secp256k1Context.getContext(), seckey.length);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] privArr = retByteArray[0];
|
||||||
|
|
||||||
|
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(privArr.length, privLen, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
assertEquals(retVal, 1, "Failed return value check.");
|
||||||
|
|
||||||
|
return privArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 Private Key Export - Export a private key in DER format.
|
||||||
|
*
|
||||||
|
* @param seckey ECDSA Sec key, 33 or 65 bytes
|
||||||
|
* @param compressed Compressed format
|
||||||
|
*/
|
||||||
|
public static byte[] privKeyExport(byte[] privkey, int compressed) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(privkey.length == 32 && (compressed == 0 || compressed == 1));
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < privkey.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(privkey.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(privkey);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_ec_privkey_export(byteBuff, Secp256k1Context.getContext(), privkey.length, compressed);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] privArr = retByteArray[0];
|
||||||
|
|
||||||
|
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(privArr.length, compressed == 1 ? 214 : 279, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
assertEquals(retVal, 1, "Failed return value check.");
|
||||||
|
|
||||||
|
return privArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long cloneContext() {
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
return secp256k1_ctx_clone(Secp256k1Context.getContext());
|
||||||
|
} finally { r.unlock(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
|
||||||
|
*
|
||||||
|
* @param tweak some bytes to tweak with
|
||||||
|
* @param seckey 32-byte seckey
|
||||||
|
*/
|
||||||
|
public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(privkey.length == 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(privkey);
|
||||||
|
byteBuff.put(tweak);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] privArr = retByteArray[0];
|
||||||
|
|
||||||
|
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(privArr.length, privLen, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
assertEquals(retVal, 1, "Failed return value check.");
|
||||||
|
|
||||||
|
return privArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
|
||||||
|
*
|
||||||
|
* @param tweak some bytes to tweak with
|
||||||
|
* @param seckey 32-byte seckey
|
||||||
|
*/
|
||||||
|
public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(privkey.length == 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(privkey);
|
||||||
|
byteBuff.put(tweak);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] privArr = retByteArray[0];
|
||||||
|
|
||||||
|
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(privArr.length, privLen, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
assertEquals(retVal, 1, "Failed return value check.");
|
||||||
|
|
||||||
|
return privArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
|
||||||
|
*
|
||||||
|
* @param tweak some bytes to tweak with
|
||||||
|
* @param pubkey 32-byte seckey
|
||||||
|
*/
|
||||||
|
public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(pubkey);
|
||||||
|
byteBuff.put(tweak);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] pubArr = retByteArray[0];
|
||||||
|
|
||||||
|
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(pubkey);
|
||||||
|
byteBuff.put(tweak);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] pubArr = retByteArray[0];
|
||||||
|
|
||||||
|
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
//TODO schnorrSign, schnoorVerify, schnorrRecover()
|
||||||
|
public static byte[] schnoorOps(byte[] pubkey, byte[] msg32) throws AssertFailException{
|
||||||
|
/*
|
||||||
|
Preconditions.checkArgument(msg32.length == 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < pubkeys.length * 65) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(pubkeys.length * 65);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(pubkey);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_ecdsa_recover(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] pubArr = retByteArray[0];
|
||||||
|
|
||||||
|
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(pubArr.length, pubLen, "Got bad pubkey length." );
|
||||||
|
|
||||||
|
assertEquals(retVal,1, "Failed return value check.");
|
||||||
|
|
||||||
|
return pubArr;*/
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(seckey);
|
||||||
|
byteBuff.put(pubkey);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] resArr = retByteArray[0];
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(resArr.length, 32, "Got bad result length.");
|
||||||
|
assertEquals(retVal, 1, "Failed return value check.");
|
||||||
|
|
||||||
|
return resArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 createRecoverableSig - create recoverable signature
|
||||||
|
*
|
||||||
|
* @param seckey byte array of secret key used in signing
|
||||||
|
* @param msg32 32-byte signed message hash
|
||||||
|
*/
|
||||||
|
//TODO createRecoverableSig()
|
||||||
|
public static byte[] createRecoverableSig(byte[] pubkey, byte[] msg32) throws AssertFailException{
|
||||||
|
/*
|
||||||
|
Preconditions.checkArgument(msg32.length == 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < pubkeys.length * 65) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(pubkeys.length * 65);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(pubkey);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_ecdsa_recover(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] pubArr = retByteArray[0];
|
||||||
|
|
||||||
|
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(pubArr.length, pubLen, "Got bad pubkey length." );
|
||||||
|
|
||||||
|
assertEquals(retVal,1, "Failed return value check.");
|
||||||
|
|
||||||
|
return pubArr;
|
||||||
|
*/
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 Recover pubkey - recover pubkey from signature
|
||||||
|
*
|
||||||
|
* @param sig byte array of signature
|
||||||
|
* @param msg32 32-byte signed message hash
|
||||||
|
*/
|
||||||
|
//TODO recoverPubkey()
|
||||||
|
public static byte[] recoverPubkey(byte[] pubkey, byte[] msg32) throws AssertFailException{
|
||||||
|
|
||||||
|
|
||||||
|
return new byte[0];
|
||||||
|
/*
|
||||||
|
Preconditions.checkArgument(msg32.length == 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < pubkeys.length * 65) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(pubkeys.length * 65);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(pubkey);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_ecdsa_recover(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] pubArr = retByteArray[0];
|
||||||
|
|
||||||
|
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(pubArr.length, pubLen, "Got bad pubkey length." );
|
||||||
|
|
||||||
|
assertEquals(retVal,1, "Failed return value check.");
|
||||||
|
|
||||||
|
return pubArr;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 PubKey combine - add pubkeys together
|
||||||
|
*
|
||||||
|
* @param pubkeys byte array of pubkeys
|
||||||
|
* @param numKeys number of pubkeys to add
|
||||||
|
*/
|
||||||
|
//TODO pubkeyCombine
|
||||||
|
public static byte[] pubKeyCombine(byte[][] pubkeys, int numKeys) throws AssertFailException{
|
||||||
|
/*
|
||||||
|
Preconditions.checkArgument(pubkeys.length > 0);
|
||||||
|
for(int i = 0; i < pubkeys.length; i++) Preconditions.checkArgument(pubkeys[i].length == 65 || pubkeys[i].length == 33);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < pubkeys.length * 65) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(pubkeys.length * 65);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(pubkey);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_pubkey_combine(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] pubArr = retByteArray[0];
|
||||||
|
|
||||||
|
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(pubArr.length, pubLen, "Got bad pubkey length." );
|
||||||
|
|
||||||
|
assertEquals(retVal,1, "Failed return value check.");
|
||||||
|
|
||||||
|
return pubArr;
|
||||||
|
*/
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* libsecp256k1 randomize - updates the context randomization
|
||||||
|
*
|
||||||
|
* @param seed 32-byte random seed
|
||||||
|
*/
|
||||||
|
public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
|
||||||
|
Preconditions.checkArgument(seed.length == 32 || seed == null);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null || byteBuff.capacity() < seed.length) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(seed.length);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(seed);
|
||||||
|
|
||||||
|
w.lock();
|
||||||
|
try {
|
||||||
|
return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
|
||||||
|
} finally {
|
||||||
|
w.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] schnorrSign(byte[] data, byte[] sec) throws AssertFailException {
|
||||||
|
Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
|
||||||
|
|
||||||
|
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||||
|
if (byteBuff == null) {
|
||||||
|
byteBuff = ByteBuffer.allocateDirect(32 + 32);
|
||||||
|
byteBuff.order(ByteOrder.nativeOrder());
|
||||||
|
nativeECDSABuffer.set(byteBuff);
|
||||||
|
}
|
||||||
|
byteBuff.rewind();
|
||||||
|
byteBuff.put(data);
|
||||||
|
byteBuff.put(sec);
|
||||||
|
|
||||||
|
byte[][] retByteArray;
|
||||||
|
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
retByteArray = secp256k1_schnorr_sign(byteBuff, Secp256k1Context.getContext());
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] sigArr = retByteArray[0];
|
||||||
|
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||||
|
|
||||||
|
assertEquals(sigArr.length, 64, "Got bad signature length.");
|
||||||
|
|
||||||
|
return retVal == 0 ? new byte[0] : sigArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native long secp256k1_ctx_clone(long context);
|
||||||
|
|
||||||
|
private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
|
||||||
|
|
||||||
|
private static native void secp256k1_destroy_context(long context);
|
||||||
|
|
||||||
|
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_ec_privkey_export(ByteBuffer byteBuff, long context, int privLen, int compressed);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_ec_privkey_import(ByteBuffer byteBuff, long context, int privLen);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_ecdsa_signature_parse_der(ByteBuffer byteBuff, long context, int inputLen);
|
||||||
|
|
||||||
|
//TODO sigNormalize()
|
||||||
|
private static native byte[][] secp256k1_ecdsa_signature_normalize(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
|
||||||
|
|
||||||
|
private static native long secp256k1_ecdsa_pubkey_combine(ByteBuffer byteBuff, long context, int keys);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context);
|
||||||
|
|
||||||
|
private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
351
src/java/org/bitcoin/NativeSecp256k1Test.java
Normal file
351
src/java/org/bitcoin/NativeSecp256k1Test.java
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
package org.bitcoin;
|
||||||
|
|
||||||
|
import com.google.common.io.BaseEncoding;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import javax.xml.bind.DatatypeConverter;
|
||||||
|
import static org.bitcoin.NativeSecp256k1Util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class holds test cases defined for testing this library.
|
||||||
|
*/
|
||||||
|
public class NativeSecp256k1Test {
|
||||||
|
|
||||||
|
//TODO improve comments/add more tests
|
||||||
|
/**
|
||||||
|
* This tests verify() for a valid signature
|
||||||
|
*/
|
||||||
|
public static void testVerifyPos() throws AssertFailException{
|
||||||
|
boolean result = false;
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
|
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
|
||||||
|
result = NativeSecp256k1.verify( data, sig, pub);
|
||||||
|
assertEquals( result, true , "testVerifyPos");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests verify() for a non-valid signature
|
||||||
|
*/
|
||||||
|
public static void testVerifyNeg() throws AssertFailException{
|
||||||
|
boolean result = false;
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
|
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
|
||||||
|
result = NativeSecp256k1.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
|
||||||
|
*/
|
||||||
|
public static void testSecKeyVerifyPos() throws AssertFailException{
|
||||||
|
boolean result = false;
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
|
||||||
|
result = NativeSecp256k1.secKeyVerify( sec );
|
||||||
|
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||||
|
assertEquals( result, true , "testSecKeyVerifyPos");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests secret key verify() for a invalid secretkey
|
||||||
|
*/
|
||||||
|
public static void testSecKeyVerifyNeg() throws AssertFailException{
|
||||||
|
boolean result = false;
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||||
|
|
||||||
|
result = NativeSecp256k1.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
|
||||||
|
*/
|
||||||
|
public static void testPubKeyCreatePos() throws AssertFailException{
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
|
||||||
|
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests public key create() for a invalid secretkey
|
||||||
|
*/
|
||||||
|
public static void testPubKeyCreateNeg() throws AssertFailException{
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
|
||||||
|
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( pubkeyString, "" , "testPubKeyCreateNeg");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests sign() for a valid secretkey
|
||||||
|
*/
|
||||||
|
public static void testSignPos() throws AssertFailException{
|
||||||
|
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.sign(data, sec);
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests sign() for a invalid secretkey
|
||||||
|
*/
|
||||||
|
public static void testSignNeg() throws AssertFailException{
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.sign(data, sec);
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString, "" , "testSignNeg");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key export
|
||||||
|
*/
|
||||||
|
public static void testPrivKeyExportComp() throws AssertFailException{
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.privKeyExport( sec , 1);
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "3081D3020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A08185308182020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704210279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A12403220002C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 12");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key export
|
||||||
|
*/
|
||||||
|
public static void testPrivKeyExportUncomp() throws AssertFailException{
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.privKeyExport( sec , 0);
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "30820113020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A081A53081A2020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704410479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A14403420004C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "Case 13");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key import
|
||||||
|
*/
|
||||||
|
public static void testSecKeyImportPos() throws AssertFailException {
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("3081D3020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A08185308182020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704210279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A12403220002C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.secKeyImport( sec );
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
|
||||||
|
assertEquals( sigString , "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530" , "testSecKeyImport");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key export
|
||||||
|
*/
|
||||||
|
public static void testSecKeyImportPos2() throws AssertFailException {
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("30820113020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A081A53081A2020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704410479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A14403420004C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.secKeyImport( sec );
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530" , "testSecKeyImport2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-add
|
||||||
|
*/
|
||||||
|
public static void testPrivKeyTweakAdd_1() throws AssertFailException {
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data );
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-mul
|
||||||
|
*/
|
||||||
|
public static void testPrivKeyTweakMul_1() throws AssertFailException {
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data );
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-add uncompressed
|
||||||
|
*/
|
||||||
|
public static void testPrivKeyTweakAdd_2() throws AssertFailException {
|
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data );
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests private key tweak-mul uncompressed
|
||||||
|
*/
|
||||||
|
public static void testPrivKeyTweakMul_2() throws AssertFailException {
|
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data );
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests seed randomization
|
||||||
|
*/
|
||||||
|
public static void testRandomize() throws AssertFailException {
|
||||||
|
byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random"
|
||||||
|
boolean result = NativeSecp256k1.randomize(seed);
|
||||||
|
assertEquals( result, true, "testRandomize");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void testRecover() throws AssertFailException {
|
||||||
|
|
||||||
|
/* TODO update this with functions from include/secp256k1_recovery.h
|
||||||
|
//Case 17
|
||||||
|
data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
|
||||||
|
sig = BaseEncoding.base16().lowerCase().decode("A33C093C80B84CA1AFBC8974EE3C42FC1CBC966CAE66612593CD1E44646BABFF00CB69703B98B0103AE22C7F9CCADD8DD98F9505BE7A66B1AE459576E930C4F6".toLowerCase());
|
||||||
|
pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
int recid = 1;
|
||||||
|
|
||||||
|
resultArr = NativeSecp256k1.recoverCompact( data , sig , 0, recid );
|
||||||
|
sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "Case 17");
|
||||||
|
|
||||||
|
resultArr = NativeSecp256k1.recoverCompact( data , sig , 1, recid );
|
||||||
|
sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "02C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 18");
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void testRecoverCompact() throws AssertFailException {
|
||||||
|
|
||||||
|
/* TODO update this with functions from include/secp256k1_recovery.h
|
||||||
|
//Case 17
|
||||||
|
data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
|
||||||
|
sig = BaseEncoding.base16().lowerCase().decode("A33C093C80B84CA1AFBC8974EE3C42FC1CBC966CAE66612593CD1E44646BABFF00CB69703B98B0103AE22C7F9CCADD8DD98F9505BE7A66B1AE459576E930C4F6".toLowerCase());
|
||||||
|
pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
int recid = 1;
|
||||||
|
|
||||||
|
resultArr = NativeSecp256k1.recoverCompact( data , sig , 0, recid );
|
||||||
|
sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "Case 17");
|
||||||
|
|
||||||
|
resultArr = NativeSecp256k1.recoverCompact( data , sig , 1, recid );
|
||||||
|
sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString , "02C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 18");
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests signSchnorr() for a valid secretkey
|
||||||
|
*/
|
||||||
|
public static void testSchnorrSign() throws AssertFailException{
|
||||||
|
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.schnorrSign(data, sec);
|
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( sigString, "C5E929AA058B982048760422D3B563749B7D0E50C5EBD8CD2FFC23214BD6A2F1B072C13880997EBA847CF20F2F90FCE07C1CA33A890A4127095A351127F8D95F" , "testSchnorrSign");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tests signSchnorr() for a valid secretkey
|
||||||
|
*/
|
||||||
|
public static void testCreateECDHSecret() throws AssertFailException{
|
||||||
|
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub);
|
||||||
|
String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||||
|
assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws AssertFailException{
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n");
|
||||||
|
|
||||||
|
assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" );
|
||||||
|
|
||||||
|
//Test verify() success/fail
|
||||||
|
testVerifyPos();
|
||||||
|
testVerifyNeg();
|
||||||
|
|
||||||
|
//Test secKeyVerify() success/fail
|
||||||
|
testSecKeyVerifyPos();
|
||||||
|
testSecKeyVerifyNeg();
|
||||||
|
|
||||||
|
//Test computePubkey() success/fail
|
||||||
|
testPubKeyCreatePos();
|
||||||
|
testPubKeyCreateNeg();
|
||||||
|
|
||||||
|
//Test sign() success/fail
|
||||||
|
testSignPos();
|
||||||
|
testSignNeg();
|
||||||
|
|
||||||
|
//Test privKeyExport() compressed/uncomp
|
||||||
|
//testPrivKeyExportComp(); //Now in /contrib
|
||||||
|
//testPrivKeyExportUncomp(); //Now in /contrib
|
||||||
|
|
||||||
|
//Test secKeyImport()/2
|
||||||
|
//testSecKeyImportPos(); //Now in /contrib
|
||||||
|
//testSecKeyImportPos2(); //Now in /contrib
|
||||||
|
|
||||||
|
//Test recovery //TODO
|
||||||
|
//testRecoverCompact();
|
||||||
|
//testRecover();
|
||||||
|
//testCreateRecoverable();
|
||||||
|
|
||||||
|
//Test ECDH //TODO
|
||||||
|
//testECDHSecretGen();
|
||||||
|
|
||||||
|
//Test Schnorr (partial support) //TODO
|
||||||
|
testSchnorrSign();
|
||||||
|
//testSchnorrVerify
|
||||||
|
//testSchnorrRecovery
|
||||||
|
|
||||||
|
//Test pubkeyCombine //TODO
|
||||||
|
//test pubkeyCombine
|
||||||
|
|
||||||
|
//Test privKeyTweakAdd() 1
|
||||||
|
testPrivKeyTweakAdd_1();
|
||||||
|
|
||||||
|
//Test privKeyTweakMul() 2
|
||||||
|
testPrivKeyTweakMul_1();
|
||||||
|
|
||||||
|
//Test privKeyTweakAdd() 3
|
||||||
|
testPrivKeyTweakAdd_2();
|
||||||
|
|
||||||
|
//Test privKeyTweakMul() 4
|
||||||
|
testPrivKeyTweakMul_2();
|
||||||
|
|
||||||
|
//Test randomize()
|
||||||
|
testRandomize();
|
||||||
|
|
||||||
|
//Test ECDH
|
||||||
|
testCreateECDHSecret();
|
||||||
|
|
||||||
|
NativeSecp256k1.cleanup();
|
||||||
|
|
||||||
|
System.out.println(" All tests passed." );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
29
src/java/org/bitcoin/NativeSecp256k1Util.java
Normal file
29
src/java/org/bitcoin/NativeSecp256k1Util.java
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package org.bitcoin;
|
||||||
|
|
||||||
|
public class NativeSecp256k1Util{
|
||||||
|
|
||||||
|
public static void assertEquals( int val, int val2, String message ) throws AssertFailException{
|
||||||
|
if( val != val2 )
|
||||||
|
throw new AssertFailException("FAIL: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{
|
||||||
|
if( val != val2 )
|
||||||
|
throw new AssertFailException("FAIL: " + message);
|
||||||
|
else
|
||||||
|
System.out.println("PASS: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertEquals( String val, String val2, String message ) throws AssertFailException{
|
||||||
|
if( !val.equals(val2) )
|
||||||
|
throw new AssertFailException("FAIL: " + message);
|
||||||
|
else
|
||||||
|
System.out.println("PASS: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AssertFailException extends Exception {
|
||||||
|
public AssertFailException(String message) {
|
||||||
|
super( message );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
src/java/org/bitcoin/Secp256k1Context.java
Normal file
35
src/java/org/bitcoin/Secp256k1Context.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package org.bitcoin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class holds the context reference used in native methods
|
||||||
|
to handle ECDSA operations.
|
||||||
|
*/
|
||||||
|
public class Secp256k1Context {
|
||||||
|
private static final boolean enabled; //true if the library is loaded
|
||||||
|
private static final long context; //ref to pointer to context obj
|
||||||
|
|
||||||
|
static { //static initializer
|
||||||
|
boolean isEnabled = true;
|
||||||
|
long contextRef = -1;
|
||||||
|
try {
|
||||||
|
System.loadLibrary("secp256k1");
|
||||||
|
contextRef = secp256k1_init_context();
|
||||||
|
} catch (UnsatisfiedLinkError e) {
|
||||||
|
System.out.println("UnsatisfiedLinkError: " + e.toString());
|
||||||
|
isEnabled = false;
|
||||||
|
}
|
||||||
|
enabled = isEnabled;
|
||||||
|
context = contextRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getContext() {
|
||||||
|
if(!enabled) return -1; //sanity check
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native long secp256k1_init_context();
|
||||||
|
}
|
|
@ -1,23 +1,572 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include "org_bitcoin_NativeSecp256k1.h"
|
#include "org_bitcoin_NativeSecp256k1.h"
|
||||||
#include "include/secp256k1.h"
|
#include "include/secp256k1.h"
|
||||||
|
#include "include/secp256k1_recovery.h"
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
|
||||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject)
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||||
|
(JNIEnv* env, jclass classObject, jlong ctx_l)
|
||||||
{
|
{
|
||||||
|
const secp256k1_context *ctx = (secp256k1_context*)ctx_l;
|
||||||
|
|
||||||
|
jlong ctx_clone_l = (jlong) secp256k1_context_clone(ctx);
|
||||||
|
|
||||||
|
(void)classObject;(void)env;
|
||||||
|
|
||||||
|
return (jlong)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*)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*)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*)ctx_l;
|
||||||
|
|
||||||
|
int result;
|
||||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
int sigLen = *((int*)(data + 32));
|
const unsigned char* sigdata = { (unsigned char*) (data + 32) };
|
||||||
int pubLen = *((int*)(data + 32 + 4));
|
const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) };
|
||||||
|
|
||||||
return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen);
|
secp256k1_ecdsa_signature sig;
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
|
||||||
|
int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Debug
|
||||||
|
printf("\nData: ");
|
||||||
|
int i;
|
||||||
|
for( i = 0; i < 32; i++) printf("%x", data[i]);
|
||||||
|
printf("\nSig: ");
|
||||||
|
for( i = 0; i < 64; i++) printf("%x", sig->data[i]);
|
||||||
|
printf("\nPub: ");
|
||||||
|
for( i = 0; i < 64; i++) printf("%x", pub->data[i]);
|
||||||
|
*/
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
result = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __javasecp256k1_attach(void) __attribute__((constructor));
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
|
||||||
static void __javasecp256k1_detach(void) __attribute__((destructor));
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)ctx_l;
|
||||||
|
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
unsigned char* secKey = (unsigned char*) (data + 32);
|
||||||
|
|
||||||
static void __javasecp256k1_attach(void) {
|
jobjectArray retArray;
|
||||||
secp256k1_start(SECP256K1_START_VERIFY);
|
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[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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __javasecp256k1_detach(void) {
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
|
||||||
secp256k1_stop();
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)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*)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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO replace with contrib/ code */
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1export
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint privLen, jint compressed)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)ctx_l;
|
||||||
|
|
||||||
|
const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
|
||||||
|
int i, ret;
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray privkeyArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
unsigned char* privkey = (unsigned char*) malloc(sizeof(unsigned char)*279);
|
||||||
|
|
||||||
|
for(i = 0; i < privLen; i++) privkey[i] = secKey[i];
|
||||||
|
|
||||||
|
ret = secp256k1_ec_privkey_export(ctx, privkey , (size_t*)&privLen, secKey, compressed);
|
||||||
|
|
||||||
|
intsarray[0] = privLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
privkeyArray = (*env)->NewByteArray(env, privLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, privkeyArray, 0, privLen, (jbyte*)privkey);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, privkeyArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO replace with contrib/ code */
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1import
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint privLen)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)ctx_l;
|
||||||
|
|
||||||
|
const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray privkeyArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
unsigned char privkey[32];
|
||||||
|
|
||||||
|
int ret = secp256k1_ec_privkey_import(ctx, privkey, secKey, privLen);
|
||||||
|
|
||||||
|
privLen = 32;
|
||||||
|
|
||||||
|
intsarray[0] = privLen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
privkeyArray = (*env)->NewByteArray(env, privLen);
|
||||||
|
(*env)->SetByteArrayRegion(env, privkeyArray, 0, privLen, (jbyte*)privkey);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, privkeyArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||||
|
|
||||||
|
(void)classObject;
|
||||||
|
|
||||||
|
return retArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO replace with serialize_compact() code */
|
||||||
|
/*SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)ctx_l;
|
||||||
|
const unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* secKey = (unsigned char*) (data + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray sigArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
unsigned char sig[64];
|
||||||
|
int siglen = 64;
|
||||||
|
int recID;
|
||||||
|
|
||||||
|
int ret = secp256k1_ecdsa_sign_compact(ctx, data, sig, secKey, NULL, NULL, &recID );
|
||||||
|
|
||||||
|
intsarray[0] = recID;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
sigArray = (*env)->NewByteArray(env, siglen);
|
||||||
|
(*env)->SetByteArrayRegion(env, sigArray, 0, siglen, (jbyte*)sig);
|
||||||
|
(*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;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO replace with recover_compact() code */
|
||||||
|
/*
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1recover_1compact
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint compressed, jint recid)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)ctx_l;
|
||||||
|
const unsigned char* msg = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||||
|
const unsigned char* sig = (unsigned char*) (msg + 32);
|
||||||
|
|
||||||
|
jobjectArray retArray;
|
||||||
|
jbyteArray pubArray, intsByteArray;
|
||||||
|
unsigned char intsarray[2];
|
||||||
|
|
||||||
|
unsigned char pubkey[64];
|
||||||
|
int pubkeylen;
|
||||||
|
|
||||||
|
int ret = secp256k1_ecdsa_recover_compact(ctx, msg, sig, pubkey, &pubkeylen, compressed, recid );
|
||||||
|
|
||||||
|
intsarray[0] = pubkeylen;
|
||||||
|
intsarray[1] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
pubArray = (*env)->NewByteArray(env, pubkeylen);
|
||||||
|
(*env)->SetByteArrayRegion(env, pubArray, 0, pubkeylen, (jbyte*)pubkey);
|
||||||
|
(*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_1privkey_1tweak_1add
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)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*)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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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*)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*)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;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine
|
||||||
|
(JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys)
|
||||||
|
{
|
||||||
|
(void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
|
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||||
|
{
|
||||||
|
secp256k1_context *ctx = (secp256k1_context*)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[1];
|
||||||
|
unsigned char sig[64];
|
||||||
|
|
||||||
|
int ret = secp256k1_schnorr_sign(ctx, sig, data, secKey, NULL, NULL);
|
||||||
|
|
||||||
|
intsarray[0] = ret;
|
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2,
|
||||||
|
(*env)->FindClass(env, "[B"),
|
||||||
|
(*env)->NewByteArray(env, 1));
|
||||||
|
|
||||||
|
sigArray = (*env)->NewByteArray(env, 64);
|
||||||
|
(*env)->SetByteArrayRegion(env, sigArray, 0, 64, (jbyte*)sig);
|
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
|
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 1);
|
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (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*)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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
#include "include/secp256k1.h"
|
||||||
/* Header for class org_bitcoin_NativeSecp256k1 */
|
/* Header for class org_bitcoin_NativeSecp256k1 */
|
||||||
|
|
||||||
#ifndef _Included_org_bitcoin_NativeSecp256k1
|
#ifndef _Included_org_bitcoin_NativeSecp256k1
|
||||||
|
@ -9,11 +10,139 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
* Class: org_bitcoin_NativeSecp256k1
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
* Method: secp256k1_ecdsa_verify
|
* Method: secp256k1_ctx_clone
|
||||||
* Signature: (Ljava/nio/ByteBuffer;)I
|
* Signature: (J)J
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||||
(JNIEnv *, jclass, jobject);
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_context_randomize
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)I
|
||||||
|
*/
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_privkey_tweak_add
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API 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
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_pubkey_tweak_add
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API 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
|
||||||
|
*/
|
||||||
|
SECP256K1_API 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
|
||||||
|
*/
|
||||||
|
SECP256K1_API 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
|
||||||
|
*/
|
||||||
|
SECP256K1_API 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
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ec_seckey_verify
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)I
|
||||||
|
*/
|
||||||
|
SECP256K1_API 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
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ec_privkey_export
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JII)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1export
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ec_privkey_import
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1import
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdsa_signature_parse_der
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1der
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdsa_signature_normalize
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1normalize
|
||||||
|
(JNIEnv *, jclass, jobject, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ec_pubkey_parse
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||||
|
*/
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_NativeSecp256k1
|
||||||
|
* Method: secp256k1_ecdsa_pubkey_combine
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;JI)J
|
||||||
|
*/
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine
|
||||||
|
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
14
src/java/org_bitcoin_Secp256k1Context.c
Normal file
14
src/java/org_bitcoin_Secp256k1Context.c
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include <stdlib.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 (jlong)ctx;
|
||||||
|
}
|
||||||
|
|
22
src/java/org_bitcoin_Secp256k1Context.h
Normal file
22
src/java/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
|
|
@ -4,8 +4,6 @@
|
||||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
#define SECP256K1_BUILD (1)
|
|
||||||
|
|
||||||
#include "include/secp256k1.h"
|
#include "include/secp256k1.h"
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
Loading…
Add table
Reference in a new issue