Repository: bitcoin-core/secp256k1
Pull request #1304 (2023-05-11 11:05:23)

build: Rename arm to arm32 and check if it's really supported
Closes https://github.com/bitcoin-core/secp256k1/issues/1034.

Solves one item in https://github.com/bitcoin-core/secp256k1/issues/1235.


Patch:
diff --git a/.cirrus.yml b/.cirrus.yml
index 5b76436..1560dc7 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -176,7 +176,7 @@ task:
     CTIMETESTS: no
   matrix:
     - env: {}
-    - env: {EXPERIMENTAL: yes, ASM: arm}
+    - env: {EXPERIMENTAL: yes, ASM: arm32}
   << : *MERGE_BASE
   test_script:
     - ./ci/cirrus.sh
@@ -397,7 +397,7 @@ task:
     - PowerShell -NoLogo -Command if ($env:CIRRUS_PR -ne $null) { git fetch $env:CIRRUS_REPO_CLONE_URL pull/$env:CIRRUS_PR/merge; git reset --hard FETCH_HEAD; }
   configure_script:
     - '%x64_NATIVE_TOOLS%'
-    - cmake -E env CFLAGS="/WX" cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON
+    - cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON
   build_script:
     - '%x64_NATIVE_TOOLS%'
     - cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cb3b4b5..f1dac7b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -102,16 +102,22 @@ if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
 endif()
 mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
 
-set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm\" (experimental). [default=AUTO]")
-set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm")
+set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]")
+set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32")
 check_string_option_value(SECP256K1_ASM)
-if(SECP256K1_ASM STREQUAL "arm")
+if(SECP256K1_ASM STREQUAL "arm32")
   enable_language(ASM)
-  add_compile_definitions(USE_EXTERNAL_ASM=1)
+  include(CheckArm32Assembly)
+  check_arm32_assembly()
+  if(HAVE_ARM32_ASM)
+    add_compile_definitions(USE_EXTERNAL_ASM=1)
+  else()
+    message(FATAL_ERROR "ARM32 assembly optimization requested but not available.")
+  endif()
 elseif(SECP256K1_ASM)
-  include(Check64bitAssembly)
-  check_64bit_assembly()
-  if(HAS_64BIT_ASM)
+  include(CheckX86_64Assembly)
+  check_x86_64_assembly()
+  if(HAVE_X86_64_ASM)
     set(SECP256K1_ASM "x86_64")
     add_compile_definitions(USE_ASM_X86_64=1)
   elseif(SECP256K1_ASM STREQUAL "AUTO")
@@ -123,8 +129,8 @@ endif()
 
 option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF)
 if(NOT SECP256K1_EXPERIMENTAL)
-  if(SECP256K1_ASM STREQUAL "arm")
-    message(FATAL_ERROR "ARM assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
+  if(SECP256K1_ASM STREQUAL "arm32")
+    message(FATAL_ERROR "ARM32 assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
   endif()
 endif()
 
diff --git a/build-aux/m4/bitcoin_secp.m4 b/build-aux/m4/bitcoin_secp.m4
index 154157f..11adef4 100644
--- a/build-aux/m4/bitcoin_secp.m4
+++ b/build-aux/m4/bitcoin_secp.m4
@@ -1,12 +1,31 @@
 dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
-AC_DEFUN([SECP_64BIT_ASM_CHECK],[
+AC_DEFUN([SECP_X86_64_ASM_CHECK],[
 AC_MSG_CHECKING(for x86_64 assembly availability)
 AC_LINK_IFELSE([AC_LANG_PROGRAM([[
   #include <stdint.h>]],[[
   uint64_t a = 11, tmp;
   __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
-  ]])],[has_64bit_asm=yes],[has_64bit_asm=no])
-AC_MSG_RESULT([$has_64bit_asm])
+  ]])], [has_x86_64_asm=yes], [has_x86_64_asm=no])
+AC_MSG_RESULT([$has_x86_64_asm])
+])
+
+AC_DEFUN([SECP_ARM32_ASM_CHECK], [
+  AC_MSG_CHECKING(for ARM32 assembly availability)
+  SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS="$CFLAGS"
+  CFLAGS="-x assembler"
+  AC_LINK_IFELSE([AC_LANG_SOURCE([[
+    .syntax unified
+    .eabi_attribute 24, 1
+    .eabi_attribute 25, 1
+    .text
+    .global main
+    main:
+      ldr r0, =0x002A
+      mov r7, #1
+      swi 0   
+    ]])], [has_arm32_asm=yes], [has_arm32_asm=no])
+  AC_MSG_RESULT([$has_arm32_asm])
+  CFLAGS="$SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS"
 ])
 
 AC_DEFUN([SECP_VALGRIND_CHECK],[
diff --git a/cmake/CheckArm32Assembly.cmake b/cmake/CheckArm32Assembly.cmake
new file mode 100644
index 0000000..15c44b2
--- /dev/null
+++ b/cmake/CheckArm32Assembly.cmake
@@ -0,0 +1,6 @@
+function(check_arm32_assembly)
+  try_compile(HAVE_ARM32_ASM
+    ${CMAKE_BINARY_DIR}/check_arm32_assembly
+    SOURCES ${CMAKE_SOURCE_DIR}/cmake/source_arm32.s
+  )
+endfunction()
diff --git a/cmake/Check64bitAssembly.cmake b/cmake/CheckX86_64Assembly.cmake
similarity index 70%
rename from cmake/Check64bitAssembly.cmake
rename to cmake/CheckX86_64Assembly.cmake
index 3f65887..ae82cd4 100644
--- a/cmake/Check64bitAssembly.cmake
+++ b/cmake/CheckX86_64Assembly.cmake
@@ -1,6 +1,6 @@
 include(CheckCSourceCompiles)
 
-function(check_64bit_assembly)
+function(check_x86_64_assembly)
   check_c_source_compiles("
     #include <stdint.h>
 
@@ -9,6 +9,6 @@ function(check_64bit_assembly)
       uint64_t a = 11, tmp;
       __asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\");
     }
-  " HAS_64BIT_ASM)
-  set(HAS_64BIT_ASM ${HAS_64BIT_ASM} PARENT_SCOPE)
+  " HAVE_X86_64_ASM)
+  set(HAVE_X86_64_ASM ${HAVE_X86_64_ASM} PARENT_SCOPE)
 endfunction()
diff --git a/cmake/source_arm32.s b/cmake/source_arm32.s
new file mode 100644
index 0000000..d3d9347
--- /dev/null
+++ b/cmake/source_arm32.s
@@ -0,0 +1,9 @@
+.syntax unified
+.eabi_attribute 24, 1
+.eabi_attribute 25, 1
+.text
+.global main
+main:
+	ldr	r0, =0x002A
+	mov	r7, #1
+	swi	0   
diff --git a/configure.ac b/configure.ac
index 6bf5b57..3db87be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -197,8 +197,8 @@ AC_ARG_ENABLE(external_default_callbacks,
 #  *  and auto (the default).
 AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
 
-AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
-[assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto])
+AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto],
+[assembly optimizations to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto])
 
 AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto],
 [window size for ecmult precomputation for verification, specified as integer in range [2..24].]
@@ -263,8 +263,8 @@ else
 fi
 
 if test x"$req_asm" = x"auto"; then
-  SECP_64BIT_ASM_CHECK
-  if test x"$has_64bit_asm" = x"yes"; then
+  SECP_X86_64_ASM_CHECK
+  if test x"$has_x86_64_asm" = x"yes"; then
     set_asm=x86_64
   fi
   if test x"$set_asm" = x; then
@@ -274,12 +274,16 @@ else
   set_asm=$req_asm
   case $set_asm in
   x86_64)
-    SECP_64BIT_ASM_CHECK
-    if test x"$has_64bit_asm" != x"yes"; then
+    SECP_X86_64_ASM_CHECK
+    if test x"$has_x86_64_asm" != x"yes"; then
       AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
     fi
     ;;
-  arm)
+  arm32)
+    SECP_ARM32_ASM_CHECK
+    if test x"$has_arm32_asm" != x"yes"; then
+      AC_MSG_ERROR([ARM32 assembly optimization requested but not available])
+    fi
     ;;
   no)
     ;;
@@ -296,7 +300,7 @@ case $set_asm in
 x86_64)
   SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1"
   ;;
-arm)
+arm32)
   enable_external_asm=yes
   ;;
 no)
@@ -413,8 +417,8 @@ if test x"$enable_experimental" = x"yes"; then
   AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
   AC_MSG_NOTICE([******])
 else
-  if test x"$set_asm" = x"arm"; then
-    AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
+  if test x"$set_asm" = x"arm32"; then
+    AC_MSG_ERROR([ARM32 assembly optimization is experimental. Use --enable-experimental to allow.])
   fi
 fi
 
@@ -436,7 +440,7 @@ AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"ye
 AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
 AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
 AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
-AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
+AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"])
 AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
 AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT)
 AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION)
diff --git a/include/secp256k1.h b/include/secp256k1.h
index d5450e2..a7a2be7 100644
--- a/include/secp256k1.h
+++ b/include/secp256k1.h
@@ -49,6 +49,19 @@ extern "C" {
  */
 typedef struct secp256k1_context_struct secp256k1_context;
 
+/** Opaque data structure that holds rewritable "scratch space"
+ *
+ *  The purpose of this structure is to replace dynamic memory allocations,
+ *  because we target architectures where this may not be available. It is
+ *  essentially a resizable (within specified parameters) block of bytes,
+ *  which is initially created either by memory allocation or TODO as a pointer
+ *  into some fixed rewritable space.
+ *
+ *  Unlike the context object, this cannot safely be shared between threads
+ *  without additional synchronization logic.
+ */
+typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
+
 /** Opaque data structure that holds a parsed and valid public key.
  *
  *  The exact representation of data inside is implementation defined and not
@@ -372,6 +385,29 @@ SECP256K1_API void secp256k1_context_set_error_callback(
     const void *data
 ) SECP256K1_ARG_NONNULL(1);
 
+/** Create a secp256k1 scratch space object.
+ *
+ *  Returns: a newly created scratch space.
+ *  Args: ctx:  an existing context object.
+ *  In:   size: amount of memory to be available as scratch space. Some extra
+ *              (<100 bytes) will be allocated for extra accounting.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space *secp256k1_scratch_space_create(
+    const secp256k1_context *ctx,
+    size_t size
+) SECP256K1_ARG_NONNULL(1);
+
+/** Destroy a secp256k1 scratch space.
+ *
+ *  The pointer may not be used afterwards.
+ *  Args:       ctx: a secp256k1 context object.
+ *          scratch: space to destroy
+ */
+SECP256K1_API void secp256k1_scratch_space_destroy(
+    const secp256k1_context *ctx,
+    secp256k1_scratch_space *scratch
+) SECP256K1_ARG_NONNULL(1);
+
 /** Parse a variable-length public key into the pubkey object.
  *
  *  Returns: 1 if the public key was fully valid.
diff --git a/include/secp256k1_schnorrsig.h b/include/secp256k1_schnorrsig.h
index 1ee665f..cd9845c 100644
--- a/include/secp256k1_schnorrsig.h
+++ b/include/secp256k1_schnorrsig.h
@@ -141,12 +141,8 @@ SECP256K1_API int secp256k1_schnorrsig_sign(
  *  variable length messages and accepts a pointer to an extraparams object that
  *  allows customizing signing by passing additional arguments.
  *
- *  Equivalent to secp256k1_schnorrsig_sign32(..., aux_rand32) if msglen is 32
- *  and extraparams is initialized as follows:
- *  ```
- *  secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
- *  extraparams.ndata = (unsigned char*)aux_rand32;
- *  ```
+ *  Creates the same signatures as schnorrsig_sign if msglen is 32 and the
+ *  extraparams.ndata is the same as aux_rand32.
  *
  *  Returns 1 on success, 0 on failure.
  *  Args:   ctx: pointer to a context object (not secp256k1_context_static).
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ad8c1a9..93844ca 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -11,7 +11,7 @@ add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL
 add_library(secp256k1 secp256k1.c $<TARGET_OBJECTS:secp256k1_precomputed>)
 
 add_library(secp256k1_asm INTERFACE)
-if(SECP256K1_ASM STREQUAL "arm")
+if(SECP256K1_ASM STREQUAL "arm32")
   add_library(secp256k1_asm_arm OBJECT EXCLUDE_FROM_ALL)
   target_sources(secp256k1_asm_arm PUBLIC
     asm/field_10x26_arm.s
diff --git a/src/bench_internal.c b/src/bench_internal.c
index f3686dd..c248ab8 100644
--- a/src/bench_internal.c
+++ b/src/bench_internal.c
@@ -65,10 +65,10 @@ static void bench_setup(void* arg) {
 
     secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL);
     secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL);
-    secp256k1_fe_set_b32_limit(&data->fe[0], init[0]);
-    secp256k1_fe_set_b32_limit(&data->fe[1], init[1]);
-    secp256k1_fe_set_b32_limit(&data->fe[2], init[2]);
-    secp256k1_fe_set_b32_limit(&data->fe[3], init[3]);
+    secp256k1_fe_set_b32(&data->fe[0], init[0]);
+    secp256k1_fe_set_b32(&data->fe[1], init[1]);
+    secp256k1_fe_set_b32(&data->fe[2], init[2]);
+    secp256k1_fe_set_b32(&data->fe[3], init[3]);
     CHECK(secp256k1_ge_set_xo_var(&data->ge[0], &data->fe[0], 0));
     CHECK(secp256k1_ge_set_xo_var(&data->ge[1], &data->fe[1], 1));
     secp256k1_gej_set_ge(&data->gej[0], &data->ge[0]);
diff --git a/src/ecdsa_impl.h b/src/ecdsa_impl.h
index 48e3085..90b4b22 100644
--- a/src/ecdsa_impl.h
+++ b/src/ecdsa_impl.h
@@ -239,8 +239,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25
 }
 #else
     secp256k1_scalar_get_b32(c, sigr);
-    /* we can ignore the fe_set_b32_limit return value, because we know the input is in range */
-    (void)secp256k1_fe_set_b32_limit(&xr, c);
+    secp256k1_fe_set_b32(&xr, c);
 
     /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
      *  in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),
diff --git a/src/eckey_impl.h b/src/eckey_impl.h
index b2fe36f..e0506d3 100644
--- a/src/eckey_impl.h
+++ b/src/eckey_impl.h
@@ -17,10 +17,10 @@
 static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
     if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) {
         secp256k1_fe x;
-        return secp256k1_fe_set_b32_limit(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
+        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)) {
         secp256k1_fe x, y;
-        if (!secp256k1_fe_set_b32_limit(&x, pub+1) || !secp256k1_fe_set_b32_limit(&y, pub+33)) {
+        if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
             return 0;
         }
         secp256k1_ge_set_xy(elem, &x, &y);
diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h
index 26b3e23..81e16e3 100644
--- a/src/ecmult_const_impl.h
+++ b/src/ecmult_const_impl.h
@@ -29,7 +29,7 @@ static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *p
 #define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
     int m = 0; \
     /* Extract the sign-bit for a constant time absolute-value. */ \
-    int volatile mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
+    int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
     int abs_n = ((n) + mask) ^ mask; \
     int idx_n = abs_n >> 1; \
     secp256k1_fe neg_y; \
diff --git a/src/ecmult_gen_compute_table_impl.h b/src/ecmult_gen_compute_table_impl.h
index 7d672b9..ff6a299 100644
--- a/src/ecmult_gen_compute_table_impl.h
+++ b/src/ecmult_gen_compute_table_impl.h
@@ -31,7 +31,7 @@ static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, cons
         secp256k1_fe nums_x;
         secp256k1_ge nums_ge;
         int r;
-        r = secp256k1_fe_set_b32_limit(&nums_x, nums_b32);
+        r = secp256k1_fe_set_b32(&nums_x, nums_b32);
         (void)r;
         VERIFY_CHECK(r);
         r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);
diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h
index deb0323..4f5ea9f 100644
--- a/src/ecmult_gen_impl.h
+++ b/src/ecmult_gen_impl.h
@@ -108,7 +108,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
     memset(keydata, 0, sizeof(keydata));
     /* Accept unobservably small non-uniformity. */
     secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
-    overflow = !secp256k1_fe_set_b32_limit(&s, nonce32);
+    overflow = !secp256k1_fe_set_b32(&s, nonce32);
     overflow |= secp256k1_fe_is_zero(&s);
     secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
     /* Randomize the projection to defend against multiplier sidechannels.
diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h
index 72fadf6..a9a6385 100644
--- a/src/ecmult_impl.h
+++ b/src/ecmult_impl.h
@@ -279,6 +279,9 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
          */
         tmp = a[np];
         if (no) {
+#ifdef VERIFY
+            secp256k1_fe_normalize_var(&Z);
+#endif
             secp256k1_gej_rescale(&tmp, &Z);
         }
         secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp);
@@ -680,7 +683,7 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call
     }
     state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps));
     state_space->wnaf_na = (int *) secp256k1_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int));
-    buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, ((size_t)1 << bucket_window) * sizeof(*buckets));
+    buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, (1<<bucket_window) * sizeof(*buckets));
     if (state_space->ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) {
         secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
         return 0;
diff --git a/src/field.h b/src/field.h
index bbc836b..dca75aa 100644
--- a/src/field.h
+++ b/src/field.h
@@ -7,35 +7,18 @@
 #ifndef SECP256K1_FIELD_H
 #define SECP256K1_FIELD_H
 
-#include "util.h"
-
-/* This file defines the generic interface for working with secp256k1_fe
- * objects, which represent field elements (integers modulo 2^256 - 2^32 - 977).
- *
- * The actual definition of the secp256k1_fe type depends on the chosen field
- * implementation; see the field_5x52.h and field_10x26.h files for details.
+/** Field element module.
  *
- * All secp256k1_fe objects have implicit properties that determine what
- * operations are permitted on it. These are purely a function of what
- * secp256k1_fe_ operations are applied on it, generally (implicitly) fixed at
- * compile time, and do not depend on the chosen field implementation. Despite
- * that, what these properties actually entail for the field representation
- * values depends on the chosen field implementation. These properties are:
- * - magnitude: an integer in [0,32]
- * - normalized: 0 or 1; normalized=1 implies magnitude <= 1.
- *
- * In VERIFY mode, they are materialized explicitly as fields in the struct,
- * allowing run-time verification of these properties. In that case, the field
- * implementation also provides a secp256k1_fe_verify routine to verify that
- * these fields match the run-time value and perform internal consistency
- * checks. */
-#ifdef VERIFY
-#  define SECP256K1_FE_VERIFY_FIELDS \
-    int magnitude; \
-    int normalized;
-#else
-#  define SECP256K1_FE_VERIFY_FIELDS
-#endif
+ *  Field elements can be represented in several ways, but code accessing
+ *  it (and implementations) need to take certain properties into account:
+ *  - Each field element can be normalized or not.
+ *  - Each field element has a magnitude, which represents how far away
+ *    its representation is away from normalization. Normalized elements
+ *    always have a magnitude of 0 or 1, but a magnitude of 1 doesn't
+ *    imply normality.
+ */
+
+#include "util.h"
 
 #if defined(SECP256K1_WIDEMUL_INT128)
 #include "field_5x52.h"
@@ -45,292 +28,119 @@
 #error "Please select wide multiplication implementation"
 #endif
 
-#ifdef VERIFY
-/* Magnitude and normalized value for constants. */
-#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) \
-    /* Magnitude is 0 for constant 0; 1 otherwise. */ \
-    , (((d7) | (d6) | (d5) | (d4) | (d3) | (d2) | (d1) | (d0)) != 0) \
-    /* Normalized is 1 unless sum(d_i<<(32*i) for i=0..7) exceeds field modulus. */ \
-    , (!(((d7) & (d6) & (d5) & (d4) & (d3) & (d2)) == 0xfffffffful && ((d1) == 0xfffffffful || ((d1) == 0xfffffffe && (d0 >= 0xfffffc2f)))))
-#else
-#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0)
-#endif
-
-/** This expands to an initializer for a secp256k1_fe valued sum((i*32) * d_i, i=0..7) mod p.
- *
- * It has magnitude 1, unless d_i are all 0, in which case the magnitude is 0.
- * It is normalized, unless sum(2^(i*32) * d_i, i=0..7) >= p.
- *
- * SECP256K1_FE_CONST_INNER is provided by the implementation.
- */
-#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) SECP256K1_FE_VERIFY_CONST((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) }
-
 static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
 static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
     0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
     0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
 );
 
-#ifndef VERIFY
-/* In non-VERIFY mode, we #define the fe operations to be identical to their
- * internal field implementation, to avoid the potential overhead of a
- * function call (even though presumably inlinable). */
-#  define secp256k1_fe_normalize secp256k1_fe_impl_normalize
-#  define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak
-#  define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var
-#  define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero
-#  define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var
-#  define secp256k1_fe_set_int secp256k1_fe_impl_set_int
-#  define secp256k1_fe_clear secp256k1_fe_impl_clear
-#  define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero
-#  define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd
-#  define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var
-#  define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod
-#  define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit
-#  define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32
-#  define secp256k1_fe_negate secp256k1_fe_impl_negate
-#  define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int
-#  define secp256k1_fe_add secp256k1_fe_impl_add
-#  define secp256k1_fe_mul secp256k1_fe_impl_mul
-#  define secp256k1_fe_sqr secp256k1_fe_impl_sqr
-#  define secp256k1_fe_cmov secp256k1_fe_impl_cmov
-#  define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage
-#  define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage
-#  define secp256k1_fe_inv secp256k1_fe_impl_inv
-#  define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var
-#  define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds
-#  define secp256k1_fe_half secp256k1_fe_impl_half
-#  define secp256k1_fe_add_int secp256k1_fe_impl_add_int
-#  define secp256k1_fe_is_square_var secp256k1_fe_impl_is_square_var
-#endif /* !defined(VERIFY) */
-
-/** Normalize a field element.
- *
- * On input, r must be a valid field element.
- * On output, r represents the same value but has normalized=1 and magnitude=1.
+/** Normalize a field element. This brings the field element to a canonical representation, reduces
+ *  its magnitude to 1, and reduces it modulo field size `p`.
  */
 static void secp256k1_fe_normalize(secp256k1_fe *r);
 
-/** Give a field element magnitude 1.
- *
- * On input, r must be a valid field element.
- * On output, r represents the same value but has magnitude=1. Normalized is unchanged.
- */
+/** Weakly normalize a field element: reduce its magnitude to 1, but don't fully normalize. */
 static void secp256k1_fe_normalize_weak(secp256k1_fe *r);
 
-/** Normalize a field element, without constant-time guarantee.
- *
- * Identical in behavior to secp256k1_fe_normalize, but not constant time in r.
- */
+/** Normalize a field element, without constant-time guarantee. */
 static void secp256k1_fe_normalize_var(secp256k1_fe *r);
 
-/** Determine whether r represents field element 0.
- *
- * On input, r must be a valid field element.
- * Returns whether r = 0 (mod p).
- */
+/** Verify whether a field element represents zero i.e. would normalize to a zero value. */
 static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r);
 
-/** Determine whether r represents field element 0, without constant-time guarantee.
- *
- * Identical in behavior to secp256k1_normalizes_to_zero, but not constant time in r.
- */
+/** Verify whether a field element represents zero i.e. would normalize to a zero value,
+ *  without constant-time guarantee. */
 static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r);
 
-/** Set a field element to an integer in range [0,0x7FFF].
- *
- * On input, r does not need to be initialized, a must be in [0,0x7FFF].
- * On output, r represents value a, is normalized and has magnitude (a!=0).
+/** Set a field element equal to a small (not greater than 0x7FFF), non-negative integer.
+ *  Resulting field element is normalized; it has magnitude 0 if a == 0, and magnitude 1 otherwise.
  */
 static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
 
-/** Set a field element to 0.
- *
- * On input, a does not need to be initialized.
- * On output, a represents 0, is normalized and has magnitude 0.
- */
+/** Sets a field element equal to zero, initializing all fields. */
 static void secp256k1_fe_clear(secp256k1_fe *a);
 
-/** Determine whether a represents field element 0.
- *
- * On input, a must be a valid normalized field element.
- * Returns whether a = 0 (mod p).
- *
- * This behaves identical to secp256k1_normalizes_to_zero{,_var}, but requires
- * normalized input (and is much faster).
- */
+/** Verify whether a field element is zero. Requires the input to be normalized. */
 static int secp256k1_fe_is_zero(const secp256k1_fe *a);
 
-/** Determine whether a (mod p) is odd.
- *
- * On input, a must be a valid normalized field element.
- * Returns (int(a) mod p) & 1.
- */
+/** Check the "oddness" of a field element. Requires the input to be normalized. */
 static int secp256k1_fe_is_odd(const secp256k1_fe *a);
 
-/** Determine whether two field elements are equal.
- *
- * On input, a and b must be valid field elements with magnitudes not exceeding
- * 1 and 31, respectively.
- * Returns a = b (mod p).
- */
+/** Compare two field elements. Requires magnitude-1 inputs. */
 static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
 
-/** Determine whether two field elements are equal, without constant-time guarantee.
- *
- * Identical in behavior to secp256k1_fe_equal, but not constant time in either a or b.
- */
+/** Same as secp256k1_fe_equal, but may be variable time. */
 static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
 
-/** Compare the values represented by 2 field elements, without constant-time guarantee.
- *
- * On input, a and b must be valid normalized field elements.
- * Returns 1 if a > b, -1 if a < b, and 0 if a = b (comparisons are done as integers
- * in range 0..p-1).
- */
+/** Compare two field elements. Requires both inputs to be normalized */
 static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
 
-/** Set a field element equal to a provided 32-byte big endian value, reducing it.
- *
- * On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
- * On output, r = a (mod p). It will have magnitude 1, and not be normalized.
- */
-static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
-
-/** Set a field element equal to a provided 32-byte big endian value, checking for overflow.
- *
- * On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
- * On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned.
- * If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting).
- */
-static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
+/** Set a field element equal to 32-byte big endian value.
+ *  Returns 1 if no overflow occurred, and then the output is normalized.
+ *  Returns 0 if overflow occurred, and then the output is only weakly normalized. */
+static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a);
 
-/** Convert a field element to 32-byte big endian byte array.
- * On input, a must be a valid normalized field element, and r a pointer to a 32-byte array.
- * On output, r = a (mod p).
- */
+/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
 static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);
 
-/** Negate a field element.
- *
- * On input, r does not need to be initialized. a must be a valid field element with
- * magnitude not exceeding m. m must be an integer in [0,31].
- * Performs {r = -a}.
- * On output, r will not be normalized, and will have magnitude m+1.
- */
+/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input
+ *  as an argument. The magnitude of the output is one higher. */
 static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
 
-/** Add a small integer to a field element.
- *
- * Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared.
- * a must be in range [0,0xFFFF].
- */
+/** Adds a small integer (up to 0x7FFF) to r. The resulting magnitude increases by one. */
 static void secp256k1_fe_add_int(secp256k1_fe *r, int a);
 
-/** Multiply a field element with a small integer.
- *
- * On input, r must be a valid field element. a must be an integer in [0,32].
- * The magnitude of r times a must not exceed 32.
- * Performs {r *= a}.
- * On output, r's magnitude is multiplied by a, and r will not be normalized.
- */
+/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
+ *  small integer. */
 static void secp256k1_fe_mul_int(secp256k1_fe *r, int a);
 
-/** Increment a field element by another.
- *
- * On input, r and a must be valid field elements, not necessarily normalized.
- * The sum of their magnitudes must not exceed 32.
- * Performs {r += a}.
- * On output, r will not be normalized, and will have magnitude incremented by a's.
- */
+/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */
 static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a);
 
-/** Multiply two field elements.
- *
- * On input, a and b must be valid field elements; r does not need to be initialized.
- * r and a may point to the same object, but neither can be equal to b. The magnitudes
- * of a and b must not exceed 8.
- * Performs {r = a * b}
- * On output, r will have magnitude 1, but won't be normalized.
- */
+/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8.
+ *  The output magnitude is 1 (but not guaranteed to be normalized). */
 static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
 
-/** Square a field element.
- *
- * On input, a must be a valid field element; r does not need to be initialized. The magnitude
- * of a must not exceed 8.
- * Performs {r = a**2}
- * On output, r will have magnitude 1, but won't be normalized.
- */
+/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8.
+ *  The output magnitude is 1 (but not guaranteed to be normalized). */
 static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
 
-/** Compute a square root of a field element.
- *
- * On input, a must be a valid field element with magnitude<=8; r need not be initialized.
- * Performs {r = sqrt(a)} or {r = sqrt(-a)}, whichever exists. The resulting value
- * represented by r will be a square itself. Variables r and a must not point to the same object.
- * On output, r will have magnitude 1 but will not be normalized.
- */
-static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a);
+/** If a has a square root, it is computed in r and 1 is returned. If a does not
+ *  have a square root, the root of its negation is computed and 0 is returned.
+ *  The input's magnitude can be at most 8. The output magnitude is 1 (but not
+ *  guaranteed to be normalized). The result in r will always be a square
+ *  itself. */
+static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a);
 
-/** Compute the modular inverse of a field element.
- *
- * On input, a must be a valid field element; r need not be initialized.
- * Performs {r = a**(p-2)} (which maps 0 to 0, and every other element to its
- * inverse).
- * On output, r will have magnitude (a.magnitude != 0) and be normalized.
- */
+/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
+ *  at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
 static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a);
 
-/** Compute the modular inverse of a field element, without constant-time guarantee.
- *
- * Behaves identically to secp256k1_fe_inv, but is not constant-time in a.
- */
+/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
 static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a);
 
-/** Convert a field element to secp256k1_fe_storage.
- *
- * On input, a must be a valid normalized field element.
- * Performs {r = a}.
- */
+/** Convert a field element to the storage type. */
 static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
 
-/** Convert a field element back from secp256k1_fe_storage.
- *
- * On input, r need not be initialized.
- * Performs {r = a}.
- * On output, r will be normalized and will have magnitude 1.
- */
+/** Convert a field element back from the storage type. */
 static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
 
 /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time.  Both *r and *a must be initialized.*/
 static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
 
-/** Conditionally move a field element in constant time.
- *
- * On input, both r and a must be valid field elements. Flag must be 0 or 1.
- * Performs {r = flag ? a : r}.
- * On output, r's magnitude and normalized will equal a's in case of flag=1, unchanged otherwise.
- */
+/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time.  Both *r and *a must be initialized.*/
 static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
 
-/** Halve the value of a field element modulo the field prime in constant-time.
- *
- * On input, r must be a valid field element.
- * On output, r will be normalized and have magnitude floor(m/2) + 1 where m is
- * the magnitude of r on input.
- */
+/** Halves the value of a field element modulo the field prime. Constant-time.
+ *  For an input magnitude 'm', the output magnitude is set to 'floor(m/2) + 1'.
+ *  The output is not guaranteed to be normalized, regardless of the input. */
 static void secp256k1_fe_half(secp256k1_fe *r);
 
-/** Sets r to a field element with magnitude m, normalized if (and only if) m==0.
- *  The value is chosen so that it is likely to trigger edge cases related to
- *  internal overflows. */
+/** Sets each limb of 'r' to its upper bound at magnitude 'm'. The output will also have its
+ *  magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */
 static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
 
-/** Determine whether a is a square (modulo p).
- *
- * On input, a must be a valid field element.
- */
+/** Determine whether a is a square (modulo p). */
 static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
 
 /** Check invariants on a field element (no-op unless VERIFY is enabled). */
diff --git a/src/field_10x26.h b/src/field_10x26.h
index 203c101..9eb6560 100644
--- a/src/field_10x26.h
+++ b/src/field_10x26.h
@@ -9,28 +9,15 @@
 
 #include <stdint.h>
 
-/** This field implementation represents the value as 10 uint32_t limbs in base
- *  2^26. */
 typedef struct {
-   /* A field element f represents the sum(i=0..9, f.n[i] << (i*26)) mod p,
-    * where p is the field modulus, 2^256 - 2^32 - 977.
-    *
-    * The individual limbs f.n[i] can exceed 2^26; the field's magnitude roughly
-    * corresponds to how much excess is allowed. The value
-    * sum(i=0..9, f.n[i] << (i*26)) may exceed p, unless the field element is
-    * normalized. */
-    uint32_t n[10];
-    /*
-     * Magnitude m requires:
-     *     n[i] <= 2 * m * (2^26 - 1) for i=0..8
-     *     n[9] <= 2 * m * (2^22 - 1)
-     *
-     * Normalized requires:
-     *     n[i] <= (2^26 - 1) for i=0..8
-     *     sum(i=0..9, n[i] << (i*26)) < p
-     *     (together these imply n[9] <= 2^22 - 1)
+    /* X = sum(i=0..9, n[i]*2^(i*26)) mod p
+     * where p = 2^256 - 0x1000003D1
      */
-    SECP256K1_FE_VERIFY_FIELDS
+    uint32_t n[10];
+#ifdef VERIFY
+    int magnitude;
+    int normalized;
+#endif
 } secp256k1_fe;
 
 /* Unpacks a constant into a overlapping multi-limbed FE element. */
@@ -47,6 +34,12 @@ typedef struct {
     (((uint32_t)d7) >> 10) \
 }
 
+#ifdef VERIFY
+#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
+#else
+#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
+#endif
+
 typedef struct {
     uint32_t n[8];
 } secp256k1_fe_storage;
diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h
index c1b32b8..c164711 100644
--- a/src/field_10x26_impl.h
+++ b/src/field_10x26_impl.h
@@ -12,32 +12,48 @@
 #include "field.h"
 #include "modinv32_impl.h"
 
+/** See the comment at the top of field_5x52_impl.h for more details.
+ *
+ *  Here, we represent field elements as 10 uint32_t's in base 2^26, least significant first,
+ *  where limbs can contain >26 bits.
+ *  A magnitude M means:
+ *  - 2*M*(2^22-1) is the max (inclusive) of the most significant limb
+ *  - 2*M*(2^26-1) is the max (inclusive) of the remaining limbs
+ */
+
+static void secp256k1_fe_verify(const secp256k1_fe *a) {
 #ifdef VERIFY
-static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
     const uint32_t *d = a->n;
-    int m = a->normalized ? 1 : 2 * a->magnitude;
-    VERIFY_CHECK(d[0] <= 0x3FFFFFFUL * m);
-    VERIFY_CHECK(d[1] <= 0x3FFFFFFUL * m);
-    VERIFY_CHECK(d[2] <= 0x3FFFFFFUL * m);
-    VERIFY_CHECK(d[3] <= 0x3FFFFFFUL * m);
-    VERIFY_CHECK(d[4] <= 0x3FFFFFFUL * m);
-    VERIFY_CHECK(d[5] <= 0x3FFFFFFUL * m);
-    VERIFY_CHECK(d[6] <= 0x3FFFFFFUL * m);
-    VERIFY_CHECK(d[7] <= 0x3FFFFFFUL * m);
-    VERIFY_CHECK(d[8] <= 0x3FFFFFFUL * m);
-    VERIFY_CHECK(d[9] <= 0x03FFFFFUL * m);
+    int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
+    r &= (d[0] <= 0x3FFFFFFUL * m);
+    r &= (d[1] <= 0x3FFFFFFUL * m);
+    r &= (d[2] <= 0x3FFFFFFUL * m);
+    r &= (d[3] <= 0x3FFFFFFUL * m);
+    r &= (d[4] <= 0x3FFFFFFUL * m);
+    r &= (d[5] <= 0x3FFFFFFUL * m);
+    r &= (d[6] <= 0x3FFFFFFUL * m);
+    r &= (d[7] <= 0x3FFFFFFUL * m);
+    r &= (d[8] <= 0x3FFFFFFUL * m);
+    r &= (d[9] <= 0x03FFFFFUL * m);
+    r &= (a->magnitude >= 0);
+    r &= (a->magnitude <= 32);
     if (a->normalized) {
-        if (d[9] == 0x03FFFFFUL) {
+        r &= (a->magnitude <= 1);
+        if (r && (d[9] == 0x03FFFFFUL)) {
             uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2];
             if (mid == 0x3FFFFFFUL) {
-                VERIFY_CHECK((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL);
+                r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL);
             }
         }
     }
-}
+    VERIFY_CHECK(r == 1);
 #endif
+    (void)a;
+}
 
-static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) {
+static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
+    VERIFY_CHECK(m >= 0);
+    VERIFY_CHECK(m <= 2048);
     r->n[0] = 0x3FFFFFFUL * 2 * m;
     r->n[1] = 0x3FFFFFFUL * 2 * m;
     r->n[2] = 0x3FFFFFFUL * 2 * m;
@@ -48,9 +64,14 @@ static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) {
     r->n[7] = 0x3FFFFFFUL * 2 * m;
     r->n[8] = 0x3FFFFFFUL * 2 * m;
     r->n[9] = 0x03FFFFFUL * 2 * m;
+#ifdef VERIFY
+    r->magnitude = m;
+    r->normalized = (m == 0);
+    secp256k1_fe_verify(r);
+#endif
 }
 
-static void secp256k1_fe_impl_normalize(secp256k1_fe *r) {
+static void secp256k1_fe_normalize(secp256k1_fe *r) {
     uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
              t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
 
@@ -97,9 +118,15 @@ static void secp256k1_fe_impl_normalize(secp256k1_fe *r) {
 
     r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
     r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
+
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) {
+static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
     uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
              t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
 
@@ -123,9 +150,14 @@ static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) {
 
     r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
     r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
+
+#ifdef VERIFY
+    r->magnitude = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) {
+static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
     uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
              t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
 
@@ -173,9 +205,15 @@ static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) {
 
     r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
     r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
+
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) {
+static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
     uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
              t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
 
@@ -204,7 +242,7 @@ static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) {
     return (z0 == 0) | (z1 == 0x3FFFFFFUL);
 }
 
-static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) {
+static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
     uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
     uint32_t z0, z1;
     uint32_t x;
@@ -256,29 +294,53 @@ static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) {
     return (z0 == 0) | (z1 == 0x3FFFFFFUL);
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
+    VERIFY_CHECK(0 <= a && a <= 0x7FFF);
     r->n[0] = a;
     r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
+#ifdef VERIFY
+    r->magnitude = (a != 0);
+    r->normalized = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) {
+SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
     const uint32_t *t = a->n;
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+    secp256k1_fe_verify(a);
+#endif
     return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0;
 }
 
-SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
+SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+    secp256k1_fe_verify(a);
+#endif
     return a->n[0] & 1;
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
+SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
     int i;
+#ifdef VERIFY
+    a->magnitude = 0;
+    a->normalized = 1;
+#endif
     for (i=0; i<10; i++) {
         a->n[i] = 0;
     }
 }
 
-static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
+static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
     int i;
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+    VERIFY_CHECK(b->normalized);
+    secp256k1_fe_verify(a);
+    secp256k1_fe_verify(b);
+#endif
     for (i = 9; i >= 0; i--) {
         if (a->n[i] > b->n[i]) {
             return 1;
@@ -290,7 +352,8 @@ static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *
     return 0;
 }
 
-static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
+static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
+    int ret;
     r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24);
     r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22);
     r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20);
@@ -301,15 +364,22 @@ static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *
     r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18);
     r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24);
     r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14);
-}
 
-static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
-    secp256k1_fe_impl_set_b32_mod(r, a);
-    return !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));
+    ret = !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = ret;
+    secp256k1_fe_verify(r);
+#endif
+    return ret;
 }
 
 /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
-static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
+static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+    secp256k1_fe_verify(a);
+#endif
     r[0] = (a->n[9] >> 14) & 0xff;
     r[1] = (a->n[9] >> 6) & 0xff;
     r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3);
@@ -344,15 +414,15 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
     r[31] = a->n[0] & 0xff;
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
-    /* For all legal values of m (0..31), the following properties hold: */
+SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->magnitude <= m);
+    secp256k1_fe_verify(a);
     VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
     VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
     VERIFY_CHECK(0x3FFFFFFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
     VERIFY_CHECK(0x03FFFFFUL * 2 * (m + 1) >= 0x03FFFFFUL * 2 * m);
-
-    /* Due to the properties above, the left hand in the subtractions below is never less than
-     * the right hand. */
+#endif
     r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0];
     r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1];
     r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2];
@@ -363,9 +433,14 @@ SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const sec
     r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7];
     r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8];
     r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9];
+#ifdef VERIFY
+    r->magnitude = m + 1;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
     r->n[0] *= a;
     r->n[1] *= a;
     r->n[2] *= a;
@@ -376,9 +451,15 @@ SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
     r->n[7] *= a;
     r->n[8] *= a;
     r->n[9] *= a;
+#ifdef VERIFY
+    r->magnitude *= a;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) {
+SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
+    secp256k1_fe_verify(a);
     r->n[0] += a->n[0];
     r->n[1] += a->n[1];
     r->n[2] += a->n[2];
@@ -389,10 +470,23 @@ SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp25
     r->n[7] += a->n[7];
     r->n[8] += a->n[8];
     r->n[9] += a->n[9];
+#ifdef VERIFY
+    r->magnitude += a->magnitude;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
+    secp256k1_fe_verify(r);
+    VERIFY_CHECK(a >= 0);
+    VERIFY_CHECK(a <= 0x7FFF);
     r->n[0] += a;
+#ifdef VERIFY
+    r->magnitude += 1;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
 #if defined(USE_EXTERNAL_ASM)
@@ -1014,15 +1108,37 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
 }
 #endif
 
-SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
+static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->magnitude <= 8);
+    VERIFY_CHECK(b->magnitude <= 8);
+    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
+    r->magnitude = 1;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
+static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->magnitude <= 8);
+    secp256k1_fe_verify(a);
+#endif
     secp256k1_fe_sqr_inner(r->n, a->n);
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
+static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
     uint32_t mask0, mask1;
     volatile int vflag = flag;
     SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
@@ -1038,14 +1154,25 @@ SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp2
     r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
     r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);
     r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);
+#ifdef VERIFY
+    if (flag) {
+        r->magnitude = a->magnitude;
+        r->normalized = a->normalized;
+    }
+#endif
 }
 
-static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
+static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
     uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
              t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
     uint32_t one = (uint32_t)1;
     uint32_t mask = -(t0 & one) >> 6;
 
+#ifdef VERIFY
+    secp256k1_fe_verify(r);
+    VERIFY_CHECK(r->magnitude < 32);
+#endif
+
     /* Bounds analysis (over the rationals).
      *
      * Let m = r->magnitude
@@ -1092,8 +1219,10 @@ static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
      *
      * Current bounds: t0..t8 <= C * (m/2 + 1/2)
      *                     t9 <= D * (m/2 + 1/4)
-     *
-     * Therefore the output magnitude (M) has to be set such that:
+     */
+
+#ifdef VERIFY
+    /* Therefore the output magnitude (M) has to be set such that:
      *     t0..t8: C * M >= C * (m/2 + 1/2)
      *         t9: D * M >= D * (m/2 + 1/4)
      *
@@ -1103,6 +1232,10 @@ static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
      * and since we want the smallest such integer value for M:
      *     M == floor(m/2) + 1
      */
+    r->magnitude = (r->magnitude >> 1) + 1;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
 static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
@@ -1121,7 +1254,10 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r,
     r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
 }
 
-static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
+static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+#endif
     r->n[0] = a->n[0] | a->n[1] << 26;
     r->n[1] = a->n[1] >> 6 | a->n[2] << 20;
     r->n[2] = a->n[2] >> 12 | a->n[3] << 14;
@@ -1132,7 +1268,7 @@ static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k
     r->n[7] = a->n[8] >> 16 | a->n[9] << 10;
 }
 
-static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
+static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
     r->n[0] = a->n[0] & 0x3FFFFFFUL;
     r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL);
     r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL);
@@ -1143,6 +1279,11 @@ static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, con
     r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL);
     r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL);
     r->n[9] = a->n[7] >> 10;
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
 static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32_signed30 *a) {
@@ -1173,6 +1314,12 @@ static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32
     r->n[7] = (a6 >>  2           ) & M26;
     r->n[8] = (a6 >> 28 | a7 <<  2) & M26;
     r->n[9] = (a7 >> 24 | a8 <<  6);
+
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
 static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_fe *a) {
@@ -1180,6 +1327,10 @@ static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp2
     const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4],
                    a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9];
 
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+#endif
+
     r->v[0] = (a0       | a1 << 26) & M30;
     r->v[1] = (a1 >>  4 | a2 << 22) & M30;
     r->v[2] = (a2 >>  8 | a3 << 18) & M30;
@@ -1197,27 +1348,37 @@ static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_fe = {
     0x2DDACACFL
 };
 
-static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) {
-    secp256k1_fe tmp = *x;
+static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
+    secp256k1_fe tmp;
     secp256k1_modinv32_signed30 s;
 
+    tmp = *x;
     secp256k1_fe_normalize(&tmp);
     secp256k1_fe_to_signed30(&s, &tmp);
     secp256k1_modinv32(&s, &secp256k1_const_modinfo_fe);
     secp256k1_fe_from_signed30(r, &s);
+
+#ifdef VERIFY
+    VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
+#endif
 }
 
-static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
-    secp256k1_fe tmp = *x;
+static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
+    secp256k1_fe tmp;
     secp256k1_modinv32_signed30 s;
 
+    tmp = *x;
     secp256k1_fe_normalize_var(&tmp);
     secp256k1_fe_to_signed30(&s, &tmp);
     secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_fe);
     secp256k1_fe_from_signed30(r, &s);
+
+#ifdef VERIFY
+    VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
+#endif
 }
 
-static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) {
+static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
     secp256k1_fe tmp;
     secp256k1_modinv32_signed30 s;
     int jac, ret;
@@ -1235,6 +1396,10 @@ static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) {
         secp256k1_fe dummy;
         ret = secp256k1_fe_sqrt(&dummy, &tmp);
     } else {
+#ifdef VERIFY
+        secp256k1_fe dummy;
+        VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
+#endif
         ret = jac >= 0;
     }
     return ret;
diff --git a/src/field_5x52.h b/src/field_5x52.h
index f20c246..50ee3f9 100644
--- a/src/field_5x52.h
+++ b/src/field_5x52.h
@@ -9,28 +9,15 @@
 
 #include <stdint.h>
 
-/** This field implementation represents the value as 5 uint64_t limbs in base
- *  2^52. */
 typedef struct {
-   /* A field element f represents the sum(i=0..4, f.n[i] << (i*52)) mod p,
-    * where p is the field modulus, 2^256 - 2^32 - 977.
-    *
-    * The individual limbs f.n[i] can exceed 2^52; the field's magnitude roughly
-    * corresponds to how much excess is allowed. The value
-    * sum(i=0..4, f.n[i] << (i*52)) may exceed p, unless the field element is
-    * normalized. */
-    uint64_t n[5];
-    /*
-     * Magnitude m requires:
-     *     n[i] <= 2 * m * (2^52 - 1) for i=0..3
-     *     n[4] <= 2 * m * (2^48 - 1)
-     *
-     * Normalized requires:
-     *     n[i] <= (2^52 - 1) for i=0..3
-     *     sum(i=0..4, n[i] << (i*52)) < p
-     *     (together these imply n[4] <= 2^48 - 1)
+    /* X = sum(i=0..4, n[i]*2^(i*52)) mod p
+     * where p = 2^256 - 0x1000003D1
      */
-    SECP256K1_FE_VERIFY_FIELDS
+    uint64_t n[5];
+#ifdef VERIFY
+    int magnitude;
+    int normalized;
+#endif
 } secp256k1_fe;
 
 /* Unpacks a constant into a overlapping multi-limbed FE element. */
@@ -42,6 +29,12 @@ typedef struct {
     ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \
 }
 
+#ifdef VERIFY
+#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
+#else
+#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
+#endif
+
 typedef struct {
     uint64_t n[4];
 } secp256k1_fe_storage;
diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h
index 0a4cc1a..9b9794c 100644
--- a/src/field_5x52_impl.h
+++ b/src/field_5x52_impl.h
@@ -18,33 +18,60 @@
 #include "field_5x52_int128_impl.h"
 #endif
 
+/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
+ *  represented as 5 uint64_t's in base 2^52, least significant first. Note that the limbs are allowed to
+ *  contain >52 bits each.
+ *
+ *  Each field element has a 'magnitude' associated with it. Internally, a magnitude M means:
+ *  - 2*M*(2^48-1) is the max (inclusive) of the most significant limb
+ *  - 2*M*(2^52-1) is the max (inclusive) of the remaining limbs
+ *
+ *  Operations have different rules for propagating magnitude to their outputs. If an operation takes a
+ *  magnitude M as a parameter, that means the magnitude of input field elements can be at most M (inclusive).
+ *
+ *  Each field element also has a 'normalized' flag. A field element is normalized if its magnitude is either
+ *  0 or 1, and its value is already reduced modulo the order of the field.
+ */
+
+static void secp256k1_fe_verify(const secp256k1_fe *a) {
 #ifdef VERIFY
-static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
     const uint64_t *d = a->n;
-    int m = a->normalized ? 1 : 2 * a->magnitude;
+    int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
    /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
-    VERIFY_CHECK(d[0] <= 0xFFFFFFFFFFFFFULL * m);
-    VERIFY_CHECK(d[1] <= 0xFFFFFFFFFFFFFULL * m);
-    VERIFY_CHECK(d[2] <= 0xFFFFFFFFFFFFFULL * m);
-    VERIFY_CHECK(d[3] <= 0xFFFFFFFFFFFFFULL * m);
-    VERIFY_CHECK(d[4] <= 0x0FFFFFFFFFFFFULL * m);
+    r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m);
+    r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m);
+    r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m);
+    r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m);
+    r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m);
+    r &= (a->magnitude >= 0);
+    r &= (a->magnitude <= 2048);
     if (a->normalized) {
-        if ((d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) {
-            VERIFY_CHECK(d[0] < 0xFFFFEFFFFFC2FULL);
+        r &= (a->magnitude <= 1);
+        if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) {
+            r &= (d[0] < 0xFFFFEFFFFFC2FULL);
         }
     }
-}
+    VERIFY_CHECK(r == 1);
 #endif
+    (void)a;
+}
 
-static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) {
+static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
+    VERIFY_CHECK(m >= 0);
+    VERIFY_CHECK(m <= 2048);
     r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m;
     r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m;
     r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m;
     r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m;
     r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m;
+#ifdef VERIFY
+    r->magnitude = m;
+    r->normalized = (m == 0);
+    secp256k1_fe_verify(r);
+#endif
 }
 
-static void secp256k1_fe_impl_normalize(secp256k1_fe *r) {
+static void secp256k1_fe_normalize(secp256k1_fe *r) {
     uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
 
     /* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -79,9 +106,15 @@ static void secp256k1_fe_impl_normalize(secp256k1_fe *r) {
     t4 &= 0x0FFFFFFFFFFFFULL;
 
     r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
+
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) {
+static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
     uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
 
     /* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -98,9 +131,14 @@ static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) {
     VERIFY_CHECK(t4 >> 49 == 0);
 
     r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
+
+#ifdef VERIFY
+    r->magnitude = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) {
+static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
     uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
 
     /* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -136,9 +174,15 @@ static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) {
     }
 
     r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
+
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) {
+static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
     uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
 
     /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
@@ -161,7 +205,7 @@ static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) {
     return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
 }
 
-static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) {
+static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
     uint64_t t0, t1, t2, t3, t4;
     uint64_t z0, z1;
     uint64_t x;
@@ -202,29 +246,53 @@ static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) {
     return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
+    VERIFY_CHECK(0 <= a && a <= 0x7FFF);
     r->n[0] = a;
     r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
+#ifdef VERIFY
+    r->magnitude = (a != 0);
+    r->normalized = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) {
+SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
     const uint64_t *t = a->n;
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+    secp256k1_fe_verify(a);
+#endif
     return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0;
 }
 
-SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
+SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+    secp256k1_fe_verify(a);
+#endif
     return a->n[0] & 1;
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
+SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
     int i;
+#ifdef VERIFY
+    a->magnitude = 0;
+    a->normalized = 1;
+#endif
     for (i=0; i<5; i++) {
         a->n[i] = 0;
     }
 }
 
-static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
+static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
     int i;
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+    VERIFY_CHECK(b->normalized);
+    secp256k1_fe_verify(a);
+    secp256k1_fe_verify(b);
+#endif
     for (i = 4; i >= 0; i--) {
         if (a->n[i] > b->n[i]) {
             return 1;
@@ -236,7 +304,8 @@ static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *
     return 0;
 }
 
-static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
+static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
+    int ret;
     r->n[0] = (uint64_t)a[31]
             | ((uint64_t)a[30] << 8)
             | ((uint64_t)a[29] << 16)
@@ -271,15 +340,21 @@ static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *
             | ((uint64_t)a[2] << 24)
             | ((uint64_t)a[1] << 32)
             | ((uint64_t)a[0] << 40);
-}
-
-static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
-    secp256k1_fe_impl_set_b32_mod(r, a);
-    return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
+    ret = !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = ret;
+    secp256k1_fe_verify(r);
+#endif
+    return ret;
 }
 
 /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
-static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
+static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+    secp256k1_fe_verify(a);
+#endif
     r[0] = (a->n[4] >> 40) & 0xFF;
     r[1] = (a->n[4] >> 32) & 0xFF;
     r[2] = (a->n[4] >> 24) & 0xFF;
@@ -314,50 +389,96 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
     r[31] = a->n[0] & 0xFF;
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
-    /* For all legal values of m (0..31), the following properties hold: */
+SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->magnitude <= m);
+    secp256k1_fe_verify(a);
     VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
     VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
     VERIFY_CHECK(0x0FFFFFFFFFFFFULL * 2 * (m + 1) >= 0x0FFFFFFFFFFFFULL * 2 * m);
-
-    /* Due to the properties above, the left hand in the subtractions below is never less than
-     * the right hand. */
+#endif
     r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0];
     r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1];
     r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2];
     r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3];
     r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4];
+#ifdef VERIFY
+    r->magnitude = m + 1;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
     r->n[0] *= a;
     r->n[1] *= a;
     r->n[2] *= a;
     r->n[3] *= a;
     r->n[4] *= a;
+#ifdef VERIFY
+    r->magnitude *= a;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
+    secp256k1_fe_verify(r);
+    VERIFY_CHECK(a >= 0);
+    VERIFY_CHECK(a <= 0x7FFF);
     r->n[0] += a;
+#ifdef VERIFY
+    r->magnitude += 1;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) {
+SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
+    secp256k1_fe_verify(a);
     r->n[0] += a->n[0];
     r->n[1] += a->n[1];
     r->n[2] += a->n[2];
     r->n[3] += a->n[3];
     r->n[4] += a->n[4];
+#ifdef VERIFY
+    r->magnitude += a->magnitude;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
+static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->magnitude <= 8);
+    VERIFY_CHECK(b->magnitude <= 8);
+    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
+    r->magnitude = 1;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
+static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->magnitude <= 8);
+    secp256k1_fe_verify(a);
+#endif
     secp256k1_fe_sqr_inner(r->n, a->n);
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
-SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
+static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
     uint64_t mask0, mask1;
     volatile int vflag = flag;
     SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
@@ -368,13 +489,24 @@ SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp2
     r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
     r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
     r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
+#ifdef VERIFY
+    if (flag) {
+        r->magnitude = a->magnitude;
+        r->normalized = a->normalized;
+    }
+#endif
 }
 
-static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
+static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
     uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
     uint64_t one = (uint64_t)1;
     uint64_t mask = -(t0 & one) >> 12;
 
+#ifdef VERIFY
+    secp256k1_fe_verify(r);
+    VERIFY_CHECK(r->magnitude < 32);
+#endif
+
     /* Bounds analysis (over the rationals).
      *
      * Let m = r->magnitude
@@ -411,8 +543,10 @@ static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
      *
      * Current bounds: t0..t3 <= C * (m/2 + 1/2)
      *                     t4 <= D * (m/2 + 1/4)
-     *
-     * Therefore the output magnitude (M) has to be set such that:
+     */
+
+#ifdef VERIFY
+    /* Therefore the output magnitude (M) has to be set such that:
      *     t0..t3: C * M >= C * (m/2 + 1/2)
      *         t4: D * M >= D * (m/2 + 1/4)
      *
@@ -422,6 +556,10 @@ static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
      * and since we want the smallest such integer value for M:
      *     M == floor(m/2) + 1
      */
+    r->magnitude = (r->magnitude >> 1) + 1;
+    r->normalized = 0;
+    secp256k1_fe_verify(r);
+#endif
 }
 
 static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
@@ -436,19 +574,27 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r,
     r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
 }
 
-static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
+static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+#endif
     r->n[0] = a->n[0] | a->n[1] << 52;
     r->n[1] = a->n[1] >> 12 | a->n[2] << 40;
     r->n[2] = a->n[2] >> 24 | a->n[3] << 28;
     r->n[3] = a->n[3] >> 36 | a->n[4] << 16;
 }
 
-static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
+static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
     r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL;
     r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL);
     r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL);
     r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL);
     r->n[4] = a->n[3] >> 16;
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
 static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64_signed62 *a) {
@@ -469,12 +615,22 @@ static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64
     r->n[2] = (a1 >> 42 | a2 << 20) & M52;
     r->n[3] = (a2 >> 32 | a3 << 30) & M52;
     r->n[4] = (a3 >> 22 | a4 << 40);
+
+#ifdef VERIFY
+    r->magnitude = 1;
+    r->normalized = 1;
+    secp256k1_fe_verify(r);
+#endif
 }
 
 static void secp256k1_fe_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_fe *a) {
     const uint64_t M62 = UINT64_MAX >> 2;
     const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4];
 
+#ifdef VERIFY
+    VERIFY_CHECK(a->normalized);
+#endif
+
     r->v[0] = (a0       | a1 << 52) & M62;
     r->v[1] = (a1 >> 10 | a2 << 42) & M62;
     r->v[2] = (a2 >> 20 | a3 << 32) & M62;
@@ -487,27 +643,37 @@ static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_fe = {
     0x27C7F6E22DDACACFLL
 };
 
-static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) {
-    secp256k1_fe tmp = *x;
+static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
+    secp256k1_fe tmp;
     secp256k1_modinv64_signed62 s;
 
+    tmp = *x;
     secp256k1_fe_normalize(&tmp);
     secp256k1_fe_to_signed62(&s, &tmp);
     secp256k1_modinv64(&s, &secp256k1_const_modinfo_fe);
     secp256k1_fe_from_signed62(r, &s);
+
+#ifdef VERIFY
+    VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
+#endif
 }
 
-static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
-    secp256k1_fe tmp = *x;
+static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
+    secp256k1_fe tmp;
     secp256k1_modinv64_signed62 s;
 
+    tmp = *x;
     secp256k1_fe_normalize_var(&tmp);
     secp256k1_fe_to_signed62(&s, &tmp);
     secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_fe);
     secp256k1_fe_from_signed62(r, &s);
+
+#ifdef VERIFY
+    VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
+#endif
 }
 
-static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) {
+static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
     secp256k1_fe tmp;
     secp256k1_modinv64_signed62 s;
     int jac, ret;
@@ -525,6 +691,10 @@ static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) {
         secp256k1_fe dummy;
         ret = secp256k1_fe_sqrt(&dummy, &tmp);
     } else {
+#ifdef VERIFY
+        secp256k1_fe dummy;
+        VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
+#endif
         ret = jac >= 0;
     }
     return ret;
diff --git a/src/field_impl.h b/src/field_impl.h
index 7270375..0a03076 100644
--- a/src/field_impl.h
+++ b/src/field_impl.h
@@ -7,7 +7,6 @@
 #ifndef SECP256K1_FIELD_IMPL_H
 #define SECP256K1_FIELD_IMPL_H
 
-#include "field.h"
 #include "util.h"
 
 #if defined(SECP256K1_WIDEMUL_INT128)
@@ -20,12 +19,6 @@
 
 SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
     secp256k1_fe na;
-#ifdef VERIFY
-    secp256k1_fe_verify(a);
-    secp256k1_fe_verify(b);
-    VERIFY_CHECK(a->magnitude <= 1);
-    VERIFY_CHECK(b->magnitude <= 31);
-#endif
     secp256k1_fe_negate(&na, a, 1);
     secp256k1_fe_add(&na, b);
     return secp256k1_fe_normalizes_to_zero(&na);
@@ -33,12 +26,6 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp
 
 SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
     secp256k1_fe na;
-#ifdef VERIFY
-    secp256k1_fe_verify(a);
-    secp256k1_fe_verify(b);
-    VERIFY_CHECK(a->magnitude <= 1);
-    VERIFY_CHECK(b->magnitude <= 31);
-#endif
     secp256k1_fe_negate(&na, a, 1);
     secp256k1_fe_add(&na, b);
     return secp256k1_fe_normalizes_to_zero_var(&na);
@@ -55,13 +42,9 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
      *  itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)).
      */
     secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
-    int j, ret;
+    int j;
 
-#ifdef VERIFY
     VERIFY_CHECK(r != a);
-    secp256k1_fe_verify(a);
-    VERIFY_CHECK(a->magnitude <= 8);
-#endif
 
     /** 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:
@@ -145,288 +128,7 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
     /* Check that a square root was actually calculated */
 
     secp256k1_fe_sqr(&t1, r);
-    ret = secp256k1_fe_equal(&t1, a);
-
-#ifdef VERIFY
-    if (!ret) {
-        secp256k1_fe_negate(&t1, &t1, 1);
-        secp256k1_fe_normalize_var(&t1);
-        VERIFY_CHECK(secp256k1_fe_equal_var(&t1, a));
-    }
-#endif
-    return ret;
-}
-
-#ifndef VERIFY
-static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; }
-#else
-static void secp256k1_fe_impl_verify(const secp256k1_fe *a);
-static void secp256k1_fe_verify(const secp256k1_fe *a) {
-    /* Magnitude between 0 and 32. */
-    VERIFY_CHECK((a->magnitude >= 0) && (a->magnitude <= 32));
-    /* Normalized is 0 or 1. */
-    VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1));
-    /* If normalized, magnitude must be 0 or 1. */
-    if (a->normalized) VERIFY_CHECK(a->magnitude <= 1);
-    /* Invoke implementation-specific checks. */
-    secp256k1_fe_impl_verify(a);
-}
-
-static void secp256k1_fe_impl_normalize(secp256k1_fe *r);
-SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) {
-    secp256k1_fe_verify(r);
-    secp256k1_fe_impl_normalize(r);
-    r->magnitude = 1;
-    r->normalized = 1;
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r);
-SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
-    secp256k1_fe_verify(r);
-    secp256k1_fe_impl_normalize_weak(r);
-    r->magnitude = 1;
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r);
-SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
-    secp256k1_fe_verify(r);
-    secp256k1_fe_impl_normalize_var(r);
-    r->magnitude = 1;
-    r->normalized = 1;
-    secp256k1_fe_verify(r);
-}
-
-static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r);
-SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
-    secp256k1_fe_verify(r);
-    return secp256k1_fe_impl_normalizes_to_zero(r);
-}
-
-static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r);
-SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
-    secp256k1_fe_verify(r);
-    return secp256k1_fe_impl_normalizes_to_zero_var(r);
-}
-
-static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a);
-SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
-    VERIFY_CHECK(0 <= a && a <= 0x7FFF);
-    secp256k1_fe_impl_set_int(r, a);
-    r->magnitude = (a != 0);
-    r->normalized = 1;
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a);
-SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
-    VERIFY_CHECK(0 <= a && a <= 0x7FFF);
-    secp256k1_fe_verify(r);
-    secp256k1_fe_impl_add_int(r, a);
-    r->magnitude += 1;
-    r->normalized = 0;
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_clear(secp256k1_fe *a);
-SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
-    a->magnitude = 0;
-    a->normalized = 1;
-    secp256k1_fe_impl_clear(a);
-    secp256k1_fe_verify(a);
-}
-
-static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a);
-SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
-    secp256k1_fe_verify(a);
-    VERIFY_CHECK(a->normalized);
-    return secp256k1_fe_impl_is_zero(a);
-}
-
-static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a);
-SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
-    secp256k1_fe_verify(a);
-    VERIFY_CHECK(a->normalized);
-    return secp256k1_fe_impl_is_odd(a);
-}
-
-static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
-SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
-    secp256k1_fe_verify(a);
-    secp256k1_fe_verify(b);
-    VERIFY_CHECK(a->normalized);
-    VERIFY_CHECK(b->normalized);
-    return secp256k1_fe_impl_cmp_var(a, b);
-}
-
-static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
-SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
-    secp256k1_fe_impl_set_b32_mod(r, a);
-    r->magnitude = 1;
-    r->normalized = 0;
-    secp256k1_fe_verify(r);
+    return secp256k1_fe_equal(&t1, a);
 }
 
-static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
-SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
-    if (secp256k1_fe_impl_set_b32_limit(r, a)) {
-        r->magnitude = 1;
-        r->normalized = 1;
-        secp256k1_fe_verify(r);
-        return 1;
-    } else {
-        /* Mark the output field element as invalid. */
-        r->magnitude = -1;
-        return 0;
-    }
-}
-
-static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a);
-SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
-    secp256k1_fe_verify(a);
-    VERIFY_CHECK(a->normalized);
-    secp256k1_fe_impl_get_b32(r, a);
-}
-
-static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
-SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
-    secp256k1_fe_verify(a);
-    VERIFY_CHECK(m >= 0 && m <= 31);
-    VERIFY_CHECK(a->magnitude <= m);
-    secp256k1_fe_impl_negate(r, a, m);
-    r->magnitude = m + 1;
-    r->normalized = 0;
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a);
-SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
-    secp256k1_fe_verify(r);
-    VERIFY_CHECK(a >= 0 && a <= 32);
-    VERIFY_CHECK(a*r->magnitude <= 32);
-    secp256k1_fe_impl_mul_int(r, a);
-    r->magnitude *= a;
-    r->normalized = 0;
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a);
-SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
-    secp256k1_fe_verify(r);
-    secp256k1_fe_verify(a);
-    VERIFY_CHECK(r->magnitude + a->magnitude <= 32);
-    secp256k1_fe_impl_add(r, a);
-    r->magnitude += a->magnitude;
-    r->normalized = 0;
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
-SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
-    secp256k1_fe_verify(a);
-    secp256k1_fe_verify(b);
-    VERIFY_CHECK(a->magnitude <= 8);
-    VERIFY_CHECK(b->magnitude <= 8);
-    VERIFY_CHECK(r != b);
-    VERIFY_CHECK(a != b);
-    secp256k1_fe_impl_mul(r, a, b);
-    r->magnitude = 1;
-    r->normalized = 0;
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a);
-SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
-    secp256k1_fe_verify(a);
-    VERIFY_CHECK(a->magnitude <= 8);
-    secp256k1_fe_impl_sqr(r, a);
-    r->magnitude = 1;
-    r->normalized = 0;
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
-SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
-    VERIFY_CHECK(flag == 0 || flag == 1);
-    secp256k1_fe_verify(a);
-    secp256k1_fe_verify(r);
-    secp256k1_fe_impl_cmov(r, a, flag);
-    if (flag) {
-        r->magnitude = a->magnitude;
-        r->normalized = a->normalized;
-    }
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
-SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
-    secp256k1_fe_verify(a);
-    VERIFY_CHECK(a->normalized);
-    secp256k1_fe_impl_to_storage(r, a);
-}
-
-static void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
-SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
-    secp256k1_fe_impl_from_storage(r, a);
-    r->magnitude = 1;
-    r->normalized = 1;
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x);
-SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
-    int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
-    secp256k1_fe_verify(x);
-    secp256k1_fe_impl_inv(r, x);
-    r->magnitude = x->magnitude > 0;
-    r->normalized = 1;
-    VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x);
-SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
-    int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
-    secp256k1_fe_verify(x);
-    secp256k1_fe_impl_inv_var(r, x);
-    r->magnitude = x->magnitude > 0;
-    r->normalized = 1;
-    VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
-    secp256k1_fe_verify(r);
-}
-
-static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x);
-SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
-    int ret;
-    secp256k1_fe tmp = *x, sqrt;
-    secp256k1_fe_verify(x);
-    ret = secp256k1_fe_impl_is_square_var(x);
-    secp256k1_fe_normalize_weak(&tmp);
-    VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp));
-    return ret;
-}
-
-static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m);
-SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) {
-    VERIFY_CHECK(m >= 0);
-    VERIFY_CHECK(m <= 32);
-    secp256k1_fe_impl_get_bounds(r, m);
-    r->magnitude = m;
-    r->normalized = (m == 0);
-    secp256k1_fe_verify(r);
-}
-
-static void secp256k1_fe_impl_half(secp256k1_fe *r);
-SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) {
-    secp256k1_fe_verify(r);
-    VERIFY_CHECK(r->magnitude < 32);
-    secp256k1_fe_impl_half(r);
-    r->magnitude = (r->magnitude >> 1) + 1;
-    r->normalized = 0;
-    secp256k1_fe_verify(r);
-}
-
-#endif /* defined(VERIFY) */
-
 #endif /* SECP256K1_FIELD_IMPL_H */
diff --git a/src/group_impl.h b/src/group_impl.h
index 44d9843..f1b62e3 100644
--- a/src/group_impl.h
+++ b/src/group_impl.h
@@ -748,9 +748,7 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
     secp256k1_fe zz;
     secp256k1_gej_verify(r);
     secp256k1_fe_verify(s);
-#ifdef VERIFY
-    VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s));
-#endif
+    VERIFY_CHECK(!secp256k1_fe_is_zero(s));
     secp256k1_fe_sqr(&zz, s);
     secp256k1_fe_mul(&r->x, &r->x, &zz);                /* r->x *= s^2 */
     secp256k1_fe_mul(&r->y, &r->y, &zz);
diff --git a/src/modinv32_impl.h b/src/modinv32_impl.h
index 0ea2699..8e400b6 100644
--- a/src/modinv32_impl.h
+++ b/src/modinv32_impl.h
@@ -64,7 +64,7 @@ static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int3
     const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
     int32_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4],
             r5 = r->v[5], r6 = r->v[6], r7 = r->v[7], r8 = r->v[8];
-    volatile int32_t cond_add, cond_negate;
+    int32_t cond_add, cond_negate;
 
 #ifdef VERIFY
     /* Verify that all limbs are in range (-2^30,2^30). */
@@ -186,8 +186,7 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
      * being inside [-2^31,2^31) means that casting to signed works correctly.
      */
     uint32_t u = 1, v = 0, q = 0, r = 1;
-    volatile uint32_t c1, c2;
-    uint32_t mask1, mask2, f = f0, g = g0, x, y, z;
+    uint32_t c1, c2, f = f0, g = g0, x, y, z;
     int i;
 
     for (i = 0; i < 30; ++i) {
@@ -196,25 +195,23 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
         VERIFY_CHECK((q * f0 + r * g0) == g << i);
         /* Compute conditional masks for (zeta < 0) and for (g & 1). */
         c1 = zeta >> 31;
-        mask1 = c1;
-        c2 = g & 1;
-        mask2 = -c2;
+        c2 = -(g & 1);
         /* Compute x,y,z, conditionally negated versions of f,u,v. */
-        x = (f ^ mask1) - mask1;
-        y = (u ^ mask1) - mask1;
-        z = (v ^ mask1) - mask1;
+        x = (f ^ c1) - c1;
+        y = (u ^ c1) - c1;
+        z = (v ^ c1) - c1;
         /* Conditionally add x,y,z to g,q,r. */
-        g += x & mask2;
-        q += y & mask2;
-        r += z & mask2;
-        /* In what follows, mask1 is a condition mask for (zeta < 0) and (g & 1). */
-        mask1 &= mask2;
+        g += x & c2;
+        q += y & c2;
+        r += z & c2;
+        /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */
+        c1 &= c2;
         /* Conditionally change zeta into -zeta-2 or zeta-1. */
-        zeta = (zeta ^ mask1) - 1;
+        zeta = (zeta ^ c1) - 1;
         /* Conditionally add g,q,r to f,u,v. */
-        f += g & mask1;
-        u += q & mask1;
-        v += r & mask1;
+        f += g & c1;
+        u += q & c1;
+        v += r & c1;
         /* Shifts */
         g >>= 1;
         u <<= 1;
diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h
index c7cef87..e33727d 100644
--- a/src/modinv64_impl.h
+++ b/src/modinv64_impl.h
@@ -88,7 +88,7 @@ static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *
 static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int64_t sign, const secp256k1_modinv64_modinfo *modinfo) {
     const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
     int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4];
-    volatile int64_t cond_add, cond_negate;
+    int64_t cond_add, cond_negate;
 
 #ifdef VERIFY
     /* Verify that all limbs are in range (-2^62,2^62). */
@@ -175,8 +175,7 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
      * being inside [-2^63,2^63) means that casting to signed works correctly.
      */
     uint64_t u = 8, v = 0, q = 0, r = 8;
-    volatile uint64_t c1, c2;
-    uint64_t mask1, mask2, f = f0, g = g0, x, y, z;
+    uint64_t c1, c2, f = f0, g = g0, x, y, z;
     int i;
 
     for (i = 3; i < 62; ++i) {
@@ -185,25 +184,23 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
         VERIFY_CHECK((q * f0 + r * g0) == g << i);
         /* Compute conditional masks for (zeta < 0) and for (g & 1). */
         c1 = zeta >> 63;
-        mask1 = c1;
-        c2 = g & 1;
-        mask2 = -c2;
+        c2 = -(g & 1);
         /* Compute x,y,z, conditionally negated versions of f,u,v. */
-        x = (f ^ mask1) - mask1;
-        y = (u ^ mask1) - mask1;
-        z = (v ^ mask1) - mask1;
+        x = (f ^ c1) - c1;
+        y = (u ^ c1) - c1;
+        z = (v ^ c1) - c1;
         /* Conditionally add x,y,z to g,q,r. */
-        g += x & mask2;
-        q += y & mask2;
-        r += z & mask2;
+        g += x & c2;
+        q += y & c2;
+        r += z & c2;
         /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */
-        mask1 &= mask2;
+        c1 &= c2;
         /* Conditionally change zeta into -zeta-2 or zeta-1. */
-        zeta = (zeta ^ mask1) - 1;
+        zeta = (zeta ^ c1) - 1;
         /* Conditionally add g,q,r to f,u,v. */
-        f += g & mask1;
-        u += q & mask1;
-        v += r & mask1;
+        f += g & c1;
+        u += q & c1;
+        v += r & c1;
         /* Shifts */
         g >>= 1;
         u <<= 1;
diff --git a/src/modules/extrakeys/main_impl.h b/src/modules/extrakeys/main_impl.h
index 0c7e266..7352004 100644
--- a/src/modules/extrakeys/main_impl.h
+++ b/src/modules/extrakeys/main_impl.h
@@ -28,7 +28,7 @@ int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_p
     memset(pubkey, 0, sizeof(*pubkey));
     ARG_CHECK(input32 != NULL);
 
-    if (!secp256k1_fe_set_b32_limit(&x, input32)) {
+    if (!secp256k1_fe_set_b32(&x, input32)) {
         return 0;
     }
     if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) {
diff --git a/src/modules/recovery/main_impl.h b/src/modules/recovery/main_impl.h
index 76a005e..e7906eb 100644
--- a/src/modules/recovery/main_impl.h
+++ b/src/modules/recovery/main_impl.h
@@ -98,7 +98,7 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_scalar *sigr, const secp2
     }
 
     secp256k1_scalar_get_b32(brx, sigr);
-    r = secp256k1_fe_set_b32_limit(&fx, brx);
+    r = secp256k1_fe_set_b32(&fx, brx);
     (void)r;
     VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */
     if (recid & 2) {
diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h
index 4e7b45a..cd65159 100644
--- a/src/modules/schnorrsig/main_impl.h
+++ b/src/modules/schnorrsig/main_impl.h
@@ -232,7 +232,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha
     ARG_CHECK(msg != NULL || msglen == 0);
     ARG_CHECK(pubkey != NULL);
 
-    if (!secp256k1_fe_set_b32_limit(&rx, &sig64[0])) {
+    if (!secp256k1_fe_set_b32(&rx, &sig64[0])) {
         return 0;
     }
 
diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h
index e50ec3a..8898151 100644
--- a/src/scalar_4x64_impl.h
+++ b/src/scalar_4x64_impl.h
@@ -111,9 +111,8 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
 
 static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
     secp256k1_uint128 t;
-    volatile int vflag = flag;
     VERIFY_CHECK(bit < 256);
-    bit += ((uint32_t) vflag - 1) & 0x100;  /* forcing (bit >> 6) > 3 makes this a noop */
+    bit += ((uint32_t) flag - 1) & 0x100;  /* forcing (bit >> 6) > 3 makes this a noop */
     secp256k1_u128_from_u64(&t, r->d[0]);
     secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
     r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
@@ -190,8 +189,7 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
 static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
     /* If we are flag = 0, mask = 00...00 and this is a no-op;
      * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
-    volatile int vflag = flag;
-    uint64_t mask = -vflag;
+    uint64_t mask = !flag - 1;
     uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1;
     secp256k1_uint128 t;
     secp256k1_u128_from_u64(&t, r->d[0] ^ mask);
diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h
index da9936d..94ae22f 100644
--- a/src/scalar_8x32_impl.h
+++ b/src/scalar_8x32_impl.h
@@ -142,9 +142,8 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
 
 static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
     uint64_t t;
-    volatile int vflag = flag;
     VERIFY_CHECK(bit < 256);
-    bit += ((uint32_t) vflag - 1) & 0x100;  /* forcing (bit >> 5) > 7 makes this a noop */
+    bit += ((uint32_t) flag - 1) & 0x100;  /* forcing (bit >> 5) > 7 makes this a noop */
     t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));
     r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
     t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F));
@@ -243,8 +242,7 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
 static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
     /* If we are flag = 0, mask = 00...00 and this is a no-op;
      * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
-    volatile int vflag = flag;
-    uint32_t mask = -vflag;
+    uint32_t mask = !flag - 1;
     uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0);
     uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
     r->d[0] = t & nonzero; t >>= 32;
diff --git a/src/scratch.h b/src/scratch.h
index 6164330..9dcb758 100644
--- a/src/scratch.h
+++ b/src/scratch.h
@@ -21,8 +21,6 @@ typedef struct secp256k1_scratch_space_struct {
     size_t max_size;
 } secp256k1_scratch;
 
-typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
-
 static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size);
 
 static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch);
diff --git a/src/secp256k1.c b/src/secp256k1.c
index 41b8285..7af333c 100644
--- a/src/secp256k1.c
+++ b/src/secp256k1.c
@@ -219,12 +219,12 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co
     ctx->error_callback.data = data;
 }
 
-static secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) {
+secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) {
     VERIFY_CHECK(ctx != NULL);
     return secp256k1_scratch_create(&ctx->error_callback, max_size);
 }
 
-static void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) {
+void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) {
     VERIFY_CHECK(ctx != NULL);
     secp256k1_scratch_destroy(&ctx->error_callback, scratch);
 }
@@ -247,8 +247,8 @@ static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge,
     } else {
         /* Otherwise, fall back to 32-byte big endian for X and Y. */
         secp256k1_fe x, y;
-        secp256k1_fe_set_b32_mod(&x, pubkey->data);
-        secp256k1_fe_set_b32_mod(&y, pubkey->data + 32);
+        secp256k1_fe_set_b32(&x, pubkey->data);
+        secp256k1_fe_set_b32(&y, pubkey->data + 32);
         secp256k1_ge_set_xy(ge, &x, &y);
     }
     ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));


Test patch:
diff --git a/src/modules/extrakeys/tests_exhaustive_impl.h b/src/modules/extrakeys/tests_exhaustive_impl.h
index d3d817a..5ecc90d 100644
--- a/src/modules/extrakeys/tests_exhaustive_impl.h
+++ b/src/modules/extrakeys/tests_exhaustive_impl.h
@@ -47,7 +47,7 @@ static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp25
         CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0);
 
         /* Compare the xonly_pubkey bytes against the precomputed group. */
-        secp256k1_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]);
+        secp256k1_fe_set_b32(&fe, xonly_pubkey_bytes[i - 1]);
         CHECK(secp256k1_fe_equal_var(&fe, &group[i].x));
 
         /* Check the parity against the precomputed group. */
diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h
index ddcb8a5..062005e 100644
--- a/src/modules/schnorrsig/tests_impl.h
+++ b/src/modules/schnorrsig/tests_impl.h
@@ -215,36 +215,28 @@ static void test_schnorrsig_sha256_tagged(void) {
 
 /* Helper function for schnorrsig_bip_vectors
  * Signs the message and checks that it's the same as expected_sig. */
-static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg, size_t msglen, const unsigned char *expected_sig) {
+static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg32, const unsigned char *expected_sig) {
     unsigned char sig[64];
     secp256k1_keypair keypair;
     secp256k1_xonly_pubkey pk, pk_expected;
 
-    secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
-    extraparams.ndata = (unsigned char*)aux_rand;
-
     CHECK(secp256k1_keypair_create(CTX, &keypair, sk));
-    CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, msglen, &keypair, &extraparams));
+    CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg32, &keypair, aux_rand));
     CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
-    if (msglen == 32) {
-        memset(sig, 0, 64);
-        CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, aux_rand));
-        CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
-    }
 
     CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk_expected, pk_serialized));
     CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair));
     CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0);
-    CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk));
+    CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk));
 }
 
 /* Helper function for schnorrsig_bip_vectors
  * Checks that both verify and verify_batch (TODO) return the same value as expected. */
-static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg, size_t msglen, const unsigned char *sig, int expected) {
+static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig, int expected) {
     secp256k1_xonly_pubkey pk;
 
     CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk, pk_serialized));
-    CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk));
+    CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk));
 }
 
 /* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See
@@ -264,7 +256,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0,
             0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9
         };
-        const unsigned char aux_rand[32] = {
+        unsigned char aux_rand[32] = {
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -286,8 +278,8 @@ static void test_schnorrsig_bip_vectors(void) {
             0xEB, 0xEE, 0xE8, 0xFD, 0xB2, 0x17, 0x2F, 0x47,
             0x7D, 0xF4, 0x90, 0x0D, 0x31, 0x05, 0x36, 0xC0
         };
-        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
+        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
     }
     {
         /* Test vector 1 */
@@ -303,7 +295,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
             0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
         };
-        const unsigned char aux_rand[32] = {
+        unsigned char aux_rand[32] = {
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -325,8 +317,8 @@ static void test_schnorrsig_bip_vectors(void) {
             0x89, 0x7E, 0xFC, 0xB6, 0x39, 0xEA, 0x87, 0x1C,
             0xFA, 0x95, 0xF6, 0xDE, 0x33, 0x9E, 0x4B, 0x0A
         };
-        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
+        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
     }
     {
         /* Test vector 2 */
@@ -342,7 +334,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0x01, 0x39, 0x71, 0x53, 0x09, 0xB0, 0x86, 0xC9,
             0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8
         };
-        const unsigned char aux_rand[32] = {
+        unsigned char aux_rand[32] = {
             0xC8, 0x7A, 0xA5, 0x38, 0x24, 0xB4, 0xD7, 0xAE,
             0x2E, 0xB0, 0x35, 0xA2, 0xB5, 0xBB, 0xBC, 0xCC,
             0x08, 0x0E, 0x76, 0xCD, 0xC6, 0xD1, 0x69, 0x2C,
@@ -364,8 +356,8 @@ static void test_schnorrsig_bip_vectors(void) {
             0x7A, 0xDE, 0xA9, 0x8D, 0x82, 0xF8, 0x48, 0x1E,
             0x0E, 0x1E, 0x03, 0x67, 0x4A, 0x6F, 0x3F, 0xB7
         };
-        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
+        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
     }
     {
         /* Test vector 3 */
@@ -381,7 +373,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0x3A, 0x0D, 0x95, 0xFB, 0xF2, 0x1D, 0x46, 0x8A,
             0x1B, 0x33, 0xF8, 0xC1, 0x60, 0xD8, 0xF5, 0x17
         };
-        const unsigned char aux_rand[32] = {
+        unsigned char aux_rand[32] = {
             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@@ -403,8 +395,8 @@ static void test_schnorrsig_bip_vectors(void) {
             0xF2, 0x5F, 0xD7, 0x88, 0x81, 0xEB, 0xB3, 0x27,
             0x71, 0xFC, 0x59, 0x22, 0xEF, 0xC6, 0x6E, 0xA3
         };
-        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
+        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
     }
     {
         /* Test vector 4 */
@@ -430,7 +422,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0x60, 0xCB, 0x71, 0xC0, 0x4E, 0x80, 0xF5, 0x93,
             0x06, 0x0B, 0x07, 0xD2, 0x83, 0x08, 0xD7, 0xF4
         };
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
     }
     {
         /* Test vector 5 */
@@ -468,7 +460,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0x7A, 0x73, 0xC6, 0x43, 0xE1, 0x66, 0xBE, 0x5E,
             0xBE, 0xAF, 0xA3, 0x4B, 0x1A, 0xC5, 0x53, 0xE2
         };
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
     }
     {
         /* Test vector 7 */
@@ -494,7 +486,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0x62, 0x2A, 0x95, 0x4C, 0xFE, 0x54, 0x57, 0x35,
             0xAA, 0xEA, 0x51, 0x34, 0xFC, 0xCD, 0xB2, 0xBD
         };
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
     }
     {
         /* Test vector 8 */
@@ -520,7 +512,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0xE8, 0xD7, 0xC9, 0x3E, 0x00, 0xC5, 0xED, 0x0C,
             0x18, 0x34, 0xFF, 0x0D, 0x0C, 0x2E, 0x6D, 0xA6
         };
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
     }
     {
         /* Test vector 9 */
@@ -546,7 +538,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0x4F, 0xB7, 0x34, 0x76, 0xF0, 0xD5, 0x94, 0xDC,
             0xB6, 0x5C, 0x64, 0x25, 0xBD, 0x18, 0x60, 0x51
         };
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
     }
     {
         /* Test vector 10 */
@@ -572,7 +564,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0xDB, 0xA8, 0x7F, 0x11, 0xAC, 0x67, 0x54, 0xF9,
             0x37, 0x80, 0xD5, 0xA1, 0x83, 0x7C, 0xF1, 0x97
         };
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
     }
     {
         /* Test vector 11 */
@@ -598,7 +590,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F,
             0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B
         };
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
     }
     {
         /* Test vector 12 */
@@ -624,7 +616,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F,
             0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B
         };
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
     }
     {
         /* Test vector 13 */
@@ -650,7 +642,7 @@ static void test_schnorrsig_bip_vectors(void) {
             0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
             0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41
         };
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
+        test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
     }
     {
         /* Test vector 14 */
@@ -664,147 +656,6 @@ static void test_schnorrsig_bip_vectors(void) {
         /* No need to check the signature of the test vector as parsing the pubkey already fails */
         CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk));
     }
-    {
-        /* Test vector 15 */
-        const unsigned char sk[32] = {
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-        };
-        const unsigned char pk[32] = {
-            0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
-            0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
-            0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
-            0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
-        };
-        const unsigned char aux_rand[32] = {
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        };
-        /* const unsigned char msg[0] = {}; */
-        const unsigned char sig[64] = {
-            0x71, 0x53, 0x5D, 0xB1, 0x65, 0xEC, 0xD9, 0xFB,
-            0xBC, 0x04, 0x6E, 0x5F, 0xFA, 0xEA, 0x61, 0x18,
-            0x6B, 0xB6, 0xAD, 0x43, 0x67, 0x32, 0xFC, 0xCC,
-            0x25, 0x29, 0x1A, 0x55, 0x89, 0x54, 0x64, 0xCF,
-            0x60, 0x69, 0xCE, 0x26, 0xBF, 0x03, 0x46, 0x62,
-            0x28, 0xF1, 0x9A, 0x3A, 0x62, 0xDB, 0x8A, 0x64,
-            0x9F, 0x2D, 0x56, 0x0F, 0xAC, 0x65, 0x28, 0x27,
-            0xD1, 0xAF, 0x05, 0x74, 0xE4, 0x27, 0xAB, 0x63,
-        };
-        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, NULL, 0, sig);
-        test_schnorrsig_bip_vectors_check_verify(pk, NULL, 0, sig, 1);
-    }
-    {
-        /* Test vector 16 */
-        const unsigned char sk[32] = {
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-        };
-        const unsigned char pk[32] = {
-            0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
-            0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
-            0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
-            0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
-        };
-        const unsigned char aux_rand[32] = {
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        };
-        const unsigned char msg[] = { 0x11 };
-        const unsigned char sig[64] = {
-            0x08, 0xA2, 0x0A, 0x0A, 0xFE, 0xF6, 0x41, 0x24,
-            0x64, 0x92, 0x32, 0xE0, 0x69, 0x3C, 0x58, 0x3A,
-            0xB1, 0xB9, 0x93, 0x4A, 0xE6, 0x3B, 0x4C, 0x35,
-            0x11, 0xF3, 0xAE, 0x11, 0x34, 0xC6, 0xA3, 0x03,
-            0xEA, 0x31, 0x73, 0xBF, 0xEA, 0x66, 0x83, 0xBD,
-            0x10, 0x1F, 0xA5, 0xAA, 0x5D, 0xBC, 0x19, 0x96,
-            0xFE, 0x7C, 0xAC, 0xFC, 0x5A, 0x57, 0x7D, 0x33,
-            0xEC, 0x14, 0x56, 0x4C, 0xEC, 0x2B, 0xAC, 0xBF,
-        };
-        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
-    }
-    {
-        /* Test vector 17 */
-        const unsigned char sk[32] = {
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-        };
-        const unsigned char pk[32] = {
-            0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
-            0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
-            0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
-            0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
-        };
-        const unsigned char aux_rand[32] = {
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        };
-        const unsigned char msg[] = {
-            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-            0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
-            0x11,
-        };
-        const unsigned char sig[64] = {
-            0x51, 0x30, 0xF3, 0x9A, 0x40, 0x59, 0xB4, 0x3B,
-            0xC7, 0xCA, 0xC0, 0x9A, 0x19, 0xEC, 0xE5, 0x2B,
-            0x5D, 0x86, 0x99, 0xD1, 0xA7, 0x1E, 0x3C, 0x52,
-            0xDA, 0x9A, 0xFD, 0xB6, 0xB5, 0x0A, 0xC3, 0x70,
-            0xC4, 0xA4, 0x82, 0xB7, 0x7B, 0xF9, 0x60, 0xF8,
-            0x68, 0x15, 0x40, 0xE2, 0x5B, 0x67, 0x71, 0xEC,
-            0xE1, 0xE5, 0xA3, 0x7F, 0xD8, 0x0E, 0x5A, 0x51,
-            0x89, 0x7C, 0x55, 0x66, 0xA9, 0x7E, 0xA5, 0xA5,
-        };
-        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
-    }
-    {
-        /* Test vector 18 */
-        const unsigned char sk[32] = {
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-            0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
-        };
-        const unsigned char pk[32] = {
-            0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
-            0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
-            0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
-            0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
-        };
-        const unsigned char aux_rand[32] = {
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        };
-        const unsigned char sig[64] = {
-            0x40, 0x3B, 0x12, 0xB0, 0xD8, 0x55, 0x5A, 0x34,
-            0x41, 0x75, 0xEA, 0x7E, 0xC7, 0x46, 0x56, 0x63,
-            0x03, 0x32, 0x1E, 0x5D, 0xBF, 0xA8, 0xBE, 0x6F,
-            0x09, 0x16, 0x35, 0x16, 0x3E, 0xCA, 0x79, 0xA8,
-            0x58, 0x5E, 0xD3, 0xE3, 0x17, 0x08, 0x07, 0xE7,
-            0xC0, 0x3B, 0x72, 0x0F, 0xC5, 0x4C, 0x7B, 0x23,
-            0x89, 0x7F, 0xCB, 0xA0, 0xE9, 0xD0, 0xB4, 0xA0,
-            0x68, 0x94, 0xCF, 0xD2, 0x49, 0xF2, 0x23, 0x67,
-        };
-        unsigned char msg[100];
-        memset(msg, 0x99, sizeof(msg));
-        test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
-        test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
-    }
 }
 
 /* Nonce function that returns constant 0 */
diff --git a/src/tests.c b/src/tests.c
index 70cee31..6d46b39 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -10,12 +10,7 @@
 
 #include <time.h>
 
-#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS
-    #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in tests.")
-    #undef USE_EXTERNAL_DEFAULT_CALLBACKS
-#endif
 #include "secp256k1.c"
-
 #include "../include/secp256k1.h"
 #include "../include/secp256k1_preallocated.h"
 #include "testrand_impl.h"
@@ -90,7 +85,7 @@ static void random_field_element_test(secp256k1_fe *fe) {
     do {
         unsigned char b32[32];
         secp256k1_testrand256_test(b32);
-        if (secp256k1_fe_set_b32_limit(fe, b32)) {
+        if (secp256k1_fe_set_b32(fe, b32)) {
             break;
         }
     } while(1);
@@ -2226,7 +2221,7 @@ static void scalar_test(void) {
         for (i = 0; i < 100; ++i) {
             int low;
             int shift = 1 + secp256k1_testrand_int(15);
-            int expected = r.d[0] % (1ULL << shift);
+            int expected = r.d[0] % (1 << shift);
             low = secp256k1_scalar_shr_int(&r, shift);
             CHECK(expected == low);
         }
@@ -2957,7 +2952,7 @@ static void random_fe(secp256k1_fe *x) {
     unsigned char bin[32];
     do {
         secp256k1_testrand256(bin);
-        if (secp256k1_fe_set_b32_limit(x, bin)) {
+        if (secp256k1_fe_set_b32(x, bin)) {
             return;
         }
     } while(1);
@@ -2967,7 +2962,7 @@ static void random_fe_test(secp256k1_fe *x) {
     unsigned char bin[32];
     do {
         secp256k1_testrand256_test(bin);
-        if (secp256k1_fe_set_b32_limit(x, bin)) {
+        if (secp256k1_fe_set_b32(x, bin)) {
             return;
         }
     } while(1);
@@ -3021,7 +3016,7 @@ static void run_field_convert(void) {
     unsigned char b322[32];
     secp256k1_fe_storage fes2;
     /* Check conversions to fe. */
-    CHECK(secp256k1_fe_set_b32_limit(&fe2, b32));
+    CHECK(secp256k1_fe_set_b32(&fe2, b32));
     CHECK(secp256k1_fe_equal_var(&fe, &fe2));
     secp256k1_fe_from_storage(&fe2, &fes);
     CHECK(secp256k1_fe_equal_var(&fe, &fe2));
@@ -3043,8 +3038,7 @@ static void run_field_be32_overflow(void) {
         static const unsigned char zero[32] = { 0x00 };
         unsigned char out[32];
         secp256k1_fe fe;
-        CHECK(secp256k1_fe_set_b32_limit(&fe, zero_overflow) == 0);
-        secp256k1_fe_set_b32_mod(&fe, zero_overflow);
+        CHECK(secp256k1_fe_set_b32(&fe, zero_overflow) == 0);
         CHECK(secp256k1_fe_normalizes_to_zero(&fe) == 1);
         secp256k1_fe_normalize(&fe);
         CHECK(secp256k1_fe_is_zero(&fe) == 1);
@@ -3066,8 +3060,7 @@ static void run_field_be32_overflow(void) {
         };
         unsigned char out[32];
         secp256k1_fe fe;
-        CHECK(secp256k1_fe_set_b32_limit(&fe, one_overflow) == 0);
-        secp256k1_fe_set_b32_mod(&fe, one_overflow);
+        CHECK(secp256k1_fe_set_b32(&fe, one_overflow) == 0);
         secp256k1_fe_normalize(&fe);
         CHECK(secp256k1_fe_cmp_var(&fe, &secp256k1_fe_one) == 0);
         secp256k1_fe_get_b32(out, &fe);
@@ -3089,8 +3082,7 @@ static void run_field_be32_overflow(void) {
         unsigned char out[32];
         secp256k1_fe fe;
         const secp256k1_fe fe_ff = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0x01, 0x000003d0);
-        CHECK(secp256k1_fe_set_b32_limit(&fe, ff_overflow) == 0);
-        secp256k1_fe_set_b32_mod(&fe, ff_overflow);
+        CHECK(secp256k1_fe_set_b32(&fe, ff_overflow) == 0);
         secp256k1_fe_normalize(&fe);
         CHECK(secp256k1_fe_cmp_var(&fe, &fe_ff) == 0);
         secp256k1_fe_get_b32(out, &fe);
@@ -3676,7 +3668,7 @@ static void run_inverse_tests(void)
         b32[31] = i & 0xff;
         b32[30] = (i >> 8) & 0xff;
         secp256k1_scalar_set_b32(&x_scalar, b32, NULL);
-        secp256k1_fe_set_b32_mod(&x_fe, b32);
+        secp256k1_fe_set_b32(&x_fe, b32);
         for (var = 0; var <= 1; ++var) {
             test_inverse_scalar(NULL, &x_scalar, var);
             test_inverse_field(NULL, &x_fe, var);
@@ -3693,7 +3685,7 @@ static void run_inverse_tests(void)
         for (i = 0; i < 64 * COUNT; ++i) {
             (testrand ? secp256k1_testrand256_test : secp256k1_testrand256)(b32);
             secp256k1_scalar_set_b32(&x_scalar, b32, NULL);
-            secp256k1_fe_set_b32_mod(&x_fe, b32);
+            secp256k1_fe_set_b32(&x_fe, b32);
             for (var = 0; var <= 1; ++var) {
                 test_inverse_scalar(NULL, &x_scalar, var);
                 test_inverse_field(NULL, &x_fe, var);
diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c
index d35acdd..ee60fe9 100644
--- a/src/tests_exhaustive.c
+++ b/src/tests_exhaustive.c
@@ -13,12 +13,7 @@
 #define EXHAUSTIVE_TEST_ORDER 13
 #endif
 
-#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS
-    #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in exhaustive_tests.")
-    #undef USE_EXTERNAL_DEFAULT_CALLBACKS
-#endif
 #include "secp256k1.c"
-
 #include "../include/secp256k1.h"
 #include "assumptions.h"
 #include "group.h"
@@ -60,7 +55,7 @@ static void random_fe(secp256k1_fe *x) {
     unsigned char bin[32];
     do {
         secp256k1_testrand256(bin);
-        if (secp256k1_fe_set_b32_limit(x, bin)) {
+        if (secp256k1_fe_set_b32(x, bin)) {
             return;
         }
     } while(1);