Repository: bitcoin-core/secp256k1
Pull request #310 (2015-09-18 01:13:27)

Add exhaustive test for group functions on a low-order subgroup
We observe that when changing the b-value in the elliptic curve formula
`y^2 = x^3 + ax + b`, the group law is unchanged. Therefore our functions
for secp256k1 will be correct if and only if they are correct when applied
to the curve defined by `y^2 = x^3 + 4` defined over the same field. This
curve has a point P of order 199.

This commit adds a test which computes the subgroup generated by P and
exhaustively checks that addition of every pair of points gives the correct
result.

Unfortunately we cannot test scalar multiplication, const-time or otherwise,
by the same mechanism. The reason is that our ecmult functions both compute
a wNAF representation of the scalar, and this representation is tied to the
order of the group.

Testing with the incomplete version of gej_add_ge (found in 5de4c5dff^)
shows that this detects the incompleteness when adding P - 106P, which
is exactly what we expected since 106 is a cube root of 1 mod 199.

Exhaustive tests added for the following internal functions:
- `secp256k1_ge_is_infinity`, `secp256k1_gej_is_infinity`
- `secp256k1_gej_add_var`, `secp256k1_gej_add_ge`, `secp256k1_gej_add_ge_var`, `secp256k1_gej_add_zinv_var`
- `secp256k1_gej_double_nonzero`, `secp256k1_gej_double_var`
- `secp256k1_ge_neg`, `secp256k1_gej_neg`
- `secp256k1_ecmult`, `secp256k1_ecmult_const`

And also (unfortunately with a bit of surgery; the original functions don't work with small group orders)
- `secp256k1_ecdsa_sign`
- `secp256k1_ecdsa_verify`


apoelstra: Rebased and completed verification
apoelstra: Updated to just disable static precomputation for `tests_exhaustive.c` instead of whining to the user about her ./configure options.
apoelstra: Updated to force-disable the endomorphism optimization for the exhaustive tests, since the `scalar_low` impl it uses does not support it.
apoelstra: Updated again to put endomorphism support back and just implement `SECP256K1_SCALAR_CONST`, which was the point of incompatibility. Turns out the Schnorr module also needs this macro.
sipa: Hmm, how can the endomorphism work without changing the lambda constant? (a cubic root of 1 mod the curve order)
apoelstra: @sipa it observably does .. I have not checked into why but my belief is that it always splits `n` into `n + 0*lambda` for such small `n`.

Patch:
diff --git a/.gitignore b/.gitignore
index efb277d..87fea16 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ bench_schnorr_verify
 bench_recover
 bench_internal
 tests
+exhaustive_tests
 gen_context
 *.exe
 *.so
diff --git a/Makefile.am b/Makefile.am
index 7461ff3..e5657f7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,9 +12,11 @@ noinst_HEADERS =
 noinst_HEADERS += src/scalar.h
 noinst_HEADERS += src/scalar_4x64.h
 noinst_HEADERS += src/scalar_8x32.h
+noinst_HEADERS += src/scalar_low.h
 noinst_HEADERS += src/scalar_impl.h
 noinst_HEADERS += src/scalar_4x64_impl.h
 noinst_HEADERS += src/scalar_8x32_impl.h
+noinst_HEADERS += src/scalar_low_impl.h
 noinst_HEADERS += src/group.h
 noinst_HEADERS += src/group_impl.h
 noinst_HEADERS += src/num_gmp.h
@@ -87,13 +89,23 @@ bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
 bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
 endif
 
+TESTS =
 if USE_TESTS
 noinst_PROGRAMS += tests
 tests_SOURCES = src/tests.c
 tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
 tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
 tests_LDFLAGS = -static
-TESTS = tests
+TESTS += tests
+endif
+
+if USE_EXHAUSTIVE_TESTS
+noinst_PROGRAMS += exhaustive_tests
+exhaustive_tests_SOURCES = src/tests_exhaustive.c
+exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src $(SECP_INCLUDES)
+exhaustive_tests_LDADD = $(SECP_LIBS)
+exhaustive_tests_LDFLAGS = -static
+TESTS += exhaustive_tests
 endif
 
 JAVAROOT=src/java
diff --git a/configure.ac b/configure.ac
index 1933f71..ec50ffe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -104,6 +104,11 @@ AC_ARG_ENABLE(experimental,
     [use_experimental=$enableval],
     [use_experimental=no])
 
+AC_ARG_ENABLE(exhaustive_tests,
+    AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]),
+    [use_exhaustive_tests=$enableval],
+    [use_exhaustive_tests=yes])
+
 AC_ARG_ENABLE(endomorphism,
     AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
     [use_endomorphism=$enableval],
@@ -456,6 +461,7 @@ AC_SUBST(SECP_LIBS)
 AC_SUBST(SECP_TEST_LIBS)
 AC_SUBST(SECP_TEST_INCLUDES)
 AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
+AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
 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"])
diff --git a/src/ecdsa_impl.h b/src/ecdsa_impl.h
index d110b4b..9a42e51 100644
--- a/src/ecdsa_impl.h
+++ b/src/ecdsa_impl.h
@@ -203,7 +203,9 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const
 static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) {
     unsigned char c[32];
     secp256k1_scalar sn, u1, u2;
+#if !defined(EXHAUSTIVE_TEST_ORDER)
     secp256k1_fe xr;
+#endif
     secp256k1_gej pubkeyj;
     secp256k1_gej pr;
 
@@ -219,6 +221,21 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const
     if (secp256k1_gej_is_infinity(&pr)) {
         return 0;
     }
+
+#if defined(EXHAUSTIVE_TEST_ORDER)
+{
+    secp256k1_scalar computed_r;
+    int overflow = 0;
+    secp256k1_ge pr_ge;
+    secp256k1_ge_set_gej(&pr_ge, &pr);
+    secp256k1_fe_normalize(&pr_ge.x);
+
+    secp256k1_fe_get_b32(c, &pr_ge.x);
+    secp256k1_scalar_set_b32(&computed_r, c, &overflow);
+    /* we fully expect overflow */
+    return secp256k1_scalar_eq(sigr, &computed_r);
+}
+#else
     secp256k1_scalar_get_b32(c, sigr);
     secp256k1_fe_set_b32(&xr, c);
 
@@ -252,6 +269,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const
         return 1;
     }
     return 0;
+#endif
 }
 
 static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) {
diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h
index 7a6a253..0db314c 100644
--- a/src/ecmult_const_impl.h
+++ b/src/ecmult_const_impl.h
@@ -78,7 +78,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
     /* Negative numbers will be negated to keep their bit representation below the maximum width */
     flip = secp256k1_scalar_is_high(&s);
     /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
-    bit = flip ^ (s.d[0] & 1);
+    bit = flip ^ !secp256k1_scalar_is_even(&s);
     /* We check for negative one, since adding 2 to it will cause an overflow */
     secp256k1_scalar_negate(&neg_s, &s);
     not_neg_one = !secp256k1_scalar_is_one(&neg_s);
diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h
index d1e83bd..4e40104 100644
--- a/src/ecmult_impl.h
+++ b/src/ecmult_impl.h
@@ -7,15 +7,29 @@
 #ifndef _SECP256K1_ECMULT_IMPL_H_
 #define _SECP256K1_ECMULT_IMPL_H_
 
+#include <string.h>
+
 #include "group.h"
 #include "scalar.h"
 #include "ecmult.h"
 
-#include <string.h>
-
+#if defined(EXHAUSTIVE_TEST_ORDER)
+/* We need to lower these values for exhaustive tests because
+ * the tables cannot have infinities in them (this breaks the
+ * affine-isomorphism stuff which tracks z-ratios) */
+#  if EXHAUSTIVE_TEST_ORDER > 128
+#    define WINDOW_A 5
+#    define WINDOW_G 8
+#  elif EXHAUSTIVE_TEST_ORDER > 8
+#    define WINDOW_A 4
+#    define WINDOW_G 4
+#  else
+#    define WINDOW_A 2
+#    define WINDOW_G 2
+#  endif
+#else
 /* optimal for 128-bit and 256-bit exponents. */
 #define WINDOW_A 5
-
 /** larger numbers may result in slightly better performance, at the cost of
     exponentially larger precomputed tables. */
 #ifdef USE_ENDOMORPHISM
@@ -25,6 +39,7 @@
 /** One table for window size 16: 1.375 MiB. */
 #define WINDOW_G 16
 #endif
+#endif
 
 /** The number of entries a table with precomputed multiples needs to have. */
 #define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))
diff --git a/src/field.h b/src/field.h
index 4daefc4..bbb1ee8 100644
--- a/src/field.h
+++ b/src/field.h
@@ -30,6 +30,8 @@
 #error "Please select field implementation"
 #endif
 
+#include "util.h"
+
 /** Normalize a field element. */
 static void secp256k1_fe_normalize(secp256k1_fe *r);
 
@@ -50,6 +52,9 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r);
 /** Set a field element equal to a small integer. Resulting field element is normalized. */
 static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
 
+/** Sets a field element equal to zero, initializing all fields. */
+static void secp256k1_fe_clear(secp256k1_fe *a);
+
 /** Verify whether a field element is zero. Requires the input to be normalized. */
 static int secp256k1_fe_is_zero(const secp256k1_fe *a);
 
diff --git a/src/group_impl.h b/src/group_impl.h
index 18f2b37..2e192b6 100644
--- a/src/group_impl.h
+++ b/src/group_impl.h
@@ -11,6 +11,53 @@
 #include "field.h"
 #include "group.h"
 
+/* These points can be generated in sage as follows:
+ *
+ * 0. Setup a worksheet with the following parameters.
+ *   b = 4  # whatever CURVE_B will be set to
+ *   F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
+ *   C = EllipticCurve ([F (0), F (b)])
+ *
+ * 1. Determine all the small orders available to you. (If there are
+ *    no satisfactory ones, go back and change b.)
+ *   print C.order().factor(limit=1000)
+ *
+ * 2. Choose an order as one of the prime factors listed in the above step.
+ *    (You can also multiply some to get a composite order, though the
+ *    tests will crash trying to invert scalars during signing.) We take a
+ *    random point and scale it to drop its order to the desired value.
+ *    There is some probability this won't work; just try again.
+ *   order = 199
+ *   P = C.random_point()
+ *   P = (int(P.order()) / int(order)) * P
+ *   assert(P.order() == order)
+ *
+ * 3. Print the values. You'll need to use a vim macro or something to
+ *    split the hex output into 4-byte chunks.
+ *   print "%x %x" % P.xy()
+ */
+#if defined(EXHAUSTIVE_TEST_ORDER)
+#  if EXHAUSTIVE_TEST_ORDER == 199
+const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
+    0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069,
+    0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18,
+    0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868,
+    0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED
+);
+
+const int CURVE_B = 4;
+#  elif EXHAUSTIVE_TEST_ORDER == 13
+const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
+    0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0,
+    0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15,
+    0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e,
+    0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac
+);
+const int CURVE_B = 2;
+#  else
+#    error No known generator for the specified exhaustive test group order.
+#  endif
+#else
 /** Generator for secp256k1, value 'g' defined in
  *  "Standards for Efficient Cryptography" (SEC2) 2.7.1.
  */
@@ -21,6 +68,9 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
     0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
 );
 
+const int CURVE_B = 7;
+#endif
+
 static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
     secp256k1_fe zi2;
     secp256k1_fe zi3;
@@ -145,9 +195,15 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp
 
 static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
     r->infinity = 1;
-    secp256k1_fe_set_int(&r->x, 0);
-    secp256k1_fe_set_int(&r->y, 0);
-    secp256k1_fe_set_int(&r->z, 0);
+    secp256k1_fe_clear(&r->x);
+    secp256k1_fe_clear(&r->y);
+    secp256k1_fe_clear(&r->z);
+}
+
+static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
+    r->infinity = 1;
+    secp256k1_fe_clear(&r->x);
+    secp256k1_fe_clear(&r->y);
 }
 
 static void secp256k1_gej_clear(secp256k1_gej *r) {
@@ -169,7 +225,7 @@ static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
     secp256k1_fe_sqr(&x2, x);
     secp256k1_fe_mul(&x3, x, &x2);
     r->infinity = 0;
-    secp256k1_fe_set_int(&c, 7);
+    secp256k1_fe_set_int(&c, CURVE_B);
     secp256k1_fe_add(&c, &x3);
     return secp256k1_fe_sqrt(&r->y, &c);
 }
@@ -228,7 +284,7 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) {
     secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
     secp256k1_fe_sqr(&z2, &a->z);
     secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
-    secp256k1_fe_mul_int(&z6, 7);
+    secp256k1_fe_mul_int(&z6, CURVE_B);
     secp256k1_fe_add(&x3, &z6);
     secp256k1_fe_normalize_weak(&x3);
     return secp256k1_fe_equal_var(&y2, &x3);
@@ -242,7 +298,7 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
     /* y^2 = x^3 + 7 */
     secp256k1_fe_sqr(&y2, &a->y);
     secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
-    secp256k1_fe_set_int(&c, 7);
+    secp256k1_fe_set_int(&c, CURVE_B);
     secp256k1_fe_add(&x3, &c);
     secp256k1_fe_normalize_weak(&x3);
     return secp256k1_fe_equal_var(&y2, &x3);
diff --git a/src/scalar.h b/src/scalar.h
index b590ccd..27e9d83 100644
--- a/src/scalar.h
+++ b/src/scalar.h
@@ -13,7 +13,9 @@
 #include "libsecp256k1-config.h"
 #endif
 
-#if defined(USE_SCALAR_4X64)
+#if defined(EXHAUSTIVE_TEST_ORDER)
+#include "scalar_low.h"
+#elif defined(USE_SCALAR_4X64)
 #include "scalar_4x64.h"
 #elif defined(USE_SCALAR_8X32)
 #include "scalar_8x32.h"
diff --git a/src/scalar_impl.h b/src/scalar_impl.h
index c5baf4d..f5b2376 100644
--- a/src/scalar_impl.h
+++ b/src/scalar_impl.h
@@ -14,7 +14,9 @@
 #include "libsecp256k1-config.h"
 #endif
 
-#if defined(USE_SCALAR_4X64)
+#if defined(EXHAUSTIVE_TEST_ORDER)
+#include "scalar_low_impl.h"
+#elif defined(USE_SCALAR_4X64)
 #include "scalar_4x64_impl.h"
 #elif defined(USE_SCALAR_8X32)
 #include "scalar_8x32_impl.h"
@@ -31,17 +33,37 @@ static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a
 
 /** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */
 static void secp256k1_scalar_order_get_num(secp256k1_num *r) {
+#if defined(EXHAUSTIVE_TEST_ORDER)
+    static const unsigned char order[32] = {
+        0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,EXHAUSTIVE_TEST_ORDER
+    };
+#else
     static const unsigned char order[32] = {
         0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
         0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
         0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
         0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
     };
+#endif
     secp256k1_num_set_bin(r, order, 32);
 }
 #endif
 
 static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) {
+#if defined(EXHAUSTIVE_TEST_ORDER)
+    int i;
+    *r = 0;
+    for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++)
+        if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1)
+            *r = i;
+    /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus
+     * have a composite group order; fix it in exhaustive_tests.c). */
+    VERIFY_CHECK(*r != 0);
+}
+#else
     secp256k1_scalar *t;
     int i;
     /* First compute x ^ (2^N - 1) for some values of N. */
@@ -233,9 +255,9 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
 }
 
 SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
-    /* d[0] is present and is the lowest word for all representations */
     return !(a->d[0] & 1);
 }
+#endif
 
 static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
 #if defined(USE_SCALAR_INV_BUILTIN)
@@ -259,6 +281,18 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc
 }
 
 #ifdef USE_ENDOMORPHISM
+#if defined(EXHAUSTIVE_TEST_ORDER)
+/**
+ * Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the
+ * full case we don't bother making k1 and k2 be small, we just want them to be
+ * nontrivial to get full test coverage for the exhaustive tests. We therefore
+ * (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda.
+ */
+static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
+    *r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER;
+    *r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER;
+}
+#else
 /**
  * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where
  * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
@@ -331,5 +365,6 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
     secp256k1_scalar_add(r1, r1, a);
 }
 #endif
+#endif
 
 #endif
diff --git a/src/scalar_low.h b/src/scalar_low.h
new file mode 100644
index 0000000..5574c44
--- /dev/null
+++ b/src/scalar_low.h
@@ -0,0 +1,15 @@
+/**********************************************************************
+ * Copyright (c) 2015 Andrew Poelstra                                 *
+ * Distributed under the MIT software license, see the accompanying   *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_SCALAR_REPR_
+#define _SECP256K1_SCALAR_REPR_
+
+#include <stdint.h>
+
+/** A scalar modulo the group order of the secp256k1 curve. */
+typedef uint32_t secp256k1_scalar;
+
+#endif
diff --git a/src/scalar_low_impl.h b/src/scalar_low_impl.h
new file mode 100644
index 0000000..4f94441
--- /dev/null
+++ b/src/scalar_low_impl.h
@@ -0,0 +1,114 @@
+/**********************************************************************
+ * Copyright (c) 2015 Andrew Poelstra                                 *
+ * Distributed under the MIT software license, see the accompanying   *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
+#define _SECP256K1_SCALAR_REPR_IMPL_H_
+
+#include "scalar.h"
+
+#include <string.h>
+
+SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
+    return !(*a & 1);
+}
+
+SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; }
+SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; }
+
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
+    if (offset < 32)
+        return ((*a >> offset) & ((((uint32_t)1) << count) - 1));
+    else
+        return 0;
+}
+
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
+    return secp256k1_scalar_get_bits(a, offset, count);
+}
+
+SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; }
+
+static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
+    *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER;
+    return *r < *b;
+}
+
+static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
+    if (flag && bit < 32)
+        *r += (1 << bit);
+#ifdef VERIFY
+    VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
+#endif
+}
+
+static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
+    const int base = 0x100 % EXHAUSTIVE_TEST_ORDER;
+    int i;
+    *r = 0;
+    for (i = 0; i < 32; i++) {
+       *r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER;
+    }
+    /* just deny overflow, it basically always happens */
+    if (overflow) *overflow = 0;
+}
+
+static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
+    memset(bin, 0, 32);
+    bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;
+}
+
+SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
+    return *a == 0;
+}
+
+static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
+    if (*a == 0) {
+        *r = 0;
+    } else {
+        *r = EXHAUSTIVE_TEST_ORDER - *a;
+    }
+}
+
+SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
+    return *a == 1;
+}
+
+static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
+    return *a > EXHAUSTIVE_TEST_ORDER / 2;
+}
+
+static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
+    if (flag) secp256k1_scalar_negate(r, r);
+    return flag ? -1 : 1;
+}
+
+static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
+    *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER;
+}
+
+static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
+    int ret;
+    VERIFY_CHECK(n > 0);
+    VERIFY_CHECK(n < 16);
+    ret = *r & ((1 << n) - 1);
+    *r >>= n;
+    return ret;
+}
+
+static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
+    *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER;
+}
+
+static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
+    *r1 = *a;
+    *r2 = 0;
+}
+
+SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
+    return *a == *b;
+}
+
+#endif


Test patch:
diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c
new file mode 100644
index 0000000..bda6ee4
--- /dev/null
+++ b/src/tests_exhaustive.c
@@ -0,0 +1,329 @@
+/***********************************************************************
+ * Copyright (c) 2016 Andrew Poelstra                                 *
+ * Distributed under the MIT software license, see the accompanying   *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#if defined HAVE_CONFIG_H
+#include "libsecp256k1-config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <time.h>
+
+#undef USE_ECMULT_STATIC_PRECOMPUTATION
+
+#ifndef EXHAUSTIVE_TEST_ORDER
+/* see group_impl.h for allowable values */
+#define EXHAUSTIVE_TEST_ORDER 13
+#define EXHAUSTIVE_TEST_LAMBDA 9   /* cube root of 1 mod 13 */
+#endif
+
+#include "include/secp256k1.h"
+#include "group.h"
+#include "secp256k1.c"
+#include "testrand_impl.h"
+
+/** stolen from tests.c */
+void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
+    CHECK(a->infinity == b->infinity);
+    if (a->infinity) {
+        return;
+    }
+    CHECK(secp256k1_fe_equal_var(&a->x, &b->x));
+    CHECK(secp256k1_fe_equal_var(&a->y, &b->y));
+}
+
+void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
+    secp256k1_fe z2s;
+    secp256k1_fe u1, u2, s1, s2;
+    CHECK(a->infinity == b->infinity);
+    if (a->infinity) {
+        return;
+    }
+    /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */
+    secp256k1_fe_sqr(&z2s, &b->z);
+    secp256k1_fe_mul(&u1, &a->x, &z2s);
+    u2 = b->x; secp256k1_fe_normalize_weak(&u2);
+    secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z);
+    s2 = b->y; secp256k1_fe_normalize_weak(&s2);
+    CHECK(secp256k1_fe_equal_var(&u1, &u2));
+    CHECK(secp256k1_fe_equal_var(&s1, &s2));
+}
+
+void random_fe(secp256k1_fe *x) {
+    unsigned char bin[32];
+    do {
+        secp256k1_rand256(bin);
+        if (secp256k1_fe_set_b32(x, bin)) {
+            return;
+        }
+    } while(1);
+}
+/** END stolen from tests.c */
+
+int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32,
+                                      const unsigned char *key32, const unsigned char *algo16,
+                                      void *data, unsigned int attempt) {
+    secp256k1_scalar s;
+    int *idata = data;
+    (void)msg32;
+    (void)key32;
+    (void)algo16;
+    /* Some nonces cannot be used because they'd cause s and/or r to be zero.
+     * The signing function has retry logic here that just re-calls the nonce
+     * function with an increased `attempt`. So if attempt > 0 this means we
+     * need to change the nonce to avoid an infinite loop. */
+    if (attempt > 0) {
+        (*idata)++;
+    }
+    secp256k1_scalar_set_int(&s, *idata);
+    secp256k1_scalar_get_b32(nonce32, &s);
+    return 1;
+}
+
+#ifdef USE_ENDOMORPHISM
+void test_exhaustive_endomorphism(const secp256k1_ge *group, int order) {
+    int i;
+    for (i = 0; i < order; i++) {
+        secp256k1_ge res;
+        secp256k1_ge_mul_lambda(&res, &group[i]);
+        ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res);
+    }
+}
+#endif
+
+void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj, int order) {
+    int i, j;
+
+    /* Sanity-check (and check infinity functions) */
+    CHECK(secp256k1_ge_is_infinity(&group[0]));
+    CHECK(secp256k1_gej_is_infinity(&groupj[0]));
+    for (i = 1; i < order; i++) {
+        CHECK(!secp256k1_ge_is_infinity(&group[i]));
+        CHECK(!secp256k1_gej_is_infinity(&groupj[i]));
+    }
+
+    /* Check all addition formulae */
+    for (j = 0; j < order; j++) {
+        secp256k1_fe fe_inv;
+        secp256k1_fe_inv(&fe_inv, &groupj[j].z);
+        for (i = 0; i < order; i++) {
+            secp256k1_ge zless_gej;
+            secp256k1_gej tmp;
+            /* add_var */
+            secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL);
+            ge_equals_gej(&group[(i + j) % order], &tmp);
+            /* add_ge */
+            if (j > 0) {
+                secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]);
+                ge_equals_gej(&group[(i + j) % order], &tmp);
+            }
+            /* add_ge_var */
+            secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL);
+            ge_equals_gej(&group[(i + j) % order], &tmp);
+            /* add_zinv_var */
+            zless_gej.infinity = groupj[j].infinity;
+            zless_gej.x = groupj[j].x;
+            zless_gej.y = groupj[j].y;
+            secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv);
+            ge_equals_gej(&group[(i + j) % order], &tmp);
+        }
+    }
+
+    /* 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_var(&tmp, &groupj[i], NULL);
+        ge_equals_gej(&group[(2 * i) % order], &tmp);
+    }
+
+    /* Check negation */
+    for (i = 1; i < order; i++) {
+        secp256k1_ge tmp;
+        secp256k1_gej tmpj;
+        secp256k1_ge_neg(&tmp, &group[i]);
+        ge_equals_ge(&group[order - i], &tmp);
+        secp256k1_gej_neg(&tmpj, &groupj[i]);
+        ge_equals_gej(&group[order - i], &tmpj);
+    }
+}
+
+void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj, int order) {
+    int i, j, r_log;
+    for (r_log = 1; r_log < order; r_log++) {
+        for (j = 0; j < order; j++) {
+            for (i = 0; i < order; i++) {
+                secp256k1_gej tmp;
+                secp256k1_scalar na, ng;
+                secp256k1_scalar_set_int(&na, i);
+                secp256k1_scalar_set_int(&ng, j);
+
+                secp256k1_ecmult(&ctx->ecmult_ctx, &tmp, &groupj[r_log], &na, &ng);
+                ge_equals_gej(&group[(i * r_log + j) % order], &tmp);
+
+                if (i > 0) {
+                    secp256k1_ecmult_const(&tmp, &group[i], &ng);
+                    ge_equals_gej(&group[(i * j) % order], &tmp);
+                }
+            }
+        }
+    }
+}
+
+void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) {
+    secp256k1_fe x;
+    unsigned char x_bin[32];
+    k %= EXHAUSTIVE_TEST_ORDER;
+    x = group[k].x;
+    secp256k1_fe_normalize(&x);
+    secp256k1_fe_get_b32(x_bin, &x);
+    secp256k1_scalar_set_b32(r, x_bin, NULL);
+}
+
+void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
+    int s, r, msg, key;
+    for (s = 1; s < order; s++) {
+        for (r = 1; r < order; r++) {
+            for (msg = 1; msg < order; msg++) {
+                for (key = 1; key < order; key++) {
+                    secp256k1_ge nonconst_ge;
+                    secp256k1_ecdsa_signature sig;
+                    secp256k1_pubkey pk;
+                    secp256k1_scalar sk_s, msg_s, r_s, s_s;
+                    secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s;
+                    int k, should_verify;
+                    unsigned char msg32[32];
+
+                    secp256k1_scalar_set_int(&s_s, s);
+                    secp256k1_scalar_set_int(&r_s, r);
+                    secp256k1_scalar_set_int(&msg_s, msg);
+                    secp256k1_scalar_set_int(&sk_s, key);
+
+                    /* Verify by hand */
+                    /* Run through every k value that gives us this r and check that *one* works.
+                     * Note there could be none, there could be multiple, ECDSA is weird. */
+                    should_verify = 0;
+                    for (k = 0; k < order; k++) {
+                        secp256k1_scalar check_x_s;
+                        r_from_k(&check_x_s, group, k);
+                        if (r_s == check_x_s) {
+                            secp256k1_scalar_set_int(&s_times_k_s, k);
+                            secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s);
+                            secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s);
+                            secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s);
+                            should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s);
+                        }
+                    }
+                    /* nb we have a "high s" rule */
+                    should_verify &= !secp256k1_scalar_is_high(&s_s);
+
+                    /* Verify by calling verify */
+                    secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s);
+                    memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge));
+                    secp256k1_pubkey_save(&pk, &nonconst_ge);
+                    secp256k1_scalar_get_b32(msg32, &msg_s);
+                    CHECK(should_verify ==
+                          secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk));
+                }
+            }
+        }
+    }
+}
+
+void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
+    int i, j, k;
+
+    /* Loop */
+    for (i = 1; i < order; i++) {  /* message */
+        for (j = 1; j < order; j++) {  /* key */
+            for (k = 1; k < order; k++) {  /* nonce */
+                secp256k1_ecdsa_signature sig;
+                secp256k1_scalar sk, msg, r, s, expected_r;
+                unsigned char sk32[32], msg32[32];
+                secp256k1_scalar_set_int(&msg, i);
+                secp256k1_scalar_set_int(&sk, j);
+                secp256k1_scalar_get_b32(sk32, &sk);
+                secp256k1_scalar_get_b32(msg32, &msg);
+
+                secp256k1_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k);
+
+                secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig);
+                /* Note that we compute expected_r *after* signing -- this is important
+                 * because our nonce-computing function function might change k during
+                 * signing. */
+                r_from_k(&expected_r, group, k);
+                CHECK(r == expected_r);
+                CHECK((k * s) % order == (i + r * j) % order ||
+                      (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);
+            }
+        }
+    }
+
+    /* We would like to verify zero-knowledge here by counting how often every
+     * possible (s, r) tuple appears, but because the group order is larger
+     * than the field order, when coercing the x-values to scalar values, some
+     * appear more often than others, so we are actually not zero-knowledge.
+     * (This effect also appears in the real code, but the difference is on the
+     * order of 1/2^128th the field order, so the deviation is not useful to a
+     * computationally bounded attacker.)
+     */
+}
+
+int main(void) {
+    int i;
+    secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER];
+    secp256k1_ge group[EXHAUSTIVE_TEST_ORDER];
+
+    /* Build context */
+    secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+
+    /* TODO set z = 1, then do num_tests runs with random z values */
+
+    /* Generate the entire group */
+    secp256k1_gej_set_infinity(&groupj[0]);
+    secp256k1_ge_set_gej(&group[0], &groupj[0]);
+    for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) {
+        /* Set a different random z-value for each Jacobian point */
+        secp256k1_fe z;
+        random_fe(&z);
+
+        secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g);
+        secp256k1_ge_set_gej(&group[i], &groupj[i]);
+        secp256k1_gej_rescale(&groupj[i], &z);
+
+        /* Verify against ecmult_gen */
+        {
+            secp256k1_scalar scalar_i;
+            secp256k1_gej generatedj;
+            secp256k1_ge generated;
+
+            secp256k1_scalar_set_int(&scalar_i, i);
+            secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i);
+            secp256k1_ge_set_gej(&generated, &generatedj);
+
+            CHECK(group[i].infinity == 0);
+            CHECK(generated.infinity == 0);
+            CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x));
+            CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y));
+        }
+    }
+
+    /* Run the tests */
+#ifdef USE_ENDOMORPHISM
+    test_exhaustive_endomorphism(group, EXHAUSTIVE_TEST_ORDER);
+#endif
+    test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER);
+    test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER);
+    test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);
+    test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);
+
+    return 0;
+}
+