From a4bdfa846d9286ae7c3ab35c2d77e7b06d54cf98 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 16 Dec 2014 22:23:17 -0500 Subject: [PATCH 01/24] jni: update jni for api change Also silence an unnecessary warning. --- src/java/org_bitcoin_NativeSecp256k1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index bb4cd70728..58e9896604 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -4,11 +4,12 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject) { + (void)classObject; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); int sigLen = *((int*)(data + 32)); int pubLen = *((int*)(data + 32 + 4)); - return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen); + return secp256k1_ecdsa_verify(data, data+32+8, sigLen, data+32+8+sigLen, pubLen); } static void __javasecp256k1_attach(void) __attribute__((constructor)); From 6594d85a2fc476417d789d625faf3eac1344b93d Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sun, 21 Sep 2014 14:03:14 -0400 Subject: [PATCH 02/24] build: add --enable-jni configure option jni headers will be used if possible, otherwise jni support is disabled --- Makefile.am | 10 +- build-aux/m4/ax_jni_include_dir.m4 | 126 ++++++++++++++++++++++ configure.ac | 24 +++++ src/java/org/bitcoin/NativeSecp256k1.java | 2 +- 4 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 build-aux/m4/ax_jni_include_dir.m4 diff --git a/Makefile.am b/Makefile.am index 390d2c9ffa..9918162b7c 100644 --- a/Makefile.am +++ b/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 @@ -44,8 +50,10 @@ pkgconfig_DATA = libsecp256k1.pc libsecp256k1_la_SOURCES = src/secp256k1.c libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include $(SECP_INCLUDES) -libsecp256k1_la_LIBADD = $(SECP_LIBS) +libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) +libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c +libsecp256k1_jni_la_CPPFLAGS = $(JNI_INCLUDES) noinst_PROGRAMS = if USE_BENCHMARK diff --git a/build-aux/m4/ax_jni_include_dir.m4 b/build-aux/m4/ax_jni_include_dir.m4 new file mode 100644 index 0000000000..b664d80b85 --- /dev/null +++ b/build-aux/m4/ax_jni_include_dir.m4 @@ -0,0 +1,126 @@ +# =========================================================================== +# 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 +# +# 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_ERROR([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_CHECK_FILE([$_JINC/jni.h], + [JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JINC"], + [_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + AC_CHECK_FILE([$_JTOPDIR/include/jni.h], + [JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include"], + AC_MSG_ERROR([cannot find JDK header files])) + ]) + +# get the likely subdirectories for system specific java includes +case "$host_os" in +bsdi*) _JNI_INC_SUBDIRS="bsdos";; +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 + +# 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 +]) + +# _ACJNI_FOLLOW_SYMLINKS +# Follows symbolic links on , +# 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 diff --git a/configure.ac b/configure.ac index b74957cec9..c0e779964d 100644 --- a/configure.ac +++ b/configure.ac @@ -96,6 +96,11 @@ AC_ARG_ENABLE(endomorphism, [use_endomorphism=$enableval], [use_endomorphism=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=gmp|64bit|32bit|auto], [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) @@ -312,6 +317,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_field" = x"gmp" || test x"$set_bignum" = x"gmp"; then SECP_LIBS="$SECP_LIBS $GMP_LIBS" SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS" @@ -326,15 +347,18 @@ 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([Using jni: $use_jni]) 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) AC_SUBST(SECP_TEST_INCLUDES) AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = 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" diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index 90a498eaa2..cd0976aa79 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -16,7 +16,7 @@ public class NativeSecp256k1 { static { boolean isEnabled = true; try { - System.loadLibrary("javasecp256k1"); + System.loadLibrary("secp256k1"); } catch (UnsatisfiedLinkError e) { isEnabled = false; } From 2d9055f22ca7fd5922059bb3b6ea2ac2540af951 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 12 Nov 2014 23:50:40 -0500 Subject: [PATCH 03/24] build: cleanup jni m4 - Don't error if not found - Don't use AC_CHECK_FILE which is disabled on cross - Check for darwin path --- build-aux/m4/ax_jni_include_dir.m4 | 44 ++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/build-aux/m4/ax_jni_include_dir.m4 b/build-aux/m4/ax_jni_include_dir.m4 index b664d80b85..1fc3627614 100644 --- a/build-aux/m4/ax_jni_include_dir.m4 +++ b/build-aux/m4/ax_jni_include_dir.m4 @@ -59,7 +59,7 @@ else fi AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no]) if test "x$_ACJNI_JAVAC" = xno; then - AC_MSG_ERROR([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME]) + 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:/[[^/]]*$::'` @@ -76,17 +76,29 @@ _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_CHECK_FILE([$_JINC/jni.h], - [JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JINC"], - [_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` - AC_CHECK_FILE([$_JTOPDIR/include/jni.h], - [JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include"], - AC_MSG_ERROR([cannot find JDK header files])) - ]) + +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";; @@ -96,13 +108,15 @@ cygwin*) _JNI_INC_SUBDIRS="win32";; *) _JNI_INC_SUBDIRS="genunix";; esac -# 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 +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 From a340fd63d4d2fe925946c934e484865a81aa6778 Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Sat, 25 Apr 2015 19:23:23 -0500 Subject: [PATCH 04/24] Add simple test --- src/java/org/bitcoin/NativeSecp256k1Test.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/java/org/bitcoin/NativeSecp256k1Test.java diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java new file mode 100644 index 0000000000..de4e99ed24 --- /dev/null +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -0,0 +1,38 @@ +package org.bitcoin; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import javax.xml.bind.DatatypeConverter; + +import com.google.common.io.BaseEncoding; + +public class NativeSecp256k1Test { + + public static void main(String[] args) { + + System.out.println(" enabled: " + NativeSecp256k1.enabled); + + if( NativeSecp256k1.enabled ) { + + boolean result = false; + + //Case 1 - PASSING + 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 ); + + System.out.println(" result: " + ( result == true ? " PASS " : " FAIL " ) ); + + //Case 2 - FAILING + data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" + sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub ); + + System.out.println(" result: " + ( result == true ? " PASS " : " FAIL " ) ); + } + } +} From f1e04f49912cea432472ec58abac75ee1317cbf8 Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Tue, 28 Apr 2015 00:25:19 -0500 Subject: [PATCH 05/24] Rebase --- src/java/org_bitcoin_NativeSecp256k1.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 58e9896604..fcf5fbfa4b 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -4,21 +4,12 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject) { - (void)classObject; + secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); int sigLen = *((int*)(data + 32)); int pubLen = *((int*)(data + 32 + 4)); - return secp256k1_ecdsa_verify(data, data+32+8, sigLen, data+32+8+sigLen, pubLen); -} - -static void __javasecp256k1_attach(void) __attribute__((constructor)); -static void __javasecp256k1_detach(void) __attribute__((destructor)); - -static void __javasecp256k1_attach(void) { - secp256k1_start(SECP256K1_START_VERIFY); -} + (void)classObject; -static void __javasecp256k1_detach(void) { - secp256k1_stop(); + return secp256k1_ecdsa_verify(vrfy, data, data+32+8, sigLen, data+32+8+sigLen, pubLen); } From 7838a3ea4aabaa372cb9f4422531502aa6e43e60 Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Thu, 30 Apr 2015 19:21:35 -0500 Subject: [PATCH 06/24] add support for several other secp256k1 functions, as well as testcases --- src/java/org/bitcoin/NativeSecp256k1.java | 108 ++++++++++++++++++ src/java/org/bitcoin/NativeSecp256k1Test.java | 97 ++++++++++++++-- src/java/org_bitcoin_NativeSecp256k1.c | 66 +++++++++++ src/java/org_bitcoin_NativeSecp256k1.h | 32 ++++++ 4 files changed, 294 insertions(+), 9 deletions(-) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index cd0976aa79..e00e4862ef 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -50,6 +50,98 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) { return secp256k1_ecdsa_verify(byteBuff) == 1; } + /** + * 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) { + 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); + return secp256k1_ecdsa_sign(byteBuff); + } + + /** + * libsecp256k1 Pubkey Verify - returns 1 if valid, 0 if invalid + * + * @param pubkey ECDSA Public key, 33 or 65 bytes + */ + + public static boolean pubKeyVerify(byte[] pubkey) { + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + 4); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.putInt(pubkey.length); + byteBuff.put(pubkey); + return secp256k1_ec_pubkey_verify(byteBuff) == 1; + } + + /** + * 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 = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + return secp256k1_ec_seckey_verify(byteBuff) == 1; + } + + + /** + * 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 + */ + + public static byte[] computePubkey(byte[] seckey, int compressed) { + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + byteBuff.putInt(compressed); + return secp256k1_ec_pubkey_create(byteBuff); + } + /** * @param byteBuff signature format is byte[32] data, * native-endian int signatureLength, native-endian int pubkeyLength, @@ -57,4 +149,20 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) { * @returns 1 for valid signature, anything else for invalid */ private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff); + + private static native byte[] secp256k1_ecdsa_sign(ByteBuffer byteBuff); + + private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff); + + private static native int secp256k1_ec_pubkey_verify(ByteBuffer byteBuff); + + private static native byte[] secp256k1_ec_pubkey_create(ByteBuffer byteBuff); + + // TODO + // secp256k1_ec_pubkey_decompress + // secp256k1_ec_privkey_export + // secp256k1_ec_privkey_import + // secp256k1_ecdsa_sign_compact + // secp256k1_ecdsa_recover_compact + } diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index de4e99ed24..78f9a93e9d 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -1,16 +1,14 @@ package org.bitcoin; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import javax.xml.bind.DatatypeConverter; - import com.google.common.io.BaseEncoding; +import java.util.Arrays; +import javax.xml.bind.DatatypeConverter; public class NativeSecp256k1Test { - public static void main(String[] args) { + public static void main(String[] args) throws AssertFailException{ - System.out.println(" enabled: " + NativeSecp256k1.enabled); + System.out.println("\n libsecp256k1 enabled: " + NativeSecp256k1.enabled + "\n"); if( NativeSecp256k1.enabled ) { @@ -22,8 +20,7 @@ public static void main(String[] args) { byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); result = NativeSecp256k1.verify( data, sig, pub ); - - System.out.println(" result: " + ( result == true ? " PASS " : " FAIL " ) ); + assertEquals( result, true , "Case 1"); //Case 2 - FAILING data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" @@ -31,8 +28,90 @@ public static void main(String[] args) { pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); result = NativeSecp256k1.verify( data, sig, pub ); + assertEquals( result, false , "Case 2"); + + //Case 3 - PASSING + pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + result = NativeSecp256k1.pubKeyVerify( pub ); + assertEquals( result, true , "Case 3"); + + //Case 4 - FAILING + pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C41".toLowerCase()); + result = NativeSecp256k1.pubKeyVerify( pub ); + assertEquals( result, false , "Case 4"); + + //Case 5 - PASSING + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + result = NativeSecp256k1.secKeyVerify( sec ); + assertEquals( result, true , "Case 5"); + + //Case 6 - FAILING + sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + result = NativeSecp256k1.secKeyVerify( sec ); + assertEquals( result, false , "Case 6"); + + //Case 7 - PASSING + sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec , 0); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "Case 7"); + + resultArr = NativeSecp256k1.computePubkey( sec , 1); + pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString, "02C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 7 Compressed"); + + //Case 8 - FAILING + sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + resultArr = NativeSecp256k1.computePubkey( sec , 0); + pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString, "" , "Case 8"); + + resultArr = NativeSecp256k1.computePubkey( sec , 1); + pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString, "" , "Case 8 Compressed"); + + //Case 9 - PASSING + data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + + assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "Case 9"); + + //Case 10 - FAILING + data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + resultArr = NativeSecp256k1.sign(data, sec); + sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + + System.out.println( sigString ); + assertEquals( sigString, "" , "Case 10"); + + System.out.println(" All tests passed." ); + } + } + + private 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); + } + + private 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); + } - System.out.println(" result: " + ( result == true ? " PASS " : " FAIL " ) ); + private static class AssertFailException extends Exception { + public AssertFailException(String message) { + super( message ); } } } diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index fcf5fbfa4b..184ebeec37 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -13,3 +13,69 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify return secp256k1_ecdsa_verify(vrfy, data, data+32+8, sigLen, data+32+8+sigLen, pubLen); } + +JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv* env, jclass classObject, jobject byteBufferObject) +{ + secp256k1_context_t *sgn = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + unsigned char* secKey = (unsigned char*) (data + 32); + + jbyteArray sigArray; + + unsigned char sig[72]; + int siglen = 72; + + int ret = secp256k1_ecdsa_sign(sgn, data, sig, &siglen, secKey, NULL, NULL ); + + sigArray = (*env)->NewByteArray(env, siglen); + (*env)->SetByteArrayRegion(env, sigArray, 0, siglen, (jbyte*)sig); + + (void)classObject; (void)ret; + return sigArray; +} + +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject) +{ + secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_ec_seckey_verify(vrfy, secKey); +} + +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject) +{ + secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + int pubLen = *((int*)(data)); + unsigned char* pubKey = (unsigned char*) (data + 4); + + (void)classObject; + + return secp256k1_ec_pubkey_verify(vrfy, pubKey, pubLen); +} + +JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv* env, jclass classObject, jobject byteBufferObject) +{ + secp256k1_context_t *sgnvrfy = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + int compressed = *((int*)(secKey + 32)); + + unsigned char pubkey[65]; + int pubkeyLen = 65; + + jbyteArray pubkeyArray; + + int ret = secp256k1_ec_pubkey_create(sgnvrfy, pubkey, &pubkeyLen, secKey, compressed ); + + pubkeyArray = (*env)->NewByteArray(env, pubkeyLen); + (*env)->SetByteArrayRegion(env, pubkeyArray, 0, pubkeyLen, (jbyte*)pubkey); + + (void)classObject; (void)ret; + return pubkeyArray; +} diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index d7fb004fa8..909a803ecb 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -15,6 +15,38 @@ extern "C" { JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify (JNIEnv *, jclass, jobject); +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_sign + * Signature: (Ljava/nio/ByteBuffer;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv *, jclass, jobject); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_seckey_verify + * Signature: (Ljava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv *, jclass, jobject); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_verify + * Signature: (Ljava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1verify + (JNIEnv *, jclass, jobject); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_create + * Signature: (Ljava/nio/ByteBuffer;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv *, jclass, jobject); + #ifdef __cplusplus } #endif From 85c9f197f35d0422b746728147ebe86918c7ac14 Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Sun, 3 May 2015 19:01:44 -0500 Subject: [PATCH 07/24] Refactor and pass single Secp256k1context instead of initializing per operation --- src/java/org/bitcoin/NativeSecp256k1.java | 26 +++++++----- src/java/org/bitcoin/NativeSecp256k1Test.java | 4 +- src/java/org_bitcoin_NativeSecp256k1.c | 42 ++++++++++++------- src/java/org_bitcoin_NativeSecp256k1.h | 28 ++++++++----- 4 files changed, 62 insertions(+), 38 deletions(-) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index e00e4862ef..df19b0eb0a 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -13,14 +13,18 @@ */ public class NativeSecp256k1 { public static final boolean enabled; + private static final long Secp256k1Context; //ref to pointer to context obj static { boolean isEnabled = true; + long contextRef = -1; try { System.loadLibrary("secp256k1"); + contextRef = secp256k1_init_context(); } catch (UnsatisfiedLinkError e) { isEnabled = false; } enabled = isEnabled; + Secp256k1Context = contextRef; } private static ThreadLocal nativeECDSABuffer = new ThreadLocal(); @@ -47,7 +51,7 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) { byteBuff.putInt(pub.length); byteBuff.put(signature); byteBuff.put(pub); - return secp256k1_ecdsa_verify(byteBuff) == 1; + return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context) == 1; } /** @@ -72,7 +76,7 @@ public static byte[] sign(byte[] data, byte[] sec) { byteBuff.rewind(); byteBuff.put(data); byteBuff.put(sec); - return secp256k1_ecdsa_sign(byteBuff); + return secp256k1_ecdsa_sign(byteBuff, Secp256k1Context); } /** @@ -93,7 +97,7 @@ public static boolean pubKeyVerify(byte[] pubkey) { byteBuff.rewind(); byteBuff.putInt(pubkey.length); byteBuff.put(pubkey); - return secp256k1_ec_pubkey_verify(byteBuff) == 1; + return secp256k1_ec_pubkey_verify(byteBuff,Secp256k1Context) == 1; } /** @@ -113,7 +117,7 @@ public static boolean secKeyVerify(byte[] seckey) { } byteBuff.rewind(); byteBuff.put(seckey); - return secp256k1_ec_seckey_verify(byteBuff) == 1; + return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context) == 1; } @@ -139,7 +143,7 @@ public static byte[] computePubkey(byte[] seckey, int compressed) { byteBuff.rewind(); byteBuff.put(seckey); byteBuff.putInt(compressed); - return secp256k1_ec_pubkey_create(byteBuff); + return secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context); } /** @@ -148,15 +152,17 @@ public static byte[] computePubkey(byte[] seckey, int compressed) { * byte[signatureLength] signature, byte[pubkeyLength] pub * @returns 1 for valid signature, anything else for invalid */ - private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff); + private static native long secp256k1_init_context(); - private static native byte[] secp256k1_ecdsa_sign(ByteBuffer byteBuff); + private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context); - private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff); + private static native byte[] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); - private static native int secp256k1_ec_pubkey_verify(ByteBuffer byteBuff); + private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); - private static native byte[] secp256k1_ec_pubkey_create(ByteBuffer byteBuff); + private static native int secp256k1_ec_pubkey_verify(ByteBuffer byteBuff, long context); + + private static native byte[] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context); // TODO // secp256k1_ec_pubkey_decompress diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 78f9a93e9d..1d1443e3a1 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -78,7 +78,6 @@ public static void main(String[] args) throws AssertFailException{ resultArr = NativeSecp256k1.sign(data, sec); String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "Case 9"); //Case 10 - FAILING @@ -87,11 +86,10 @@ public static void main(String[] args) throws AssertFailException{ resultArr = NativeSecp256k1.sign(data, sec); sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - - System.out.println( sigString ); assertEquals( sigString, "" , "Case 10"); System.out.println(" All tests passed." ); + } } diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 184ebeec37..784b018c3e 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -1,23 +1,35 @@ #include "org_bitcoin_NativeSecp256k1.h" #include "include/secp256k1.h" +JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1context + (JNIEnv* env, jclass classObject) +{ + secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + (void)classObject;(void)env; + + return (long)ctx; +} + + JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject) + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); int sigLen = *((int*)(data + 32)); int pubLen = *((int*)(data + 32 + 4)); (void)classObject; - return secp256k1_ecdsa_verify(vrfy, data, data+32+8, sigLen, data+32+8+sigLen, pubLen); + return secp256k1_ecdsa_verify(ctx, data, data+32+8, sigLen, data+32+8+sigLen, pubLen); } JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign - (JNIEnv* env, jclass classObject, jobject byteBufferObject) + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *sgn = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); unsigned char* secKey = (unsigned char*) (data + 32); @@ -26,7 +38,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1 unsigned char sig[72]; int siglen = 72; - int ret = secp256k1_ecdsa_sign(sgn, data, sig, &siglen, secKey, NULL, NULL ); + int ret = secp256k1_ecdsa_sign(ctx, data, sig, &siglen, secKey, NULL, NULL ); sigArray = (*env)->NewByteArray(env, siglen); (*env)->SetByteArrayRegion(env, sigArray, 0, siglen, (jbyte*)sig); @@ -36,33 +48,33 @@ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1 } JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject) + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); (void)classObject; - return secp256k1_ec_seckey_verify(vrfy, secKey); + return secp256k1_ec_seckey_verify(ctx, secKey); } JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject) + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); int pubLen = *((int*)(data)); unsigned char* pubKey = (unsigned char*) (data + 4); (void)classObject; - return secp256k1_ec_pubkey_verify(vrfy, pubKey, pubLen); + return secp256k1_ec_pubkey_verify(ctx, pubKey, pubLen); } JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create - (JNIEnv* env, jclass classObject, jobject byteBufferObject) + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *sgnvrfy = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); int compressed = *((int*)(secKey + 32)); @@ -71,7 +83,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pub jbyteArray pubkeyArray; - int ret = secp256k1_ec_pubkey_create(sgnvrfy, pubkey, &pubkeyLen, secKey, compressed ); + int ret = secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeyLen, secKey, compressed ); pubkeyArray = (*env)->NewByteArray(env, pubkeyLen); (*env)->SetByteArrayRegion(env, pubkeyArray, 0, pubkeyLen, (jbyte*)pubkey); diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index 909a803ecb..ddb9631c5b 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -7,45 +7,53 @@ #ifdef __cplusplus extern "C" { #endif +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_init_context + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1context + (JNIEnv *, jclass); + /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_verify - * Signature: (Ljava/nio/ByteBuffer;)I + * Signature: (Ljava/nio/ByteBuffer;J)I */ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv *, jclass, jobject); + (JNIEnv *, jclass, jobject, jlong); /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_sign - * Signature: (Ljava/nio/ByteBuffer;)[B + * Signature: (Ljava/nio/ByteBuffer;J)[B */ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign - (JNIEnv *, jclass, jobject); + (JNIEnv *, jclass, jobject, jlong); /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ec_seckey_verify - * Signature: (Ljava/nio/ByteBuffer;)I + * Signature: (Ljava/nio/ByteBuffer;J)I */ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify - (JNIEnv *, jclass, jobject); + (JNIEnv *, jclass, jobject, jlong); /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ec_pubkey_verify - * Signature: (Ljava/nio/ByteBuffer;)I + * Signature: (Ljava/nio/ByteBuffer;J)I */ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1verify - (JNIEnv *, jclass, jobject); + (JNIEnv *, jclass, jobject, jlong); /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ec_pubkey_create - * Signature: (Ljava/nio/ByteBuffer;)[B + * Signature: (Ljava/nio/ByteBuffer;J)[B */ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create - (JNIEnv *, jclass, jobject); + (JNIEnv *, jclass, jobject, jlong); #ifdef __cplusplus } From 8d7163db9d64e3d13d94e99309ca6a8f27484ec4 Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Sun, 3 May 2015 21:13:59 -0500 Subject: [PATCH 08/24] long to jlong -> 64bit --- src/java/org_bitcoin_NativeSecp256k1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 784b018c3e..85a3bd840d 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -8,7 +8,7 @@ JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1contex (void)classObject;(void)env; - return (long)ctx; + return (jlong)ctx; } From 4f1b7102f58665f92482cb6139cab78db44b316f Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Mon, 4 May 2015 11:52:13 -0500 Subject: [PATCH 09/24] Make sure there is a way to cleanup the context, and add comment to explain when it should be used. --- src/java/org/bitcoin/NativeSecp256k1.java | 9 +++++++++ src/java/org/bitcoin/NativeSecp256k1Test.java | 1 + src/java/org_bitcoin_NativeSecp256k1.c | 9 +++++++++ src/java/org_bitcoin_NativeSecp256k1.h | 8 ++++++++ 4 files changed, 27 insertions(+) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index df19b0eb0a..254477f366 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -146,6 +146,13 @@ public static byte[] computePubkey(byte[] seckey, int compressed) { return secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context); } + /** + * 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 void cleanup() { + secp256k1_destroy_context(Secp256k1Context); + } /** * @param byteBuff signature format is byte[32] data, * native-endian int signatureLength, native-endian int pubkeyLength, @@ -154,6 +161,8 @@ public static byte[] computePubkey(byte[] seckey, int compressed) { */ private static native long secp256k1_init_context(); + private static native void secp256k1_destroy_context(long context); + private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context); private static native byte[] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 1d1443e3a1..7dfbaa208b 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -88,6 +88,7 @@ public static void main(String[] args) throws AssertFailException{ sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString, "" , "Case 10"); + NativeSecp256k1.cleanup(); System.out.println(" All tests passed." ); } diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 85a3bd840d..6ee2b58dbc 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -11,6 +11,15 @@ JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1contex return (jlong)ctx; } +JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + + secp256k1_context_destroy(ctx); + + (void)classObject;(void)env; +} JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index ddb9631c5b..c5540a4f65 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -15,6 +15,14 @@ extern "C" { JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1context (JNIEnv *, jclass); +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_destroy_context + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv *, jclass, jlong); + /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_verify From da729b6b0a826f83d32d14d2f68f31bff4a02b17 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 4 May 2015 23:16:11 -0400 Subject: [PATCH 10/24] travis: add check-java make target and update travis to test it --- .travis.yml | 7 +++++++ Makefile.am | 30 +++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0d8089cfe4..96e0686905 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,9 +6,13 @@ addons: compiler: - clang - gcc +cache: + directories: + - src/java/guava/ env: global: - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST= + - 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 - SCALAR=64bit @@ -22,6 +26,7 @@ env: - BIGNUM=no ENDOMORPHISM=yes - BUILD=distcheck - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC + - BUILD=check-java matrix: fast_finish: true include: @@ -51,6 +56,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 diff --git a/Makefile.am b/Makefile.am index 8d17ec86b6..768fac3d71 100644 --- a/Makefile.am +++ b/Makefile.am @@ -82,4 +82,32 @@ tests_LDFLAGS = -static TESTS = tests endif -EXTRA_DIST = autogen.sh +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 + +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=".libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test + +endif +endif +CLEANFILES = $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java +EXTRA_DIST = autogen.sh $(JAVA_FILES) From 0348e83232342a17d1710d3913da94df0c83a4f6 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 5 May 2015 19:08:41 -0400 Subject: [PATCH 11/24] jni: pass size parameters rather than embedding them in the bytebuffers --- src/java/org/bitcoin/NativeSecp256k1.java | 20 ++++++++------------ src/java/org_bitcoin_NativeSecp256k1.c | 15 +++++---------- src/java/org_bitcoin_NativeSecp256k1.h | 6 +++--- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index 254477f366..4aab51171a 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -41,17 +41,15 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) { ByteBuffer byteBuff = nativeECDSABuffer.get(); if (byteBuff == null) { - byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520); + byteBuff = ByteBuffer.allocateDirect(32 + 520 + 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, Secp256k1Context) == 1; + return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context, signature.length, pub.length) == 1; } /** @@ -90,14 +88,13 @@ public static boolean pubKeyVerify(byte[] pubkey) { ByteBuffer byteBuff = nativeECDSABuffer.get(); if (byteBuff == null) { - byteBuff = ByteBuffer.allocateDirect(pubkey.length + 4); + byteBuff = ByteBuffer.allocateDirect(pubkey.length); byteBuff.order(ByteOrder.nativeOrder()); nativeECDSABuffer.set(byteBuff); } byteBuff.rewind(); - byteBuff.putInt(pubkey.length); byteBuff.put(pubkey); - return secp256k1_ec_pubkey_verify(byteBuff,Secp256k1Context) == 1; + return secp256k1_ec_pubkey_verify(byteBuff,Secp256k1Context, pubkey.length) == 1; } /** @@ -142,8 +139,7 @@ public static byte[] computePubkey(byte[] seckey, int compressed) { } byteBuff.rewind(); byteBuff.put(seckey); - byteBuff.putInt(compressed); - return secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context); + return secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context, compressed); } /** @@ -163,15 +159,15 @@ public static void cleanup() { private static native void secp256k1_destroy_context(long context); - private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, 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 int secp256k1_ec_pubkey_verify(ByteBuffer byteBuff, long context); + private static native int secp256k1_ec_pubkey_verify(ByteBuffer byteBuff, long context, int pubLen); - private static native byte[] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context); + private static native byte[] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context, int compressed); // TODO // secp256k1_ec_pubkey_decompress diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 6ee2b58dbc..89f7e0c8ca 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -22,17 +22,15 @@ JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1cont } JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint sigLen, jint pubLen) { secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - int sigLen = *((int*)(data + 32)); - int pubLen = *((int*)(data + 32 + 4)); (void)classObject; - return secp256k1_ecdsa_verify(ctx, data, data+32+8, sigLen, data+32+8+sigLen, pubLen); + return secp256k1_ecdsa_verify(ctx, data, data+32, sigLen, data+32+sigLen, pubLen); } JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign @@ -68,12 +66,10 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1v } JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint pubLen) { secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; - unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - int pubLen = *((int*)(data)); - unsigned char* pubKey = (unsigned char*) (data + 4); + unsigned char* pubKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); (void)classObject; @@ -81,11 +77,10 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1v } JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint compressed) { secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - int compressed = *((int*)(secKey + 32)); unsigned char pubkey[65]; int pubkeyLen = 65; diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index c5540a4f65..e4b00f94c9 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -29,7 +29,7 @@ JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1cont * Signature: (Ljava/nio/ByteBuffer;J)I */ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv *, jclass, jobject, jlong); + (JNIEnv *, jclass, jobject, jlong, jint, jint); /* * Class: org_bitcoin_NativeSecp256k1 @@ -53,7 +53,7 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1v * Signature: (Ljava/nio/ByteBuffer;J)I */ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1verify - (JNIEnv *, jclass, jobject, jlong); + (JNIEnv *, jclass, jobject, jlong, jint); /* * Class: org_bitcoin_NativeSecp256k1 @@ -61,7 +61,7 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1v * Signature: (Ljava/nio/ByteBuffer;J)[B */ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create - (JNIEnv *, jclass, jobject, jlong); + (JNIEnv *, jclass, jobject, jlong, jint); #ifdef __cplusplus } From 76bd6c2b838fde8ae00cdd18ff20d3dc851f21cf Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Thu, 7 May 2015 19:46:00 -0500 Subject: [PATCH 12/24] Tabs to spaces --- src/java/org_bitcoin_NativeSecp256k1.c | 46 +++++++++++++------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 89f7e0c8ca..c52a4379da 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -4,7 +4,7 @@ JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1context (JNIEnv* env, jclass classObject) { - secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); (void)classObject;(void)env; @@ -14,7 +14,7 @@ JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1contex JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context (JNIEnv* env, jclass classObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; secp256k1_context_destroy(ctx); @@ -24,21 +24,21 @@ JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1cont JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint sigLen, jint pubLen) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; - unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - (void)classObject; + (void)classObject; - return secp256k1_ecdsa_verify(ctx, data, data+32, sigLen, data+32+sigLen, pubLen); + return secp256k1_ecdsa_verify(ctx, data, data+32, sigLen, data+32+sigLen, pubLen); } JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; - unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - unsigned char* secKey = (unsigned char*) (data + 32); + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + unsigned char* secKey = (unsigned char*) (data + 32); jbyteArray sigArray; @@ -50,37 +50,37 @@ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1 sigArray = (*env)->NewByteArray(env, siglen); (*env)->SetByteArrayRegion(env, sigArray, 0, siglen, (jbyte*)sig); - (void)classObject; (void)ret; - return sigArray; + (void)classObject; (void)ret; + return sigArray; } JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; - unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - (void)classObject; + (void)classObject; - return secp256k1_ec_seckey_verify(ctx, secKey); + return secp256k1_ec_seckey_verify(ctx, secKey); } JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint pubLen) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; - unsigned char* pubKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + unsigned char* pubKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - (void)classObject; + (void)classObject; - return secp256k1_ec_pubkey_verify(ctx, pubKey, pubLen); + return secp256k1_ec_pubkey_verify(ctx, pubKey, pubLen); } JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint compressed) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; - unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); unsigned char pubkey[65]; int pubkeyLen = 65; @@ -92,6 +92,6 @@ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pub pubkeyArray = (*env)->NewByteArray(env, pubkeyLen); (*env)->SetByteArrayRegion(env, pubkeyArray, 0, pubkeyLen, (jbyte*)pubkey); - (void)classObject; (void)ret; - return pubkeyArray; + (void)classObject; (void)ret; + return pubkeyArray; } From 3ce6181d94bae5984cc53fe40bc4629cb0087ec0 Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Fri, 8 May 2015 00:52:43 -0500 Subject: [PATCH 13/24] Use 2d byte array to pass back ret --- src/java/org/bitcoin/NativeSecp256k1.java | 44 +++++++++++++++--- src/java/org/bitcoin/NativeSecp256k1Test.java | 7 ++- src/java/org_bitcoin_NativeSecp256k1.c | 45 ++++++++++++++++--- src/java/org_bitcoin_NativeSecp256k1.h | 12 ++--- 4 files changed, 87 insertions(+), 21 deletions(-) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index 4aab51171a..8dfb59e6f3 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -3,6 +3,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.math.BigInteger; import com.google.common.base.Preconditions; @@ -62,7 +63,7 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) { * @param sig byte array of signature */ - public static byte[] sign(byte[] data, byte[] sec) { + public static byte[] sign(byte[] data, byte[] sec) throws NativeSecp256k1Test.AssertFailException{ Preconditions.checkArgument(data.length == 32 && sec.length <= 32); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -74,7 +75,18 @@ public static byte[] sign(byte[] data, byte[] sec) { byteBuff.rewind(); byteBuff.put(data); byteBuff.put(sec); - return secp256k1_ecdsa_sign(byteBuff, Secp256k1Context); + + byte[][] retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context); + + byte[] sigArr = retByteArray[0]; + int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + NativeSecp256k1Test.assertEquals(sigArr.length,sigLen, "Got bad signature length." ); + + NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + + return sigArr; } /** @@ -128,7 +140,7 @@ public static boolean secKeyVerify(byte[] seckey) { * @param pubkey ECDSA Public key, 33 or 65 bytes */ - public static byte[] computePubkey(byte[] seckey, int compressed) { + public static byte[] computePubkey(byte[] seckey, int compressed) throws NativeSecp256k1Test.AssertFailException{ Preconditions.checkArgument(seckey.length == 32); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -139,7 +151,18 @@ public static byte[] computePubkey(byte[] seckey, int compressed) { } byteBuff.rewind(); byteBuff.put(seckey); - return secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context, compressed); + + byte[][] retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context, compressed); + + byte[] pubArr = retByteArray[0]; + int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + NativeSecp256k1Test.assertEquals(pubArr.length,pubLen, "Got bad pubkey length." ); + + NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + + return pubArr; } /** @@ -157,23 +180,30 @@ public static void cleanup() { */ private static native long secp256k1_init_context(); - private static native void secp256k1_destroy_context(long context); + private static native void secp256k1_destroy_context(long context); //thread unsafe - need exclusive access to call 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 byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); private static native int secp256k1_ec_pubkey_verify(ByteBuffer byteBuff, long context, int pubLen); - private static native byte[] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context, int compressed); + private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context, int compressed); // TODO + // thread exclusivity // secp256k1_ec_pubkey_decompress // secp256k1_ec_privkey_export // secp256k1_ec_privkey_import // secp256k1_ecdsa_sign_compact // secp256k1_ecdsa_recover_compact + // randomize() - thread unsafe - need exclusive access from all threads to call + // clone() + // privkey_tweak_add() + // privkey_tweak_mul() + // pubkey_tweak_add() + // pubkey_tweak_mul() } diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 7dfbaa208b..2d40f1da72 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -94,6 +94,11 @@ public static void main(String[] args) throws AssertFailException{ } } + public static void assertEquals( int val, int val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + } + private static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{ if( val != val2 ) throw new AssertFailException("FAIL: " + message); @@ -108,7 +113,7 @@ private static void assertEquals( String val, String val2, String message ) thro System.out.println("PASS: " + message); } - private static class AssertFailException extends Exception { + public static class AssertFailException extends Exception { public AssertFailException(String message) { super( message ); } diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index c52a4379da..a75debd925 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -33,25 +33,40 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify return secp256k1_ecdsa_verify(ctx, data, data+32, sigLen, data+32+sigLen, pubLen); } -JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); unsigned char* secKey = (unsigned char*) (data + 32); - jbyteArray sigArray; + jobjectArray retArray; + jbyteArray sigArray, intsByteArray; + unsigned char intsarray[2]; unsigned char sig[72]; int siglen = 72; int ret = secp256k1_ecdsa_sign(ctx, data, sig, &siglen, secKey, NULL, NULL ); + intsarray[0] = siglen; + 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; (void)ret; - return sigArray; + (void)classObject; + + return retArray; } JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify @@ -85,13 +100,29 @@ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pub unsigned char pubkey[65]; int pubkeyLen = 65; - jbyteArray pubkeyArray; + jobjectArray retArray; + jbyteArray pubkeyArray, intsByteArray; + unsigned char intsarray[2]; int ret = secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeyLen, secKey, compressed ); + intsarray[0] = pubkeyLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + pubkeyArray = (*env)->NewByteArray(env, pubkeyLen); (*env)->SetByteArrayRegion(env, pubkeyArray, 0, pubkeyLen, (jbyte*)pubkey); + (*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; - (void)classObject; (void)ret; - return pubkeyArray; } diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index e4b00f94c9..001cf1dc63 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -26,7 +26,7 @@ JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1cont /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_verify - * Signature: (Ljava/nio/ByteBuffer;J)I + * Signature: (Ljava/nio/ByteBuffer;JII)I */ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify (JNIEnv *, jclass, jobject, jlong, jint, jint); @@ -34,9 +34,9 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_sign - * Signature: (Ljava/nio/ByteBuffer;J)[B + * Signature: (Ljava/nio/ByteBuffer;J)[[B */ -JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign (JNIEnv *, jclass, jobject, jlong); /* @@ -50,7 +50,7 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1v /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ec_pubkey_verify - * Signature: (Ljava/nio/ByteBuffer;J)I + * Signature: (Ljava/nio/ByteBuffer;JI)I */ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1verify (JNIEnv *, jclass, jobject, jlong, jint); @@ -58,9 +58,9 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1v /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ec_pubkey_create - * Signature: (Ljava/nio/ByteBuffer;J)[B + * Signature: (Ljava/nio/ByteBuffer;JI)[[B */ -JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create (JNIEnv *, jclass, jobject, jlong, jint); #ifdef __cplusplus From 524da6fd40b35986e393440e104e91e8a62c726a Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Mon, 11 May 2015 19:40:45 -0500 Subject: [PATCH 14/24] Add rest of to-be-implemented funcs, and implement pubkey decompression + test --- src/java/org/bitcoin/NativeSecp256k1.java | 64 +++++++++++++++---- src/java/org/bitcoin/NativeSecp256k1Test.java | 7 ++ src/java/org_bitcoin_NativeSecp256k1.c | 53 +++++++++++++++ src/java/org_bitcoin_NativeSecp256k1.h | 40 ++++++++++++ 4 files changed, 153 insertions(+), 11 deletions(-) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index 8dfb59e6f3..d3cbd91627 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -172,6 +172,38 @@ public static byte[] computePubkey(byte[] seckey, int compressed) throws NativeS public static void cleanup() { secp256k1_destroy_context(Secp256k1Context); } + + /** + * libsecp256k1 Pubkey Decompress - Decompress a public key + * + * @param pubkey ECDSA Public key, 33 or 65 bytes + */ + + public static byte[] pubKeyDecompress(byte[] pubkey) throws NativeSecp256k1Test.AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + + byte[][] retByteArray = secp256k1_ec_pubkey_decompress(byteBuff,Secp256k1Context, pubkey.length); + + byte[] pubArr = retByteArray[0]; + int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + NativeSecp256k1Test.assertEquals(pubArr.length,pubLen, "Got bad pubkey length." ); + + NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + + return pubArr; + } + /** * @param byteBuff signature format is byte[32] data, * native-endian int signatureLength, native-endian int pubkeyLength, @@ -179,7 +211,17 @@ public static void cleanup() { * @returns 1 for valid signature, anything else for invalid */ private static native long secp256k1_init_context(); +/* + private static native long secp256k1_ctx_clone(long context); + private static native long secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); + + private static native long secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); + + private static native long secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context); + + private static native long secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context); +*/ private static native void secp256k1_destroy_context(long context); //thread unsafe - need exclusive access to call private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); @@ -192,18 +234,18 @@ public static void cleanup() { private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context, int compressed); +// + private static native byte[][] secp256k1_ec_pubkey_decompress(ByteBuffer byteBuff, long context, int pubLen); + + private static native int secp256k1_ec_pubkey_export(ByteBuffer byteBuff, long context, int compressed); + + private static native int secp256k1_ec_pubkey_import(ByteBuffer byteBuff, long context, int privLen); + + private static native byte[][] secp256k1_ecdsa_sign_compact(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ecdsa_sign_compact(ByteBuffer byteBuff, long context, int compressed); + // TODO // thread exclusivity - // secp256k1_ec_pubkey_decompress - // secp256k1_ec_privkey_export - // secp256k1_ec_privkey_import - // secp256k1_ecdsa_sign_compact - // secp256k1_ecdsa_recover_compact // randomize() - thread unsafe - need exclusive access from all threads to call - // clone() - // privkey_tweak_add() - // privkey_tweak_mul() - // pubkey_tweak_add() - // pubkey_tweak_mul() - } diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 2d40f1da72..432432f9cf 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -88,6 +88,13 @@ public static void main(String[] args) throws AssertFailException{ sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString, "" , "Case 10"); + //Case 11 - PASSING + pub = BaseEncoding.base16().lowerCase().decode("020A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE5".toLowerCase()); + + resultArr = NativeSecp256k1.pubKeyDecompress( pub ); + sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40" , "Case 11"); + NativeSecp256k1.cleanup(); System.out.println(" All tests passed." ); diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index a75debd925..2b76cf21b1 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -1,3 +1,4 @@ +#include #include "org_bitcoin_NativeSecp256k1.h" #include "include/secp256k1.h" @@ -126,3 +127,55 @@ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pub return retArray; } + +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1decompress + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint pubLen) +{ + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + + unsigned char* pubkey = (unsigned char*) malloc(sizeof(unsigned char)*65); + + unsigned char* temp = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + int i, ret; + jobjectArray retArray; + jbyteArray pubkeyArray, intsByteArray; + unsigned char intsarray[2]; + + for(i = 0; i < pubLen; i++) pubkey[i] = temp[i]; + + ret = secp256k1_ec_pubkey_decompress(ctx, pubkey, &pubLen); + + intsarray[0] = pubLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubkeyArray = (*env)->NewByteArray(env, pubLen); + (*env)->SetByteArrayRegion(env, pubkeyArray, 0, pubLen, (jbyte*)pubkey); + (*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; +} + +/* +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1export + (JNIEnv *, jclass, jobject, jlong, jint); + +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1import + (JNIEnv *, jclass, jobject, jlong, jint); + +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact__Ljava_nio_ByteBuffer_2J + (JNIEnv *, jclass, jobject, jlong); + +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact__Ljava_nio_ByteBuffer_2JI + (JNIEnv *, jclass, jobject, jlong, jint); +*/ diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index 001cf1dc63..fb062ffa30 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -63,6 +63,46 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1v JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create (JNIEnv *, jclass, jobject, jlong, jint); +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_decompress + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1decompress + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_export + * Signature: (Ljava/nio/ByteBuffer;JI)I + */ +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1export + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_import + * Signature: (Ljava/nio/ByteBuffer;JI)I + */ +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1import + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_sign_compact + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact__Ljava_nio_ByteBuffer_2J + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_sign_compact + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact__Ljava_nio_ByteBuffer_2JI + (JNIEnv *, jclass, jobject, jlong, jint); + #ifdef __cplusplus } #endif From fbcf6a2f8f4c0849a9edf9ecf5c48ae829b88482 Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Mon, 11 May 2015 22:12:13 -0500 Subject: [PATCH 15/24] add support for sign_compact, verify_compact, privkey import/export (der) --- src/java/org/bitcoin/NativeSecp256k1.java | 143 +++++++++++++++- src/java/org/bitcoin/NativeSecp256k1Test.java | 53 ++++++ src/java/org_bitcoin_NativeSecp256k1.c | 157 ++++++++++++++++-- src/java/org_bitcoin_NativeSecp256k1.h | 28 ++-- 4 files changed, 352 insertions(+), 29 deletions(-) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index d3cbd91627..b3a17527b2 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -53,6 +53,40 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) { return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context, signature.length, pub.length) == 1; } + /** + * 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 + */ + public static byte[] recoverCompact(byte[] data, byte[] signature,int compressed, int recID) throws NativeSecp256k1Test.AssertFailException{ + Preconditions.checkArgument(data.length == 32 && signature.length == 64 && (compressed == 0 || compressed == 1)); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(32 + 64); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(signature); + + byte[][] retByteArray = 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(); + + NativeSecp256k1Test.assertEquals(pubArr.length,pubLen, "Got bad signature length." ); + + NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + + return pubArr; + } + /** * libsecp256k1 Create an ECDSA signature. * @@ -89,6 +123,43 @@ public static byte[] sign(byte[] data, byte[] sec) throws NativeSecp256k1Test.As return sigArr; } + /** + * libsecp256k1 Create a compact ECDSA signature. + * + * @param data Message hash, 32 bytes + * @param key Secret key, 32 bytes + * + * Return values + * @param sig byte array of signature + * @param recid recovery id + */ + + public static byte[][] signCompact(byte[] data, byte[] sec) throws NativeSecp256k1Test.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 = secp256k1_ecdsa_sign_compact(byteBuff, Secp256k1Context); + + byte[] sigArr = retByteArray[0]; + int recID = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + //NativeSecp256k1Test.assertEquals(sigArr.length,sigLen, "Got bad signature length." ); + + NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + + return new byte[][] { sigArr , new byte[]{ (byte) recID} }; + } + /** * libsecp256k1 Pubkey Verify - returns 1 if valid, 0 if invalid * @@ -204,6 +275,69 @@ public static byte[] pubKeyDecompress(byte[] pubkey) throws NativeSecp256k1Test. return pubArr; } + /** + * 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 NativeSecp256k1Test.AssertFailException{ + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + byte[][] retByteArray = secp256k1_ec_privkey_import(byteBuff,Secp256k1Context, seckey.length); + + 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(); + + NativeSecp256k1Test.assertEquals(privArr.length,privLen, "Got bad pubkey length." ); + + NativeSecp256k1Test.assertEquals(retVal,retVal, "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 NativeSecp256k1Test.AssertFailException{ + Preconditions.checkArgument(privkey.length == 32 && (compressed == 0 || compressed == 1) ); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(privkey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + + byte[][] retByteArray = secp256k1_ec_privkey_export(byteBuff,Secp256k1Context, privkey.length, compressed ); + + 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(); + + NativeSecp256k1Test.assertEquals(privArr.length, compressed == 1? 214 : 279, "Got bad pubkey length." ); + + NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + + return privArr; + } + /** * @param byteBuff signature format is byte[32] data, * native-endian int signatureLength, native-endian int pubkeyLength, @@ -234,16 +368,15 @@ public static byte[] pubKeyDecompress(byte[] pubkey) throws NativeSecp256k1Test. private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context, int compressed); -// private static native byte[][] secp256k1_ec_pubkey_decompress(ByteBuffer byteBuff, long context, int pubLen); - private static native int secp256k1_ec_pubkey_export(ByteBuffer byteBuff, long context, int compressed); + private static native byte[][] secp256k1_ec_privkey_export(ByteBuffer byteBuff, long context, int privLen, int compressed); - private static native int secp256k1_ec_pubkey_import(ByteBuffer byteBuff, long context, int privLen); + private static native byte[][] secp256k1_ec_privkey_import(ByteBuffer byteBuff, long context, int privLen); - private static native byte[][] secp256k1_ecdsa_sign_compact(ByteBuffer byteBuff, long context); + private static native byte[][] secp256k1_ecdsa_recover_compact(ByteBuffer byteBuff, long context, int compressed, int recID); - private static native byte[][] secp256k1_ecdsa_sign_compact(ByteBuffer byteBuff, long context, int compressed); + private static native byte[][] secp256k1_ecdsa_sign_compact(ByteBuffer byteBuff, long context); // TODO // thread exclusivity diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 432432f9cf..2079d76d49 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -95,6 +95,59 @@ public static void main(String[] args) throws AssertFailException{ sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40" , "Case 11"); + //Case 12 - PASSING + sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + resultArr = NativeSecp256k1.privKeyExport( sec , 1); + sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "3081D3020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A08185308182020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704210279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A12403220002C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 12"); + + //Case 13 - PASSING + sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + resultArr = NativeSecp256k1.privKeyExport( sec , 0); + sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "30820113020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A081A53081A2020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704410479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A14403420004C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "Case 13"); + + //Case 14 - PASSING + sec = BaseEncoding.base16().lowerCase().decode("3081D3020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A08185308182020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704210279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A12403220002C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D".toLowerCase()); + + resultArr = NativeSecp256k1.secKeyImport( sec ); + sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + + assertEquals( sigString , "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530" , "Case 14"); + + //Case 15 - PASSING + sec = BaseEncoding.base16().lowerCase().decode("30820113020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A081A53081A2020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704410479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A14403420004C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6".toLowerCase()); + + resultArr = NativeSecp256k1.secKeyImport( sec ); + sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530" , "Case 15"); + + //Case 16 - PASSING + data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" + sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[][] resultByteArr = NativeSecp256k1.signCompact( data , sec ); + sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultByteArr[0]); + String idString = javax.xml.bind.DatatypeConverter.printHexBinary(resultByteArr[1]); + assertEquals( sigString , "A33C093C80B84CA1AFBC8974EE3C42FC1CBC966CAE66612593CD1E44646BABFF00CB69703B98B0103AE22C7F9CCADD8DD98F9505BE7A66B1AE459576E930C4F6" , "Case 16 assert 1"); + assertEquals( idString , "01" , "Case 16 assert 2"); + + //Case 17 - PASSING + 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"); + NativeSecp256k1.cleanup(); System.out.println(" All tests passed." ); diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 2b76cf21b1..c742315e2e 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -166,16 +166,153 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p return retArray; } -/* -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1export - (JNIEnv *, jclass, jobject, jlong, jint); -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1import - (JNIEnv *, jclass, jobject, jlong, jint); +JNIEXPORT 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_t *ctx = (secp256k1_context_t*)ctx_l; + + const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + int i, ret; + jobjectArray retArray; + jbyteArray privkeyArray, intsByteArray; + unsigned char intsarray[2]; -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact__Ljava_nio_ByteBuffer_2J - (JNIEnv *, jclass, jobject, jlong); + unsigned char* privkey = (unsigned char*) malloc(sizeof(unsigned char)*279); -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact__Ljava_nio_ByteBuffer_2JI - (JNIEnv *, jclass, jobject, jlong, jint); -*/ + for(i = 0; i < privLen; i++) privkey[i] = secKey[i]; + + ret = secp256k1_ec_privkey_export(ctx, secKey, privkey ,&privLen, 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; +} + +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1import + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint privLen) +{ + secp256k1_context_t *ctx = (secp256k1_context_t*)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; +} + + +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context_t *ctx = (secp256k1_context_t*)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; +} + + +JNIEXPORT 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_t *ctx = (secp256k1_context_t*)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; +} diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index fb062ffa30..427033d23a 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -73,35 +73,35 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p /* * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ec_pubkey_export - * Signature: (Ljava/nio/ByteBuffer;JI)I + * Method: secp256k1_ec_privkey_export + * Signature: (Ljava/nio/ByteBuffer;JII)[[B */ -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1export - (JNIEnv *, jclass, jobject, jlong, jint); +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1export + (JNIEnv *, jclass, jobject, jlong, jint, jint); /* * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ec_pubkey_import - * Signature: (Ljava/nio/ByteBuffer;JI)I + * Method: secp256k1_ec_privkey_import + * Signature: (Ljava/nio/ByteBuffer;JI)[[B */ -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1import +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1import (JNIEnv *, jclass, jobject, jlong, jint); /* * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdsa_sign_compact - * Signature: (Ljava/nio/ByteBuffer;J)[[B + * Method: secp256k1_ecdsa_recover_compact + * Signature: (Ljava/nio/ByteBuffer;JII)[[B */ -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact__Ljava_nio_ByteBuffer_2J - (JNIEnv *, jclass, jobject, jlong); +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1recover_1compact + (JNIEnv *, jclass, jobject, jlong, jint, jint); /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_sign_compact - * Signature: (Ljava/nio/ByteBuffer;JI)[[B + * Signature: (Ljava/nio/ByteBuffer;J)[[B */ -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact__Ljava_nio_ByteBuffer_2JI - (JNIEnv *, jclass, jobject, jlong, jint); +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact + (JNIEnv *, jclass, jobject, jlong); #ifdef __cplusplus } From 072d19370a76c6ae14d828514ac4c9557b5856ca Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Tue, 12 May 2015 21:38:10 -0500 Subject: [PATCH 16/24] added tweak implementations, clone and tests --- src/java/org/bitcoin/NativeSecp256k1.java | 146 ++++++++++++++++- src/java/org/bitcoin/NativeSecp256k1Test.java | 32 ++++ src/java/org_bitcoin_NativeSecp256k1.c | 149 ++++++++++++++++++ src/java/org_bitcoin_NativeSecp256k1.h | 40 +++++ 4 files changed, 361 insertions(+), 6 deletions(-) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index b3a17527b2..21fb83a45b 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -338,6 +338,141 @@ public static byte[] privKeyExport(byte[] privkey, int compressed) throws Native return privArr; } + public static long cloneContext() { + return secp256k1_ctx_clone(Secp256k1Context); + } + + /** + * 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 NativeSecp256k1Test.AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context); + + 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(); + + NativeSecp256k1Test.assertEquals(privArr.length, privLen, "Got bad pubkey length." ); + + NativeSecp256k1Test.assertEquals(retVal,retVal, "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 NativeSecp256k1Test.AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context); + + 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(); + + NativeSecp256k1Test.assertEquals(privArr.length, privLen, "Got bad pubkey length." ); + + NativeSecp256k1Test.assertEquals(retVal,retVal, "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 NativeSecp256k1Test.AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context, pubkey.length); + + 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(); + + NativeSecp256k1Test.assertEquals(pubArr.length, pubLen, "Got bad pubkey length." ); + + NativeSecp256k1Test.assertEquals(retVal,retVal, "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 NativeSecp256k1Test.AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context, pubkey.length); + + 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(); + + NativeSecp256k1Test.assertEquals(pubArr.length, pubLen, "Got bad pubkey length." ); + + NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + + return pubArr; + } /** * @param byteBuff signature format is byte[32] data, * native-endian int signatureLength, native-endian int pubkeyLength, @@ -345,17 +480,16 @@ public static byte[] privKeyExport(byte[] privkey, int compressed) throws Native * @returns 1 for valid signature, anything else for invalid */ private static native long secp256k1_init_context(); -/* + private static native long secp256k1_ctx_clone(long context); - private static native long secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); + private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); - private static native long secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); + private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); - private static native long secp256k1_pubkey_tweak_add(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 long secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context); -*/ private static native void secp256k1_destroy_context(long context); //thread unsafe - need exclusive access to call private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 2079d76d49..2a37608349 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -148,6 +148,38 @@ public static void main(String[] args) throws AssertFailException{ sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "02C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 18"); + //Case 18 - PASSING + sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data ); + sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "Case 18"); + + //Case 19 - PASSING + sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + resultArr = NativeSecp256k1.privKeyTweakMul( sec , data ); + sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "Case 19"); + + //Case 20 - PASSING + pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data ); + sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "Case 20"); + + //Case 21 - PASSING + pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data ); + sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "Case 21"); + NativeSecp256k1.cleanup(); System.out.println(" All tests passed." ); diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index c742315e2e..847208bc24 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -12,6 +12,19 @@ JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1contex return (jlong)ctx; } +JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + const secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + + jlong ctx_clone_l = (jlong) secp256k1_context_clone(ctx); + + (void)classObject;(void)env; + + return (jlong)ctx_clone_l; + +} + JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context (JNIEnv* env, jclass classObject, jlong ctx_l) { @@ -316,3 +329,139 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa return retArray; } + +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + unsigned char* pubkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pubkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + + int ret = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, publen, tweak); + + intsarray[0] = publen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, publen); + (*env)->SetByteArrayRegion(env, pubArray, 0, publen, (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; +} + +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + unsigned char* pubkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pubkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + + int ret = secp256k1_ec_pubkey_tweak_mul(ctx, pubkey, publen, tweak); + + intsarray[0] = publen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, publen); + (*env)->SetByteArrayRegion(env, pubArray, 0, publen, (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; +} diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index 427033d23a..6a85f50798 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -15,6 +15,46 @@ extern "C" { JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1context (JNIEnv *, jclass); +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ctx_clone + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv *, jclass, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong, jint); + /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_destroy_context From 6d3facb433d38361e2797d03e92fdfa6ffee6fe9 Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Thu, 14 May 2015 21:10:49 -0500 Subject: [PATCH 17/24] Cleanup, add randomize() and synchronized access --- src/java/org/bitcoin/NativeSecp256k1.java | 34 ++++++++++++--- src/java/org/bitcoin/NativeSecp256k1Test.java | 43 +++++++++++-------- src/java/org_bitcoin_NativeSecp256k1.c | 13 ++++++ src/java/org_bitcoin_NativeSecp256k1.h | 8 ++++ 4 files changed, 72 insertions(+), 26 deletions(-) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index 21fb83a45b..5a08f19b05 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -6,7 +6,6 @@ import java.math.BigInteger; import com.google.common.base.Preconditions; - /** * This class holds native methods to handle ECDSA verification. * You can find an example library that can be used for this at @@ -14,7 +13,7 @@ */ public class NativeSecp256k1 { public static final boolean enabled; - private static final long Secp256k1Context; //ref to pointer to context obj + public static final long Secp256k1Context; //ref to pointer to context obj static { boolean isEnabled = true; long contextRef = -1; @@ -240,7 +239,7 @@ public static byte[] computePubkey(byte[] seckey, int compressed) throws NativeS * 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 void cleanup() { + public static synchronized void cleanup() { secp256k1_destroy_context(Secp256k1Context); } @@ -473,6 +472,27 @@ public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws NativeSe return pubArr; } + + /** + * libsecp256k1 randomize - updates the context randomization + * + * @param seed some random bytes to seed with + */ + public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1Test.AssertFailException{ + Preconditions.checkArgument(seed.length == 32 || seed == null); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(seed.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seed); + + return secp256k1_context_randomize(byteBuff, Secp256k1Context) == 1; + } + /** * @param byteBuff signature format is byte[32] data, * native-endian int signatureLength, native-endian int pubkeyLength, @@ -483,14 +503,17 @@ public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws NativeSe 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); //thread unsafe - need exclusive access to call + private static native void secp256k1_destroy_context(long context); private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); @@ -512,7 +535,4 @@ public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws NativeSe private static native byte[][] secp256k1_ecdsa_sign_compact(ByteBuffer byteBuff, long context); - // TODO - // thread exclusivity - // randomize() - thread unsafe - need exclusive access from all threads to call } diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 2a37608349..9d8fc629ce 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -14,7 +14,7 @@ public static void main(String[] args) throws AssertFailException{ boolean result = false; - //Case 1 - PASSING + //Case 1 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()); @@ -22,7 +22,7 @@ public static void main(String[] args) throws AssertFailException{ result = NativeSecp256k1.verify( data, sig, pub ); assertEquals( result, true , "Case 1"); - //Case 2 - FAILING + //Case 2 data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); @@ -30,27 +30,27 @@ public static void main(String[] args) throws AssertFailException{ result = NativeSecp256k1.verify( data, sig, pub ); assertEquals( result, false , "Case 2"); - //Case 3 - PASSING + //Case 3 pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); result = NativeSecp256k1.pubKeyVerify( pub ); assertEquals( result, true , "Case 3"); - //Case 4 - FAILING + //Case 4 pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C41".toLowerCase()); result = NativeSecp256k1.pubKeyVerify( pub ); assertEquals( result, false , "Case 4"); - //Case 5 - PASSING + //Case 5 byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); result = NativeSecp256k1.secKeyVerify( sec ); assertEquals( result, true , "Case 5"); - //Case 6 - FAILING + //Case 6 sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); result = NativeSecp256k1.secKeyVerify( sec ); assertEquals( result, false , "Case 6"); - //Case 7 - PASSING + //Case 7 sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); byte[] resultArr = NativeSecp256k1.computePubkey( sec , 0); @@ -72,7 +72,7 @@ public static void main(String[] args) throws AssertFailException{ pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( pubkeyString, "" , "Case 8 Compressed"); - //Case 9 - PASSING + //Case 9 data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); @@ -88,28 +88,28 @@ public static void main(String[] args) throws AssertFailException{ sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString, "" , "Case 10"); - //Case 11 - PASSING + //Case 11 pub = BaseEncoding.base16().lowerCase().decode("020A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE5".toLowerCase()); resultArr = NativeSecp256k1.pubKeyDecompress( pub ); sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40" , "Case 11"); - //Case 12 - PASSING + //Case 12 sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); resultArr = NativeSecp256k1.privKeyExport( sec , 1); sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "3081D3020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A08185308182020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704210279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A12403220002C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 12"); - //Case 13 - PASSING + //Case 13 sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); resultArr = NativeSecp256k1.privKeyExport( sec , 0); sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "30820113020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A081A53081A2020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704410479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A14403420004C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "Case 13"); - //Case 14 - PASSING + //Case 14 sec = BaseEncoding.base16().lowerCase().decode("3081D3020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A08185308182020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704210279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A12403220002C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D".toLowerCase()); resultArr = NativeSecp256k1.secKeyImport( sec ); @@ -117,14 +117,14 @@ public static void main(String[] args) throws AssertFailException{ assertEquals( sigString , "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530" , "Case 14"); - //Case 15 - PASSING + //Case 15 sec = BaseEncoding.base16().lowerCase().decode("30820113020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A081A53081A2020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704410479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A14403420004C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6".toLowerCase()); resultArr = NativeSecp256k1.secKeyImport( sec ); sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530" , "Case 15"); - //Case 16 - PASSING + //Case 16 data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); @@ -134,7 +134,7 @@ public static void main(String[] args) throws AssertFailException{ assertEquals( sigString , "A33C093C80B84CA1AFBC8974EE3C42FC1CBC966CAE66612593CD1E44646BABFF00CB69703B98B0103AE22C7F9CCADD8DD98F9505BE7A66B1AE459576E930C4F6" , "Case 16 assert 1"); assertEquals( idString , "01" , "Case 16 assert 2"); - //Case 17 - PASSING + //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()); @@ -148,7 +148,7 @@ public static void main(String[] args) throws AssertFailException{ sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "02C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 18"); - //Case 18 - PASSING + //Case 18 sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" @@ -156,7 +156,7 @@ public static void main(String[] args) throws AssertFailException{ sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "Case 18"); - //Case 19 - PASSING + //Case 19 sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" @@ -164,7 +164,7 @@ public static void main(String[] args) throws AssertFailException{ sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "Case 19"); - //Case 20 - PASSING + //Case 20 pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" @@ -172,7 +172,7 @@ public static void main(String[] args) throws AssertFailException{ sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "Case 20"); - //Case 21 - PASSING + //Case 21 pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" @@ -180,6 +180,11 @@ public static void main(String[] args) throws AssertFailException{ sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "Case 21"); + //Case 22 + byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random" + result = NativeSecp256k1.randomize(seed); + assertEquals( result, true, "Case 22"); + NativeSecp256k1.cleanup(); System.out.println(" All tests passed." ); diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 847208bc24..04ad11e28b 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -25,6 +25,19 @@ JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone } +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + + const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_context_randomize(ctx, seed); + +} + JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context (JNIEnv* env, jclass classObject, jlong ctx_l) { diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index 6a85f50798..f26b251c95 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -23,6 +23,14 @@ JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1contex JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone (JNIEnv *, jclass, jlong); +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_context_randomize + * Signature: (Ljava/nio/ByteBuffer;J)[J + */ +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv *, jclass, jobject, jlong); + /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_privkey_tweak_add From 633e0e6b16f49186a45f3ff5cea5d1413b17458d Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Fri, 21 Aug 2015 16:50:09 -0500 Subject: [PATCH 18/24] Committing temp work --- Makefile.am | 9 +- src/java/org/bitcoin/NativeSecp256k1.java | 52 ++++++++++- src/java/org/bitcoin/NativeSecp256k1Test.java | 17 +++- src/java/org_bitcoin_NativeSecp256k1.c | 92 +++++++++++++++++-- src/java/org_bitcoin_NativeSecp256k1.h | 62 ++++++++++++- 5 files changed, 210 insertions(+), 22 deletions(-) diff --git a/Makefile.am b/Makefile.am index 3a14e62e8e..198e9f484d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -112,9 +112,7 @@ check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java endif endif -CLEANFILES = $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java -EXTRA_DIST = autogen.sh $(JAVA_FILES) -======= + if USE_ECMULT_STATIC_PRECOMPUTATION CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)/ CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function @@ -133,10 +131,10 @@ $(tests_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 @@ -145,4 +143,3 @@ endif if ENABLE_MODULE_SCHNORR include src/modules/schnorr/Makefile.am.include endif ->>>>>>> 9d96e362a54e8d6527c510199f465600112d7117 diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index 5a08f19b05..a351903b70 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -35,21 +35,40 @@ public class NativeSecp256k1 { * @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 + * @param compact Verify a compact signature + * @param recovery Signature recovery ID (-1 if not compact) */ - public static boolean verify(byte[] data, byte[] signature, byte[] pub) { + public static boolean verify(byte[] data, byte[] signature, byte[] pub, boolean compact, int recovery) { Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); ByteBuffer byteBuff = nativeECDSABuffer.get(); if (byteBuff == null) { - byteBuff = ByteBuffer.allocateDirect(32 + 520 + 520); + byteBuff = ByteBuffer.allocateDirect(520); byteBuff.order(ByteOrder.nativeOrder()); nativeECDSABuffer.set(byteBuff); } byteBuff.rewind(); - byteBuff.put(data); byteBuff.put(signature); + + long[] sigRef; + if(compact) + sigRef = secp256k1_ecdsa_signature_parse_compact(byteBuff, Secp256k1Context, recovery); + else + sigRef = secp256k1_ecdsa_signature_parse_der(byteBuff, Secp256k1Context, signature.length); + + System.out.println(" SigRef " + sigRef[1]); + + byteBuff.rewind(); byteBuff.put(pub); - return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context, signature.length, pub.length) == 1; + + long[] pubRef = secp256k1_ec_pubkey_parse(byteBuff, Secp256k1Context, pub.length); + + System.out.println(" PubRef " + pubRef[1]); + + byteBuff.rewind(); + byteBuff.put(data); + + return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context, sigRef[1], pubRef[1] ) == 1; } /** @@ -515,7 +534,7 @@ public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1 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 int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, long signature, long pubkey); private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); @@ -525,14 +544,37 @@ public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1 private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context, int compressed); + //deprecated private static native byte[][] secp256k1_ec_pubkey_decompress(ByteBuffer byteBuff, long context, int pubLen); 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); + //deprecated private static native byte[][] secp256k1_ecdsa_recover_compact(ByteBuffer byteBuff, long context, int compressed, int recID); + //deprecated private static native byte[][] secp256k1_ecdsa_sign_compact(ByteBuffer byteBuff, long context); + //TODO support sending back error codes + //TODO make verify() work again + //TODO fix old methods to support new types and remove stale function args + //TODO add below methods + //TODO fix locking https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html#readLock() + private static native long[] secp256k1_ecdsa_signature_parse_der(ByteBuffer byteBuff, long context, int inputLen); + + private static native long[] secp256k1_ecdsa_signature_parse_compact(ByteBuffer byteBuff, long context, int recovery); + + private static native byte[][] secp256k1_ecdsa_signature_serialize_der(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ecdsa_signature_serialize_compact(ByteBuffer byteBuff, long context); + + private static native long[] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); + + private static native byte[][] secp256k1_ecdsa_pubkey_serialize(ByteBuffer byteBuff, long context); + + private static native long secp256k1_ecdsa_pubkey_combine(ByteBuffer byteBuff, long context, int keys); + + //private static native byte[][] secp256k1_ecdsa_recover_compact(ByteBuffer byteBuff, long context, int compressed, int recID); } diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 9d8fc629ce..00d869bfc9 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -2,6 +2,7 @@ import com.google.common.io.BaseEncoding; import java.util.Arrays; +import java.math.BigInteger; import javax.xml.bind.DatatypeConverter; public class NativeSecp256k1Test { @@ -13,13 +14,25 @@ public static void main(String[] args) throws AssertFailException{ if( NativeSecp256k1.enabled ) { boolean result = false; + //byte[] resultbytes = null; + + //Case 1 + //byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + //byte[] sec = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); + + //resultbytes = NativeSecp256k1.sign( data, sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + //assertEquals( result, true , "Case 1"); //Case 1 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()); + boolean compact = false; + int recovery = 0; - result = NativeSecp256k1.verify( data, sig, pub ); + result = NativeSecp256k1.verify( data, sig, pub, compact, recovery ); +System.out.println(" TEST " + result); assertEquals( result, true , "Case 1"); //Case 2 @@ -27,7 +40,7 @@ public static void main(String[] args) throws AssertFailException{ sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); - result = NativeSecp256k1.verify( data, sig, pub ); + result = NativeSecp256k1.verify( data, sig, pub, compact, recovery ); assertEquals( result, false , "Case 2"); //Case 3 diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 04ad11e28b..4eb9de7d83 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -49,15 +49,30 @@ JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1cont } JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint sigLen, jint pubLen) + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jlong sig_l, jlong pub_l) { + + printf(" \n JLONG 2: %ld \n", sig_l); + printf(" \n JLONG 2: %ld \n", pub_l); secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + secp256k1_ecdsa_signature_t *sig = (secp256k1_ecdsa_signature_t*)sig_l; + secp256k1_pubkey_t *pub = (secp256k1_pubkey_t*)pub_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + printf("hashedChars 2: "); + int i; + for (i = 0; i < 64; i++) { + printf("%x", sig->data[i]); + } + printf("\n"); + +/* (void)classObject; - return secp256k1_ecdsa_verify(ctx, data, data+32, sigLen, data+32+sigLen, pubLen); + return secp256k1_ecdsa_verify(ctx, data, sig, pub); +*/ + return 0; } JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign @@ -74,7 +89,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa unsigned char sig[72]; int siglen = 72; - int ret = secp256k1_ecdsa_sign(ctx, data, sig, &siglen, secKey, NULL, NULL ); + int ret = secp256k1_ecdsa_sign(ctx, data, sig, secKey, NULL, NULL ); intsarray[0] = siglen; intsarray[1] = ret; @@ -131,7 +146,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pub jbyteArray pubkeyArray, intsByteArray; unsigned char intsarray[2]; - int ret = secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeyLen, secKey, compressed ); + int ret = secp256k1_ec_pubkey_create(ctx, pubkey, secKey); intsarray[0] = pubkeyLen; intsarray[1] = ret; @@ -424,7 +439,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubke jbyteArray pubArray, intsByteArray; unsigned char intsarray[2]; - int ret = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, publen, tweak); + int ret = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, tweak); intsarray[0] = publen; intsarray[1] = ret; @@ -457,7 +472,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubke jbyteArray pubArray, intsByteArray; unsigned char intsarray[2]; - int ret = secp256k1_ec_pubkey_tweak_mul(ctx, pubkey, publen, tweak); + int ret = secp256k1_ec_pubkey_tweak_mul(ctx, pubkey, tweak); intsarray[0] = publen; intsarray[1] = ret; @@ -478,3 +493,68 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubke return retArray; } + +JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1der + (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint inputlen) +{ + const secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + + secp256k1_ecdsa_signature_t sig; + unsigned char* input = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, input, inputlen); + + /*TODO return error value?*/ + jlong sig_l = (jlong) &sig; + + jlongArray retArray; + + printf("hashedChars 0: "); + int i; + for (i = 0; i < 64; i++) { + printf("%x", sig.data[i]); + } + printf("\n"); + printf(" \n JLONG 0: %ld \n", sig_l); + + retArray = (*env)->NewLongArray(env, 2); + + (*env)->SetLongArrayRegion(env, retArray, 0, 1, &sig_l); + (*env)->SetLongArrayRegion(env, retArray, 1, 1, &sig_l); + + (void)classObject; + + return retArray; +} + +JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1compact + (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint recovery) +{ + (void)classObject; + return 0; +} + +JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse + (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint inputlen) +{ + const secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + + secp256k1_pubkey_t pubkey; + unsigned char* input = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, input, inputlen); + + /*TODO return error value?*/ + jlong pubkey_l = (jlong) &pubkey; + + jlongArray retArray; + + retArray = (*env)->NewLongArray(env, 2); + + (*env)->SetLongArrayRegion(env, retArray, 0, 1, &pubkey_l); + (*env)->SetLongArrayRegion(env, retArray, 1, 1, &pubkey_l); + + (void)classObject; + + return retArray; +} diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index f26b251c95..f4a76c02be 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -26,7 +26,7 @@ JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_context_randomize - * Signature: (Ljava/nio/ByteBuffer;J)[J + * Signature: (Ljava/nio/ByteBuffer;J)I */ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize (JNIEnv *, jclass, jobject, jlong); @@ -74,10 +74,10 @@ JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1cont /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_verify - * Signature: (Ljava/nio/ByteBuffer;JII)I + * Signature: (Ljava/nio/ByteBuffer;JJJ)I */ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv *, jclass, jobject, jlong, jint, jint); + (JNIEnv *, jclass, jobject, jlong, jlong, jlong); /* * Class: org_bitcoin_NativeSecp256k1 @@ -151,6 +151,62 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact (JNIEnv *, jclass, jobject, jlong); +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_signature_parse_der + * Signature: (Ljava/nio/ByteBuffer;JI)[J + */ +JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1der + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_signature_parse_compact + * Signature: (Ljava/nio/ByteBuffer;JI)[J + */ +JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1compact + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_signature_serialize_der + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1serialize_1der + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_signature_serialize_compact + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1serialize_1compact + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_parse + * Signature: (Ljava/nio/ByteBuffer;JI)[J + */ +JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_pubkey_serialize + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1serialize + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_pubkey_combine + * Signature: (Ljava/nio/ByteBuffer;JI)J + */ +JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine + (JNIEnv *, jclass, jobject, jlong, jint); + #ifdef __cplusplus } #endif From 88d81acc85d5e2c1a2a9dcab596b45978cdc8715 Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Mon, 31 Aug 2015 04:55:37 -0500 Subject: [PATCH 19/24] Update ecdsa_Verify --- src/java/org/bitcoin/NativeSecp256k1.java | 42 ++++++----- src/java/org/bitcoin/NativeSecp256k1Test.java | 7 +- src/java/org_bitcoin_NativeSecp256k1.c | 72 +++++++++---------- src/java/org_bitcoin_NativeSecp256k1.h | 20 ++---- 4 files changed, 68 insertions(+), 73 deletions(-) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index a351903b70..7581dca035 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -35,10 +35,8 @@ public class NativeSecp256k1 { * @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 - * @param compact Verify a compact signature - * @param recovery Signature recovery ID (-1 if not compact) */ - public static boolean verify(byte[] data, byte[] signature, byte[] pub, boolean compact, int recovery) { + public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws NativeSecp256k1Test.AssertFailException{ Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -50,25 +48,37 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub, boolean byteBuff.rewind(); byteBuff.put(signature); - long[] sigRef; - if(compact) - sigRef = secp256k1_ecdsa_signature_parse_compact(byteBuff, Secp256k1Context, recovery); - else - sigRef = secp256k1_ecdsa_signature_parse_der(byteBuff, Secp256k1Context, signature.length); + byte[][] retByteArray = secp256k1_ecdsa_signature_parse_der(byteBuff, Secp256k1Context, signature.length); - System.out.println(" SigRef " + sigRef[1]); + byte[] sigArr = retByteArray[0]; + //DEBUG System.out.println(" Sigarr is " + new BigInteger(1, sigArr).toString(16)); + int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + //DEBUG System.out.println(" RetVal is " + retVal); + + NativeSecp256k1Test.assertEquals(sigArr.length, 64, "Got bad signature length." ); + + NativeSecp256k1Test.assertEquals(retVal, 1, "Failed return value check."); byteBuff.rewind(); byteBuff.put(pub); - long[] pubRef = secp256k1_ec_pubkey_parse(byteBuff, Secp256k1Context, pub.length); + retByteArray = secp256k1_ec_pubkey_parse(byteBuff, Secp256k1Context, pub.length); + + byte[] pubArr = retByteArray[0]; + //DEBUG System.out.println(" Pubarr is " + new BigInteger(1, pubArr).toString(16)); + retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + //DEBUG System.out.println(" RetVal is " + retVal); + + NativeSecp256k1Test.assertEquals(pubArr.length, 64, "Got bad pubkey length." ); - System.out.println(" PubRef " + pubRef[1]); + NativeSecp256k1Test.assertEquals(retVal, 1, "Failed return value check."); byteBuff.rewind(); byteBuff.put(data); + byteBuff.put(sigArr); + byteBuff.put(pubArr); - return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context, sigRef[1], pubRef[1] ) == 1; + return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context) == 1; } /** @@ -534,7 +544,7 @@ public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1 private static native void secp256k1_destroy_context(long context); - private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, long signature, long pubkey); + private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context); private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); @@ -562,15 +572,15 @@ public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1 //TODO fix old methods to support new types and remove stale function args //TODO add below methods //TODO fix locking https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html#readLock() - private static native long[] secp256k1_ecdsa_signature_parse_der(ByteBuffer byteBuff, long context, int inputLen); + private static native byte[][] secp256k1_ecdsa_signature_parse_der(ByteBuffer byteBuff, long context, int inputLen); - private static native long[] secp256k1_ecdsa_signature_parse_compact(ByteBuffer byteBuff, long context, int recovery); + //private static native long[] secp256k1_ecdsa_signature_parse_compact(ByteBuffer byteBuff, long context, int recovery); private static native byte[][] secp256k1_ecdsa_signature_serialize_der(ByteBuffer byteBuff, long context); private static native byte[][] secp256k1_ecdsa_signature_serialize_compact(ByteBuffer byteBuff, long context); - private static native long[] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); + private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); private static native byte[][] secp256k1_ecdsa_pubkey_serialize(ByteBuffer byteBuff, long context); diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 00d869bfc9..bd93416fb7 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -28,11 +28,8 @@ public static void main(String[] args) throws AssertFailException{ 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()); - boolean compact = false; - int recovery = 0; - result = NativeSecp256k1.verify( data, sig, pub, compact, recovery ); -System.out.println(" TEST " + result); + result = NativeSecp256k1.verify( data, sig, pub); assertEquals( result, true , "Case 1"); //Case 2 @@ -40,7 +37,7 @@ public static void main(String[] args) throws AssertFailException{ sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); - result = NativeSecp256k1.verify( data, sig, pub, compact, recovery ); + result = NativeSecp256k1.verify( data, sig, pub); assertEquals( result, false , "Case 2"); //Case 3 diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 4eb9de7d83..793526a0d4 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -49,30 +49,17 @@ JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1cont } JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jlong sig_l, jlong pub_l) + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - - printf(" \n JLONG 2: %ld \n", sig_l); - printf(" \n JLONG 2: %ld \n", pub_l); secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; - secp256k1_ecdsa_signature_t *sig = (secp256k1_ecdsa_signature_t*)sig_l; - secp256k1_pubkey_t *pub = (secp256k1_pubkey_t*)pub_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const secp256k1_ecdsa_signature_t *sig = { (unsigned char*) (data + 32) }; + const secp256k1_pubkey_t *pub = { (unsigned char*) (data + 64 + 32) }; - printf("hashedChars 2: "); - int i; - for (i = 0; i < 64; i++) { - printf("%x", sig->data[i]); - } - printf("\n"); - -/* (void)classObject; return secp256k1_ecdsa_verify(ctx, data, sig, pub); -*/ - return 0; } JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign @@ -494,7 +481,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubke return retArray; } -JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1der +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1der (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint inputlen) { const secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; @@ -502,25 +489,25 @@ JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1 secp256k1_ecdsa_signature_t sig; unsigned char* input = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, input, inputlen); + jobjectArray retArray; + jbyteArray sigArray, intsByteArray; + unsigned char intsarray[1]; - /*TODO return error value?*/ - jlong sig_l = (jlong) &sig; + int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, input, inputlen); - jlongArray retArray; + intsarray[0] = ret; - printf("hashedChars 0: "); - int i; - for (i = 0; i < 64; i++) { - printf("%x", sig.data[i]); - } - printf("\n"); - printf(" \n JLONG 0: %ld \n", sig_l); + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); - retArray = (*env)->NewLongArray(env, 2); + sigArray = (*env)->NewByteArray(env, 64); + (*env)->SetByteArrayRegion(env, sigArray, 0, 64, (jbyte*)sig.data); + (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); - (*env)->SetLongArrayRegion(env, retArray, 0, 1, &sig_l); - (*env)->SetLongArrayRegion(env, retArray, 1, 1, &sig_l); + intsByteArray = (*env)->NewByteArray(env, 1); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (void)classObject; @@ -531,10 +518,11 @@ JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1 (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint recovery) { (void)classObject; + return 0; } -JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint inputlen) { const secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; @@ -542,17 +530,25 @@ JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pub secp256k1_pubkey_t pubkey; unsigned char* input = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, input, inputlen); - /*TODO return error value?*/ - jlong pubkey_l = (jlong) &pubkey; + intsarray[0] = ret; - jlongArray retArray; + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); - retArray = (*env)->NewLongArray(env, 2); + pubArray = (*env)->NewByteArray(env, 64); + (*env)->SetByteArrayRegion(env, pubArray, 0, 64, (jbyte*)pubkey.data); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); - (*env)->SetLongArrayRegion(env, retArray, 0, 1, &pubkey_l); - (*env)->SetLongArrayRegion(env, retArray, 1, 1, &pubkey_l); + intsByteArray = (*env)->NewByteArray(env, 1); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); (void)classObject; diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index f4a76c02be..8c38abbef8 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -74,10 +74,10 @@ JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1cont /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_verify - * Signature: (Ljava/nio/ByteBuffer;JJJ)I + * Signature: (Ljava/nio/ByteBuffer;J)I */ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv *, jclass, jobject, jlong, jlong, jlong); + (JNIEnv *, jclass, jobject, jlong); /* * Class: org_bitcoin_NativeSecp256k1 @@ -154,17 +154,9 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_signature_parse_der - * Signature: (Ljava/nio/ByteBuffer;JI)[J - */ -JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1der - (JNIEnv *, jclass, jobject, jlong, jint); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdsa_signature_parse_compact - * Signature: (Ljava/nio/ByteBuffer;JI)[J + * Signature: (Ljava/nio/ByteBuffer;JI)[[B */ -JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1compact +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1der (JNIEnv *, jclass, jobject, jlong, jint); /* @@ -186,9 +178,9 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ec_pubkey_parse - * Signature: (Ljava/nio/ByteBuffer;JI)[J + * Signature: (Ljava/nio/ByteBuffer;JI)[[B */ -JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse (JNIEnv *, jclass, jobject, jlong, jint); /* From 769227601d337d8a3942bc2536add3bd19b9454d Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Sat, 5 Sep 2015 13:45:35 -0500 Subject: [PATCH 20/24] Update test runner and remove deprecated API --- Makefile.am | 1 - src/java/org/bitcoin/NativeSecp256k1.java | 124 +------- src/java/org/bitcoin/NativeSecp256k1Test.java | 276 ++++++++++-------- src/java/org_bitcoin_NativeSecp256k1.c | 37 +-- src/java/org_bitcoin_NativeSecp256k1.h | 31 -- 5 files changed, 183 insertions(+), 286 deletions(-) diff --git a/Makefile.am b/Makefile.am index 351ade3fed..9af5c58115 100644 --- a/Makefile.am +++ b/Makefile.am @@ -81,7 +81,6 @@ tests_LDFLAGS = -static TESTS = tests endif -<<<<<<< HEAD JAVAROOT=src/java JAVAORG=org/bitcoin JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index 7581dca035..3be0c5a448 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -51,9 +51,11 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws N byte[][] retByteArray = secp256k1_ecdsa_signature_parse_der(byteBuff, Secp256k1Context, signature.length); byte[] sigArr = retByteArray[0]; - //DEBUG System.out.println(" Sigarr is " + new BigInteger(1, sigArr).toString(16)); + //DEBUG + System.out.println(" Sigarr is " + new BigInteger(1, sigArr).toString(16)); int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); - //DEBUG System.out.println(" RetVal is " + retVal); + //DEBUG + System.out.println(" RetVal is " + retVal); NativeSecp256k1Test.assertEquals(sigArr.length, 64, "Got bad signature length." ); @@ -65,9 +67,11 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws N retByteArray = secp256k1_ec_pubkey_parse(byteBuff, Secp256k1Context, pub.length); byte[] pubArr = retByteArray[0]; - //DEBUG System.out.println(" Pubarr is " + new BigInteger(1, pubArr).toString(16)); + //DEBUG + System.out.println(" Pubarr is " + new BigInteger(1, pubArr).toString(16)); retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); - //DEBUG System.out.println(" RetVal is " + retVal); + //DEBUG + System.out.println(" RetVal is " + retVal); NativeSecp256k1Test.assertEquals(pubArr.length, 64, "Got bad pubkey length." ); @@ -78,7 +82,9 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws N byteBuff.put(sigArr); byteBuff.put(pubArr); - return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context) == 1; + boolean result = secp256k1_ecdsa_verify(byteBuff, Secp256k1Context) == 1; + System.out.println(" Result is " + result ); + return result; } /** @@ -102,7 +108,7 @@ public static byte[] recoverCompact(byte[] data, byte[] signature,int compressed byteBuff.put(data); byteBuff.put(signature); - byte[][] retByteArray = secp256k1_ecdsa_recover_compact(byteBuff, Secp256k1Context, compressed, recID); + 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(); @@ -151,63 +157,6 @@ public static byte[] sign(byte[] data, byte[] sec) throws NativeSecp256k1Test.As return sigArr; } - /** - * libsecp256k1 Create a compact ECDSA signature. - * - * @param data Message hash, 32 bytes - * @param key Secret key, 32 bytes - * - * Return values - * @param sig byte array of signature - * @param recid recovery id - */ - - public static byte[][] signCompact(byte[] data, byte[] sec) throws NativeSecp256k1Test.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 = secp256k1_ecdsa_sign_compact(byteBuff, Secp256k1Context); - - byte[] sigArr = retByteArray[0]; - int recID = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); - int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); - - //NativeSecp256k1Test.assertEquals(sigArr.length,sigLen, "Got bad signature length." ); - - NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); - - return new byte[][] { sigArr , new byte[]{ (byte) recID} }; - } - - /** - * libsecp256k1 Pubkey Verify - returns 1 if valid, 0 if invalid - * - * @param pubkey ECDSA Public key, 33 or 65 bytes - */ - - public static boolean pubKeyVerify(byte[] pubkey) { - Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null) { - byteBuff = ByteBuffer.allocateDirect(pubkey.length); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(pubkey); - return secp256k1_ec_pubkey_verify(byteBuff,Secp256k1Context, pubkey.length) == 1; - } - /** * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid * @@ -272,37 +221,6 @@ public static synchronized void cleanup() { secp256k1_destroy_context(Secp256k1Context); } - /** - * libsecp256k1 Pubkey Decompress - Decompress a public key - * - * @param pubkey ECDSA Public key, 33 or 65 bytes - */ - - public static byte[] pubKeyDecompress(byte[] pubkey) throws NativeSecp256k1Test.AssertFailException{ - Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null) { - byteBuff = ByteBuffer.allocateDirect(pubkey.length); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(pubkey); - - byte[][] retByteArray = secp256k1_ec_pubkey_decompress(byteBuff,Secp256k1Context, pubkey.length); - - byte[] pubArr = retByteArray[0]; - int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); - int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); - - NativeSecp256k1Test.assertEquals(pubArr.length,pubLen, "Got bad pubkey length." ); - - NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); - - return pubArr; - } - /** * libsecp256k1 Secret Key Import - Import a secret key in DER format. * @@ -550,32 +468,17 @@ public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1 private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); - private static native int secp256k1_ec_pubkey_verify(ByteBuffer byteBuff, long context, int pubLen); - private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context, int compressed); - //deprecated - private static native byte[][] secp256k1_ec_pubkey_decompress(ByteBuffer byteBuff, long context, int pubLen); - 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); - //deprecated - private static native byte[][] secp256k1_ecdsa_recover_compact(ByteBuffer byteBuff, long context, int compressed, int recID); - - //deprecated - private static native byte[][] secp256k1_ecdsa_sign_compact(ByteBuffer byteBuff, long context); - - //TODO support sending back error codes - //TODO make verify() work again //TODO fix old methods to support new types and remove stale function args - //TODO add below methods + //TODO add new methods, _schnor, _ecdh, and _recovery, see include/ //TODO fix locking https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html#readLock() private static native byte[][] secp256k1_ecdsa_signature_parse_der(ByteBuffer byteBuff, long context, int inputLen); - //private static native long[] secp256k1_ecdsa_signature_parse_compact(ByteBuffer byteBuff, long context, int recovery); - private static native byte[][] secp256k1_ecdsa_signature_serialize_der(ByteBuffer byteBuff, long context); private static native byte[][] secp256k1_ecdsa_signature_serialize_compact(ByteBuffer byteBuff, long context); @@ -586,5 +489,4 @@ public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1 private static native long secp256k1_ecdsa_pubkey_combine(ByteBuffer byteBuff, long context, int keys); - //private static native byte[][] secp256k1_ecdsa_recover_compact(ByteBuffer byteBuff, long context, int compressed, int recID); } diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index bd93416fb7..72aaa5e7d7 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -7,143 +7,189 @@ public class NativeSecp256k1Test { - public static void main(String[] args) throws AssertFailException{ - - System.out.println("\n libsecp256k1 enabled: " + NativeSecp256k1.enabled + "\n"); - - if( NativeSecp256k1.enabled ) { + public static void testVerifyPos() throws AssertFailException{ boolean result = false; - //byte[] resultbytes = null; - - //Case 1 - //byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" - //byte[] sec = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); - - //resultbytes = NativeSecp256k1.sign( data, sec ); - //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); - //assertEquals( result, true , "Case 1"); - - //Case 1 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 , "Case 1"); + assertEquals( result, true , "testVerifyPos"); + } - //Case 2 - data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" - sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); - pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + 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); - assertEquals( result, false , "Case 2"); - - //Case 3 - pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); - result = NativeSecp256k1.pubKeyVerify( pub ); - assertEquals( result, true , "Case 3"); - - //Case 4 - pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C41".toLowerCase()); - result = NativeSecp256k1.pubKeyVerify( pub ); - assertEquals( result, false , "Case 4"); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testVerifyNeg"); + } - //Case 5 + public static void testSecKeyVerifyPos() throws AssertFailException{ + boolean result = false; byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + result = NativeSecp256k1.secKeyVerify( sec ); - assertEquals( result, true , "Case 5"); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, true , "testSecKeyVerifyPos"); + } + + public static void testSecKeyVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); - //Case 6 - sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); result = NativeSecp256k1.secKeyVerify( sec ); - assertEquals( result, false , "Case 6"); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testSecKeyVerifyPos"); + } - //Case 7 - sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + public static void testPubKeyCreatePos() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); byte[] resultArr = NativeSecp256k1.computePubkey( sec , 0); String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "Case 7"); + } - resultArr = NativeSecp256k1.computePubkey( sec , 1); - pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( pubkeyString, "02C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 7 Compressed"); - - //Case 8 - FAILING - sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + public static void testPubKeyCreateNeg() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); - resultArr = NativeSecp256k1.computePubkey( sec , 0); - pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( pubkeyString, "" , "Case 8"); + byte[] resultArr = NativeSecp256k1.computePubkey( sec , 0); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString, "" , "Case 8"); + } - resultArr = NativeSecp256k1.computePubkey( sec , 1); - pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( pubkeyString, "" , "Case 8 Compressed"); + public static void testSignPos() throws AssertFailException{ - //Case 9 - data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" - sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); - resultArr = NativeSecp256k1.sign(data, sec); + byte[] resultArr = NativeSecp256k1.sign(data, sec); String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "Case 9"); + } - //Case 10 - FAILING - data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" - sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + 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()); - resultArr = NativeSecp256k1.sign(data, sec); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString, "" , "Case 10"); + } - //Case 11 - pub = BaseEncoding.base16().lowerCase().decode("020A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE5".toLowerCase()); - - resultArr = NativeSecp256k1.pubKeyDecompress( pub ); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40" , "Case 11"); - - //Case 12 - sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + public static void testPrivKeyExportComp() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); - resultArr = NativeSecp256k1.privKeyExport( sec , 1); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + byte[] resultArr = NativeSecp256k1.privKeyExport( sec , 1); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "3081D3020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A08185308182020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704210279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A12403220002C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 12"); - //Case 13 - sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + } - resultArr = NativeSecp256k1.privKeyExport( sec , 0); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + 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"); - //Case 14 - sec = BaseEncoding.base16().lowerCase().decode("3081D3020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A08185308182020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704210279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A12403220002C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D".toLowerCase()); + } - resultArr = NativeSecp256k1.secKeyImport( sec ); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + public static void testSecKeyImportPos() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("3081D3020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A08185308182020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704210279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A12403220002C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D".toLowerCase()); - assertEquals( sigString , "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530" , "Case 14"); + byte[] resultArr = NativeSecp256k1.secKeyImport( sec ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - //Case 15 - sec = BaseEncoding.base16().lowerCase().decode("30820113020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A081A53081A2020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704410479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A14403420004C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6".toLowerCase()); + assertEquals( sigString , "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530" , "testSecKeyImport"); + } - resultArr = NativeSecp256k1.secKeyImport( sec ); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530" , "Case 15"); + public static void testSecKeyImportPos2() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("30820113020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A081A53081A2020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704410479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A14403420004C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6".toLowerCase()); - //Case 16 - data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" - sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] resultArr = NativeSecp256k1.secKeyImport( sec ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530" , "testSecKeyImport2"); + } + + 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"); + } + + 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"); + } + + 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"); + } + + 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"); + } + + 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 main(String[] args) throws AssertFailException{ + + System.out.println("\n libsecp256k1 enabled: " + NativeSecp256k1.enabled + "\n"); + + if( NativeSecp256k1.enabled ) { + + //Test verify() success/fail + testVerifyPos(); + testVerifyNeg(); + + //Test secKeyVerify() success/fail + testSecKeyVerifyPos(); + testSecKeyVerifyNeg(); + + //Test computePubkey() success/fail + //testPubKeyCreatePos(); // TODO Update API + //testPubKeyCreatePos(); // TODO Update API + + //Test sign() success/fail + //testSignPos(); //TODO update API + //testSignNeg(); //TODO update API + + //Test privKeyExport() compressed/uncomp + //testPrivKeyExportComp() //TODO update API + //testPrivKeyExportUncomp() //TODO update API - byte[][] resultByteArr = NativeSecp256k1.signCompact( data , sec ); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultByteArr[0]); - String idString = javax.xml.bind.DatatypeConverter.printHexBinary(resultByteArr[1]); - assertEquals( sigString , "A33C093C80B84CA1AFBC8974EE3C42FC1CBC966CAE66612593CD1E44646BABFF00CB69703B98B0103AE22C7F9CCADD8DD98F9505BE7A66B1AE459576E930C4F6" , "Case 16 assert 1"); - assertEquals( idString , "01" , "Case 16 assert 2"); + //Test secKeyImport()/2 + testSecKeyImportPos(); + testSecKeyImportPos2(); + /* 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()); @@ -157,45 +203,25 @@ public static void main(String[] args) throws AssertFailException{ resultArr = NativeSecp256k1.recoverCompact( data , sig , 1, recid ); sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( sigString , "02C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 18"); + */ - //Case 18 - sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); - data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + //Test privKeyTweakAdd() 1 + testPrivKeyTweakAdd_1(); - resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data ); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "Case 18"); - - //Case 19 - sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); - data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" - - resultArr = NativeSecp256k1.privKeyTweakMul( sec , data ); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "Case 19"); - - //Case 20 - pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); - data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + //Test privKeyTweakMul() 2 + testPrivKeyTweakMul_1(); - resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data ); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "Case 20"); - - //Case 21 - pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); - data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + //Test privKeyTweakAdd() 3 + //TODO FIX test testPrivKeyTweakAdd_2(); - resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data ); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "Case 21"); + //Test privKeyTweakMul() 4 + //TODO FIX test testPrivKeyTweakMul_2(); - //Case 22 - byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random" - result = NativeSecp256k1.randomize(seed); - assertEquals( result, true, "Case 22"); + //Test randomize() + testRandomize(); NativeSecp256k1.cleanup(); + System.out.println(" All tests passed." ); } diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 793526a0d4..e8340999ed 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -54,12 +54,23 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - const secp256k1_ecdsa_signature_t *sig = { (unsigned char*) (data + 32) }; - const secp256k1_pubkey_t *pub = { (unsigned char*) (data + 64 + 32) }; + const secp256k1_ecdsa_signature_t *sig = { (secp256k1_ecdsa_signature_t*) (data + 32) }; + const secp256k1_pubkey_t *pub = { (secp256k1_pubkey_t*) (data + 64 + 32) }; + + 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; - return secp256k1_ecdsa_verify(ctx, data, sig, pub); + int result = secp256k1_ecdsa_verify(ctx, data, sig, pub); + printf("\nResult: %d", result); + printf("\n"); + return result; } JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign @@ -109,17 +120,6 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1v return secp256k1_ec_seckey_verify(ctx, secKey); } -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint pubLen) -{ - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; - unsigned char* pubKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - - (void)classObject; - - return secp256k1_ec_pubkey_verify(ctx, pubKey, pubLen); -} - JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint compressed) { @@ -156,6 +156,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pub } +/* JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1decompress (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint pubLen) { @@ -192,7 +193,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p (void)classObject; return retArray; -} +}*/ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1export @@ -271,7 +272,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p } -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact +/*JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; @@ -306,7 +307,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa (void)classObject; return retArray; -} +}*/ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1recover_1compact @@ -517,7 +518,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1compact (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint recovery) { - (void)classObject; + (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)recovery; return 0; } diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index 8c38abbef8..6a5ae165bd 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -95,14 +95,6 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify (JNIEnv *, jclass, jobject, jlong); -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ec_pubkey_verify - * Signature: (Ljava/nio/ByteBuffer;JI)I - */ -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1verify - (JNIEnv *, jclass, jobject, jlong, jint); - /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ec_pubkey_create @@ -111,13 +103,6 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1v JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create (JNIEnv *, jclass, jobject, jlong, jint); -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ec_pubkey_decompress - * Signature: (Ljava/nio/ByteBuffer;JI)[[B - */ -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1decompress - (JNIEnv *, jclass, jobject, jlong, jint); /* * Class: org_bitcoin_NativeSecp256k1 @@ -135,22 +120,6 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1import (JNIEnv *, jclass, jobject, jlong, jint); -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdsa_recover_compact - * Signature: (Ljava/nio/ByteBuffer;JII)[[B - */ -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1recover_1compact - (JNIEnv *, jclass, jobject, jlong, jint, jint); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdsa_sign_compact - * Signature: (Ljava/nio/ByteBuffer;J)[[B - */ -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact - (JNIEnv *, jclass, jobject, jlong); - /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_signature_parse_der From 8045c2fbc8b60e2068c2039350f86abd14d9550b Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Sat, 19 Sep 2015 18:15:38 -0500 Subject: [PATCH 21/24] Add ReadWriteLock to library methods, separate static context from other classes and utils, add comments --- Makefile.am | 7 +- src/java/org/bitcoin/NativeSecp256k1.java | 229 ++++++++++++------ src/java/org/bitcoin/NativeSecp256k1Test.java | 87 ++++--- src/java/org/bitcoin/NativeSecp256k1Util.java | 29 +++ src/java/org/bitcoin/Secp256k1Context.java | 34 +++ src/java/org_bitcoin_NativeSecp256k1.c | 9 - src/java/org_bitcoin_NativeSecp256k1.h | 9 - src/java/org_bitcoin_Secp256k1Context.c | 14 ++ src/java/org_bitcoin_Secp256k1Context.h | 21 ++ 9 files changed, 313 insertions(+), 126 deletions(-) create mode 100644 src/java/org/bitcoin/NativeSecp256k1Util.java create mode 100644 src/java/org/bitcoin/Secp256k1Context.java create mode 100644 src/java/org_bitcoin_Secp256k1Context.c create mode 100644 src/java/org_bitcoin_Secp256k1Context.h diff --git a/Makefile.am b/Makefile.am index 9af5c58115..e9df537cd8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,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 @@ -54,7 +55,7 @@ libsecp256k1_la_SOURCES = src/secp256k1.c libsecp256k1_la_CPPFLAGS = -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 +libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c libsecp256k1_jni_la_CPPFLAGS = $(JNI_INCLUDES) noinst_PROGRAMS = @@ -87,7 +88,9 @@ 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)/NativeSecp256k1Test.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \ + $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java if USE_JNI diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index 3be0c5a448..693fd38292 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -5,28 +5,24 @@ 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. * You can find an example library that can be used for this at * https://github.com/sipa/secp256k1 */ +//TODO fix old methods to support new types and remove stale function args +//TODO add new methods from, _schnor, _ecdh, and _recovery includes +//TODO rebase +//TODO fixup of travis errors https://travis-ci.org/bitcoin/secp256k1/jobs/79025947 public class NativeSecp256k1 { - public static final boolean enabled; - public static final long Secp256k1Context; //ref to pointer to context obj - static { - boolean isEnabled = true; - long contextRef = -1; - try { - System.loadLibrary("secp256k1"); - contextRef = secp256k1_init_context(); - } catch (UnsatisfiedLinkError e) { - isEnabled = false; - } - enabled = isEnabled; - Secp256k1Context = contextRef; - } - + + private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private static final Lock r = rwl.readLock(); + private static final Lock w = rwl.writeLock(); private static ThreadLocal nativeECDSABuffer = new ThreadLocal(); /** * Verifies the given secp256k1 signature in native code. @@ -36,7 +32,7 @@ public class NativeSecp256k1 { * @param signature The signature * @param pub The public key which did the signing */ - public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws NativeSecp256k1Test.AssertFailException{ + 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(); @@ -48,43 +44,55 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws N byteBuff.rewind(); byteBuff.put(signature); - byte[][] retByteArray = secp256k1_ecdsa_signature_parse_der(byteBuff, Secp256k1Context, signature.length); + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_ecdsa_signature_parse_der(byteBuff, Secp256k1Context.getContext(), signature.length); + } finally { + r.unlock(); + } byte[] sigArr = retByteArray[0]; - //DEBUG - System.out.println(" Sigarr is " + new BigInteger(1, sigArr).toString(16)); + //DEBUG System.out.println(" Sigarr is " + new BigInteger(1, sigArr).toString(16)); int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); - //DEBUG - System.out.println(" RetVal is " + retVal); + //DEBUG System.out.println(" RetVal is " + retVal); - NativeSecp256k1Test.assertEquals(sigArr.length, 64, "Got bad signature length." ); + assertEquals(sigArr.length, 64, "Got bad signature length." ); - NativeSecp256k1Test.assertEquals(retVal, 1, "Failed return value check."); + assertEquals(retVal, 1, "Failed return value check."); byteBuff.rewind(); byteBuff.put(pub); - retByteArray = secp256k1_ec_pubkey_parse(byteBuff, Secp256k1Context, pub.length); + r.lock(); + try { + retByteArray = secp256k1_ec_pubkey_parse(byteBuff, Secp256k1Context.getContext(), pub.length); + } finally { + r.unlock(); + } byte[] pubArr = retByteArray[0]; - //DEBUG - System.out.println(" Pubarr is " + new BigInteger(1, pubArr).toString(16)); + //DEBUG System.out.println(" Pubarr is " + new BigInteger(1, pubArr).toString(16)); retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); - //DEBUG - System.out.println(" RetVal is " + retVal); + //DEBUG System.out.println(" RetVal is " + retVal); - NativeSecp256k1Test.assertEquals(pubArr.length, 64, "Got bad pubkey length." ); + assertEquals(pubArr.length, 64, "Got bad pubkey length." ); - NativeSecp256k1Test.assertEquals(retVal, 1, "Failed return value check."); + assertEquals(retVal, 1, "Failed return value check."); byteBuff.rewind(); byteBuff.put(data); byteBuff.put(sigArr); byteBuff.put(pubArr); - boolean result = secp256k1_ecdsa_verify(byteBuff, Secp256k1Context) == 1; - System.out.println(" Result is " + result ); - return result; + r.lock(); + try { + boolean result = secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext()) == 1; + System.out.println(" Result is " + result ); + return result; + } finally { + r.unlock(); + } } /** @@ -95,7 +103,7 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws N * @param compressed whether to recover a compressed pubkey * @param pub The public key which did the signing */ - public static byte[] recoverCompact(byte[] data, byte[] signature,int compressed, int recID) throws NativeSecp256k1Test.AssertFailException{ + 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(); @@ -114,9 +122,9 @@ public static byte[] recoverCompact(byte[] data, byte[] signature,int compressed int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); - NativeSecp256k1Test.assertEquals(pubArr.length,pubLen, "Got bad signature length." ); + assertEquals(pubArr.length,pubLen, "Got bad signature length." ); - NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,retVal, "Failed return value check."); return pubArr; } @@ -131,7 +139,7 @@ public static byte[] recoverCompact(byte[] data, byte[] signature,int compressed * @param sig byte array of signature */ - public static byte[] sign(byte[] data, byte[] sec) throws NativeSecp256k1Test.AssertFailException{ + public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ Preconditions.checkArgument(data.length == 32 && sec.length <= 32); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -144,15 +152,22 @@ public static byte[] sign(byte[] data, byte[] sec) throws NativeSecp256k1Test.As byteBuff.put(data); byteBuff.put(sec); - byte[][] retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context); + 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(); - NativeSecp256k1Test.assertEquals(sigArr.length,sigLen, "Got bad signature length." ); + assertEquals(sigArr.length,sigLen, "Got bad signature length." ); - NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,retVal, "Failed return value check."); return sigArr; } @@ -174,7 +189,13 @@ public static boolean secKeyVerify(byte[] seckey) { } byteBuff.rewind(); byteBuff.put(seckey); - return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context) == 1; + + r.lock(); + try { + return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1; + } finally { + r.unlock(); + } } @@ -188,7 +209,7 @@ public static boolean secKeyVerify(byte[] seckey) { * @param pubkey ECDSA Public key, 33 or 65 bytes */ - public static byte[] computePubkey(byte[] seckey, int compressed) throws NativeSecp256k1Test.AssertFailException{ + public static byte[] computePubkey(byte[] seckey, int compressed) throws AssertFailException{ Preconditions.checkArgument(seckey.length == 32); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -200,15 +221,22 @@ public static byte[] computePubkey(byte[] seckey, int compressed) throws NativeS byteBuff.rewind(); byteBuff.put(seckey); - byte[][] retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context, compressed); + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext(), compressed); + } 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(); - NativeSecp256k1Test.assertEquals(pubArr.length,pubLen, "Got bad pubkey length." ); + assertEquals(pubArr.length,pubLen, "Got bad pubkey length." ); - NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,retVal, "Failed return value check."); return pubArr; } @@ -218,7 +246,12 @@ public static byte[] computePubkey(byte[] seckey, int compressed) throws NativeS * This should be called at the end of the program for proper cleanup of the context. */ public static synchronized void cleanup() { - secp256k1_destroy_context(Secp256k1Context); + w.lock(); + try { + secp256k1_destroy_context(Secp256k1Context.getContext()); + } finally { + w.unlock(); + } } /** @@ -227,7 +260,7 @@ public static synchronized void cleanup() { * @param seckey DER Sec key * @param compressed Compressed format */ - public static byte[] secKeyImport(byte[] seckey) throws NativeSecp256k1Test.AssertFailException{ + public static byte[] secKeyImport(byte[] seckey) throws AssertFailException{ ByteBuffer byteBuff = nativeECDSABuffer.get(); if (byteBuff == null) { @@ -238,16 +271,23 @@ public static byte[] secKeyImport(byte[] seckey) throws NativeSecp256k1Test.Asse byteBuff.rewind(); byteBuff.put(seckey); - byte[][] retByteArray = secp256k1_ec_privkey_import(byteBuff,Secp256k1Context, seckey.length); + 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(); - NativeSecp256k1Test.assertEquals(privArr.length,privLen, "Got bad pubkey length." ); + assertEquals(privArr.length,privLen, "Got bad pubkey length." ); - NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,retVal, "Failed return value check."); return privArr; } @@ -258,7 +298,7 @@ public static byte[] secKeyImport(byte[] seckey) throws NativeSecp256k1Test.Asse * @param seckey ECDSA Sec key, 33 or 65 bytes * @param compressed Compressed format */ - public static byte[] privKeyExport(byte[] privkey, int compressed) throws NativeSecp256k1Test.AssertFailException{ + public static byte[] privKeyExport(byte[] privkey, int compressed) throws AssertFailException{ Preconditions.checkArgument(privkey.length == 32 && (compressed == 0 || compressed == 1) ); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -270,22 +310,31 @@ public static byte[] privKeyExport(byte[] privkey, int compressed) throws Native byteBuff.rewind(); byteBuff.put(privkey); - byte[][] retByteArray = secp256k1_ec_privkey_export(byteBuff,Secp256k1Context, privkey.length, compressed ); + 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(); - NativeSecp256k1Test.assertEquals(privArr.length, compressed == 1? 214 : 279, "Got bad pubkey length." ); + assertEquals(privArr.length, compressed == 1? 214 : 279, "Got bad pubkey length." ); - NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,retVal, "Failed return value check."); return privArr; } public static long cloneContext() { - return secp256k1_ctx_clone(Secp256k1Context); + r.lock(); + try { + return secp256k1_ctx_clone(Secp256k1Context.getContext()); + } finally { r.unlock(); } } /** @@ -294,7 +343,7 @@ public static long cloneContext() { * @param tweak some bytes to tweak with * @param seckey 32-byte seckey */ - public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws NativeSecp256k1Test.AssertFailException{ + public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{ Preconditions.checkArgument(privkey.length == 32); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -307,16 +356,22 @@ public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws Native byteBuff.put(privkey); byteBuff.put(tweak); - byte[][] retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context); + 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(); - NativeSecp256k1Test.assertEquals(privArr.length, privLen, "Got bad pubkey length." ); + assertEquals(privArr.length, privLen, "Got bad pubkey length." ); - NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,retVal, "Failed return value check."); return privArr; } @@ -327,7 +382,7 @@ public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws Native * @param tweak some bytes to tweak with * @param seckey 32-byte seckey */ - public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws NativeSecp256k1Test.AssertFailException{ + public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{ Preconditions.checkArgument(privkey.length == 32); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -340,16 +395,22 @@ public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws Native byteBuff.put(privkey); byteBuff.put(tweak); - byte[][] retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context); + 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(); - NativeSecp256k1Test.assertEquals(privArr.length, privLen, "Got bad pubkey length." ); + assertEquals(privArr.length, privLen, "Got bad pubkey length." ); - NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,retVal, "Failed return value check."); return privArr; } @@ -360,7 +421,7 @@ public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws Native * @param tweak some bytes to tweak with * @param pubkey 32-byte seckey */ - public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws NativeSecp256k1Test.AssertFailException{ + public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{ Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -373,16 +434,22 @@ public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws NativeSe byteBuff.put(pubkey); byteBuff.put(tweak); - byte[][] retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context, pubkey.length); + 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(); - NativeSecp256k1Test.assertEquals(pubArr.length, pubLen, "Got bad pubkey length." ); + assertEquals(pubArr.length, pubLen, "Got bad pubkey length." ); - NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,retVal, "Failed return value check."); return pubArr; } @@ -393,7 +460,7 @@ public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws NativeSe * @param tweak some bytes to tweak with * @param pubkey 32-byte seckey */ - public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws NativeSecp256k1Test.AssertFailException{ + public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{ Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -406,16 +473,22 @@ public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws NativeSe byteBuff.put(pubkey); byteBuff.put(tweak); - byte[][] retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context, pubkey.length); + 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(); - NativeSecp256k1Test.assertEquals(pubArr.length, pubLen, "Got bad pubkey length." ); + assertEquals(pubArr.length, pubLen, "Got bad pubkey length." ); - NativeSecp256k1Test.assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,retVal, "Failed return value check."); return pubArr; } @@ -425,7 +498,7 @@ public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws NativeSe * * @param seed some random bytes to seed with */ - public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1Test.AssertFailException{ + public static synchronized boolean randomize(byte[] seed) throws AssertFailException{ Preconditions.checkArgument(seed.length == 32 || seed == null); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -437,7 +510,12 @@ public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1 byteBuff.rewind(); byteBuff.put(seed); - return secp256k1_context_randomize(byteBuff, Secp256k1Context) == 1; + w.lock(); + try { + return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1; + } finally { + w.unlock(); + } } /** @@ -446,7 +524,6 @@ public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1 * byte[signatureLength] signature, byte[pubkeyLength] pub * @returns 1 for valid signature, anything else for invalid */ - private static native long secp256k1_init_context(); private static native long secp256k1_ctx_clone(long context); @@ -474,9 +551,6 @@ public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1 private static native byte[][] secp256k1_ec_privkey_import(ByteBuffer byteBuff, long context, int privLen); - //TODO fix old methods to support new types and remove stale function args - //TODO add new methods, _schnor, _ecdh, and _recovery, see include/ - //TODO fix locking https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html#readLock() private static native byte[][] secp256k1_ecdsa_signature_parse_der(ByteBuffer byteBuff, long context, int inputLen); private static native byte[][] secp256k1_ecdsa_signature_serialize_der(ByteBuffer byteBuff, long context); @@ -488,5 +562,4 @@ public static synchronized boolean randomize(byte[] seed) throws NativeSecp256k1 private static native byte[][] secp256k1_ecdsa_pubkey_serialize(ByteBuffer byteBuff, long context); private static native long secp256k1_ecdsa_pubkey_combine(ByteBuffer byteBuff, long context, int keys); - } diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 72aaa5e7d7..1d701fbecc 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -4,10 +4,18 @@ 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 formatting for 100char wide + //TODO improve comments + /** + * 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" @@ -18,6 +26,9 @@ public static void testVerifyPos() throws AssertFailException{ 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" @@ -29,6 +40,9 @@ public static void testVerifyNeg() throws AssertFailException{ 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()); @@ -38,6 +52,9 @@ public static void testSecKeyVerifyPos() throws AssertFailException{ 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()); @@ -47,6 +64,9 @@ public static void testSecKeyVerifyNeg() throws AssertFailException{ assertEquals( result, false , "testSecKeyVerifyPos"); } + /** + * This tests public key create() for a valid secretkey + */ public static void testPubKeyCreatePos() throws AssertFailException{ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); @@ -55,6 +75,9 @@ public static void testPubKeyCreatePos() throws AssertFailException{ assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "Case 7"); } + /** + * This tests public key create() for a invalid secretkey + */ public static void testPubKeyCreateNeg() throws AssertFailException{ byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); @@ -63,6 +86,9 @@ public static void testPubKeyCreateNeg() throws AssertFailException{ assertEquals( pubkeyString, "" , "Case 8"); } + /** + * This tests sign() for a valid secretkey + */ public static void testSignPos() throws AssertFailException{ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" @@ -73,6 +99,9 @@ public static void testSignPos() throws AssertFailException{ assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "Case 9"); } + /** + * 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()); @@ -82,6 +111,9 @@ public static void testSignNeg() throws AssertFailException{ assertEquals( sigString, "" , "Case 10"); } + /** + * This tests private key export + */ public static void testPrivKeyExportComp() throws AssertFailException{ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); @@ -91,6 +123,9 @@ public static void testPrivKeyExportComp() throws AssertFailException{ } + /** + * This tests private key export + */ public static void testPrivKeyExportUncomp() throws AssertFailException{ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); @@ -100,6 +135,9 @@ public static void testPrivKeyExportUncomp() throws AssertFailException{ } + /** + * This tests private key import + */ public static void testSecKeyImportPos() throws AssertFailException { byte[] sec = BaseEncoding.base16().lowerCase().decode("3081D3020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A08185308182020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704210279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A12403220002C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D".toLowerCase()); @@ -109,6 +147,9 @@ public static void testSecKeyImportPos() throws AssertFailException { assertEquals( sigString , "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530" , "testSecKeyImport"); } + /** + * This tests private key export + */ public static void testSecKeyImportPos2() throws AssertFailException { byte[] sec = BaseEncoding.base16().lowerCase().decode("30820113020101042067E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530A081A53081A2020101302C06072A8648CE3D0101022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F300604010004010704410479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8022100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141020101A14403420004C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6".toLowerCase()); @@ -117,6 +158,9 @@ public static void testSecKeyImportPos2() throws AssertFailException { 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" @@ -126,6 +170,9 @@ public static void testPrivKeyTweakAdd_1() throws AssertFailException { 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" @@ -135,6 +182,9 @@ public static void testPrivKeyTweakMul_1() throws AssertFailException { 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" @@ -144,6 +194,9 @@ public static void testPrivKeyTweakAdd_2() throws AssertFailException { 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" @@ -153,6 +206,9 @@ public static void testPrivKeyTweakMul_2() throws AssertFailException { 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); @@ -161,9 +217,9 @@ public static void testRandomize() throws AssertFailException { public static void main(String[] args) throws AssertFailException{ - System.out.println("\n libsecp256k1 enabled: " + NativeSecp256k1.enabled + "\n"); + System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n"); - if( NativeSecp256k1.enabled ) { + if( Secp256k1Context.isEnabled() ) { //Test verify() success/fail testVerifyPos(); @@ -226,29 +282,4 @@ public static void main(String[] args) throws AssertFailException{ } } - - public static void assertEquals( int val, int val2, String message ) throws AssertFailException{ - if( val != val2 ) - throw new AssertFailException("FAIL: " + message); - } - - private 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); - } - - private 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 ); - } - } } diff --git a/src/java/org/bitcoin/NativeSecp256k1Util.java b/src/java/org/bitcoin/NativeSecp256k1Util.java new file mode 100644 index 0000000000..278dc1d108 --- /dev/null +++ b/src/java/org/bitcoin/NativeSecp256k1Util.java @@ -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 ); + } + } +} diff --git a/src/java/org/bitcoin/Secp256k1Context.java b/src/java/org/bitcoin/Secp256k1Context.java new file mode 100644 index 0000000000..d6ffa05dc4 --- /dev/null +++ b/src/java/org/bitcoin/Secp256k1Context.java @@ -0,0 +1,34 @@ +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) { + 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(); +} diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index e8340999ed..a63c6758b4 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -2,15 +2,6 @@ #include "org_bitcoin_NativeSecp256k1.h" #include "include/secp256k1.h" -JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1context - (JNIEnv* env, jclass classObject) -{ - secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - (void)classObject;(void)env; - - return (jlong)ctx; -} JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone (JNIEnv* env, jclass classObject, jlong ctx_l) diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index 6a5ae165bd..e62be81d23 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -7,14 +7,6 @@ #ifdef __cplusplus extern "C" { #endif -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_init_context - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1init_1context - (JNIEnv *, jclass); - /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ctx_clone @@ -103,7 +95,6 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1v JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create (JNIEnv *, jclass, jobject, jlong, jint); - /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ec_privkey_export diff --git a/src/java/org_bitcoin_Secp256k1Context.c b/src/java/org_bitcoin_Secp256k1Context.c new file mode 100644 index 0000000000..02bbb32b04 --- /dev/null +++ b/src/java/org_bitcoin_Secp256k1Context.c @@ -0,0 +1,14 @@ +#include +#include "org_bitcoin_Secp256k1Context.h" +#include "include/secp256k1.h" + +JNIEXPORT jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv* env, jclass classObject) +{ + secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + (void)classObject;(void)env; + + return (jlong)ctx; +} + diff --git a/src/java/org_bitcoin_Secp256k1Context.h b/src/java/org_bitcoin_Secp256k1Context.h new file mode 100644 index 0000000000..64abbc8822 --- /dev/null +++ b/src/java/org_bitcoin_Secp256k1Context.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* 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 + */ +JNIEXPORT jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif From f5dcc25ecbc6d097eb7cd4535fb65facc7b61eab Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Sat, 26 Sep 2015 03:45:42 -0500 Subject: [PATCH 22/24] Fix warnings and update API with new typenames --- src/java/org/bitcoin/NativeSecp256k1.java | 9 ++- src/java/org/bitcoin/NativeSecp256k1Test.java | 8 +-- src/java/org_bitcoin_NativeSecp256k1.c | 70 ++++++++++--------- src/java/org_bitcoin_NativeSecp256k1.h | 2 +- src/java/org_bitcoin_Secp256k1Context.c | 2 +- 5 files changed, 48 insertions(+), 43 deletions(-) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index 693fd38292..0719e837fd 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -14,8 +14,7 @@ * You can find an example library that can be used for this at * https://github.com/sipa/secp256k1 */ -//TODO fix old methods to support new types and remove stale function args -//TODO add new methods from, _schnor, _ecdh, and _recovery includes +//TODO add new methods from, _schnor, _ecdh, and _recovery includes, fix/add tests //TODO rebase //TODO fixup of travis errors https://travis-ci.org/bitcoin/secp256k1/jobs/79025947 public class NativeSecp256k1 { @@ -209,7 +208,7 @@ public static boolean secKeyVerify(byte[] seckey) { * @param pubkey ECDSA Public key, 33 or 65 bytes */ - public static byte[] computePubkey(byte[] seckey, int compressed) throws AssertFailException{ + public static byte[] computePubkey(byte[] seckey) throws AssertFailException{ Preconditions.checkArgument(seckey.length == 32); ByteBuffer byteBuff = nativeECDSABuffer.get(); @@ -225,7 +224,7 @@ public static byte[] computePubkey(byte[] seckey, int compressed) throws AssertF r.lock(); try { - retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext(), compressed); + retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext()); } finally { r.unlock(); } @@ -545,7 +544,7 @@ public static synchronized boolean randomize(byte[] seed) throws AssertFailExcep private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); - private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context, int compressed); + 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); diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 1d701fbecc..4ed2eac550 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -70,7 +70,7 @@ public static void testSecKeyVerifyNeg() throws AssertFailException{ public static void testPubKeyCreatePos() throws AssertFailException{ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); - byte[] resultArr = NativeSecp256k1.computePubkey( sec , 0); + byte[] resultArr = NativeSecp256k1.computePubkey( sec); String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "Case 7"); } @@ -81,7 +81,7 @@ public static void testPubKeyCreatePos() throws AssertFailException{ public static void testPubKeyCreateNeg() throws AssertFailException{ byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); - byte[] resultArr = NativeSecp256k1.computePubkey( sec , 0); + byte[] resultArr = NativeSecp256k1.computePubkey( sec); String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); assertEquals( pubkeyString, "" , "Case 8"); } @@ -238,8 +238,8 @@ public static void main(String[] args) throws AssertFailException{ //testSignNeg(); //TODO update API //Test privKeyExport() compressed/uncomp - //testPrivKeyExportComp() //TODO update API - //testPrivKeyExportUncomp() //TODO update API + testPrivKeyExportComp(); + testPrivKeyExportUncomp(); //Test secKeyImport()/2 testSecKeyImportPos(); diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index a63c6758b4..189936ddea 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -6,7 +6,7 @@ JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone (JNIEnv* env, jclass classObject, jlong ctx_l) { - const secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + const secp256k1_context *ctx = (secp256k1_context*)ctx_l; jlong ctx_clone_l = (jlong) secp256k1_context_clone(ctx); @@ -19,7 +19,7 @@ JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + secp256k1_context *ctx = (secp256k1_context*)ctx_l; const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); @@ -32,7 +32,7 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1rand JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context (JNIEnv* env, jclass classObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + secp256k1_context *ctx = (secp256k1_context*)ctx_l; secp256k1_context_destroy(ctx); @@ -42,12 +42,14 @@ JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1cont JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + secp256k1_context *ctx = (secp256k1_context*)ctx_l; + int result; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - const secp256k1_ecdsa_signature_t *sig = { (secp256k1_ecdsa_signature_t*) (data + 32) }; - const secp256k1_pubkey_t *pub = { (secp256k1_pubkey_t*) (data + 64 + 32) }; + const secp256k1_ecdsa_signature *sig = { (secp256k1_ecdsa_signature*) (data + 32) }; + const secp256k1_pubkey *pub = { (secp256k1_pubkey*) (data + 64 + 32) }; + /*TODO remove debug printf("\nData: "); int i; for( i = 0; i < 32; i++) printf("%x", data[i]); @@ -55,10 +57,13 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify 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; - int result = secp256k1_ecdsa_verify(ctx, data, sig, pub); + + result = secp256k1_ecdsa_verify(ctx, sig, data, pub); + printf("\nResult: %d", result); printf("\n"); return result; @@ -67,7 +72,7 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)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); @@ -75,10 +80,10 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa jbyteArray sigArray, intsByteArray; unsigned char intsarray[2]; - unsigned char sig[72]; + secp256k1_ecdsa_signature sig[72]; int siglen = 72; - int ret = secp256k1_ecdsa_sign(ctx, data, sig, secKey, NULL, NULL ); + int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL ); intsarray[0] = siglen; intsarray[1] = ret; @@ -103,7 +108,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + secp256k1_context *ctx = (secp256k1_context*)ctx_l; unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); (void)classObject; @@ -111,13 +116,13 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1v return secp256k1_ec_seckey_verify(ctx, secKey); } -JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint compressed) +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + secp256k1_context *ctx = (secp256k1_context*)ctx_l; unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - unsigned char pubkey[65]; + secp256k1_pubkey pubkey[65]; int pubkeyLen = 65; jobjectArray retArray; @@ -151,7 +156,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pub JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1decompress (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint pubLen) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + secp256k1_context *ctx = (secp256k1_context*)ctx_l; unsigned char* pubkey = (unsigned char*) malloc(sizeof(unsigned char)*65); @@ -190,7 +195,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p JNIEXPORT 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_t *ctx = (secp256k1_context_t*)ctx_l; + secp256k1_context *ctx = (secp256k1_context*)ctx_l; const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); @@ -203,7 +208,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p for(i = 0; i < privLen; i++) privkey[i] = secKey[i]; - ret = secp256k1_ec_privkey_export(ctx, secKey, privkey ,&privLen, compressed); + ret = secp256k1_ec_privkey_export(ctx, privkey , (size_t*)&privLen, secKey, compressed); intsarray[0] = privLen; intsarray[1] = ret; @@ -228,7 +233,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1import (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint privLen) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + secp256k1_context *ctx = (secp256k1_context*)ctx_l; const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); @@ -266,7 +271,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p /*JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)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); @@ -301,10 +306,11 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p }*/ +/* JNIEXPORT 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_t *ctx = (secp256k1_context_t*)ctx_l; + 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); @@ -335,12 +341,12 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa (void)classObject; return retArray; -} +}*/ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)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); @@ -375,7 +381,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privk JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - secp256k1_context_t *ctx = (secp256k1_context_t*)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); @@ -410,8 +416,8 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privk JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; - unsigned char* pubkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + secp256k1_context *ctx = (secp256k1_context*)ctx_l; + secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* tweak = (unsigned char*) (pubkey + publen); jobjectArray retArray; @@ -443,8 +449,8 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubke JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) { - secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; - unsigned char* pubkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + secp256k1_context *ctx = (secp256k1_context*)ctx_l; + secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* tweak = (unsigned char*) (pubkey + publen); jobjectArray retArray; @@ -476,9 +482,9 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubke JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1der (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint inputlen) { - const secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + const secp256k1_context *ctx = (secp256k1_context*)ctx_l; - secp256k1_ecdsa_signature_t sig; + secp256k1_ecdsa_signature sig; unsigned char* input = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); jobjectArray retArray; @@ -517,9 +523,9 @@ JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1 JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint inputlen) { - const secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l; + const secp256k1_context *ctx = (secp256k1_context*)ctx_l; - secp256k1_pubkey_t pubkey; + secp256k1_pubkey pubkey; unsigned char* input = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); jobjectArray retArray; diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index e62be81d23..ee4857803d 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -93,7 +93,7 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1v * Signature: (Ljava/nio/ByteBuffer;JI)[[B */ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create - (JNIEnv *, jclass, jobject, jlong, jint); + (JNIEnv *, jclass, jobject, jlong); /* * Class: org_bitcoin_NativeSecp256k1 diff --git a/src/java/org_bitcoin_Secp256k1Context.c b/src/java/org_bitcoin_Secp256k1Context.c index 02bbb32b04..f9263b7f31 100644 --- a/src/java/org_bitcoin_Secp256k1Context.c +++ b/src/java/org_bitcoin_Secp256k1Context.c @@ -5,7 +5,7 @@ JNIEXPORT jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context (JNIEnv* env, jclass classObject) { - secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); (void)classObject;(void)env; From 77717bd49d54233dd748a9a72471085023c9e8f0 Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Fri, 2 Oct 2015 23:51:08 -0500 Subject: [PATCH 23/24] Add travis fix for locating secp256k1 libs --- Makefile.am | 2 +- src/java/org/bitcoin/Secp256k1Context.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 4b228385cd..5defb17759 100644 --- a/Makefile.am +++ b/Makefile.am @@ -107,7 +107,7 @@ $(JAVA_GUAVA): if USE_TESTS check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java - $(AM_V_at)java -Djava.library.path=".libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test + $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test endif endif diff --git a/src/java/org/bitcoin/Secp256k1Context.java b/src/java/org/bitcoin/Secp256k1Context.java index d6ffa05dc4..53dcd54d91 100644 --- a/src/java/org/bitcoin/Secp256k1Context.java +++ b/src/java/org/bitcoin/Secp256k1Context.java @@ -15,6 +15,7 @@ public class Secp256k1Context { System.loadLibrary("secp256k1"); contextRef = secp256k1_init_context(); } catch (UnsatisfiedLinkError e) { + System.out.println("UnsatisfiedLinkError: " + e.toString()); isEnabled = false; } enabled = isEnabled; From b6dc95844a3ef95d6d3eb14c7c19329ffb8dab55 Mon Sep 17 00:00:00 2001 From: Faiz Khan Date: Sat, 5 Dec 2015 12:18:53 -0600 Subject: [PATCH 24/24] Update API to latest and clean up usage to use serialize/parse() methods for loading native sig/pubkey objects. Add TODO notes and stubs for rest of API addtiions --- src/java/org/bitcoin/NativeSecp256k1.java | 298 ++++++++++++++---- src/java/org/bitcoin/NativeSecp256k1Test.java | 98 ++++-- src/java/org_bitcoin_NativeSecp256k1.c | 219 +++++-------- src/java/org_bitcoin_NativeSecp256k1.h | 26 +- 4 files changed, 384 insertions(+), 257 deletions(-) diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index 0719e837fd..b480224262 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -14,9 +14,7 @@ * You can find an example library that can be used for this at * https://github.com/sipa/secp256k1 */ -//TODO add new methods from, _schnor, _ecdh, and _recovery includes, fix/add tests -//TODO rebase -//TODO fixup of travis errors https://travis-ci.org/bitcoin/secp256k1/jobs/79025947 +//TODO fixup of travis test errors https://travis-ci.org/bitcoin/secp256k1/jobs/79025947 public class NativeSecp256k1 { private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); @@ -41,53 +39,15 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws A nativeECDSABuffer.set(byteBuff); } byteBuff.rewind(); + byteBuff.put(data); byteBuff.put(signature); - - byte[][] retByteArray; - r.lock(); - try { - retByteArray = secp256k1_ecdsa_signature_parse_der(byteBuff, Secp256k1Context.getContext(), signature.length); - } finally { - r.unlock(); - } - - byte[] sigArr = retByteArray[0]; - //DEBUG System.out.println(" Sigarr is " + new BigInteger(1, sigArr).toString(16)); - int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); - //DEBUG System.out.println(" RetVal is " + retVal); - - assertEquals(sigArr.length, 64, "Got bad signature length." ); - - assertEquals(retVal, 1, "Failed return value check."); - - byteBuff.rewind(); byteBuff.put(pub); - r.lock(); - try { - retByteArray = secp256k1_ec_pubkey_parse(byteBuff, Secp256k1Context.getContext(), pub.length); - } finally { - r.unlock(); - } - - byte[] pubArr = retByteArray[0]; - //DEBUG System.out.println(" Pubarr is " + new BigInteger(1, pubArr).toString(16)); - retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); - //DEBUG System.out.println(" RetVal is " + retVal); - - assertEquals(pubArr.length, 64, "Got bad pubkey length." ); - - assertEquals(retVal, 1, "Failed return value check."); - - byteBuff.rewind(); - byteBuff.put(data); - byteBuff.put(sigArr); - byteBuff.put(pubArr); + byte[][] retByteArray; r.lock(); try { - boolean result = secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext()) == 1; - System.out.println(" Result is " + result ); + boolean result = secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; return result; } finally { r.unlock(); @@ -102,6 +62,7 @@ public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws A * @param compressed whether to recover a compressed pubkey * @param pub The public key which did the signing */ + //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)); @@ -123,7 +84,7 @@ public static byte[] recoverCompact(byte[] data, byte[] signature,int compressed assertEquals(pubArr.length,pubLen, "Got bad signature length." ); - assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,1, "Failed return value check."); return pubArr; } @@ -166,7 +127,7 @@ public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ assertEquals(sigArr.length,sigLen, "Got bad signature length." ); - assertEquals(retVal,retVal, "Failed return value check."); + if( retVal == 0 ) sigArr = new byte[0]; return sigArr; } @@ -208,6 +169,7 @@ public static boolean secKeyVerify(byte[] seckey) { * @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); @@ -235,7 +197,7 @@ public static byte[] computePubkey(byte[] seckey) throws AssertFailException{ assertEquals(pubArr.length,pubLen, "Got bad pubkey length." ); - assertEquals(retVal,retVal, "Failed return value check."); + if( retVal == 0 ) pubArr = new byte[0]; return pubArr; } @@ -286,7 +248,7 @@ public static byte[] secKeyImport(byte[] seckey) throws AssertFailException{ assertEquals(privArr.length,privLen, "Got bad pubkey length." ); - assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,1, "Failed return value check."); return privArr; } @@ -324,7 +286,7 @@ public static byte[] privKeyExport(byte[] privkey, int compressed) throws Assert assertEquals(privArr.length, compressed == 1? 214 : 279, "Got bad pubkey length." ); - assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,1, "Failed return value check."); return privArr; } @@ -370,7 +332,7 @@ public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws Assert assertEquals(privArr.length, privLen, "Got bad pubkey length." ); - assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,1, "Failed return value check."); return privArr; } @@ -409,7 +371,7 @@ public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws Assert assertEquals(privArr.length, privLen, "Got bad pubkey length." ); - assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,1, "Failed return value check."); return privArr; } @@ -448,7 +410,7 @@ public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFa assertEquals(pubArr.length, pubLen, "Got bad pubkey length." ); - assertEquals(retVal,retVal, "Failed return value check."); + assertEquals(retVal,1, "Failed return value check."); return pubArr; } @@ -487,15 +449,227 @@ public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFa assertEquals(pubArr.length, pubLen, "Got bad pubkey length." ); - assertEquals(retVal,retVal, "Failed return value check."); + 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 = 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 + */ + //TODO createECDHSecret() + public static byte[] createECDHSecret(byte[] pubkey, byte[] msg32) throws AssertFailException{ +/* + Preconditions.checkArgument(msg32.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + 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 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 = 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 = 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 = 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 some random bytes to seed with + * @param seed 32-byte random seed */ public static synchronized boolean randomize(byte[] seed) throws AssertFailException{ Preconditions.checkArgument(seed.length == 32 || seed == null); @@ -517,13 +691,6 @@ public static synchronized boolean randomize(byte[] seed) throws AssertFailExcep } } - /** - * @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 - */ - private static native long secp256k1_ctx_clone(long context); private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context); @@ -538,7 +705,7 @@ public static synchronized boolean randomize(byte[] seed) throws AssertFailExcep private static native void secp256k1_destroy_context(long context); - private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, 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); @@ -552,13 +719,10 @@ public static synchronized boolean randomize(byte[] seed) throws AssertFailExcep private static native byte[][] secp256k1_ecdsa_signature_parse_der(ByteBuffer byteBuff, long context, int inputLen); - private static native byte[][] secp256k1_ecdsa_signature_serialize_der(ByteBuffer byteBuff, long context); - - private static native byte[][] secp256k1_ecdsa_signature_serialize_compact(ByteBuffer byteBuff, long context); + //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 byte[][] secp256k1_ecdsa_pubkey_serialize(ByteBuffer byteBuff, long context); - private static native long secp256k1_ecdsa_pubkey_combine(ByteBuffer byteBuff, long context, int keys); } diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java index 4ed2eac550..aa376951c6 100644 --- a/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -11,8 +11,7 @@ */ public class NativeSecp256k1Test { - //TODO formatting for 100char wide - //TODO improve comments + //TODO improve comments/add more tests /** * This tests verify() for a valid signature */ @@ -61,7 +60,7 @@ public static void testSecKeyVerifyNeg() throws AssertFailException{ result = NativeSecp256k1.secKeyVerify( sec ); //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); - assertEquals( result, false , "testSecKeyVerifyPos"); + assertEquals( result, false , "testSecKeyVerifyNeg"); } /** @@ -72,7 +71,7 @@ public static void testPubKeyCreatePos() throws AssertFailException{ byte[] resultArr = NativeSecp256k1.computePubkey( sec); String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "Case 7"); + assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos"); } /** @@ -83,7 +82,7 @@ public static void testPubKeyCreateNeg() throws AssertFailException{ byte[] resultArr = NativeSecp256k1.computePubkey( sec); String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( pubkeyString, "" , "Case 8"); + assertEquals( pubkeyString, "" , "testPubKeyCreateNeg"); } /** @@ -96,7 +95,7 @@ public static void testSignPos() throws AssertFailException{ byte[] resultArr = NativeSecp256k1.sign(data, sec); String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "Case 9"); + assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos"); } /** @@ -108,7 +107,7 @@ public static void testSignNeg() throws AssertFailException{ byte[] resultArr = NativeSecp256k1.sign(data, sec); String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString, "" , "Case 10"); + assertEquals( sigString, "" , "testSignNeg"); } /** @@ -215,8 +214,47 @@ public static void testRandomize() throws AssertFailException { 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"); + */ + } + public static void main(String[] args) throws AssertFailException{ + System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n"); if( Secp256k1Context.isEnabled() ) { @@ -230,36 +268,36 @@ public static void main(String[] args) throws AssertFailException{ testSecKeyVerifyNeg(); //Test computePubkey() success/fail - //testPubKeyCreatePos(); // TODO Update API - //testPubKeyCreatePos(); // TODO Update API + testPubKeyCreatePos(); + testPubKeyCreateNeg(); //Test sign() success/fail - //testSignPos(); //TODO update API - //testSignNeg(); //TODO update API + testSignPos(); + testSignNeg(); //Test privKeyExport() compressed/uncomp - testPrivKeyExportComp(); - testPrivKeyExportUncomp(); + //testPrivKeyExportComp(); //Now in /contrib + //testPrivKeyExportUncomp(); //Now in /contrib //Test secKeyImport()/2 - testSecKeyImportPos(); - testSecKeyImportPos2(); + //testSecKeyImportPos(); //Now in /contrib + //testSecKeyImportPos2(); //Now in /contrib - /* 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; + //Test recovery //TODO + //testRecoverCompact(); + //testRecover(); + //testCreateRecoverable(); - resultArr = NativeSecp256k1.recoverCompact( data , sig , 0, recid ); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "Case 17"); + //Test ECDH //TODO + //testECDHSecretGen(); - resultArr = NativeSecp256k1.recoverCompact( data , sig , 1, recid ); - sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "02C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D" , "Case 18"); - */ + //Test Schnorr (partial support) //TODO + //testSchnorrSign + //testSchnorrVerify + //testSchnorrRecovery + + //Test pubkeyCombine //TODO + //test pubkeyCombine //Test privKeyTweakAdd() 1 testPrivKeyTweakAdd_1(); @@ -268,10 +306,10 @@ public static void main(String[] args) throws AssertFailException{ testPrivKeyTweakMul_1(); //Test privKeyTweakAdd() 3 - //TODO FIX test testPrivKeyTweakAdd_2(); + testPrivKeyTweakAdd_2(); //Test privKeyTweakMul() 4 - //TODO FIX test testPrivKeyTweakMul_2(); + testPrivKeyTweakMul_2(); //Test randomize() testRandomize(); diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index 189936ddea..7767814754 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -1,6 +1,8 @@ #include +#include #include "org_bitcoin_NativeSecp256k1.h" #include "include/secp256k1.h" +#include "include/secp256k1_recovery.h" JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone @@ -40,16 +42,25 @@ JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1cont } JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) + (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 secp256k1_ecdsa_signature *sig = { (secp256k1_ecdsa_signature*) (data + 32) }; - const secp256k1_pubkey *pub = { (secp256k1_pubkey*) (data + 64 + 32) }; + 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); + } - /*TODO remove debug + /*Debug printf("\nData: "); int i; for( i = 0; i < 32; i++) printf("%x", data[i]); @@ -61,11 +72,8 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify (void)classObject; + result = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey); - result = secp256k1_ecdsa_verify(ctx, sig, data, pub); - - printf("\nResult: %d", result); - printf("\n"); return result; } @@ -81,19 +89,25 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa unsigned char intsarray[2]; secp256k1_ecdsa_signature sig[72]; - int siglen = 72; int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL ); - intsarray[0] = siglen; + 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, siglen); - (*env)->SetByteArrayRegion(env, sigArray, 0, siglen, (jbyte*)sig); + sigArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); intsByteArray = (*env)->NewByteArray(env, 2); @@ -120,66 +134,32 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p (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); + const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - secp256k1_pubkey pubkey[65]; - int pubkeyLen = 65; + secp256k1_pubkey pubkey; jobjectArray retArray; jbyteArray pubkeyArray, intsByteArray; unsigned char intsarray[2]; - int ret = secp256k1_ec_pubkey_create(ctx, pubkey, secKey); - - intsarray[0] = pubkeyLen; - intsarray[1] = ret; - - retArray = (*env)->NewObjectArray(env, 2, - (*env)->FindClass(env, "[B"), - (*env)->NewByteArray(env, 1)); - - pubkeyArray = (*env)->NewByteArray(env, pubkeyLen); - (*env)->SetByteArrayRegion(env, pubkeyArray, 0, pubkeyLen, (jbyte*)pubkey); - (*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; - -} - -/* -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1decompress - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint pubLen) -{ - secp256k1_context *ctx = (secp256k1_context*)ctx_l; - - unsigned char* pubkey = (unsigned char*) malloc(sizeof(unsigned char)*65); - - unsigned char* temp = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - - int i, ret; - jobjectArray retArray; - jbyteArray pubkeyArray, intsByteArray; - unsigned char intsarray[2]; + int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey); - for(i = 0; i < pubLen; i++) pubkey[i] = temp[i]; + unsigned char outputSer[65]; + size_t outputLen = 65; - ret = secp256k1_ec_pubkey_decompress(ctx, pubkey, &pubLen); + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } - intsarray[0] = pubLen; + intsarray[0] = outputLen; intsarray[1] = ret; retArray = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "[B"), (*env)->NewByteArray(env, 1)); - pubkeyArray = (*env)->NewByteArray(env, pubLen); - (*env)->SetByteArrayRegion(env, pubkeyArray, 0, pubLen, (jbyte*)pubkey); + pubkeyArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer); (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray); intsByteArray = (*env)->NewByteArray(env, 2); @@ -189,9 +169,10 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p (void)classObject; return retArray; -}*/ +} +/* TODO replace with contrib/ code */ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1export (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint privLen, jint compressed) { @@ -230,6 +211,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p return retArray; } +/* TODO replace with contrib/ code */ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1privkey_1import (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint privLen) { @@ -268,6 +250,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p } +/* TODO replace with serialize_compact() code */ /*JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign_1compact (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { @@ -306,6 +289,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1p }*/ +/* TODO replace with recover_compact() code */ /* JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1recover_1compact (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint compressed, jint recid) @@ -417,24 +401,36 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubke (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); - const unsigned char* tweak = (unsigned char*) (pubkey + publen); +/* 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); - int ret = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, tweak); + if( ret ) { + ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak); + } - intsarray[0] = publen; + 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, publen); - (*env)->SetByteArrayRegion(env, pubArray, 0, publen, (jbyte*)pubkey); + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); intsByteArray = (*env)->NewByteArray(env, 2); @@ -450,24 +446,35 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubke (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); - const unsigned char* tweak = (unsigned char*) (pubkey + publen); + 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); + } - int 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] = publen; + intsarray[0] = outputLen; intsarray[1] = ret; retArray = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "[B"), (*env)->NewByteArray(env, 1)); - pubArray = (*env)->NewByteArray(env, publen); - (*env)->SetByteArrayRegion(env, pubArray, 0, publen, (jbyte*)pubkey); + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); intsByteArray = (*env)->NewByteArray(env, 2); @@ -479,76 +486,10 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubke return retArray; } -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1der - (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint inputlen) +JNIEXPORT jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine + (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys) { - const secp256k1_context *ctx = (secp256k1_context*)ctx_l; - - secp256k1_ecdsa_signature sig; - unsigned char* input = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - - jobjectArray retArray; - jbyteArray sigArray, intsByteArray; - unsigned char intsarray[1]; - - int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, input, inputlen); - - 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.data); - (*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; -} - -JNIEXPORT jlongArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1parse_1compact - (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint recovery) -{ - (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)recovery; + (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys; return 0; } - -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse - (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint inputlen) -{ - const secp256k1_context *ctx = (secp256k1_context*)ctx_l; - - secp256k1_pubkey pubkey; - unsigned char* input = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - - jobjectArray retArray; - jbyteArray pubArray, intsByteArray; - unsigned char intsarray[2]; - - int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, input, inputlen); - - intsarray[0] = ret; - - retArray = (*env)->NewObjectArray(env, 2, - (*env)->FindClass(env, "[B"), - (*env)->NewByteArray(env, 1)); - - pubArray = (*env)->NewByteArray(env, 64); - (*env)->SetByteArrayRegion(env, pubArray, 0, 64, (jbyte*)pubkey.data); - (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); - - intsByteArray = (*env)->NewByteArray(env, 1); - (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); - (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); - - (void)classObject; - - return retArray; -} diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index ee4857803d..8fbcefb89e 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -66,10 +66,10 @@ JNIEXPORT void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1cont /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_verify - * Signature: (Ljava/nio/ByteBuffer;J)I + * Signature: (Ljava/nio/ByteBuffer;JII)I */ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv *, jclass, jobject, jlong); + (JNIEnv *, jclass, jobject, jlong, jint, jint); /* * Class: org_bitcoin_NativeSecp256k1 @@ -90,7 +90,7 @@ JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1v /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ec_pubkey_create - * Signature: (Ljava/nio/ByteBuffer;JI)[[B + * Signature: (Ljava/nio/ByteBuffer;J)[[B */ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create (JNIEnv *, jclass, jobject, jlong); @@ -121,18 +121,10 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa /* * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdsa_signature_serialize_der + * Method: secp256k1_ecdsa_signature_normalize * Signature: (Ljava/nio/ByteBuffer;J)[[B */ -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1serialize_1der - (JNIEnv *, jclass, jobject, jlong); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdsa_signature_serialize_compact - * Signature: (Ljava/nio/ByteBuffer;J)[[B - */ -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1serialize_1compact +JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1signature_1normalize (JNIEnv *, jclass, jobject, jlong); /* @@ -143,14 +135,6 @@ JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse (JNIEnv *, jclass, jobject, jlong, jint); -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdsa_pubkey_serialize - * Signature: (Ljava/nio/ByteBuffer;J)[[B - */ -JNIEXPORT jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1serialize - (JNIEnv *, jclass, jobject, jlong); - /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_pubkey_combine