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
					
				| @ -6,9 +6,13 @@ addons: | ||||
| compiler: | ||||
|   - clang | ||||
|   - gcc | ||||
| cache: | ||||
|   directories: | ||||
|   - src/java/guava/ | ||||
| env: | ||||
|   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 | ||||
|     - 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: | ||||
|     - SCALAR=32bit    RECOVERY=yes | ||||
|     - SCALAR=32bit    FIELD=32bit       ECDH=yes  EXPERIMENTAL=yes | ||||
| @ -26,6 +30,7 @@ env: | ||||
|     - BUILD=distcheck | ||||
|     - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC | ||||
|     - EXTRAFLAGS=CFLAGS=-O0 | ||||
|     - BUILD=check-java ECDH=yes SCHNORR=yes EXPERIMENTAL=yes | ||||
| matrix: | ||||
|   fast_finish: true | ||||
|   include: | ||||
| @ -55,6 +60,8 @@ matrix: | ||||
|           packages: | ||||
|             - gcc-multilib | ||||
|             - 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 | ||||
| script: | ||||
|  - 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 | ||||
| 
 | ||||
| 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 | ||||
| noinst_HEADERS = | ||||
| 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_asm_impl.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/testrand.h | ||||
| noinst_HEADERS += src/testrand_impl.h | ||||
| @ -49,9 +56,11 @@ pkgconfigdir = $(libdir)/pkgconfig | ||||
| pkgconfig_DATA = libsecp256k1.pc | ||||
| 
 | ||||
| libsecp256k1_la_SOURCES = src/secp256k1.c | ||||
| libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) | ||||
| libsecp256k1_la_LIBADD = $(SECP_LIBS) | ||||
| libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) | ||||
| 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 = | ||||
| if USE_BENCHMARK | ||||
| @ -68,12 +77,42 @@ endif | ||||
| if USE_TESTS | ||||
| noinst_PROGRAMS += tests | ||||
| 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_LDFLAGS = -static | ||||
| TESTS = tests | ||||
| 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 | ||||
| CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) | ||||
| 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) | ||||
| 	./$(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 | ||||
| 
 | ||||
| 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 | ||||
| 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=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], | ||||
| [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 | ||||
| 
 | ||||
| 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 | ||||
|   SECP_LIBS="$SECP_LIBS $GMP_LIBS" | ||||
|   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 scalar implementation: $set_scalar]) | ||||
| 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([Using jni: $use_jni]) | ||||
| 
 | ||||
| if test x"$enable_experimental" = x"yes"; then | ||||
|   AC_MSG_NOTICE([******]) | ||||
| @ -375,6 +399,7 @@ fi | ||||
| 
 | ||||
| AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) | ||||
| AC_CONFIG_FILES([Makefile libsecp256k1.pc]) | ||||
| AC_SUBST(JNI_INCLUDES) | ||||
| AC_SUBST(SECP_INCLUDES) | ||||
| AC_SUBST(SECP_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_SCHNORR], [test x"$enable_module_schnorr" = 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 | ||||
| PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" | ||||
|  | ||||
| @ -3,8 +3,11 @@ package org.bitcoin; | ||||
| import java.nio.ByteBuffer; | ||||
| import java.nio.ByteOrder; | ||||
| 
 | ||||
| import java.math.BigInteger; | ||||
| 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. | ||||
| @ -12,49 +15,737 @@ import com.google.common.base.Preconditions; | ||||
|  * https://github.com/sipa/secp256k1 | ||||
|  */ | ||||
| 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>(); | ||||
|     /** | ||||
|      * Verifies the given secp256k1 signature in native code. | ||||
|      * Calling when enabled == false is undefined (probably library not loaded) | ||||
|      *  | ||||
|      * | ||||
|      * @param data The data which was signed, must be exactly 32 bytes | ||||
|      * @param signature The signature | ||||
|      * @param pub The public key which did the signing | ||||
|      */ | ||||
|     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); | ||||
| 
 | ||||
|         ByteBuffer byteBuff = nativeECDSABuffer.get(); | ||||
|         if (byteBuff == null) { | ||||
|             byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520); | ||||
|         if (byteBuff == null || byteBuff.capacity() < 520) { | ||||
|             byteBuff = ByteBuffer.allocateDirect(520); | ||||
|             byteBuff.order(ByteOrder.nativeOrder()); | ||||
|             nativeECDSABuffer.set(byteBuff); | ||||
|         } | ||||
|         byteBuff.rewind(); | ||||
|         byteBuff.put(data); | ||||
|         byteBuff.putInt(signature.length); | ||||
|         byteBuff.putInt(pub.length); | ||||
|         byteBuff.put(signature); | ||||
|         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, | ||||
|      *        native-endian int signatureLength, native-endian int pubkeyLength, | ||||
|      *        byte[signatureLength] signature, byte[pubkeyLength] pub | ||||
|      * @returns 1 for valid signature, anything else for invalid | ||||
|      * recover the given secp256k1 pubkey in native code. | ||||
|      * | ||||
|      * @param data The data which was signed, must be exactly 32 bytes | ||||
|      * @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 "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) | ||||
| { | ||||
| 	unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); | ||||
| 	int sigLen = *((int*)(data + 32)); | ||||
| 	int pubLen = *((int*)(data + 32 + 4)); | ||||
|   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; | ||||
| 
 | ||||
| 	return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen); | ||||
| } | ||||
| 
 | ||||
| static void __javasecp256k1_attach(void) __attribute__((constructor)); | ||||
| static void __javasecp256k1_detach(void) __attribute__((destructor)); | ||||
| 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); | ||||
| 
 | ||||
| static void __javasecp256k1_attach(void) { | ||||
| 	secp256k1_start(SECP256K1_START_VERIFY); | ||||
| } | ||||
| 
 | ||||
| static void __javasecp256k1_detach(void) { | ||||
| 	secp256k1_stop(); | ||||
| 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); | ||||
|   const unsigned char* sigdata = {  (unsigned char*) (data + 32) }; | ||||
|   const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; | ||||
| 
 | ||||
|   secp256k1_ecdsa_signature sig; | ||||
|   secp256k1_pubkey pubkey; | ||||
| 
 | ||||
|   int ret = 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; | ||||
| } | ||||
| 
 | ||||
| SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign | ||||
|   (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) | ||||
| { | ||||
|   secp256k1_context *ctx = (secp256k1_context*)ctx_l; | ||||
|   unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); | ||||
|   unsigned char* secKey = (unsigned char*) (data + 32); | ||||
| 
 | ||||
|   jobjectArray retArray; | ||||
|   jbyteArray sigArray, intsByteArray; | ||||
|   unsigned char intsarray[2]; | ||||
| 
 | ||||
|   secp256k1_ecdsa_signature sig[72]; | ||||
| 
 | ||||
|   int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL ); | ||||
| 
 | ||||
|   unsigned char outputSer[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; | ||||
| } | ||||
| 
 | ||||
| SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify | ||||
|   (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) | ||||
| { | ||||
|   secp256k1_context *ctx = (secp256k1_context*)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 */ | ||||
| #include <jni.h> | ||||
| #include "include/secp256k1.h" | ||||
| /* Header for class org_bitcoin_NativeSecp256k1 */ | ||||
| 
 | ||||
| #ifndef _Included_org_bitcoin_NativeSecp256k1 | ||||
| @ -9,11 +10,139 @@ extern "C" { | ||||
| #endif | ||||
| /*
 | ||||
|  * Class:     org_bitcoin_NativeSecp256k1 | ||||
|  * Method:    secp256k1_ecdsa_verify | ||||
|  * Signature: (Ljava/nio/ByteBuffer;)I | ||||
|  * Method:    secp256k1_ctx_clone | ||||
|  * Signature: (J)J | ||||
|  */ | ||||
| JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify | ||||
|   (JNIEnv *, jclass, jobject); | ||||
| SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone | ||||
|   (JNIEnv *, jclass, jlong); | ||||
| 
 | ||||
| /*
 | ||||
|  * Class:     org_bitcoin_NativeSecp256k1 | ||||
|  * Method:    secp256k1_context_randomize | ||||
|  * Signature: (Ljava/nio/ByteBuffer;J)I | ||||
|  */ | ||||
| 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 | ||||
| } | ||||
|  | ||||
							
								
								
									
										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.*
 | ||||
|  **********************************************************************/ | ||||
| 
 | ||||
| #define SECP256K1_BUILD (1) | ||||
| 
 | ||||
| #include "include/secp256k1.h" | ||||
| 
 | ||||
| #include "util.h" | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user