Repository: bitcoin-core/secp256k1
Pull request #1160 (2022-11-22 03:19:36)

Makefile: add `-I$(top_srcdir)/{include,src}` to `CPPFLAGS` for precomputed
When performing an out-of-source-tree build, regenerating the source files for the precomputed ecmult tables places them outside the source tree. Then, when they are to be compiled, they cannot find the headers they need because the source tree is absent from their include search path. This appears to have been an oversight, as the relevant `-I` options are present in `libsecp256k1_la_CPPFLAGS` but were missing from `libsecp256k1_precomputed_la_CPPFLAGS`. This PR adds them.

hebasto: I can reproduce the bug when building out-of-source:
```
src/precomputed_ecmult.c:8:10: fatal error: ../include/secp256k1.h: No such file or directory
    8 | #include "../include/secp256k1.h"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
```
```
src/precomputed_ecmult_gen.c:6:10: fatal error: ../include/secp256k1.h: No such file or directory
    6 | #include "../include/secp256k1.h"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
```

Tested that adding `-I$(top_srcdir)/src` is enough to fix it, as @real-or-random [suggested](https://github.com/bitcoin-core/secp256k1/pull/1160#discussion_r1029197729).

---

> as the relevant `-I` options are present in `libsecp256k1_la_CPPFLAGS` but were missing from `libsecp256k1_precomputed_la_CPPFLAGS`.

I'm not sure about it:

https://github.com/bitcoin-core/secp256k1/blob/751c4354d51fb5b10a80764df627b84e1a5ccd4f/Makefile.am#L95

https://github.com/bitcoin-core/secp256k1/blob/751c4354d51fb5b10a80764df627b84e1a5ccd4f/Makefile.am#L76
real-or-random: @whitslack Friendly ping. :)
whitslack: > Okay, I think this is not how we intend users to build the library

The reason is to build for multiple ABIs (e.g., x86 and x86_64) without needing to make an extra copy of the sources.

> `-I$(top_srcdir)/src` suffices.

Confirmed.
real-or-random: @whitslack 

Nice! Can you also add the comments I suggested above? https://github.com/bitcoin-core/secp256k1/pull/1160#discussion_r1029197729 

Patch:
diff --git a/.cirrus.yml b/.cirrus.yml
index 3a26720..51e3bc9 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -1,7 +1,6 @@
 env:
   ### compiler options
   HOST:
-  WRAPPER_CMD:
   # Specific warnings can be disabled with -Wno-error=foo.
   # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual.
   WERROR_CFLAGS: -Werror -pedantic-errors
diff --git a/.gitignore b/.gitignore
index c68645b..80c646b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,8 @@ coverage.*.html
 *.gcno
 *.gcov
 
+src/libsecp256k1-config.h
+src/libsecp256k1-config.h.in
 build-aux/ar-lib
 build-aux/config.guess
 build-aux/config.sub
@@ -56,4 +58,5 @@ build-aux/m4/ltversion.m4
 build-aux/missing
 build-aux/compile
 build-aux/test-driver
+src/stamp-h1
 libsecp256k1.pc
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3a13a39..7443483 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,39 +1,28 @@
 # Changelog
 
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ## [Unreleased]
 
 ## [0.2.0] - 2022-12-12
 
-#### Added
- - Added usage examples for common use cases in a new `examples/` directory.
+### Added
  - Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`.
- - Added support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms.
 
-#### Changed
- - Enabled modules `schnorrsig`, `extrakeys` and `ecdh` by default in `./configure`.
- - The `secp256k1_nonce_function_rfc6979` nonce function, used by default by `secp256k1_ecdsa_sign`, now reduces the message hash modulo the group order to match the specification. This only affects improper use of ECDSA signing API.
+### Changed
+ - Enabled modules schnorrsig, extrakeys and ECDH by default in `./configure`.
 
-#### Deprecated
+### Deprecated
  - Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead.
  - Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`.
- - Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`.
 
-#### ABI Compatibility
+### ABI Compatibility
 
 Since this is the first release, we do not compare application binary interfaces.
-However, there are earlier unreleased versions of libsecp256k1 that are *not* ABI compatible with this version.
+However, there are unreleased versions of libsecp256k1 that are *not* ABI compatible with this version.
 
 ## [0.1.0] - 2013-03-05 to 2021-12-25
 
 This version was in fact never released.
 The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6).
 Therefore, this version number does not uniquely identify a set of source files.
-
-[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...HEAD
-[0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0
-[0.1.0]: https://github.com/bitcoin-core/secp256k1/commit/423b6d19d373f1224fd671a982584d7e7900bc93
diff --git a/Makefile.am b/Makefile.am
index 0e59c3a..7399348 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -73,7 +73,9 @@ noinst_HEADERS += examples/random.h
 PRECOMPUTED_LIB = libsecp256k1_precomputed.la
 noinst_LTLIBRARIES = $(PRECOMPUTED_LIB)
 libsecp256k1_precomputed_la_SOURCES =  src/precomputed_ecmult.c src/precomputed_ecmult_gen.c
-libsecp256k1_precomputed_la_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES)
+# We need `-I$(top_srcdir)/src` in VPATH builds if libsecp256k1_precomputed_la_SOURCES have been recreated in the build tree.
+# This helps users and packagers who insist on recreating the precomputed files (e.g., Gentoo).
+libsecp256k1_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES)
 
 if USE_EXTERNAL_ASM
 COMMON_LIB = libsecp256k1_common.la
@@ -105,7 +107,6 @@ if USE_BENCHMARK
 noinst_PROGRAMS += bench bench_internal bench_ecmult
 bench_SOURCES = src/bench.c
 bench_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
-bench_CPPFLAGS = $(SECP_CONFIG_DEFINES)
 bench_internal_SOURCES = src/bench_internal.c
 bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
 bench_internal_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES)
@@ -149,7 +150,7 @@ endif
 if USE_EXAMPLES
 noinst_PROGRAMS += ecdsa_example
 ecdsa_example_SOURCES = examples/ecdsa.c
-ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include
+ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include $(SECP_CONFIG_DEFINES)
 ecdsa_example_LDADD = libsecp256k1.la
 ecdsa_example_LDFLAGS = -static
 if BUILD_WINDOWS
@@ -159,7 +160,7 @@ TESTS += ecdsa_example
 if ENABLE_MODULE_ECDH
 noinst_PROGRAMS += ecdh_example
 ecdh_example_SOURCES = examples/ecdh.c
-ecdh_example_CPPFLAGS = -I$(top_srcdir)/include
+ecdh_example_CPPFLAGS = -I$(top_srcdir)/include $(SECP_CONFIG_DEFINES)
 ecdh_example_LDADD = libsecp256k1.la
 ecdh_example_LDFLAGS = -static
 if BUILD_WINDOWS
@@ -170,7 +171,7 @@ endif
 if ENABLE_MODULE_SCHNORRSIG
 noinst_PROGRAMS += schnorr_example
 schnorr_example_SOURCES = examples/schnorr.c
-schnorr_example_CPPFLAGS = -I$(top_srcdir)/include
+schnorr_example_CPPFLAGS = -I$(top_srcdir)/include $(SECP_CONFIG_DEFINES)
 schnorr_example_LDADD = libsecp256k1.la
 schnorr_example_LDFLAGS = -static
 if BUILD_WINDOWS
diff --git a/build-aux/m4/bitcoin_secp.m4 b/build-aux/m4/bitcoin_secp.m4
index 624f5e9..98be915 100644
--- a/build-aux/m4/bitcoin_secp.m4
+++ b/build-aux/m4/bitcoin_secp.m4
@@ -20,7 +20,7 @@ if test x"$has_valgrind" != x"yes"; then
     #if defined(NVALGRIND)
     #  error "Valgrind does not support this platform."
     #endif
-  ]])], [has_valgrind=yes])
+  ]])], [has_valgrind=yes; AC_DEFINE(HAVE_VALGRIND,1,[Define this symbol if valgrind is installed, and it supports the host platform])])
 fi
 AC_MSG_RESULT($has_valgrind)
 ])
diff --git a/ci/cirrus.sh b/ci/cirrus.sh
index 80ce8f2..fb5854a 100755
--- a/ci/cirrus.sh
+++ b/ci/cirrus.sh
@@ -1,6 +1,7 @@
 #!/bin/sh
 
-set -eux
+set -e
+set -x
 
 export LC_ALL=C
 
@@ -10,20 +11,14 @@ print_environment() {
     set +x
     # There are many ways to print variable names and their content. This one
     # does not rely on bash.
-    for var in WERROR_CFLAGS MAKEFLAGS BUILD \
+    for i in WERROR_CFLAGS MAKEFLAGS BUILD \
             ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
             EXPERIMENTAL ECDH RECOVERY SCHNORRSIG \
             SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETEST\
             EXAMPLES \
-            HOST WRAPPER_CMD \
-            CC CFLAGS CPPFLAGS AR NM
+            WRAPPER_CMD CC AR NM HOST
     do
-        eval "isset=\${$var+x}"
-        if [ -n "$isset" ]; then
-            eval "val=\${$var}"
-            # shellcheck disable=SC2154
-            printf '%s="%s" ' "$var" "$val"
-        fi
+        eval 'printf "%s %s " "$i=\"${'"$i"'}\""'
     done
     echo "$0"
     set -x
@@ -41,7 +36,7 @@ esac
 
 env >> test_env.log
 
-if [ -n "${CC+x}" ]; then
+if [ -n "$CC" ]; then
     # The MSVC compiler "cl" doesn't understand "-v"
     $CC -v || true
 fi
diff --git a/include/secp256k1.h b/include/secp256k1.h
index 3d169ec..826ab75 100644
--- a/include/secp256k1.h
+++ b/include/secp256k1.h
@@ -849,7 +849,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
  * kind of elliptic curve point multiplication and thus does not benefit from
  * enhanced protection against side-channel leakage currently.
  *
- * It is safe to call this function on a copy of secp256k1_context_static in writable
+ * It is safe call this function on a copy of secp256k1_context_static in writable
  * memory (e.g., obtained via secp256k1_context_clone). In that case, this
  * function is guaranteed to return 1, but the call will have no effect because
  * the static context (or a copy thereof) is not meant to be randomized.
diff --git a/src/int128.h b/src/int128.h
index 8c1c061..84d969a 100644
--- a/src/int128.h
+++ b/src/int128.h
@@ -66,12 +66,7 @@ static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a,
  */
 static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b);
 
-/* Return the input value modulo 2^64. */
-static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a);
-
-/* Return the value as a signed 64-bit value.
- * Requires the input to be between INT64_MIN and INT64_MAX.
- */
+/* Return the low 64-bits of a 128-bit value interpreted as an signed 64-bit value. */
 static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a);
 
 /* Write a signed 64-bit value to r. */
diff --git a/src/int128_native_impl.h b/src/int128_native_impl.h
index 30c26f2..e4b7f41 100644
--- a/src/int128_native_impl.h
+++ b/src/int128_native_impl.h
@@ -67,12 +67,7 @@ static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned
    *r >>= n;
 }
 
-static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
-   return (uint64_t)*a;
-}
-
 static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
-   VERIFY_CHECK(INT64_MIN <= *a && *a <= INT64_MAX);
    return *a;
 }
 
diff --git a/src/int128_struct_impl.h b/src/int128_struct_impl.h
index 298a7bb..b5f8fb7 100644
--- a/src/int128_struct_impl.h
+++ b/src/int128_struct_impl.h
@@ -170,14 +170,8 @@ static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned
    }
 }
 
-static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
-   return a->lo;
-}
-
 static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
-   /* Verify that a represents a 64 bit signed value by checking that the high bits are a sign extension of the low bits. */
-   VERIFY_CHECK(a->hi == -(a->lo >> 63));
-   return (int64_t)secp256k1_i128_to_u64(a);
+   return (int64_t)a->lo;
 }
 
 static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) {
diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h
index 2b5463a..50be2e5 100644
--- a/src/modinv64_impl.h
+++ b/src/modinv64_impl.h
@@ -39,13 +39,13 @@ static const secp256k1_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}};
 
 /* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */
 static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) {
-    const uint64_t M62 = UINT64_MAX >> 2;
+    const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
     secp256k1_int128 c, d;
     int i;
     secp256k1_i128_from_i64(&c, 0);
     for (i = 0; i < 4; ++i) {
         if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor);
-        r->v[i] = secp256k1_i128_to_u64(&c) & M62; secp256k1_i128_rshift(&c, 62);
+        r->v[i] = secp256k1_i128_to_i64(&c) & M62; secp256k1_i128_rshift(&c, 62);
     }
     if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor);
     secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c));
@@ -314,7 +314,7 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
  * This implements the update_de function from the explanation.
  */
 static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp256k1_modinv64_signed62 *e, const secp256k1_modinv64_trans2x2 *t, const secp256k1_modinv64_modinfo* modinfo) {
-    const uint64_t M62 = UINT64_MAX >> 2;
+    const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
     const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4];
     const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4];
     const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
@@ -327,8 +327,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
     VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0);  /* e <    modulus */
     VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) >= 0); /* |u|+|v| doesn't overflow */
     VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) >= 0); /* |q|+|r| doesn't overflow */
-    VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) <= (int64_t)1 << 62); /* |u|+|v| <= 2^62 */
-    VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) <= (int64_t)1 << 62); /* |q|+|r| <= 2^62 */
+    VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) <= M62 + 1); /* |u|+|v| <= 2^62 */
+    VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) <= M62 + 1); /* |q|+|r| <= 2^62 */
 #endif
     /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
     sd = d4 >> 63;
@@ -341,14 +341,14 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
     secp256k1_i128_mul(&ce, q, d0);
     secp256k1_i128_accum_mul(&ce, r, e0);
     /* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */
-    md -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&cd) + md) & M62;
-    me -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&ce) + me) & M62;
+    md -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&cd) + md) & M62;
+    me -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&ce) + me) & M62;
     /* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */
     secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md);
     secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me);
     /* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */
-    VERIFY_CHECK((secp256k1_i128_to_u64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62);
-    VERIFY_CHECK((secp256k1_i128_to_u64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62);
+    VERIFY_CHECK((secp256k1_i128_to_i64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62);
+    VERIFY_CHECK((secp256k1_i128_to_i64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62);
     /* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */
     secp256k1_i128_accum_mul(&cd, u, d1);
     secp256k1_i128_accum_mul(&cd, v, e1);
@@ -358,8 +358,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
         secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md);
         secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me);
     }
-    d->v[0] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
-    e->v[0] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
+    d->v[0] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
+    e->v[0] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
     /* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */
     secp256k1_i128_accum_mul(&cd, u, d2);
     secp256k1_i128_accum_mul(&cd, v, e2);
@@ -369,8 +369,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
         secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md);
         secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me);
     }
-    d->v[1] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
-    e->v[1] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
+    d->v[1] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
+    e->v[1] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
     /* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */
     secp256k1_i128_accum_mul(&cd, u, d3);
     secp256k1_i128_accum_mul(&cd, v, e3);
@@ -380,8 +380,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
         secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md);
         secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me);
     }
-    d->v[2] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
-    e->v[2] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
+    d->v[2] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
+    e->v[2] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
     /* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */
     secp256k1_i128_accum_mul(&cd, u, d4);
     secp256k1_i128_accum_mul(&cd, v, e4);
@@ -389,8 +389,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
     secp256k1_i128_accum_mul(&ce, r, e4);
     secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md);
     secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me);
-    d->v[3] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
-    e->v[3] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
+    d->v[3] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
+    e->v[3] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
     /* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */
     d->v[4] = secp256k1_i128_to_i64(&cd);
     e->v[4] = secp256k1_i128_to_i64(&ce);
@@ -407,7 +407,7 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
  * This implements the update_fg function from the explanation.
  */
 static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
-    const uint64_t M62 = UINT64_MAX >> 2;
+    const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
     const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4];
     const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4];
     const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
@@ -418,36 +418,36 @@ static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp
     secp256k1_i128_mul(&cg, q, f0);
     secp256k1_i128_accum_mul(&cg, r, g0);
     /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
-    VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
-    VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
+    VERIFY_CHECK((secp256k1_i128_to_i64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
+    VERIFY_CHECK((secp256k1_i128_to_i64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
     /* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */
     secp256k1_i128_accum_mul(&cf, u, f1);
     secp256k1_i128_accum_mul(&cf, v, g1);
     secp256k1_i128_accum_mul(&cg, q, f1);
     secp256k1_i128_accum_mul(&cg, r, g1);
-    f->v[0] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
-    g->v[0] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
+    f->v[0] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
+    g->v[0] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
     /* Compute limb 2 of t*[f,g], and store it as output limb 1. */
     secp256k1_i128_accum_mul(&cf, u, f2);
     secp256k1_i128_accum_mul(&cf, v, g2);
     secp256k1_i128_accum_mul(&cg, q, f2);
     secp256k1_i128_accum_mul(&cg, r, g2);
-    f->v[1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
-    g->v[1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
+    f->v[1] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
+    g->v[1] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
     /* Compute limb 3 of t*[f,g], and store it as output limb 2. */
     secp256k1_i128_accum_mul(&cf, u, f3);
     secp256k1_i128_accum_mul(&cf, v, g3);
     secp256k1_i128_accum_mul(&cg, q, f3);
     secp256k1_i128_accum_mul(&cg, r, g3);
-    f->v[2] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
-    g->v[2] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
+    f->v[2] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
+    g->v[2] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
     /* Compute limb 4 of t*[f,g], and store it as output limb 3. */
     secp256k1_i128_accum_mul(&cf, u, f4);
     secp256k1_i128_accum_mul(&cf, v, g4);
     secp256k1_i128_accum_mul(&cg, q, f4);
     secp256k1_i128_accum_mul(&cg, r, g4);
-    f->v[3] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
-    g->v[3] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
+    f->v[3] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
+    g->v[3] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
     /* What remains is limb 5 of t*[f,g]; store it as output limb 4. */
     f->v[4] = secp256k1_i128_to_i64(&cf);
     g->v[4] = secp256k1_i128_to_i64(&cg);
@@ -460,7 +460,7 @@ static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp
  * This implements the update_fg function from the explanation.
  */
 static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
-    const uint64_t M62 = UINT64_MAX >> 2;
+    const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
     const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
     int64_t fi, gi;
     secp256k1_int128 cf, cg;
@@ -474,8 +474,8 @@ static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_sign
     secp256k1_i128_mul(&cg, q, fi);
     secp256k1_i128_accum_mul(&cg, r, gi);
     /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
-    VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
-    VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
+    VERIFY_CHECK((secp256k1_i128_to_i64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
+    VERIFY_CHECK((secp256k1_i128_to_i64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
     /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting
      * down by 62 bits). */
     for (i = 1; i < len; ++i) {
@@ -485,8 +485,8 @@ static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_sign
         secp256k1_i128_accum_mul(&cf, v, gi);
         secp256k1_i128_accum_mul(&cg, q, fi);
         secp256k1_i128_accum_mul(&cg, r, gi);
-        f->v[i - 1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
-        g->v[i - 1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
+        f->v[i - 1] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
+        g->v[i - 1] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
     }
     /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */
     f->v[len - 1] = secp256k1_i128_to_i64(&cf);
diff --git a/src/secp256k1.c b/src/secp256k1.c
index 67c8019..5ed3824 100644
--- a/src/secp256k1.c
+++ b/src/secp256k1.c
@@ -51,10 +51,9 @@
     } \
 } while(0)
 
-#define ARG_CHECK_VOID(cond) do { \
+#define ARG_CHECK_NO_RETURN(cond) do { \
     if (EXPECT(!(cond), 0)) { \
         secp256k1_callback_call(&ctx->illegal_callback, #cond); \
-        return; \
     } \
 } while(0)
 
@@ -76,15 +75,6 @@ static const secp256k1_context secp256k1_context_static_ = {
 const secp256k1_context *secp256k1_context_static = &secp256k1_context_static_;
 const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_static_;
 
-/* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof.
- *
- * This is intended for "context" functions such as secp256k1_context_clone. Function which need specific
- * features of a context should still check for these features directly. For example, a function that needs
- * ecmult_gen should directly check for the existence of the ecmult_gen context. */
-static int secp256k1_context_is_proper(const secp256k1_context* ctx) {
-    return secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx);
-}
-
 void secp256k1_selftest(void) {
     if (!secp256k1_selftest_passes()) {
         secp256k1_callback_call(&default_error_callback, "self test failed");
@@ -167,7 +157,7 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
 }
 
 void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
-    ARG_CHECK_VOID(ctx != secp256k1_context_static);
+    ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static);
     if (ctx != NULL) {
         secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
     }
@@ -181,10 +171,7 @@ 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) {
-    /* We compare pointers instead of checking secp256k1_context_is_proper() here
-       because setting callbacks is allowed on *copies* of the static context:
-       it's harmless and makes testing easier. */
-    ARG_CHECK_VOID(ctx != secp256k1_context_static);
+    ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static);
     if (fun == NULL) {
         fun = secp256k1_default_illegal_callback_fn;
     }
@@ -193,10 +180,7 @@ 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) {
-    /* We compare pointers instead of checking secp256k1_context_is_proper() here
-       because setting callbacks is allowed on *copies* of the static context:
-       it's harmless and makes testing easier. */
-    ARG_CHECK_VOID(ctx != secp256k1_context_static);
+    ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static);
     if (fun == NULL) {
         fun = secp256k1_default_error_callback_fn;
     }


Test patch:
diff --git a/src/modules/extrakeys/tests_impl.h b/src/modules/extrakeys/tests_impl.h
index dd535b9..8030aed 100644
--- a/src/modules/extrakeys/tests_impl.h
+++ b/src/modules/extrakeys/tests_impl.h
@@ -336,6 +336,7 @@ void test_keypair(void) {
     secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
     int pk_parity, pk_parity_tmp;
     int ecount;
+    secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static);
 
     set_counting_callbacks(ctx, &ecount);
     set_counting_callbacks(sttc, &ecount);
@@ -439,9 +440,7 @@ void test_keypair(void) {
     memset(&keypair, 0, sizeof(keypair));
     CHECK(secp256k1_keypair_sec(ctx, sk_tmp, &keypair) == 1);
     CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
-
-    secp256k1_context_set_error_callback(sttc, NULL, NULL);
-    secp256k1_context_set_illegal_callback(sttc, NULL, NULL);
+    secp256k1_context_destroy(sttc);
 }
 
 void test_keypair_add(void) {
diff --git a/src/modules/recovery/tests_impl.h b/src/modules/recovery/tests_impl.h
index 0769b96..0ff9294 100644
--- a/src/modules/recovery/tests_impl.h
+++ b/src/modules/recovery/tests_impl.h
@@ -30,6 +30,7 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c
 
 void test_ecdsa_recovery_api(void) {
     /* Setup contexts that just count errors */
+    secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static);
     secp256k1_pubkey pubkey;
     secp256k1_pubkey recpubkey;
     secp256k1_ecdsa_signature normal_sig;
@@ -123,8 +124,7 @@ void test_ecdsa_recovery_api(void) {
     CHECK(ecount == 7);
 
     /* cleanup */
-    secp256k1_context_set_error_callback(sttc, NULL, NULL);
-    secp256k1_context_set_illegal_callback(sttc, NULL, NULL);
+    secp256k1_context_destroy(sttc);
 }
 
 void test_ecdsa_recovery_end_to_end(void) {
diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h
index f79d7aa..06cc097 100644
--- a/src/modules/schnorrsig/tests_impl.h
+++ b/src/modules/schnorrsig/tests_impl.h
@@ -128,7 +128,8 @@ void test_schnorrsig_api(void) {
     secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL};
 
     /** setup **/
-    int ecount = 0;
+    secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static);
+    int ecount;
 
     secp256k1_context_set_error_callback(ctx, counting_illegal_callback_fn, &ecount);
     secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
@@ -197,8 +198,7 @@ void test_schnorrsig_api(void) {
     CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &zero_pk) == 0);
     CHECK(ecount == 4);
 
-    secp256k1_context_set_error_callback(sttc, NULL, NULL);
-    secp256k1_context_set_illegal_callback(sttc, NULL, NULL);
+    secp256k1_context_destroy(sttc);
 }
 
 /* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the
diff --git a/src/tests.c b/src/tests.c
index 89246cf..728f264 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -29,7 +29,6 @@
 
 static int count = 64;
 static secp256k1_context *ctx = NULL;
-static secp256k1_context *sttc = NULL;
 
 static void counting_illegal_callback_fn(const char* str, void* data) {
     /* Dummy callback function that just counts. */
@@ -153,44 +152,111 @@ int context_eq(const secp256k1_context *a, const secp256k1_context *b) {
     return a->declassify == b->declassify
             && ecmult_gen_context_eq(&a->ecmult_gen_ctx, &b->ecmult_gen_ctx)
             && a->illegal_callback.fn == b->illegal_callback.fn
-            && a->illegal_callback.data == b->illegal_callback.data
+            && a->illegal_callback.data == b->illegal_callback.
+data
             && a->error_callback.fn == b->error_callback.fn
             && a->error_callback.data == b->error_callback.data;
 }
 
-void run_deprecated_context_flags_test(void) {
-    /* Check that a context created with any of the flags in the flags array is
-     * identical to the NONE context. */
+void test_deprecated_flags(void) {
     unsigned int flags[] = { SECP256K1_CONTEXT_SIGN,
                              SECP256K1_CONTEXT_VERIFY,
                              SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY };
-    secp256k1_context *none_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
     int i;
+    /* Check that a context created with any of the flags in the flags array is
+     * identical to the NONE context. */
     for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) {
         secp256k1_context *tmp_ctx;
         CHECK(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE) == secp256k1_context_preallocated_size(flags[i]));
         tmp_ctx = secp256k1_context_create(flags[i]);
-        CHECK(context_eq(none_ctx, tmp_ctx));
+        CHECK(context_eq(ctx, tmp_ctx));
         secp256k1_context_destroy(tmp_ctx);
     }
-    secp256k1_context_destroy(none_ctx);
 }
 
-void run_ec_illegal_argument_tests(void) {
-    int ecount = 0;
-    int ecount2 = 10;
+void run_context_tests(int use_prealloc) {
     secp256k1_pubkey pubkey;
     secp256k1_pubkey zero_pubkey;
     secp256k1_ecdsa_signature sig;
     unsigned char ctmp[32];
+    int32_t ecount;
+    int32_t ecount2;
+    secp256k1_context *sttc;
+    void *ctx_prealloc = NULL;
+    void *sttc_prealloc = NULL;
+
+    secp256k1_gej pubj;
+    secp256k1_ge pub;
+    secp256k1_scalar msg, key, nonce;
+    secp256k1_scalar sigr, sigs;
+
+    /* Check that deprecated secp256k1_context_no_precomp is an alias to secp256k1_context_static. */
+    CHECK(secp256k1_context_no_precomp == secp256k1_context_static);
+
+    if (use_prealloc) {
+        ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
+        CHECK(ctx_prealloc != NULL);
+        ctx = secp256k1_context_preallocated_create(ctx_prealloc, SECP256K1_CONTEXT_NONE);
+        sttc_prealloc = malloc(secp256k1_context_preallocated_clone_size(secp256k1_context_static));
+        CHECK(sttc_prealloc != NULL);
+        sttc = secp256k1_context_preallocated_clone(secp256k1_context_static, sttc_prealloc);
+    } else {
+        sttc = secp256k1_context_clone(secp256k1_context_static);
+        ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+    }
+
+    test_deprecated_flags();
+
+    memset(&zero_pubkey, 0, sizeof(zero_pubkey));
 
-    /* Setup */
+    ecount = 0;
+    ecount2 = 10;
     secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
     secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount2);
-    memset(ctmp, 1, 32);
-    memset(&zero_pubkey, 0, sizeof(zero_pubkey));
+    /* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */
+    secp256k1_context_set_error_callback(ctx, secp256k1_default_illegal_callback_fn, NULL);
+    CHECK(ctx->error_callback.fn != sttc->error_callback.fn);
+    CHECK(ctx->error_callback.fn == secp256k1_default_illegal_callback_fn);
+
+    /* check if sizes for cloning are consistent */
+    CHECK(secp256k1_context_preallocated_clone_size(ctx) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
+    CHECK(secp256k1_context_preallocated_clone_size(sttc) >= sizeof(secp256k1_context));
+
+    /*** clone and destroy all of them to make sure cloning was complete ***/
+    {
+        secp256k1_context *ctx_tmp;
+
+        if (use_prealloc) {
+            /* clone into a non-preallocated context and then again into a new preallocated one. */
+            ctx_tmp = ctx; ctx = secp256k1_context_clone(ctx); secp256k1_context_preallocated_destroy(ctx_tmp);
+            free(ctx_prealloc); ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(ctx_prealloc != NULL);
+            ctx_tmp = ctx; ctx = secp256k1_context_preallocated_clone(ctx, ctx_prealloc); secp256k1_context_destroy(ctx_tmp);
+        } else {
+            /* clone into a preallocated context and then again into a new non-preallocated one. */
+            void *prealloc_tmp;
+
+            prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(prealloc_tmp != NULL);
+            ctx_tmp = ctx; ctx = secp256k1_context_preallocated_clone(ctx, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
+            ctx_tmp = ctx; ctx = secp256k1_context_clone(ctx); secp256k1_context_preallocated_destroy(ctx_tmp);
+            free(prealloc_tmp);
+        }
+    }
+
+    /* Verify that the error callback makes it across the clone. */
+    CHECK(ctx->error_callback.fn != sttc->error_callback.fn);
+    CHECK(ctx->error_callback.fn == secp256k1_default_illegal_callback_fn);
+    /* And that it resets back to default. */
+    secp256k1_context_set_error_callback(ctx, NULL, NULL);
+    CHECK(ctx->error_callback.fn == sttc->error_callback.fn);
+
+    /*** attempt to use them ***/
+    random_scalar_order_test(&msg);
+    random_scalar_order_test(&key);
+    secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key);
+    secp256k1_ge_set_gej(&pub, &pubj);
 
     /* Verify context-type checking illegal-argument errors. */
+    memset(ctmp, 1, 32);
     CHECK(secp256k1_ec_pubkey_create(sttc, &pubkey, ctmp) == 0);
     CHECK(ecount == 1);
     VG_UNDEF(&pubkey, sizeof(pubkey));
@@ -216,115 +282,43 @@ void run_ec_illegal_argument_tests(void) {
     CHECK(ecount == 2);
     CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey) == 1);
     CHECK(ecount == 2);
-    CHECK(secp256k1_ec_pubkey_negate(sttc, &zero_pubkey) == 0);
-    CHECK(ecount == 3);
     CHECK(secp256k1_ec_pubkey_negate(ctx, NULL) == 0);
     CHECK(ecount2 == 11);
+    CHECK(secp256k1_ec_pubkey_negate(sttc, &zero_pubkey) == 0);
+    CHECK(ecount == 3);
     CHECK(secp256k1_ec_pubkey_tweak_mul(sttc, &pubkey, ctmp) == 1);
     CHECK(ecount == 3);
-
-    /* Clean up */
+    CHECK(secp256k1_context_randomize(sttc, ctmp) == 1);
+    CHECK(ecount == 3);
+    CHECK(secp256k1_context_randomize(sttc, NULL) == 1);
+    CHECK(ecount == 3);
+    CHECK(secp256k1_context_randomize(ctx, ctmp) == 1);
+    CHECK(ecount2 == 11);
+    CHECK(secp256k1_context_randomize(ctx, NULL) == 1);
+    CHECK(ecount2 == 11);
     secp256k1_context_set_illegal_callback(sttc, NULL, NULL);
     secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
-}
-
-void run_static_context_tests(void) {
-    int32_t dummy = 0;
-
-    /* Check that deprecated secp256k1_context_no_precomp is an alias to secp256k1_context_static. */
-    CHECK(secp256k1_context_no_precomp == secp256k1_context_static);
-
-    /* check if sizes for cloning are consistent */
-    CHECK(secp256k1_context_preallocated_clone_size(sttc) >= sizeof(secp256k1_context));
-
-    /* Verify that setting and resetting illegal callback works */
-    secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &dummy);
-    CHECK(sttc->illegal_callback.fn == counting_illegal_callback_fn);
-    secp256k1_context_set_illegal_callback(sttc, NULL, NULL);
-    CHECK(sttc->illegal_callback.fn == secp256k1_default_illegal_callback_fn);
-}
-
-void run_proper_context_tests(int use_prealloc) {
-    int32_t dummy = 0;
-    secp256k1_context *my_ctx;
-    void *my_ctx_prealloc = NULL;
-
-    secp256k1_gej pubj;
-    secp256k1_ge pub;
-    secp256k1_scalar msg, key, nonce;
-    secp256k1_scalar sigr, sigs;
-    if (use_prealloc) {
-        my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
-        CHECK(my_ctx_prealloc != NULL);
-        my_ctx = secp256k1_context_preallocated_create(my_ctx_prealloc, SECP256K1_CONTEXT_NONE);
-    } else {
-        my_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
-    }
-
-    /* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */
-    secp256k1_context_set_error_callback(my_ctx, secp256k1_default_illegal_callback_fn, NULL);
-    CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn);
-    CHECK(my_ctx->error_callback.fn == secp256k1_default_illegal_callback_fn);
-
-    /* check if sizes for cloning are consistent */
-    CHECK(secp256k1_context_preallocated_clone_size(my_ctx) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
-
-    /*** clone and destroy all of them to make sure cloning was complete ***/
-    {
-        secp256k1_context *ctx_tmp;
-
-        if (use_prealloc) {
-            /* clone into a non-preallocated context and then again into a new preallocated one. */
-            ctx_tmp = my_ctx; my_ctx = secp256k1_context_clone(my_ctx); secp256k1_context_preallocated_destroy(ctx_tmp);
-            free(my_ctx_prealloc); my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(my_ctx_prealloc != NULL);
-            ctx_tmp = my_ctx; my_ctx = secp256k1_context_preallocated_clone(my_ctx, my_ctx_prealloc); secp256k1_context_destroy(ctx_tmp);
-        } else {
-            /* clone into a preallocated context and then again into a new non-preallocated one. */
-            void *prealloc_tmp;
-
-            prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(prealloc_tmp != NULL);
-            ctx_tmp = my_ctx; my_ctx = secp256k1_context_preallocated_clone(my_ctx, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
-            ctx_tmp = my_ctx; my_ctx = secp256k1_context_clone(my_ctx); secp256k1_context_preallocated_destroy(ctx_tmp);
-            free(prealloc_tmp);
-        }
-    }
-
-    /* Verify that the error callback makes it across the clone. */
-    CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn);
-    CHECK(my_ctx->error_callback.fn == secp256k1_default_illegal_callback_fn);
-    /* And that it resets back to default. */
-    secp256k1_context_set_error_callback(my_ctx, NULL, NULL);
-    CHECK(my_ctx->error_callback.fn == secp256k1_default_error_callback_fn);
-
-    /* Verify that setting and resetting illegal callback works */
-    secp256k1_context_set_illegal_callback(my_ctx, counting_illegal_callback_fn, &dummy);
-    CHECK(my_ctx->illegal_callback.fn == counting_illegal_callback_fn);
-    secp256k1_context_set_illegal_callback(my_ctx, NULL, NULL);
-    CHECK(my_ctx->illegal_callback.fn == secp256k1_default_illegal_callback_fn);
-
-    /*** attempt to use them ***/
-    random_scalar_order_test(&msg);
-    random_scalar_order_test(&key);
-    secp256k1_ecmult_gen(&my_ctx->ecmult_gen_ctx, &pubj, &key);
-    secp256k1_ge_set_gej(&pub, &pubj);
 
     /* obtain a working nonce */
     do {
         random_scalar_order_test(&nonce);
-    } while(!secp256k1_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
+    } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
 
     /* try signing */
-    CHECK(secp256k1_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
+    CHECK(secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
 
     /* try verifying */
     CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg));
 
     /* cleanup */
     if (use_prealloc) {
-        secp256k1_context_preallocated_destroy(my_ctx);
-        free(my_ctx_prealloc);
+        secp256k1_context_preallocated_destroy(ctx);
+        secp256k1_context_preallocated_destroy(sttc);
+        free(ctx_prealloc);
+        free(sttc_prealloc);
     } else {
-        secp256k1_context_destroy(my_ctx);
+        secp256k1_context_destroy(ctx);
+        secp256k1_context_destroy(sttc);
     }
     /* Defined as no-op. */
     secp256k1_context_destroy(NULL);
@@ -340,10 +334,12 @@ void run_scratch_tests(void) {
     secp256k1_scratch_space *scratch;
     secp256k1_scratch_space local_scratch;
 
+    ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+
+    /* Test public API */
     secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
     secp256k1_context_set_error_callback(ctx, counting_illegal_callback_fn, &ecount);
 
-    /* Test public API */
     scratch = secp256k1_scratch_space_create(ctx, 1000);
     CHECK(scratch != NULL);
     CHECK(ecount == 0);
@@ -410,9 +406,7 @@ void run_scratch_tests(void) {
 
     /* cleanup */
     secp256k1_scratch_space_destroy(ctx, NULL); /* no-op */
-
-    secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
-    secp256k1_context_set_error_callback(ctx, NULL, NULL);
+    secp256k1_context_destroy(ctx);
 }
 
 
@@ -1788,7 +1782,7 @@ void load256i128(uint16_t* out, const secp256k1_int128* v) {
     uint64_t lo;
     int64_t hi;
     secp256k1_int128 c = *v;
-    lo = secp256k1_i128_to_u64(&c);
+    lo = secp256k1_i128_to_i64(&c);
     secp256k1_i128_rshift(&c, 64);
     hi = secp256k1_i128_to_i64(&c);
     load256two64(out, hi, lo, 1);
@@ -1905,14 +1899,12 @@ void run_int128_test_case(void) {
     secp256k1_i128_rshift(&swz, uc % 127);
     load256i128(rswz, &swz);
     CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0);
-    /* test secp256k1_i128_to_u64 */
-    CHECK(secp256k1_i128_to_u64(&swa) == v[0]);
+    /* test secp256k1_i128_to_i64 */
+    CHECK((uint64_t)secp256k1_i128_to_i64(&swa) == v[0]);
     /* test secp256k1_i128_from_i64 */
     secp256k1_i128_from_i64(&swz, sb);
     load256i128(rswz, &swz);
     CHECK(secp256k1_memcmp_var(rsb, rswz, 16) == 0);
-    /* test secp256k1_i128_to_i64 */
-    CHECK(secp256k1_i128_to_i64(&swz) == sb);
     /* test secp256k1_i128_eq_var */
     {
         int expect = (uc & 1);
@@ -1972,20 +1964,20 @@ void run_int128_tests(void) {
         /* Compute INT128_MAX = 2^127 - 1 with secp256k1_i128_accum_mul */
         secp256k1_i128_mul(&res, INT64_MAX, INT64_MAX);
         secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MAX);
-        CHECK(secp256k1_i128_to_u64(&res) == 2);
+        CHECK(secp256k1_i128_to_i64(&res) == 2);
         secp256k1_i128_accum_mul(&res, 4, 9223372036854775807);
         secp256k1_i128_accum_mul(&res, 1, 1);
-        CHECK(secp256k1_i128_to_u64(&res) == UINT64_MAX);
+        CHECK((uint64_t)secp256k1_i128_to_i64(&res) == UINT64_MAX);
         secp256k1_i128_rshift(&res, 64);
         CHECK(secp256k1_i128_to_i64(&res) == INT64_MAX);
 
         /* Compute INT128_MIN = - 2^127 with secp256k1_i128_accum_mul */
         secp256k1_i128_mul(&res, INT64_MAX, INT64_MIN);
-        CHECK(secp256k1_i128_to_u64(&res) == (uint64_t)INT64_MIN);
+        CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN);
         secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MIN);
-        CHECK(secp256k1_i128_to_u64(&res) == 0);
+        CHECK(secp256k1_i128_to_i64(&res) == 0);
         secp256k1_i128_accum_mul(&res, 2, INT64_MIN);
-        CHECK(secp256k1_i128_to_u64(&res) == 0);
+        CHECK(secp256k1_i128_to_i64(&res) == 0);
         secp256k1_i128_rshift(&res, 64);
         CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN);
     }
@@ -7363,9 +7355,12 @@ int main(int argc, char **argv) {
     /* find random seed */
     secp256k1_testrand_init(argc > 2 ? argv[2] : NULL);
 
-    /*** Setup test environment ***/
+    /* initialize */
+    run_selftest_tests();
+    run_context_tests(0);
+    run_context_tests(1);
+    run_scratch_tests();
 
-    /* Create a global context available to all tests */
     ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
     /* Randomize the context only with probability 15/16
        to make sure we test without context randomization from time to time.
@@ -7375,34 +7370,10 @@ int main(int argc, char **argv) {
         secp256k1_testrand256(rand32);
         CHECK(secp256k1_context_randomize(ctx, rand32));
     }
-    /* Make a writable copy of secp256k1_context_static in order to test the effect of API functions
-       that write to the context. The API does not support cloning the static context, so we use
-       memcpy instead. The user is not supposed to copy a context but we should still ensure that
-       the API functions handle copies of the static context gracefully. */
-    sttc = malloc(sizeof(*secp256k1_context_static));
-    CHECK(sttc != NULL);
-    memcpy(sttc, secp256k1_context_static, sizeof(secp256k1_context));
-    CHECK(!secp256k1_context_is_proper(sttc));
-
-    /*** Run actual tests ***/
-
-    /* selftest tests */
-    run_selftest_tests();
-
-    /* context tests */
-    run_proper_context_tests(0);
-    run_proper_context_tests(1);
-    run_static_context_tests();
-    run_deprecated_context_flags_test();
-
-    /* scratch tests */
-    run_scratch_tests();
 
-    /* randomness tests */
     run_rand_bits();
     run_rand_int();
 
-    /* integer arithmetic tests */
 #ifdef SECP256K1_WIDEMUL_INT128
     run_int128_tests();
 #endif
@@ -7410,7 +7381,6 @@ int main(int argc, char **argv) {
     run_modinv_tests();
     run_inverse_tests();
 
-    /* hash tests */
     run_sha256_known_output_tests();
     run_sha256_counter_tests();
     run_hmac_sha256_tests();
@@ -7463,7 +7433,6 @@ int main(int argc, char **argv) {
 #endif
 
     /* ecdsa tests */
-    run_ec_illegal_argument_tests();
     run_pubkey_comparison();
     run_random_pubkeys();
     run_ecdsa_der_parse();
@@ -7490,12 +7459,11 @@ int main(int argc, char **argv) {
 
     run_cmov_tests();
 
-    /*** Tear down test environment ***/
-    free(sttc);
-    secp256k1_context_destroy(ctx);
-
     secp256k1_testrand_finish();
 
+    /* shutdown */
+    secp256k1_context_destroy(ctx);
+
     printf("no problems found\n");
     return 0;
 }