Repository: bitcoin-core/secp256k1
Pull request #533 (2018-05-06 07:44:31)

Make sure we're not using an uninitialized variable in secp256k1_wnaf_const(...)
Make sure we're not using an uninitialized variable in `secp256k1_wnaf_const(...)`:

```
In file included from src/secp256k1.c:15:0,
                 from src/tests.c:17:
src/ecmult_const_impl.h: In function ‘secp256k1_wnaf_const’:
src/ecmult_const_impl.h:117:20: warning: ‘u’ may be used uninitialized in this function [-Wmaybe-uninitialized]
     wnaf[word] = u * global_sign;
                    ^
```

**Note to reviewers:** Perhaps an `assert(…);` is a bit drastic. What would be a more graceful way to handle this? :-)

sipa: We don't use `assert` in the secp256k1 codebase. Instead I suggest you:
* Turn the `while` loop into a `do` loop.
* Add a `VERIFY_CHECK(size > 0);` (which only affects the code in unit tests).
practicalswift: @sipa Makes perfect sense. Thanks for the quick feedback!

I've now pushed an updated version. Please re-review :-)
Empact: utACK 5f10203
gmaxwell: ACK
ymmah: ; ) 確認
jonasnick: utACK
gmaxwell: On re-review, I believe we need to VERIFY_CHECK w>0 for the loop transformation to be correct. (obviously w>0 or the code is already broken... so.) @sipa opinion?
real-or-random: I think it's best to just `VERIFY_CHECK(w > 0)` too. If `w == 0`, we even divide by 0 in the `VERIFY_CHECK` here: 
https://github.com/bitcoin-core/secp256k1/blob/5f10203cfe3c40e7295aced2f36e090bb3f50e33/src/ecmult_const_impl.h#L119
real-or-random: @practicalswift: Could you update this?
practicalswift: @real-or-random Sure!

Just to clarify (better safe than sorry!):

Is the suggestion to change from:

```
VERIFY_CHECK(size > 0);
```

To:

```
VERIFY_CHECK(w > 0);
VERIFY_CHECK(size > 0);
```

And otherwise leave the PR unchanged?
real-or-random: Yes that's my suggestion. :) 

Patch:
diff --git a/Makefile.am b/Makefile.am
index 9e5b7dc..01fd0cd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -114,7 +114,7 @@ exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDE
 if !ENABLE_COVERAGE
 exhaustive_tests_CPPFLAGS += -DVERIFY
 endif
-exhaustive_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+exhaustive_tests_LDADD = $(SECP_LIBS)
 exhaustive_tests_LDFLAGS = -static
 TESTS += exhaustive_tests
 endif
@@ -151,6 +151,7 @@ endif
 
 if USE_ECMULT_STATIC_PRECOMPUTATION
 CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)
+CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function
 
 gen_context_OBJECTS = gen_context.o
 gen_context_BIN = gen_context$(BUILD_EXEEXT)
@@ -158,7 +159,7 @@ gen_%.o: src/gen_%.c
 	$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@
 
 $(gen_context_BIN): $(gen_context_OBJECTS)
-	$(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) $^ -o $@
+	$(CC_FOR_BUILD) $^ -o $@
 
 $(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h
 $(tests_OBJECTS): src/ecmult_static_context.h
diff --git a/configure.ac b/configure.ac
index 3b7a328..68c45a5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -153,6 +153,12 @@ AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto]
 
 AC_CHECK_TYPES([__int128])
 
+AC_MSG_CHECKING([for __builtin_expect])
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
+    [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ],
+    [ AC_MSG_RESULT([no])
+    ])
+
 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"
@@ -162,54 +168,27 @@ else
 fi
 
 if test x"$use_ecmult_static_precomputation" != x"no"; then
-  # Temporarily switch to an environment for the native compiler
   save_cross_compiling=$cross_compiling
   cross_compiling=no
-  SAVE_CC="$CC"
+  TEMP_CC="$CC"
   CC="$CC_FOR_BUILD"
-  SAVE_CFLAGS="$CFLAGS"
-  CFLAGS="$CFLAGS_FOR_BUILD"
-  SAVE_CPPFLAGS="$CPPFLAGS"
-  CPPFLAGS="$CPPFLAGS_FOR_BUILD"
-  SAVE_LDFLAGS="$LDFLAGS"
-  LDFLAGS="$LDFLAGS_FOR_BUILD"
-
-  warn_CFLAGS_FOR_BUILD="-Wall -Wextra -Wno-unused-function"
-  saved_CFLAGS="$CFLAGS"
-  CFLAGS="$CFLAGS $warn_CFLAGS_FOR_BUILD"
-  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]) ],
-      [ AC_MSG_RESULT([no])
-        CFLAGS="$saved_CFLAGS"
-      ])
-
-  AC_MSG_CHECKING([for working native compiler: ${CC_FOR_BUILD}])
+  AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}])
   AC_RUN_IFELSE(
-    [AC_LANG_PROGRAM([], [])],
+    [AC_LANG_PROGRAM([], [return 0])],
     [working_native_cc=yes],
     [working_native_cc=no],[dnl])
-
-  CFLAGS_FOR_BUILD="$CFLAGS"
-
-  # Restore the environment
+  CC="$TEMP_CC"
   cross_compiling=$save_cross_compiling
-  CC="$SAVE_CC"
-  CFLAGS="$SAVE_CFLAGS"
-  CPPFLAGS="$SAVE_CPPFLAGS"
-  LDFLAGS="$SAVE_LDFLAGS"
 
   if test x"$working_native_cc" = x"no"; then
-    AC_MSG_RESULT([no])
     set_precomp=no
-    m4_define([please_set_for_build], [Please set CC_FOR_BUILD, CFLAGS_FOR_BUILD, CPPFLAGS_FOR_BUILD, and/or LDFLAGS_FOR_BUILD.])
     if test x"$use_ecmult_static_precomputation" = x"yes";  then
-      AC_MSG_ERROR([native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
+      AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
     else
-      AC_MSG_WARN([Disabling statically generated ecmult table because the native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
+      AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
     fi
   else
-    AC_MSG_RESULT([yes])
+    AC_MSG_RESULT([ok])
     set_precomp=yes
   fi
 else
@@ -462,6 +441,18 @@ 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
 
+AC_MSG_NOTICE([Using static precomputation: $set_precomp])
+AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
+AC_MSG_NOTICE([Using field implementation: $set_field])
+AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
+AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
+AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
+AC_MSG_NOTICE([Building benchmarks: $use_benchmark])
+AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage])
+AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
+AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
+AC_MSG_NOTICE([Using jni: $use_jni])
+
 if test x"$enable_experimental" = x"yes"; then
   AC_MSG_NOTICE([******])
   AC_MSG_NOTICE([WARNING: experimental build])
@@ -491,7 +482,7 @@ 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_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"])
 
@@ -501,24 +492,3 @@ unset PKG_CONFIG_PATH
 PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
 
 AC_OUTPUT
-
-echo
-echo "Build Options:"
-echo "  with endomorphism   = $use_endomorphism"
-echo "  with ecmult precomp = $set_precomp"
-echo "  with jni            = $use_jni"
-echo "  with benchmarks     = $use_benchmark"
-echo "  with coverage       = $enable_coverage"
-echo "  module ecdh         = $enable_module_ecdh"
-echo "  module recovery     = $enable_module_recovery"
-echo
-echo "  asm                 = $set_asm"
-echo "  bignum              = $set_bignum"
-echo "  field               = $set_field"
-echo "  scalar              = $set_scalar"
-echo
-echo "  CC                  = $CC"
-echo "  CFLAGS              = $CFLAGS"
-echo "  CPPFLAGS            = $CPPFLAGS"
-echo "  LDFLAGS             = $LDFLAGS"
-echo
diff --git a/include/secp256k1.h b/include/secp256k1.h
index 43af09c..3c4a311 100644
--- a/include/secp256k1.h
+++ b/include/secp256k1.h
@@ -179,13 +179,6 @@ typedef int (*secp256k1_nonce_function)(
 #define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
 #define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
 
-/** A simple secp256k1 context object with no precomputed tables. These are useful for
- *  type serialization/parsing functions which require a context object to maintain
- *  API consistency, but currently do not require expensive precomputations or dynamic
- *  allocations.
- */
-SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp;
-
 /** Create a secp256k1 context object.
  *
  *  Returns: a newly created context object.
@@ -615,7 +608,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
 
 /** Updates the context randomization to protect against side-channel leakage.
- *  Returns: 1: randomization successfully updated or nothing to randomize
+ *  Returns: 1: randomization successfully updated
  *           0: error
  *  Args:    ctx:       pointer to a context object (cannot be NULL)
  *  In:      seed32:    pointer to a 32-byte random seed (NULL resets to initial state)
@@ -630,11 +623,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
  * that it does not affect function results, but shields against attacks which
  * rely on any input-dependent behaviour.
  *
- * This function has currently an effect only on contexts initialized for signing
- * because randomization is currently used only for signing. However, this is not
- * guaranteed and may change in the future. It is safe to call this function on
- * contexts not initialized for signing; then it will have no effect and return 1.
- *
  * You should call this after secp256k1_context_create or
  * secp256k1_context_clone, and may call this repeatedly afterwards.
  */
diff --git a/include/secp256k1_ecdh.h b/include/secp256k1_ecdh.h
index df5fde2..88492dc 100644
--- a/include/secp256k1_ecdh.h
+++ b/include/secp256k1_ecdh.h
@@ -7,45 +7,21 @@
 extern "C" {
 #endif
 
-/** A pointer to a function that applies hash function to a point
- *
- *  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
- */
-typedef int (*secp256k1_ecdh_hash_function)(
-  unsigned char *output,
-  const unsigned char *x,
-  const unsigned char *y,
-  void *data
-);
-
-/** An implementation of SHA256 hash function that applies to compressed public key. */
-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). */
-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)
  *  Args:    ctx:        pointer to a context object (cannot be NULL)
- *  Out:     output:     pointer to an array to be filled by the function
+ *  Out:     result:     a 32-byte array which will be populated by an ECDH
+ *                       secret computed from the point and scalar
  *  In:      pubkey:     a pointer to a secp256k1_pubkey containing an
  *                       initialized public key
  *           privkey:    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
  */
 SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
   const secp256k1_context* ctx,
-  unsigned char *output,
+  unsigned char *result,
   const secp256k1_pubkey *pubkey,
-  const unsigned char *privkey,
-  secp256k1_ecdh_hash_function hashfp,
-  void *data
+  const unsigned char *privkey
 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
 
 #ifdef __cplusplus
diff --git a/libsecp256k1.pc.in b/libsecp256k1.pc.in
index 694e98e..a0d006f 100644
--- a/libsecp256k1.pc.in
+++ b/libsecp256k1.pc.in
@@ -8,6 +8,6 @@ Description: Optimized C library for EC operations on curve secp256k1
 URL: https://github.com/bitcoin-core/secp256k1
 Version: @PACKAGE_VERSION@
 Cflags: -I${includedir}
-Libs: -L${libdir} -lsecp256k1
 Libs.private: @SECP_LIBS@
+Libs: -L${libdir} -lsecp256k1
 
diff --git a/src/bench_ecdh.c b/src/bench_ecdh.c
index c1dd5a6..5837f4e 100644
--- a/src/bench_ecdh.c
+++ b/src/bench_ecdh.c
@@ -42,7 +42,7 @@ static void bench_ecdh(void* arg) {
     bench_ecdh_data *data = (bench_ecdh_data*)arg;
 
     for (i = 0; i < 20000; i++) {
-        CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1);
+        CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1);
     }
 }
 
diff --git a/src/bench_ecmult.c b/src/bench_ecmult.c
index 6d0ed1f..52d0476 100644
--- a/src/bench_ecmult.c
+++ b/src/bench_ecmult.c
@@ -139,11 +139,6 @@ int main(int argc, char **argv) {
     secp256k1_gej* pubkeys_gej;
     size_t scratch_size;
 
-    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);
-    data.ecmult_multi = secp256k1_ecmult_multi_var;
-
     if (argc > 1) {
         if(have_flag(argc, argv, "pippenger_wnaf")) {
             printf("Using pippenger_wnaf:\n");
@@ -151,19 +146,15 @@ int main(int argc, char **argv) {
         } else if(have_flag(argc, argv, "strauss_wnaf")) {
             printf("Using strauss_wnaf:\n");
             data.ecmult_multi = secp256k1_ecmult_strauss_batch_single;
-        } else if(have_flag(argc, argv, "simple")) {
-            printf("Using simple algorithm:\n");
-            data.ecmult_multi = secp256k1_ecmult_multi_var;
-            secp256k1_scratch_space_destroy(data.scratch);
-            data.scratch = NULL;
-        } else {
-            fprintf(stderr, "%s: unrecognized argument '%s'.\n", argv[0], argv[1]);
-            fprintf(stderr, "Use 'pippenger_wnaf', 'strauss_wnaf', 'simple' or no argument to benchmark a combined algorithm.\n");
-            return 1;
         }
+    } else {
+        data.ecmult_multi = secp256k1_ecmult_multi_var;
     }
 
     /* Allocate stuff */
+    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);
     data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS);
     data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS);
     data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS);
@@ -181,7 +172,7 @@ int main(int argc, char **argv) {
             secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]);
         }
     }
-    secp256k1_ge_set_all_gej_var(data.pubkeys, pubkeys_gej, POINTS);
+    secp256k1_ge_set_all_gej_var(data.pubkeys, pubkeys_gej, POINTS, &data.ctx->error_callback);
     free(pubkeys_gej);
 
     for (i = 1; i <= 8; ++i) {
@@ -194,9 +185,7 @@ int main(int argc, char **argv) {
         }
     }
     secp256k1_context_destroy(data.ctx);
-    if (data.scratch != NULL) {
-        secp256k1_scratch_space_destroy(data.scratch);
-    }
+    secp256k1_scratch_space_destroy(data.scratch);
     free(data.scalars);
     free(data.pubkeys);
     free(data.seckeys);
diff --git a/src/bench_internal.c b/src/bench_internal.c
index 9071724..9c0a07f 100644
--- a/src/bench_internal.c
+++ b/src/bench_internal.c
@@ -184,11 +184,9 @@ void bench_field_inverse_var(void* arg) {
 void bench_field_sqrt(void* arg) {
     int i;
     bench_inv *data = (bench_inv*)arg;
-    secp256k1_fe t;
 
     for (i = 0; i < 20000; i++) {
-        t = data->fe_x;
-        secp256k1_fe_sqrt(&data->fe_x, &t);
+        secp256k1_fe_sqrt(&data->fe_x, &data->fe_x);
         secp256k1_fe_add(&data->fe_x, &data->fe_y);
     }
 }
diff --git a/src/eckey_impl.h b/src/eckey_impl.h
index 7c5b789..1ab9a68 100644
--- a/src/eckey_impl.h
+++ b/src/eckey_impl.h
@@ -18,7 +18,7 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char
     if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) {
         secp256k1_fe x;
         return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
-    } else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
+    } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
         secp256k1_fe x, y;
         if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
             return 0;
diff --git a/src/ecmult.h b/src/ecmult.h
index 3d75a96..ea1cd8a 100644
--- a/src/ecmult.h
+++ b/src/ecmult.h
@@ -37,8 +37,7 @@ typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge
  * Chooses the right algorithm for a given number of points and scratch space
  * size. Resets and overwrites the given scratch space. If the points do not
  * fit in the scratch space the algorithm is repeatedly run with batches of
- * points. If no scratch space is given then a simple algorithm is used that
- * simply multiplies the points with the corresponding scalars and adds them up.
+ * points.
  * Returns: 1 on success (including when inp_g_sc is NULL and n is 0)
  *          0 if there is not enough scratch space for a single point or
  *          callback returns 0
diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h
index 8411752..61a4770 100644
--- a/src/ecmult_const_impl.h
+++ b/src/ecmult_const_impl.h
@@ -61,6 +61,10 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size)
     int bit;
     secp256k1_scalar neg_s;
     int not_neg_one;
+
+    VERIFY_CHECK(w > 0);
+    VERIFY_CHECK(size > 0);
+
     /* Note that we cannot handle even numbers by negating them to be odd, as is
      * done in other implementations, since if our scalars were specified to have
      * width < 256 for performance reasons, their negations would have width 256
@@ -93,7 +97,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size)
 
     /* 4 */
     u_last = secp256k1_scalar_shr_int(&s, w);
-    while (word * w < size) {
+    do {
         int sign;
         int even;
 
@@ -109,7 +113,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size)
         wnaf[word++] = u_last * global_sign;
 
         u_last = u;
-    }
+    } while (word * w < size);
     wnaf[word] = u * global_sign;
 
     VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h
index d64505d..714f02e 100644
--- a/src/ecmult_gen_impl.h
+++ b/src/ecmult_gen_impl.h
@@ -77,7 +77,7 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx
                 secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
             }
         }
-        secp256k1_ge_set_all_gej_var(prec, precj, 1024);
+        secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb);
     }
     for (j = 0; j < 64; j++) {
         for (i = 0; i < 16; i++) {
diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h
index cbafd07..d5fb6c5 100644
--- a/src/ecmult_impl.h
+++ b/src/ecmult_impl.h
@@ -137,135 +137,24 @@ static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *p
     secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr);
 }
 
-static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp256k1_ge_storage *pre, const secp256k1_gej *a) {
-    secp256k1_gej d;
-    secp256k1_ge d_ge, p_ge;
-    secp256k1_gej pj;
-    secp256k1_fe zi;
-    secp256k1_fe zr;
-    secp256k1_fe dx_over_dz_squared;
+static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage *pre, const secp256k1_gej *a, const secp256k1_callback *cb) {
+    secp256k1_gej *prej = (secp256k1_gej*)checked_malloc(cb, sizeof(secp256k1_gej) * n);
+    secp256k1_ge *prea = (secp256k1_ge*)checked_malloc(cb, sizeof(secp256k1_ge) * n);
+    secp256k1_fe *zr = (secp256k1_fe*)checked_malloc(cb, sizeof(secp256k1_fe) * n);
     int i;
 
-    VERIFY_CHECK(!a->infinity);
-
-    secp256k1_gej_double_var(&d, a, NULL);
-
-    /* First, we perform all the additions in an isomorphic curve obtained by multiplying
-     * all `z` coordinates by 1/`d.z`. In these coordinates `d` is affine so we can use
-     * `secp256k1_gej_add_ge_var` to perform the additions. For each addition, we store
-     * the resulting y-coordinate and the z-ratio, since we only have enough memory to
-     * store two field elements. These are sufficient to efficiently undo the isomorphism
-     * and recompute all the `x`s.
-     */
-    d_ge.x = d.x;
-    d_ge.y = d.y;
-    d_ge.infinity = 0;
-
-    secp256k1_ge_set_gej_zinv(&p_ge, a, &d.z);
-    pj.x = p_ge.x;
-    pj.y = p_ge.y;
-    pj.z = a->z;
-    pj.infinity = 0;
-
-    for (i = 0; i < (n - 1); i++) {
-        secp256k1_fe_normalize_var(&pj.y);
-        secp256k1_fe_to_storage(&pre[i].y, &pj.y);
-        secp256k1_gej_add_ge_var(&pj, &pj, &d_ge, &zr);
-        secp256k1_fe_normalize_var(&zr);
-        secp256k1_fe_to_storage(&pre[i].x, &zr);
+    /* Compute the odd multiples in Jacobian form. */
+    secp256k1_ecmult_odd_multiples_table(n, prej, zr, a);
+    /* Convert them in batch to affine coordinates. */
+    secp256k1_ge_set_table_gej_var(prea, prej, zr, n);
+    /* Convert them to compact storage form. */
+    for (i = 0; i < n; i++) {
+        secp256k1_ge_to_storage(&pre[i], &prea[i]);
     }
 
-    /* Invert d.z in the same batch, preserving pj.z so we can extract 1/d.z */
-    secp256k1_fe_mul(&zi, &pj.z, &d.z);
-    secp256k1_fe_inv_var(&zi, &zi);
-
-    /* Directly set `pre[n - 1]` to `pj`, saving the inverted z-coordinate so
-     * that we can combine it with the saved z-ratios to compute the other zs
-     * without any more inversions. */
-    secp256k1_ge_set_gej_zinv(&p_ge, &pj, &zi);
-    secp256k1_ge_to_storage(&pre[n - 1], &p_ge);
-
-    /* Compute the actual x-coordinate of D, which will be needed below. */
-    secp256k1_fe_mul(&d.z, &zi, &pj.z);  /* d.z = 1/d.z */
-    secp256k1_fe_sqr(&dx_over_dz_squared, &d.z);
-    secp256k1_fe_mul(&dx_over_dz_squared, &dx_over_dz_squared, &d.x);
-
-    /* Going into the second loop, we have set `pre[n-1]` to its final affine
-     * form, but still need to set `pre[i]` for `i` in 0 through `n-2`. We
-     * have `zi = (p.z * d.z)^-1`, where
-     *
-     *     `p.z` is the z-coordinate of the point on the isomorphic curve
-     *           which was ultimately assigned to `pre[n-1]`.
-     *     `d.z` is the multiplier that must be applied to all z-coordinates
-     *           to move from our isomorphic curve back to secp256k1; so the
-     *           product `p.z * d.z` is the z-coordinate of the secp256k1
-     *           point assigned to `pre[n-1]`.
-     *
-     * All subsequent inverse-z-coordinates can be obtained by multiplying this
-     * factor by successive z-ratios, which is much more efficient than directly
-     * computing each one.
-     *
-     * Importantly, these inverse-zs will be coordinates of points on secp256k1,
-     * while our other stored values come from computations on the isomorphic
-     * curve. So in the below loop, we will take care not to actually use `zi`
-     * or any derived values until we're back on secp256k1.
-     */
-    i = n - 1;
-    while (i > 0) {
-        secp256k1_fe zi2, zi3;
-        const secp256k1_fe *rzr;
-        i--;
-
-        secp256k1_ge_from_storage(&p_ge, &pre[i]);
-
-        /* For each remaining point, we extract the z-ratio from the stored
-         * x-coordinate, compute its z^-1 from that, and compute the full
-         * point from that. */
-        rzr = &p_ge.x;
-        secp256k1_fe_mul(&zi, &zi, rzr);
-        secp256k1_fe_sqr(&zi2, &zi);
-        secp256k1_fe_mul(&zi3, &zi2, &zi);
-        /* To compute the actual x-coordinate, we use the stored z ratio and
-         * y-coordinate, which we obtained from `secp256k1_gej_add_ge_var`
-         * in the loop above, as well as the inverse of the square of its
-         * z-coordinate. We store the latter in the `zi2` variable, which is
-         * computed iteratively starting from the overall Z inverse then
-         * multiplying by each z-ratio in turn.
-         *
-         * Denoting the z-ratio as `rzr`, we observe that it is equal to `h`
-         * from the inside of the above `gej_add_ge_var` call. This satisfies
-         *
-         *    rzr = d_x * z^2 - x * d_z^2
-         *
-         * where (`d_x`, `d_z`) are Jacobian coordinates of `D` and `(x, z)`
-         * are Jacobian coordinates of our desired point -- except both are on
-         * the isomorphic curve that we were using when we called `gej_add_ge_var`.
-         * To get back to secp256k1, we must multiply both `z`s by `d_z`, or
-         * equivalently divide both `x`s by `d_z^2`. Our equation then becomes
-         *
-         *    rzr = d_x * z^2 / d_z^2 - x
-         *
-         * (The left-hand-side, being a ratio of z-coordinates, is unaffected
-         * by the isomorphism.)
-         *
-         * Rearranging to solve for `x`, we have
-         *
-         *     x = d_x * z^2 / d_z^2 - rzr
-         *
-         * But what we actually want is the affine coordinate `X = x/z^2`,
-         * which will satisfy
-         *
-         *     X = d_x / d_z^2 - rzr / z^2
-         *       = dx_over_dz_squared - rzr * zi2
-         */
-        secp256k1_fe_mul(&p_ge.x, rzr, &zi2);
-        secp256k1_fe_negate(&p_ge.x, &p_ge.x, 1);
-        secp256k1_fe_add(&p_ge.x, &dx_over_dz_squared);
-        /* y is stored_y/z^3, as we expect */
-        secp256k1_fe_mul(&p_ge.y, &p_ge.y, &zi3);
-        /* Store */
-        secp256k1_ge_to_storage(&pre[i], &p_ge);
-    }
+    free(prea);
+    free(prej);
+    free(zr);
 }
 
 /** The following two macro retrieves a particular odd multiple from a table
@@ -277,8 +166,7 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
     if ((n) > 0) { \
         *(r) = (pre)[((n)-1)/2]; \
     } else { \
-        *(r) = (pre)[(-(n)-1)/2]; \
-        secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
+        secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \
     } \
 } while(0)
 
@@ -290,7 +178,7 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
         secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \
     } else { \
         secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \
-        secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
+        secp256k1_ge_neg((r), (r)); \
     } \
 } while(0)
 
@@ -314,7 +202,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
     ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));
 
     /* precompute the tables with odd multiples */
-    secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj);
+    secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb);
 
 #ifdef USE_ENDOMORPHISM
     {
@@ -328,7 +216,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
         for (i = 0; i < 128; i++) {
             secp256k1_gej_double_var(&g_128j, &g_128j, NULL);
         }
-        secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j);
+        secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb);
     }
 #endif
 }
@@ -1084,58 +972,12 @@ static size_t secp256k1_pippenger_max_points(secp256k1_scratch *scratch) {
     return res;
 }
 
-/* Computes ecmult_multi by simply multiplying and adding each point. Does not
- * require a scratch space */
-static int secp256k1_ecmult_multi_simple_var(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) {
-    size_t point_idx;
-    secp256k1_scalar szero;
-    secp256k1_gej tmpj;
-
-    secp256k1_scalar_set_int(&szero, 0);
-    secp256k1_gej_set_infinity(r);
-    secp256k1_gej_set_infinity(&tmpj);
-    /* r = inp_g_sc*G */
-    secp256k1_ecmult(ctx, r, &tmpj, &szero, inp_g_sc);
-    for (point_idx = 0; point_idx < n_points; point_idx++) {
-        secp256k1_ge point;
-        secp256k1_gej pointj;
-        secp256k1_scalar scalar;
-        if (!cb(&scalar, &point, point_idx, cbdata)) {
-            return 0;
-        }
-        /* r += scalar*point */
-        secp256k1_gej_set_ge(&pointj, &point);
-        secp256k1_ecmult(ctx, &tmpj, &pointj, &scalar, NULL);
-        secp256k1_gej_add_var(r, r, &tmpj, NULL);
-    }
-    return 1;
-}
-
-/* Compute the number of batches and the batch size given the maximum batch size and the
- * total number of points */
-static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_n_batch_points, size_t n) {
-    if (max_n_batch_points == 0) {
-        return 0;
-    }
-    if (max_n_batch_points > ECMULT_MAX_POINTS_PER_BATCH) {
-        max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH;
-    }
-    if (n == 0) {
-        *n_batches = 0;
-        *n_batch_points = 0;
-        return 1;
-    }
-    /* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */
-    *n_batches = 1 + (n - 1) / max_n_batch_points;
-    *n_batch_points = 1 + (n - 1) / *n_batches;
-    return 1;
-}
-
 typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t);
 static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
     size_t i;
 
     int (*f)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t);
+    size_t max_points;
     size_t n_batches;
     size_t n_batch_points;
 
@@ -1148,21 +990,25 @@ static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp2
         secp256k1_ecmult(ctx, r, r, &szero, inp_g_sc);
         return 1;
     }
-    if (scratch == NULL) {
-        return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
-    }
 
-    /* Compute the batch sizes for pippenger given a scratch space. If it's greater than a threshold
-     * use pippenger. Otherwise use strauss */
-    if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(scratch), n)) {
+    max_points = secp256k1_pippenger_max_points(scratch);
+    if (max_points == 0) {
         return 0;
+    } else if (max_points > ECMULT_MAX_POINTS_PER_BATCH) {
+        max_points = ECMULT_MAX_POINTS_PER_BATCH;
     }
+    n_batches = (n+max_points-1)/max_points;
+    n_batch_points = (n+n_batches-1)/n_batches;
+
     if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) {
         f = secp256k1_ecmult_pippenger_batch;
     } else {
-        if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(scratch), n)) {
+        max_points = secp256k1_strauss_max_points(scratch);
+        if (max_points == 0) {
             return 0;
         }
+        n_batches = (n+max_points-1)/max_points;
+        n_batch_points = (n+n_batches-1)/n_batches;
         f = secp256k1_ecmult_strauss_batch;
     }
     for(i = 0; i < n_batches; i++) {
diff --git a/src/field_10x26.h b/src/field_10x26.h
index 5ff03c8..727c526 100644
--- a/src/field_10x26.h
+++ b/src/field_10x26.h
@@ -10,9 +10,7 @@
 #include <stdint.h>
 
 typedef struct {
-    /* X = sum(i=0..9, n[i]*2^(i*26)) mod p
-     * where p = 2^256 - 0x1000003D1
-     */
+    /* X = sum(i=0..9, elem[i]*2^26) mod n */
     uint32_t n[10];
 #ifdef VERIFY
     int magnitude;
diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h
index 4ae4fdc..94f8132 100644
--- a/src/field_10x26_impl.h
+++ b/src/field_10x26_impl.h
@@ -8,6 +8,7 @@
 #define SECP256K1_FIELD_REPR_IMPL_H
 
 #include "util.h"
+#include "num.h"
 #include "field.h"
 
 #ifdef VERIFY
@@ -485,8 +486,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
     VERIFY_BITS(b[9], 26);
 
     /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n.
-     *  for 0 <= x <= 9, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
-     *  for 9 <= x <= 18, px is a shorthand for sum(a[i]*b[x-i], i=(x-9)..9)
+     *  px is a shorthand for sum(a[i]*b[x-i], i=0..x).
      *  Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0].
      */
 
@@ -1069,7 +1069,6 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2
     secp256k1_fe_verify(a);
     secp256k1_fe_verify(b);
     VERIFY_CHECK(r != b);
-    VERIFY_CHECK(a != b);
 #endif
     secp256k1_fe_mul_inner(r->n, a->n, b->n);
 #ifdef VERIFY
diff --git a/src/field_5x52.h b/src/field_5x52.h
index fc5bfe3..bccd8fe 100644
--- a/src/field_5x52.h
+++ b/src/field_5x52.h
@@ -10,9 +10,7 @@
 #include <stdint.h>
 
 typedef struct {
-    /* X = sum(i=0..4, n[i]*2^(i*52)) mod p
-     * where p = 2^256 - 0x1000003D1
-     */
+    /* X = sum(i=0..4, elem[i]*2^52) mod n */
     uint64_t n[5];
 #ifdef VERIFY
     int magnitude;
diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h
index f426332..957c61b 100644
--- a/src/field_5x52_impl.h
+++ b/src/field_5x52_impl.h
@@ -12,6 +12,7 @@
 #endif
 
 #include "util.h"
+#include "num.h"
 #include "field.h"
 
 #if defined(USE_ASM_X86_64)
@@ -421,7 +422,6 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2
     secp256k1_fe_verify(a);
     secp256k1_fe_verify(b);
     VERIFY_CHECK(r != b);
-    VERIFY_CHECK(a != b);
 #endif
     secp256k1_fe_mul_inner(r->n, a->n, b->n);
 #ifdef VERIFY
diff --git a/src/field_5x52_int128_impl.h b/src/field_5x52_int128_impl.h
index bcbfb92..95a0d17 100644
--- a/src/field_5x52_int128_impl.h
+++ b/src/field_5x52_int128_impl.h
@@ -32,11 +32,9 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
     VERIFY_BITS(b[3], 56);
     VERIFY_BITS(b[4], 52);
     VERIFY_CHECK(r != b);
-    VERIFY_CHECK(a != b);
 
     /*  [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
-     *  for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
-     *  for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4)
+     *  px is a shorthand for sum(a[i]*b[x-i], i=0..x).
      *  Note that [x 0 0 0 0 0] = [x*R].
      */
 
diff --git a/src/field_impl.h b/src/field_impl.h
index 6070cac..2042864 100644
--- a/src/field_impl.h
+++ b/src/field_impl.h
@@ -12,7 +12,6 @@
 #endif
 
 #include "util.h"
-#include "num.h"
 
 #if defined(USE_FIELD_10X26)
 #include "field_10x26_impl.h"
@@ -49,8 +48,6 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
     secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
     int j;
 
-    VERIFY_CHECK(r != a);
-
     /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
      *  { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
      *  1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
diff --git a/src/group.h b/src/group.h
index 8e122ab..3947ea2 100644
--- a/src/group.h
+++ b/src/group.h
@@ -65,7 +65,12 @@ static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a);
 static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a);
 
 /** Set a batch of group elements equal to the inputs given in jacobian coordinates */
-static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len);
+static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb);
+
+/** Set a batch of group elements equal to the inputs given in jacobian
+ *  coordinates (with known z-ratios). zr must contain the known z-ratios such
+ *  that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */
+static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len);
 
 /** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to
  *  the same global z "denominator". zr must contain the known z-ratios such
diff --git a/src/group_impl.h b/src/group_impl.h
index 9b93c39..b1ace87 100644
--- a/src/group_impl.h
+++ b/src/group_impl.h
@@ -38,22 +38,22 @@
  */
 #if defined(EXHAUSTIVE_TEST_ORDER)
 #  if EXHAUSTIVE_TEST_ORDER == 199
-static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
+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
 );
 
-static const int CURVE_B = 4;
+const int CURVE_B = 4;
 #  elif EXHAUSTIVE_TEST_ORDER == 13
-static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
+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
 );
-static const int CURVE_B = 2;
+const int CURVE_B = 2;
 #  else
 #    error No known generator for the specified exhaustive test group order.
 #  endif
@@ -68,7 +68,7 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
     0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
 );
 
-static const int CURVE_B = 7;
+const int CURVE_B = 7;
 #endif
 
 static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
@@ -126,43 +126,46 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
     r->y = a->y;
 }
 
-static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
-    secp256k1_fe u;
+static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) {
+    secp256k1_fe *az;
+    secp256k1_fe *azi;
     size_t i;
-    size_t last_i = SIZE_MAX;
-
+    size_t count = 0;
+    az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len);
     for (i = 0; i < len; i++) {
         if (!a[i].infinity) {
-            /* Use destination's x coordinates as scratch space */
-            if (last_i == SIZE_MAX) {
-                r[i].x = a[i].z;
-            } else {
-                secp256k1_fe_mul(&r[i].x, &r[last_i].x, &a[i].z);
-            }
-            last_i = i;
+            az[count++] = a[i].z;
         }
     }
-    if (last_i == SIZE_MAX) {
-        return;
-    }
-    secp256k1_fe_inv_var(&u, &r[last_i].x);
 
-    i = last_i;
-    while (i > 0) {
-        i--;
-        if (!a[i].infinity) {
-            secp256k1_fe_mul(&r[last_i].x, &r[i].x, &u);
-            secp256k1_fe_mul(&u, &u, &a[last_i].z);
-            last_i = i;
-        }
-    }
-    VERIFY_CHECK(!a[last_i].infinity);
-    r[last_i].x = u;
+    azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count);
+    secp256k1_fe_inv_all_var(azi, az, count);
+    free(az);
 
+    count = 0;
     for (i = 0; i < len; i++) {
         r[i].infinity = a[i].infinity;
         if (!a[i].infinity) {
-            secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
+            secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]);
+        }
+    }
+    free(azi);
+}
+
+static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) {
+    size_t i = len - 1;
+    secp256k1_fe zi;
+
+    if (len > 0) {
+        /* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */
+        secp256k1_fe_inv(&zi, &a[i].z);
+        secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
+
+        /* Work out way backwards, using the z-ratios to scale the x/y values. */
+        while (i > 0) {
+            secp256k1_fe_mul(&zi, &zi, &zr[i]);
+            i--;
+            secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
         }
     }
 }
@@ -175,8 +178,6 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp
         /* The z of the final point gives us the "global Z" for the table. */
         r[i].x = a[i].x;
         r[i].y = a[i].y;
-        /* Ensure all y values are in weak normal form for fast negation of points */
-        secp256k1_fe_normalize_weak(&r[i].y);
         *globalz = a[i].z;
         r[i].infinity = 0;
         zs = zr[i];
diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c
index b50970b..bcef7b3 100644
--- a/src/java/org_bitcoin_NativeSecp256k1.c
+++ b/src/java/org_bitcoin_NativeSecp256k1.c
@@ -83,7 +83,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
 
   secp256k1_ecdsa_signature sig[72];
 
-  int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL);
+  int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL );
 
   unsigned char outputSer[72];
   size_t outputLen = 72;
@@ -353,9 +353,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
       ctx,
       nonce_res,
       &pubkey,
-      secdata,
-      NULL,
-      NULL
+      secdata
     );
   }
 
diff --git a/src/modules/ecdh/main_impl.h b/src/modules/ecdh/main_impl.h
index 44cb68e..df3ec5c 100644
--- a/src/modules/ecdh/main_impl.h
+++ b/src/modules/ecdh/main_impl.h
@@ -10,35 +10,16 @@
 #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;
-    secp256k1_sha256 sha;
-    (void)data;
-
-    secp256k1_sha256_initialize(&sha);
-    secp256k1_sha256_write(&sha, &version, 1);
-    secp256k1_sha256_write(&sha, x, 32);
-    secp256k1_sha256_finalize(&sha, output);
-
-    return 1;
-}
-
-const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256;
-const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256;
-
-int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) {
+int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) {
     int ret = 0;
     int overflow = 0;
     secp256k1_gej res;
     secp256k1_ge pt;
     secp256k1_scalar s;
     VERIFY_CHECK(ctx != NULL);
-    ARG_CHECK(output != NULL);
+    ARG_CHECK(result != 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);
@@ -46,18 +27,24 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
         ret = 0;
     } else {
         unsigned char x[32];
-        unsigned char y[32];
+        unsigned char y[1];
+        secp256k1_sha256 sha;
 
         secp256k1_ecmult_const(&res, &pt, &s, 256);
         secp256k1_ge_set_gej(&pt, &res);
-
-        /* Compute a hash of the point */
+        /* Compute a hash of the point in compressed form
+         * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not
+         * expect its output to be secret and has a timing sidechannel. */
         secp256k1_fe_normalize(&pt.x);
         secp256k1_fe_normalize(&pt.y);
         secp256k1_fe_get_b32(x, &pt.x);
-        secp256k1_fe_get_b32(y, &pt.y);
+        y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y);
 
-        ret = hashfp(output, x, y, data);
+        secp256k1_sha256_initialize(&sha);
+        secp256k1_sha256_write(&sha, y, sizeof(y));
+        secp256k1_sha256_write(&sha, x, sizeof(x));
+        secp256k1_sha256_finalize(&sha, result);
+        ret = 1;
     }
 
     secp256k1_scalar_clear(&s);
diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h
index d378335..db1ebf9 100644
--- a/src/scalar_4x64_impl.h
+++ b/src/scalar_4x64_impl.h
@@ -376,7 +376,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
     /* extract m6 */
     "movq %%r8, %q6\n"
     : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6)
-    : "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
+    : "S"(l), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
     : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc");
 
     /* Reduce 385 bits into 258. */
@@ -455,7 +455,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
     /* extract p4 */
     "movq %%r9, %q4\n"
     : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4)
-    : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
+    : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
     : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc");
 
     /* Reduce 258 bits into 256. */
@@ -501,7 +501,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
     /* Extract c */
     "movq %%r9, %q0\n"
     : "=g"(c)
-    : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
+    : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
     : "rax", "rdx", "r8", "r9", "r10", "cc", "memory");
 #else
     uint128_t c;
diff --git a/src/secp256k1.c b/src/secp256k1.c
index 15981f4..cd0972d 100644
--- a/src/secp256k1.c
+++ b/src/secp256k1.c
@@ -56,14 +56,6 @@ struct secp256k1_context_struct {
     secp256k1_callback error_callback;
 };
 
-static const secp256k1_context secp256k1_context_no_precomp_ = {
-    { 0 },
-    { 0 },
-    { default_illegal_callback_fn, 0 },
-    { default_error_callback_fn, 0 }
-};
-const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_;
-
 secp256k1_context* secp256k1_context_create(unsigned int flags) {
     secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context));
     ret->illegal_callback = default_illegal_callback;
@@ -99,7 +91,6 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
 }
 
 void secp256k1_context_destroy(secp256k1_context* ctx) {
-    CHECK(ctx != secp256k1_context_no_precomp);
     if (ctx != NULL) {
         secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
         secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
@@ -109,7 +100,6 @@ void secp256k1_context_destroy(secp256k1_context* ctx) {
 }
 
 void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
-    CHECK(ctx != secp256k1_context_no_precomp);
     if (fun == NULL) {
         fun = default_illegal_callback_fn;
     }
@@ -118,7 +108,6 @@ void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(
 }
 
 void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
-    CHECK(ctx != secp256k1_context_no_precomp);
     if (fun == NULL) {
         fun = default_error_callback_fn;
     }
@@ -570,9 +559,8 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey
 
 int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {
     VERIFY_CHECK(ctx != NULL);
-    if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) {
-        secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
-    }
+    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+    secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
     return 1;
 }
 
diff --git a/src/util.h b/src/util.h
index e1f5b76..e014750 100644
--- a/src/util.h
+++ b/src/util.h
@@ -36,7 +36,7 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback *
 } while(0)
 #endif
 
-#if SECP256K1_GNUC_PREREQ(3, 0)
+#ifdef HAVE_BUILTIN_EXPECT
 #define EXPECT(x,c) __builtin_expect((x),(c))
 #else
 #define EXPECT(x,c) (x)


Test patch:
diff --git a/src/modules/ecdh/tests_impl.h b/src/modules/ecdh/tests_impl.h
index fe26e8f..0c53f8e 100644
--- a/src/modules/ecdh/tests_impl.h
+++ b/src/modules/ecdh/tests_impl.h
@@ -7,23 +7,6 @@
 #ifndef SECP256K1_MODULE_ECDH_TESTS_H
 #define SECP256K1_MODULE_ECDH_TESTS_H
 
-int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
-    (void)output;
-    (void)x;
-    (void)y;
-    (void)data;
-    return 0;
-}
-
-int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
-    (void)data;
-    /* Save x and y as uncompressed public key */
-    output[0] = 0x04;
-    memcpy(output + 1, x, 32);
-    memcpy(output + 33, y, 32);
-    return 1;
-}
-
 void test_ecdh_api(void) {
     /* Setup context that just counts errors */
     secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
@@ -38,15 +21,15 @@ void test_ecdh_api(void) {
     CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
 
     /* Check all NULLs are detected */
-    CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
+    CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
     CHECK(ecount == 0);
-    CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0);
+    CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0);
     CHECK(ecount == 1);
-    CHECK(secp256k1_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0);
+    CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0);
     CHECK(ecount == 2);
-    CHECK(secp256k1_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0);
+    CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0);
     CHECK(ecount == 3);
-    CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
+    CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
     CHECK(ecount == 3);
 
     /* Cleanup */
@@ -63,34 +46,27 @@ void test_ecdh_generator_basepoint(void) {
     for (i = 0; i < 100; ++i) {
         secp256k1_sha256 sha;
         unsigned char s_b32[32];
-        unsigned char output_ecdh[65];
+        unsigned char output_ecdh[32];
         unsigned char output_ser[32];
-        unsigned char point_ser[65];
+        unsigned char point_ser[33];
         size_t point_ser_len = sizeof(point_ser);
         secp256k1_scalar s;
 
         random_scalar_order(&s);
         secp256k1_scalar_get_b32(s_b32, &s);
 
+        /* compute using ECDH function */
         CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1);
-        CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1);
-
-        /* compute using ECDH function with custom hash function */
-        CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1);
-        /* compute "explicitly" */
-        CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1);
-        /* compare */
-        CHECK(memcmp(output_ecdh, point_ser, 65) == 0);
-
-        /* compute using ECDH function with default hash function */
-        CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1);
+        CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1);
         /* compute "explicitly" */
+        CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1);
         CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
+        CHECK(point_ser_len == sizeof(point_ser));
         secp256k1_sha256_initialize(&sha);
         secp256k1_sha256_write(&sha, point_ser, point_ser_len);
         secp256k1_sha256_finalize(&sha, output_ser);
         /* compare */
-        CHECK(memcmp(output_ecdh, output_ser, 32) == 0);
+        CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0);
     }
 }
 
@@ -113,14 +89,11 @@ void test_bad_scalar(void) {
     CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1);
 
     /* Try to multiply it by bad values */
-    CHECK(secp256k1_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0);
-    CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0);
+    CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0);
+    CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0);
     /* ...and a good one */
     s_overflow[31] -= 1;
-    CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 1);
-
-    /* Hash function failure results in ecdh failure */
-    CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
+    CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1);
 }
 
 void run_ecdh_tests(void) {
diff --git a/src/tests.c b/src/tests.c
index f1c4db9..e85c460 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -218,12 +218,8 @@ void run_context_tests(void) {
     CHECK(ecount == 3);
     CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
     CHECK(ecount == 3);
-    CHECK(secp256k1_context_randomize(vrfy, ctmp) == 1);
-    CHECK(ecount == 3);
-    CHECK(secp256k1_context_randomize(vrfy, NULL) == 1);
-    CHECK(ecount == 3);
-    CHECK(secp256k1_context_randomize(sign, ctmp) == 1);
-    CHECK(ecount2 == 14);
+    CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
+    CHECK(ecount == 4);
     CHECK(secp256k1_context_randomize(sign, NULL) == 1);
     CHECK(ecount2 == 14);
     secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);
@@ -2099,6 +2095,7 @@ void test_ge(void) {
     /* Test batch gej -> ge conversion with and without known z ratios. */
     {
         secp256k1_fe *zr = (secp256k1_fe *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_fe));
+        secp256k1_ge *ge_set_table = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
         secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
         for (i = 0; i < 4 * runs + 1; i++) {
             /* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */
@@ -2106,33 +2103,20 @@ void test_ge(void) {
                 secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z);
             }
         }
-        secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1);
+        secp256k1_ge_set_table_gej_var(ge_set_table, gej, zr, 4 * runs + 1);
+        secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1, &ctx->error_callback);
         for (i = 0; i < 4 * runs + 1; i++) {
             secp256k1_fe s;
             random_fe_non_zero(&s);
             secp256k1_gej_rescale(&gej[i], &s);
+            ge_equals_gej(&ge_set_table[i], &gej[i]);
             ge_equals_gej(&ge_set_all[i], &gej[i]);
         }
+        free(ge_set_table);
         free(ge_set_all);
         free(zr);
     }
 
-    /* Test batch gej -> ge conversion with many infinities. */
-    for (i = 0; i < 4 * runs + 1; i++) {
-        random_group_element_test(&ge[i]);
-        /* randomly set half the points to infinitiy */
-        if(secp256k1_fe_is_odd(&ge[i].x)) {
-            secp256k1_ge_set_infinity(&ge[i]);
-        }
-        secp256k1_gej_set_ge(&gej[i], &ge[i]);
-    }
-    /* batch invert */
-    secp256k1_ge_set_all_gej_var(ge, gej, 4 * runs + 1);
-    /* check result */
-    for (i = 0; i < 4 * runs + 1; i++) {
-        ge_equals_gej(&ge[i], &gej[i]);
-    }
-
     free(ge);
     free(gej);
     free(zinv);
@@ -2741,11 +2725,6 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
     }
 
     /* Sanity check that zero scalars don't cause problems */
-    for (ncount = 0; ncount < 20; ncount++) {
-        random_scalar_order(&sc[ncount]);
-        random_group_element_test(&pt[ncount]);
-    }
-
     secp256k1_scalar_clear(&sc[0]);
     CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
     secp256k1_scalar_clear(&sc[1]);
@@ -2854,50 +2833,6 @@ void test_ecmult_multi_pippenger_max_points(void) {
     CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW);
 }
 
-void test_ecmult_multi_batch_size_helper(void) {
-    size_t n_batches, n_batch_points, max_n_batch_points, n;
-
-    max_n_batch_points = 0;
-    n = 1;
-    CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 0);
-
-    max_n_batch_points = 1;
-    n = 0;
-    CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
-    CHECK(n_batches == 0);
-    CHECK(n_batch_points == 0);
-
-    max_n_batch_points = 2;
-    n = 5;
-    CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
-    CHECK(n_batches == 3);
-    CHECK(n_batch_points == 2);
-
-    max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH;
-    n = ECMULT_MAX_POINTS_PER_BATCH;
-    CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
-    CHECK(n_batches == 1);
-    CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH);
-
-    max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH + 1;
-    n = ECMULT_MAX_POINTS_PER_BATCH + 1;
-    CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
-    CHECK(n_batches == 2);
-    CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH/2 + 1);
-
-    max_n_batch_points = 1;
-    n = SIZE_MAX;
-    CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
-    CHECK(n_batches == SIZE_MAX);
-    CHECK(n_batch_points == 1);
-
-    max_n_batch_points = 2;
-    n = SIZE_MAX;
-    CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
-    CHECK(n_batches == SIZE_MAX/2 + 1);
-    CHECK(n_batch_points == 2);
-}
-
 /**
  * Run secp256k1_ecmult_multi_var with num points and a scratch space restricted to
  * 1 <= i <= num points.
@@ -2970,7 +2905,6 @@ void run_ecmult_multi_tests(void) {
     test_ecmult_multi_pippenger_max_points();
     scratch = secp256k1_scratch_create(&ctx->error_callback, 819200);
     test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
-    test_ecmult_multi(NULL, secp256k1_ecmult_multi_var);
     test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single);
     test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single);
     secp256k1_scratch_destroy(scratch);
@@ -2980,7 +2914,6 @@ void run_ecmult_multi_tests(void) {
     test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
     secp256k1_scratch_destroy(scratch);
 
-    test_ecmult_multi_batch_size_helper();
     test_ecmult_multi_batching();
 }
 
@@ -3661,7 +3594,6 @@ void run_ec_pubkey_parse_test(void) {
     ecount = 0;
     VG_UNDEF(&pubkey, sizeof(pubkey));
     CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1);
-    CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_no_precomp, &pubkey, pubkeyc, 65) == 1);
     VG_CHECK(&pubkey, sizeof(pubkey));
     CHECK(ecount == 0);
     VG_UNDEF(&ge, sizeof(ge));
@@ -5040,9 +4972,8 @@ int main(int argc, char **argv) {
         }
     } else {
         FILE *frand = fopen("/dev/urandom", "r");
-        if ((frand == NULL) || fread(&seed16, 1, sizeof(seed16), frand) != sizeof(seed16)) {
+        if ((frand == NULL) || fread(&seed16, sizeof(seed16), 1, frand) != sizeof(seed16)) {
             uint64_t t = time(NULL) * (uint64_t)1337;
-            fprintf(stderr, "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG\n");
             seed16[0] ^= t;
             seed16[1] ^= t >> 8;
             seed16[2] ^= t >> 16;