]> Git Repo - secp256k1.git/commitdiff
Merge #699: Initialize field elements when resulting in infinity
authorTim Ruffing <[email protected]>
Wed, 9 Sep 2020 14:00:12 +0000 (16:00 +0200)
committerTim Ruffing <[email protected]>
Wed, 9 Sep 2020 14:04:08 +0000 (16:04 +0200)
47a7b8382fd6f1458d859b315cf3bcd3b9790b68 Clear field elements when writing infinity (Elichai Turkel)
61d1ecb02847be9d65ffe9df2d2408d85f3a0711 Added test with additions resulting in infinity (Elichai Turkel)

Pull request description:

  Currently if `secp256k1_gej_add_var` / `secp256k1_gej_add_ge_var` /` secp256k1_gej_add_zinv_var` receive `P + (-P)` it will set `gej->infinity = 1` but doesn't call initialize the field elements.
  Notice that this is the only branch in the function that results in an uninitialized output.

  By using `secp256k1_gej_set_infinity()` it will set the field elements to zero while also setting the infinity flag.

  I also added a test that fails with valgrind on current master but passes with the fix.

  EDIT: This isn't a bug or something necessary, I just personally found this helpful.

ACKs for top commit:
  real-or-random:
    ACK 47a7b8382fd6f1458d859b315cf3bcd3b9790b68

Tree-SHA512: cdc2efc242a1b04b4f081183c07d4b2602cdba705e6b30b548df4e115e54fb97691f4b1a28f142f02d5e523c020721337a297b17d732acde147b910f5c53bd0a

58 files changed:
.gitignore
.travis.yml
Makefile.am
README.md
TODO [deleted file]
build-aux/m4/ax_jni_include_dir.m4 [deleted file]
build-aux/m4/bitcoin_secp.m4
configure.ac
contrib/lax_der_parsing.c
contrib/travis.sh [new file with mode: 0755]
include/secp256k1.h
include/secp256k1_ecdh.h
include/secp256k1_recovery.h
src/assumptions.h [new file with mode: 0644]
src/basic-config.h
src/bench.h
src/bench_ecdh.c
src/bench_ecmult.c
src/bench_internal.c
src/bench_recover.c
src/bench_sign.c
src/bench_verify.c
src/ecdsa_impl.h
src/eckey_impl.h
src/ecmult_const_impl.h
src/ecmult_gen_impl.h
src/field.h
src/field_10x26_impl.h
src/field_5x52.h
src/field_5x52_impl.h
src/field_impl.h
src/gen_context.c
src/group.h
src/group_impl.h
src/hash_impl.h
src/java/org/bitcoin/NativeSecp256k1.java [deleted file]
src/java/org/bitcoin/NativeSecp256k1Test.java [deleted file]
src/java/org/bitcoin/NativeSecp256k1Util.java [deleted file]
src/java/org/bitcoin/Secp256k1Context.java [deleted file]
src/java/org_bitcoin_NativeSecp256k1.c [deleted file]
src/java/org_bitcoin_NativeSecp256k1.h [deleted file]
src/java/org_bitcoin_Secp256k1Context.c [deleted file]
src/java/org_bitcoin_Secp256k1Context.h [deleted file]
src/modules/ecdh/main_impl.h
src/modules/recovery/main_impl.h [changed mode: 0755->0644]
src/scalar.h
src/scalar_4x64_impl.h
src/scalar_8x32_impl.h
src/scalar_impl.h
src/scalar_low.h
src/scalar_low_impl.h
src/scratch_impl.h
src/secp256k1.c
src/selftest.h [new file with mode: 0644]
src/tests.c
src/tests_exhaustive.c
src/util.h
src/valgrind_ctime_test.c [new file with mode: 0644]

index 55d325aeefa9c084a06e78808ddde841d702538c..c061705f4e39bb6ef166150f4374d7b33a733ae1 100644 (file)
@@ -9,6 +9,7 @@ bench_internal
 tests
 exhaustive_tests
 gen_context
+valgrind_ctime_test
 *.exe
 *.so
 *.a
@@ -30,6 +31,8 @@ libtool
 *.lo
 *.o
 *~
+*.log
+*.trs
 src/libsecp256k1-config.h
 src/libsecp256k1-config.h.in
 src/ecmult_static_context.h
index 4d5adf779d539ce203166a666bb307411bbf5414..81d1ba894f15d397962faacc050e049b23d23c70 100644 (file)
 language: c
-os: linux
+os:
+  - linux
+  - osx
+
+dist: bionic
+# Valgrind currently supports upto macOS 10.13, the latest xcode of that version is 10.1
+osx_image: xcode10.1
 addons:
   apt:
-    packages: libgmp-dev
+    packages:
+      - libgmp-dev
+      - valgrind
+      - libtool-bin
 compiler:
   - clang
   - gcc
-cache:
-  directories:
-  - src/java/guava/
 env:
   global:
-    - FIELD=auto  BIGNUM=auto  SCALAR=auto  ENDOMORPHISM=no  STATICPRECOMPUTATION=yes  ECMULTGENPRECISION=auto  ASM=no  BUILD=check  EXTRAFLAGS=  HOST=  ECDH=no  RECOVERY=no  EXPERIMENTAL=no  JNI=no
-    - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
+    - WIDEMUL=auto  BIGNUM=auto  ENDOMORPHISM=no  STATICPRECOMPUTATION=yes  ECMULTGENPRECISION=auto  ASM=no  BUILD=check  EXTRAFLAGS=  HOST=  ECDH=no  RECOVERY=no  EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2
   matrix:
-    - SCALAR=32bit    RECOVERY=yes
-    - SCALAR=32bit    FIELD=32bit       ECDH=yes  EXPERIMENTAL=yes
-    - SCALAR=64bit
-    - FIELD=64bit     RECOVERY=yes
-    - FIELD=64bit     ENDOMORPHISM=yes
-    - FIELD=64bit     ENDOMORPHISM=yes  ECDH=yes EXPERIMENTAL=yes
-    - FIELD=64bit                       ASM=x86_64
-    - FIELD=64bit     ENDOMORPHISM=yes  ASM=x86_64
-    - FIELD=32bit     ENDOMORPHISM=yes
+    - WIDEMUL=int64   RECOVERY=yes
+    - WIDEMUL=int64   ECDH=yes  EXPERIMENTAL=yes
+    - WIDEMUL=int64   ENDOMORPHISM=yes
+    - WIDEMUL=int128
+    - WIDEMUL=int128  RECOVERY=yes
+    - WIDEMUL=int128  ENDOMORPHISM=yes
+    - WIDEMUL=int128  ENDOMORPHISM=yes  ECDH=yes EXPERIMENTAL=yes
+    - WIDEMUL=int128                    ASM=x86_64
+    - WIDEMUL=int128  ENDOMORPHISM=yes  ASM=x86_64
     - BIGNUM=no
     - BIGNUM=no       ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes
     - BIGNUM=no       STATICPRECOMPUTATION=no
-    - BUILD=distcheck
-    - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
-    - EXTRAFLAGS=CFLAGS=-O0
-    - BUILD=check-java JNI=yes ECDH=yes EXPERIMENTAL=yes
+    - BUILD=distcheck CTIMETEST= BENCH=
+    - CPPFLAGS=-DDETERMINISTIC
+    - CFLAGS=-O0 CTIMETEST=
     - ECMULTGENPRECISION=2
     - ECMULTGENPRECISION=8
+    - VALGRIND=yes ENDOMORPHISM=yes BIGNUM=no ASM=x86_64 EXPERIMENTAL=yes ECDH=yes  RECOVERY=yes EXTRAFLAGS="--disable-openssl-tests" CPPFLAGS=-DVALGRIND BUILD=
+    - VALGRIND=yes                  BIGNUM=no ASM=x86_64 EXPERIMENTAL=yes ECDH=yes  RECOVERY=yes EXTRAFLAGS="--disable-openssl-tests" CPPFLAGS=-DVALGRIND BUILD=
 matrix:
   fast_finish: true
   include:
     - compiler: clang
+      os: linux
       env: HOST=i686-linux-gnu ENDOMORPHISM=yes
       addons:
         apt:
           packages:
             - gcc-multilib
             - libgmp-dev:i386
+            - valgrind
+            - libtool-bin
+            - libc6-dbg:i386
     - compiler: clang
       env: HOST=i686-linux-gnu
+      os: linux
       addons:
         apt:
           packages:
             - gcc-multilib
+            - valgrind
+            - libtool-bin
+            - libc6-dbg:i386
     - compiler: gcc
       env: HOST=i686-linux-gnu ENDOMORPHISM=yes
+      os: linux
       addons:
         apt:
           packages:
             - gcc-multilib
+            - valgrind
+            - libtool-bin
+            - libc6-dbg:i386
     - compiler: gcc
+      os: linux
       env: HOST=i686-linux-gnu
       addons:
         apt:
           packages:
             - gcc-multilib
             - libgmp-dev:i386
-    - compiler: gcc
-      env:
-        - BIGNUM=no  ENDOMORPHISM=yes  ASM=x86_64 EXPERIMENTAL=yes ECDH=yes  RECOVERY=yes
-        - VALGRIND=yes EXTRAFLAGS="--disable-openssl-tests CPPFLAGS=-DVALGRIND" BUILD=
-      addons:
-        apt:
-          packages:
             - valgrind
+            - libtool-bin
+            - libc6-dbg:i386
+    # S390x build (big endian system)
     - compiler: gcc
-      env: # The same as above but without endomorphism.
-        - BIGNUM=no  ENDOMORPHISM=no  ASM=x86_64 EXPERIMENTAL=yes ECDH=yes  RECOVERY=yes
-        - VALGRIND=yes EXTRAFLAGS="--disable-openssl-tests CPPFLAGS=-DVALGRIND" BUILD=
-      addons:
-        apt:
-          packages:
-            - valgrind
+      env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes CTIMETEST=
+      arch: s390x
+
+# We use this to install macOS dependencies instead of the built in `homebrew` plugin,
+# because in xcode earlier than 11 they have a bug requiring updating the system which overall takes ~8 minutes.
+# https://travis-ci.community/t/macos-build-fails-because-of-homebrew-bundle-unknown-command/7296
+before_install:
+ - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then HOMEBREW_NO_AUTO_UPDATE=1 brew install gmp valgrind gcc@9; fi
 
-before_install: mkdir -p `dirname $GUAVA_JAR`
-install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi
 before_script: ./autogen.sh
 
+# travis auto terminates jobs that go for 10 minutes without printing to stdout, but travis_wait doesn't work well with forking programs like valgrind (https://docs.travis-ci.com/user/common-build-problems/#build-times-out-because-no-output-was-received https://github.com/bitcoin-core/secp256k1/pull/750#issuecomment-623476860)
 script:
- - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
- - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
- - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-asm=$ASM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --with-ecmult-gen-precision=$ECMULTGENPRECISION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-jni=$JNI $EXTRAFLAGS $USE_HOST
- - if [ -n "$BUILD" ]; then make -j2 $BUILD; fi
- - # travis_wait extends the 10 minutes without output allowed (https://docs.travis-ci.com/user/common-build-problems/#build-times-out-because-no-output-was-received)
- - # the `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (http://valgrind.org/docs/manual/manual-core.html)
- - if [ -n "$VALGRIND" ]; then
-   make -j2 &&
-   travis_wait 30 valgrind --error-exitcode=42 ./tests 16 &&
-   travis_wait 30 valgrind --error-exitcode=42 ./exhaustive_tests;
-   fi
+  - function keep_alive() { while true; do echo -en "\a"; sleep 60; done }
+  - keep_alive &
+  - ./contrib/travis.sh
+  - kill %keep_alive
 
 after_script:
     - cat ./tests.log
     - cat ./exhaustive_tests.log
+    - cat ./valgrind_ctime_test.log
+    - cat ./bench.log
+    - $CC --version
+    - valgrind --version
index f420944e8fcfa006b6893d74a8dd9c6d3ec04ce9..9a7c770db720de85fa16ac85b875e8640f6291d7 100644 (file)
@@ -1,12 +1,6 @@
 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
 include_HEADERS += include/secp256k1_preallocated.h
 noinst_HEADERS =
@@ -40,11 +34,11 @@ noinst_HEADERS += src/field_5x52.h
 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/assumptions.h
 noinst_HEADERS += src/util.h
 noinst_HEADERS += src/scratch.h
 noinst_HEADERS += src/scratch_impl.h
+noinst_HEADERS += src/selftest.h
 noinst_HEADERS += src/testrand.h
 noinst_HEADERS += src/testrand_impl.h
 noinst_HEADERS += src/hash.h
@@ -75,16 +69,19 @@ endif
 
 libsecp256k1_la_SOURCES = src/secp256k1.c
 libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
-libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB)
+libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB)
 
-libsecp256k1_jni_la_SOURCES  = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c
-libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)
+if VALGRIND_ENABLED
+libsecp256k1_la_CPPFLAGS += -DVALGRIND
+endif
 
 noinst_PROGRAMS =
 if USE_BENCHMARK
 noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_ecmult
 bench_verify_SOURCES = src/bench_verify.c
 bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
+# SECP_TEST_INCLUDES are only used here for CRYPTO_CPPFLAGS
+bench_verify_CPPFLAGS = -DSECP256K1_BUILD $(SECP_TEST_INCLUDES)
 bench_sign_SOURCES = src/bench_sign.c
 bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
 bench_internal_SOURCES = src/bench_internal.c
@@ -100,6 +97,12 @@ if USE_TESTS
 noinst_PROGRAMS += tests
 tests_SOURCES = src/tests.c
 tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
+if VALGRIND_ENABLED
+tests_CPPFLAGS += -DVALGRIND
+noinst_PROGRAMS += valgrind_ctime_test
+valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c
+valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_LIBS) $(COMMON_LIB)
+endif
 if !ENABLE_COVERAGE
 tests_CPPFLAGS += -DVERIFY
 endif
@@ -120,36 +123,6 @@ exhaustive_tests_LDFLAGS = -static
 TESTS += exhaustive_tests
 endif
 
-JAVAROOT=src/java
-JAVAORG=org/bitcoin
-JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar
-CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA)
-JAVA_FILES= \
-  $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \
-  $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \
-  $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \
-  $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java
-
-if USE_JNI
-
-$(JAVA_GUAVA):
-       @echo Guava is missing. Fetch it via: \
-       wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@)
-       @false
-
-.stamp-java: $(JAVA_FILES)
-       @echo   Compiling $^
-       $(AM_V_at)$(CLASSPATH_ENV) javac $^
-       @touch $@
-
-if USE_TESTS
-
-check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java
-       $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test
-
-endif
-endif
-
 if USE_ECMULT_STATIC_PRECOMPUTATION
 CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) -I$(builddir)/src
 
@@ -169,10 +142,10 @@ $(bench_ecmult_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 $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java
+CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h
 endif
 
-EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES)
+EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h
 
 if ENABLE_MODULE_ECDH
 include src/modules/ecdh/Makefile.am.include
index 5603d7b0ee42962a9f09e29978bcb81ff6f5223d..434178b372839b56a3b4b0dee2568ea57c05142c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,17 +3,22 @@ libsecp256k1
 
 [![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1)
 
-Optimized C library for EC operations on curve secp256k1.
+Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.
 
-This library is a work in progress and is being used to research best practices. Use at your own risk.
+This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose.
 
 Features:
 * secp256k1 ECDSA signing/verification and key generation.
-* Adding/multiplying private/public keys.
-* Serialization/parsing of private keys, public keys, signatures.
-* Constant time, constant memory access signing and pubkey generation.
-* Derandomized DSA (via RFC6979 or with a caller provided function.)
+* Additive and multiplicative tweaking of secret/public keys.
+* Serialization/parsing of secret keys, public keys, signatures.
+* Constant time, constant memory access signing and public key generation.
+* Derandomized ECDSA (via RFC6979 or with a caller provided function.)
 * Very efficient implementation.
+* Suitable for embedded systems.
+* Optional module for public key recovery.
+* Optional module for ECDH key exchange (experimental).
+
+Experimental features have not received enough scrutiny to satisfy the standard of quality of this library but are made available for testing and review by the community. The APIs of these features should not be considered stable.
 
 Implementation details
 ----------------------
@@ -23,12 +28,12 @@ Implementation details
   * Extensive testing infrastructure.
   * Structured to facilitate review and analysis.
   * Intended to be portable to any system with a C89 compiler and uint64_t support.
-  * No use of floating types, except in benchmarks.
+  * No use of floating types.
   * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
 * Field operations
   * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
     * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys).
-    * Using 10 26-bit limbs.
+    * Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan).
   * Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman).
 * Scalar operations
   * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
@@ -50,7 +55,7 @@ Implementation details
     * Access the table with branch-free conditional moves so memory access is uniform.
     * No data-dependent branches
   * Optional runtime blinding which attempts to frustrate differential power analysis.
-  * The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally.
+  * The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally.
 
 Build steps
 -----------
@@ -72,6 +77,27 @@ With valgrind, you might need to increase the max stack size:
 
     $ valgrind --max-stackframe=2500000 ./exhaustive_tests
 
+Test coverage
+-----------
+
+This library aims to have full coverage of the reachable lines and branches.
+
+To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary):
+
+    $ ./configure --enable-coverage
+
+Run the tests:
+
+    $ make check
+
+To create a report, `gcovr` is recommended, as it includes branch coverage reporting:
+
+    $ gcovr --exclude 'src/bench*' --print-summary
+
+To create a HTML report with coloured and annotated source code:
+
+    $ gcovr --exclude 'src/bench*' --html --html-details -o coverage.html
+
 Reporting a vulnerability
 ------------
 
diff --git a/TODO b/TODO
deleted file mode 100644 (file)
index a300e1c..0000000
--- a/TODO
+++ /dev/null
@@ -1,3 +0,0 @@
-* Unit tests for fieldelem/groupelem, including ones intended to
-  trigger fieldelem's boundary cases.
-* Complete constant-time operations for signing/keygen
diff --git a/build-aux/m4/ax_jni_include_dir.m4 b/build-aux/m4/ax_jni_include_dir.m4
deleted file mode 100644 (file)
index cdc78d8..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-# ===========================================================================
-#    https://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 <[email protected]>
-#
-#   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 14
-
-AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
-AC_DEFUN([AX_JNI_INCLUDE_DIR],[
-
-JNI_INCLUDE_DIRS=""
-
-if test "x$JAVA_HOME" != x; then
-       _JTOPDIR="$JAVA_HOME"
-else
-       if test "x$JAVAC" = x; then
-               JAVAC=javac
-       fi
-       AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
-       if test "x$_ACJNI_JAVAC" = xno; then
-               AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME])
-       fi
-       _ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
-       _JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
-fi
-
-case "$host_os" in
-        darwin*)        # Apple Java headers are inside the Xcode bundle.
-            macos_version=$(sw_vers -productVersion | sed -n -e 's/^@<:@0-9@:>@*.\(@<:@0-9@:>@*\).@<:@0-9@:>@*/\1/p')
-            if @<:@ "$macos_version" -gt "7" @:>@; then
-                _JTOPDIR="$(xcrun --show-sdk-path)/System/Library/Frameworks/JavaVM.framework"
-                _JINC="$_JTOPDIR/Headers"
-            else
-                _JTOPDIR="/System/Library/Frameworks/JavaVM.framework"
-                _JINC="$_JTOPDIR/Headers"
-            fi
-            ;;
-        *) _JINC="$_JTOPDIR/include";;
-esac
-_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
-_AS_ECHO_LOG([_JINC=$_JINC])
-
-# On Mac OS X 10.6.4, jni.h is a symlink:
-# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
-# -> ../../CurrentJDK/Headers/jni.h.
-AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,
-[
-  if test -f "$_JINC/jni.h"; then
-    ac_cv_jni_header_path="$_JINC"
-    JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
-  else
-    _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
-    if test -f "$_JTOPDIR/include/jni.h"; then
-      ac_cv_jni_header_path="$_JTOPDIR/include"
-      JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
-    else
-      ac_cv_jni_header_path=none
-    fi
-  fi
-])
-
-# get the likely subdirectories for system specific java includes
-case "$host_os" in
-bsdi*)          _JNI_INC_SUBDIRS="bsdos";;
-freebsd*)       _JNI_INC_SUBDIRS="freebsd";;
-darwin*)        _JNI_INC_SUBDIRS="darwin";;
-linux*)         _JNI_INC_SUBDIRS="linux genunix";;
-osf*)           _JNI_INC_SUBDIRS="alpha";;
-solaris*)       _JNI_INC_SUBDIRS="solaris";;
-mingw*)                _JNI_INC_SUBDIRS="win32";;
-cygwin*)       _JNI_INC_SUBDIRS="win32";;
-*)              _JNI_INC_SUBDIRS="genunix";;
-esac
-
-if test "x$ac_cv_jni_header_path" != "xnone"; then
-  # add any subdirectories that are present
-  for JINCSUBDIR in $_JNI_INC_SUBDIRS
-  do
-    if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
-         JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
-    fi
-  done
-fi
-])
-
-# _ACJNI_FOLLOW_SYMLINKS <path>
-# Follows symbolic links on <path>,
-# finally setting variable _ACJNI_FOLLOWED
-# ----------------------------------------
-AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
-# find the include directory relative to the javac executable
-_cur="$1"
-while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
-        AC_MSG_CHECKING([symlink for $_cur])
-        _slink=`ls -ld "$_cur" | sed 's/.* -> //'`
-        case "$_slink" in
-        /*) _cur="$_slink";;
-        # 'X' avoids triggering unwanted echo options.
-        *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
-        esac
-        AC_MSG_RESULT([$_cur])
-done
-_ACJNI_FOLLOWED="$_cur"
-])# _ACJNI
index 3b3975cbdda81d9a96f7bece460c3d126ecc97b1..57595f4499d8e10646e6cbb56417a831803786cd 100644 (file)
@@ -1,8 +1,3 @@
-dnl libsecp25k1 helper checks
-AC_DEFUN([SECP_INT128_CHECK],[
-has_int128=$ac_cv_type___int128
-])
-
 dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
 AC_DEFUN([SECP_64BIT_ASM_CHECK],[
 AC_MSG_CHECKING(for x86_64 assembly availability)
@@ -38,6 +33,8 @@ AC_DEFUN([SECP_OPENSSL_CHECK],[
   fi
 if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
   AC_MSG_CHECKING(for EC functions in libcrypto)
+  CPPFLAGS_TEMP="$CPPFLAGS"
+  CPPFLAGS="$CRYPTO_CPPFLAGS $CPPFLAGS"
   AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
     #include <openssl/ec.h>
     #include <openssl/ecdsa.h>
@@ -51,6 +48,7 @@ if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
     ECDSA_SIG_free(sig_openssl);
   ]])],[has_openssl_ec=yes],[has_openssl_ec=no])
   AC_MSG_RESULT([$has_openssl_ec])
+  CPPFLAGS="$CPPFLAGS_TEMP"
 fi
 ])
 
index 2a8db0a51c607c41cb70c48c624f8f5671e77d93..743f7f7ba9887a772a7159b9fcbe828c6b32794b 100644 (file)
@@ -7,6 +7,11 @@ AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
 AH_TOP([#define LIBSECP256K1_CONFIG_H])
 AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
 AM_INIT_AUTOMAKE([foreign subdir-objects])
+
+# Set -g if CFLAGS are not already set, which matches the default autoconf
+# behavior (see PROG_CC in the Autoconf manual) with the exception that we don't
+# set -O2 here because we set it in any case (see further down).
+: ${CFLAGS="-g"}
 LT_INIT
 
 dnl make the compilation flags quiet unless V=1 is used
@@ -19,10 +24,6 @@ AC_PATH_TOOL(RANLIB, ranlib)
 AC_PATH_TOOL(STRIP, strip)
 AX_PROG_CC_FOR_BUILD
 
-if test "x$CFLAGS" = "x"; then
-  CFLAGS="-g"
-fi
-
 AM_PROG_CC_C_O
 
 AC_PROG_CC_C89
@@ -45,6 +46,7 @@ case $host_os in
          if test x$openssl_prefix != x; then
            PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
            export PKG_CONFIG_PATH
+           CRYPTO_CPPFLAGS="-I$openssl_prefix/include"
          fi
          if test x$gmp_prefix != x; then
            GMP_CPPFLAGS="-I$gmp_prefix/include"
@@ -63,11 +65,11 @@ case $host_os in
    ;;
 esac
 
-CFLAGS="$CFLAGS -W"
+CFLAGS="-W $CFLAGS"
 
 warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings"
 saved_CFLAGS="$CFLAGS"
-CFLAGS="$CFLAGS $warn_CFLAGS"
+CFLAGS="$warn_CFLAGS $CFLAGS"
 AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}])
 AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
     [ AC_MSG_RESULT([yes]) ],
@@ -76,7 +78,7 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
     ])
 
 saved_CFLAGS="$CFLAGS"
-CFLAGS="$CFLAGS -fvisibility=hidden"
+CFLAGS="-fvisibility=hidden $CFLAGS"
 AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
 AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
     [ AC_MSG_RESULT([yes]) ],
@@ -139,20 +141,13 @@ AC_ARG_ENABLE(external_default_callbacks,
     [use_external_default_callbacks=$enableval],
     [use_external_default_callbacks=no])
 
-AC_ARG_ENABLE(jni,
-    AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni [default=no]]),
-    [use_jni=$enableval],
-    [use_jni=no])
-
-AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
-[finite field implementation to use [default=auto]])],[req_field=$withval], [req_field=auto])
+dnl Test-only override of the (autodetected by the C code) "widemul" setting.
+dnl Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
+AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
 
 AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
 [bignum implementation to use [default=auto]])],[req_bignum=$withval], [req_bignum=auto])
 
-AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
-[scalar implementation to use [default=auto]])],[req_scalar=$withval], [req_scalar=auto])
-
 AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
 [assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto])
 
@@ -173,14 +168,15 @@ AC_ARG_WITH([ecmult-gen-precision], [AS_HELP_STRING([--with-ecmult-gen-precision
 )],
 [req_ecmult_gen_precision=$withval], [req_ecmult_gen_precision=auto])
 
-AC_CHECK_TYPES([__int128])
+AC_CHECK_HEADER([valgrind/memcheck.h], [enable_valgrind=yes], [enable_valgrind=no], [])
+AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"])
 
 if test x"$enable_coverage" = x"yes"; then
     AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
-    CFLAGS="$CFLAGS -O0 --coverage"
-    LDFLAGS="$LDFLAGS --coverage"
+    CFLAGS="-O0 --coverage $CFLAGS"
+    LDFLAGS="--coverage $LDFLAGS"
 else
-    CFLAGS="$CFLAGS -O3"
+    CFLAGS="-O2 $CFLAGS"
 fi
 
 if test x"$use_ecmult_static_precomputation" != x"no"; then
@@ -198,7 +194,7 @@ if test x"$use_ecmult_static_precomputation" != x"no"; then
 
   warn_CFLAGS_FOR_BUILD="-Wall -Wextra -Wno-unused-function"
   saved_CFLAGS="$CFLAGS"
-  CFLAGS="$CFLAGS $warn_CFLAGS_FOR_BUILD"
+  CFLAGS="$warn_CFLAGS_FOR_BUILD $CFLAGS"
   AC_MSG_CHECKING([if native ${CC_FOR_BUILD} supports ${warn_CFLAGS_FOR_BUILD}])
   AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
       [ AC_MSG_RESULT([yes]) ],
@@ -210,7 +206,7 @@ if test x"$use_ecmult_static_precomputation" != x"no"; then
   AC_RUN_IFELSE(
     [AC_LANG_PROGRAM([], [])],
     [working_native_cc=yes],
-    [working_native_cc=no],[dnl])
+    [working_native_cc=no],[:])
 
   CFLAGS_FOR_BUILD="$CFLAGS"
 
@@ -265,63 +261,6 @@ else
   esac
 fi
 
-if test x"$req_field" = x"auto"; then
-  if test x"set_asm" = x"x86_64"; then
-    set_field=64bit
-  fi
-  if test x"$set_field" = x; then
-    SECP_INT128_CHECK
-    if test x"$has_int128" = x"yes"; then
-      set_field=64bit
-    fi
-  fi
-  if test x"$set_field" = x; then
-    set_field=32bit
-  fi
-else
-  set_field=$req_field
-  case $set_field in
-  64bit)
-    if test x"$set_asm" != x"x86_64"; then
-      SECP_INT128_CHECK
-      if test x"$has_int128" != x"yes"; then
-        AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available])
-      fi
-    fi
-    ;;
-  32bit)
-    ;;
-  *)
-    AC_MSG_ERROR([invalid field implementation selection])
-    ;;
-  esac
-fi
-
-if test x"$req_scalar" = x"auto"; then
-  SECP_INT128_CHECK
-  if test x"$has_int128" = x"yes"; then
-    set_scalar=64bit
-  fi
-  if test x"$set_scalar" = x; then
-    set_scalar=32bit
-  fi
-else
-  set_scalar=$req_scalar
-  case $set_scalar in
-  64bit)
-    SECP_INT128_CHECK
-    if test x"$has_int128" != x"yes"; then
-      AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available])
-    fi
-    ;;
-  32bit)
-    ;;
-  *)
-    AC_MSG_ERROR([invalid scalar implementation selected])
-    ;;
-  esac
-fi
-
 if test x"$req_bignum" = x"auto"; then
   SECP_GMP_CHECK
   if test x"$has_gmp" = x"yes"; then
@@ -365,16 +304,18 @@ no)
   ;;
 esac
 
-# select field implementation
-case $set_field in
-64bit)
-  AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation])
+# select wide multiplication implementation
+case $set_widemul in
+int128)
+  AC_DEFINE(USE_FORCE_WIDEMUL_INT128, 1, [Define this symbol to force the use of the (unsigned) __int128 based wide multiplication implementation])
   ;;
-32bit)
-  AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation])
+int64)
+  AC_DEFINE(USE_FORCE_WIDEMUL_INT64, 1, [Define this symbol to force the use of the (u)int64_t based wide multiplication implementation])
+  ;;
+auto)
   ;;
 *)
-  AC_MSG_ERROR([invalid field implementation])
+  AC_MSG_ERROR([invalid wide multiplication implementation])
   ;;
 esac
 
@@ -396,19 +337,6 @@ no)
   ;;
 esac
 
-#select scalar implementation
-case $set_scalar in
-64bit)
-  AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation])
-  ;;
-32bit)
-  AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation])
-  ;;
-*)
-  AC_MSG_ERROR([invalid scalar implementation])
-  ;;
-esac
-
 #set ecmult window size
 if test x"$req_ecmult_window" = x"auto"; then
   set_ecmult_window=15
@@ -452,7 +380,7 @@ if test x"$use_tests" = x"yes"; then
   if test x"$has_openssl_ec" = x"yes"; then
     if test x"$enable_openssl_tests" != x"no"; then
       AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
-      SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
+      SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS $CRYPTO_CPPFLAGS"
       SECP_TEST_LIBS="$CRYPTO_LIBS"
 
       case $host in
@@ -472,29 +400,6 @@ else
   fi
 fi
 
-if test x"$use_jni" != x"no"; then
-  AX_JNI_INCLUDE_DIR
-  have_jni_dependencies=yes
-  if test x"$enable_module_ecdh" = x"no"; then
-    have_jni_dependencies=no
-  fi
-  if test "x$JNI_INCLUDE_DIRS" = "x"; then
-    have_jni_dependencies=no
-  fi
-  if test "x$have_jni_dependencies" = "xno"; then
-    if test x"$use_jni" = x"yes"; then
-      AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.])
-    fi
-    AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])
-    use_jni=no
-  else
-    use_jni=yes
-    for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
-      JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR"
-    done
-  fi
-fi
-
 if test x"$set_bignum" = x"gmp"; then
   SECP_LIBS="$SECP_LIBS $GMP_LIBS"
   SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS"
@@ -516,8 +421,6 @@ if test x"$enable_module_recovery" = x"yes"; then
   AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
 fi
 
-AC_C_BIGENDIAN()
-
 if test x"$use_external_asm" = x"yes"; then
   AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
 fi
@@ -543,7 +446,6 @@ fi
 
 AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
 AC_CONFIG_FILES([Makefile libsecp256k1.pc])
-AC_SUBST(JNI_INCLUDES)
 AC_SUBST(SECP_INCLUDES)
 AC_SUBST(SECP_LIBS)
 AC_SUBST(SECP_TEST_LIBS)
@@ -555,7 +457,6 @@ AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
 AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
 AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
 AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
-AM_CONDITIONAL([USE_JNI], [test x"$use_jni" = x"yes"])
 AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
 AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
 
@@ -571,7 +472,6 @@ echo "Build Options:"
 echo "  with endomorphism       = $use_endomorphism"
 echo "  with ecmult precomp     = $set_precomp"
 echo "  with external callbacks = $use_external_default_callbacks"
-echo "  with jni                = $use_jni"
 echo "  with benchmarks         = $use_benchmark"
 echo "  with coverage           = $enable_coverage"
 echo "  module ecdh             = $enable_module_ecdh"
@@ -579,11 +479,14 @@ echo "  module recovery         = $enable_module_recovery"
 echo
 echo "  asm                     = $set_asm"
 echo "  bignum                  = $set_bignum"
-echo "  field                   = $set_field"
-echo "  scalar                  = $set_scalar"
 echo "  ecmult window size      = $set_ecmult_window"
 echo "  ecmult gen prec. bits   = $set_ecmult_gen_precision"
+dnl Hide test-only options unless they're used.
+if test x"$set_widemul" != xauto; then
+echo "  wide multiplication     = $set_widemul"
+fi
 echo
+echo "  valgrind                = $enable_valgrind"
 echo "  CC                      = $CC"
 echo "  CFLAGS                  = $CFLAGS"
 echo "  CPPFLAGS                = $CPPFLAGS"
index e177a0562dd2d2525a095c1dc3922b0ad5241ca5..f71db4b53524cc1254190cb915f810adf3113ad7 100644 (file)
@@ -112,7 +112,6 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
         return 0;
     }
     spos = pos;
-    pos += slen;
 
     /* Ignore leading zeroes in R */
     while (rlen > 0 && input[rpos] == 0) {
diff --git a/contrib/travis.sh b/contrib/travis.sh
new file mode 100755 (executable)
index 0000000..2023d0b
--- /dev/null
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+set -e
+set -x
+
+if [ "$HOST" = "i686-linux-gnu" ]
+then
+    export CC="$CC -m32"
+fi
+if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$TRAVIS_COMPILER" = "gcc" ]
+then
+    export CC="gcc-9"
+fi
+
+./configure \
+    --enable-experimental="$EXPERIMENTAL" --enable-endomorphism="$ENDOMORPHISM" \
+    --with-test-override-wide-multiply="$WIDEMUL" --with-bignum="$BIGNUM" --with-asm="$ASM" \
+    --enable-ecmult-static-precomputation="$STATICPRECOMPUTATION" --with-ecmult-gen-precision="$ECMULTGENPRECISION" \
+    --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
+    --host="$HOST" $EXTRAFLAGS
+
+if [ -n "$BUILD" ]
+then
+    make -j2 "$BUILD"
+fi
+if [ -n "$VALGRIND" ]
+then
+    make -j2
+    # the `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (http://valgrind.org/docs/manual/manual-core.html)
+    valgrind --error-exitcode=42 ./tests 16
+    valgrind --error-exitcode=42 ./exhaustive_tests
+fi
+if [ -n "$BENCH" ]
+then
+    if [ -n "$VALGRIND" ]
+    then
+        # Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool
+        EXEC='./libtool --mode=execute valgrind --error-exitcode=42'
+    else
+        EXEC=
+    fi
+    # This limits the iterations in the benchmarks below to ITER(set in .travis.yml) iterations.
+    export SECP256K1_BENCH_ITERS="$ITERS"
+    {
+        $EXEC ./bench_ecmult
+        $EXEC ./bench_internal
+        $EXEC ./bench_sign
+        $EXEC ./bench_verify
+    } >> bench.log 2>&1
+    if [ "$RECOVERY" = "yes" ]
+    then
+        $EXEC ./bench_recover >> bench.log 2>&1
+    fi
+    if [ "$ECDH" = "yes" ]
+    then
+        $EXEC ./bench_ecdh >> bench.log 2>&1
+    fi
+fi
+if [ -n "$CTIMETEST" ]
+then
+    ./libtool --mode=execute valgrind --error-exitcode=42 ./valgrind_ctime_test > valgrind_ctime_test.log 2>&1
+fi
index 36020e516467782fc7e5f80ca07169c2851c963d..2178c8e2d6f1864b563f0087c829372804f2cd78 100644 (file)
@@ -14,7 +14,7 @@ extern "C" {
  * 2. Array lengths always immediately the follow the argument whose length
  *    they describe, even if this violates rule 1.
  * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated
- *    later go first. This means: signatures, public nonces, private nonces,
+ *    later go first. This means: signatures, public nonces, secret nonces,
  *    messages, public keys, secret keys, tweaks.
  * 4. Arguments that are not data pointers go last, from more complex to less
  *    complex: function pointers, algorithm names, messages, void pointers,
@@ -134,7 +134,7 @@ typedef int (*secp256k1_nonce_function)(
 #  else
 #   define SECP256K1_API
 #  endif
-# elif defined(__GNUC__) && defined(SECP256K1_BUILD)
+# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
 #  define SECP256K1_API __attribute__ ((visibility ("default")))
 # else
 #  define SECP256K1_API
@@ -162,12 +162,14 @@ typedef int (*secp256k1_nonce_function)(
 /** The higher bits contain the actual data. Do not use directly. */
 #define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)
 #define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
+#define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10)
 #define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
 
 /** Flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and
  *  secp256k1_context_preallocated_create. */
 #define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
 #define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
+#define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY)
 #define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
 
 /** Flag to pass to secp256k1_ec_pubkey_serialize. */
@@ -529,7 +531,7 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def
 /** Create an ECDSA signature.
  *
  *  Returns: 1: signature created
- *           0: the nonce generation function failed, or the private key was invalid.
+ *           0: the nonce generation function failed, or the secret key was invalid.
  *  Args:    ctx:    pointer to a context object, initialized for signing (cannot be NULL)
  *  Out:     sig:    pointer to an array where the signature will be placed (cannot be NULL)
  *  In:      msg32:  the 32-byte message hash being signed (cannot be NULL)
@@ -550,6 +552,11 @@ SECP256K1_API int secp256k1_ecdsa_sign(
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
 
 /** Verify an ECDSA secret key.
+ *
+ *  A secret key is valid if it is not 0 and less than the secp256k1 curve order
+ *  when interpreted as an integer (most significant byte first). The
+ *  probability of choosing a 32-byte string uniformly at random which is an
+ *  invalid secret key is negligible.
  *
  *  Returns: 1: secret key is valid
  *           0: secret key is invalid
@@ -567,7 +574,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
  *           0: secret was invalid, try again
  *  Args:   ctx:        pointer to a context object, initialized for signing (cannot be NULL)
  *  Out:    pubkey:     pointer to the created public key (cannot be NULL)
- *  In:     seckey:     pointer to a 32-byte private key (cannot be NULL)
+ *  In:     seckey:     pointer to a 32-byte secret key (cannot be NULL)
  */
 SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
     const secp256k1_context* ctx,
@@ -575,12 +582,24 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
     const unsigned char *seckey
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
-/** Negates a private key in place.
+/** Negates a secret key in place.
  *
- *  Returns: 1 always
- *  Args:   ctx:        pointer to a context object
- *  In/Out: seckey:     pointer to the 32-byte private key to be negated (cannot be NULL)
+ *  Returns: 0 if the given secret key is invalid according to
+ *           secp256k1_ec_seckey_verify. 1 otherwise
+ *  Args:   ctx:    pointer to a context object
+ *  In/Out: seckey: pointer to the 32-byte secret key to be negated. If the
+ *                  secret key is invalid according to
+ *                  secp256k1_ec_seckey_verify, this function returns 0 and
+ *                  seckey will be set to some unspecified value. (cannot be
+ *                  NULL)
  */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
+    const secp256k1_context* ctx,
+    unsigned char *seckey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
+
+/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in
+ *  future versions. */
 SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
     const secp256k1_context* ctx,
     unsigned char *seckey
@@ -597,15 +616,29 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
     secp256k1_pubkey *pubkey
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
 
-/** Tweak a private key by adding tweak to it.
- * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
- *          uniformly random 32-byte arrays, or if the resulting private key
- *          would be invalid (only when the tweak is the complement of the
- *          private key). 1 otherwise.
- * Args:    ctx:    pointer to a context object (cannot be NULL).
- * In/Out:  seckey: pointer to a 32-byte private key.
- * In:      tweak:  pointer to a 32-byte tweak.
- */
+/** Tweak a secret key by adding tweak to it.
+ *
+ *  Returns: 0 if the arguments are invalid or the resulting secret key would be
+ *           invalid (only when the tweak is the negation of the secret key). 1
+ *           otherwise.
+ *  Args:    ctx:   pointer to a context object (cannot be NULL).
+ *  In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
+ *                  invalid according to secp256k1_ec_seckey_verify, this
+ *                  function returns 0. seckey will be set to some unspecified
+ *                  value if this function returns 0. (cannot be NULL)
+ *  In:      tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
+ *                  secp256k1_ec_seckey_verify, this function returns 0. For
+ *                  uniformly random 32-byte arrays the chance of being invalid
+ *                  is negligible (around 1 in 2^128) (cannot be NULL).
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
+    const secp256k1_context* ctx,
+    unsigned char *seckey,
+    const unsigned char *tweak
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in
+ *  future versions. */
 SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
     const secp256k1_context* ctx,
     unsigned char *seckey,
@@ -613,14 +646,18 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
 /** Tweak a public key by adding tweak times the generator to it.
- * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
- *          uniformly random 32-byte arrays, or if the resulting public key
- *          would be invalid (only when the tweak is the complement of the
- *          corresponding private key). 1 otherwise.
- * Args:    ctx:    pointer to a context object initialized for validation
+ *
+ *  Returns: 0 if the arguments are invalid or the resulting public key would be
+ *           invalid (only when the tweak is the negation of the corresponding
+ *           secret key). 1 otherwise.
+ *  Args:    ctx:   pointer to a context object initialized for validation
  *                  (cannot be NULL).
- * In/Out:  pubkey: pointer to a public key object.
- * In:      tweak:  pointer to a 32-byte tweak.
+ *  In/Out: pubkey: pointer to a public key object. pubkey will be set to an
+ *                  invalid value if this function returns 0 (cannot be NULL).
+ *  In:      tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
+ *                  secp256k1_ec_seckey_verify, this function returns 0. For
+ *                  uniformly random 32-byte arrays the chance of being invalid
+ *                  is negligible (around 1 in 2^128) (cannot be NULL).
  */
 SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
     const secp256k1_context* ctx,
@@ -628,13 +665,27 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
     const unsigned char *tweak
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
-/** Tweak a private key by multiplying it by a tweak.
- * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
- *          uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
- * Args:   ctx:    pointer to a context object (cannot be NULL).
- * In/Out: seckey: pointer to a 32-byte private key.
- * In:     tweak:  pointer to a 32-byte tweak.
+/** Tweak a secret key by multiplying it by a tweak.
+ *
+ *  Returns: 0 if the arguments are invalid. 1 otherwise.
+ *  Args:   ctx:    pointer to a context object (cannot be NULL).
+ *  In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
+ *                  invalid according to secp256k1_ec_seckey_verify, this
+ *                  function returns 0. seckey will be set to some unspecified
+ *                  value if this function returns 0. (cannot be NULL)
+ *  In:      tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
+ *                  secp256k1_ec_seckey_verify, this function returns 0. For
+ *                  uniformly random 32-byte arrays the chance of being invalid
+ *                  is negligible (around 1 in 2^128) (cannot be NULL).
  */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
+    const secp256k1_context* ctx,
+    unsigned char *seckey,
+    const unsigned char *tweak
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in
+ *  future versions. */
 SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
     const secp256k1_context* ctx,
     unsigned char *seckey,
@@ -642,12 +693,16 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
 /** Tweak a public key by multiplying it by a tweak value.
- * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
- *          uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
- * Args:    ctx:    pointer to a context object initialized for validation
- *                 (cannot be NULL).
- * In/Out:  pubkey: pointer to a public key object.
- * In:      tweak:  pointer to a 32-byte tweak.
+ *
+ *  Returns: 0 if the arguments are invalid. 1 otherwise.
+ *  Args:    ctx:   pointer to a context object initialized for validation
+ *                  (cannot be NULL).
+ *  In/Out: pubkey: pointer to a public key object. pubkey will be set to an
+ *                  invalid value if this function returns 0 (cannot be NULL).
+ *  In:      tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
+ *                  secp256k1_ec_seckey_verify, this function returns 0. For
+ *                  uniformly random 32-byte arrays the chance of being invalid
+ *                  is negligible (around 1 in 2^128) (cannot be NULL).
  */
 SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
     const secp256k1_context* ctx,
@@ -686,6 +741,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
 ) SECP256K1_ARG_NONNULL(1);
 
 /** Add a number of public keys together.
+ *
  *  Returns: 1: the sum of the public keys is valid.
  *           0: the sum of the public keys is not valid.
  *  Args:   ctx:        pointer to a context object
index df5fde235c7b97d802d6abc071d2b54b2497c2b0..4058e9c0436dd430f8cbe8c6a8b63be2a8c5dbc1 100644 (file)
@@ -7,43 +7,50 @@
 extern "C" {
 #endif
 
-/** A pointer to a function that applies hash function to a point
+/** A pointer to a function that hashes an EC point to obtain an ECDH secret
  *
- *  Returns: 1 if a point was successfully hashed. 0 will cause ecdh to fail
- *  Out:    output:     pointer to an array to be filled by the function
- *  In:     x:          pointer to a 32-byte x coordinate
- *          y:          pointer to a 32-byte y coordinate
- *          data:       Arbitrary data pointer that is passed through
+ *  Returns: 1 if the point was successfully hashed.
+ *           0 will cause secp256k1_ecdh to fail and return 0.
+ *           Other return values are not allowed, and the behaviour of
+ *           secp256k1_ecdh is undefined for other return values.
+ *  Out:     output:     pointer to an array to be filled by the function
+ *  In:      x32:        pointer to a 32-byte x coordinate
+ *           y32:        pointer to a 32-byte y coordinate
+ *           data:       arbitrary data pointer that is passed through
  */
 typedef int (*secp256k1_ecdh_hash_function)(
   unsigned char *output,
-  const unsigned char *x,
-  const unsigned char *y,
+  const unsigned char *x32,
+  const unsigned char *y32,
   void *data
 );
 
-/** An implementation of SHA256 hash function that applies to compressed public key. */
+/** An implementation of SHA256 hash function that applies to compressed public key.
+ * Populates the output parameter with 32 bytes. */
 SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
 
-/** A default ecdh hash function (currently equal to secp256k1_ecdh_hash_function_sha256). */
+/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256).
+ * Populates the output parameter with 32 bytes. */
 SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
 
 /** Compute an EC Diffie-Hellman secret in constant time
+ *
  *  Returns: 1: exponentiation was successful
- *           0: scalar was invalid (zero or overflow)
+ *           0: scalar was invalid (zero or overflow) or hashfp returned 0
  *  Args:    ctx:        pointer to a context object (cannot be NULL)
- *  Out:     output:     pointer to an array to be filled by the function
+ *  Out:     output:     pointer to an array to be filled by hashfp
  *  In:      pubkey:     a pointer to a secp256k1_pubkey containing an
  *                       initialized public key
- *           privkey:    a 32-byte scalar with which to multiply the point
+ *           seckey:     a 32-byte scalar with which to multiply the point
  *           hashfp:     pointer to a hash function. If NULL, secp256k1_ecdh_hash_function_sha256 is used
- *           data:       Arbitrary data pointer that is passed through
+ *                       (in which case, 32 bytes will be written to output)
+ *           data:       arbitrary data pointer that is passed through to hashfp
  */
 SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
   const secp256k1_context* ctx,
   unsigned char *output,
   const secp256k1_pubkey *pubkey,
-  const unsigned char *privkey,
+  const unsigned char *seckey,
   secp256k1_ecdh_hash_function hashfp,
   void *data
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
index cf6c5ed7f5e3db97507ed3d68dee95081abe3ddb..f8ccaecd3dfb188b8f73b00ea107b911703f6b58 100644 (file)
@@ -70,7 +70,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
 /** Create a recoverable ECDSA signature.
  *
  *  Returns: 1: signature created
- *           0: the nonce generation function failed, or the private key was invalid.
+ *           0: the nonce generation function failed, or the secret key was invalid.
  *  Args:    ctx:    pointer to a context object, initialized for signing (cannot be NULL)
  *  Out:     sig:    pointer to an array where the signature will be placed (cannot be NULL)
  *  In:      msg32:  the 32-byte message hash being signed (cannot be NULL)
diff --git a/src/assumptions.h b/src/assumptions.h
new file mode 100644 (file)
index 0000000..f9d4e8e
--- /dev/null
@@ -0,0 +1,74 @@
+/**********************************************************************
+ * Copyright (c) 2020 Pieter Wuille                                   *
+ * Distributed under the MIT software license, see the accompanying   *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef SECP256K1_ASSUMPTIONS_H
+#define SECP256K1_ASSUMPTIONS_H
+
+#include "util.h"
+
+/* This library, like most software, relies on a number of compiler implementation defined (but not undefined)
+   behaviours. Although the behaviours we require are essentially universal we test them specifically here to
+   reduce the odds of experiencing an unwelcome surprise.
+*/
+
+struct secp256k1_assumption_checker {
+    /* This uses a trick to implement a static assertion in C89: a type with an array of negative size is not
+       allowed. */
+    int dummy_array[(
+        /* Bytes are 8 bits. */
+        CHAR_BIT == 8 &&
+
+        /* Conversions from unsigned to signed outside of the bounds of the signed type are
+           implementation-defined. Verify that they function as reinterpreting the lower
+           bits of the input in two's complement notation. Do this for conversions:
+           - from uint(N)_t to int(N)_t with negative result
+           - from uint(2N)_t to int(N)_t with negative result
+           - from int(2N)_t to int(N)_t with negative result
+           - from int(2N)_t to int(N)_t with positive result */
+
+        /* To int8_t. */
+        ((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55) &&
+        ((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33) &&
+        ((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF) &&
+        ((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34) &&
+
+        /* To int16_t. */
+        ((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322) &&
+        ((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C) &&
+        ((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4) &&
+        ((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678) &&
+
+        /* To int32_t. */
+        ((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B) &&
+        ((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE) &&
+        ((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8) &&
+        ((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789) &&
+
+        /* To int64_t. */
+        ((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) &&
+#if defined(SECP256K1_WIDEMUL_INT128)
+        ((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) &&
+        (((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) &&
+        (((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) &&
+
+        /* To int128_t. */
+        ((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)) &&
+#endif
+
+        /* Right shift on negative signed values is implementation defined. Verify that it
+           acts as a right shift in two's complement with sign extension (i.e duplicating
+           the top bit into newly added bits). */
+        ((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA) &&
+        ((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) &&
+        ((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) &&
+        ((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) &&
+#if defined(SECP256K1_WIDEMUL_INT128)
+        ((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) &&
+#endif
+    1) * 2 - 1];
+};
+
+#endif /* SECP256K1_ASSUMPTIONS_H */
index e9be39d4ca4d4eaacceef15c605a2a3fd8bb2813..83dbe6f25b0e2fabef3537e476757ce3395536a7 100644 (file)
 #undef USE_ENDOMORPHISM
 #undef USE_EXTERNAL_ASM
 #undef USE_EXTERNAL_DEFAULT_CALLBACKS
-#undef USE_FIELD_10X26
-#undef USE_FIELD_5X52
 #undef USE_FIELD_INV_BUILTIN
 #undef USE_FIELD_INV_NUM
 #undef USE_NUM_GMP
 #undef USE_NUM_NONE
-#undef USE_SCALAR_4X64
-#undef USE_SCALAR_8X32
 #undef USE_SCALAR_INV_BUILTIN
 #undef USE_SCALAR_INV_NUM
+#undef USE_FORCE_WIDEMUL_INT64
+#undef USE_FORCE_WIDEMUL_INT128
 #undef ECMULT_WINDOW_SIZE
 
 #define USE_NUM_NONE 1
 #define USE_FIELD_INV_BUILTIN 1
 #define USE_SCALAR_INV_BUILTIN 1
-#define USE_FIELD_10X26 1
-#define USE_SCALAR_8X32 1
+#define USE_WIDEMUL_64 1
 #define ECMULT_WINDOW_SIZE 15
 
 #endif /* USE_BASIC_CONFIG */
index 5b59783f68a950f61a74372325635ddc1b194326..9bfed903e04e4ec589277cd96b390e840aa2b015 100644 (file)
@@ -7,45 +7,87 @@
 #ifndef SECP256K1_BENCH_H
 #define SECP256K1_BENCH_H
 
+#include <stdint.h>
 #include <stdio.h>
 #include <string.h>
-#include <math.h>
 #include "sys/time.h"
 
-static double gettimedouble(void) {
+static int64_t gettime_i64(void) {
     struct timeval tv;
     gettimeofday(&tv, NULL);
-    return tv.tv_usec * 0.000001 + tv.tv_sec;
+    return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
 }
 
-void print_number(double x) {
-    double y = x;
-    int c = 0;
-    if (y < 0.0) {
-        y = -y;
+#define FP_EXP (6)
+#define FP_MULT (1000000LL)
+
+/* Format fixed point number. */
+void print_number(const int64_t x) {
+    int64_t x_abs, y;
+    int c, i, rounding;
+    size_t ptr;
+    char buffer[30];
+
+    if (x == INT64_MIN) {
+        /* Prevent UB. */
+        printf("ERR");
+        return;
     }
-    while (y > 0 && y < 100.0) {
-        y *= 10.0;
+    x_abs = x < 0 ? -x : x;
+
+    /* Determine how many decimals we want to show (more than FP_EXP makes no
+     * sense). */
+    y = x_abs;
+    c = 0;
+    while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) {
+        y *= 10LL;
         c++;
     }
-    printf("%.*f", c, x);
+
+    /* Round to 'c' decimals. */
+    y = x_abs;
+    rounding = 0;
+    for (i = c; i < FP_EXP; ++i) {
+        rounding = (y % 10) >= 5;
+        y /= 10;
+    }
+    y += rounding;
+
+    /* Format and print the number. */
+    ptr = sizeof(buffer) - 1;
+    buffer[ptr] = 0;
+    if (c != 0) {
+        for (i = 0; i < c; ++i) {
+            buffer[--ptr] = '0' + (y % 10);
+            y /= 10;
+        }
+        buffer[--ptr] = '.';
+    }
+    do {
+        buffer[--ptr] = '0' + (y % 10);
+        y /= 10;
+    } while (y != 0);
+    if (x < 0) {
+        buffer[--ptr] = '-';
+    }
+    printf("%s", &buffer[ptr]);
 }
 
-void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) {
+void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
     int i;
-    double min = HUGE_VAL;
-    double sum = 0.0;
-    double max = 0.0;
+    int64_t min = INT64_MAX;
+    int64_t sum = 0;
+    int64_t max = 0;
     for (i = 0; i < count; i++) {
-        double begin, total;
+        int64_t begin, total;
         if (setup != NULL) {
             setup(data);
         }
-        begin = gettimedouble();
-        benchmark(data);
-        total = gettimedouble() - begin;
+        begin = gettime_i64();
+        benchmark(data, iter);
+        total = gettime_i64() - begin;
         if (teardown != NULL) {
-            teardown(data);
+            teardown(data, iter);
         }
         if (total < min) {
             min = total;
@@ -56,11 +98,11 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v
         sum += total;
     }
     printf("%s: min ", name);
-    print_number(min * 1000000.0 / iter);
+    print_number(min * FP_MULT / iter);
     printf("us / avg ");
-    print_number((sum / count) * 1000000.0 / iter);
+    print_number(((sum * FP_MULT) / count) / iter);
     printf("us / max ");
-    print_number(max * 1000000.0 / iter);
+    print_number(max * FP_MULT / iter);
     printf("us\n");
 }
 
@@ -79,4 +121,13 @@ int have_flag(int argc, char** argv, char *flag) {
     return 0;
 }
 
+int get_iters(int default_iters) {
+    char* env = getenv("SECP256K1_BENCH_ITERS");
+    if (env) {
+        return strtol(env, NULL, 0);
+    } else {
+        return default_iters;
+    }
+}
+
 #endif /* SECP256K1_BENCH_H */
index c1dd5a6ac93c8cbf0c4017673102e09a8ee3c392..f099d33884bcfbb2f4fe4c5e27e0342f3e3a1b47 100644 (file)
@@ -28,20 +28,18 @@ static void bench_ecdh_setup(void* arg) {
         0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
     };
 
-    /* create a context with no capabilities */
-    data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
     for (i = 0; i < 32; i++) {
         data->scalar[i] = i + 1;
     }
     CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1);
 }
 
-static void bench_ecdh(void* arg) {
+static void bench_ecdh(void* arg, int iters) {
     int i;
     unsigned char res[32];
     bench_ecdh_data *data = (bench_ecdh_data*)arg;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1);
     }
 }
@@ -49,6 +47,13 @@ static void bench_ecdh(void* arg) {
 int main(void) {
     bench_ecdh_data data;
 
-    run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000);
+    int iters = get_iters(20000);
+
+    /* create a context with no capabilities */
+    data.ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
+
+    run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, iters);
+
+    secp256k1_context_destroy(data.ctx);
     return 0;
 }
index 7b5d185dce606b4d60a4d115a34cbbf7fd9432ee..facd07ef31b3eeff19a9adc3e9cceb4c69f800b6 100644 (file)
@@ -18,7 +18,6 @@
 #include "secp256k1.c"
 
 #define POINTS 32768
-#define ITERS 10000
 
 typedef struct {
     /* Setup once in advance */
@@ -55,13 +54,13 @@ static int bench_callback(secp256k1_scalar* sc, secp256k1_ge* ge, size_t idx, vo
     return 1;
 }
 
-static void bench_ecmult(void* arg) {
+static void bench_ecmult(void* arg, int iters) {
     bench_data* data = (bench_data*)arg;
 
-    size_t count = data->count;
     int includes_g = data->includes_g;
-    size_t iters = 1 + ITERS / count;
-    size_t iter;
+    int iter;
+    int count = data->count;
+    iters = iters / data->count;
 
     for (iter = 0; iter < iters; ++iter) {
         data->ecmult_multi(&data->ctx->error_callback, &data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g);
@@ -76,10 +75,10 @@ static void bench_ecmult_setup(void* arg) {
     data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS;
 }
 
-static void bench_ecmult_teardown(void* arg) {
+static void bench_ecmult_teardown(void* arg, int iters) {
     bench_data* data = (bench_data*)arg;
-    size_t iters = 1 + ITERS / data->count;
-    size_t iter;
+    int iter;
+    iters = iters / data->count;
     /* Verify the results in teardown, to avoid doing comparisons while benchmarking. */
     for (iter = 0; iter < iters; ++iter) {
         secp256k1_gej tmp;
@@ -104,10 +103,10 @@ static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
     CHECK(!overflow);
 }
 
-static void run_test(bench_data* data, size_t count, int includes_g) {
+static void run_test(bench_data* data, size_t count, int includes_g, int num_iters) {
     char str[32];
     static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
-    size_t iters = 1 + ITERS / count;
+    size_t iters = 1 + num_iters / count;
     size_t iter;
 
     data->count = count;
@@ -130,7 +129,7 @@ static void run_test(bench_data* data, size_t count, int includes_g) {
 
     /* Run the benchmark. */
     sprintf(str, includes_g ? "ecmult_%ig" : "ecmult_%i", (int)count);
-    run_benchmark(str, bench_ecmult, bench_ecmult_setup, bench_ecmult_teardown, data, 10, count * (1 + ITERS / count));
+    run_benchmark(str, bench_ecmult, bench_ecmult_setup, bench_ecmult_teardown, data, 10, count * iters);
 }
 
 int main(int argc, char **argv) {
@@ -139,6 +138,8 @@ int main(int argc, char **argv) {
     secp256k1_gej* pubkeys_gej;
     size_t scratch_size;
 
+    int iters = get_iters(10000);
+
     data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
     scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
     data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
@@ -167,8 +168,8 @@ int main(int argc, char **argv) {
     data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS);
     data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS);
     data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS);
-    data.expected_output = malloc(sizeof(secp256k1_gej) * (ITERS + 1));
-    data.output = malloc(sizeof(secp256k1_gej) * (ITERS + 1));
+    data.expected_output = malloc(sizeof(secp256k1_gej) * (iters + 1));
+    data.output = malloc(sizeof(secp256k1_gej) * (iters + 1));
 
     /* Generate a set of scalars, and private/public keypairs. */
     pubkeys_gej = malloc(sizeof(secp256k1_gej) * POINTS);
@@ -185,14 +186,20 @@ int main(int argc, char **argv) {
     free(pubkeys_gej);
 
     for (i = 1; i <= 8; ++i) {
-        run_test(&data, i, 1);
+        run_test(&data, i, 1, iters);
     }
 
-    for (p = 0; p <= 11; ++p) {
-        for (i = 9; i <= 16; ++i) {
-            run_test(&data, i << p, 1);
+    /* This is disabled with low count of iterations because the loop runs 77 times even with iters=1
+    * and the higher it goes the longer the computation takes(more points)
+    * So we don't run this benchmark with low iterations to prevent slow down */
+     if (iters > 2) {
+        for (p = 0; p <= 11; ++p) {
+            for (i = 9; i <= 16; ++i) {
+                run_test(&data, i << p, 1, iters);
+            }
         }
     }
+
     if (data.scratch != NULL) {
         secp256k1_scratch_space_destroy(data.ctx, data.scratch);
     }
index 9159c0a7c3a95abaaa05655bb5e64477b4d15ff8..cb8368ddff62892b1ace397037bd870648844355 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "include/secp256k1.h"
 
+#include "assumptions.h"
 #include "util.h"
 #include "hash_impl.h"
 #include "num_impl.h"
@@ -56,271 +57,271 @@ void bench_setup(void* arg) {
     memcpy(data->data + 32, init_y, 32);
 }
 
-void bench_scalar_add(void* arg) {
+void bench_scalar_add(void* arg, int iters) {
     int i, j = 0;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 2000000; i++) {
+    for (i = 0; i < iters; i++) {
         j += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
     }
-    CHECK(j <= 2000000);
+    CHECK(j <= iters);
 }
 
-void bench_scalar_negate(void* arg) {
+void bench_scalar_negate(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 2000000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x);
     }
 }
 
-void bench_scalar_sqr(void* arg) {
+void bench_scalar_sqr(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 200000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x);
     }
 }
 
-void bench_scalar_mul(void* arg) {
+void bench_scalar_mul(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 200000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y);
     }
 }
 
 #ifdef USE_ENDOMORPHISM
-void bench_scalar_split(void* arg) {
+void bench_scalar_split(void* arg, int iters) {
     int i, j = 0;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_scalar_split_lambda(&data->scalar_x, &data->scalar_y, &data->scalar_x);
         j += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
     }
-    CHECK(j <= 20000);
+    CHECK(j <= iters);
 }
 #endif
 
-void bench_scalar_inverse(void* arg) {
+void bench_scalar_inverse(void* arg, int iters) {
     int i, j = 0;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 2000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x);
         j += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
     }
-    CHECK(j <= 2000);
+    CHECK(j <= iters);
 }
 
-void bench_scalar_inverse_var(void* arg) {
+void bench_scalar_inverse_var(void* arg, int iters) {
     int i, j = 0;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 2000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x);
         j += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
     }
-    CHECK(j <= 2000);
+    CHECK(j <= iters);
 }
 
-void bench_field_normalize(void* arg) {
+void bench_field_normalize(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 2000000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_fe_normalize(&data->fe_x);
     }
 }
 
-void bench_field_normalize_weak(void* arg) {
+void bench_field_normalize_weak(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 2000000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_fe_normalize_weak(&data->fe_x);
     }
 }
 
-void bench_field_mul(void* arg) {
+void bench_field_mul(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 200000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y);
     }
 }
 
-void bench_field_sqr(void* arg) {
+void bench_field_sqr(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 200000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_fe_sqr(&data->fe_x, &data->fe_x);
     }
 }
 
-void bench_field_inverse(void* arg) {
+void bench_field_inverse(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_fe_inv(&data->fe_x, &data->fe_x);
         secp256k1_fe_add(&data->fe_x, &data->fe_y);
     }
 }
 
-void bench_field_inverse_var(void* arg) {
+void bench_field_inverse_var(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_fe_inv_var(&data->fe_x, &data->fe_x);
         secp256k1_fe_add(&data->fe_x, &data->fe_y);
     }
 }
 
-void bench_field_sqrt(void* arg) {
+void bench_field_sqrt(void* arg, int iters) {
     int i, j = 0;
     bench_inv *data = (bench_inv*)arg;
     secp256k1_fe t;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         t = data->fe_x;
         j += secp256k1_fe_sqrt(&data->fe_x, &t);
         secp256k1_fe_add(&data->fe_x, &data->fe_y);
     }
-    CHECK(j <= 20000);
+    CHECK(j <= iters);
 }
 
-void bench_group_double_var(void* arg) {
+void bench_group_double_var(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 200000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL);
     }
 }
 
-void bench_group_add_var(void* arg) {
+void bench_group_add_var(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 200000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL);
     }
 }
 
-void bench_group_add_affine(void* arg) {
+void bench_group_add_affine(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 200000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y);
     }
 }
 
-void bench_group_add_affine_var(void* arg) {
+void bench_group_add_affine_var(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 200000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL);
     }
 }
 
-void bench_group_jacobi_var(void* arg) {
+void bench_group_jacobi_var(void* arg, int iters) {
     int i, j = 0;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         j += secp256k1_gej_has_quad_y_var(&data->gej_x);
     }
-    CHECK(j == 20000);
+    CHECK(j == iters);
 }
 
-void bench_ecmult_wnaf(void* arg) {
+void bench_ecmult_wnaf(void* arg, int iters) {
     int i, bits = 0, overflow = 0;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         bits += secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A);
         overflow += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
     }
     CHECK(overflow >= 0);
-    CHECK(bits <= 256*20000);
+    CHECK(bits <= 256*iters);
 }
 
-void bench_wnaf_const(void* arg) {
+void bench_wnaf_const(void* arg, int iters) {
     int i, bits = 0, overflow = 0;
     bench_inv *data = (bench_inv*)arg;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         bits += secp256k1_wnaf_const(data->wnaf, &data->scalar_x, WINDOW_A, 256);
         overflow += secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
     }
     CHECK(overflow >= 0);
-    CHECK(bits <= 256*20000);
+    CHECK(bits <= 256*iters);
 }
 
 
-void bench_sha256(void* arg) {
+void bench_sha256(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
     secp256k1_sha256 sha;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_sha256_initialize(&sha);
         secp256k1_sha256_write(&sha, data->data, 32);
         secp256k1_sha256_finalize(&sha, data->data);
     }
 }
 
-void bench_hmac_sha256(void* arg) {
+void bench_hmac_sha256(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
     secp256k1_hmac_sha256 hmac;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_hmac_sha256_initialize(&hmac, data->data, 32);
         secp256k1_hmac_sha256_write(&hmac, data->data, 32);
         secp256k1_hmac_sha256_finalize(&hmac, data->data);
     }
 }
 
-void bench_rfc6979_hmac_sha256(void* arg) {
+void bench_rfc6979_hmac_sha256(void* arg, int iters) {
     int i;
     bench_inv *data = (bench_inv*)arg;
     secp256k1_rfc6979_hmac_sha256 rng;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64);
         secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32);
     }
 }
 
-void bench_context_verify(void* arg) {
+void bench_context_verify(void* arg, int iters) {
     int i;
     (void)arg;
-    for (i = 0; i < 20; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY));
     }
 }
 
-void bench_context_sign(void* arg) {
+void bench_context_sign(void* arg, int iters) {
     int i;
     (void)arg;
-    for (i = 0; i < 200; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN));
     }
 }
 
 #ifndef USE_NUM_NONE
-void bench_num_jacobi(void* arg) {
+void bench_num_jacobi(void* arg, int iters) {
     int i, j = 0;
     bench_inv *data = (bench_inv*)arg;
     secp256k1_num nx, norder;
@@ -329,51 +330,53 @@ void bench_num_jacobi(void* arg) {
     secp256k1_scalar_order_get_num(&norder);
     secp256k1_scalar_get_num(&norder, &data->scalar_y);
 
-    for (i = 0; i < 200000; i++) {
+    for (i = 0; i < iters; i++) {
         j += secp256k1_num_jacobi(&nx, &norder);
     }
-    CHECK(j <= 200000);
+    CHECK(j <= iters);
 }
 #endif
 
 int main(int argc, char **argv) {
     bench_inv data;
-    if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000);
-    if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000);
-    if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000);
-    if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000);
+    int iters = get_iters(20000);
+
+    if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100);
+    if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100);
+    if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, iters*10);
+    if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10);
 #ifdef USE_ENDOMORPHISM
-    if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, 20000);
+    if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters);
 #endif
     if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000);
     if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000);
 
-    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000);
-    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000);
-    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, 200000);
-    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000);
-    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000);
-    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000);
-    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000);
+    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, iters*100);
+    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, iters*100);
+    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10);
+    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10);
+    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters);
+    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters);
+    if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters);
 
-    if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000);
-    if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000);
-    if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000);
-    if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000);
-    if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000);
+    if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10);
+    if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, iters*10);
+    if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, iters*10);
+    if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, iters*10);
+    if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, iters);
 
-    if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000);
-    if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000);
+    if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, iters);
+    if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters);
 
-    if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000);
-    if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000);
-    if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000);
+    if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, iters);
+    if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, iters);
+    if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, iters);
 
-    if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20);
-    if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200);
+    if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 1 + iters/1000);
+    if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 1 + iters/100);
 
 #ifndef USE_NUM_NONE
-    if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000);
+    if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, iters*10);
 #endif
     return 0;
 }
index b806eed94e1501becbdfc1d89a741e2ec6076276..e952ed1215ed12bb7ef28ead6275262d75293dc7 100644 (file)
@@ -15,13 +15,13 @@ typedef struct {
     unsigned char sig[64];
 } bench_recover_data;
 
-void bench_recover(void* arg) {
+void bench_recover(void* arg, int iters) {
     int i;
     bench_recover_data *data = (bench_recover_data*)arg;
     secp256k1_pubkey pubkey;
     unsigned char pubkeyc[33];
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         int j;
         size_t pubkeylen = 33;
         secp256k1_ecdsa_recoverable_signature sig;
@@ -51,9 +51,11 @@ void bench_recover_setup(void* arg) {
 int main(void) {
     bench_recover_data data;
 
+    int iters = get_iters(20000);
+
     data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
 
-    run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000);
+    run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, iters);
 
     secp256k1_context_destroy(data.ctx);
     return 0;
index 544b43963c8d10d08aaddbd748abaaf181296223..c6b2942cc0c9bdc062b97bbadb24f531b9bedc1e 100644 (file)
@@ -26,12 +26,12 @@ static void bench_sign_setup(void* arg) {
     }
 }
 
-static void bench_sign_run(void* arg) {
+static void bench_sign_run(void* arg, int iters) {
     int i;
     bench_sign *data = (bench_sign*)arg;
 
     unsigned char sig[74];
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         size_t siglen = 74;
         int j;
         secp256k1_ecdsa_signature signature;
@@ -47,9 +47,11 @@ static void bench_sign_run(void* arg) {
 int main(void) {
     bench_sign data;
 
+    int iters = get_iters(20000);
+
     data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
 
-    run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, 20000);
+    run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
 
     secp256k1_context_destroy(data.ctx);
     return 0;
index 418defa0aa22a06dff07d3f1567e205235706976..272d3e5cc4b4c19addc8eb3c977502872918d8f0 100644 (file)
@@ -17,6 +17,7 @@
 #include <openssl/obj_mac.h>
 #endif
 
+
 typedef struct {
     secp256k1_context *ctx;
     unsigned char msg[32];
@@ -30,11 +31,11 @@ typedef struct {
 #endif
 } benchmark_verify_t;
 
-static void benchmark_verify(void* arg) {
+static void benchmark_verify(void* arg, int iters) {
     int i;
     benchmark_verify_t* data = (benchmark_verify_t*)arg;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         secp256k1_pubkey pubkey;
         secp256k1_ecdsa_signature sig;
         data->sig[data->siglen - 1] ^= (i & 0xFF);
@@ -50,11 +51,11 @@ static void benchmark_verify(void* arg) {
 }
 
 #ifdef ENABLE_OPENSSL_TESTS
-static void benchmark_verify_openssl(void* arg) {
+static void benchmark_verify_openssl(void* arg, int iters) {
     int i;
     benchmark_verify_t* data = (benchmark_verify_t*)arg;
 
-    for (i = 0; i < 20000; i++) {
+    for (i = 0; i < iters; i++) {
         data->sig[data->siglen - 1] ^= (i & 0xFF);
         data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
         data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
@@ -85,6 +86,8 @@ int main(void) {
     secp256k1_ecdsa_signature sig;
     benchmark_verify_t data;
 
+    int iters = get_iters(20000);
+
     data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
 
     for (i = 0; i < 32; i++) {
@@ -100,10 +103,10 @@ int main(void) {
     data.pubkeylen = 33;
     CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
 
-    run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
+    run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, iters);
 #ifdef ENABLE_OPENSSL_TESTS
     data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1);
-    run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000);
+    run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, iters);
     EC_GROUP_free(data.ec_group);
 #endif
 
index eb099c87dc83fe0898814a8de5e4edaeeeb8f448..5f54b59faa693bc4742d11ad72750ca92b4e1a34 100644 (file)
@@ -280,6 +280,7 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
     secp256k1_ge r;
     secp256k1_scalar n;
     int overflow = 0;
+    int high;
 
     secp256k1_ecmult_gen(ctx, &rp, nonce);
     secp256k1_ge_set_gej(&r, &rp);
@@ -287,15 +288,11 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
     secp256k1_fe_normalize(&r.y);
     secp256k1_fe_get_b32(b, &r.x);
     secp256k1_scalar_set_b32(sigr, b, &overflow);
-    /* These two conditions should be checked before calling */
-    VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr));
-    VERIFY_CHECK(overflow == 0);
-
     if (recid) {
         /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log
          * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria.
          */
-        *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
+        *recid = (overflow << 1) | secp256k1_fe_is_odd(&r.y);
     }
     secp256k1_scalar_mul(&n, sigr, seckey);
     secp256k1_scalar_add(&n, &n, message);
@@ -304,16 +301,15 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
     secp256k1_scalar_clear(&n);
     secp256k1_gej_clear(&rp);
     secp256k1_ge_clear(&r);
-    if (secp256k1_scalar_is_zero(sigs)) {
-        return 0;
-    }
-    if (secp256k1_scalar_is_high(sigs)) {
-        secp256k1_scalar_negate(sigs, sigs);
-        if (recid) {
-            *recid ^= 1;
-        }
+    high = secp256k1_scalar_is_high(sigs);
+    secp256k1_scalar_cond_negate(sigs, high);
+    if (recid) {
+            *recid ^= high;
     }
-    return 1;
+    /* P.x = order is on the curve, so technically sig->r could end up being zero, which would be an invalid signature.
+     * This is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N.
+     */
+    return !secp256k1_scalar_is_zero(sigr) & !secp256k1_scalar_is_zero(sigs);
 }
 
 #endif /* SECP256K1_ECDSA_IMPL_H */
index 7c5b789325f40d2886ff28ede70ab4ff436700b8..e2e72d93039a72b1ba1837b3b5e392f4ea28759e 100644 (file)
@@ -54,10 +54,7 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p
 
 static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
     secp256k1_scalar_add(key, key, tweak);
-    if (secp256k1_scalar_is_zero(key)) {
-        return 0;
-    }
-    return 1;
+    return !secp256k1_scalar_is_zero(key);
 }
 
 static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {
@@ -75,12 +72,11 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx,
 }
 
 static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
-    if (secp256k1_scalar_is_zero(tweak)) {
-        return 0;
-    }
+    int ret;
+    ret = !secp256k1_scalar_is_zero(tweak);
 
     secp256k1_scalar_mul(key, key, tweak);
-    return 1;
+    return ret;
 }
 
 static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {
index aaa576ada4cc22bb2bb3a784d0c2514e8aeccead..55b61e49372cbc68d57464b4e59fd1cc72eacf6d 100644 (file)
 
 /* This is like `ECMULT_TABLE_GET_GE` but is constant time */
 #define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
-    int m; \
-    int abs_n = (n) * (((n) > 0) * 2 - 1); \
-    int idx_n = abs_n / 2; \
+    int m = 0; \
+    /* Extract the sign-bit for a constant time absolute-value. */ \
+    int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
+    int abs_n = ((n) + mask) ^ mask; \
+    int idx_n = abs_n >> 1; \
     secp256k1_fe neg_y; \
     VERIFY_CHECK(((n) & 1) == 1); \
     VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
     VERIFY_CHECK((n) <=  ((1 << ((w)-1)) - 1)); \
     VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \
     VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \
-    for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \
+    /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one \
+     * or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \
+    (r)->x = (pre)[m].x; \
+    (r)->y = (pre)[m].y; \
+    for (m = 1; m < ECMULT_TABLE_SIZE(w); m++) { \
         /* This loop is used to avoid secret data in array indices. See
          * the comment in ecmult_gen_impl.h for rationale. */ \
         secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \
@@ -44,7 +50,7 @@
  *
  *  Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar
  *  Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.)
- *  CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003
+ *  CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlag Berlin Heidelberg 2003
  *
  *  Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
  */
@@ -99,16 +105,22 @@ static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w
     /* 4 */
     u_last = secp256k1_scalar_shr_int(&s, w);
     do {
-        int sign;
         int even;
 
         /* 4.1 4.4 */
         u = secp256k1_scalar_shr_int(&s, w);
         /* 4.2 */
         even = ((u & 1) == 0);
-        sign = 2 * (u_last > 0) - 1;
-        u += sign * even;
-        u_last -= sign * even * (1 << w);
+        /* In contrast to the original algorithm, u_last is always > 0 and
+         * therefore we do not need to check its sign. In particular, it's easy
+         * to see that u_last is never < 0 because u is never < 0. Moreover,
+         * u_last is never = 0 because u is never even after a loop
+         * iteration. The same holds analogously for the initial value of
+         * u_last (in the first loop iteration). */
+        VERIFY_CHECK(u_last > 0);
+        VERIFY_CHECK((u_last & 1) == 1);
+        u += even;
+        u_last -= even * (1 << w);
 
         /* 4.3, adapted for global sign change */
         wnaf[word++] = u_last * global_sign;
@@ -172,6 +184,7 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
         for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
             secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
         }
+
     }
 #endif
 
@@ -195,7 +208,7 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
         int n;
         int j;
         for (j = 0; j < WINDOW_A - 1; ++j) {
-            secp256k1_gej_double_nonzero(r, r, NULL);
+            secp256k1_gej_double(r, r);
         }
 
         n = wnaf_1[i];
index a1b96393939e2b99a9b0bd88c1024e3cbaa27459..30ac16518bf4872cca6fe7d783851d59b0164230 100644 (file)
@@ -163,7 +163,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
     secp256k1_fe s;
     unsigned char nonce32[32];
     secp256k1_rfc6979_hmac_sha256 rng;
-    int retry;
+    int overflow;
     unsigned char keydata[64] = {0};
     if (seed32 == NULL) {
         /* When seed is NULL, reset the initial point and blinding value. */
@@ -183,21 +183,18 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
     }
     secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32);
     memset(keydata, 0, sizeof(keydata));
-    /* Retry for out of range results to achieve uniformity. */
-    do {
-        secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
-        retry = !secp256k1_fe_set_b32(&s, nonce32);
-        retry = retry || secp256k1_fe_is_zero(&s);
-    } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */
+    /* Accept unobservably small non-uniformity. */
+    secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
+    overflow = !secp256k1_fe_set_b32(&s, nonce32);
+    overflow |= secp256k1_fe_is_zero(&s);
+    secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
     /* Randomize the projection to defend against multiplier sidechannels. */
     secp256k1_gej_rescale(&ctx->initial, &s);
     secp256k1_fe_clear(&s);
-    do {
-        secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
-        secp256k1_scalar_set_b32(&b, nonce32, &retry);
-        /* A blinding value of 0 works, but would undermine the projection hardening. */
-        retry = retry || secp256k1_scalar_is_zero(&b);
-    } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */
+    secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
+    secp256k1_scalar_set_b32(&b, nonce32, NULL);
+    /* A blinding value of 0 works, but would undermine the projection hardening. */
+    secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
     secp256k1_rfc6979_hmac_sha256_finalize(&rng);
     memset(nonce32, 0, 32);
     secp256k1_ecmult_gen(ctx, &gb, &b);
index bb6692ad57835498257a492028e1646d7cc584f5..aca1fb72c5084e99b44056d5dd979d5252889743 100644 (file)
 #include "libsecp256k1-config.h"
 #endif
 
-#if defined(USE_FIELD_10X26)
-#include "field_10x26.h"
-#elif defined(USE_FIELD_5X52)
+#include "util.h"
+
+#if defined(SECP256K1_WIDEMUL_INT128)
 #include "field_5x52.h"
+#elif defined(SECP256K1_WIDEMUL_INT64)
+#include "field_10x26.h"
 #else
-#error "Please select field implementation"
+#error "Please select wide multiplication implementation"
 #endif
 
-#include "util.h"
-
-/** Normalize a field element. */
+/** Normalize a field element. This brings the field element to a canonical representation, reduces
+ *  its magnitude to 1, and reduces it modulo field size `p`.
+ */
 static void secp256k1_fe_normalize(secp256k1_fe *r);
 
-/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */
+/** Weakly normalize a field element: reduce its magnitude to 1, but don't fully normalize. */
 static void secp256k1_fe_normalize_weak(secp256k1_fe *r);
 
 /** Normalize a field element, without constant-time guarantee. */
@@ -123,10 +125,10 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe
 /** Convert a field element back from the storage type. */
 static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
 
-/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
+/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time.  Both *r and *a must be initialized.*/
 static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
 
-/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
+/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time.  Both *r and *a must be initialized.*/
 static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
 
 #endif /* SECP256K1_FIELD_H */
index 4ae4fdcec884c124a81e45fa1226a17ce3585842..651500ee8eb90bdf54e058ea201ab4da1c912fd4 100644 (file)
@@ -320,6 +320,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
 }
 
 static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
+    int ret;
     r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24);
     r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22);
     r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20);
@@ -331,15 +332,17 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
     r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24);
     r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14);
 
-    if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) {
-        return 0;
-    }
+    ret = !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));
 #ifdef VERIFY
     r->magnitude = 1;
-    r->normalized = 1;
-    secp256k1_fe_verify(r);
+    if (ret) {
+        r->normalized = 1;
+        secp256k1_fe_verify(r);
+    } else {
+        r->normalized = 0;
+    }
 #endif
-    return 1;
+    return ret;
 }
 
 /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
@@ -1094,6 +1097,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
 
 static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
     uint32_t mask0, mask1;
+    VG_CHECK_VERIFY(r->n, sizeof(r->n));
     mask0 = flag + ~((uint32_t)0);
     mask1 = ~mask0;
     r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -1107,15 +1111,16 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
     r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);
     r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);
 #ifdef VERIFY
-    if (a->magnitude > r->magnitude) {
+    if (flag) {
         r->magnitude = a->magnitude;
+        r->normalized = a->normalized;
     }
-    r->normalized &= a->normalized;
 #endif
 }
 
 static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
     uint32_t mask0, mask1;
+    VG_CHECK_VERIFY(r->n, sizeof(r->n));
     mask0 = flag + ~((uint32_t)0);
     mask1 = ~mask0;
     r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
index fc5bfe357e705d75b1185aa88f9017be2f37cc8e..6a068484c28a0d386fd62cfad107e3ca1b15ae02 100644 (file)
@@ -46,4 +46,10 @@ typedef struct {
     (d6) | (((uint64_t)(d7)) << 32) \
 }}
 
+#define SECP256K1_FE_STORAGE_CONST_GET(d) \
+    (uint32_t)(d.n[3] >> 32), (uint32_t)d.n[3], \
+    (uint32_t)(d.n[2] >> 32), (uint32_t)d.n[2], \
+    (uint32_t)(d.n[1] >> 32), (uint32_t)d.n[1], \
+    (uint32_t)(d.n[0] >> 32), (uint32_t)d.n[0]
+
 #endif /* SECP256K1_FIELD_REPR_H */
index f4263320d510065c74808638a20ca85c09cc6abf..71a38f915b2f462cd2ac6c8a749a62689a490408 100644 (file)
@@ -283,6 +283,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
 }
 
 static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
+    int ret;
     r->n[0] = (uint64_t)a[31]
             | ((uint64_t)a[30] << 8)
             | ((uint64_t)a[29] << 16)
@@ -317,15 +318,17 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
             | ((uint64_t)a[2] << 24)
             | ((uint64_t)a[1] << 32)
             | ((uint64_t)a[0] << 40);
-    if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) {
-        return 0;
-    }
+    ret = !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
 #ifdef VERIFY
     r->magnitude = 1;
-    r->normalized = 1;
-    secp256k1_fe_verify(r);
+    if (ret) {
+        r->normalized = 1;
+        secp256k1_fe_verify(r);
+    } else {
+        r->normalized = 0;
+    }
 #endif
-    return 1;
+    return ret;
 }
 
 /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
@@ -446,6 +449,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
 
 static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
     uint64_t mask0, mask1;
+    VG_CHECK_VERIFY(r->n, sizeof(r->n));
     mask0 = flag + ~((uint64_t)0);
     mask1 = ~mask0;
     r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -454,15 +458,16 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
     r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
     r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
 #ifdef VERIFY
-    if (a->magnitude > r->magnitude) {
+    if (flag) {
         r->magnitude = a->magnitude;
+        r->normalized = a->normalized;
     }
-    r->normalized &= a->normalized;
 #endif
 }
 
 static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
     uint64_t mask0, mask1;
+    VG_CHECK_VERIFY(r->n, sizeof(r->n));
     mask0 = flag + ~((uint64_t)0);
     mask1 = ~mask0;
     r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
index 6070caccfeaad68d387207e2c4de758202ca77f0..18e4d2f30ea66450e9de4020d6e7a26d337e9985 100644 (file)
 #include "util.h"
 #include "num.h"
 
-#if defined(USE_FIELD_10X26)
-#include "field_10x26_impl.h"
-#elif defined(USE_FIELD_5X52)
+#if defined(SECP256K1_WIDEMUL_INT128)
 #include "field_5x52_impl.h"
+#elif defined(SECP256K1_WIDEMUL_INT64)
+#include "field_10x26_impl.h"
 #else
-#error "Please select field implementation"
+#error "Please select wide multiplication implementation"
 #endif
 
 SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
@@ -315,4 +315,6 @@ static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
 #endif
 }
 
+static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+
 #endif /* SECP256K1_FIELD_IMPL_H */
index 539f574bfd0c690be1e939748bf86249305c981e..8b7729aee4c8d4c15f82fa8e2592a136d59cabad 100644 (file)
@@ -13,6 +13,7 @@
 #include "basic-config.h"
 
 #include "include/secp256k1.h"
+#include "assumptions.h"
 #include "util.h"
 #include "field_impl.h"
 #include "scalar_impl.h"
index 8e122ab429c56365d89f39c6d55d786e2766e7fe..6185be052db065e4c42e085e1889dbae5aa10429 100644 (file)
@@ -95,14 +95,13 @@ static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
 /** Check whether a group element's y coordinate is a quadratic residue. */
 static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a);
 
-/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0).
- * a may not be zero. Constant time. */
-static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
+/** Set r equal to the double of a. Constant time. */
+static void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a);
 
-/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */
+/** Set r equal to the double of a. If rzr is not-NULL this sets *rzr such that r->z == a->z * *rzr (where infinity means an implicit z = 0). */
 static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
 
-/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
+/** Set r equal to the sum of a and b. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */
 static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr);
 
 /** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */
@@ -110,7 +109,7 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
 
 /** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient
     than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time
-    guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
+    guarantee, and b is allowed to be infinity. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */
 static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr);
 
 /** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */
@@ -133,7 +132,7 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge
 /** Convert a group element back from the storage type. */
 static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a);
 
-/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
+/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time.  Both *r and *a must be initialized.*/
 static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag);
 
 /** Rescale a jacobian point by b which must be non-zero. Constant-time. */
index ade7a593063c632d7a46eaa1fcb5de84e159740e..ccd93d3483ab6e464049889cc7b06b1239a0e1db 100644 (file)
@@ -303,7 +303,7 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
     return secp256k1_fe_equal_var(&y2, &x3);
 }
 
-static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
+static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) {
     /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
      *
      * Note that there is an implementation described at
@@ -312,29 +312,8 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
      * mainly because it requires more normalizations.
      */
     secp256k1_fe t1,t2,t3,t4;
-    /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
-     *  Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
-     *  y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
-     *
-     *  Having said this, if this function receives a point on a sextic twist, e.g. by
-     *  a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
-     *  since -6 does have a cube root mod p. For this point, this function will not set
-     *  the infinity flag even though the point doubles to infinity, and the result
-     *  point will be gibberish (z = 0 but infinity = 0).
-     */
-    r->infinity = a->infinity;
-    if (r->infinity) {
-        if (rzr != NULL) {
-            secp256k1_fe_set_int(rzr, 1);
-        }
-        return;
-    }
 
-    if (rzr != NULL) {
-        *rzr = a->y;
-        secp256k1_fe_normalize_weak(rzr);
-        secp256k1_fe_mul_int(rzr, 2);
-    }
+    r->infinity = a->infinity;
 
     secp256k1_fe_mul(&r->z, &a->z, &a->y);
     secp256k1_fe_mul_int(&r->z, 2);       /* Z' = 2*Y*Z (2) */
@@ -358,9 +337,32 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
     secp256k1_fe_add(&r->y, &t2);         /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
 }
 
-static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
-    VERIFY_CHECK(!secp256k1_gej_is_infinity(a));
-    secp256k1_gej_double_var(r, a, rzr);
+static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
+    /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
+     *  Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
+     *  y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
+     *
+     *  Having said this, if this function receives a point on a sextic twist, e.g. by
+     *  a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
+     *  since -6 does have a cube root mod p. For this point, this function will not set
+     *  the infinity flag even though the point doubles to infinity, and the result
+     *  point will be gibberish (z = 0 but infinity = 0).
+     */
+    if (a->infinity) {
+        r->infinity = 1;
+        if (rzr != NULL) {
+            secp256k1_fe_set_int(rzr, 1);
+        }
+        return;
+    }
+
+    if (rzr != NULL) {
+        *rzr = a->y;
+        secp256k1_fe_normalize_weak(rzr);
+        secp256k1_fe_mul_int(rzr, 2);
+    }
+
+    secp256k1_gej_double(r, a);
 }
 
 static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
index 782f97216c284eff353a339fdd544c49ab2a7911..1985a07836daf2938332ab0588c614d7f3dab880 100644 (file)
@@ -8,6 +8,7 @@
 #define SECP256K1_HASH_IMPL_H
 
 #include "hash.h"
+#include "util.h"
 
 #include <stdlib.h>
 #include <stdint.h>
@@ -27,9 +28,9 @@
     (h) = t1 + t2; \
 } while(0)
 
-#ifdef WORDS_BIGENDIAN
+#if defined(SECP256K1_BIG_ENDIAN)
 #define BE32(x) (x)
-#else
+#elif defined(SECP256K1_LITTLE_ENDIAN)
 #define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
 #endif
 
diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java
deleted file mode 100644 (file)
index 1c67802..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- * Copyright 2014-2016 the libsecp256k1 contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.bitcoin;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-import java.math.BigInteger;
-import com.google.common.base.Preconditions;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import static org.bitcoin.NativeSecp256k1Util.*;
-
-/**
- * <p>This class holds native methods to handle ECDSA verification.</p>
- *
- * <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
- *
- * <p>To build secp256k1 for use with bitcoinj, run
- * `./configure --enable-jni --enable-experimental --enable-module-ecdh`
- * and `make` then copy `.libs/libsecp256k1.so` to your system library path
- * or point the JVM to the folder containing it with -Djava.library.path
- * </p>
- */
-public class NativeSecp256k1 {
-
-    private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
-    private static final Lock r = rwl.readLock();
-    private static final Lock w = rwl.writeLock();
-    private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
-    /**
-     * Verifies the given secp256k1 signature in native code.
-     * Calling when enabled == false is undefined (probably library not loaded)
-     *
-     * @param data The data which was signed, must be exactly 32 bytes
-     * @param signature The signature
-     * @param pub The public key which did the signing
-     */
-    public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{
-        Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
-
-        ByteBuffer byteBuff = nativeECDSABuffer.get();
-        if (byteBuff == null || byteBuff.capacity() < 520) {
-            byteBuff = ByteBuffer.allocateDirect(520);
-            byteBuff.order(ByteOrder.nativeOrder());
-            nativeECDSABuffer.set(byteBuff);
-        }
-        byteBuff.rewind();
-        byteBuff.put(data);
-        byteBuff.put(signature);
-        byteBuff.put(pub);
-
-        byte[][] retByteArray;
-
-        r.lock();
-        try {
-          return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
-        } finally {
-          r.unlock();
-        }
-    }
-
-    /**
-     * libsecp256k1 Create an ECDSA signature.
-     *
-     * @param data Message hash, 32 bytes
-     * @param key Secret key, 32 bytes
-     *
-     * Return values
-     * @param sig byte array of signature
-     */
-    public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
-        Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
-
-        ByteBuffer byteBuff = nativeECDSABuffer.get();
-        if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
-            byteBuff = ByteBuffer.allocateDirect(32 + 32);
-            byteBuff.order(ByteOrder.nativeOrder());
-            nativeECDSABuffer.set(byteBuff);
-        }
-        byteBuff.rewind();
-        byteBuff.put(data);
-        byteBuff.put(sec);
-
-        byte[][] retByteArray;
-
-        r.lock();
-        try {
-          retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
-        } finally {
-          r.unlock();
-        }
-
-        byte[] sigArr = retByteArray[0];
-        int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
-        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
-
-        assertEquals(sigArr.length, sigLen, "Got bad signature length.");
-
-        return retVal == 0 ? new byte[0] : sigArr;
-    }
-
-    /**
-     * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
-     *
-     * @param seckey ECDSA Secret key, 32 bytes
-     */
-    public static boolean secKeyVerify(byte[] seckey) {
-        Preconditions.checkArgument(seckey.length == 32);
-
-        ByteBuffer byteBuff = nativeECDSABuffer.get();
-        if (byteBuff == null || byteBuff.capacity() < seckey.length) {
-            byteBuff = ByteBuffer.allocateDirect(seckey.length);
-            byteBuff.order(ByteOrder.nativeOrder());
-            nativeECDSABuffer.set(byteBuff);
-        }
-        byteBuff.rewind();
-        byteBuff.put(seckey);
-
-        r.lock();
-        try {
-          return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;
-        } finally {
-          r.unlock();
-        }
-    }
-
-
-    /**
-     * libsecp256k1 Compute Pubkey - computes public key from secret key
-     *
-     * @param seckey ECDSA Secret key, 32 bytes
-     *
-     * Return values
-     * @param pubkey ECDSA Public key, 33 or 65 bytes
-     */
-    //TODO add a 'compressed' arg
-    public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
-        Preconditions.checkArgument(seckey.length == 32);
-
-        ByteBuffer byteBuff = nativeECDSABuffer.get();
-        if (byteBuff == null || byteBuff.capacity() < seckey.length) {
-            byteBuff = ByteBuffer.allocateDirect(seckey.length);
-            byteBuff.order(ByteOrder.nativeOrder());
-            nativeECDSABuffer.set(byteBuff);
-        }
-        byteBuff.rewind();
-        byteBuff.put(seckey);
-
-        byte[][] retByteArray;
-
-        r.lock();
-        try {
-          retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
-        } finally {
-          r.unlock();
-        }
-
-        byte[] pubArr = retByteArray[0];
-        int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
-        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
-
-        assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
-
-        return retVal == 0 ? new byte[0]: pubArr;
-    }
-
-    /**
-     * libsecp256k1 Cleanup - This destroys the secp256k1 context object
-     * This should be called at the end of the program for proper cleanup of the context.
-     */
-    public static synchronized void cleanup() {
-        w.lock();
-        try {
-          secp256k1_destroy_context(Secp256k1Context.getContext());
-        } finally {
-          w.unlock();
-        }
-    }
-
-    public static long cloneContext() {
-       r.lock();
-       try {
-        return secp256k1_ctx_clone(Secp256k1Context.getContext());
-       } finally { r.unlock(); }
-    }
-
-    /**
-     * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
-     *
-     * @param tweak some bytes to tweak with
-     * @param seckey 32-byte seckey
-     */
-    public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
-        Preconditions.checkArgument(privkey.length == 32);
-
-        ByteBuffer byteBuff = nativeECDSABuffer.get();
-        if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
-            byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
-            byteBuff.order(ByteOrder.nativeOrder());
-            nativeECDSABuffer.set(byteBuff);
-        }
-        byteBuff.rewind();
-        byteBuff.put(privkey);
-        byteBuff.put(tweak);
-
-        byte[][] retByteArray;
-        r.lock();
-        try {
-          retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
-        } finally {
-          r.unlock();
-        }
-
-        byte[] privArr = retByteArray[0];
-
-        int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
-        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
-
-        assertEquals(privArr.length, privLen, "Got bad pubkey length.");
-
-        assertEquals(retVal, 1, "Failed return value check.");
-
-        return privArr;
-    }
-
-    /**
-     * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
-     *
-     * @param tweak some bytes to tweak with
-     * @param seckey 32-byte seckey
-     */
-    public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
-        Preconditions.checkArgument(privkey.length == 32);
-
-        ByteBuffer byteBuff = nativeECDSABuffer.get();
-        if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
-            byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
-            byteBuff.order(ByteOrder.nativeOrder());
-            nativeECDSABuffer.set(byteBuff);
-        }
-        byteBuff.rewind();
-        byteBuff.put(privkey);
-        byteBuff.put(tweak);
-
-        byte[][] retByteArray;
-        r.lock();
-        try {
-          retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
-        } finally {
-          r.unlock();
-        }
-
-        byte[] privArr = retByteArray[0];
-
-        int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
-        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
-
-        assertEquals(privArr.length, privLen, "Got bad pubkey length.");
-
-        assertEquals(retVal, 1, "Failed return value check.");
-
-        return privArr;
-    }
-
-    /**
-     * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
-     *
-     * @param tweak some bytes to tweak with
-     * @param pubkey 32-byte seckey
-     */
-    public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
-        Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
-
-        ByteBuffer byteBuff = nativeECDSABuffer.get();
-        if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
-            byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
-            byteBuff.order(ByteOrder.nativeOrder());
-            nativeECDSABuffer.set(byteBuff);
-        }
-        byteBuff.rewind();
-        byteBuff.put(pubkey);
-        byteBuff.put(tweak);
-
-        byte[][] retByteArray;
-        r.lock();
-        try {
-          retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
-        } finally {
-          r.unlock();
-        }
-
-        byte[] pubArr = retByteArray[0];
-
-        int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
-        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
-
-        assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
-
-        assertEquals(retVal, 1, "Failed return value check.");
-
-        return pubArr;
-    }
-
-    /**
-     * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
-     *
-     * @param tweak some bytes to tweak with
-     * @param pubkey 32-byte seckey
-     */
-    public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
-        Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
-
-        ByteBuffer byteBuff = nativeECDSABuffer.get();
-        if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
-            byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
-            byteBuff.order(ByteOrder.nativeOrder());
-            nativeECDSABuffer.set(byteBuff);
-        }
-        byteBuff.rewind();
-        byteBuff.put(pubkey);
-        byteBuff.put(tweak);
-
-        byte[][] retByteArray;
-        r.lock();
-        try {
-          retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
-        } finally {
-          r.unlock();
-        }
-
-        byte[] pubArr = retByteArray[0];
-
-        int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
-        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
-
-        assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
-
-        assertEquals(retVal, 1, "Failed return value check.");
-
-        return pubArr;
-    }
-
-    /**
-     * libsecp256k1 create ECDH secret - constant time ECDH calculation
-     *
-     * @param seckey byte array of secret key used in exponentiaion
-     * @param pubkey byte array of public key used in exponentiaion
-     */
-    public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
-        Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
-
-        ByteBuffer byteBuff = nativeECDSABuffer.get();
-        if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
-            byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
-            byteBuff.order(ByteOrder.nativeOrder());
-            nativeECDSABuffer.set(byteBuff);
-        }
-        byteBuff.rewind();
-        byteBuff.put(seckey);
-        byteBuff.put(pubkey);
-
-        byte[][] retByteArray;
-        r.lock();
-        try {
-          retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
-        } finally {
-          r.unlock();
-        }
-
-        byte[] resArr = retByteArray[0];
-        int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
-
-        assertEquals(resArr.length, 32, "Got bad result length.");
-        assertEquals(retVal, 1, "Failed return value check.");
-
-        return resArr;
-    }
-
-    /**
-     * libsecp256k1 randomize - updates the context randomization
-     *
-     * @param seed 32-byte random seed
-     */
-    public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
-        Preconditions.checkArgument(seed.length == 32 || seed == null);
-
-        ByteBuffer byteBuff = nativeECDSABuffer.get();
-        if (byteBuff == null || byteBuff.capacity() < seed.length) {
-            byteBuff = ByteBuffer.allocateDirect(seed.length);
-            byteBuff.order(ByteOrder.nativeOrder());
-            nativeECDSABuffer.set(byteBuff);
-        }
-        byteBuff.rewind();
-        byteBuff.put(seed);
-
-        w.lock();
-        try {
-          return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
-        } finally {
-          w.unlock();
-        }
-    }
-
-    private static native long secp256k1_ctx_clone(long context);
-
-    private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
-
-    private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
-
-    private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
-
-    private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
-
-    private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
-
-    private static native void secp256k1_destroy_context(long context);
-
-    private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
-
-    private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
-
-    private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
-
-    private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
-
-    private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
-
-    private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
-
-}
diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java
deleted file mode 100644 (file)
index 710d9f0..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-package org.bitcoin;
-
-import com.google.common.io.BaseEncoding;
-import java.util.Arrays;
-import java.math.BigInteger;
-import static org.bitcoin.NativeSecp256k1Util.*;
-
-/**
- * This class holds test cases defined for testing this library.
- */
-public class NativeSecp256k1Test {
-
-    //TODO improve comments/add more tests
-    /**
-      * This tests verify() for a valid signature
-      */
-    public static void testVerifyPos() throws AssertFailException{
-        boolean result = false;
-        byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
-        byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
-        byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
-
-        result = NativeSecp256k1.verify( data, sig, pub);
-        assertEquals( result, true , "testVerifyPos");
-    }
-
-    /**
-      * This tests verify() for a non-valid signature
-      */
-    public static void testVerifyNeg() throws AssertFailException{
-        boolean result = false;
-        byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
-        byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
-        byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
-
-        result = NativeSecp256k1.verify( data, sig, pub);
-        //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
-        assertEquals( result, false , "testVerifyNeg");
-    }
-
-    /**
-      * This tests secret key verify() for a valid secretkey
-      */
-    public static void testSecKeyVerifyPos() throws AssertFailException{
-        boolean result = false;
-        byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
-
-        result = NativeSecp256k1.secKeyVerify( sec );
-        //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
-        assertEquals( result, true , "testSecKeyVerifyPos");
-    }
-
-    /**
-      * This tests secret key verify() for an invalid secretkey
-      */
-    public static void testSecKeyVerifyNeg() throws AssertFailException{
-        boolean result = false;
-        byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
-
-        result = NativeSecp256k1.secKeyVerify( sec );
-        //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
-        assertEquals( result, false , "testSecKeyVerifyNeg");
-    }
-
-    /**
-      * This tests public key create() for a valid secretkey
-      */
-    public static void testPubKeyCreatePos() throws AssertFailException{
-        byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
-
-        byte[] resultArr = NativeSecp256k1.computePubkey( sec);
-        String pubkeyString = BaseEncoding.base16().encode(resultArr);
-        assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos");
-    }
-
-    /**
-      * This tests public key create() for a invalid secretkey
-      */
-    public static void testPubKeyCreateNeg() throws AssertFailException{
-       byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
-
-       byte[] resultArr = NativeSecp256k1.computePubkey( sec);
-       String pubkeyString = BaseEncoding.base16().encode(resultArr);
-       assertEquals( pubkeyString, "" , "testPubKeyCreateNeg");
-    }
-
-    /**
-      * This tests sign() for a valid secretkey
-      */
-    public static void testSignPos() throws AssertFailException{
-
-        byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
-        byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
-
-        byte[] resultArr = NativeSecp256k1.sign(data, sec);
-        String sigString = BaseEncoding.base16().encode(resultArr);
-        assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
-    }
-
-    /**
-      * This tests sign() for a invalid secretkey
-      */
-    public static void testSignNeg() throws AssertFailException{
-        byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
-        byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
-
-        byte[] resultArr = NativeSecp256k1.sign(data, sec);
-        String sigString = BaseEncoding.base16().encode(resultArr);
-        assertEquals( sigString, "" , "testSignNeg");
-    }
-
-    /**
-      * This tests private key tweak-add
-      */
-    public static void testPrivKeyTweakAdd_1() throws AssertFailException {
-        byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
-        byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
-
-        byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data );
-        String sigString = BaseEncoding.base16().encode(resultArr);
-        assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1");
-    }
-
-    /**
-      * This tests private key tweak-mul
-      */
-    public static void testPrivKeyTweakMul_1() throws AssertFailException {
-        byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
-        byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
-
-        byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data );
-        String sigString = BaseEncoding.base16().encode(resultArr);
-        assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1");
-    }
-
-    /**
-      * This tests private key tweak-add uncompressed
-      */
-    public static void testPrivKeyTweakAdd_2() throws AssertFailException {
-        byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
-        byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
-
-        byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data );
-        String sigString = BaseEncoding.base16().encode(resultArr);
-        assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2");
-    }
-
-    /**
-      * This tests private key tweak-mul uncompressed
-      */
-    public static void testPrivKeyTweakMul_2() throws AssertFailException {
-        byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
-        byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
-
-        byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data );
-        String sigString = BaseEncoding.base16().encode(resultArr);
-        assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2");
-    }
-
-    /**
-      * This tests seed randomization
-      */
-    public static void testRandomize() throws AssertFailException {
-        byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random"
-        boolean result = NativeSecp256k1.randomize(seed);
-        assertEquals( result, true, "testRandomize");
-    }
-
-    public static void testCreateECDHSecret() throws AssertFailException{
-
-        byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
-        byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
-
-        byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub);
-        String ecdhString = BaseEncoding.base16().encode(resultArr);
-        assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret");
-    }
-
-    public static void main(String[] args) throws AssertFailException{
-
-
-        System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n");
-
-        assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" );
-
-        //Test verify() success/fail
-        testVerifyPos();
-        testVerifyNeg();
-
-        //Test secKeyVerify() success/fail
-        testSecKeyVerifyPos();
-        testSecKeyVerifyNeg();
-
-        //Test computePubkey() success/fail
-        testPubKeyCreatePos();
-        testPubKeyCreateNeg();
-
-        //Test sign() success/fail
-        testSignPos();
-        testSignNeg();
-
-        //Test privKeyTweakAdd() 1
-        testPrivKeyTweakAdd_1();
-
-        //Test privKeyTweakMul() 2
-        testPrivKeyTweakMul_1();
-
-        //Test privKeyTweakAdd() 3
-        testPrivKeyTweakAdd_2();
-
-        //Test privKeyTweakMul() 4
-        testPrivKeyTweakMul_2();
-
-        //Test randomize()
-        testRandomize();
-
-        //Test ECDH
-        testCreateECDHSecret();
-
-        NativeSecp256k1.cleanup();
-
-        System.out.println(" All tests passed." );
-
-    }
-}
diff --git a/src/java/org/bitcoin/NativeSecp256k1Util.java b/src/java/org/bitcoin/NativeSecp256k1Util.java
deleted file mode 100644 (file)
index 04732ba..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2014-2016 the libsecp256k1 contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.bitcoin;
-
-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
deleted file mode 100644 (file)
index 216c986..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2014-2016 the libsecp256k1 contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.bitcoin;
-
-/**
- * This class holds the context reference used in native methods 
- * to handle ECDSA operations.
- */
-public class Secp256k1Context {
-  private static final boolean enabled; //true if the library is loaded
-  private static final long context; //ref to pointer to context obj
-
-  static { //static initializer
-      boolean isEnabled = true;
-      long contextRef = -1;
-      try {
-          System.loadLibrary("secp256k1");
-          contextRef = secp256k1_init_context();
-      } catch (UnsatisfiedLinkError e) {
-          System.out.println("UnsatisfiedLinkError: " + e.toString());
-          isEnabled = false;
-      }
-      enabled = isEnabled;
-      context = contextRef;
-  }
-
-  public static boolean isEnabled() {
-     return enabled;
-  }
-
-  public static long getContext() {
-     if(!enabled) return -1; //sanity check
-     return context;
-  }
-
-  private static native long secp256k1_init_context();
-}
diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c
deleted file mode 100644 (file)
index b590256..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include "org_bitcoin_NativeSecp256k1.h"
-#include "include/secp256k1.h"
-#include "include/secp256k1_ecdh.h"
-#include "include/secp256k1_recovery.h"
-
-
-SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
-  (JNIEnv* env, jclass classObject, jlong ctx_l)
-{
-  const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-
-  jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx);
-
-  (void)classObject;(void)env;
-
-  return ctx_clone_l;
-
-}
-
-SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
-  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
-{
-  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-
-  const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
-
-  (void)classObject;
-
-  return secp256k1_context_randomize(ctx, seed);
-
-}
-
-SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
-  (JNIEnv* env, jclass classObject, jlong ctx_l)
-{
-  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-
-  secp256k1_context_destroy(ctx);
-
-  (void)classObject;(void)env;
-}
-
-SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
-  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen)
-{
-  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-
-  unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
-  const unsigned char* sigdata = {  (unsigned char*) (data + 32) };
-  const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) };
-
-  secp256k1_ecdsa_signature sig;
-  secp256k1_pubkey pubkey;
-
-  int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);
-
-  if( ret ) {
-    ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
-
-    if( ret ) {
-      ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey);
-    }
-  }
-
-  (void)classObject;
-
-  return ret;
-}
-
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
-  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
-{
-  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-  unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
-  unsigned char* secKey = (unsigned char*) (data + 32);
-
-  jobjectArray retArray;
-  jbyteArray sigArray, intsByteArray;
-  unsigned char intsarray[2];
-
-  secp256k1_ecdsa_signature sig;
-
-  int ret = secp256k1_ecdsa_sign(ctx, &sig, data, secKey, NULL, NULL);
-
-  unsigned char outputSer[72];
-  size_t outputLen = 72;
-
-  if( ret ) {
-    int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, &sig ); (void)ret2;
-  }
-
-  intsarray[0] = outputLen;
-  intsarray[1] = ret;
-
-  retArray = (*env)->NewObjectArray(env, 2,
-    (*env)->FindClass(env, "[B"),
-    (*env)->NewByteArray(env, 1));
-
-  sigArray = (*env)->NewByteArray(env, outputLen);
-  (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);
-  (*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
-
-  intsByteArray = (*env)->NewByteArray(env, 2);
-  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
-  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
-
-  (void)classObject;
-
-  return retArray;
-}
-
-SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
-  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
-{
-  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-  unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
-
-  (void)classObject;
-
-  return secp256k1_ec_seckey_verify(ctx, secKey);
-}
-
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
-  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
-{
-  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-  const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
-
-  secp256k1_pubkey pubkey;
-
-  jobjectArray retArray;
-  jbyteArray pubkeyArray, intsByteArray;
-  unsigned char intsarray[2];
-
-  int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey);
-
-  unsigned char outputSer[65];
-  size_t outputLen = 65;
-
-  if( ret ) {
-    int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
-  }
-
-  intsarray[0] = outputLen;
-  intsarray[1] = ret;
-
-  retArray = (*env)->NewObjectArray(env, 2,
-    (*env)->FindClass(env, "[B"),
-    (*env)->NewByteArray(env, 1));
-
-  pubkeyArray = (*env)->NewByteArray(env, outputLen);
-  (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer);
-  (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray);
-
-  intsByteArray = (*env)->NewByteArray(env, 2);
-  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
-  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
-
-  (void)classObject;
-
-  return retArray;
-
-}
-
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
-  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
-{
-  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-  unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
-  const unsigned char* tweak = (unsigned char*) (privkey + 32);
-
-  jobjectArray retArray;
-  jbyteArray privArray, intsByteArray;
-  unsigned char intsarray[2];
-
-  int privkeylen = 32;
-
-  int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak);
-
-  intsarray[0] = privkeylen;
-  intsarray[1] = ret;
-
-  retArray = (*env)->NewObjectArray(env, 2,
-    (*env)->FindClass(env, "[B"),
-    (*env)->NewByteArray(env, 1));
-
-  privArray = (*env)->NewByteArray(env, privkeylen);
-  (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
-  (*env)->SetObjectArrayElement(env, retArray, 0, privArray);
-
-  intsByteArray = (*env)->NewByteArray(env, 2);
-  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
-  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
-
-  (void)classObject;
-
-  return retArray;
-}
-
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
-  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
-{
-  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-  unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
-  const unsigned char* tweak = (unsigned char*) (privkey + 32);
-
-  jobjectArray retArray;
-  jbyteArray privArray, intsByteArray;
-  unsigned char intsarray[2];
-
-  int privkeylen = 32;
-
-  int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak);
-
-  intsarray[0] = privkeylen;
-  intsarray[1] = ret;
-
-  retArray = (*env)->NewObjectArray(env, 2,
-    (*env)->FindClass(env, "[B"),
-    (*env)->NewByteArray(env, 1));
-
-  privArray = (*env)->NewByteArray(env, privkeylen);
-  (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
-  (*env)->SetObjectArrayElement(env, retArray, 0, privArray);
-
-  intsByteArray = (*env)->NewByteArray(env, 2);
-  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
-  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
-
-  (void)classObject;
-
-  return retArray;
-}
-
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
-  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
-{
-  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-/*  secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/
-  unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
-  const unsigned char* tweak = (unsigned char*) (pkey + publen);
-
-  jobjectArray retArray;
-  jbyteArray pubArray, intsByteArray;
-  unsigned char intsarray[2];
-  unsigned char outputSer[65];
-  size_t outputLen = 65;
-
-  secp256k1_pubkey pubkey;
-  int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
-
-  if( ret ) {
-    ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak);
-  }
-
-  if( ret ) {
-    int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
-  }
-
-  intsarray[0] = outputLen;
-  intsarray[1] = ret;
-
-  retArray = (*env)->NewObjectArray(env, 2,
-    (*env)->FindClass(env, "[B"),
-    (*env)->NewByteArray(env, 1));
-
-  pubArray = (*env)->NewByteArray(env, outputLen);
-  (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
-  (*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
-
-  intsByteArray = (*env)->NewByteArray(env, 2);
-  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
-  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
-
-  (void)classObject;
-
-  return retArray;
-}
-
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
-  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
-{
-  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-  unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
-  const unsigned char* tweak = (unsigned char*) (pkey + publen);
-
-  jobjectArray retArray;
-  jbyteArray pubArray, intsByteArray;
-  unsigned char intsarray[2];
-  unsigned char outputSer[65];
-  size_t outputLen = 65;
-
-  secp256k1_pubkey pubkey;
-  int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
-
-  if ( ret ) {
-    ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak);
-  }
-
-  if( ret ) {
-    int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
-  }
-
-  intsarray[0] = outputLen;
-  intsarray[1] = ret;
-
-  retArray = (*env)->NewObjectArray(env, 2,
-    (*env)->FindClass(env, "[B"),
-    (*env)->NewByteArray(env, 1));
-
-  pubArray = (*env)->NewByteArray(env, outputLen);
-  (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
-  (*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
-
-  intsByteArray = (*env)->NewByteArray(env, 2);
-  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
-  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
-
-  (void)classObject;
-
-  return retArray;
-}
-
-SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine
-  (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys)
-{
-  (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys;
-
-  return 0;
-}
-
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
-  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
-{
-  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
-  const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);
-  const unsigned char* pubdata = (const unsigned char*) (secdata + 32);
-
-  jobjectArray retArray;
-  jbyteArray outArray, intsByteArray;
-  unsigned char intsarray[1];
-  secp256k1_pubkey pubkey;
-  unsigned char nonce_res[32];
-  size_t outputLen = 32;
-
-  int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
-
-  if (ret) {
-    ret = secp256k1_ecdh(
-      ctx,
-      nonce_res,
-      &pubkey,
-      secdata,
-      NULL,
-      NULL
-    );
-  }
-
-  intsarray[0] = ret;
-
-  retArray = (*env)->NewObjectArray(env, 2,
-    (*env)->FindClass(env, "[B"),
-    (*env)->NewByteArray(env, 1));
-
-  outArray = (*env)->NewByteArray(env, outputLen);
-  (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res);
-  (*env)->SetObjectArrayElement(env, retArray, 0, outArray);
-
-  intsByteArray = (*env)->NewByteArray(env, 1);
-  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
-  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
-
-  (void)classObject;
-
-  return retArray;
-}
diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h
deleted file mode 100644 (file)
index fe613c9..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-#include "include/secp256k1.h"
-/* Header for class org_bitcoin_NativeSecp256k1 */
-
-#ifndef _Included_org_bitcoin_NativeSecp256k1
-#define _Included_org_bitcoin_NativeSecp256k1
-#ifdef __cplusplus
-extern "C" {
-#endif
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_ctx_clone
- * Signature: (J)J
- */
-SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
-  (JNIEnv *, jclass, jlong);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_context_randomize
- * Signature: (Ljava/nio/ByteBuffer;J)I
- */
-SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
-  (JNIEnv *, jclass, jobject, jlong);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_privkey_tweak_add
- * Signature: (Ljava/nio/ByteBuffer;J)[[B
- */
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
-  (JNIEnv *, jclass, jobject, jlong);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_privkey_tweak_mul
- * Signature: (Ljava/nio/ByteBuffer;J)[[B
- */
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
-  (JNIEnv *, jclass, jobject, jlong);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_pubkey_tweak_add
- * Signature: (Ljava/nio/ByteBuffer;JI)[[B
- */
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
-  (JNIEnv *, jclass, jobject, jlong, jint);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_pubkey_tweak_mul
- * Signature: (Ljava/nio/ByteBuffer;JI)[[B
- */
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
-  (JNIEnv *, jclass, jobject, jlong, jint);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_destroy_context
- * Signature: (J)V
- */
-SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
-  (JNIEnv *, jclass, jlong);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_ecdsa_verify
- * Signature: (Ljava/nio/ByteBuffer;JII)I
- */
-SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
-  (JNIEnv *, jclass, jobject, jlong, jint, jint);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_ecdsa_sign
- * Signature: (Ljava/nio/ByteBuffer;J)[[B
- */
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
-  (JNIEnv *, jclass, jobject, jlong);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_ec_seckey_verify
- * Signature: (Ljava/nio/ByteBuffer;J)I
- */
-SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
-  (JNIEnv *, jclass, jobject, jlong);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_ec_pubkey_create
- * Signature: (Ljava/nio/ByteBuffer;J)[[B
- */
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
-  (JNIEnv *, jclass, jobject, jlong);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_ec_pubkey_parse
- * Signature: (Ljava/nio/ByteBuffer;JI)[[B
- */
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
-  (JNIEnv *, jclass, jobject, jlong, jint);
-
-/*
- * Class:     org_bitcoin_NativeSecp256k1
- * Method:    secp256k1_ecdh
- * Signature: (Ljava/nio/ByteBuffer;JI)[[B
- */
-SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
-  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen);
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/src/java/org_bitcoin_Secp256k1Context.c b/src/java/org_bitcoin_Secp256k1Context.c
deleted file mode 100644 (file)
index a52939e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <stdlib.h>
-#include <stdint.h>
-#include "org_bitcoin_Secp256k1Context.h"
-#include "include/secp256k1.h"
-
-SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
-  (JNIEnv* env, jclass classObject)
-{
-  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
-
-  (void)classObject;(void)env;
-
-  return (uintptr_t)ctx;
-}
-
diff --git a/src/java/org_bitcoin_Secp256k1Context.h b/src/java/org_bitcoin_Secp256k1Context.h
deleted file mode 100644 (file)
index 0d2bc84..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-#include "include/secp256k1.h"
-/* Header for class org_bitcoin_Secp256k1Context */
-
-#ifndef _Included_org_bitcoin_Secp256k1Context
-#define _Included_org_bitcoin_Secp256k1Context
-#ifdef __cplusplus
-extern "C" {
-#endif
-/*
- * Class:     org_bitcoin_Secp256k1Context
- * Method:    secp256k1_init_context
- * Signature: ()J
- */
-SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
-  (JNIEnv *, jclass);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
index 44cb68e75025126b21385d953fcfabfcd68d5381..07a25b80d4ab6f080d46fc55d635b0b86b7cb5f1 100644 (file)
 #include "include/secp256k1_ecdh.h"
 #include "ecmult_const_impl.h"
 
-static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
-    unsigned char version = (y[31] & 0x01) | 0x02;
+static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
+    unsigned char version = (y32[31] & 0x01) | 0x02;
     secp256k1_sha256 sha;
     (void)data;
 
     secp256k1_sha256_initialize(&sha);
     secp256k1_sha256_write(&sha, &version, 1);
-    secp256k1_sha256_write(&sha, x, 32);
+    secp256k1_sha256_write(&sha, x32, 32);
     secp256k1_sha256_finalize(&sha, output);
 
     return 1;
@@ -32,36 +32,40 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
     secp256k1_gej res;
     secp256k1_ge pt;
     secp256k1_scalar s;
+    unsigned char x[32];
+    unsigned char y[32];
+
     VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(output != NULL);
     ARG_CHECK(point != NULL);
     ARG_CHECK(scalar != NULL);
+
     if (hashfp == NULL) {
         hashfp = secp256k1_ecdh_hash_function_default;
     }
 
     secp256k1_pubkey_load(ctx, &pt, point);
     secp256k1_scalar_set_b32(&s, scalar, &overflow);
-    if (overflow || secp256k1_scalar_is_zero(&s)) {
-        ret = 0;
-    } else {
-        unsigned char x[32];
-        unsigned char y[32];
-
-        secp256k1_ecmult_const(&res, &pt, &s, 256);
-        secp256k1_ge_set_gej(&pt, &res);
-
-        /* Compute a hash of the point */
-        secp256k1_fe_normalize(&pt.x);
-        secp256k1_fe_normalize(&pt.y);
-        secp256k1_fe_get_b32(x, &pt.x);
-        secp256k1_fe_get_b32(y, &pt.y);
-
-        ret = hashfp(output, x, y, data);
-    }
 
+    overflow |= secp256k1_scalar_is_zero(&s);
+    secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
+
+    secp256k1_ecmult_const(&res, &pt, &s, 256);
+    secp256k1_ge_set_gej(&pt, &res);
+
+    /* Compute a hash of the point */
+    secp256k1_fe_normalize(&pt.x);
+    secp256k1_fe_normalize(&pt.y);
+    secp256k1_fe_get_b32(x, &pt.x);
+    secp256k1_fe_get_b32(y, &pt.y);
+
+    ret = hashfp(output, x, y, data);
+
+    memset(x, 0, 32);
+    memset(y, 0, 32);
     secp256k1_scalar_clear(&s);
-    return ret;
+
+    return !!ret & !overflow;
 }
 
 #endif /* SECP256K1_MODULE_ECDH_MAIN_H */
old mode 100755 (executable)
new mode 100644 (file)
index ed356e5..e2576aa
@@ -122,48 +122,15 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, cons
 
 int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
     secp256k1_scalar r, s;
-    secp256k1_scalar sec, non, msg;
-    int recid;
-    int ret = 0;
-    int overflow = 0;
+    int ret, recid;
     VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
     ARG_CHECK(msg32 != NULL);
     ARG_CHECK(signature != NULL);
     ARG_CHECK(seckey != NULL);
-    if (noncefp == NULL) {
-        noncefp = secp256k1_nonce_function_default;
-    }
 
-    secp256k1_scalar_set_b32(&sec, seckey, &overflow);
-    /* Fail if the secret key is invalid. */
-    if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
-        unsigned char nonce32[32];
-        unsigned int count = 0;
-        secp256k1_scalar_set_b32(&msg, msg32, NULL);
-        while (1) {
-            ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
-            if (!ret) {
-                break;
-            }
-            secp256k1_scalar_set_b32(&non, nonce32, &overflow);
-            if (!overflow && !secp256k1_scalar_is_zero(&non)) {
-                if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
-                    break;
-                }
-            }
-            count++;
-        }
-        memset(nonce32, 0, 32);
-        secp256k1_scalar_clear(&msg);
-        secp256k1_scalar_clear(&non);
-        secp256k1_scalar_clear(&sec);
-    }
-    if (ret) {
-        secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
-    } else {
-        memset(signature, 0, sizeof(*signature));
-    }
+    ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, msg32, seckey, noncefp, noncedata);
+    secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
     return ret;
 }
 
index 59304cb66e90504bbc65ec13449160336c91d66a..95d3e326c9c6f0f6959b90b30f191de988b509eb 100644 (file)
@@ -8,6 +8,7 @@
 #define SECP256K1_SCALAR_H
 
 #include "num.h"
+#include "util.h"
 
 #if defined HAVE_CONFIG_H
 #include "libsecp256k1-config.h"
 
 #if defined(EXHAUSTIVE_TEST_ORDER)
 #include "scalar_low.h"
-#elif defined(USE_SCALAR_4X64)
+#elif defined(SECP256K1_WIDEMUL_INT128)
 #include "scalar_4x64.h"
-#elif defined(USE_SCALAR_8X32)
+#elif defined(SECP256K1_WIDEMUL_INT64)
 #include "scalar_8x32.h"
 #else
-#error "Please select scalar implementation"
+#error "Please select wide multiplication implementation"
 #endif
 
 /** Clear a scalar to prevent the leak of sensitive data. */
@@ -32,9 +33,17 @@ static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigne
 /** Access bits from a scalar. Not constant time. */
 static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count);
 
-/** Set a scalar from a big endian byte array. */
+/** Set a scalar from a big endian byte array. The scalar will be reduced modulo group order `n`.
+ * In:      bin:        pointer to a 32-byte array.
+ * Out:     r:          scalar to be set.
+ *          overflow:   non-zero if the scalar was bigger or equal to `n` before reduction, zero otherwise (can be NULL).
+ */
 static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow);
 
+/** Set a scalar from a big endian byte array and returns 1 if it is a valid
+ *  seckey and 0 otherwise. */
+static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin);
+
 /** Set a scalar to an unsigned integer. */
 static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v);
 
@@ -103,4 +112,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
 /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */
 static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift);
 
+/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time.  Both *r and *a must be initialized.*/
+static void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag);
+
 #endif /* SECP256K1_SCALAR_H */
index d378335d996f32449a1d782352f91d5c60cac3aa..7f3992786101cf0f603aa447deb673afcdde125f 100644 (file)
@@ -192,9 +192,9 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
         tl = t; \
     } \
     c0 += tl;                 /* overflow is handled on the next line */ \
-    th += (c0 < tl) ? 1 : 0;  /* at most 0xFFFFFFFFFFFFFFFF */ \
+    th += (c0 < tl);          /* at most 0xFFFFFFFFFFFFFFFF */ \
     c1 += th;                 /* overflow is handled on the next line */ \
-    c2 += (c1 < th) ? 1 : 0;  /* never overflows by contract (verified in the next line) */ \
+    c2 += (c1 < th);          /* never overflows by contract (verified in the next line) */ \
     VERIFY_CHECK((c1 >= th) || (c2 != 0)); \
 }
 
@@ -207,7 +207,7 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
         tl = t; \
     } \
     c0 += tl;                 /* overflow is handled on the next line */ \
-    th += (c0 < tl) ? 1 : 0;  /* at most 0xFFFFFFFFFFFFFFFF */ \
+    th += (c0 < tl);          /* at most 0xFFFFFFFFFFFFFFFF */ \
     c1 += th;                 /* never overflows by contract (verified in the next line) */ \
     VERIFY_CHECK(c1 >= th); \
 }
@@ -221,16 +221,16 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
         tl = t; \
     } \
     th2 = th + th;                  /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \
-    c2 += (th2 < th) ? 1 : 0;       /* never overflows by contract (verified the next line) */ \
+    c2 += (th2 < th);               /* never overflows by contract (verified the next line) */ \
     VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
     tl2 = tl + tl;                  /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \
-    th2 += (tl2 < tl) ? 1 : 0;      /* at most 0xFFFFFFFFFFFFFFFF */ \
+    th2 += (tl2 < tl);              /* at most 0xFFFFFFFFFFFFFFFF */ \
     c0 += tl2;                      /* overflow is handled on the next line */ \
-    th2 += (c0 < tl2) ? 1 : 0;      /* second overflow is handled on the next line */ \
+    th2 += (c0 < tl2);              /* second overflow is handled on the next line */ \
     c2 += (c0 < tl2) & (th2 == 0);  /* never overflows by contract (verified the next line) */ \
     VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \
     c1 += th2;                      /* overflow is handled on the next line */ \
-    c2 += (c1 < th2) ? 1 : 0;       /* never overflows by contract (verified the next line) */ \
+    c2 += (c1 < th2);               /* never overflows by contract (verified the next line) */ \
     VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \
 }
 
@@ -238,15 +238,15 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
 #define sumadd(a) { \
     unsigned int over; \
     c0 += (a);                  /* overflow is handled on the next line */ \
-    over = (c0 < (a)) ? 1 : 0; \
+    over = (c0 < (a));         \
     c1 += over;                 /* overflow is handled on the next line */ \
-    c2 += (c1 < over) ? 1 : 0;  /* never overflows by contract */ \
+    c2 += (c1 < over);          /* never overflows by contract */ \
 }
 
 /** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */
 #define sumadd_fast(a) { \
     c0 += (a);                 /* overflow is handled on the next line */ \
-    c1 += (c0 < (a)) ? 1 : 0;  /* never overflows by contract (verified the next line) */ \
+    c1 += (c0 < (a));          /* never overflows by contract (verified the next line) */ \
     VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \
     VERIFY_CHECK(c2 == 0); \
 }
@@ -946,4 +946,15 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
     secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1);
 }
 
+static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
+    uint64_t mask0, mask1;
+    VG_CHECK_VERIFY(r->d, sizeof(r->d));
+    mask0 = flag + ~((uint64_t)0);
+    mask1 = ~mask0;
+    r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);
+    r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1);
+    r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1);
+    r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1);
+}
+
 #endif /* SECP256K1_SCALAR_REPR_IMPL_H */
index 4f9ed61feaeccf4fca036df8d9f24df2ad7a14ed..f8c7fa7efaba92980d6f74599c93b877887504be 100644 (file)
@@ -271,9 +271,9 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
         tl = t; \
     } \
     c0 += tl;                 /* overflow is handled on the next line */ \
-    th += (c0 < tl) ? 1 : 0;  /* at most 0xFFFFFFFF */ \
+    th += (c0 < tl);          /* at most 0xFFFFFFFF */ \
     c1 += th;                 /* overflow is handled on the next line */ \
-    c2 += (c1 < th) ? 1 : 0;  /* never overflows by contract (verified in the next line) */ \
+    c2 += (c1 < th);          /* never overflows by contract (verified in the next line) */ \
     VERIFY_CHECK((c1 >= th) || (c2 != 0)); \
 }
 
@@ -286,7 +286,7 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
         tl = t; \
     } \
     c0 += tl;                 /* overflow is handled on the next line */ \
-    th += (c0 < tl) ? 1 : 0;  /* at most 0xFFFFFFFF */ \
+    th += (c0 < tl);          /* at most 0xFFFFFFFF */ \
     c1 += th;                 /* never overflows by contract (verified in the next line) */ \
     VERIFY_CHECK(c1 >= th); \
 }
@@ -300,16 +300,16 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
         tl = t; \
     } \
     th2 = th + th;                  /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \
-    c2 += (th2 < th) ? 1 : 0;       /* never overflows by contract (verified the next line) */ \
+    c2 += (th2 < th);               /* never overflows by contract (verified the next line) */ \
     VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
     tl2 = tl + tl;                  /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \
-    th2 += (tl2 < tl) ? 1 : 0;      /* at most 0xFFFFFFFF */ \
+    th2 += (tl2 < tl);              /* at most 0xFFFFFFFF */ \
     c0 += tl2;                      /* overflow is handled on the next line */ \
-    th2 += (c0 < tl2) ? 1 : 0;      /* second overflow is handled on the next line */ \
+    th2 += (c0 < tl2);              /* second overflow is handled on the next line */ \
     c2 += (c0 < tl2) & (th2 == 0);  /* never overflows by contract (verified the next line) */ \
     VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \
     c1 += th2;                      /* overflow is handled on the next line */ \
-    c2 += (c1 < th2) ? 1 : 0;       /* never overflows by contract (verified the next line) */ \
+    c2 += (c1 < th2);               /* never overflows by contract (verified the next line) */ \
     VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \
 }
 
@@ -317,15 +317,15 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
 #define sumadd(a) { \
     unsigned int over; \
     c0 += (a);                  /* overflow is handled on the next line */ \
-    over = (c0 < (a)) ? 1 : 0; \
+    over = (c0 < (a)); \
     c1 += over;                 /* overflow is handled on the next line */ \
-    c2 += (c1 < over) ? 1 : 0;  /* never overflows by contract */ \
+    c2 += (c1 < over);          /* never overflows by contract */ \
 }
 
 /** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */
 #define sumadd_fast(a) { \
     c0 += (a);                 /* overflow is handled on the next line */ \
-    c1 += (c0 < (a)) ? 1 : 0;  /* never overflows by contract (verified the next line) */ \
+    c1 += (c0 < (a));          /* never overflows by contract (verified the next line) */ \
     VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \
     VERIFY_CHECK(c2 == 0); \
 }
@@ -718,4 +718,19 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
     secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1);
 }
 
+static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
+    uint32_t mask0, mask1;
+    VG_CHECK_VERIFY(r->d, sizeof(r->d));
+    mask0 = flag + ~((uint32_t)0);
+    mask1 = ~mask0;
+    r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);
+    r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1);
+    r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1);
+    r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1);
+    r->d[4] = (r->d[4] & mask0) | (a->d[4] & mask1);
+    r->d[5] = (r->d[5] & mask0) | (a->d[5] & mask1);
+    r->d[6] = (r->d[6] & mask0) | (a->d[6] & mask1);
+    r->d[7] = (r->d[7] & mask0) | (a->d[7] & mask1);
+}
+
 #endif /* SECP256K1_SCALAR_REPR_IMPL_H */
index 6b336d9d1a66d9c70a8c636b6ddad8b154613299..2ec04b1ae9aa27c26ee1a6483a90ce3b292b2a16 100644 (file)
 
 #if defined(EXHAUSTIVE_TEST_ORDER)
 #include "scalar_low_impl.h"
-#elif defined(USE_SCALAR_4X64)
+#elif defined(SECP256K1_WIDEMUL_INT128)
 #include "scalar_4x64_impl.h"
-#elif defined(USE_SCALAR_8X32)
+#elif defined(SECP256K1_WIDEMUL_INT64)
 #include "scalar_8x32_impl.h"
 #else
-#error "Please select scalar implementation"
+#error "Please select wide multiplication implementation"
 #endif
 
+static const secp256k1_scalar secp256k1_scalar_one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+static const secp256k1_scalar secp256k1_scalar_zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
+
 #ifndef USE_NUM_NONE
 static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a) {
     unsigned char c[32];
@@ -52,6 +55,12 @@ static void secp256k1_scalar_order_get_num(secp256k1_num *r) {
 }
 #endif
 
+static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin) {
+    int overflow;
+    secp256k1_scalar_set_b32(r, bin, &overflow);
+    return (!overflow) & (!secp256k1_scalar_is_zero(r));
+}
+
 static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) {
 #if defined(EXHAUSTIVE_TEST_ORDER)
     int i;
index 5836febc5b729d8113842212b31fee01b21410cb..2794a7f171fa39b5741e4345455a3435b5a8a39d 100644 (file)
@@ -12,4 +12,6 @@
 /** A scalar modulo the group order of the secp256k1 curve. */
 typedef uint32_t secp256k1_scalar;
 
+#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) (d0)
+
 #endif /* SECP256K1_SCALAR_REPR_H */
index 910ce3f4933d9a8ceb18c4f09d017fe910c82534..b79cf1ff6c5cad46a183d51678b352e1154ac6a6 100644 (file)
@@ -114,4 +114,12 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const
     return *a == *b;
 }
 
+static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
+    uint32_t mask0, mask1;
+    VG_CHECK_VERIFY(r, sizeof(*r));
+    mask0 = flag + ~((uint32_t)0);
+    mask1 = ~mask0;
+    *r = (*r & mask0) | (*a & mask1);
+}
+
 #endif /* SECP256K1_SCALAR_REPR_IMPL_H */
index 4cee70000147b7b84e5759f00b0275fb9ead9107..b205620224b6bb339b09ee79e6347e5303aefee3 100644 (file)
@@ -11,7 +11,7 @@
 #include "scratch.h"
 
 static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) {
-    const size_t base_alloc = ((sizeof(secp256k1_scratch) + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
+    const size_t base_alloc = ROUND_TO_ALIGN(sizeof(secp256k1_scratch));
     void *alloc = checked_malloc(error_callback, base_alloc + size);
     secp256k1_scratch* ret = (secp256k1_scratch *)alloc;
     if (ret != NULL) {
@@ -60,6 +60,10 @@ static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_c
         secp256k1_callback_call(error_callback, "invalid scratch space");
         return 0;
     }
+    /* Ensure that multiplication will not wrap around */
+    if (ALIGNMENT > 1 && objects > SIZE_MAX/(ALIGNMENT - 1)) {
+        return 0;
+    }
     if (scratch->max_size - scratch->alloc_size <= objects * (ALIGNMENT - 1)) {
         return 0;
     }
@@ -68,7 +72,14 @@ static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_c
 
 static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t size) {
     void *ret;
-    size = ROUND_TO_ALIGN(size);
+    size_t rounded_size;
+
+    rounded_size = ROUND_TO_ALIGN(size);
+    /* Check that rounding did not wrap around */
+    if (rounded_size < size) {
+        return NULL;
+    }
+    size = rounded_size;
 
     if (memcmp(scratch->magic, "scratch", 8) != 0) {
         secp256k1_callback_call(error_callback, "invalid scratch space");
index a3f446e507e20985d3d3d1f912f4a0203b44cc09..0b539979d96805b4db9807155accc96c4f280c40 100644 (file)
@@ -7,6 +7,7 @@
 #include "include/secp256k1.h"
 #include "include/secp256k1_preallocated.h"
 
+#include "assumptions.h"
 #include "util.h"
 #include "num_impl.h"
 #include "field_impl.h"
 #include "eckey_impl.h"
 #include "hash_impl.h"
 #include "scratch_impl.h"
+#include "selftest.h"
+
+#if defined(VALGRIND)
+# include <valgrind/memcheck.h>
+#endif
 
 #define ARG_CHECK(cond) do { \
     if (EXPECT(!(cond), 0)) { \
@@ -66,13 +72,15 @@ struct secp256k1_context_struct {
     secp256k1_ecmult_gen_context ecmult_gen_ctx;
     secp256k1_callback illegal_callback;
     secp256k1_callback error_callback;
+    int declassify;
 };
 
 static const secp256k1_context secp256k1_context_no_precomp_ = {
     { 0 },
     { 0 },
     { secp256k1_default_illegal_callback_fn, 0 },
-    { secp256k1_default_error_callback_fn, 0 }
+    { secp256k1_default_error_callback_fn, 0 },
+    0
 };
 const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_;
 
@@ -111,6 +119,9 @@ secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigne
     size_t prealloc_size;
     secp256k1_context* ret;
 
+    if (!secp256k1_selftest()) {
+        secp256k1_callback_call(&default_error_callback, "self test failed");
+    }
     VERIFY_CHECK(prealloc != NULL);
     prealloc_size = secp256k1_context_preallocated_size(flags);
     ret = (secp256k1_context*)manual_alloc(&prealloc, sizeof(secp256k1_context), base, prealloc_size);
@@ -132,6 +143,7 @@ secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigne
     if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) {
         secp256k1_ecmult_context_build(&ret->ecmult_ctx, &prealloc);
     }
+    ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY);
 
     return (secp256k1_context*) ret;
 }
@@ -215,6 +227,20 @@ void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scr
     secp256k1_scratch_destroy(&ctx->error_callback, scratch);
 }
 
+/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour
+ *  of the software. This is setup for use with valgrind but could be substituted with
+ *  the appropriate instrumentation for other analysis tools.
+ */
+static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, void *p, size_t len) {
+#if defined(VALGRIND)
+    if (EXPECT(ctx->declassify,0)) VALGRIND_MAKE_MEM_DEFINED(p, len);
+#else
+    (void)ctx;
+    (void)p;
+    (void)len;
+#endif
+}
+
 static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
     if (sizeof(secp256k1_ge_storage) == 64) {
         /* When the secp256k1_ge_storage type is exactly 64 byte, use its
@@ -270,7 +296,7 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o
 
     VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(outputlen != NULL);
-    ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65));
+    ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33u : 65u));
     len = *outputlen;
     *outputlen = 0;
     ARG_CHECK(output != NULL);
@@ -446,61 +472,83 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
 const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
 const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;
 
-int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
-    secp256k1_scalar r, s;
+static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
     secp256k1_scalar sec, non, msg;
     int ret = 0;
-    int overflow = 0;
-    VERIFY_CHECK(ctx != NULL);
-    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
-    ARG_CHECK(msg32 != NULL);
-    ARG_CHECK(signature != NULL);
-    ARG_CHECK(seckey != NULL);
+    int is_sec_valid;
+    unsigned char nonce32[32];
+    unsigned int count = 0;
+    /* Default initialization here is important so we won't pass uninit values to the cmov in the end */
+    *r = secp256k1_scalar_zero;
+    *s = secp256k1_scalar_zero;
+    if (recid) {
+        *recid = 0;
+    }
     if (noncefp == NULL) {
         noncefp = secp256k1_nonce_function_default;
     }
 
-    secp256k1_scalar_set_b32(&sec, seckey, &overflow);
     /* Fail if the secret key is invalid. */
-    if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
-        unsigned char nonce32[32];
-        unsigned int count = 0;
-        secp256k1_scalar_set_b32(&msg, msg32, NULL);
-        while (1) {
-            ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
-            if (!ret) {
+    is_sec_valid = secp256k1_scalar_set_b32_seckey(&sec, seckey);
+    secp256k1_scalar_cmov(&sec, &secp256k1_scalar_one, !is_sec_valid);
+    secp256k1_scalar_set_b32(&msg, msg32, NULL);
+    while (1) {
+        int is_nonce_valid;
+        ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
+        if (!ret) {
+            break;
+        }
+        is_nonce_valid = secp256k1_scalar_set_b32_seckey(&non, nonce32);
+        /* The nonce is still secret here, but it being invalid is is less likely than 1:2^255. */
+        secp256k1_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid));
+        if (is_nonce_valid) {
+            ret = secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid);
+            /* The final signature is no longer a secret, nor is the fact that we were successful or not. */
+            secp256k1_declassify(ctx, &ret, sizeof(ret));
+            if (ret) {
                 break;
             }
-            secp256k1_scalar_set_b32(&non, nonce32, &overflow);
-            if (!overflow && !secp256k1_scalar_is_zero(&non)) {
-                if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) {
-                    break;
-                }
-            }
-            count++;
         }
-        memset(nonce32, 0, 32);
-        secp256k1_scalar_clear(&msg);
-        secp256k1_scalar_clear(&non);
-        secp256k1_scalar_clear(&sec);
-    }
-    if (ret) {
-        secp256k1_ecdsa_signature_save(signature, &r, &s);
-    } else {
-        memset(signature, 0, sizeof(*signature));
+        count++;
+    }
+    /* We don't want to declassify is_sec_valid and therefore the range of
+     * seckey. As a result is_sec_valid is included in ret only after ret was
+     * used as a branching variable. */
+    ret &= is_sec_valid;
+    memset(nonce32, 0, 32);
+    secp256k1_scalar_clear(&msg);
+    secp256k1_scalar_clear(&non);
+    secp256k1_scalar_clear(&sec);
+    secp256k1_scalar_cmov(r, &secp256k1_scalar_zero, !ret);
+    secp256k1_scalar_cmov(s, &secp256k1_scalar_zero, !ret);
+    if (recid) {
+        const int zero = 0;
+        secp256k1_int_cmov(recid, &zero, !ret);
     }
     return ret;
 }
 
+int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
+    secp256k1_scalar r, s;
+    int ret;
+    VERIFY_CHECK(ctx != NULL);
+    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+    ARG_CHECK(msg32 != NULL);
+    ARG_CHECK(signature != NULL);
+    ARG_CHECK(seckey != NULL);
+
+    ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, msg32, seckey, noncefp, noncedata);
+    secp256k1_ecdsa_signature_save(signature, &r, &s);
+    return ret;
+}
+
 int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) {
     secp256k1_scalar sec;
     int ret;
-    int overflow;
     VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(seckey != NULL);
 
-    secp256k1_scalar_set_b32(&sec, seckey, &overflow);
-    ret = !overflow && !secp256k1_scalar_is_zero(&sec);
+    ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
     secp256k1_scalar_clear(&sec);
     return ret;
 }
@@ -509,7 +557,6 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p
     secp256k1_gej pj;
     secp256k1_ge p;
     secp256k1_scalar sec;
-    int overflow;
     int ret = 0;
     VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(pubkey != NULL);
@@ -517,28 +564,35 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p
     ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
     ARG_CHECK(seckey != NULL);
 
-    secp256k1_scalar_set_b32(&sec, seckey, &overflow);
-    ret = !overflow && !secp256k1_scalar_is_zero(&sec);
-    if (ret) {
-        secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
-        secp256k1_ge_set_gej(&p, &pj);
-        secp256k1_pubkey_save(pubkey, &p);
-    }
+    ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
+    secp256k1_scalar_cmov(&sec, &secp256k1_scalar_one, !ret);
+
+    secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
+    secp256k1_ge_set_gej(&p, &pj);
+    secp256k1_pubkey_save(pubkey, &p);
+    memczero(pubkey, sizeof(*pubkey), !ret);
+
     secp256k1_scalar_clear(&sec);
     return ret;
 }
 
-int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) {
+int secp256k1_ec_seckey_negate(const secp256k1_context* ctx, unsigned char *seckey) {
     secp256k1_scalar sec;
+    int ret = 0;
     VERIFY_CHECK(ctx != NULL);
     ARG_CHECK(seckey != NULL);
 
-    secp256k1_scalar_set_b32(&sec, seckey, NULL);
+    ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
+    secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
     secp256k1_scalar_negate(&sec, &sec);
     secp256k1_scalar_get_b32(seckey, &sec);
 
     secp256k1_scalar_clear(&sec);
-    return 1;
+    return ret;
+}
+
+int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) {
+    return secp256k1_ec_seckey_negate(ctx, seckey);
 }
 
 int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) {
@@ -556,7 +610,7 @@ int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *p
     return ret;
 }
 
-int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
+int secp256k1_ec_seckey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
     secp256k1_scalar term;
     secp256k1_scalar sec;
     int ret = 0;
@@ -566,19 +620,21 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *
     ARG_CHECK(tweak != NULL);
 
     secp256k1_scalar_set_b32(&term, tweak, &overflow);
-    secp256k1_scalar_set_b32(&sec, seckey, NULL);
+    ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
 
-    ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term);
-    memset(seckey, 0, 32);
-    if (ret) {
-        secp256k1_scalar_get_b32(seckey, &sec);
-    }
+    ret &= (!overflow) & secp256k1_eckey_privkey_tweak_add(&sec, &term);
+    secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
+    secp256k1_scalar_get_b32(seckey, &sec);
 
     secp256k1_scalar_clear(&sec);
     secp256k1_scalar_clear(&term);
     return ret;
 }
 
+int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
+    return secp256k1_ec_seckey_tweak_add(ctx, seckey, tweak);
+}
+
 int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) {
     secp256k1_ge p;
     secp256k1_scalar term;
@@ -603,7 +659,7 @@ int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey
     return ret;
 }
 
-int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
+int secp256k1_ec_seckey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
     secp256k1_scalar factor;
     secp256k1_scalar sec;
     int ret = 0;
@@ -613,18 +669,20 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *
     ARG_CHECK(tweak != NULL);
 
     secp256k1_scalar_set_b32(&factor, tweak, &overflow);
-    secp256k1_scalar_set_b32(&sec, seckey, NULL);
-    ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor);
-    memset(seckey, 0, 32);
-    if (ret) {
-        secp256k1_scalar_get_b32(seckey, &sec);
-    }
+    ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
+    ret &= (!overflow) & secp256k1_eckey_privkey_tweak_mul(&sec, &factor);
+    secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
+    secp256k1_scalar_get_b32(seckey, &sec);
 
     secp256k1_scalar_clear(&sec);
     secp256k1_scalar_clear(&factor);
     return ret;
 }
 
+int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
+    return secp256k1_ec_seckey_tweak_mul(ctx, seckey, tweak);
+}
+
 int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) {
     secp256k1_ge p;
     secp256k1_scalar factor;
diff --git a/src/selftest.h b/src/selftest.h
new file mode 100644 (file)
index 0000000..885983a
--- /dev/null
@@ -0,0 +1,32 @@
+/**********************************************************************
+ * Copyright (c) 2020 Pieter Wuille                                   *
+ * Distributed under the MIT software license, see the accompanying   *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef SECP256K1_SELFTEST_H
+#define SECP256K1_SELFTEST_H
+
+#include "hash.h"
+
+#include <string.h>
+
+static int secp256k1_selftest_sha256(void) {
+    static const char *input63 = "For this sample, this 63-byte string will be used as input data";
+    static const unsigned char output32[32] = {
+        0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e,
+        0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42,
+    };
+    unsigned char out[32];
+    secp256k1_sha256 hasher;
+    secp256k1_sha256_initialize(&hasher);
+    secp256k1_sha256_write(&hasher, (const unsigned char*)input63, 63);
+    secp256k1_sha256_finalize(&hasher, out);
+    return memcmp(out, output32, 32) == 0;
+}
+
+static int secp256k1_selftest(void) {
+    return secp256k1_selftest_sha256();
+}
+
+#endif /* SECP256K1_SELFTEST_H */
index 15012e831a987adb97a42befc41a7362e99f374b..67b328b45cbe2d08ea7490fc89f268d7acc5234b 100644 (file)
@@ -32,17 +32,6 @@ void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
 #include "contrib/lax_der_parsing.c"
 #include "contrib/lax_der_privatekey_parsing.c"
 
-#if !defined(VG_CHECK)
-# if defined(VALGRIND)
-#  include <valgrind/memcheck.h>
-#  define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y))
-#  define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y))
-# else
-#  define VG_UNDEF(x,y)
-#  define VG_CHECK(x,y)
-# endif
-#endif
-
 static int count = 64;
 static secp256k1_context *ctx = NULL;
 
@@ -140,6 +129,12 @@ void random_scalar_order(secp256k1_scalar *num) {
     } while(1);
 }
 
+void random_scalar_order_b32(unsigned char *b32) {
+    secp256k1_scalar num;
+    random_scalar_order(&num);
+    secp256k1_scalar_get_b32(b32, &num);
+}
+
 void run_context_tests(int use_prealloc) {
     secp256k1_pubkey pubkey;
     secp256k1_pubkey zero_pubkey;
@@ -187,8 +182,10 @@ void run_context_tests(int use_prealloc) {
     ecount2 = 10;
     secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
     secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2);
-    secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL);
-    CHECK(vrfy->error_callback.fn != sign->error_callback.fn);
+    /* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */
+    secp256k1_context_set_error_callback(sign, secp256k1_default_illegal_callback_fn, NULL);
+    CHECK(sign->error_callback.fn != vrfy->error_callback.fn);
+    CHECK(sign->error_callback.fn == secp256k1_default_illegal_callback_fn);
 
     /* check if sizes for cloning are consistent */
     CHECK(secp256k1_context_preallocated_clone_size(none) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
@@ -244,7 +241,8 @@ void run_context_tests(int use_prealloc) {
     }
 
     /* Verify that the error callback makes it across the clone. */
-    CHECK(vrfy->error_callback.fn != sign->error_callback.fn);
+    CHECK(sign->error_callback.fn != vrfy->error_callback.fn);
+    CHECK(sign->error_callback.fn == secp256k1_default_illegal_callback_fn);
     /* And that it resets back to default. */
     secp256k1_context_set_error_callback(sign, NULL, NULL);
     CHECK(vrfy->error_callback.fn == sign->error_callback.fn);
@@ -366,8 +364,8 @@ void run_scratch_tests(void) {
     CHECK(scratch->alloc_size != 0);
     CHECK(scratch->alloc_size % ALIGNMENT == 0);
 
-    /* Allocating another 500 bytes fails */
-    CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL);
+    /* Allocating another 501 bytes fails */
+    CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 501) == NULL);
     CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc);
     CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
     CHECK(scratch->alloc_size != 0);
@@ -400,6 +398,18 @@ void run_scratch_tests(void) {
     secp256k1_scratch_space_destroy(none, scratch);
     CHECK(ecount == 5);
 
+    /* Test that large integers do not wrap around in a bad way */
+    scratch = secp256k1_scratch_space_create(none, 1000);
+    /* Try max allocation with a large number of objects. Only makes sense if
+     * ALIGNMENT is greater than 1 because otherwise the objects take no extra
+     * space. */
+    CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&none->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1));
+    /* Try allocating SIZE_MAX to test wrap around which only happens if
+     * ALIGNMENT > 1, otherwise it returns NULL anyway because the scratch
+     * space is too small. */
+    CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, SIZE_MAX) == NULL);
+    secp256k1_scratch_space_destroy(none, scratch);
+
     /* cleanup */
     secp256k1_scratch_space_destroy(none, NULL); /* no-op */
     secp256k1_context_destroy(none);
@@ -1077,11 +1087,31 @@ void scalar_test(void) {
 
 }
 
+void run_scalar_set_b32_seckey_tests(void) {
+    unsigned char b32[32];
+    secp256k1_scalar s1;
+    secp256k1_scalar s2;
+
+    /* Usually set_b32 and set_b32_seckey give the same result */
+    random_scalar_order_b32(b32);
+    secp256k1_scalar_set_b32(&s1, b32, NULL);
+    CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 1);
+    CHECK(secp256k1_scalar_eq(&s1, &s2) == 1);
+
+    memset(b32, 0, sizeof(b32));
+    CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0);
+    memset(b32, 0xFF, sizeof(b32));
+    CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0);
+}
+
 void run_scalar_tests(void) {
     int i;
     for (i = 0; i < 128 * count; i++) {
         scalar_test();
     }
+    for (i = 0; i < count; i++) {
+        run_scalar_set_b32_seckey_tests();
+    }
 
     {
         /* (-1)+1 should be zero. */
@@ -1097,16 +1127,43 @@ void run_scalar_tests(void) {
 
 #ifndef USE_NUM_NONE
     {
-        /* A scalar with value of the curve order should be 0. */
+        /* Test secp256k1_scalar_set_b32 boundary conditions */
         secp256k1_num order;
-        secp256k1_scalar zero;
+        secp256k1_scalar scalar;
         unsigned char bin[32];
+        unsigned char bin_tmp[32];
         int overflow = 0;
+        /* 2^256-1 - order */
+        static const secp256k1_scalar all_ones_minus_order = SECP256K1_SCALAR_CONST(
+            0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000001UL,
+            0x45512319UL, 0x50B75FC4UL, 0x402DA173UL, 0x2FC9BEBEUL
+        );
+
+        /* A scalar set to 0s should be 0. */
+        memset(bin, 0, 32);
+        secp256k1_scalar_set_b32(&scalar, bin, &overflow);
+        CHECK(overflow == 0);
+        CHECK(secp256k1_scalar_is_zero(&scalar));
+
+        /* A scalar with value of the curve order should be 0. */
         secp256k1_scalar_order_get_num(&order);
         secp256k1_num_get_bin(bin, 32, &order);
-        secp256k1_scalar_set_b32(&zero, bin, &overflow);
+        secp256k1_scalar_set_b32(&scalar, bin, &overflow);
         CHECK(overflow == 1);
-        CHECK(secp256k1_scalar_is_zero(&zero));
+        CHECK(secp256k1_scalar_is_zero(&scalar));
+
+        /* A scalar with value of the curve order minus one should not overflow. */
+        bin[31] -= 1;
+        secp256k1_scalar_set_b32(&scalar, bin, &overflow);
+        CHECK(overflow == 0);
+        secp256k1_scalar_get_b32(bin_tmp, &scalar);
+        CHECK(memcmp(bin, bin_tmp, 32) == 0);
+
+        /* A scalar set to all 1s should overflow. */
+        memset(bin, 0xFF, 32);
+        secp256k1_scalar_set_b32(&scalar, bin, &overflow);
+        CHECK(overflow == 1);
+        CHECK(secp256k1_scalar_eq(&scalar, &all_ones_minus_order));
     }
 #endif
 
@@ -1822,7 +1879,7 @@ void run_field_misc(void) {
         q = x;
         secp256k1_fe_cmov(&x, &z, 0);
 #ifdef VERIFY
-        CHECK(!x.normalized && x.magnitude == z.magnitude);
+        CHECK(x.normalized && x.magnitude == 1);
 #endif
         secp256k1_fe_cmov(&x, &x, 1);
         CHECK(fe_memcmp(&x, &z) != 0);
@@ -1845,7 +1902,7 @@ void run_field_misc(void) {
             secp256k1_fe_normalize_var(&q);
             secp256k1_fe_cmov(&q, &z, (j&1));
 #ifdef VERIFY
-            CHECK(!q.normalized && q.magnitude == (j+2));
+            CHECK((q.normalized != (j&1)) && q.magnitude == ((j&1) ? z.magnitude : 1));
 #endif
         }
         secp256k1_fe_normalize_var(&z);
@@ -2173,6 +2230,9 @@ void test_ge(void) {
                 /* Normal doubling. */
                 secp256k1_gej_double_var(&resj, &gej[i2], NULL);
                 ge_equals_gej(&ref, &resj);
+                /* Constant-time doubling. */
+                secp256k1_gej_double(&resj, &gej[i2]);
+                ge_equals_gej(&ref, &resj);
             }
 
             /* Test adding opposites. */
@@ -2959,14 +3019,16 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
 
 void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
     secp256k1_scalar szero;
-    secp256k1_scalar sc[32];
-    secp256k1_ge pt[32];
+    secp256k1_scalar sc;
+    secp256k1_ge pt;
     secp256k1_gej r;
     ecmult_multi_data data;
     secp256k1_scratch *scratch_empty;
 
-    data.sc = sc;
-    data.pt = pt;
+    random_group_element_test(&pt);
+    random_scalar_order(&sc);
+    data.sc = &sc;
+    data.pt = &pt;
     secp256k1_scalar_set_int(&szero, 0);
 
     /* Try to multiply 1 point, but scratch space is empty.*/
@@ -3110,7 +3172,7 @@ void test_ecmult_multi_batching(void) {
     data.pt = pt;
     secp256k1_gej_neg(&r2, &r2);
 
-    /* Test with empty scratch space. It should compute the correct result using 
+    /* Test with empty scratch space. It should compute the correct result using
      * ecmult_mult_simple algorithm which doesn't require a scratch space. */
     scratch = secp256k1_scratch_create(&ctx->error_callback, 0);
     CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
@@ -3224,6 +3286,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
     int skew;
     int bits = 256;
     secp256k1_scalar num = *number;
+    secp256k1_scalar scalar_skew;
 
     secp256k1_scalar_set_int(&x, 0);
     secp256k1_scalar_set_int(&shift, 1 << w);
@@ -3254,7 +3317,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
         secp256k1_scalar_add(&x, &x, &t);
     }
     /* Skew num because when encoding numbers as odd we use an offset */
-    secp256k1_scalar_cadd_bit(&num, skew == 2, 1);
+    secp256k1_scalar_set_int(&scalar_skew, 1 << (skew == 2));
+    secp256k1_scalar_add(&num, &num, &scalar_skew);
     CHECK(secp256k1_scalar_eq(&x, &num));
 }
 
@@ -3366,13 +3430,32 @@ void run_wnaf(void) {
     int i;
     secp256k1_scalar n = {{0}};
 
+    test_constant_wnaf(&n, 4);
     /* Sanity check: 1 and 2 are the smallest odd and even numbers and should
      *               have easier-to-diagnose failure modes  */
     n.d[0] = 1;
     test_constant_wnaf(&n, 4);
     n.d[0] = 2;
     test_constant_wnaf(&n, 4);
-    /* Test 0 */
+    /* Test -1, because it's a special case in wnaf_const */
+    n = secp256k1_scalar_one;
+    secp256k1_scalar_negate(&n, &n);
+    test_constant_wnaf(&n, 4);
+
+    /* Test -2, which may not lead to overflows in wnaf_const */
+    secp256k1_scalar_add(&n, &secp256k1_scalar_one, &secp256k1_scalar_one);
+    secp256k1_scalar_negate(&n, &n);
+    test_constant_wnaf(&n, 4);
+
+    /* Test (1/2) - 1 = 1/-2 and 1/2 = (1/-2) + 1
+       as corner cases of negation handling in wnaf_const */
+    secp256k1_scalar_inverse(&n, &n);
+    test_constant_wnaf(&n, 4);
+
+    secp256k1_scalar_add(&n, &n, &secp256k1_scalar_one);
+    test_constant_wnaf(&n, 4);
+
+    /* Test 0 for fixed wnaf */
     test_fixed_wnaf_small();
     /* Random tests */
     for (i = 0; i < count; i++) {
@@ -3970,37 +4053,57 @@ void run_eckey_edge_case_test(void) {
     pubkey_negone = pubkey;
     /* Tweak of zero leaves the value unchanged. */
     memset(ctmp2, 0, 32);
-    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1);
+    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, ctmp2) == 1);
     CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40);
     memcpy(&pubkey2, &pubkey, sizeof(pubkey));
     CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
     CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
     /* Multiply tweak of zero zeroizes the output. */
-    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0);
+    CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, ctmp2) == 0);
     CHECK(memcmp(zeros, ctmp, 32) == 0);
     CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0);
     CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
     memcpy(&pubkey, &pubkey2, sizeof(pubkey));
-    /* Overflowing key tweak zeroizes. */
+    /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing
+    seckey, the seckey is zeroized. */
+    memcpy(ctmp, orderc, 32);
+    memset(ctmp2, 0, 32);
+    ctmp2[31] = 0x01;
+    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp2) == 1);
+    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
+    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, ctmp2) == 0);
+    CHECK(memcmp(zeros, ctmp, 32) == 0);
+    memcpy(ctmp, orderc, 32);
+    CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, ctmp2) == 0);
+    CHECK(memcmp(zeros, ctmp, 32) == 0);
+    /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing
+    tweak, the seckey is zeroized. */
     memcpy(ctmp, orderc, 32);
     ctmp[31] = 0x40;
-    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0);
+    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, orderc) == 0);
     CHECK(memcmp(zeros, ctmp, 32) == 0);
     memcpy(ctmp, orderc, 32);
     ctmp[31] = 0x40;
-    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0);
+    CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, orderc) == 0);
     CHECK(memcmp(zeros, ctmp, 32) == 0);
     memcpy(ctmp, orderc, 32);
     ctmp[31] = 0x40;
+    /* If pubkey_tweak_add or pubkey_tweak_mul are called with an overflowing
+    tweak, the pubkey is zeroized. */
     CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0);
     CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
     memcpy(&pubkey, &pubkey2, sizeof(pubkey));
     CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0);
     CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
     memcpy(&pubkey, &pubkey2, sizeof(pubkey));
-    /* Private key tweaks results in a key of zero. */
+    /* If the resulting key in secp256k1_ec_seckey_tweak_add and
+     * secp256k1_ec_pubkey_tweak_add is 0 the functions fail and in the latter
+     * case the pubkey is zeroized. */
+    memcpy(ctmp, orderc, 32);
+    ctmp[31] = 0x40;
+    memset(ctmp2, 0, 32);
     ctmp2[31] = 1;
-    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0);
+    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp2, ctmp) == 0);
     CHECK(memcmp(zeros, ctmp2, 32) == 0);
     ctmp2[31] = 1;
     CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0);
@@ -4008,7 +4111,7 @@ void run_eckey_edge_case_test(void) {
     memcpy(&pubkey, &pubkey2, sizeof(pubkey));
     /* Tweak computation wraps and results in a key of 1. */
     ctmp2[31] = 2;
-    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1);
+    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp2, ctmp) == 1);
     CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1);
     ctmp2[31] = 2;
     CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
@@ -4056,16 +4159,16 @@ void run_eckey_edge_case_test(void) {
     CHECK(ecount == 2);
     ecount = 0;
     memset(ctmp2, 0, 32);
-    CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0);
+    CHECK(secp256k1_ec_seckey_tweak_add(ctx, NULL, ctmp2) == 0);
     CHECK(ecount == 1);
-    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0);
+    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, NULL) == 0);
     CHECK(ecount == 2);
     ecount = 0;
     memset(ctmp2, 0, 32);
     ctmp2[31] = 1;
-    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0);
+    CHECK(secp256k1_ec_seckey_tweak_mul(ctx, NULL, ctmp2) == 0);
     CHECK(ecount == 1);
-    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0);
+    CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, NULL) == 0);
     CHECK(ecount == 2);
     ecount = 0;
     CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0);
@@ -4138,6 +4241,41 @@ void run_eckey_edge_case_test(void) {
     secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
 }
 
+void run_eckey_negate_test(void) {
+    unsigned char seckey[32];
+    unsigned char seckey_tmp[32];
+
+    random_scalar_order_b32(seckey);
+    memcpy(seckey_tmp, seckey, 32);
+
+    /* Verify negation changes the key and changes it back */
+    CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1);
+    CHECK(memcmp(seckey, seckey_tmp, 32) != 0);
+    CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1);
+    CHECK(memcmp(seckey, seckey_tmp, 32) == 0);
+
+    /* Check that privkey alias gives same result */
+    CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1);
+    CHECK(secp256k1_ec_privkey_negate(ctx, seckey_tmp) == 1);
+    CHECK(memcmp(seckey, seckey_tmp, 32) == 0);
+
+    /* Negating all 0s fails */
+    memset(seckey, 0, 32);
+    memset(seckey_tmp, 0, 32);
+    CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 0);
+    /* Check that seckey is not modified */
+    CHECK(memcmp(seckey, seckey_tmp, 32) == 0);
+
+    /* Negating an overflowing seckey fails and the seckey is zeroed. In this
+     * test, the seckey has 16 random bytes to ensure that ec_seckey_negate
+     * doesn't just set seckey to a constant value in case of failure. */
+    random_scalar_order_b32(seckey);
+    memset(seckey, 0xFF, 16);
+    memset(seckey_tmp, 0, 32);
+    CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 0);
+    CHECK(memcmp(seckey, seckey_tmp, 32) == 0);
+}
+
 void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) {
     secp256k1_scalar nonce;
     do {
@@ -4277,15 +4415,22 @@ void test_ecdsa_end_to_end(void) {
     if (secp256k1_rand_int(3) == 0) {
         int ret1;
         int ret2;
+        int ret3;
         unsigned char rnd[32];
+        unsigned char privkey_tmp[32];
         secp256k1_pubkey pubkey2;
         secp256k1_rand256_test(rnd);
-        ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd);
+        memcpy(privkey_tmp, privkey, 32);
+        ret1 = secp256k1_ec_seckey_tweak_add(ctx, privkey, rnd);
         ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd);
+        /* Check that privkey alias gives same result */
+        ret3 = secp256k1_ec_privkey_tweak_add(ctx, privkey_tmp, rnd);
         CHECK(ret1 == ret2);
+        CHECK(ret2 == ret3);
         if (ret1 == 0) {
             return;
         }
+        CHECK(memcmp(privkey, privkey_tmp, 32) == 0);
         CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
         CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
     }
@@ -4294,15 +4439,22 @@ void test_ecdsa_end_to_end(void) {
     if (secp256k1_rand_int(3) == 0) {
         int ret1;
         int ret2;
+        int ret3;
         unsigned char rnd[32];
+        unsigned char privkey_tmp[32];
         secp256k1_pubkey pubkey2;
         secp256k1_rand256_test(rnd);
-        ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd);
+        memcpy(privkey_tmp, privkey, 32);
+        ret1 = secp256k1_ec_seckey_tweak_mul(ctx, privkey, rnd);
         ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd);
+        /* Check that privkey alias gives same result */
+        ret3 = secp256k1_ec_privkey_tweak_mul(ctx, privkey_tmp, rnd);
         CHECK(ret1 == ret2);
+        CHECK(ret2 == ret3);
         if (ret1 == 0) {
             return;
         }
+        CHECK(memcmp(privkey, privkey_tmp, 32) == 0);
         CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
         CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
     }
@@ -5200,6 +5352,176 @@ void run_ecdsa_openssl(void) {
 # include "modules/recovery/tests_impl.h"
 #endif
 
+void run_memczero_test(void) {
+    unsigned char buf1[6] = {1, 2, 3, 4, 5, 6};
+    unsigned char buf2[sizeof(buf1)];
+
+    /* memczero(..., ..., 0) is a noop. */
+    memcpy(buf2, buf1, sizeof(buf1));
+    memczero(buf1, sizeof(buf1), 0);
+    CHECK(memcmp(buf1, buf2, sizeof(buf1)) == 0);
+
+    /* memczero(..., ..., 1) zeros the buffer. */
+    memset(buf2, 0, sizeof(buf2));
+    memczero(buf1, sizeof(buf1) , 1);
+    CHECK(memcmp(buf1, buf2, sizeof(buf1)) == 0);
+}
+
+void int_cmov_test(void) {
+    int r = INT_MAX;
+    int a = 0;
+
+    secp256k1_int_cmov(&r, &a, 0);
+    CHECK(r == INT_MAX);
+
+    r = 0; a = INT_MAX;
+    secp256k1_int_cmov(&r, &a, 1);
+    CHECK(r == INT_MAX);
+
+    a = 0;
+    secp256k1_int_cmov(&r, &a, 1);
+    CHECK(r == 0);
+
+    a = 1;
+    secp256k1_int_cmov(&r, &a, 1);
+    CHECK(r == 1);
+
+    r = 1; a = 0;
+    secp256k1_int_cmov(&r, &a, 0);
+    CHECK(r == 1);
+
+}
+
+void fe_cmov_test(void) {
+    static const secp256k1_fe zero = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0);
+    static const secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+    static const secp256k1_fe max = SECP256K1_FE_CONST(
+        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
+        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL
+    );
+    secp256k1_fe r = max;
+    secp256k1_fe a = zero;
+
+    secp256k1_fe_cmov(&r, &a, 0);
+    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
+
+    r = zero; a = max;
+    secp256k1_fe_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
+
+    a = zero;
+    secp256k1_fe_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &zero, sizeof(r)) == 0);
+
+    a = one;
+    secp256k1_fe_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
+
+    r = one; a = zero;
+    secp256k1_fe_cmov(&r, &a, 0);
+    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
+}
+
+void fe_storage_cmov_test(void) {
+    static const secp256k1_fe_storage zero = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0);
+    static const secp256k1_fe_storage one = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+    static const secp256k1_fe_storage max = SECP256K1_FE_STORAGE_CONST(
+        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
+        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL
+    );
+    secp256k1_fe_storage r = max;
+    secp256k1_fe_storage a = zero;
+
+    secp256k1_fe_storage_cmov(&r, &a, 0);
+    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
+
+    r = zero; a = max;
+    secp256k1_fe_storage_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
+
+    a = zero;
+    secp256k1_fe_storage_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &zero, sizeof(r)) == 0);
+
+    a = one;
+    secp256k1_fe_storage_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
+
+    r = one; a = zero;
+    secp256k1_fe_storage_cmov(&r, &a, 0);
+    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
+}
+
+void scalar_cmov_test(void) {
+    static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
+    static const secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);
+    static const secp256k1_scalar max = SECP256K1_SCALAR_CONST(
+        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
+        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL
+    );
+    secp256k1_scalar r = max;
+    secp256k1_scalar a = zero;
+
+    secp256k1_scalar_cmov(&r, &a, 0);
+    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
+
+    r = zero; a = max;
+    secp256k1_scalar_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
+
+    a = zero;
+    secp256k1_scalar_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &zero, sizeof(r)) == 0);
+
+    a = one;
+    secp256k1_scalar_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
+
+    r = one; a = zero;
+    secp256k1_scalar_cmov(&r, &a, 0);
+    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
+}
+
+void ge_storage_cmov_test(void) {
+    static const secp256k1_ge_storage zero = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+    static const secp256k1_ge_storage one = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1);
+    static const secp256k1_ge_storage max = SECP256K1_GE_STORAGE_CONST(
+        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
+        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
+        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
+        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL
+    );
+    secp256k1_ge_storage r = max;
+    secp256k1_ge_storage a = zero;
+
+    secp256k1_ge_storage_cmov(&r, &a, 0);
+    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
+
+    r = zero; a = max;
+    secp256k1_ge_storage_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
+
+    a = zero;
+    secp256k1_ge_storage_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &zero, sizeof(r)) == 0);
+
+    a = one;
+    secp256k1_ge_storage_cmov(&r, &a, 1);
+    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
+
+    r = one; a = zero;
+    secp256k1_ge_storage_cmov(&r, &a, 0);
+    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
+}
+
+void run_cmov_tests(void) {
+    int_cmov_test();
+    fe_cmov_test();
+    fe_storage_cmov_test();
+    scalar_cmov_test();
+    ge_storage_cmov_test();
+}
+
 int main(int argc, char **argv) {
     unsigned char seed16[16] = {0};
     unsigned char run32[32] = {0};
@@ -5313,6 +5635,9 @@ int main(int argc, char **argv) {
     /* EC key edge cases */
     run_eckey_edge_case_test();
 
+    /* EC key arithmetic test */
+    run_eckey_negate_test();
+
 #ifdef ENABLE_MODULE_ECDH
     /* ecdh tests */
     run_ecdh_tests();
@@ -5333,6 +5658,11 @@ int main(int argc, char **argv) {
     run_recovery_tests();
 #endif
 
+    /* util tests */
+    run_memczero_test();
+
+    run_cmov_tests();
+
     secp256k1_rand256(run32);
     printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]);
 
index b44e357cb69c742b1eccb94695412960c82e6385..681ed80bd0bc4ef2108313195ad89a3dd54e46b5 100644 (file)
@@ -22,6 +22,7 @@
 #endif
 
 #include "include/secp256k1.h"
+#include "assumptions.h"
 #include "group.h"
 #include "secp256k1.c"
 #include "testrand_impl.h"
@@ -141,10 +142,8 @@ void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *gr
     /* Check doubling */
     for (i = 0; i < order; i++) {
         secp256k1_gej tmp;
-        if (i > 0) {
-            secp256k1_gej_double_nonzero(&tmp, &groupj[i], NULL);
-            ge_equals_gej(&group[(2 * i) % order], &tmp);
-        }
+        secp256k1_gej_double(&tmp, &groupj[i]);
+        ge_equals_gej(&group[(2 * i) % order], &tmp);
         secp256k1_gej_double_var(&tmp, &groupj[i], NULL);
         ge_equals_gej(&group[(2 * i) % order], &tmp);
     }
index 9deb61bc59d153c987ecc3a8fdca91962344e591..a5cbe03ef52198544e5448888978a6bab772106a 100644 (file)
@@ -14,6 +14,7 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <limits.h>
 
 typedef struct {
     void (*fn)(const char *text, void* data);
@@ -68,6 +69,25 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback *
 #define VERIFY_SETUP(stmt)
 #endif
 
+/* Define `VG_UNDEF` and `VG_CHECK` when VALGRIND is defined  */
+#if !defined(VG_CHECK)
+# if defined(VALGRIND)
+#  include <valgrind/memcheck.h>
+#  define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y))
+#  define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y))
+# else
+#  define VG_UNDEF(x,y)
+#  define VG_CHECK(x,y)
+# endif
+#endif
+
+/* Like `VG_CHECK` but on VERIFY only */
+#if defined(VERIFY)
+#define VG_CHECK_VERIFY(x,y) VG_CHECK((x), (y))
+#else
+#define VG_CHECK_VERIFY(x,y)
+#endif
+
 static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) {
     void *ret = malloc(size);
     if (ret == NULL) {
@@ -150,13 +170,86 @@ static SECP256K1_INLINE void *manual_alloc(void** prealloc_ptr, size_t alloc_siz
 # define I64uFORMAT "llu"
 #endif
 
-#if defined(HAVE___INT128)
-# if defined(__GNUC__)
-#  define SECP256K1_GNUC_EXT __extension__
-# else
-#  define SECP256K1_GNUC_EXT
+#if defined(__GNUC__)
+# define SECP256K1_GNUC_EXT __extension__
+#else
+# define SECP256K1_GNUC_EXT
+#endif
+
+/* If SECP256K1_{LITTLE,BIG}_ENDIAN is not explicitly provided, infer from various other system macros. */
+#if !defined(SECP256K1_LITTLE_ENDIAN) && !defined(SECP256K1_BIG_ENDIAN)
+/* Inspired by https://github.com/rofl0r/endianness.h/blob/9853923246b065a3b52d2c43835f3819a62c7199/endianness.h#L52L73 */
+# if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
+     defined(_X86_) || defined(__x86_64__) || defined(__i386__) || \
+     defined(__i486__) || defined(__i586__) || defined(__i686__) || \
+     defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) || \
+     defined(__ARMEL__) || defined(__AARCH64EL__) || \
+     (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \
+     (defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN == 1) || \
+     defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM) /* MSVC */
+#  define SECP256K1_LITTLE_ENDIAN
+# endif
+# if (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
+     defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) || \
+     defined(__MICROBLAZEEB__) || defined(__ARMEB__) || defined(__AARCH64EB__) || \
+     (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \
+     (defined(_BIG_ENDIAN) && _BIG_ENDIAN == 1)
+#  define SECP256K1_BIG_ENDIAN
 # endif
+#endif
+#if defined(SECP256K1_LITTLE_ENDIAN) == defined(SECP256K1_BIG_ENDIAN)
+# error Please make sure that either SECP256K1_LITTLE_ENDIAN or SECP256K1_BIG_ENDIAN is set, see src/util.h.
+#endif
+
+/* Zero memory if flag == 1. Flag must be 0 or 1. Constant time. */
+static SECP256K1_INLINE void memczero(void *s, size_t len, int flag) {
+    unsigned char *p = (unsigned char *)s;
+    /* Access flag with a volatile-qualified lvalue.
+       This prevents clang from figuring out (after inlining) that flag can
+       take only be 0 or 1, which leads to variable time code. */
+    volatile int vflag = flag;
+    unsigned char mask = -(unsigned char) vflag;
+    while (len) {
+        *p &= ~mask;
+        p++;
+        len--;
+    }
+}
+
+/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time.  Both *r and *a must be initialized and non-negative.*/
+static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag) {
+    unsigned int mask0, mask1, r_masked, a_masked;
+    /* Access flag with a volatile-qualified lvalue.
+       This prevents clang from figuring out (after inlining) that flag can
+       take only be 0 or 1, which leads to variable time code. */
+    volatile int vflag = flag;
+
+    /* Casting a negative int to unsigned and back to int is implementation defined behavior */
+    VERIFY_CHECK(*r >= 0 && *a >= 0);
+
+    mask0 = (unsigned int)vflag + ~0u;
+    mask1 = ~mask0;
+    r_masked = ((unsigned int)*r & mask0);
+    a_masked = ((unsigned int)*a & mask1);
+
+    *r = (int)(r_masked | a_masked);
+}
+
+/* If USE_FORCE_WIDEMUL_{INT128,INT64} is set, use that wide multiplication implementation.
+ * Otherwise use the presence of __SIZEOF_INT128__ to decide.
+ */
+#if defined(USE_FORCE_WIDEMUL_INT128)
+# define SECP256K1_WIDEMUL_INT128 1
+#elif defined(USE_FORCE_WIDEMUL_INT64)
+# define SECP256K1_WIDEMUL_INT64 1
+#elif defined(__SIZEOF_INT128__)
+# define SECP256K1_WIDEMUL_INT128 1
+#else
+# define SECP256K1_WIDEMUL_INT64 1
+#endif
+#if defined(SECP256K1_WIDEMUL_INT128)
 SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
+SECP256K1_GNUC_EXT typedef __int128 int128_t;
 #endif
 
 #endif /* SECP256K1_UTIL_H */
diff --git a/src/valgrind_ctime_test.c b/src/valgrind_ctime_test.c
new file mode 100644 (file)
index 0000000..090fde2
--- /dev/null
@@ -0,0 +1,120 @@
+/**********************************************************************
+ * Copyright (c) 2020 Gregory Maxwell                                 *
+ * Distributed under the MIT software license, see the accompanying   *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include <valgrind/memcheck.h>
+#include "include/secp256k1.h"
+#include "assumptions.h"
+#include "util.h"
+
+#if ENABLE_MODULE_ECDH
+# include "include/secp256k1_ecdh.h"
+#endif
+
+#if ENABLE_MODULE_RECOVERY
+# include "include/secp256k1_recovery.h"
+#endif
+
+int main(void) {
+    secp256k1_context* ctx;
+    secp256k1_ecdsa_signature signature;
+    secp256k1_pubkey pubkey;
+    size_t siglen = 74;
+    size_t outputlen = 33;
+    int i;
+    int ret;
+    unsigned char msg[32];
+    unsigned char key[32];
+    unsigned char sig[74];
+    unsigned char spubkey[33];
+#if ENABLE_MODULE_RECOVERY
+    secp256k1_ecdsa_recoverable_signature recoverable_signature;
+    int recid;
+#endif
+
+    if (!RUNNING_ON_VALGRIND) {
+        fprintf(stderr, "This test can only usefully be run inside valgrind.\n");
+        fprintf(stderr, "Usage: libtool --mode=execute valgrind ./valgrind_ctime_test\n");
+        exit(1);
+    }
+
+    /** In theory, testing with a single secret input should be sufficient:
+     *  If control flow depended on secrets the tool would generate an error.
+     */
+    for (i = 0; i < 32; i++) {
+        key[i] = i + 65;
+    }
+    for (i = 0; i < 32; i++) {
+        msg[i] = i + 1;
+    }
+
+    ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_DECLASSIFY);
+
+    /* Test keygen. */
+    VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+    ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key);
+    VALGRIND_MAKE_MEM_DEFINED(&pubkey, sizeof(secp256k1_pubkey));
+    VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+    CHECK(ret);
+    CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
+
+    /* Test signing. */
+    VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+    ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL);
+    VALGRIND_MAKE_MEM_DEFINED(&signature, sizeof(secp256k1_ecdsa_signature));
+    VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+    CHECK(ret);
+    CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature));
+
+#if ENABLE_MODULE_ECDH
+    /* Test ECDH. */
+    VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+    ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL);
+    VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+    CHECK(ret == 1);
+#endif
+
+#if ENABLE_MODULE_RECOVERY
+    /* Test signing a recoverable signature. */
+    VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+    ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL);
+    VALGRIND_MAKE_MEM_DEFINED(&recoverable_signature, sizeof(recoverable_signature));
+    VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+    CHECK(ret);
+    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature));
+    CHECK(recid >= 0 && recid <= 3);
+#endif
+
+    VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+    ret = secp256k1_ec_seckey_verify(ctx, key);
+    VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+    CHECK(ret == 1);
+
+    VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+    ret = secp256k1_ec_seckey_negate(ctx, key);
+    VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+    CHECK(ret == 1);
+
+    VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+    VALGRIND_MAKE_MEM_UNDEFINED(msg, 32);
+    ret = secp256k1_ec_seckey_tweak_add(ctx, key, msg);
+    VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+    CHECK(ret == 1);
+
+    VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+    VALGRIND_MAKE_MEM_UNDEFINED(msg, 32);
+    ret = secp256k1_ec_seckey_tweak_mul(ctx, key, msg);
+    VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+    CHECK(ret == 1);
+
+    /* Test context randomisation. Do this last because it leaves the context tainted. */
+    VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+    ret = secp256k1_context_randomize(ctx, key);
+    VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+    CHECK(ret);
+
+    secp256k1_context_destroy(ctx);
+    return 0;
+}
This page took 0.2333 seconds and 4 git commands to generate.