Skip to content

Commit a1ac8e1

Browse files
committed
Squashed 'src/secp256k1/' changes from 44c2452fd3..5398d0ae28
5398d0ae28 ElligatorSwift d29ce7c882 Add benchmark for key generation f4211ce366 Add x-only ecmult_const version for x=n/d 00ae789e89 doc: Describe Jacobi calculation in safegcd_implementation.md 90062550c2 Native jacobi symbol algorithm 63a3565e97 Merge bitcoin-core/secp256k1#1120: ecmult_gen: Skip RNG when creating blinding if no seed is available 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: 5398d0ae28f16ac4223e57791fd34e6d51e8be70
1 parent c41bfd1 commit a1ac8e1

36 files changed

+1634
-86
lines changed

.cirrus.yml

+56-9
Original file line numberDiff line numberDiff line change
@@ -241,17 +241,57 @@ task:
241241
<< : *CAT_LOGS
242242

243243
task:
244-
name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
245244
<< : *LINUX_CONTAINER
246245
env:
247-
WRAPPER_CMD: wine64-stable
248-
SECP256K1_TEST_ITERS: 16
249-
HOST: x86_64-w64-mingw32
246+
WRAPPER_CMD: wine
247+
WITH_VALGRIND: no
248+
ECDH: yes
249+
RECOVERY: yes
250+
SCHNORRSIG: yes
251+
CTIMETEST: no
252+
matrix:
253+
- name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
254+
env:
255+
HOST: x86_64-w64-mingw32
256+
- name: "i686 (mingw32-w64): Windows (Debian stable, Wine)"
257+
env:
258+
HOST: i686-w64-mingw32
259+
<< : *MERGE_BASE
260+
test_script:
261+
- ./ci/cirrus.sh
262+
<< : *CAT_LOGS
263+
264+
task:
265+
<< : *LINUX_CONTAINER
266+
env:
267+
WRAPPER_CMD: wine
268+
WERROR_CFLAGS: -WX
250269
WITH_VALGRIND: no
251270
ECDH: yes
252271
RECOVERY: yes
272+
EXPERIMENTAL: yes
253273
SCHNORRSIG: yes
254274
CTIMETEST: no
275+
# Set non-essential options that affect the CLI messages here.
276+
# (They depend on the user's taste, so we don't want to set them automatically in configure.ac.)
277+
CFLAGS: -nologo -diagnostics:caret
278+
LDFLAGS: -XCClinker -nologo -XCClinker -diagnostics:caret
279+
# Use a MinGW-w64 host to tell ./configure we're building for Windows.
280+
# This will detect some MinGW-w64 tools but then make will need only
281+
# the MSVC tools CC, AR and NM as specified below.
282+
matrix:
283+
- name: "x86_64 (MSVC): Windows (Debian stable, Wine)"
284+
env:
285+
HOST: x86_64-w64-mingw32
286+
CC: /opt/msvc/bin/x64/cl
287+
AR: /opt/msvc/bin/x64/lib
288+
NM: /opt/msvc/bin/x64/dumpbin -symbols -headers
289+
- name: "i686 (MSVC): Windows (Debian stable, Wine)"
290+
env:
291+
HOST: i686-w64-mingw32
292+
CC: /opt/msvc/bin/x86/cl
293+
AR: /opt/msvc/bin/x86/lib
294+
NM: /opt/msvc/bin/x86/dumpbin -symbols -headers
255295
<< : *MERGE_BASE
256296
test_script:
257297
- ./ci/cirrus.sh
@@ -302,13 +342,12 @@ task:
302342
<< : *CAT_LOGS
303343

304344
task:
305-
name: "C++ -fpermissive"
345+
name: "C++ -fpermissive (entire project)"
306346
<< : *LINUX_CONTAINER
307347
env:
308-
# ./configure correctly errors out when given CC=g++.
309-
# We hack around this by passing CC=g++ only to make.
310-
CC: gcc
311-
MAKEFLAGS: -j4 CC=g++ CFLAGS=-fpermissive\ -g
348+
CC: g++
349+
CFLAGS: -fpermissive -g
350+
CPPFLAGS: -DSECP256K1_CPLUSPLUS_TEST_OVERRIDE
312351
WERROR_CFLAGS:
313352
ECDH: yes
314353
RECOVERY: yes
@@ -318,6 +357,14 @@ task:
318357
- ./ci/cirrus.sh
319358
<< : *CAT_LOGS
320359

360+
task:
361+
name: "C++ (public headers)"
362+
<< : *LINUX_CONTAINER
363+
test_script:
364+
- g++ -Werror include/*.h
365+
- clang -Werror -x c++-header include/*.h
366+
- /opt/msvc/bin/x64/cl.exe -c -WX -TP include/*.h
367+
321368
task:
322369
name: "sage prover"
323370
<< : *LINUX_CONTAINER

Makefile.am

+6-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ endif
8787
endif
8888

8989
libsecp256k1_la_SOURCES = src/secp256k1.c
90-
libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
90+
libsecp256k1_la_CPPFLAGS = $(SECP_INCLUDES)
9191
libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
9292
libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE)
9393

@@ -112,7 +112,7 @@ TESTS =
112112
if USE_TESTS
113113
noinst_PROGRAMS += tests
114114
tests_SOURCES = src/tests.c
115-
tests_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
115+
tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
116116
if VALGRIND_ENABLED
117117
tests_CPPFLAGS += -DVALGRIND
118118
noinst_PROGRAMS += valgrind_ctime_test
@@ -228,3 +228,7 @@ endif
228228
if ENABLE_MODULE_SCHNORRSIG
229229
include src/modules/schnorrsig/Makefile.am.include
230230
endif
231+
232+
if ENABLE_MODULE_ELLSWIFT
233+
include src/modules/ellswift/Makefile.am.include
234+
endif

build-aux/m4/bitcoin_secp.m4

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ AC_MSG_RESULT([$has_64bit_asm])
1010
])
1111

1212
AC_DEFUN([SECP_VALGRIND_CHECK],[
13+
AC_MSG_CHECKING([for valgrind support])
1314
if test x"$has_valgrind" != x"yes"; then
1415
CPPFLAGS_TEMP="$CPPFLAGS"
1516
CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS"
@@ -21,6 +22,7 @@ if test x"$has_valgrind" != x"yes"; then
2122
#endif
2223
]])], [has_valgrind=yes; AC_DEFINE(HAVE_VALGRIND,1,[Define this symbol if valgrind is installed, and it supports the host platform])])
2324
fi
25+
AC_MSG_RESULT($has_valgrind)
2426
])
2527

2628
dnl SECP_TRY_APPEND_CFLAGS(flags, VAR)

ci/cirrus.sh

+13
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,20 @@ set -x
55

66
export LC_ALL=C
77

8+
# Start persistent wineserver if necessary.
9+
# This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously.
10+
case "$WRAPPER_CMD" in
11+
*wine*)
12+
# This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards.
13+
wineserver -p && wine hh.exe
14+
;;
15+
esac
16+
817
env >> test_env.log
918

1019
$CC -v || true
1120
valgrind --version || true
21+
$WRAPPER_CMD --version || true
1222

1323
./autogen.sh
1424

@@ -63,6 +73,9 @@ then
6373
make precomp
6474
fi
6575

76+
# Shutdown wineserver again
77+
wineserver -k || true
78+
6679
# Check that no repo files have been modified by the build.
6780
# (This fails for example if the precomp files need to be updated in the repo.)
6881
git diff --exit-code

ci/linux-debian.Dockerfile

+21-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
FROM debian:stable
22

3-
RUN dpkg --add-architecture i386
4-
RUN dpkg --add-architecture s390x
5-
RUN dpkg --add-architecture armhf
6-
RUN dpkg --add-architecture arm64
7-
RUN dpkg --add-architecture ppc64el
8-
RUN apt-get update
3+
RUN dpkg --add-architecture i386 && \
4+
dpkg --add-architecture s390x && \
5+
dpkg --add-architecture armhf && \
6+
dpkg --add-architecture arm64 && \
7+
dpkg --add-architecture ppc64el
98

109
# dkpg-dev: to make pkg-config work in cross-builds
1110
# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces
12-
RUN apt-get install --no-install-recommends --no-upgrade -y \
11+
RUN apt-get update && apt-get install --no-install-recommends -y \
1312
git ca-certificates \
1413
make automake libtool pkg-config dpkg-dev valgrind qemu-user \
1514
gcc clang llvm libc6-dbg \
@@ -19,8 +18,20 @@ RUN apt-get install --no-install-recommends --no-upgrade -y \
1918
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \
2019
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \
2120
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
22-
wine gcc-mingw-w64-x86-64 \
21+
gcc-mingw-w64-x86-64-win32 wine64 wine \
22+
gcc-mingw-w64-i686-win32 wine32 \
2323
sagemath
2424

25-
# Run a dummy command in wine to make it set up configuration
26-
RUN wine64-stable xcopy || true
25+
WORKDIR /root
26+
# The "wine" package provides a convience wrapper that we need
27+
RUN apt-get update && apt-get install --no-install-recommends -y \
28+
git ca-certificates wine64 wine python3-simplejson python3-six msitools winbind procps && \
29+
git clone https://github.com/mstorsjo/msvc-wine && \
30+
mkdir /opt/msvc && \
31+
python3 msvc-wine/vsdownload.py --accept-license --dest /opt/msvc Microsoft.VisualStudio.Workload.VCTools && \
32+
msvc-wine/install.sh /opt/msvc
33+
34+
# Initialize the wine environment. Wait until the wineserver process has
35+
# exited before closing the session, to avoid corrupting the wine prefix.
36+
RUN wine64 wineboot --init && \
37+
while (ps -A | grep wineserver) > /dev/null; do sleep 1; done

configure.ac

+50-21
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,18 @@ AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
3333
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
3434

3535
AC_PROG_CC
36-
if test x"$ac_cv_prog_cc_c89" = x"no"; then
37-
AC_MSG_ERROR([c89 compiler support required])
38-
fi
3936
AM_PROG_AS
4037
AM_PROG_AR
4138

39+
# Clear some cache variables as a workaround for a bug that appears due to a bad
40+
# interaction between AM_PROG_AR and LT_INIT when combining MSVC's archiver lib.exe.
41+
# https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54421
42+
AS_UNSET(ac_cv_prog_AR)
43+
AS_UNSET(ac_cv_prog_ac_ct_AR)
4244
LT_INIT([win32-dll])
4345

46+
PKG_PROG_PKG_CONFIG
47+
4448
build_windows=no
4549

4650
case $host_os in
@@ -87,23 +91,35 @@ esac
8791
#
8892
# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues.
8993
AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
90-
# Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
91-
# not error out if it gets unknown warning flags and the checks here will always succeed
92-
# no matter if clang knows the flag or not.
93-
SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
94-
SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
95-
96-
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.
97-
SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
98-
SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
99-
SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
100-
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.
101-
SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
102-
SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
103-
SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
104-
SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
105-
106-
CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
94+
# GCC and compatible (incl. clang)
95+
if test "x$GCC" = "xyes"; then
96+
# Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
97+
# not error out if it gets unknown warning flags and the checks here will always succeed
98+
# no matter if clang knows the flag or not.
99+
SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
100+
SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
101+
102+
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.
103+
SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
104+
SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
105+
SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
106+
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.
107+
SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
108+
SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
109+
SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
110+
SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
111+
112+
CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
113+
fi
114+
115+
# MSVC
116+
# Assume MSVC if we're building for Windows but not with GCC or compatible;
117+
# libtool makes the same assumption internally.
118+
# Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path.
119+
if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then
120+
SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned"
121+
SECP_TRY_APPEND_CFLAGS([-external:anglebrackets -external:W0], $1) # Suppress warnings from #include <...> files
122+
fi
107123
])
108124
SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
109125

@@ -156,6 +172,11 @@ AC_ARG_ENABLE(module_schnorrsig,
156172
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=no]]), [],
157173
[SECP_SET_DEFAULT([enable_module_schnorrsig], [no], [yes])])
158174

175+
AC_ARG_ENABLE(module_ellswift,
176+
AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module (experimental)]),
177+
[enable_module_ellswift=$enableval],
178+
[enable_module_ellswift=no])
179+
159180
AC_ARG_ENABLE(external_default_callbacks,
160181
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
161182
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
@@ -326,7 +347,9 @@ if test x"$enable_valgrind" = x"yes"; then
326347
SECP_INCLUDES="$SECP_INCLUDES $VALGRIND_CPPFLAGS"
327348
fi
328349

329-
# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI)
350+
# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI).
351+
# We don't want to set the user variable CFLAGS in CI because this would disable
352+
# autoconf's logic for setting default CFLAGS, which we would like to test in CI.
330353
SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
331354

332355
###
@@ -346,6 +369,10 @@ if test x"$enable_module_schnorrsig" = x"yes"; then
346369
enable_module_extrakeys=yes
347370
fi
348371

372+
if test x"$enable_module_ellswift" = x"yes"; then
373+
AC_DEFINE(ENABLE_MODULE_ELLSWIFT, 1, [Define this symbol to enable the ElligatorSwift module])
374+
fi
375+
349376
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
350377
# module to set enable_module_extrakeys=yes
351378
if test x"$enable_module_extrakeys" = x"yes"; then
@@ -391,6 +418,7 @@ AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
391418
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
392419
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
393420
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
421+
AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"])
394422
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
395423
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
396424
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
@@ -411,6 +439,7 @@ echo " module ecdh = $enable_module_ecdh"
411439
echo " module recovery = $enable_module_recovery"
412440
echo " module extrakeys = $enable_module_extrakeys"
413441
echo " module schnorrsig = $enable_module_schnorrsig"
442+
echo " module ellswift = $enable_module_ellswift"
414443
echo
415444
echo " asm = $set_asm"
416445
echo " ecmult window size = $set_ecmult_window"

doc/safegcd_implementation.md

+29-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# The safegcd implementation in libsecp256k1 explained
22

3-
This document explains the modular inverse implementation in the `src/modinv*.h` files. It is based
4-
on the paper
3+
This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files.
4+
It is based on the paper
55
["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd)
66
by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version.
77

@@ -769,3 +769,30 @@ def modinv_var(M, Mi, x):
769769
d, e = update_de(d, e, t, M, Mi)
770770
return normalize(f, d, Mi)
771771
```
772+
773+
## 8. From GCDs to Jacobi symbol
774+
775+
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*.
776+
777+
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:
778+
779+
```python
780+
# Before
781+
if delta > 0 and g & 1:
782+
delta, f, g = 1 - delta, g, (g - f) // 2
783+
784+
# After
785+
if delta > 0 and g & 1:
786+
delta, f, g = 1 - delta, g, (g + f) // 2
787+
```
788+
789+
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(f<sub>0</sub>, g<sub>0<sub>)* in a number of steps proportional to their logarithm.
790+
791+
Note that:
792+
- We require inputs to satisfy *gcd(x, M) = 1*.
793+
- We need to update the termination condition from *g=0* to *f=1*.
794+
- We deal with the case where *g=0* on input specially.
795+
796+
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.
797+
798+
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.

0 commit comments

Comments
 (0)