From a2e91d2816d52ea7edff556ef3aaf2d90c878e13 Mon Sep 17 00:00:00 2001
From: dhruv <856960+dhruv@users.noreply.github.com>
Date: Thu, 20 Oct 2022 15:23:18 -0700
Subject: [PATCH] Squashed 'src/secp256k1/' changes from 44c2452fd3..e46f81abd6
e46f81abd6 ElligatorSwift
d556a9d9aa Add benchmark for key generation
855c8e667d Add x-only ecmult_const version for x=n/d
223ccb76d1 doc: Describe Jacobi calculation in safegcd_implementation.md
a72e280efe Native jacobi symbol algorithm
694ce8fb2d Merge bitcoin-core/secp256k1#1131: readme: Misc improvements
88b00897e7 readme: Fix line break
78f5296da4 readme: Sell "no runtime dependencies"
ef48f088ad readme: Add IRC channel
9f8a13dc8e Merge bitcoin-core/secp256k1#1128: configure: Remove pkgconfig macros again (reintroduced by mismerge)
cabe085bb4 configure: Remove pkgconfig macros again (reintroduced by mismerge)
3efeb9da21 Merge bitcoin-core/secp256k1#1121: config: Set preprocessor defaults for ECMULT_* config values
6a873cc4a9 Merge bitcoin-core/secp256k1#1122: tests: Randomize the context with probability 15/16 instead of 1/4
17065f48ae tests: Randomize the context with probability 15/16 instead of 1/4
c27ae45144 config: Remove basic-config.h
da6514a04a config: Introduce DEBUG_CONFIG macro for debug output of config
63a3565e97 Merge bitcoin-core/secp256k1#1120: ecmult_gen: Skip RNG when creating blinding if no seed is available
d0cf55e13a config: Set preprocessor defaults for ECMULT_* config values
55f8bc99dc ecmult_gen: Improve comments about projective blinding
7a86955800 ecmult_gen: Simplify code (no observable change)
4cc0b1b669 ecmult_gen: Skip RNG when creating blinding if no seed is available
af65d30cc8 Merge bitcoin-core/secp256k1#1116: build: Fix #include "..." paths to get rid of further -I arguments
40a3473a9d build: Fix #include "..." paths to get rid of further -I arguments
43756da819 Merge bitcoin-core/secp256k1#1115: Fix sepc256k1 -> secp256k1 typo in group.h
069aba8125 Fix sepc256k1 -> secp256k1 typo in group.h
accadc94df Merge bitcoin-core/secp256k1#1114: `_scratch_destroy`: move `VERIFY_CHECK` after invalid scrach space check
cd47033335 Merge bitcoin-core/secp256k1#1084: ci: Add MSVC builds
1827c9bf2b scratch_destroy: move VERIFY_CHECK after invalid scrach space check
49e2acd927 configure: Improve rationale for WERROR_CFLAGS
8dc4b03341 ci: Add a C++ job that compiles the public headers without -fpermissive
51f296a46c ci: Run persistent wineserver to speed up wine
3fb3269c22 ci: Add 32-bit MinGW64 build
9efc2e5221 ci: Add MSVC builds
2be6ba0fed configure: Convince autotools to work with MSVC's archiver lib.exe
bd81f4140a schnorrsig bench: Suppress a stupid warning in MSVC
09f3d71c51 configure: Add a few CFLAGS for MSVC
3b4f3d0d46 build: Reject C++ compilers in the preprocessor
1cc0941414 configure: Don't abort if the compiler does not define __STDC__
cca8cbbac8 configure: Output message when checking for valgrind
1a6be5745f bench: Make benchmarks compile on MSVC
git-subtree-dir: src/secp256k1
git-subtree-split: e46f81abd67e6d2d4d2399814b8c9fc982218aac
---
.cirrus.yml | 80 +++-
Makefile.am | 9 +-
README.md | 8 +-
build-aux/m4/bitcoin_secp.m4 | 2 +
ci/cirrus.sh | 14 +
ci/linux-debian.Dockerfile | 31 +-
configure.ac | 69 ++-
doc/safegcd_implementation.md | 31 +-
include/secp256k1_ellswift.h | 175 ++++++++
src/basic-config.h | 17 -
src/bench.c | 26 ++
src/bench.h | 18 +-
src/bench_internal.c | 12 +
src/ecmult.h | 11 +
src/ecmult_const.h | 19 +
src/ecmult_const_impl.h | 54 +++
src/ecmult_gen.h | 12 +
src/ecmult_gen_impl.h | 17 +-
src/field.h | 3 +
src/field_10x26_impl.h | 28 ++
src/field_5x52_impl.h | 28 ++
src/group.h | 2 +-
src/modinv32.h | 4 +
src/modinv32_impl.h | 174 +++++++-
src/modinv64.h | 4 +
src/modinv64_impl.h | 155 ++++++-
src/modules/ecdh/bench_impl.h | 2 +-
src/modules/ellswift/Makefile.am.include | 4 +
src/modules/ellswift/bench_impl.h | 94 +++++
src/modules/ellswift/main_impl.h | 394 ++++++++++++++++++
src/modules/ellswift/tests_impl.h | 193 +++++++++
src/modules/extrakeys/tests_exhaustive_impl.h | 2 +-
src/modules/recovery/bench_impl.h | 2 +-
src/modules/recovery/tests_exhaustive_impl.h | 2 +-
src/modules/schnorrsig/bench_impl.h | 10 +-
.../schnorrsig/tests_exhaustive_impl.h | 2 +-
src/scratch_impl.h | 2 +-
src/secp256k1.c | 15 +
src/tests.c | 125 +++++-
src/tests_exhaustive.c | 6 +-
src/util.h | 5 +
41 files changed, 1750 insertions(+), 111 deletions(-)
create mode 100644 include/secp256k1_ellswift.h
delete mode 100644 src/basic-config.h
create mode 100644 src/modules/ellswift/Makefile.am.include
create mode 100644 src/modules/ellswift/bench_impl.h
create mode 100644 src/modules/ellswift/main_impl.h
create mode 100644 src/modules/ellswift/tests_impl.h
diff --git a/.cirrus.yml b/.cirrus.yml
index a2e7f36d1f..4e2429779e 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -18,6 +18,7 @@ env:
ECDH: no
RECOVERY: no
SCHNORRSIG: no
+ ELLSWIFT: no
### test options
SECP256K1_TEST_ITERS:
BENCH: yes
@@ -67,11 +68,11 @@ task:
<< : *LINUX_CONTAINER
matrix: &ENV_MATRIX
- env: {WIDEMUL: int64, RECOVERY: yes}
- - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes}
+ - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: {WIDEMUL: int128}
- - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
+ - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes}
- - env: {WIDEMUL: int128, ASM: x86_64}
+ - env: {WIDEMUL: int128, ASM: x86_64 , ELLSWIFT: yes}
- env: { RECOVERY: yes, SCHNORRSIG: yes}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
- env: {CPPFLAGS: -DDETERMINISTIC}
@@ -178,6 +179,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETEST: no
<< : *MERGE_BASE
test_script:
@@ -197,6 +199,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETEST: no
matrix:
- env: {}
@@ -217,6 +220,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETEST: no
<< : *MERGE_BASE
test_script:
@@ -234,6 +238,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETEST: no
<< : *MERGE_BASE
test_script:
@@ -241,17 +246,59 @@ task:
<< : *CAT_LOGS
task:
- name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
<< : *LINUX_CONTAINER
env:
- WRAPPER_CMD: wine64-stable
- SECP256K1_TEST_ITERS: 16
- HOST: x86_64-w64-mingw32
+ WRAPPER_CMD: wine
+ WITH_VALGRIND: no
+ ECDH: yes
+ RECOVERY: yes
+ SCHNORRSIG: yes
+ CTIMETEST: no
+ matrix:
+ - name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
+ env:
+ HOST: x86_64-w64-mingw32
+ - name: "i686 (mingw32-w64): Windows (Debian stable, Wine)"
+ env:
+ HOST: i686-w64-mingw32
+ << : *MERGE_BASE
+ test_script:
+ - ./ci/cirrus.sh
+ << : *CAT_LOGS
+
+task:
+ << : *LINUX_CONTAINER
+ env:
+ WRAPPER_CMD: wine
+ WERROR_CFLAGS: -WX
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
+ EXPERIMENTAL: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
+ ELLSWIFT: yes
CTIMETEST: no
+ # Set non-essential options that affect the CLI messages here.
+ # (They depend on the user's taste, so we don't want to set them automatically in configure.ac.)
+ CFLAGS: -nologo -diagnostics:caret
+ LDFLAGS: -XCClinker -nologo -XCClinker -diagnostics:caret
+ # Use a MinGW-w64 host to tell ./configure we're building for Windows.
+ # This will detect some MinGW-w64 tools but then make will need only
+ # the MSVC tools CC, AR and NM as specified below.
+ matrix:
+ - name: "x86_64 (MSVC): Windows (Debian stable, Wine)"
+ env:
+ HOST: x86_64-w64-mingw32
+ CC: /opt/msvc/bin/x64/cl
+ AR: /opt/msvc/bin/x64/lib
+ NM: /opt/msvc/bin/x64/dumpbin -symbols -headers
+ - name: "i686 (MSVC): Windows (Debian stable, Wine)"
+ env:
+ HOST: i686-w64-mingw32
+ CC: /opt/msvc/bin/x86/cl
+ AR: /opt/msvc/bin/x86/lib
+ NM: /opt/msvc/bin/x86/dumpbin -symbols -headers
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
@@ -264,6 +311,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETEST: no
matrix:
- name: "Valgrind (memcheck)"
@@ -302,22 +350,30 @@ task:
<< : *CAT_LOGS
task:
- name: "C++ -fpermissive"
+ name: "C++ -fpermissive (entire project)"
<< : *LINUX_CONTAINER
env:
- # ./configure correctly errors out when given CC=g++.
- # We hack around this by passing CC=g++ only to make.
- CC: gcc
- MAKEFLAGS: -j4 CC=g++ CFLAGS=-fpermissive\ -g
+ CC: g++
+ CFLAGS: -fpermissive -g
+ CPPFLAGS: -DSECP256K1_CPLUSPLUS_TEST_OVERRIDE
WERROR_CFLAGS:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
+task:
+ name: "C++ (public headers)"
+ << : *LINUX_CONTAINER
+ test_script:
+ - g++ -Werror include/*.h
+ - clang -Werror -x c++-header include/*.h
+ - /opt/msvc/bin/x64/cl.exe -c -WX -TP include/*.h
+
task:
name: "sage prover"
<< : *LINUX_CONTAINER
diff --git a/Makefile.am b/Makefile.am
index 51c5960301..145baee617 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -58,7 +58,6 @@ noinst_HEADERS += src/hash_impl.h
noinst_HEADERS += src/field.h
noinst_HEADERS += src/field_impl.h
noinst_HEADERS += src/bench.h
-noinst_HEADERS += src/basic-config.h
noinst_HEADERS += contrib/lax_der_parsing.h
noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
@@ -87,7 +86,7 @@ endif
endif
libsecp256k1_la_SOURCES = src/secp256k1.c
-libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
+libsecp256k1_la_CPPFLAGS = $(SECP_INCLUDES)
libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE)
@@ -112,7 +111,7 @@ TESTS =
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
-tests_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
+tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
if VALGRIND_ENABLED
tests_CPPFLAGS += -DVALGRIND
noinst_PROGRAMS += valgrind_ctime_test
@@ -228,3 +227,7 @@ endif
if ENABLE_MODULE_SCHNORRSIG
include src/modules/schnorrsig/Makefile.am.include
endif
+
+if ENABLE_MODULE_ELLSWIFT
+include src/modules/ellswift/Makefile.am.include
+endif
diff --git a/README.md b/README.md
index f5db915e83..ffdc9aeaee 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,8 @@ libsecp256k1
============
[![Build Status](https://api.cirrus-ci.com/github/bitcoin-core/secp256k1.svg?branch=master)](https://cirrus-ci.com/github/bitcoin-core/secp256k1)
+![Dependencies: None](https://img.shields.io/badge/dependencies-none-success)
+[![irc.libera.chat #secp256k1](https://img.shields.io/badge/irc.libera.chat-%23secp256k1-success)](https://web.libera.chat/#secp256k1)
Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.
@@ -15,6 +17,7 @@ Features:
* Derandomized ECDSA (via RFC6979 or with a caller provided function.)
* Very efficient implementation.
* Suitable for embedded systems.
+* No runtime dependencies.
* Optional module for public key recovery.
* Optional module for ECDH key exchange.
* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
@@ -72,11 +75,12 @@ To compile optional modules (such as Schnorr signatures), you need to run `./con
Usage examples
-----------
- Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
+Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
* [ECDSA example](examples/ecdsa.c)
* [Schnorr signatures example](examples/schnorr.c)
* [Deriving a shared secret (ECDH) example](examples/ecdh.c)
- To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
+
+To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
Test coverage
-----------
diff --git a/build-aux/m4/bitcoin_secp.m4 b/build-aux/m4/bitcoin_secp.m4
index 9cb54de098..98be915b67 100644
--- a/build-aux/m4/bitcoin_secp.m4
+++ b/build-aux/m4/bitcoin_secp.m4
@@ -10,6 +10,7 @@ AC_MSG_RESULT([$has_64bit_asm])
])
AC_DEFUN([SECP_VALGRIND_CHECK],[
+AC_MSG_CHECKING([for valgrind support])
if test x"$has_valgrind" != x"yes"; then
CPPFLAGS_TEMP="$CPPFLAGS"
CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS"
@@ -21,6 +22,7 @@ if test x"$has_valgrind" != x"yes"; then
#endif
]])], [has_valgrind=yes; AC_DEFINE(HAVE_VALGRIND,1,[Define this symbol if valgrind is installed, and it supports the host platform])])
fi
+AC_MSG_RESULT($has_valgrind)
])
dnl SECP_TRY_APPEND_CFLAGS(flags, VAR)
diff --git a/ci/cirrus.sh b/ci/cirrus.sh
index b85f012d3f..8779b6fa52 100755
--- a/ci/cirrus.sh
+++ b/ci/cirrus.sh
@@ -5,10 +5,20 @@ set -x
export LC_ALL=C
+# Start persistent wineserver if necessary.
+# This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously.
+case "$WRAPPER_CMD" in
+ *wine*)
+ # This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards.
+ wineserver -p && wine hh.exe
+ ;;
+esac
+
env >> test_env.log
$CC -v || true
valgrind --version || true
+$WRAPPER_CMD --version || true
./autogen.sh
@@ -18,6 +28,7 @@ valgrind --version || true
--with-ecmult-window="$ECMULTWINDOW" \
--with-ecmult-gen-precision="$ECMULTGENPRECISION" \
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
+ --enable-module-ellswift="$ELLSWIFT" \
--enable-module-schnorrsig="$SCHNORRSIG" \
--enable-examples="$EXAMPLES" \
--with-valgrind="$WITH_VALGRIND" \
@@ -63,6 +74,9 @@ then
make precomp
fi
+# Shutdown wineserver again
+wineserver -k || true
+
# Check that no repo files have been modified by the build.
# (This fails for example if the precomp files need to be updated in the repo.)
git diff --exit-code
diff --git a/ci/linux-debian.Dockerfile b/ci/linux-debian.Dockerfile
index 5cccbb5565..a83a4e36db 100644
--- a/ci/linux-debian.Dockerfile
+++ b/ci/linux-debian.Dockerfile
@@ -1,15 +1,14 @@
FROM debian:stable
-RUN dpkg --add-architecture i386
-RUN dpkg --add-architecture s390x
-RUN dpkg --add-architecture armhf
-RUN dpkg --add-architecture arm64
-RUN dpkg --add-architecture ppc64el
-RUN apt-get update
+RUN dpkg --add-architecture i386 && \
+ dpkg --add-architecture s390x && \
+ dpkg --add-architecture armhf && \
+ dpkg --add-architecture arm64 && \
+ dpkg --add-architecture ppc64el
# dkpg-dev: to make pkg-config work in cross-builds
# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces
-RUN apt-get install --no-install-recommends --no-upgrade -y \
+RUN apt-get update && apt-get install --no-install-recommends -y \
git ca-certificates \
make automake libtool pkg-config dpkg-dev valgrind qemu-user \
gcc clang llvm libc6-dbg \
@@ -19,8 +18,20 @@ RUN apt-get install --no-install-recommends --no-upgrade -y \
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
- wine gcc-mingw-w64-x86-64 \
+ gcc-mingw-w64-x86-64-win32 wine64 wine \
+ gcc-mingw-w64-i686-win32 wine32 \
sagemath
-# Run a dummy command in wine to make it set up configuration
-RUN wine64-stable xcopy || true
+WORKDIR /root
+# The "wine" package provides a convience wrapper that we need
+RUN apt-get update && apt-get install --no-install-recommends -y \
+ git ca-certificates wine64 wine python3-simplejson python3-six msitools winbind procps && \
+ git clone https://github.com/mstorsjo/msvc-wine && \
+ mkdir /opt/msvc && \
+ python3 msvc-wine/vsdownload.py --accept-license --dest /opt/msvc Microsoft.VisualStudio.Workload.VCTools && \
+ msvc-wine/install.sh /opt/msvc
+
+# Initialize the wine environment. Wait until the wineserver process has
+# exited before closing the session, to avoid corrupting the wine prefix.
+RUN wine64 wineboot --init && \
+ while (ps -A | grep wineserver) > /dev/null; do sleep 1; done
diff --git a/configure.ac b/configure.ac
index 2db59a8ff3..cf4019e06f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,12 +33,14 @@ AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_PROG_CC
-if test x"$ac_cv_prog_cc_c89" = x"no"; then
- AC_MSG_ERROR([c89 compiler support required])
-fi
AM_PROG_AS
AM_PROG_AR
+# Clear some cache variables as a workaround for a bug that appears due to a bad
+# interaction between AM_PROG_AR and LT_INIT when combining MSVC's archiver lib.exe.
+# https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54421
+AS_UNSET(ac_cv_prog_AR)
+AS_UNSET(ac_cv_prog_ac_ct_AR)
LT_INIT([win32-dll])
build_windows=no
@@ -87,23 +89,35 @@ esac
#
# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues.
AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
- # Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
- # not error out if it gets unknown warning flags and the checks here will always succeed
- # no matter if clang knows the flag or not.
- SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
- SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
-
- SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
- SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
- SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
- SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
- SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
- SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
- SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
- SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
- SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
-
- CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
+ # GCC and compatible (incl. clang)
+ if test "x$GCC" = "xyes"; then
+ # Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
+ # not error out if it gets unknown warning flags and the checks here will always succeed
+ # no matter if clang knows the flag or not.
+ SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
+ SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
+
+ SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
+ SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
+ SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
+ SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
+ SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
+ SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
+ SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
+ SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
+ SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
+
+ CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
+ fi
+
+ # MSVC
+ # Assume MSVC if we're building for Windows but not with GCC or compatible;
+ # libtool makes the same assumption internally.
+ # Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path.
+ if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then
+ SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned"
+ SECP_TRY_APPEND_CFLAGS([-external:anglebrackets -external:W0], $1) # Suppress warnings from #include <...> files
+ fi
])
SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
@@ -156,6 +170,11 @@ AC_ARG_ENABLE(module_schnorrsig,
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig], [no], [yes])])
+AC_ARG_ENABLE(module_ellswift,
+ AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module (experimental)]),
+ [enable_module_ellswift=$enableval],
+ [enable_module_ellswift=no])
+
AC_ARG_ENABLE(external_default_callbacks,
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
@@ -326,7 +345,9 @@ if test x"$enable_valgrind" = x"yes"; then
SECP_INCLUDES="$SECP_INCLUDES $VALGRIND_CPPFLAGS"
fi
-# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI)
+# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI).
+# We don't want to set the user variable CFLAGS in CI because this would disable
+# autoconf's logic for setting default CFLAGS, which we would like to test in CI.
SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
###
@@ -346,6 +367,10 @@ if test x"$enable_module_schnorrsig" = x"yes"; then
enable_module_extrakeys=yes
fi
+if test x"$enable_module_ellswift" = x"yes"; then
+ AC_DEFINE(ENABLE_MODULE_ELLSWIFT, 1, [Define this symbol to enable the ElligatorSwift module])
+fi
+
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
# module to set enable_module_extrakeys=yes
if test x"$enable_module_extrakeys" = x"yes"; then
@@ -391,6 +416,7 @@ AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
+AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = 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([BUILD_WINDOWS], [test "$build_windows" = "yes"])
@@ -411,6 +437,7 @@ echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo " module extrakeys = $enable_module_extrakeys"
echo " module schnorrsig = $enable_module_schnorrsig"
+echo " module ellswift = $enable_module_ellswift"
echo
echo " asm = $set_asm"
echo " ecmult window size = $set_ecmult_window"
diff --git a/doc/safegcd_implementation.md b/doc/safegcd_implementation.md
index 063aa8efae..c1cdd0cfe1 100644
--- a/doc/safegcd_implementation.md
+++ b/doc/safegcd_implementation.md
@@ -1,7 +1,7 @@
# The safegcd implementation in libsecp256k1 explained
-This document explains the modular inverse implementation in the `src/modinv*.h` files. It is based
-on the paper
+This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files.
+It is based on the paper
["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd)
by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version.
@@ -769,3 +769,30 @@ def modinv_var(M, Mi, x):
d, e = update_de(d, e, t, M, Mi)
return normalize(f, d, Mi)
```
+
+## 8. From GCDs to Jacobi symbol
+
+We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we make corresponding updates to *j* using [properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties). In particular, we update *j* whenever we divide *g* by *2* or swap *f* and *g*; these updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied very quickly. Overall, this calculation is slightly simpler than the one for modular inverse because we no longer need to keep track of *d* and *e*.
+
+However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative values. We resolve this by using the following modified steps:
+
+```python
+ # Before
+ if delta > 0 and g & 1:
+ delta, f, g = 1 - delta, g, (g - f) // 2
+
+ # After
+ if delta > 0 and g & 1:
+ delta, f, g = 1 - delta, g, (g + f) // 2
+```
+
+The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4 and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm will converge. The justification for posdivsteps is completely empirical: in practice, it appears that the vast majority of inputs converge to *f=g=gcd(f0, g0)* in a number of steps proportional to their logarithm.
+
+Note that:
+- We require inputs to satisfy *gcd(x, M) = 1*.
+- We need to update the termination condition from *g=0* to *f=1*.
+- We deal with the case where *g=0* on input specially.
+
+We account for the possibility of nonconvergence by only performing a bounded number of posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not yet been found.
+
+The optimizations in sections 3-7 above are described in the context of the original divsteps, but in the C implementation we also adapt most of them (not including "avoiding modulus operations", since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate Jacobi symbols for secret data) to the posdivsteps version.
diff --git a/include/secp256k1_ellswift.h b/include/secp256k1_ellswift.h
new file mode 100644
index 0000000000..cda5bac2e3
--- /dev/null
+++ b/include/secp256k1_ellswift.h
@@ -0,0 +1,175 @@
+#ifndef SECP256K1_ELLSWIFT_H
+#define SECP256K1_ELLSWIFT_H
+
+#include "secp256k1.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This module provides an implementation of ElligatorSwift as well as
+ * a version of x-only ECDH using it.
+ *
+ * ElligatorSwift is described in https://eprint.iacr.org/2022/759 by
+ * Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding
+ * public keys in 64-byte objects which are indistinguishable from
+ * uniformly random.
+ *
+ * Let f be the function from pairs of field elements to point X coordinates,
+ * defined as follows (all operations modulo p = 2^256 - 2^32 - 977)
+ * f(u,t):
+ * - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852,
+ * a square root of -3.
+ * - If u=0, set u=1 instead.
+ * - If t=0, set t=1 instead.
+ * - If u^3 + t^2 + 7 = 0, multiply t by 2.
+ * - Let p = u^3 + t^2 + 7
+ * - Let m = u^3 - t^2 + 7
+ * - Let v = (C * m / p - 1) * u / 2
+ * - Let w = p / (C * t * u)
+ * - Let x1 = v
+ * - Let x2 = -u - v
+ * - Let x3 = u + w^2
+ * - Return the first of [x3,x2,x1] that is an X coordinate on the curve
+ * (at least one of them is, for any inputs u and t).
+ *
+ * Then an ElligatorSwift encoding of x consists of the 32-byte big-endian
+ * encodings of field elements u and t concatenated, where f(u,t) = x.
+ * The encoding algorithm is described in the paper, and effectively picks a
+ * uniformly random pair (u,t) among those which encode x.
+ *
+ * If the Y coordinate is relevant, it is given the same parity as t.
+ *
+ * Changes w.r.t. the the paper:
+ * - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point
+ * at infinity in the paper. Here they are remapped to finite points.
+ * - The paper uses an additional encoding bit for the parity of y. Here the
+ * parity of t is used (negating t does not affect the decoded x coordinate,
+ * so this is possible).
+ */
+
+/** A pointer to a function used for hashing the shared X coordinate along
+ * with the encoded public keys to a uniform shared secret.
+ *
+ * Returns: 1 if a shared secret was was successfully computed.
+ * 0 will cause secp256k1_ellswift_xdh to fail and return 0.
+ * Other return values are not allowed, and the behaviour of
+ * secp256k1_ellswift_xdh is undefined for other return values.
+ * Out: output: pointer to an array to be filled by the function
+ * In: x32: pointer to the 32-byte serialized X coordinate
+ * of the resulting shared point
+ * ours64: pointer to the 64-byte encoded public key we sent
+ * to the other party
+ * theirs64: pointer to the 64-byte encoded public key we received
+ * from the other party
+ * data: arbitrary data pointer that is passed through
+ */
+typedef int (*secp256k1_ellswift_xdh_hash_function)(
+ unsigned char *output,
+ const unsigned char *x32,
+ const unsigned char *ours64,
+ const unsigned char *theirs64,
+ void *data
+);
+
+/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses
+ * SHA256(key1 || key2 || x32), where (key1, key2) = sorted([ours64, theirs64]), and
+ * ignores data. The sorting is lexicographic. */
+SECP256K1_API extern const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_sha256;
+
+/** A default secp256k1_ellswift_xdh_hash_function, currently secp256k1_ellswift_xdh_hash_function_sha256. */
+SECP256K1_API extern const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_default;
+
+/* Construct a 64-byte ElligatorSwift encoding of a given pubkey.
+ *
+ * Returns: 1 when pubkey is valid.
+ * Args: ctx: pointer to a context object
+ * Out: ell64: pointer to a 64-byte array to be filled
+ * In: pubkey: a pointer to a secp256k1_pubkey containing an
+ * initialized public key
+ * rnd32: pointer to 32 bytes of entropy (must be unpredictable)
+ *
+ * This function runs in variable time.
+ */
+SECP256K1_API int secp256k1_ellswift_encode(
+ const secp256k1_context* ctx,
+ unsigned char *ell64,
+ const secp256k1_pubkey *pubkey,
+ const unsigned char *rnd32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Decode a 64-bytes ElligatorSwift encoded public key.
+ *
+ * Returns: always 1
+ * Args: ctx: pointer to a context object
+ * Out: pubkey: pointer to a secp256k1_pubkey that will be filled
+ * In: ell64: pointer to a 64-byte array to decode
+ *
+ * This function runs in variable time.
+ */
+SECP256K1_API int secp256k1_ellswift_decode(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *pubkey,
+ const unsigned char *ell64
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Compute an ElligatorSwift public key for a secret key.
+ *
+ * Returns: 1: secret was valid, public key was stored.
+ * 0: secret was invalid, try again.
+ * Args: ctx: pointer to a context object, initialized for signing.
+ * Out: ell64: pointer to a 64-byte area to receive the ElligatorSwift public key
+ * In: seckey32: pointer to a 32-byte secret key.
+ * auxrand32: (optional) pointer to 32 bytes of additional randomness
+ *
+ * Constant time in seckey and auxrand32, but not in the resulting public key.
+ *
+ * This function can be used instead of calling secp256k1_ec_pubkey_create followed
+ * by secp256k1_ellswift_encode. It is safer, as it can use the secret key as
+ * entropy for the encoding. That means that if the secret key itself is
+ * unpredictable, no additional auxrand32 is needed to achieve indistinguishability
+ * of the encoding.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create(
+ const secp256k1_context* ctx,
+ unsigned char *ell64,
+ const unsigned char *seckey32,
+ const unsigned char *auxrand32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Given a private key, and ElligatorSwift public keys sent in both directions,
+ * compute a shared secret using x-only Diffie-Hellman.
+ *
+ * Returns: 1: shared secret was succesfully computed
+ * 0: secret was invalid or hashfp returned 0
+ * Args: ctx: pointer to a context object.
+ * Out: output: pointer to an array to be filled by hashfp.
+ * In: theirs64: a pointer to the 64-byte ElligatorSquare public key received from the other party.
+ * ours64: a pointer to the 64-byte ElligatorSquare public key sent to the other party.
+ * seckey32: a pointer to the 32-byte private key corresponding to ours64.
+ * hashfp: pointer to a hash function. If NULL,
+ * secp256k1_elswift_xdh_hash_function_default is used
+ * (in which case, 32 bytes will be written to output).
+ * data: arbitrary data pointer that is passed through to hashfp
+ * (ignored for secp256k1_ellswift_xdh_hash_function_default).
+ *
+ * Constant time in seckey32.
+ *
+ * This function is more efficient than decoding the public keys, and performing ECDH on them.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh(
+ const secp256k1_context* ctx,
+ unsigned char *output,
+ const unsigned char* theirs64,
+ const unsigned char* ours64,
+ const unsigned char* seckey32,
+ secp256k1_ellswift_xdh_hash_function hashfp,
+ void *data
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECP256K1_ELLSWIFT_H */
diff --git a/src/basic-config.h b/src/basic-config.h
deleted file mode 100644
index 6f7693cb8f..0000000000
--- a/src/basic-config.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/***********************************************************************
- * Copyright (c) 2013, 2014 Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
- ***********************************************************************/
-
-#ifndef SECP256K1_BASIC_CONFIG_H
-#define SECP256K1_BASIC_CONFIG_H
-
-#ifdef USE_BASIC_CONFIG
-
-#define ECMULT_WINDOW_SIZE 15
-#define ECMULT_GEN_PREC_BITS 4
-
-#endif /* USE_BASIC_CONFIG */
-
-#endif /* SECP256K1_BASIC_CONFIG_H */
diff --git a/src/bench.c b/src/bench.c
index d5937b763f..68cb163b13 100644
--- a/src/bench.c
+++ b/src/bench.c
@@ -121,6 +121,22 @@ static void bench_sign_run(void* arg, int iters) {
}
}
+static void bench_keygen_run(void* arg, int iters) {
+ int i;
+ bench_sign_data *data = (bench_sign_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ unsigned char pub33[33];
+ size_t len = 33;
+ secp256k1_pubkey pubkey;
+ CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->key));
+ CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pub33, &len, &pubkey, SECP256K1_EC_COMPRESSED));
+ memcpy(data->key, pub33 + 1, 32);
+ data->key[17] ^= i;
+ }
+}
+
+
#ifdef ENABLE_MODULE_ECDH
# include "modules/ecdh/bench_impl.h"
#endif
@@ -133,6 +149,10 @@ static void bench_sign_run(void* arg, int iters) {
# include "modules/schnorrsig/bench_impl.h"
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+# include "modules/ellswift/bench_impl.h"
+#endif
+
int main(int argc, char** argv) {
int i;
secp256k1_pubkey pubkey;
@@ -212,6 +232,7 @@ int main(int argc, char** argv) {
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ec") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ec_keygen")) run_benchmark("ec_keygen", bench_keygen_run, bench_sign_setup, NULL, &data, 10, iters);
secp256k1_context_destroy(data.ctx);
@@ -230,5 +251,10 @@ int main(int argc, char** argv) {
run_schnorrsig_bench(iters, argc, argv);
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+ /* ElligatorSwift benchmarks */
+ run_ellswift_bench(iters, argc, argv);
+#endif
+
return 0;
}
diff --git a/src/bench.h b/src/bench.h
index aa275fe919..611ba11f04 100644
--- a/src/bench.h
+++ b/src/bench.h
@@ -7,15 +7,31 @@
#ifndef SECP256K1_BENCH_H
#define SECP256K1_BENCH_H
+#include
#include
#include
#include
-#include "sys/time.h"
+
+#if (defined(_MSC_VER) && _MSC_VER >= 1900)
+# include
+#else
+# include "sys/time.h"
+#endif
static int64_t gettime_i64(void) {
+#if (defined(_MSC_VER) && _MSC_VER >= 1900)
+ /* C11 way to get wallclock time */
+ struct timespec tv;
+ if (!timespec_get(&tv, TIME_UTC)) {
+ fputs("timespec_get failed!", stderr);
+ exit(1);
+ }
+ return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL;
+#else
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
+#endif
}
#define FP_EXP (6)
diff --git a/src/bench_internal.c b/src/bench_internal.c
index 7eb3af28d7..27af24b1a0 100644
--- a/src/bench_internal.c
+++ b/src/bench_internal.c
@@ -218,6 +218,17 @@ void bench_field_sqrt(void* arg, int iters) {
CHECK(j <= iters);
}
+void bench_field_jacobi_var(void* arg, int iters) {
+ int i, j = 0;
+ bench_inv *data = (bench_inv*)arg;
+
+ for (i = 0; i < iters; i++) {
+ j += secp256k1_fe_jacobi_var(&data->fe[0]);
+ secp256k1_fe_add(&data->fe[0], &data->fe[1]);
+ }
+ CHECK(j <= iters);
+}
+
void bench_group_double_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -379,6 +390,7 @@ int main(int argc, char **argv) {
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "jacobi")) run_benchmark("field_jacobi_var", bench_field_jacobi_var, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10);
diff --git a/src/ecmult.h b/src/ecmult.h
index b47d8f494a..e28c602506 100644
--- a/src/ecmult.h
+++ b/src/ecmult.h
@@ -11,6 +11,17 @@
#include "scalar.h"
#include "scratch.h"
+#ifndef ECMULT_WINDOW_SIZE
+# define ECMULT_WINDOW_SIZE 15
+# ifdef DEBUG_CONFIG
+# pragma message DEBUG_CONFIG_MSG("ECMULT_WINDOW_SIZE undefined, assuming default value")
+# endif
+#endif
+
+#ifdef DEBUG_CONFIG
+# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE)
+#endif
+
/* Noone will ever need more than a window size of 24. The code might
* be correct for larger values of ECMULT_WINDOW_SIZE but this is not
* tested.
diff --git a/src/ecmult_const.h b/src/ecmult_const.h
index f891f3f306..aae902743b 100644
--- a/src/ecmult_const.h
+++ b/src/ecmult_const.h
@@ -18,4 +18,23 @@
*/
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits);
+/**
+ * Same as secp256k1_ecmult_const, but takes in an x coordinate of the base point
+ * only, specified as fraction n/d. Only the x coordinate of the result is returned.
+ *
+ * If known_on_curve is 0, a verification is performed that n/d is a valid X
+ * coordinate, and 0 is returned if not. Otherwise, 1 is returned.
+ *
+ * d being NULL is interpreted as d=1.
+ *
+ * Constant time in the value of q, but not any other inputs.
+ */
+static int secp256k1_ecmult_const_xonly(
+ secp256k1_fe* r,
+ const secp256k1_fe *n,
+ const secp256k1_fe *d,
+ const secp256k1_scalar *q,
+ int bits,
+ int known_on_curve);
+
#endif /* SECP256K1_ECMULT_CONST_H */
diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h
index 12dbcc6c5b..1940ee7f08 100644
--- a/src/ecmult_const_impl.h
+++ b/src/ecmult_const_impl.h
@@ -228,4 +228,58 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
secp256k1_fe_mul(&r->z, &r->z, &Z);
}
+static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int bits, int known_on_curve) {
+
+ /* This algorithm is a generalization of Peter Dettman's technique for
+ * avoiding the square root in a random-basepoint x-only multiplication
+ * on a Weierstrass curve:
+ * https://mailarchive.ietf.org/arch/msg/cfrg/7DyYY6gg32wDgHAhgSb6XxMDlJA/
+ */
+ secp256k1_fe g, i;
+ secp256k1_ge p;
+ secp256k1_gej rj;
+
+ /* Compute g = (n^3 + B*d^3). */
+ secp256k1_fe_sqr(&g, n);
+ secp256k1_fe_mul(&g, &g, n);
+ if (d) {
+ secp256k1_fe b;
+ secp256k1_fe_sqr(&b, d);
+ secp256k1_fe_mul(&b, &b, d);
+ secp256k1_fe_mul(&b, &b, &secp256k1_fe_const_b);
+ secp256k1_fe_add(&g, &b);
+ if (!known_on_curve) {
+ secp256k1_fe c;
+ secp256k1_fe_mul(&c, &g, d);
+ if (secp256k1_fe_jacobi_var(&c) < 0) return 0;
+ }
+ } else {
+ secp256k1_fe_add(&g, &secp256k1_fe_const_b);
+ if (!known_on_curve) {
+ if (secp256k1_fe_jacobi_var(&g) < 0) return 0;
+ }
+ }
+
+ /* Compute base point P = (n*g, g^2), the effective affine version of
+ * (n*g, g^2, sqrt(d*g)), which has corresponding affine X coordinate
+ * n/d. */
+ secp256k1_fe_mul(&p.x, &g, n);
+ secp256k1_fe_sqr(&p.y, &g);
+ p.infinity = 0;
+
+ /* Perform x-only EC multiplication of P with q. */
+ secp256k1_ecmult_const(&rj, &p, q, bits);
+
+ /* The resulting (X, Y, Z) point on the effective-affine isomorphic curve
+ * corresponds to (X, Y, Z*sqrt(d*g)) on the secp256k1 curve. The affine
+ * version of that has X coordinate (X / (Z^2*d*g)). */
+ secp256k1_fe_sqr(&i, &rj.z);
+ secp256k1_fe_mul(&i, &i, &g);
+ if (d) secp256k1_fe_mul(&i, &i, d);
+ secp256k1_fe_inv(&i, &i);
+ secp256k1_fe_mul(r, &rj.x, &i);
+
+ return 1;
+}
+
#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
diff --git a/src/ecmult_gen.h b/src/ecmult_gen.h
index f48f266461..a430e8d5d9 100644
--- a/src/ecmult_gen.h
+++ b/src/ecmult_gen.h
@@ -10,9 +10,21 @@
#include "scalar.h"
#include "group.h"
+#ifndef ECMULT_GEN_PREC_BITS
+# define ECMULT_GEN_PREC_BITS 4
+# ifdef DEBUG_CONFIG
+# pragma message DEBUG_CONFIG_MSG("ECMULT_GEN_PREC_BITS undefined, assuming default value")
+# endif
+#endif
+
+#ifdef DEBUG_CONFIG
+# pragma message DEBUG_CONFIG_DEF(ECMULT_GEN_PREC_BITS)
+#endif
+
#if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8
# error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8."
#endif
+
#define ECMULT_GEN_PREC_G(bits) (1 << bits)
#define ECMULT_GEN_PREC_N(bits) (256 / bits)
diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h
index 2c8a503acc..4f5ea9f3c0 100644
--- a/src/ecmult_gen_impl.h
+++ b/src/ecmult_gen_impl.h
@@ -88,31 +88,31 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
unsigned char nonce32[32];
secp256k1_rfc6979_hmac_sha256 rng;
int overflow;
- unsigned char keydata[64] = {0};
+ unsigned char keydata[64];
if (seed32 == NULL) {
/* When seed is NULL, reset the initial point and blinding value. */
secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);
secp256k1_gej_neg(&ctx->initial, &ctx->initial);
secp256k1_scalar_set_int(&ctx->blind, 1);
+ return;
}
/* The prior blinding value (if not reset) is chained forward by including it in the hash. */
- secp256k1_scalar_get_b32(nonce32, &ctx->blind);
+ secp256k1_scalar_get_b32(keydata, &ctx->blind);
/** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data,
* and guards against weak or adversarial seeds. This is a simpler and safer interface than
* asking the caller for blinding values directly and expecting them to retry on failure.
*/
- memcpy(keydata, nonce32, 32);
- if (seed32 != NULL) {
- memcpy(keydata + 32, seed32, 32);
- }
- secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32);
+ VERIFY_CHECK(seed32 != NULL);
+ memcpy(keydata + 32, seed32, 32);
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
memset(keydata, 0, sizeof(keydata));
/* Accept unobservably small non-uniformity. */
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
overflow = !secp256k1_fe_set_b32(&s, nonce32);
overflow |= secp256k1_fe_is_zero(&s);
secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
- /* Randomize the projection to defend against multiplier sidechannels. */
+ /* Randomize the projection to defend against multiplier sidechannels.
+ Do this before our own call to secp256k1_ecmult_gen below. */
secp256k1_gej_rescale(&ctx->initial, &s);
secp256k1_fe_clear(&s);
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
@@ -121,6 +121,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
memset(nonce32, 0, 32);
+ /* The random projection in ctx->initial ensures that gb will have a random projection. */
secp256k1_ecmult_gen(ctx, &gb, &b);
secp256k1_scalar_negate(&b, &b);
ctx->blind = b;
diff --git a/src/field.h b/src/field.h
index 2584a494ee..c9bafeb481 100644
--- a/src/field.h
+++ b/src/field.h
@@ -139,4 +139,7 @@ static void secp256k1_fe_half(secp256k1_fe *r);
* 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);
+/** Compute the Jacobi symbol of a / p. 0 if a=0; 1 if a square; -1 if a non-square. */
+static int secp256k1_fe_jacobi_var(const secp256k1_fe *a);
+
#endif /* SECP256K1_FIELD_H */
diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h
index 21742bf6eb..61a86190c5 100644
--- a/src/field_10x26_impl.h
+++ b/src/field_10x26_impl.h
@@ -1364,4 +1364,32 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
}
+static int secp256k1_fe_jacobi_var(const secp256k1_fe *x) {
+ secp256k1_fe tmp;
+ secp256k1_modinv32_signed30 s;
+ int ret;
+
+ tmp = *x;
+ secp256k1_fe_normalize_var(&tmp);
+ secp256k1_fe_to_signed30(&s, &tmp);
+ ret = secp256k1_jacobi32_maybe_var(&s, &secp256k1_const_modinfo_fe);
+ if (ret == -2) {
+ /* secp256k1_jacobi32_maybe_var failed to compute the Jacobi symbol. Fall back
+ * to computing a square root. This should be extremely rare with random
+ * input. */
+ secp256k1_fe dummy;
+ ret = 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1;
+#ifdef VERIFY
+ } else {
+ secp256k1_fe dummy;
+ if (secp256k1_fe_is_zero(&tmp)) {
+ VERIFY_CHECK(ret == 0);
+ } else {
+ VERIFY_CHECK(ret == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
+ }
+#endif
+ }
+ return ret;
+}
+
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h
index 6bd202f587..26e89123a0 100644
--- a/src/field_5x52_impl.h
+++ b/src/field_5x52_impl.h
@@ -667,4 +667,32 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
#endif
}
+static int secp256k1_fe_jacobi_var(const secp256k1_fe *x) {
+ secp256k1_fe tmp;
+ secp256k1_modinv64_signed62 s;
+ int ret;
+
+ tmp = *x;
+ secp256k1_fe_normalize_var(&tmp);
+ secp256k1_fe_to_signed62(&s, &tmp);
+ ret = secp256k1_jacobi64_maybe_var(&s, &secp256k1_const_modinfo_fe);
+ if (ret == -2) {
+ /* secp256k1_jacobi64_maybe_var failed to compute the Jacobi symbol. Fall back
+ * to computing a square root. This should be extremely rare with random
+ * input. */
+ secp256k1_fe dummy;
+ ret = 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1;
+#ifdef VERIFY
+ } else {
+ secp256k1_fe dummy;
+ if (secp256k1_fe_is_zero(&tmp)) {
+ VERIFY_CHECK(ret == 0);
+ } else {
+ VERIFY_CHECK(ret == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
+ }
+#endif
+ }
+ return ret;
+}
+
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
diff --git a/src/group.h b/src/group.h
index bb7dae1cf7..585457d93b 100644
--- a/src/group.h
+++ b/src/group.h
@@ -23,7 +23,7 @@ typedef struct {
#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
/** A group element of the secp256k1 curve, in jacobian coordinates.
- * Note: For exhastive test mode, sepc256k1 is replaced by a small subgroup of a different curve.
+ * Note: For exhastive test mode, secp256k1 is replaced by a small subgroup of a different curve.
*/
typedef struct {
secp256k1_fe x; /* actual X: x/z^2 */
diff --git a/src/modinv32.h b/src/modinv32.h
index 0efdda9ab5..263bda20b8 100644
--- a/src/modinv32.h
+++ b/src/modinv32.h
@@ -39,4 +39,8 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
/* Same as secp256k1_modinv32_var, but constant time in x (not in the modulus). */
static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
+/* Compute the Jacobi symbol for (x | modinfo->modulus). Either x must be 0, or x must be coprime with
+ * modulus. All limbs of x must be non-negative. Returns -2 if the result cannot be computed. */
+static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
+
#endif /* SECP256K1_MODINV32_H */
diff --git a/src/modinv32_impl.h b/src/modinv32_impl.h
index 661c5fc04c..93bc576675 100644
--- a/src/modinv32_impl.h
+++ b/src/modinv32_impl.h
@@ -232,6 +232,21 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
return zeta;
}
+/* inv256[i] = -(2*i+1)^-1 (mod 256) */
+static const uint8_t secp256k1_modinv32_inv256[128] = {
+ 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59,
+ 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31,
+ 0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89,
+ 0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61,
+ 0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9,
+ 0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91,
+ 0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9,
+ 0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1,
+ 0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19,
+ 0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1,
+ 0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01
+};
+
/* Compute the transition matrix and eta for 30 divsteps (variable time).
*
* Input: eta: initial eta
@@ -243,21 +258,6 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
* Implements the divsteps_n_matrix_var function from the explanation.
*/
static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) {
- /* inv256[i] = -(2*i+1)^-1 (mod 256) */
- static const uint8_t inv256[128] = {
- 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59,
- 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31,
- 0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89,
- 0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61,
- 0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9,
- 0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91,
- 0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9,
- 0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1,
- 0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19,
- 0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1,
- 0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01
- };
-
/* Transformation matrix; see comments in secp256k1_modinv32_divsteps_30. */
uint32_t u = 1, v = 0, q = 0, r = 1;
uint32_t f = f0, g = g0, m;
@@ -297,7 +297,7 @@ static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint
VERIFY_CHECK(limit > 0 && limit <= 30);
m = (UINT32_MAX >> (32 - limit)) & 255U;
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */
- w = (g * inv256[(f >> 1) & 127]) & m;
+ w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m;
/* Do so. */
g += f * w;
q += u * w;
@@ -317,6 +317,83 @@ static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint
return eta;
}
+/* Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track
+ * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because
+ * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2).
+ *
+ * Input: eta: initial eta
+ * f0: bottom limb of initial f
+ * g0: bottom limb of initial g
+ * Output: t: transition matrix
+ * Return: final eta
+ */
+static int32_t secp256k1_modinv32_posdivsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t, int *jacp) {
+ /* Transformation matrix. */
+ uint32_t u = 1, v = 0, q = 0, r = 1;
+ uint32_t f = f0, g = g0, m;
+ uint16_t w;
+ int i = 30, limit, zeros;
+ int jac = *jacp;
+
+ for (;;) {
+ /* Use a sentinel bit to count zeros only up to i. */
+ zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i));
+ /* Perform zeros divsteps at once; they all just divide g by two. */
+ g >>= zeros;
+ u <<= zeros;
+ v <<= zeros;
+ eta -= zeros;
+ i -= zeros;
+ /* Update the bottom bit of jac: when dividing g by an odd power of 2,
+ * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */
+ jac ^= (zeros & ((f >> 1) ^ (f >> 2)));
+ /* We're done once we've done 30 posdivsteps. */
+ if (i == 0) break;
+ VERIFY_CHECK((f & 1) == 1);
+ VERIFY_CHECK((g & 1) == 1);
+ VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i));
+ VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i));
+ /* If eta is negative, negate it and replace f,g with g,f. */
+ if (eta < 0) {
+ uint32_t tmp;
+ eta = -eta;
+ /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
+ * if both f and g are 3 mod 4. */
+ jac ^= ((f & g) >> 1);
+ tmp = f; f = g; g = tmp;
+ tmp = u; u = q; q = tmp;
+ tmp = v; v = r; r = tmp;
+ }
+ /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more
+ * than i can be cancelled out (as we'd be done before that point), and no more than eta+1
+ * can be done as its sign will flip once that happens. */
+ limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
+ /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */
+ VERIFY_CHECK(limit > 0 && limit <= 30);
+ m = (UINT32_MAX >> (32 - limit)) & 255U;
+ /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */
+ w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m;
+ /* Do so. */
+ g += f * w;
+ q += u * w;
+ r += v * w;
+ VERIFY_CHECK((g & m) == 0);
+ }
+ /* Return data in t and return value. */
+ t->u = (int32_t)u;
+ t->v = (int32_t)v;
+ t->q = (int32_t)q;
+ t->r = (int32_t)r;
+ /* The determinant of t must be a power of two. This guarantees that multiplication with t
+ * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
+ * will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
+ * the aggregate of 30 of them will have determinant 2^30 or -2^30. */
+ VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30 ||
+ (int64_t)t->u * t->r - (int64_t)t->v * t->q == -(((int64_t)1) << 30));
+ *jacp = jac;
+ return eta;
+}
+
/* Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps.
*
* On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range
@@ -584,4 +661,69 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
*x = d;
}
+/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1, or x must be 0. */
+static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) {
+ /* Start with f=modulus, g=x, eta=-1. */
+ secp256k1_modinv32_signed30 f = modinfo->modulus;
+ secp256k1_modinv32_signed30 g = *x;
+ int j, len = 9;
+ int32_t eta = -1; /* eta = -delta; delta is initially 1 */
+ int32_t cond, fn, gn;
+ int jac = 0;
+ int count;
+
+ VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0 && g.v[5] >= 0 && g.v[6] >= 0 && g.v[7] >= 0 && g.v[8] >= 0);
+
+ /* The loop below does not converge for input g=0. Deal with this case specifically. */
+ if (!(g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4] | g.v[5] | g.v[6] | g.v[7] | g.v[8])) return 0;
+
+ /* Do up to 50 iterations of 30 posdivsteps (up to 1500 steps; more is extremely rare) each until f=1.
+ * In VERIFY mode use a lower number of iterations (750, close to the median 756), so failure actually occurs. */
+#ifdef VERIFY
+ for (count = 0; count < 25; ++count) {
+#else
+ for (count = 0; count < 50; ++count) {
+#endif
+ /* Compute transition matrix and new eta after 30 posdivsteps. */
+ secp256k1_modinv32_trans2x2 t;
+ eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac);
+ /* Update f,g using that transition matrix. */
+#ifdef VERIFY
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
+#endif
+ secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t);
+ /* If the bottom limb of f is 1, there is a chance that f=1. */
+ if (f.v[0] == 1) {
+ cond = 0;
+ /* Check if the other limbs are also 0. */
+ for (j = 1; j < len; ++j) {
+ cond |= f.v[j];
+ }
+ /* If so, we're done. */
+ if (cond == 0) return 1 - 2*(jac & 1);
+ }
+
+ /* Determine if len>1 and limb (len-1) of both f and g is 0. */
+ fn = f.v[len - 1];
+ gn = g.v[len - 1];
+ cond = ((int32_t)len - 2) >> 31;
+ cond |= fn;
+ cond |= gn;
+ /* If so, reduce length. */
+ if (cond == 0) --len;
+#ifdef VERIFY
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
+ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
+#endif
+ }
+
+ /* The loop failed to converge to f=g after 1500 iterations. Return -2, indicating unknown result. */
+ return -2;
+}
+
#endif /* SECP256K1_MODINV32_IMPL_H */
diff --git a/src/modinv64.h b/src/modinv64.h
index da506dfa9f..e432fcbe8d 100644
--- a/src/modinv64.h
+++ b/src/modinv64.h
@@ -43,4 +43,8 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
/* Same as secp256k1_modinv64_var, but constant time in x (not in the modulus). */
static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
+/* Compute the Jacobi symbol for (x | modinfo->modulus). Either x must be 0, or x must be coprime with
+ * modulus. All limbs of x must be non-negative. Returns -2 if the result cannot be computed. */
+static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
+
#endif /* SECP256K1_MODINV64_H */
diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h
index 0743a9c821..2d0d33d777 100644
--- a/src/modinv64_impl.h
+++ b/src/modinv64_impl.h
@@ -256,7 +256,7 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
tmp = v; v = r; r = -tmp;
/* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled
* out (as we'd be done before that point), and no more than eta+1 can be done as its
- * will flip again once that happens. */
+ * sign will flip again once that happens. */
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
VERIFY_CHECK(limit > 0 && limit <= 62);
/* m is a mask for the bottom min(limit, 6) bits. */
@@ -294,6 +294,94 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
return eta;
}
+/* Compute the transition matrix and eta for 62 posdivsteps (variable time, eta=-delta), and keeps track
+ * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^64 rather than 2^62, because
+ * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2).
+ *
+ * Input: eta: initial eta
+ * f0: bottom limb of initial f
+ * g0: bottom limb of initial g
+ * Output: t: transition matrix
+ * Return: final eta
+ */
+static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t, int *jacp) {
+ /* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */
+ uint64_t u = 1, v = 0, q = 0, r = 1;
+ uint64_t f = f0, g = g0, m;
+ uint32_t w;
+ int i = 62, limit, zeros;
+ int jac = *jacp;
+
+ for (;;) {
+ /* Use a sentinel bit to count zeros only up to i. */
+ zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i));
+ /* Perform zeros divsteps at once; they all just divide g by two. */
+ g >>= zeros;
+ u <<= zeros;
+ v <<= zeros;
+ eta -= zeros;
+ i -= zeros;
+ /* Update the bottom bit of jac: when dividing g by an odd power of 2,
+ * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */
+ jac ^= (zeros & ((f >> 1) ^ (f >> 2)));
+ /* We're done once we've done 62 posdivsteps. */
+ if (i == 0) break;
+ VERIFY_CHECK((f & 1) == 1);
+ VERIFY_CHECK((g & 1) == 1);
+ VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i));
+ VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i));
+ /* If eta is negative, negate it and replace f,g with g,f. */
+ if (eta < 0) {
+ uint64_t tmp;
+ eta = -eta;
+ tmp = f; f = g; g = tmp;
+ tmp = u; u = q; q = tmp;
+ tmp = v; v = r; r = tmp;
+ /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
+ * if both f and g are 3 mod 4. */
+ jac ^= ((f & g) >> 1);
+ /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled
+ * out (as we'd be done before that point), and no more than eta+1 can be done as its
+ * sign will flip again once that happens. */
+ limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
+ VERIFY_CHECK(limit > 0 && limit <= 62);
+ /* m is a mask for the bottom min(limit, 6) bits. */
+ m = (UINT64_MAX >> (64 - limit)) & 63U;
+ /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6)
+ * bits. */
+ w = (f * g * (f * f - 2)) & m;
+ } else {
+ /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as
+ * eta tends to be smaller here. */
+ limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
+ VERIFY_CHECK(limit > 0 && limit <= 62);
+ /* m is a mask for the bottom min(limit, 4) bits. */
+ m = (UINT64_MAX >> (64 - limit)) & 15U;
+ /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4)
+ * bits. */
+ w = f + (((f + 1) & 4) << 1);
+ w = (-w * g) & m;
+ }
+ g += f * w;
+ q += u * w;
+ r += v * w;
+ VERIFY_CHECK((g & m) == 0);
+ }
+ /* Return data in t and return value. */
+ t->u = (int64_t)u;
+ t->v = (int64_t)v;
+ t->q = (int64_t)q;
+ t->r = (int64_t)r;
+ /* The determinant of t must be a power of two. This guarantees that multiplication with t
+ * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
+ * will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
+ * the aggregate of 62 of them will have determinant 2^62 or -2^62. */
+ VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 62 ||
+ (int128_t)t->u * t->r - (int128_t)t->v * t->q == -(((int128_t)1) << 62));
+ *jacp = jac;
+ return eta;
+}
+
/* Compute (t/2^62) * [d, e] mod modulus, where t is a transition matrix scaled by 2^62.
*
* On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range
@@ -590,4 +678,69 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
*x = d;
}
+/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1, or x must be 0. */
+static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) {
+ /* Start with f=modulus, g=x, eta=-1. */
+ secp256k1_modinv64_signed62 f = modinfo->modulus;
+ secp256k1_modinv64_signed62 g = *x;
+ int j, len = 5;
+ int64_t eta = -1; /* eta = -delta; delta is initially 1 */
+ int64_t cond, fn, gn;
+ int jac = 0;
+ int count;
+
+ VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0);
+
+ /* The loop below does not converge for input g=0. Deal with this case specifically. */
+ if (!(g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4])) return 0;
+
+ /* Do up to 25 iterations of 62 posdivsteps (up to 1550 steps; more is extremely rare) each until f=1.
+ * In VERIFY mode use a lower number of iterations (744, close to the median 756), so failure actually occurs. */
+#ifdef VERIFY
+ for (count = 0; count < 12; ++count) {
+#else
+ for (count = 0; count < 25; ++count) {
+#endif
+ /* Compute transition matrix and new eta after 62 posdivsteps. */
+ secp256k1_modinv64_trans2x2 t;
+ eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac);
+ /* Update f,g using that transition matrix. */
+#ifdef VERIFY
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
+#endif
+ secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t);
+ /* If the bottom limb of f is 1, there is a chance that f=1. */
+ if (f.v[0] == 1) {
+ cond = 0;
+ /* Check if the other limbs are also 0. */
+ for (j = 1; j < len; ++j) {
+ cond |= f.v[j];
+ }
+ /* If so, we're done. */
+ if (cond == 0) return 1 - 2*(jac & 1);
+ }
+
+ /* Determine if len>1 and limb (len-1) of both f and g is 0. */
+ fn = f.v[len - 1];
+ gn = g.v[len - 1];
+ cond = ((int64_t)len - 2) >> 63;
+ cond |= fn;
+ cond |= gn;
+ /* If so, reduce length. */
+ if (cond == 0) --len;
+#ifdef VERIFY
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
+ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
+#endif
+ }
+
+ /* The loop failed to converge to f=g after 1550 iterations. Return -2, indicating unknown result. */
+ return -2;
+}
+
#endif /* SECP256K1_MODINV64_IMPL_H */
diff --git a/src/modules/ecdh/bench_impl.h b/src/modules/ecdh/bench_impl.h
index 94d833462f..8df15bcf43 100644
--- a/src/modules/ecdh/bench_impl.h
+++ b/src/modules/ecdh/bench_impl.h
@@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_ECDH_BENCH_H
#define SECP256K1_MODULE_ECDH_BENCH_H
-#include "../include/secp256k1_ecdh.h"
+#include "../../../include/secp256k1_ecdh.h"
typedef struct {
secp256k1_context *ctx;
diff --git a/src/modules/ellswift/Makefile.am.include b/src/modules/ellswift/Makefile.am.include
new file mode 100644
index 0000000000..e7efea2981
--- /dev/null
+++ b/src/modules/ellswift/Makefile.am.include
@@ -0,0 +1,4 @@
+include_HEADERS += include/secp256k1_ellswift.h
+noinst_HEADERS += src/modules/ellswift/bench_impl.h
+noinst_HEADERS += src/modules/ellswift/main_impl.h
+noinst_HEADERS += src/modules/ellswift/tests_impl.h
diff --git a/src/modules/ellswift/bench_impl.h b/src/modules/ellswift/bench_impl.h
new file mode 100644
index 0000000000..1befd0a4a2
--- /dev/null
+++ b/src/modules/ellswift/bench_impl.h
@@ -0,0 +1,94 @@
+/***********************************************************************
+ * Copyright (c) 2022 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
+ ***********************************************************************/
+
+#ifndef SECP256K1_MODULE_ELLSWIFT_BENCH_H
+#define SECP256K1_MODULE_ELLSWIFT_BENCH_H
+
+#include "../include/secp256k1_ellswift.h"
+
+typedef struct {
+ secp256k1_context *ctx;
+ secp256k1_pubkey point;
+ unsigned char rnd64[64];
+} bench_ellswift_data;
+
+static void bench_ellswift_setup(void* arg) {
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+ static const unsigned char point[] = {
+ 0x03,
+ 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
+ 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,
+ 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,
+ 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
+ };
+ memcpy(data->rnd64, point, 32);
+ memcpy(data->rnd64 + 32, point + 1, 32);
+ CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1);
+}
+
+static void bench_ellswift_encode(void* arg, int iters) {
+ int i;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ data->rnd64[19] ^= 247;
+ data->rnd64[47] ^= 113;
+ CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point, data->rnd64 + 16) == 1);
+ }
+}
+
+static void bench_ellswift_create(void* arg, int iters) {
+ int i, j;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ unsigned char out64[64];
+ CHECK(secp256k1_ellswift_create(data->ctx, out64, data->rnd64, data->rnd64 + 32) == 1);
+ for (j = 0; j < 64; j++) data->rnd64[j] ^= out64[j];
+ }
+}
+
+static void bench_ellswift_decode(void* arg, int iters) {
+ int i;
+ secp256k1_pubkey out;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ data->rnd64[13] ^= 247;
+ data->rnd64[49] ^= 113;
+ CHECK(secp256k1_ellswift_decode(data->ctx, &out, data->rnd64) == 1);
+ memcpy(data->rnd64 + 16, &out.data, 32);
+ }
+}
+
+static void bench_ellswift_xdh(void* arg, int iters) {
+ int i;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ data->rnd64[13] ^= 247;
+ data->rnd64[49] ^= 113;
+ CHECK(secp256k1_ellswift_xdh(data->ctx, data->rnd64 + 16, data->rnd64, data->rnd64, data->rnd64 + 13, NULL, NULL) == 1);
+ }
+}
+
+void run_ellswift_bench(int iters, int argc, char** argv) {
+ bench_ellswift_data data;
+ int d = argc == 1;
+
+ /* create a context with signing capabilities */
+ data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ memset(data.rnd64, 11, sizeof(data.rnd64));
+
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "encode") || have_flag(argc, argv, "ellswift_encode")) run_benchmark("ellswift_encode", bench_ellswift_encode, bench_ellswift_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_decode")) run_benchmark("ellswift_decode", bench_ellswift_decode, bench_ellswift_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "create") || have_flag(argc, argv, "ellswift_create")) run_benchmark("ellswift_create", bench_ellswift_create, bench_ellswift_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "xdh") || have_flag(argc, argv, "ellswift_xdh")) run_benchmark("ellswift_xdh", bench_ellswift_xdh, bench_ellswift_setup, NULL, &data, 10, iters);
+
+ secp256k1_context_destroy(data.ctx);
+}
+
+#endif /* SECP256K1_MODULE_ellswift_BENCH_H */
diff --git a/src/modules/ellswift/main_impl.h b/src/modules/ellswift/main_impl.h
new file mode 100644
index 0000000000..cbfe0e2cf8
--- /dev/null
+++ b/src/modules/ellswift/main_impl.h
@@ -0,0 +1,394 @@
+/***********************************************************************
+ * Copyright (c) 2022 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
+ ***********************************************************************/
+
+#ifndef SECP256K1_MODULE_ELLSWIFT_MAIN_H
+#define SECP256K1_MODULE_ELLSWIFT_MAIN_H
+
+#include "../../../include/secp256k1.h"
+#include "../../../include/secp256k1_ellswift.h"
+#include "../../hash.h"
+
+/** c1 = the square root of -3 ((-3)**((p+1)/4)). */
+static const secp256k1_fe secp256k1_ellswift_c1 = SECP256K1_FE_CONST(0x0a2d2ba9, 0x3507f1df, 0x233770c2, 0xa797962c, 0xc61f6d15, 0xda14ecd4, 0x7d8d27ae, 0x1cd5f852);
+/** c2 = -1/2 * (c1 - 1). */
+static const secp256k1_fe secp256k1_ellswift_c2 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ef);
+
+/** Decode ElligatorSwift encoding (u, t) to a fraction xn/xd representing a curve X coordinate. */
+static void secp256k1_ellswift_fe2_to_gexfrac_var(secp256k1_fe* xn, secp256k1_fe* xd, const secp256k1_fe* u, const secp256k1_fe* t) {
+ secp256k1_fe v1 = *u, v2 = *t;
+ secp256k1_fe v3, v4, v5, v6, v7, v8;
+ secp256k1_fe_normalize_var(&v1);
+ secp256k1_fe_normalize_var(&v2);
+ if (secp256k1_fe_is_zero(&v1)) v1 = secp256k1_fe_one;
+ if (secp256k1_fe_is_zero(&v2)) v2 = secp256k1_fe_one;
+ secp256k1_fe_sqr(&v3, &v1);
+ secp256k1_fe_mul(&v3, &v3, &v1);
+ secp256k1_fe_add(&v3, &secp256k1_fe_const_b);
+ secp256k1_fe_sqr(&v4, &v2);
+ v5 = v3;
+ secp256k1_fe_add(&v5, &v4);
+ if (secp256k1_fe_normalizes_to_zero_var(&v5)) {
+ secp256k1_fe_add(&v2, &v2);
+ secp256k1_fe_sqr(&v4, &v2);
+ v5 = v3;
+ secp256k1_fe_add(&v5, &v4);
+ }
+ secp256k1_fe_mul(&v6, &v1, &secp256k1_ellswift_c1);
+ secp256k1_fe_negate(&v4, &v4, 1);
+ secp256k1_fe_add(&v4, &v3);
+ secp256k1_fe_mul(&v4, &v4, &v6);
+ secp256k1_fe_mul(&v2, &v2, &v6);
+ secp256k1_fe_sqr(&v2, &v2);
+ secp256k1_fe_sqr(&v8, &v5);
+ secp256k1_fe_mul(&v3, &v1, &v2);
+ secp256k1_fe_add(&v3, &v8);
+ secp256k1_fe_sqr(&v6, &v2);
+ secp256k1_fe_sqr(&v6, &v6);
+ secp256k1_fe_mul_int(&v6, 7);
+ secp256k1_fe_sqr(&v7, &v3);
+ secp256k1_fe_mul(&v7, &v7, &v3);
+ secp256k1_fe_mul(&v7, &v7, &v2);
+ secp256k1_fe_add(&v7, &v6);
+ if (secp256k1_fe_jacobi_var(&v7) >= 0) {
+ *xn = v3;
+ *xd = v2;
+ return;
+ }
+ secp256k1_fe_mul(&v1, &v1, &v5);
+ secp256k1_fe_add(&v1, &v4);
+ secp256k1_fe_half(&v1);
+ secp256k1_fe_negate(&v1, &v1, 3);
+ secp256k1_fe_sqr(&v6, &v8);
+ secp256k1_fe_mul_int(&v6, 7);
+ secp256k1_fe_sqr(&v7, &v1);
+ secp256k1_fe_mul(&v7, &v7, &v1);
+ secp256k1_fe_mul(&v7, &v7, &v5);
+ secp256k1_fe_add(&v7, &v6);
+ *xd = v5;
+ secp256k1_fe_inv_var(&v5, &v5);
+ if (secp256k1_fe_jacobi_var(&v7) >= 0) {
+ *xn = v1;
+ return;
+ }
+ secp256k1_fe_add(&v1, &v4);
+ *xn = v1;
+}
+
+/** Decode ElligatorSwift encoding (u, t) to X coordinate. */
+static void secp256k1_ellswift_fe2_to_gex_var(secp256k1_fe* x, const secp256k1_fe* u, const secp256k1_fe* t) {
+ secp256k1_fe xn, xd;
+ secp256k1_ellswift_fe2_to_gexfrac_var(&xn, &xd, u, t);
+ secp256k1_fe_inv_var(&xd, &xd);
+ secp256k1_fe_mul(x, &xn, &xd);
+}
+
+/** Decode ElligatorSwift encoding (u, t) to point P. */
+static void secp256k1_ellswift_fe2_to_ge_var(secp256k1_ge* p, const secp256k1_fe* u, const secp256k1_fe* t) {
+ secp256k1_fe x;
+ secp256k1_ellswift_fe2_to_gex_var(&x, u, t);
+ secp256k1_ge_set_xo_var(p, &x, secp256k1_fe_is_odd(t));
+}
+
+/* Try to complete an ElligatorSwift encoding (u, t) for X coordinate x, given u and x.
+ *
+ * There may be up to 8 distinct t values such that (u, t) decodes back to x, but also
+ * fewer, or none at all. Each such partial inverse can be accessed individually using a
+ * distinct input argument i (in range 0-7), and some or all of these may return failure.
+ * The following guarantees exist:
+ * - Given (x, u), no two distinct i values give the same successful result t.
+ * - Every successful result maps back to x through secp256k1_ellswift_fe2_to_gex_var.
+ * - Given (x, u), all t values that map back to x can be reached by combining the
+ * successful results from this function over all i values, with the exception of:
+ * - this function cannot be called with u=0
+ * - no result with t=0 will be returned
+ * - no result for which u^3 + t^2 + 7 = 0 will be returned.
+ */
+static int secp256k1_ellswift_fegex_to_fe_var(secp256k1_fe* t, const secp256k1_fe* x, const secp256k1_fe* u, int i) {
+ secp256k1_fe xm = *x, um = *u;
+ secp256k1_fe g, s, w2, w;
+ secp256k1_fe_normalize_weak(&xm);
+ secp256k1_fe_normalize_weak(&um);
+ secp256k1_fe_sqr(&g, u);
+ secp256k1_fe_mul(&g, &g, u);
+ secp256k1_fe_add(&g, &secp256k1_fe_const_b);
+ if ((i & 2) == 0) {
+ secp256k1_fe o;
+ s = xm;
+ secp256k1_fe_add(&s, &um);
+ secp256k1_fe_sqr(&o, &s);
+ secp256k1_fe_mul(&o, &o, &s);
+ secp256k1_fe_negate(&o, &o, 1);
+ secp256k1_fe_add(&o, &secp256k1_fe_const_b);
+ if (secp256k1_fe_jacobi_var(&o) >= 0) return 0;
+ if (i & 1) {
+ secp256k1_fe_add(&xm, &um);
+ secp256k1_fe_negate(&xm, &xm, 2);
+ }
+ o = um;
+ secp256k1_fe_add(&o, &xm);
+ secp256k1_fe_sqr(&o, &o);
+ secp256k1_fe_negate(&o, &o, 1);
+ secp256k1_fe_mul(&w2, &um, &xm);
+ secp256k1_fe_add(&w2, &o);
+ secp256k1_fe_inv_var(&w2, &w2);
+ secp256k1_fe_mul(&w2, &w2, &g);
+ } else {
+ secp256k1_fe r2, r;
+ secp256k1_fe_negate(&w2, &um, 1);
+ secp256k1_fe_add(&w2, &xm);
+ if (secp256k1_fe_normalizes_to_zero_var(&w2)) return 0;
+ secp256k1_fe_normalize_weak(&g);
+ secp256k1_fe_mul_int(&g, 4);
+ secp256k1_fe_sqr(&r2, &um);
+ secp256k1_fe_mul_int(&r2, 3);
+ secp256k1_fe_mul(&r2, &r2, &w2);
+ secp256k1_fe_add(&r2, &g);
+ secp256k1_fe_mul(&r2, &r2, &w2);
+ secp256k1_fe_negate(&r2, &r2, 1);
+ if (!secp256k1_fe_sqrt(&r, &r2)) return 0;
+ if (i & 1) {
+ if (secp256k1_fe_normalizes_to_zero_var(&r)) return 0;
+ } else {
+ secp256k1_fe_negate(&r, &r, 1);
+ }
+ secp256k1_fe_inv_var(&xm, &w2);
+ secp256k1_fe_mul(&xm, &xm, &r);
+ secp256k1_fe_add(&xm, &um);
+ secp256k1_fe_half(&xm);
+ secp256k1_fe_negate(&xm, &xm, 2);
+ }
+ if (!secp256k1_fe_sqrt(&w, &w2)) return 0;
+ if ((i & 4) == 0) secp256k1_fe_negate(&w, &w, 1);
+ secp256k1_fe_mul(&um, &um, &secp256k1_ellswift_c2);
+ secp256k1_fe_add(&um, &xm);
+ secp256k1_fe_mul(t, &w, &um);
+ return 1;
+}
+
+/** Find an ElligatorSwift encoding (u, t) for X coordinate x.
+ *
+ * hasher is a SHA256 object which a incrementing 4-byte counter is added to to
+ * generate randomness for the rejection sampling in this function. Its size plus
+ * 4 (for the counter) plus 9 (for the SHA256 padding) must be a multiple of 64
+ * for efficiency reasons.
+ */
+static void secp256k1_ellswift_gex_to_fe2_var(secp256k1_fe* u, secp256k1_fe* t, const secp256k1_fe* x, const secp256k1_sha256* hasher) {
+ /* Pool of 3-bit branch values. */
+ unsigned char branch_hash[32];
+ /* Number of 3-bit values in branch_hash left. */
+ int branches_left = 0;
+ /* Field elements u and branch values are extracted from
+ * SHA256(hasher || cnt) for consecutive values of cnt. cnt==0
+ * is first used to populate a pool of 64 4-bit branch values. The 64 cnt
+ * values that follow are used to generate field elements u. cnt==65 (and
+ * multiples thereof) are used to repopulate the pool and start over, if
+ * that were ever necessary. */
+ uint32_t cnt = 0;
+ VERIFY_CHECK((hasher->bytes + 4 + 9) % 64 == 0);
+ while (1) {
+ int branch;
+ /* If the pool of branch values is empty, populate it. */
+ if (branches_left == 0) {
+ secp256k1_sha256 hash = *hasher;
+ unsigned char buf4[4];
+ buf4[0] = cnt;
+ buf4[1] = cnt >> 8;
+ buf4[2] = cnt >> 16;
+ buf4[3] = cnt >> 24;
+ ++cnt;
+ secp256k1_sha256_write(&hash, buf4, 4);
+ secp256k1_sha256_finalize(&hash, branch_hash);
+ branches_left = 64;
+ }
+ /* Take a 3-bit branch value from the branch pool (top bit is discarded). */
+ --branches_left;
+ branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7;
+ /* Compute a new u value by hashing. */
+ {
+ secp256k1_sha256 hash = *hasher;
+ unsigned char buf4[4];
+ unsigned char u32[32];
+ buf4[0] = cnt;
+ buf4[1] = cnt >> 8;
+ buf4[2] = cnt >> 16;
+ buf4[3] = cnt >> 24;
+ ++cnt;
+ secp256k1_sha256_write(&hash, buf4, 4);
+ secp256k1_sha256_finalize(&hash, u32);
+ if (!secp256k1_fe_set_b32(u, u32)) continue;
+ if (secp256k1_fe_is_zero(u)) continue;
+ }
+ /* Find a remainder t, and return it if found. */
+ if (secp256k1_ellswift_fegex_to_fe_var(t, x, u, branch)) {
+ secp256k1_fe_normalize_var(t);
+ break;
+ }
+ }
+}
+
+/** Find an ElligatorSwift encoding (u, t) for point P. */
+static void secp256k1_ellswift_ge_to_fe2_var(secp256k1_fe* u, secp256k1_fe* t, const secp256k1_ge* p, const secp256k1_sha256* hasher) {
+ secp256k1_ellswift_gex_to_fe2_var(u, t, &p->x, hasher);
+ if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) {
+ secp256k1_fe_negate(t, t, 1);
+ secp256k1_fe_normalize_var(t);
+ }
+}
+
+int secp256k1_ellswift_encode(const secp256k1_context* ctx, unsigned char *ell64, const secp256k1_pubkey *pubkey, const unsigned char *rnd32) {
+ secp256k1_ge p;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(ell64 != NULL);
+ ARG_CHECK(pubkey != NULL);
+ ARG_CHECK(rnd32 != NULL);
+
+ if (secp256k1_pubkey_load(ctx, &p, pubkey)) {
+ static const unsigned char PREFIX[128 - 9 - 4 - 32 - 33] = "secp256k1_ellswift_encode";
+ secp256k1_fe u, t;
+ unsigned char p33[33];
+ secp256k1_sha256 hash;
+
+ /* Set up hasher state */
+ secp256k1_sha256_initialize(&hash);
+ secp256k1_sha256_write(&hash, PREFIX, sizeof(PREFIX));
+ secp256k1_sha256_write(&hash, rnd32, 32);
+ secp256k1_fe_get_b32(p33, &p.x);
+ p33[32] = secp256k1_fe_is_odd(&p.y);
+ secp256k1_sha256_write(&hash, p33, sizeof(p33));
+ VERIFY_CHECK(hash.bytes == 128 - 9 - 4);
+
+ /* Compute ElligatorSwift encoding and construct output. */
+ secp256k1_ellswift_ge_to_fe2_var(&u, &t, &p, &hash);
+ secp256k1_fe_get_b32(ell64, &u);
+ secp256k1_fe_get_b32(ell64 + 32, &t);
+ return 1;
+ }
+ /* Only returned in case the provided pubkey is invalid. */
+ return 0;
+}
+
+int secp256k1_ellswift_create(const secp256k1_context* ctx, unsigned char *ell64, const unsigned char *seckey32, const unsigned char *rnd32) {
+ secp256k1_ge p;
+ secp256k1_fe u, t;
+ secp256k1_sha256 hash;
+ secp256k1_scalar seckey_scalar;
+ static const unsigned char PREFIX[32] = "secp256k1_ellswift_create";
+ static const unsigned char ZERO[32] = {0};
+ int ret = 0;
+
+ /* Sanity check inputs. */
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(ell64 != NULL);
+ memset(ell64, 0, 64);
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(seckey32 != NULL);
+
+ /* Compute (affine) public key */
+ ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey32);
+ secp256k1_fe_normalize_var(&p.x);
+ secp256k1_fe_normalize_var(&p.y);
+
+ /* Set up hasher state */
+ secp256k1_sha256_initialize(&hash);
+ secp256k1_sha256_write(&hash, PREFIX, sizeof(PREFIX));
+ secp256k1_sha256_write(&hash, seckey32, 32);
+ secp256k1_sha256_write(&hash, rnd32 ? rnd32 : ZERO, 32);
+ secp256k1_sha256_write(&hash, ZERO, 32 - 9 - 4);
+
+ /* Compute ElligatorSwift encoding and construct output. */
+ secp256k1_ellswift_ge_to_fe2_var(&u, &t, &p, &hash);
+ secp256k1_fe_get_b32(ell64, &u);
+ secp256k1_fe_get_b32(ell64 + 32, &t);
+
+ secp256k1_memczero(ell64, 64, !ret);
+ secp256k1_scalar_clear(&seckey_scalar);
+
+ return ret;
+}
+
+int secp256k1_ellswift_decode(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *ell64) {
+ secp256k1_fe u, t;
+ secp256k1_ge p;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(pubkey != NULL);
+ ARG_CHECK(ell64 != NULL);
+
+ secp256k1_fe_set_b32(&u, ell64);
+ secp256k1_fe_normalize_var(&u);
+ secp256k1_fe_set_b32(&t, ell64 + 32);
+ secp256k1_fe_normalize_var(&t);
+ secp256k1_ellswift_fe2_to_ge_var(&p, &u, &t);
+ secp256k1_pubkey_save(pubkey, &p);
+ return 1;
+}
+
+static int ellswift_xdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *ours64, const unsigned char *theirs64, void *data) {
+ secp256k1_sha256 sha;
+
+ (void)data;
+
+ secp256k1_sha256_initialize(&sha);
+ if (secp256k1_memcmp_var(ours64, theirs64, 64) <= 0) {
+ secp256k1_sha256_write(&sha, ours64, 64);
+ secp256k1_sha256_write(&sha, theirs64, 64);
+ } else {
+ secp256k1_sha256_write(&sha, theirs64, 64);
+ secp256k1_sha256_write(&sha, ours64, 64);
+ }
+ secp256k1_sha256_write(&sha, x32, 32);
+ secp256k1_sha256_finalize(&sha, output);
+
+ return 1;
+}
+
+const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_sha256 = ellswift_xdh_hash_function_sha256;
+const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_default = ellswift_xdh_hash_function_sha256;
+
+int secp256k1_ellswift_xdh(const secp256k1_context* ctx, unsigned char *output, const unsigned char* theirs64, const unsigned char* ours64, const unsigned char* seckey32, secp256k1_ellswift_xdh_hash_function hashfp, void *data) {
+ int ret = 0;
+ int overflow;
+ secp256k1_scalar s;
+ secp256k1_fe xn, xd, px, u, t;
+ unsigned char sx[32];
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(output != NULL);
+ ARG_CHECK(theirs64 != NULL);
+ ARG_CHECK(ours64 != NULL);
+ ARG_CHECK(seckey32 != NULL);
+
+ if (hashfp == NULL) {
+ hashfp = secp256k1_ellswift_xdh_hash_function_default;
+ }
+
+ /* Load remote public key (as fraction). */
+ secp256k1_fe_set_b32(&u, theirs64);
+ secp256k1_fe_normalize_var(&u);
+ secp256k1_fe_set_b32(&t, theirs64 + 32);
+ secp256k1_fe_normalize_var(&t);
+ secp256k1_ellswift_fe2_to_gexfrac_var(&xn, &xd, &u, &t);
+
+ /* Load private key (using one if invalid). */
+ secp256k1_scalar_set_b32(&s, seckey32, &overflow);
+ overflow = secp256k1_scalar_is_zero(&s);
+ secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
+
+ /* Compute shared X coordinate. */
+ secp256k1_ecmult_const_xonly(&px, &xn, &xd, &s, 256, 1);
+ secp256k1_fe_normalize(&px);
+ secp256k1_fe_get_b32(sx, &px);
+
+ /* Invoke hasher */
+ ret = hashfp(output, sx, ours64, theirs64, data);
+
+ memset(sx, 0, 32);
+ secp256k1_fe_clear(&px);
+ secp256k1_scalar_clear(&s);
+
+ return !!ret & !overflow;
+}
+
+#endif
diff --git a/src/modules/ellswift/tests_impl.h b/src/modules/ellswift/tests_impl.h
new file mode 100644
index 0000000000..699a9496d0
--- /dev/null
+++ b/src/modules/ellswift/tests_impl.h
@@ -0,0 +1,193 @@
+/***********************************************************************
+ * Copyright (c) 2022 Pieter Wuile *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
+ ***********************************************************************/
+
+#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_H
+#define SECP256K1_MODULE_ELLSWIFT_TESTS_H
+
+#include "../../../include/secp256k1_ellswift.h"
+
+struct ellswift_test_vec {
+ int enc_bitmap;
+ secp256k1_fe u;
+ secp256k1_fe x;
+ secp256k1_fe encs[8];
+};
+
+/* Set of (point, encodings) test vectors, selected to maximize branch coverage.
+ * Created using an independent implementation, and tested against paper author's code. */
+static const struct ellswift_test_vec ellswift_tests[] = {
+ {0x33, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), {SECP256K1_FE_CONST(0x2c8864a8, 0xc34e87d7, 0x53ee7300, 0x8bbed54a, 0x47b37907, 0x56d0b747, 0x10341b37, 0xf598a5fe), SECP256K1_FE_CONST(0x15908d62, 0x2377bedc, 0x0fecf55f, 0xcc6425c9, 0xde992fcb, 0x01af2628, 0xac40f220, 0x88de01f0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xd3779b57, 0x3cb17828, 0xac118cff, 0x74412ab5, 0xb84c86f8, 0xa92f48b8, 0xefcbe4c7, 0x0a675631), SECP256K1_FE_CONST(0xea6f729d, 0xdc884123, 0xf0130aa0, 0x339bda36, 0x2166d034, 0xfe50d9d7, 0x53bf0dde, 0x7721fa3f), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x44, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x4218f20a, 0xe6c646b3, 0x63db6860, 0x5822fb14, 0x264ca8d2, 0x587fdd6f, 0xbc750d58, 0x7e76a7ee), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xbde70df5, 0x1939b94c, 0x9c24979f, 0xa7dd04eb, 0xd9b3572d, 0xa7802290, 0x438af2a6, 0x81895441), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), SECP256K1_FE_CONST(0x31d8011e, 0x503be7cd, 0x04ed2465, 0x4f09771e, 0x721346f2, 0x2c5b5fee, 0x14f5c5c1, 0x56167823), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), SECP256K1_FE_CONST(0xb8438fb4, 0x2a2cead9, 0xace238da, 0x755840bf, 0x6ca51d4c, 0x6eb4074c, 0x43b215de, 0x5711e680), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), SECP256K1_FE_CONST(0xf5df3913, 0x4f41d9f0, 0xa9c7c4ad, 0xa1c76e02, 0xc92d9e3f, 0xd5de26f4, 0x7e39e55e, 0xef6d1717), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x1db9675d, 0x54da4f19, 0x8bc3ba39, 0xc91d945a, 0x30eb2963, 0xc63eb119, 0x606d6a45, 0xc857dbe0), SECP256K1_FE_CONST(0x3b9efb64, 0xe9d56bf7, 0xee4bc029, 0x288e000e, 0x875be218, 0xd92fca16, 0xda6b82fe, 0xb7035c86), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xe24698a2, 0xab25b0e6, 0x743c45c6, 0x36e26ba5, 0xcf14d69c, 0x39c14ee6, 0x9f9295b9, 0x37a8204f), SECP256K1_FE_CONST(0xc461049b, 0x162a9408, 0x11b43fd6, 0xd771fff1, 0x78a41de7, 0x26d035e9, 0x25947d00, 0x48fc9fa9)}},
+ {0x00, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), SECP256K1_FE_CONST(0x7975920f, 0x7dd28f06, 0x0b90de63, 0xaa069e8c, 0x34858639, 0xf4a77e0d, 0x9774649e, 0xb9087bac), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), SECP256K1_FE_CONST(0x3125472c, 0x4bca81e7, 0xfa8493d7, 0x253f29c8, 0x8a51d3ec, 0x7afefaae, 0x19f87a91, 0xc6c35775), {SECP256K1_FE_CONST(0x3a14b35f, 0x5b086a06, 0xf6b746cb, 0x79730ca2, 0x202855e7, 0xe1bbfdca, 0x1aa809bd, 0x810ff058), SECP256K1_FE_CONST(0xe116acef, 0x46c0d624, 0x6dc90c90, 0x714ad693, 0x47b24bdc, 0x2b07c677, 0xa7a24d13, 0xcba4d6ec), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xc5eb4ca0, 0xa4f795f9, 0x0948b934, 0x868cf35d, 0xdfd7aa18, 0x1e440235, 0xe557f641, 0x7ef00bd7), SECP256K1_FE_CONST(0x1ee95310, 0xb93f29db, 0x9236f36f, 0x8eb5296c, 0xb84db423, 0xd4f83988, 0x585db2eb, 0x345b2543), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), SECP256K1_FE_CONST(0x7f39a9ef, 0x29f9d846, 0x5a1a18e1, 0x3ed5d07b, 0x613f8094, 0x96700779, 0xd81d8e89, 0x59b2e8c5), {SECP256K1_FE_CONST(0x1788e280, 0x7a2a0adc, 0xeb6cfa2e, 0xa176478b, 0xaee9b178, 0xbd2c3819, 0xe56e54c2, 0x6e4fccbd), SECP256K1_FE_CONST(0xc5983497, 0x8137ee51, 0xb41566c7, 0xb56c7df1, 0xe9ccd528, 0xfe0db5da, 0x33c95ff8, 0xf1b96212), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xe8771d7f, 0x85d5f523, 0x149305d1, 0x5e89b874, 0x51164e87, 0x42d3c7e6, 0x1a91ab3c, 0x91b02f72), SECP256K1_FE_CONST(0x3a67cb68, 0x7ec811ae, 0x4bea9938, 0x4a93820e, 0x16332ad7, 0x01f24a25, 0xcc36a006, 0x0e469a1d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), SECP256K1_FE_CONST(0xf30a866b, 0x849cd237, 0x534f9089, 0xaed6bfcf, 0x8dd9952b, 0xd77346f6, 0xd426158b, 0xc82be41a), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xff, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), SECP256K1_FE_CONST(0xdd7328f6, 0x725a645a, 0x4224d125, 0x455291fb, 0x3eeabb13, 0x6151926f, 0x5ca6d4c2, 0x849e3ef6), {SECP256K1_FE_CONST(0x362565da, 0x03102cb1, 0x084ab68f, 0xb28babcc, 0x3f9165e2, 0x4070e29a, 0x238ca4d1, 0x88b0c8ad), SECP256K1_FE_CONST(0xa3e8fec6, 0x1c9c7267, 0xda96f709, 0x958f8065, 0xaf5a59c2, 0xe2375058, 0x4b7ccc68, 0x6f31cf07), SECP256K1_FE_CONST(0x38c4364d, 0x829d26d1, 0xfd5d0080, 0xf399db60, 0xe3ff1836, 0xaff5d615, 0x42fc04b5, 0xdc690ffd), SECP256K1_FE_CONST(0x6d6333ac, 0x7a4cbac0, 0x458657c3, 0x898bf188, 0x30d4ba43, 0xf7ce7115, 0x54f3d846, 0x6023d718), SECP256K1_FE_CONST(0xc9da9a25, 0xfcefd34e, 0xf7b54970, 0x4d745433, 0xc06e9a1d, 0xbf8f1d65, 0xdc735b2d, 0x774f3382), SECP256K1_FE_CONST(0x5c170139, 0xe3638d98, 0x256908f6, 0x6a707f9a, 0x50a5a63d, 0x1dc8afa7, 0xb4833396, 0x90ce2d28), SECP256K1_FE_CONST(0xc73bc9b2, 0x7d62d92e, 0x02a2ff7f, 0x0c66249f, 0x1c00e7c9, 0x500a29ea, 0xbd03fb49, 0x2396ec32), SECP256K1_FE_CONST(0x929ccc53, 0x85b3453f, 0xba79a83c, 0x76740e77, 0xcf2b45bc, 0x08318eea, 0xab0c27b8, 0x9fdc2517)}},
+ {0xcc, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), SECP256K1_FE_CONST(0xf0f46c7e, 0x8c23f563, 0x18550c00, 0x2ef33695, 0x01220ba3, 0xe25cb308, 0x4013711f, 0xb679743f), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x8e574be1, 0xbba447e9, 0x85f3ee1f, 0x4940c0ee, 0x27087f6d, 0xfb739fdd, 0x05aa1bb3, 0xfbc5b224), SECP256K1_FE_CONST(0xd1c89542, 0x677cfeb2, 0xf20712a2, 0x35033c21, 0x2b7a7446, 0xbc99894f, 0xd2d0651f, 0x20b75905), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x71a8b41e, 0x445bb816, 0x7a0c11e0, 0xb6bf3f11, 0xd8f78092, 0x048c6022, 0xfa55e44b, 0x043a4a0b), SECP256K1_FE_CONST(0x2e376abd, 0x9883014d, 0x0df8ed5d, 0xcafcc3de, 0xd4858bb9, 0x436676b0, 0x2d2f9adf, 0xdf48a32a)}},
+ {0x33, SECP256K1_FE_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffc2e), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), {SECP256K1_FE_CONST(0x2bd4bfb6, 0x851f02c7, 0xb9e42ee0, 0x1243906f, 0x0272ec4e, 0xad1781cc, 0x345affbc, 0x83aa54ef), SECP256K1_FE_CONST(0x3750ab59, 0xd50a6745, 0x5be4edb0, 0x71f0e82f, 0x370010ec, 0xd7a84a5b, 0x66549448, 0x3a07a6f6), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xd42b4049, 0x7ae0fd38, 0x461bd11f, 0xedbc6f90, 0xfd8d13b1, 0x52e87e33, 0xcba50042, 0x7c55a740), SECP256K1_FE_CONST(0xc8af54a6, 0x2af598ba, 0xa41b124f, 0x8e0f17d0, 0xc8ffef13, 0x2857b5a4, 0x99ab6bb6, 0xc5f85539), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ffffe18), SECP256K1_FE_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffc13), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xefbd23d5, 0x2ebf879f, 0x228dbeb0, 0x5c85881a, 0xdb886b53, 0x23bda366, 0x4520a05e, 0x6c549854), SECP256K1_FE_CONST(0x1326b8de, 0x9cad16c3, 0xc859d692, 0xfbc6c22a, 0x78698964, 0x86e0b713, 0x174982af, 0x7d28eb8d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x1042dc2a, 0xd1407860, 0xdd72414f, 0xa37a77e5, 0x247794ac, 0xdc425c99, 0xbadf5fa0, 0x93ab63db), SECP256K1_FE_CONST(0xecd94721, 0x6352e93c, 0x37a6296d, 0x04393dd5, 0x8796769b, 0x791f48ec, 0xe8b67d4f, 0x82d710a2)}},
+ {0xff, SECP256K1_FE_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ffffe17), SECP256K1_FE_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffc13), {SECP256K1_FE_CONST(0x6342f23b, 0x31f75ef3, 0x861b36fc, 0x33383cfb, 0x43d08212, 0xe42ad82b, 0x5b397b00, 0x005ebee7), SECP256K1_FE_CONST(0xf3d7c0d4, 0x14a2d008, 0x4251039d, 0x4ad2978e, 0x0c5a2094, 0x5f21755b, 0xf3873e00, 0x2c359f65), SECP256K1_FE_CONST(0xa14a6f4e, 0x4006cb83, 0x7201f076, 0x58ca4e2e, 0x369402df, 0xa5b9a6a2, 0x6522fd67, 0x3916dfa4), SECP256K1_FE_CONST(0x8beba960, 0x40d7d2bd, 0xb9af082d, 0xfc7ff55f, 0x29e55f15, 0xa6826848, 0x6dd89b37, 0x3cb586b1), SECP256K1_FE_CONST(0x9cbd0dc4, 0xce08a10c, 0x79e4c903, 0xccc7c304, 0xbc2f7ded, 0x1bd527d4, 0xa4c684fe, 0xffa13d48), SECP256K1_FE_CONST(0x0c283f2b, 0xeb5d2ff7, 0xbdaefc62, 0xb52d6871, 0xf3a5df6b, 0xa0de8aa4, 0x0c78c1fe, 0xd3ca5cca), SECP256K1_FE_CONST(0x5eb590b1, 0xbff9347c, 0x8dfe0f89, 0xa735b1d1, 0xc96bfd20, 0x5a46595d, 0x9add0297, 0xc6e91c8b), SECP256K1_FE_CONST(0x7414569f, 0xbf282d42, 0x4650f7d2, 0x03800aa0, 0xd61aa0ea, 0x597d97b7, 0x922764c7, 0xc34a757e)}},
+ {0x00, SECP256K1_FE_CONST(0x6e340b9c, 0xffb37a98, 0x9ca544e6, 0xbb780a2c, 0x78901d3f, 0xb3373876, 0x8511a306, 0x17afa01d), SECP256K1_FE_CONST(0x91cbf463, 0x004c8567, 0x635abb19, 0x4487f5d3, 0x876fe2c0, 0x4cc8c789, 0x7aee5cf8, 0xe8505c12), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x77, SECP256K1_FE_CONST(0x6e340b9c, 0xffb37a98, 0x9ca544e6, 0xbb780a2c, 0x78901d3f, 0xb3373876, 0x8511a306, 0x17afa01d), SECP256K1_FE_CONST(0x161462dd, 0x57fffa52, 0x1137bcd7, 0x9ed6981a, 0x726e402a, 0xc56b081c, 0x2bbe912e, 0x3132360d), {SECP256K1_FE_CONST(0x51fe8154, 0x3cba720f, 0x207dab99, 0x1262b65e, 0xa1b89324, 0x25fd389b, 0xcdb6a339, 0x7b045976), SECP256K1_FE_CONST(0x866f19a8, 0xdda199c9, 0x22157b84, 0x46ded073, 0xa4d67b2e, 0x893675dd, 0xd99aaaba, 0xe7bf1a25), SECP256K1_FE_CONST(0xae574801, 0x101b2890, 0xd3c2d4ba, 0xc6cb4559, 0x0d9ebe59, 0x6e75638a, 0xa8d65f54, 0xc56f6004), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xae017eab, 0xc3458df0, 0xdf825466, 0xed9d49a1, 0x5e476cdb, 0xda02c764, 0x32495cc5, 0x84fba2b9), SECP256K1_FE_CONST(0x7990e657, 0x225e6636, 0xddea847b, 0xb9212f8c, 0x5b2984d1, 0x76c98a22, 0x26655544, 0x1840e20a), SECP256K1_FE_CONST(0x51a8b7fe, 0xefe4d76f, 0x2c3d2b45, 0x3934baa6, 0xf26141a6, 0x918a9c75, 0x5729a0aa, 0x3a909c2b), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0x6e340b9c, 0xffb37a98, 0x9ca544e6, 0xbb780a2c, 0x78901d3f, 0xb3373876, 0x8511a306, 0x17afa01d), SECP256K1_FE_CONST(0x2c1c4d0d, 0x41ecda63, 0xb4131edb, 0x65fef49e, 0xf3f6b770, 0x00de1432, 0xc21355a4, 0x2ad19091), {SECP256K1_FE_CONST(0xa1b6e32d, 0x9a3b31b5, 0xecad712f, 0x72bfe460, 0x587dcea9, 0x5c6c65c1, 0xaa1dad5a, 0xa4cf57c0), SECP256K1_FE_CONST(0xf5696de5, 0x3dba0943, 0xafe12a72, 0x0049b0a8, 0x6f6cde0e, 0xd4a5eb64, 0xb7f52a8b, 0x464cbedb), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x5e491cd2, 0x65c4ce4a, 0x13528ed0, 0x8d401b9f, 0xa7823156, 0xa3939a3e, 0x55e252a4, 0x5b30a46f), SECP256K1_FE_CONST(0x0a96921a, 0xc245f6bc, 0x501ed58d, 0xffb64f57, 0x909321f1, 0x2b5a149b, 0x480ad573, 0xb9b33d54), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0x4bf5122f, 0x344554c5, 0x3bde2ebb, 0x8cd2b7e3, 0xd1600ad6, 0x31c385a5, 0xd7cce23c, 0x7785459a), SECP256K1_FE_CONST(0x71a59aaa, 0x83bff3a0, 0x53323c20, 0xa43aa0ff, 0x3b17f582, 0xd245ba85, 0xb2ad61cf, 0x91df00bf), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xaa89b76b, 0x710916f7, 0x7e57e7bf, 0xd726ad9d, 0x27e90d86, 0x18903b0a, 0x1852b680, 0x478b687c), SECP256K1_FE_CONST(0x6fa74a38, 0x06a04766, 0xdd1d2ed9, 0x81466c12, 0x8ec84ade, 0x00ff9883, 0xb4354956, 0x0834fde1), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x55764894, 0x8ef6e908, 0x81a81840, 0x28d95262, 0xd816f279, 0xe76fc4f5, 0xe7ad497e, 0xb87493b3), SECP256K1_FE_CONST(0x9058b5c7, 0xf95fb899, 0x22e2d126, 0x7eb993ed, 0x7137b521, 0xff00677c, 0x4bcab6a8, 0xf7cafe4e)}},
+ {0xcc, SECP256K1_FE_CONST(0xe52d9c50, 0x8c502347, 0x344d8c07, 0xad91cbd6, 0x068afc75, 0xff6292f0, 0x62a09ca3, 0x81c89e71), SECP256K1_FE_CONST(0x1ad263af, 0x73afdcb8, 0xcbb273f8, 0x526e3429, 0xf975038a, 0x009d6d0f, 0x9d5f635b, 0x7e375dbe), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb8d1cbd7, 0x33ae8215, 0x642c30af, 0x7cedc7ef, 0x73be8269, 0xfbcc1fb5, 0x44ab3dee, 0xdbea1af4), SECP256K1_FE_CONST(0x945290ca, 0x86af703c, 0x1e0bed9d, 0xf1514972, 0x4357fb2b, 0x8d2382ce, 0x6c2794bf, 0xd14efe9c), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x472e3428, 0xcc517dea, 0x9bd3cf50, 0x83123810, 0x8c417d96, 0x0433e04a, 0xbb54c210, 0x2415e13b), SECP256K1_FE_CONST(0x6bad6f35, 0x79508fc3, 0xe1f41262, 0x0eaeb68d, 0xbca804d4, 0x72dc7d31, 0x93d86b3f, 0x2eb0fd93)}},
+ {0x00, SECP256K1_FE_CONST(0xe52d9c50, 0x8c502347, 0x344d8c07, 0xad91cbd6, 0x068afc75, 0xff6292f0, 0x62a09ca3, 0x81c89e71), SECP256K1_FE_CONST(0x2a58379a, 0x649cd129, 0x3b83c6f8, 0x59fa83fe, 0xa9850a31, 0x5bd1d7aa, 0xfda9b4b3, 0x25e37402), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0x67586e98, 0xfad27da0, 0xb9968bc0, 0x39a1ef34, 0xc939b9b8, 0xe523a8be, 0xf89d4786, 0x08c5ecf6), SECP256K1_FE_CONST(0x98a79167, 0x052d825f, 0x4669743f, 0xc65e10cb, 0x36c64647, 0x1adc5741, 0x0762b878, 0xf73a0f39), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0x67586e98, 0xfad27da0, 0xb9968bc0, 0x39a1ef34, 0xc939b9b8, 0xe523a8be, 0xf89d4786, 0x08c5ecf6), SECP256K1_FE_CONST(0x15a4118b, 0x47af907e, 0xd47bc9cd, 0x722f3641, 0x134228bd, 0x78c1934b, 0x615136f8, 0x3a35675c), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x44, SECP256K1_FE_CONST(0x01ba4719, 0xc80b6fe9, 0x11b091a7, 0xc05124b6, 0x4eeece96, 0x4e09c058, 0xef8f9805, 0xdaca546b), SECP256K1_FE_CONST(0xbcfa28ac, 0x31453f0e, 0x2ea23512, 0x37dac2de, 0x92e5bbb5, 0xaebfd7bc, 0x3c5a2cae, 0x57c5440f), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x6fa317d3, 0x93c1632e, 0x73ea7133, 0xb38b0904, 0x670b85c1, 0xf48efa45, 0xcc8c2459, 0xd1463610), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x905ce82c, 0x6c3e9cd1, 0x8c158ecc, 0x4c74f6fb, 0x98f47a3e, 0x0b7105ba, 0x3373dba5, 0x2eb9c61f), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0xef6cbd21, 0x61eaea79, 0x43ce8693, 0xb9824d23, 0xd1793ffb, 0x1c0fca05, 0xb600d389, 0x9b44c977), SECP256K1_FE_CONST(0x129374d7, 0x73a60424, 0x662d54d6, 0xe8eba424, 0x38c8c9a7, 0x701a59dc, 0x8fbd0fbb, 0xe6094899), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x1b65b9d9, 0x1eda84f6, 0x9a068601, 0x70c9c4e9, 0xd43cd0f2, 0x53ec9b13, 0x0f6c2b3d, 0xd949b672), SECP256K1_FE_CONST(0xb5139bd2, 0x4e8e8a6e, 0x5d0875f3, 0x58e3d884, 0xf7f9836d, 0x893fdae8, 0x86cbc6f9, 0x1fd2f993), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xe49a4626, 0xe1257b09, 0x65f979fe, 0x8f363b16, 0x2bc32f0d, 0xac1364ec, 0xf093d4c1, 0x26b645bd), SECP256K1_FE_CONST(0x4aec642d, 0xb1717591, 0xa2f78a0c, 0xa71c277b, 0x08067c92, 0x76c02517, 0x79343905, 0xe02d029c)}},
+ {0x33, SECP256K1_FE_CONST(0xdc0e9c36, 0x58a1a3ed, 0x1ec94274, 0xd8b19925, 0xc93e1abb, 0x7ddba294, 0x923ad9bd, 0xe30f8cb8), SECP256K1_FE_CONST(0x23f163c9, 0xa75e5c12, 0xe136bd8b, 0x274e66da, 0x36c1e544, 0x82245d6b, 0x6dc52641, 0x1cf06f77), {SECP256K1_FE_CONST(0x8245e76e, 0xd8605614, 0xa33447db, 0xdcd4b712, 0x3b80c63f, 0xd0809c87, 0x7b134540, 0x63732da2), SECP256K1_FE_CONST(0x9e474ae5, 0x1714465b, 0x33293068, 0x569fe336, 0x174fb0dc, 0x259049d7, 0x6917ce59, 0x07b6dcff), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x7dba1891, 0x279fa9eb, 0x5ccbb824, 0x232b48ed, 0xc47f39c0, 0x2f7f6378, 0x84ecbabe, 0x9c8cce8d), SECP256K1_FE_CONST(0x61b8b51a, 0xe8ebb9a4, 0xccd6cf97, 0xa9601cc9, 0xe8b04f23, 0xda6fb628, 0x96e831a5, 0xf8491f30), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xff, SECP256K1_FE_CONST(0xc555eab4, 0x5d08845a, 0xe9f10d45, 0x2a99bfcb, 0x06f74a50, 0xb988fe7e, 0x48dd3237, 0x89b88ee3), SECP256K1_FE_CONST(0x356b434d, 0x1ef1666c, 0xf7d19635, 0x94a3bdad, 0x982f46ab, 0x3cbdd705, 0x9e1bd9ab, 0x0b7e1686), {SECP256K1_FE_CONST(0x5439b77f, 0x597b2e6f, 0xe48c3f46, 0x599a18fa, 0x0ae89a7a, 0xf778c1dc, 0x886793c8, 0x0fe616ee), SECP256K1_FE_CONST(0xbd6ec9c1, 0x2a329529, 0xf15dfc85, 0xc4526169, 0x5d0767c7, 0x7b4f13ea, 0x91395718, 0x07f3b290), SECP256K1_FE_CONST(0x55715e7f, 0x5d440cc8, 0x3a4010d0, 0x34221026, 0xbcee7131, 0x6217b016, 0xb90dfee7, 0x60a48608), SECP256K1_FE_CONST(0x7e2af404, 0x24b93bf0, 0x1d143213, 0x30df30a2, 0x09678d47, 0xccd5135e, 0x739e4028, 0x26844028), SECP256K1_FE_CONST(0xabc64880, 0xa684d190, 0x1b73c0b9, 0xa665e705, 0xf5176585, 0x08873e23, 0x77986c36, 0xf019e541), SECP256K1_FE_CONST(0x4291363e, 0xd5cd6ad6, 0x0ea2037a, 0x3bad9e96, 0xa2f89838, 0x84b0ec15, 0x6ec6a8e6, 0xf80c499f), SECP256K1_FE_CONST(0xaa8ea180, 0xa2bbf337, 0xc5bfef2f, 0xcbddefd9, 0x43118ece, 0x9de84fe9, 0x46f20117, 0x9f5b7627), SECP256K1_FE_CONST(0x81d50bfb, 0xdb46c40f, 0xe2ebcdec, 0xcf20cf5d, 0xf69872b8, 0x332aeca1, 0x8c61bfd6, 0xd97bbc07)}},
+ {0x33, SECP256K1_FE_CONST(0xab897fbd, 0xedfa502b, 0x2d839b6a, 0x56100887, 0xdccdc507, 0x555c282e, 0x59589e06, 0x300a62e2), SECP256K1_FE_CONST(0x3119ceb1, 0xe5e26b7b, 0x1a85520b, 0xaec3ad2c, 0x5661a453, 0xec37f4c6, 0xfae6be04, 0x905fed19), {SECP256K1_FE_CONST(0xa7698f80, 0xa9f7d4f1, 0x4973086b, 0x258934fb, 0x85f056a1, 0xcc824068, 0x70555d65, 0xa5c77c9d), SECP256K1_FE_CONST(0xf5284d8f, 0xc6ee63f5, 0x9511b121, 0xf4fb6105, 0x11b38678, 0x577a2a74, 0xe151f484, 0xfa980ce7), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x5896707f, 0x56082b0e, 0xb68cf794, 0xda76cb04, 0x7a0fa95e, 0x337dbf97, 0x8faaa299, 0x5a387f92), SECP256K1_FE_CONST(0x0ad7b270, 0x39119c0a, 0x6aee4ede, 0x0b049efa, 0xee4c7987, 0xa885d58b, 0x1eae0b7a, 0x0567ef48), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0xbd4fc42a, 0x21f1f860, 0xa1030e6e, 0xba23d53e, 0xcab71bd1, 0x9297ab6c, 0x074381d4, 0xecee0018), SECP256K1_FE_CONST(0x503cffcb, 0xc1e36f3c, 0x517b387a, 0xd7cbc856, 0x576627d1, 0x4c500c68, 0x33d17039, 0xbb652c96), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0x8a331fdd, 0xe7032f33, 0xa71e1b2e, 0x257d8016, 0x6e348e00, 0xfcb17914, 0xf48bdb57, 0xa1c63007), SECP256K1_FE_CONST(0x5796039b, 0xb8d1bc43, 0x7e7be940, 0x5259919f, 0xc3436f9c, 0xcfd03f91, 0x4c655809, 0x066c7412), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xf4ec92d2, 0xa1c536c0, 0x3ec32f1b, 0x189f29a2, 0x928ca492, 0x00e81d6e, 0x3e21d469, 0x5458ce50), SECP256K1_FE_CONST(0xf746d123, 0x702173df, 0x05b05807, 0x67a764fe, 0x71c5d1dc, 0xb9aba858, 0xa862814f, 0xa31faf3d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x0b136d2d, 0x5e3ac93f, 0xc13cd0e4, 0xe760d65d, 0x6d735b6d, 0xff17e291, 0xc1de2b95, 0xaba72ddf), SECP256K1_FE_CONST(0x08b92edc, 0x8fde8c20, 0xfa4fa7f8, 0x98589b01, 0x8e3a2e23, 0x465457a7, 0x579d7eaf, 0x5ce04cf2)}},
+ {0xff, SECP256K1_FE_CONST(0x8a5edab2, 0x82632443, 0x219e051e, 0x4ade2d1d, 0x5bbc671c, 0x781051bf, 0x1437897c, 0xbdfea0f1), SECP256K1_FE_CONST(0x75a1254d, 0x7d9cdbbc, 0xde61fae1, 0xb521d2e2, 0xa44398e3, 0x87efae40, 0xebc87682, 0x42015b3e), {SECP256K1_FE_CONST(0xd7a081ca, 0xf5521f4d, 0xb4f7c478, 0x35ab68a8, 0x217980e6, 0xdad52704, 0xc70b9ba2, 0x14ee14b0), SECP256K1_FE_CONST(0x195dcf2d, 0xa9578581, 0xefa8f64c, 0xa9d6ed4b, 0x8d95e4d0, 0x058fec92, 0x789ad40d, 0xa38c63bb), SECP256K1_FE_CONST(0x52235236, 0x41d891c9, 0x536b9668, 0x46f2af60, 0x028fbd88, 0xac20cad5, 0xc6890a04, 0x886ccc5b), SECP256K1_FE_CONST(0x84e5bc30, 0x521d45e4, 0x0783f049, 0x740067b1, 0x57bfb6d7, 0x71484329, 0x6daba2c9, 0xfc8949fd), SECP256K1_FE_CONST(0x285f7e35, 0x0aade0b2, 0x4b083b87, 0xca549757, 0xde867f19, 0x252ad8fb, 0x38f4645c, 0xeb11e77f), SECP256K1_FE_CONST(0xe6a230d2, 0x56a87a7e, 0x105709b3, 0x562912b4, 0x726a1b2f, 0xfa70136d, 0x87652bf1, 0x5c739874), SECP256K1_FE_CONST(0xaddcadc9, 0xbe276e36, 0xac946997, 0xb90d509f, 0xfd704277, 0x53df352a, 0x3976f5fa, 0x77932fd4), SECP256K1_FE_CONST(0x7b1a43cf, 0xade2ba1b, 0xf87c0fb6, 0x8bff984e, 0xa8404928, 0x8eb7bcd6, 0x92545d35, 0x0376b232)}},
+ {0x00, SECP256K1_FE_CONST(0xe7f6c011, 0x776e8db7, 0xcd330b54, 0x174fd76f, 0x7d0216b6, 0x12387a5f, 0xfcfb81e6, 0xf0919683), SECP256K1_FE_CONST(0x2838007a, 0x22e59acb, 0xe2f7e413, 0xd2327157, 0x1c83200f, 0xca4a029d, 0x5b84990f, 0xc3b96177), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}
+};
+
+/** This is a hasher for ellswift_xdh which just returns the shared X coordinate.
+ *
+ * This is generally a bad idea as it means changes to the encoding of the
+ * exchanged public keys do not affect the shared secret. However, it's used here
+ * in tests to be able to verify the X coordinate through other means.
+ */
+static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32, const unsigned char *ours64, const unsigned char *theirs64, void *data) {
+ (void)ours64;
+ (void)theirs64;
+ (void)data;
+ memcpy(output, x32, 32);
+ return 1;
+}
+
+void run_ellswift_tests(void) {
+ int i = 0;
+ /* Test vectors. */
+ for (i = 0; (unsigned)i < sizeof(ellswift_tests) / sizeof(ellswift_tests[0]); ++i) {
+ const struct ellswift_test_vec* testcase = &ellswift_tests[i];
+ int c;
+ for (c = 0; c < 8; ++c) {
+ secp256k1_fe t;
+ int ret = secp256k1_ellswift_fegex_to_fe_var(&t, &testcase->x, &testcase->u, c);
+ CHECK(ret == ((testcase->enc_bitmap >> c) & 1));
+ if (ret) {
+ secp256k1_fe x2;
+ CHECK(check_fe_equal(&t, &testcase->encs[c]));
+ secp256k1_ellswift_fe2_to_gex_var(&x2, &testcase->u, &testcase->encs[c]);
+ CHECK(check_fe_equal(&testcase->x, &x2));
+ }
+ }
+ }
+ /* Verify that secp256k1_ellswift_encode + decode roundtrips. */
+ for (i = 0; i < 1000 * count; i++) {
+ unsigned char rnd32[32];
+ unsigned char ell64[64];
+ secp256k1_ge g, g2;
+ secp256k1_pubkey pubkey, pubkey2;
+ /* Generate random public key and random randomizer. */
+ random_group_element_test(&g);
+ secp256k1_pubkey_save(&pubkey, &g);
+ secp256k1_testrand256(rnd32);
+ /* Convert the public key to ElligatorSwift and back. */
+ secp256k1_ellswift_encode(ctx, ell64, &pubkey, rnd32);
+ secp256k1_ellswift_decode(ctx, &pubkey2, ell64);
+ secp256k1_pubkey_load(ctx, &g2, &pubkey2);
+ /* Compare with original. */
+ ge_equals_ge(&g, &g2);
+ }
+ /* Verify the behavior of secp256k1_ellswift_create */
+ for (i = 0; i < 400 * count; i++) {
+ unsigned char rnd32[32], sec32[32];
+ secp256k1_scalar sec;
+ secp256k1_gej res;
+ secp256k1_ge dec;
+ secp256k1_pubkey pub;
+ unsigned char ell64[64];
+ int ret;
+ /* Generate random secret key and random randomizer. */
+ secp256k1_testrand256_test(rnd32);
+ random_scalar_order_test(&sec);
+ secp256k1_scalar_get_b32(sec32, &sec);
+ /* Construct ElligatorSwift-encoded public keys for that key. */
+ ret = secp256k1_ellswift_create(ctx, ell64, sec32, rnd32);
+ CHECK(ret);
+ /* Decode it, and compare with traditionally-computed public key. */
+ secp256k1_ellswift_decode(ctx, &pub, ell64);
+ secp256k1_pubkey_load(ctx, &dec, &pub);
+ secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec);
+ ge_equals_gej(&dec, &res);
+ }
+ /* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate. */
+ for (i = 0; i < 800 * count; i++) {
+ unsigned char ell64[64], sec32[32], share32[32];
+ secp256k1_scalar sec;
+ secp256k1_ge dec, res;
+ secp256k1_fe share_x;
+ secp256k1_gej decj, resj;
+ secp256k1_pubkey pub;
+ int ret;
+ /* Generate random secret key. */
+ random_scalar_order_test(&sec);
+ secp256k1_scalar_get_b32(sec32, &sec);
+ /* Generate random ElligatorSwift encoding for the remote key and decode it. */
+ secp256k1_testrand256_test(ell64);
+ secp256k1_testrand256_test(ell64 + 32);
+ secp256k1_ellswift_decode(ctx, &pub, ell64);
+ secp256k1_pubkey_load(ctx, &dec, &pub);
+ secp256k1_gej_set_ge(&decj, &dec);
+ /* Compute the X coordinate of seckey*pubkey using ellswift_xdh. Note that we
+ * pass ell64 as claimed (but incorrect) encoding for sec32 here; this works
+ * because the "hasher" function we use here ignores the ours64 argument. */
+ ret = secp256k1_ellswift_xdh(ctx, share32, ell64, ell64, sec32, &ellswift_xdh_hash_x32, NULL);
+ CHECK(ret);
+ secp256k1_fe_set_b32(&share_x, share32);
+ /* Compute seckey*pubkey directly. */
+ secp256k1_ecmult(&resj, &decj, &sec, NULL);
+ secp256k1_ge_set_gej(&res, &resj);
+ /* Compare. */
+ CHECK(check_fe_equal(&res.x, &share_x));
+ }
+ /* Verify the joint behavior of secp256k1_ellswift_xdh */
+ for (i = 0; i < 200 * count; i++) {
+ unsigned char rnd32a[32], rnd32b[32], sec32a[32], sec32b[32];
+ secp256k1_scalar seca, secb;
+ unsigned char ell64a[64], ell64b[64];
+ unsigned char share32a[32], share32b[32];
+ int ret;
+ /* Generate random secret keys and random randomizers. */
+ secp256k1_testrand256_test(rnd32a);
+ secp256k1_testrand256_test(rnd32b);
+ random_scalar_order_test(&seca);
+ random_scalar_order_test(&secb);
+ secp256k1_scalar_get_b32(sec32a, &seca);
+ secp256k1_scalar_get_b32(sec32b, &secb);
+ /* Construct ElligatorSwift-encoded public keys for those keys. */
+ ret = secp256k1_ellswift_create(ctx, ell64a, sec32a, rnd32a);
+ CHECK(ret);
+ ret = secp256k1_ellswift_create(ctx, ell64b, sec32b, rnd32b);
+ CHECK(ret);
+ /* Compute the shared secret both ways and compare with each other. */
+ ret = secp256k1_ellswift_xdh(ctx, share32a, ell64a, ell64b, sec32b, NULL, NULL);
+ CHECK(ret);
+ ret = secp256k1_ellswift_xdh(ctx, share32b, ell64b, ell64a, sec32a, NULL, NULL);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32a, share32b, 32) == 0);
+ /* Verify that the shared secret doesn't match if a secret key or remote pubkey changes. */
+ secp256k1_testrand_flip(ell64a, 64);
+ ret = secp256k1_ellswift_xdh(ctx, share32a, ell64a, ell64b, sec32b, NULL, NULL);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32a, share32b, 32) != 0);
+ secp256k1_testrand_flip(sec32a, 32);
+ ret = secp256k1_ellswift_xdh(ctx, share32a, ell64a, ell64b, sec32b, NULL, NULL);
+ CHECK(!ret || secp256k1_memcmp_var(share32a, share32b, 32) != 0);
+ }
+}
+
+#endif
diff --git a/src/modules/extrakeys/tests_exhaustive_impl.h b/src/modules/extrakeys/tests_exhaustive_impl.h
index d4a2f5bdf4..5ecc90d50f 100644
--- a/src/modules/extrakeys/tests_exhaustive_impl.h
+++ b/src/modules/extrakeys/tests_exhaustive_impl.h
@@ -7,8 +7,8 @@
#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
#define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
-#include "src/modules/extrakeys/main_impl.h"
#include "../../../include/secp256k1_extrakeys.h"
+#include "main_impl.h"
static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) {
secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1];
diff --git a/src/modules/recovery/bench_impl.h b/src/modules/recovery/bench_impl.h
index 4a9e886910..e1cf4924d3 100644
--- a/src/modules/recovery/bench_impl.h
+++ b/src/modules/recovery/bench_impl.h
@@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_RECOVERY_BENCH_H
#define SECP256K1_MODULE_RECOVERY_BENCH_H
-#include "../include/secp256k1_recovery.h"
+#include "../../../include/secp256k1_recovery.h"
typedef struct {
secp256k1_context *ctx;
diff --git a/src/modules/recovery/tests_exhaustive_impl.h b/src/modules/recovery/tests_exhaustive_impl.h
index 590a972ed3..ed9386b6f8 100644
--- a/src/modules/recovery/tests_exhaustive_impl.h
+++ b/src/modules/recovery/tests_exhaustive_impl.h
@@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
-#include "src/modules/recovery/main_impl.h"
+#include "main_impl.h"
#include "../../../include/secp256k1_recovery.h"
void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {
diff --git a/src/modules/schnorrsig/bench_impl.h b/src/modules/schnorrsig/bench_impl.h
index 41f393c84d..84a172742f 100644
--- a/src/modules/schnorrsig/bench_impl.h
+++ b/src/modules/schnorrsig/bench_impl.h
@@ -91,10 +91,12 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) {
free((void *)data.msgs[i]);
free((void *)data.sigs[i]);
}
- free(data.keypairs);
- free(data.pk);
- free(data.msgs);
- free(data.sigs);
+
+ /* Casting to (void *) avoids a stupid warning in MSVC. */
+ free((void *)data.keypairs);
+ free((void *)data.pk);
+ free((void *)data.msgs);
+ free((void *)data.sigs);
secp256k1_context_destroy(data.ctx);
}
diff --git a/src/modules/schnorrsig/tests_exhaustive_impl.h b/src/modules/schnorrsig/tests_exhaustive_impl.h
index d8df9dd2df..55f9028a63 100644
--- a/src/modules/schnorrsig/tests_exhaustive_impl.h
+++ b/src/modules/schnorrsig/tests_exhaustive_impl.h
@@ -8,7 +8,7 @@
#define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H
#include "../../../include/secp256k1_schnorrsig.h"
-#include "src/modules/schnorrsig/main_impl.h"
+#include "main_impl.h"
static const unsigned char invalid_pubkey_bytes[][32] = {
/* 0 */
diff --git a/src/scratch_impl.h b/src/scratch_impl.h
index 688e18eb66..f71a20b963 100644
--- a/src/scratch_impl.h
+++ b/src/scratch_impl.h
@@ -25,11 +25,11 @@ static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* err
static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) {
if (scratch != NULL) {
- VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */
if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return;
}
+ VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */
memset(scratch->magic, 0, sizeof(scratch->magic));
free(scratch);
}
diff --git a/src/secp256k1.c b/src/secp256k1.c
index 8f34c35283..df9bd1e5d7 100644
--- a/src/secp256k1.c
+++ b/src/secp256k1.c
@@ -4,6 +4,17 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
+/* This is a C project. It should not be compiled with a C++ compiler,
+ * and we error out if we detect one.
+ *
+ * We still want to be able to test the project with a C++ compiler
+ * because it is still good to know if this will lead to real trouble, so
+ * there is a possibility to override the check. But be warned that
+ * compiling with a C++ compiler is not supported. */
+#if defined(__cplusplus) && !defined(SECP256K1_CPLUSPLUS_TEST_OVERRIDE)
+#error Trying to compile a C project with a C++ compiler.
+#endif
+
#define SECP256K1_BUILD
#include "../include/secp256k1.h"
@@ -765,3 +776,7 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32,
#ifdef ENABLE_MODULE_SCHNORRSIG
# include "modules/schnorrsig/main_impl.h"
#endif
+
+#ifdef ENABLE_MODULE_ELLSWIFT
+# include "modules/ellswift/main_impl.h"
+#endif
diff --git a/src/tests.c b/src/tests.c
index dd53173930..9494a2cdc9 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -942,12 +942,32 @@ void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod
uint16_to_signed30(&x, in);
nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4] | x.v[5] | x.v[6] | x.v[7] | x.v[8]) != 0;
uint16_to_signed30(&m.modulus, mod);
- mutate_sign_signed30(&m.modulus);
/* compute 1/modulus mod 2^30 */
m.modulus_inv30 = modinv2p64(m.modulus.v[0]) & 0x3fffffff;
CHECK(((m.modulus_inv30 * m.modulus.v[0]) & 0x3fffffff) == 1);
+ /* Test secp256k1_jacobi32_maybe_var. */
+ {
+ int jac;
+ uint16_t sqr[16], negone[16];
+ mulmod256(sqr, in, in, mod);
+ uint16_to_signed30(&x, sqr);
+ /* Compute jacobi symbol of in^2, which must be 0 or 1 (or uncomputable). */
+ jac = secp256k1_jacobi32_maybe_var(&x, &m);
+ CHECK(jac == -2 || jac == nonzero);
+ /* Then compute the jacobi symbol of -(in^2). x and -x have opposite
+ * jacobi symbols if and only if (mod % 4) == 3. */
+ negone[0] = mod[0] - 1;
+ for (i = 1; i < 16; ++i) negone[i] = mod[i];
+ mulmod256(sqr, sqr, negone, mod);
+ uint16_to_signed30(&x, sqr);
+ jac = secp256k1_jacobi32_maybe_var(&x, &m);
+ CHECK(jac == -2 || jac == (1 - (mod[0] & 2)) * nonzero);
+ }
+
+ uint16_to_signed30(&x, in);
+ mutate_sign_signed30(&m.modulus);
for (vartime = 0; vartime < 2; ++vartime) {
/* compute inverse */
(vartime ? secp256k1_modinv32_var : secp256k1_modinv32)(&x, &m);
@@ -1015,12 +1035,32 @@ void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod
uint16_to_signed62(&x, in);
nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4]) != 0;
uint16_to_signed62(&m.modulus, mod);
- mutate_sign_signed62(&m.modulus);
/* compute 1/modulus mod 2^62 */
m.modulus_inv62 = modinv2p64(m.modulus.v[0]) & M62;
CHECK(((m.modulus_inv62 * m.modulus.v[0]) & M62) == 1);
+ /* Test secp256k1_jacobi64_maybe_var. */
+ {
+ int jac;
+ uint16_t sqr[16], negone[16];
+ mulmod256(sqr, in, in, mod);
+ uint16_to_signed62(&x, sqr);
+ /* Compute jacobi symbol of in^2, which must be 0 or 1 (or uncomputable). */
+ jac = secp256k1_jacobi64_maybe_var(&x, &m);
+ CHECK(jac == -2 || jac == nonzero);
+ /* Then compute the jacobi symbol of -(in^2). x and -x have opposite
+ * jacobi symbols if and only if (mod % 4) == 3. */
+ negone[0] = mod[0] - 1;
+ for (i = 1; i < 16; ++i) negone[i] = mod[i];
+ mulmod256(sqr, sqr, negone, mod);
+ uint16_to_signed62(&x, sqr);
+ jac = secp256k1_jacobi64_maybe_var(&x, &m);
+ CHECK(jac == -2 || jac == (1 - (mod[0] & 2)) * nonzero);
+ }
+
+ uint16_to_signed62(&x, in);
+ mutate_sign_signed62(&m.modulus);
for (vartime = 0; vartime < 2; ++vartime) {
/* compute inverse */
(vartime ? secp256k1_modinv64_var : secp256k1_modinv64)(&x, &m);
@@ -2854,8 +2894,10 @@ void run_sqrt(void) {
for (j = 0; j < count; j++) {
random_fe(&x);
secp256k1_fe_sqr(&s, &x);
+ CHECK(secp256k1_fe_jacobi_var(&s) == 1);
test_sqrt(&s, &x);
secp256k1_fe_negate(&t, &s, 1);
+ CHECK(secp256k1_fe_jacobi_var(&t) == -1);
test_sqrt(&t, NULL);
secp256k1_fe_mul(&t, &s, &ns);
test_sqrt(&t, NULL);
@@ -3986,6 +4028,68 @@ void ecmult_const_mult_zero_one(void) {
ge_equals_ge(&res2, &point);
}
+void ecmult_const_mult_xonly(void) {
+ int i;
+
+ /* Test correspondence between secp256k1_ecmult_const and secp256k1_ecmult_const_xonly. */
+ for (i = 0; i < 2*count; ++i) {
+ secp256k1_ge base;
+ secp256k1_gej basej, resj;
+ secp256k1_fe n, d, resx, v;
+ secp256k1_scalar q;
+ int res;
+ /* Random base point. */
+ random_group_element_test(&base);
+ /* Random scalar to multiply it with. */
+ random_scalar_order_test(&q);
+ /* If i is odd, n=d*base.x for random non-zero d */
+ if (i & 1) {
+ do {
+ random_field_element_test(&d);
+ } while (secp256k1_fe_normalizes_to_zero_var(&d));
+ secp256k1_fe_mul(&n, &base.x, &d);
+ } else {
+ n = base.x;
+ }
+ /* Perform x-only multiplication. */
+ res = secp256k1_ecmult_const_xonly(&resx, &n, (i & 1) ? &d : NULL, &q, 256, i & 2);
+ CHECK(res);
+ /* Perform normal multiplication. */
+ secp256k1_gej_set_ge(&basej, &base);
+ secp256k1_ecmult(&resj, &basej, &q, NULL);
+ /* Check that resj's X coordinate corresponds with resx. */
+ secp256k1_fe_sqr(&v, &resj.z);
+ secp256k1_fe_mul(&v, &v, &resx);
+ CHECK(check_fe_equal(&v, &resj.x));
+ }
+
+ /* Test that secp256k1_ecmult_const_xonly correctly rejects X coordinates not on curve. */
+ for (i = 0; i < 2*count; ++i) {
+ secp256k1_fe x, n, d, c, r;
+ int res;
+ secp256k1_scalar q;
+ random_scalar_order_test(&q);
+ /* Generate random X coordinate not on the curve. */
+ do {
+ random_field_element_test(&x);
+ secp256k1_fe_sqr(&c, &x);
+ secp256k1_fe_mul(&c, &c, &x);
+ secp256k1_fe_add(&c, &secp256k1_fe_const_b);
+ } while (secp256k1_fe_jacobi_var(&c) >= 0);
+ /* If i is odd, n=d*x for random non-zero d. */
+ if (i & 1) {
+ do {
+ random_field_element_test(&d);
+ } while (secp256k1_fe_normalizes_to_zero_var(&d));
+ secp256k1_fe_mul(&n, &x, &d);
+ } else {
+ n = x;
+ }
+ res = secp256k1_ecmult_const_xonly(&r, &n, (i & 1) ? &d : NULL, &q, 256, 0);
+ CHECK(res == 0);
+ }
+}
+
void ecmult_const_chain_multiply(void) {
/* Check known result (randomly generated test problem from sage) */
const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST(
@@ -4017,6 +4121,7 @@ void run_ecmult_const_tests(void) {
ecmult_const_random_mult();
ecmult_const_commutativity();
ecmult_const_chain_multiply();
+ ecmult_const_mult_xonly();
}
typedef struct {
@@ -6872,6 +6977,10 @@ void run_ecdsa_edge_cases(void) {
# include "modules/schnorrsig/tests_impl.h"
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+# include "modules/ellswift/tests_impl.h"
+#endif
+
void run_secp256k1_memczero_test(void) {
unsigned char buf1[6] = {1, 2, 3, 4, 5, 6};
unsigned char buf2[sizeof(buf1)];
@@ -7086,11 +7195,15 @@ int main(int argc, char **argv) {
run_context_tests(0);
run_context_tests(1);
run_scratch_tests();
+
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
- if (secp256k1_testrand_bits(1)) {
+ /* Randomize the context only with probability 15/16
+ to make sure we test without context randomization from time to time.
+ TODO Reconsider this when recalibrating the tests. */
+ if (secp256k1_testrand_bits(4)) {
unsigned char rand32[32];
secp256k1_testrand256(rand32);
- CHECK(secp256k1_context_randomize(ctx, secp256k1_testrand_bits(1) ? rand32 : NULL));
+ CHECK(secp256k1_context_randomize(ctx, rand32));
}
run_rand_bits();
@@ -7172,6 +7285,10 @@ int main(int argc, char **argv) {
run_schnorrsig_tests();
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+ run_ellswift_tests();
+#endif
+
/* util tests */
run_secp256k1_memczero_test();
run_secp256k1_byteorder_tests();
diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c
index 6a4e2340f2..225bbddffc 100644
--- a/src/tests_exhaustive.c
+++ b/src/tests_exhaustive.c
@@ -342,15 +342,15 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
}
#ifdef ENABLE_MODULE_RECOVERY
-#include "src/modules/recovery/tests_exhaustive_impl.h"
+#include "modules/recovery/tests_exhaustive_impl.h"
#endif
#ifdef ENABLE_MODULE_EXTRAKEYS
-#include "src/modules/extrakeys/tests_exhaustive_impl.h"
+#include "modules/extrakeys/tests_exhaustive_impl.h"
#endif
#ifdef ENABLE_MODULE_SCHNORRSIG
-#include "src/modules/schnorrsig/tests_exhaustive_impl.h"
+#include "modules/schnorrsig/tests_exhaustive_impl.h"
#endif
int main(int argc, char** argv) {
diff --git a/src/util.h b/src/util.h
index dac86bd77f..0921e34f16 100644
--- a/src/util.h
+++ b/src/util.h
@@ -16,6 +16,11 @@
#include
#include
+#define STR_(x) #x
+#define STR(x) STR_(x)
+#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x
+#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x))
+
typedef struct {
void (*fn)(const char *text, void* data);
const void* data;