Merge ElementsProject/secp256k1-zkp#174: Upstream PRs 1064, 1049, 899, 1068, 1072, 1069, 1074, 1026, 1033, 748, 1079, 1088, 1090, 731, 1089, 995, 1094, 1093

645d9c53c4d9095342cf770c98e3d367f670ae46 examples: let musig use random.h instead of /dev/urandom (Jonas Nick)
eccba5b4e5eb70710f4d34ae89e62abfab542f7c examples: relicense musig example to CC0 public domain (Jonas Nick)
7c5af740fab0d36a54c9e36872a87de2727c49f1 ci: fix missing EXPERIMENTAL flags (Jonas Nick)
03bea1e173d84b33ca81bba4c06b876e160dbe65 configure: add -zkp modules to dev-mode and remove redundant code (Jonas Nick)
2adb741c45ecc4ef7180009c42f961e4aee4bf5c examples: rename example_musig to musig_example for consistency (Jonas Nick)
37d36927dff793e61df6d6f6a6c50e8fa2519e33 tests: Add tests for _read_be32 and _write_be32 (Tim Ruffing)
616b43dd3b6949923f0752cd60382153cfd5dda9 util: Remove endianness detection (Tim Ruffing)
8d89b9e6e562000cdb91a70a85fae5e4817cec8a hash: Make code agnostic of endianness (Tim Ruffing)
55512d30b7921bc46247a78be1da98108f243c1c doc: clean up module help text in configure.ac (Elliott Jin)
d9d94a9969785abbb3e04b2b9f75f1049c7b8936 doc: mention optional modules in README (Elliott Jin)
7f09d0f311117289719b690f91f6a907c2c6f3e2 README: mention that ARM assembly is experimental (Jonas Nick)
80cf4eea5fa0162350614c08f2252a07f9d7804b build: stop treating schnorrsig, extrakeys modules as experimental (Jonas Nick)
b8f8b99f0fb3a5cd4c6fb1c9c8dfed881839e19e docs: Fix return value for functions that don't have invalid inputs (Tim Ruffing)
f813bb0df3153dc055e0e76101ed9e4607155870 schnorrsig: Adapt example to new API (Tim Ruffing)
99e6568fc6ea2768f5355eb4617283086f756931 schnorrsig: Rename schnorrsig_sign to schnorsig_sign32 and deprecate (Tim Ruffing)
fc94a2da4457325c4be539838ceed21b31c60fbd Use SECP256K1_DEPRECATED for existing deprecated API functions (Tim Ruffing)
3db0560606acb285cc7ef11662ce166ed67e9015 Add SECP256K1_DEPRECATED attribute for marking API parts as deprecated (Tim Ruffing)
f8d9174357391ab4bf65a2f4d9d9cfb8039dc592 Add SHA256 bit counter tests (Tim Ruffing)
9b514ce1d25f1944c549ead30cc84367d616e0e6 Add test vector for very long SHA256 messages (Tim Ruffing)
8e3dde113741615fcb1aedcacfc54bd3b3d204f1 Simplify struct initializer for SHA256 padding (Tim Ruffing)
eb28464a8bf8652a2b49d2ed765801d7c0aa195d Change SHA256 byte counter from size_t to uint64_t (Tim Ruffing)
21b2ebaf74222017f85123deb6f30a33c7678513 configure: Remove redundant pkg-config code (Tim Ruffing)
0d253d52e804a5affb0f1c851ec250071e7345d9 configure: Use modern way to set AR (Tim Ruffing)
e0838d663deba5a9663a0ad02bd7e4c563325c4d configure: Add hidden --enable-dev-mode to enable all the stuff (Tim Ruffing)
fabd579dfa85711e96e4012d20352b8ee8f2a9d1 configure: Remove redundant code that sets _enable variables (Tim Ruffing)
0d4226c051415d12384586ae938499975a248cab configure: Use canonical variable prefix _enable consistently (Tim Ruffing)
7c9502cece9c9e8d811333f7ab5bb22f4eb01c04 Add a copy of the CC0 license to the examples (Elichai Turkel)
42e03432e6be7f0bf18c7f86130d3930bdf4038d Add usage examples to the readme (Elichai Turkel)
517644eab14ef397e1f0bc2b45f2dff8b1a473ec Optionally compile the examples in autotools, compile+run in travis (Elichai Turkel)
422a7cc86ae86496794c5014028ee249bbe0e072 Add a ecdh shared secret example (Elichai Turkel)
b0cfbcc14347ff6b04ff62a0d935638840a37971 Add a Schnorr signing and verifying example (Elichai Turkel)
fee7d4bf9e4ea316ea4ff3151bbe52bec1f0745c Add an ECDSA signing and verifying example (Elichai Turkel)
e848c3799c4f31367c3ed98d17e3b7de504d4c6e Update sage files for new formulae (Peter Dettman)
d64bb5d4f3fbd48b570d847c9389b9cf8f3d9abc Add fe_half tests for worst-case inputs (Peter Dettman)
4eb8b932ff8e64f8de3ae8ecfebeab1e84ca420e Further improve doubling formula using fe_half (Peter Dettman)
557b31fac36529948709d4bfcc00ad3acb7e83b9 Doubling formula using fe_half (Pieter Wuille)
2cbb4b1a424d9dee12a4e11f0479410b7e4cc930 Run more iterations of run_field_misc (Pieter Wuille)
9cc5c257eddc2d7614985be60bee29cf2bec65fb Add test for secp256k1_fe_half (Pieter Wuille)
925f78d55e112cd00f1e2867886bdc751a5d6606 Add _fe_half and use in _gej_add_ge (Peter Dettman)
3531a43b5bc739838f5634afcfd02bdbef71b1ef ecdh: Make generator_basepoint test depend on global iteration count (Tim Ruffing)
c881dd49bdb865d9e455d504b90aebf77e807e85 ecdh: Add test computing shared_secret=basepoint with random inputs (Tim Ruffing)
e51ad3b737a2f12605d346cf9c0e7eaabf6a39ec ci: Retry `brew update` a few times to avoid random failures (Tim Ruffing)
b1cb969e8ab9ad86fec3ce30cb732f4c42e015e0 ci: Revert "Attempt to make macOS builds more reliable" (Tim Ruffing)
e0db3f8a25c20a247a0b49ca00dd6c973b6a16e0 build: Replace use of deprecated autoconf macro AC_PROG_CC_C89 (laanwj)
d9396a56da13df97827e193f636a7593fb4d7864 ci: Attempt to make macOS builds more reliable (Tim Ruffing)
ebb1beea7832207e5c8c5112d250fd216259ef41 sage: Ensure that constraints are always fastfracs (Tim Ruffing)
d8d54859ed138a8ed9a8486d847155211c9f4a7d ci: Run sage prover on CI (Tim Ruffing)
77cfa98dbc40f9494048447b8a302867235300da sage: Normalize sign of polynomial factors in prover (Tim Ruffing)
eae75869cfbbbcb69d881bc5d313bd94c6155655 sage: Exit with non-zero status in case of failures (Tim Ruffing)
b54d843eac905993eba2314a89a2d7f155445eaa sage: Fix printing of errors (Tim Ruffing)
e108d0039c36483dffe4be00815c1b6d65ef5751 sage: Fix incompatibility with sage 9.4 (Tim Ruffing)
b797a500ec194948eecbea8bd80f6b7d455f7ca2 Create a SECP256K1_ECMULT_TABLE_VERIFY macro. (Russell O'Connor)
a731200cc30fcf019af08a41f7b6f329a08eaa0c Replace ECMULT_TABLE_GET_GE_STORAGE macro with a function. (Russell O'Connor)
fe34d9f3419d090e94b0c0897895c5b2b9fdc244 Eliminate input_pos state field from ecmult_strauss_wnaf. (Russell O'Connor)
0397d00ba0401bf5be7c4312d84d17fc789a6566 Eliminate na_1 and na_lam state fields from ecmult_strauss_wnaf. (Russell O'Connor)
7ba3ffcca0ae054cf0a1d6407c2dcf7445a46935 Remove the unused pre_a_lam allocations. (Russell O'Connor)
b3b57ad6eedac86bda40f062daee7d5f4241d25c Eliminate the pre_a_lam array from ecmult_strauss_wnaf. (Russell O'Connor)
ae7ba0f922b4c1439888b8488b307cd0f0e8ec59 Remove the unused prej allocations. (Russell O'Connor)
e5c18892db69b5db44d282225ab4fea788af8035 Eliminate the prej array from ecmult_strauss_wnaf. (Russell O'Connor)
c9da1baad125e830901f0ed6ad65eb4f9ccb81f4 Move secp256k1_fe_one to field.h (Russell O'Connor)
070e772211b3fcd297577b90b56bbf7a5cfbd0a3 Faster fixed-input ecmult tests (Pieter Wuille)
45f37b650635e46865104f37baed26ef8d2cfb97 Modulo-reduce msg32 inside RFC6979 nonce fn to match spec. Fixes #1063. (Paul Miller)

Pull request description:

  [bitcoin-core/secp256k1#1064]: Modulo-reduce msg32 inside RFC6979 nonce fn to match spec. Fixes #1063
  [bitcoin-core/secp256k1#1049]: Faster fixed-input ecmult tests
  [bitcoin-core/secp256k1#899]: Reduce stratch space needed by ecmult_strauss_wnaf.
  [bitcoin-core/secp256k1#1068]: sage: Fix incompatibility with sage 9.4
  [bitcoin-core/secp256k1#1072]: ci: Attempt to make macOS builds more reliable
  [bitcoin-core/secp256k1#1069]: build: Replace use of deprecated autoconf macro AC_PROG_CC_C89
  [bitcoin-core/secp256k1#1074]: ci: Retry brew update a few times to avoid random failures
  [bitcoin-core/secp256k1#1026]: ecdh: Add test computing shared_secret=basepoint with random inputs
  [bitcoin-core/secp256k1#1033]: Add _fe_half and use in _gej_add_ge and _gej_double
  [bitcoin-core/secp256k1#748]: Add usage examples
  [bitcoin-core/secp256k1#1079]: configure: Add hidden --enable-dev-mode to enable all the stuff
  [bitcoin-core/secp256k1#1088]: configure: Use modern way to set AR
  [bitcoin-core/secp256k1#1090]: configure: Remove redundant pkg-config code
  [bitcoin-core/secp256k1#731]: Change SHA256 byte counter from size_t to uint64_t
  [bitcoin-core/secp256k1#1089]: Schnorrsig API improvements
  [bitcoin-core/secp256k1#995]: build: stop treating schnorrsig, extrakeys modules as experimental
  [bitcoin-core/secp256k1#1094]: doc: Clarify configure flags for optional modules
  [bitcoin-core/secp256k1#1093]: hash: Make code agnostic of endianness

  This PR can be recreated  with `./sync-upstream.sh range 8746600eec5e7fcd35dabd480839a3a4bdfee87b`.

ACKs for top commit:
  real-or-random:
    ACK 645d9c53c4d9095342cf770c98e3d367f670ae46 I rederived the tree, and tested it with MSVC, including the musig example

Tree-SHA512: 3b771630806ed8481053958c21820dce6e869371833cd18a5c430a2768bda8064ad2bb247afbe38e3fa37320a8b1dbbe65ad68c8963efb995d96aa29ae574884
This commit is contained in:
Tim Ruffing 2022-04-01 15:20:47 +02:00
commit 6c0aecf72b
No known key found for this signature in database
GPG Key ID: 8C461CCD293F6011
38 changed files with 1712 additions and 444 deletions

View File

@ -28,6 +28,8 @@ env:
BENCH: yes
SECP256K1_BENCH_ITERS: 2
CTIMETEST: yes
# Compile and run the tests
EXAMPLES: yes
cat_logs_snippet: &CAT_LOGS
always:
@ -70,12 +72,12 @@ task:
<< : *LINUX_CONTAINER
matrix: &ENV_MATRIX
- env: {WIDEMUL: int64, RECOVERY: yes}
- env: {WIDEMUL: int64, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
- env: {WIDEMUL: int128}
- env: {WIDEMUL: int128, RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
- env: {WIDEMUL: int128, ASM: x86_64}
- env: { RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
- env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
- env: {CPPFLAGS: -DDETERMINISTIC}
- env: {CFLAGS: -O0, CTIMETEST: no}
@ -98,8 +100,8 @@ task:
HOST: i686-linux-gnu
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
EXPERIMENTAL: yes
ECDSA_S2C: yes
RANGEPROOF: yes
WHITELIST: yes
@ -148,7 +150,8 @@ task:
## - rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
##
brew_valgrind_pre_script:
- brew update
# Retry a few times because this tends to fail randomly.
- for i in {1..5}; do brew update && break || sleep 15; done
- brew config
- brew tap LouisBrunner/valgrind
# Fetch valgrind source but don't build it yet.
@ -188,8 +191,8 @@ task:
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
EXPERIMENTAL: yes
ECDSA_S2C: yes
RANGEPROOF: yes
WHITELIST: yes
@ -214,12 +217,11 @@ task:
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
matrix:
- env: {}
- env: {ASM: arm}
- env: {EXPERIMENTAL: yes, ASM: arm}
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
@ -235,7 +237,6 @@ task:
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
@ -253,7 +254,6 @@ task:
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
@ -271,7 +271,6 @@ task:
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
@ -286,8 +285,8 @@ task:
env:
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
EXPERIMENTAL: yes
ECDSA_S2C: yes
RANGEPROOF: yes
WHITELIST: yes
@ -340,7 +339,6 @@ task:
CC: gcc
MAKEFLAGS: -j4 CC=g++ CFLAGS=-fpermissive\ -g
WERROR_CFLAGS:
EXPERIMENTAL: yes
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
@ -348,3 +346,10 @@ task:
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "sage prover"
<< : *LINUX_CONTAINER
test_script:
- cd sage
- sage prove_group_implementations.sage

8
.gitignore vendored
View File

@ -8,11 +8,16 @@ exhaustive_tests
precompute_ecmult_gen
precompute_ecmult
valgrind_ctime_test
ecdh_example
ecdsa_example
schnorr_example
*.exe
*.so
*.a
*.csv
!.gitignore
*.log
*.trs
Makefile
configure
@ -43,6 +48,7 @@ coverage.*.html
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
build-aux/ar-lib
build-aux/config.guess
build-aux/config.sub
build-aux/depcomp
@ -60,4 +66,4 @@ src/stamp-h1
libsecp256k1.pc
contrib/gh-pr-create.sh
example_musig
musig_example

View File

@ -65,6 +65,7 @@ noinst_HEADERS += contrib/lax_der_parsing.h
noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
noinst_HEADERS += examples/random.h
PRECOMPUTED_LIB = libsecp256k1_precomputed.la
noinst_LTLIBRARIES = $(PRECOMPUTED_LIB)
@ -141,13 +142,49 @@ exhaustive_tests_LDFLAGS = -static
TESTS += exhaustive_tests
endif
if USE_EXAMPLES
noinst_PROGRAMS += ecdsa_example
ecdsa_example_SOURCES = examples/ecdsa.c
ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include
ecdsa_example_LDADD = libsecp256k1.la
ecdsa_example_LDFLAGS = -static
if BUILD_WINDOWS
ecdsa_example_LDFLAGS += -lbcrypt
endif
TESTS += ecdsa_example
if ENABLE_MODULE_ECDH
noinst_PROGRAMS += ecdh_example
ecdh_example_SOURCES = examples/ecdh.c
ecdh_example_CPPFLAGS = -I$(top_srcdir)/include
ecdh_example_LDADD = libsecp256k1.la
ecdh_example_LDFLAGS = -static
if BUILD_WINDOWS
ecdh_example_LDFLAGS += -lbcrypt
endif
TESTS += ecdh_example
endif
if ENABLE_MODULE_SCHNORRSIG
noinst_PROGRAMS += schnorr_example
schnorr_example_SOURCES = examples/schnorr.c
schnorr_example_CPPFLAGS = -I$(top_srcdir)/include
schnorr_example_LDADD = libsecp256k1.la
schnorr_example_LDFLAGS = -static
if BUILD_WINDOWS
schnorr_example_LDFLAGS += -lbcrypt
endif
TESTS += schnorr_example
endif
if ENABLE_MODULE_MUSIG
noinst_PROGRAMS += example_musig
example_musig_SOURCES = examples/musig.c
example_musig_CPPFLAGS = -I$(top_srcdir)/include
example_musig_LDADD = libsecp256k1.la
example_musig_LDFLAGS = -static
TESTS += example_musig
noinst_PROGRAMS += musig_example
musig_example_SOURCES = examples/musig.c
musig_example_CPPFLAGS = -I$(top_srcdir)/include
musig_example_LDADD = libsecp256k1.la
musig_example_LDFLAGS = -static
if BUILD_WINDOWS
musig_example_LDFLAGS += -lbcrypt
endif
TESTS += musig_example
endif
endif
### Precomputed tables

View File

@ -17,7 +17,7 @@ Features:
* Suitable for embedded systems.
* 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) (experimental).
* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
* Optional module for ECDSA adaptor signatures (experimental).
Experimental features have not received enough scrutiny to satisfy the standard of quality of this library but are made available for testing and review by the community. The APIs of these features should not be considered stable.
@ -36,6 +36,7 @@ Implementation details
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
* Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys).
* Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan).
* This is an experimental feature that has not received enough scrutiny to satisfy the standard of quality of this library but is made available for testing and review by the community.
* Scalar operations
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
* Using 4 64-bit limbs (relying on __int128 support in the compiler).
@ -70,6 +71,16 @@ libsecp256k1 is built using autotools:
$ make check # run the test suite
$ sudo make install # optional
To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags.
Usage 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`.
Test coverage
-----------

View File

@ -38,3 +38,16 @@ AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [
unset flag_works
AC_SUBST($2)
])
dnl SECP_SET_DEFAULT(VAR, default, default-dev-mode)
dnl Set VAR to default or default-dev-mode, depending on whether dev mode is enabled
AC_DEFUN([SECP_SET_DEFAULT], [
if test "${enable_dev_mode+set}" != set; then
AC_MSG_ERROR([[Set enable_dev_mode before calling SECP_SET_DEFAULT]])
fi
if test x"$enable_dev_mode" = x"yes"; then
$1="$3"
else
$1="$2"
fi
])

View File

@ -21,6 +21,8 @@ valgrind --version || true
--enable-module-ecdsa-s2c="$ECDSA_S2C" \
--enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
--enable-module-schnorrsig="$SCHNORRSIG" \
--enable-examples="$EXAMPLES" \
--with-valgrind="$WITH_VALGRIND" \
--host="$HOST" $EXTRAFLAGS

View File

@ -19,7 +19,8 @@ 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
wine gcc-mingw-w64-x86-64 \
sagemath
# Run a dummy command in wine to make it set up configuration
RUN wine64-stable xcopy || true

View File

@ -25,25 +25,23 @@ AC_CANONICAL_HOST
AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
AH_TOP([#define LIBSECP256K1_CONFIG_H])
AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
AM_INIT_AUTOMAKE([foreign subdir-objects])
LT_INIT([win32-dll])
# Require Automake 1.11.2 for AM_PROG_AR
AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
# Make the compilation flags quiet unless V=1 is used.
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
PKG_PROG_PKG_CONFIG
AC_PATH_TOOL(AR, ar)
AC_PATH_TOOL(RANLIB, ranlib)
AC_PATH_TOOL(STRIP, strip)
AM_PROG_CC_C_O
AC_PROG_CC_C89
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
LT_INIT([win32-dll])
build_windows=no
case $host_os in
*darwin*)
@ -68,6 +66,9 @@ case $host_os in
fi
fi
;;
cygwin*|mingw*)
build_windows=yes
;;
esac
# Try if some desirable compiler flags are supported and append them to SECP_CFLAGS.
@ -110,95 +111,94 @@ SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
### Define config arguments
###
# In dev mode, we enable all binaries and modules by default but individual options can still be overridden explicitly.
# Check for dev mode first because SECP_SET_DEFAULT needs enable_dev_mode set.
AC_ARG_ENABLE(dev_mode, [], [],
[enable_dev_mode=no])
AC_ARG_ENABLE(benchmark,
AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]),
[use_benchmark=$enableval],
[use_benchmark=yes])
AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), [],
[SECP_SET_DEFAULT([enable_benchmark], [yes], [yes])])
AC_ARG_ENABLE(coverage,
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]),
[enable_coverage=$enableval],
[enable_coverage=no])
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [],
[SECP_SET_DEFAULT([enable_coverage], [no], [no])])
AC_ARG_ENABLE(tests,
AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]),
[use_tests=$enableval],
[use_tests=yes])
AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [],
[SECP_SET_DEFAULT([enable_tests], [yes], [yes])])
AC_ARG_ENABLE(experimental,
AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]),
[use_experimental=$enableval],
[use_experimental=no])
AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [],
[SECP_SET_DEFAULT([enable_experimental], [no], [yes])])
AC_ARG_ENABLE(exhaustive_tests,
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]),
[use_exhaustive_tests=$enableval],
[use_exhaustive_tests=yes])
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), [],
[SECP_SET_DEFAULT([enable_exhaustive_tests], [yes], [yes])])
AC_ARG_ENABLE(examples,
AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [],
[SECP_SET_DEFAULT([enable_examples], [no], [yes])])
AC_ARG_ENABLE(module_ecdh,
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation]),
[enable_module_ecdh=$enableval],
[enable_module_ecdh=no])
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])])
AC_ARG_ENABLE(module_musig,
AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]),
[enable_module_musig=$enableval],
[enable_module_musig=no])
[],
[SECP_SET_DEFAULT([enable_module_musig], [no], [yes])])
AC_ARG_ENABLE(module_recovery,
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]),
[enable_module_recovery=$enableval],
[enable_module_recovery=no])
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])])
AC_ARG_ENABLE(module_generator,
AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module [default=no]]),
[enable_module_generator=$enableval],
[enable_module_generator=no])
[],
[SECP_SET_DEFAULT([enable_module_generator], [no], [yes])])
AC_ARG_ENABLE(module_rangeproof,
AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module [default=no]]),
[enable_module_rangeproof=$enableval],
[enable_module_rangeproof=no])
[],
[SECP_SET_DEFAULT([enable_module_rangeproof], [no], [yes])])
AC_ARG_ENABLE(module_whitelist,
AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module [default=no]]),
[enable_module_whitelist=$enableval],
[enable_module_whitelist=no])
[],
[SECP_SET_DEFAULT([enable_module_whitelist], [no], [yes])])
AC_ARG_ENABLE(module_extrakeys,
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module (experimental)]),
[enable_module_extrakeys=$enableval],
[enable_module_extrakeys=no])
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_extrakeys], [no], [yes])])
AC_ARG_ENABLE(module_schnorrsig,
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]),
[enable_module_schnorrsig=$enableval],
[enable_module_schnorrsig=no])
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig], [no], [yes])])
AC_ARG_ENABLE(module_ecdsa_s2c,
AS_HELP_STRING([--enable-module-ecdsa-s2c],[enable ECDSA sign-to-contract module [default=no]]),
[enable_module_ecdsa_s2c=$enableval],
[enable_module_ecdsa_s2c=no])
[],
[SECP_SET_DEFAULT([enable_module_ecdsa_s2c], [no], [yes])])
AC_ARG_ENABLE(module_ecdsa-adaptor,
AS_HELP_STRING([--enable-module-ecdsa-adaptor],[enable ECDSA adaptor module [default=no]]),
[enable_module_ecdsa_adaptor=$enableval],
[enable_module_ecdsa_adaptor=no])
[],
[SECP_SET_DEFAULT([enable_module_ecdsa_adaptor], [no], [yes])])
AC_ARG_ENABLE(external_default_callbacks,
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]),
[use_external_default_callbacks=$enableval],
[use_external_default_callbacks=no])
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
AC_ARG_ENABLE(module_surjectionproof,
AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module [default=no]]),
[enable_module_surjectionproof=$enableval],
[enable_module_surjectionproof=no])
[],
[SECP_SET_DEFAULT([enable_module_surjectionproof], [no], [yes])])
AC_ARG_ENABLE(reduced_surjection_proof_size,
AS_HELP_STRING([--enable-reduced-surjection-proof-size],[use reduced surjection proof size (disabling parsing and verification) [default=no]]),
[use_reduced_surjection_proof_size=$enableval],
[use_reduced_surjection_proof_size=no])
[],
[SECP_SET_DEFAULT([use_reduced_surjection_proof_size], [no], [no])])
# Test-only override of the (autodetected by the C code) "widemul" setting.
# Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
@ -300,14 +300,14 @@ else
fi
# Select assembly optimization
use_external_asm=no
enable_external_asm=no
case $set_asm in
x86_64)
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
;;
arm)
use_external_asm=yes
enable_external_asm=yes
;;
no)
;;
@ -316,7 +316,7 @@ no)
;;
esac
if test x"$use_external_asm" = x"yes"; then
if test x"$enable_external_asm" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
fi
@ -430,7 +430,7 @@ if test x"$enable_module_ecdsa_s2c" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDSA_S2C, 1, [Define this symbol to enable the ECDSA sign-to-contract module])
fi
if test x"$use_external_default_callbacks" = x"yes"; then
if test x"$enable_external_default_callbacks" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
fi
@ -455,8 +455,6 @@ if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([Building key whitelisting module: $enable_module_whitelist])
AC_MSG_NOTICE([Building surjection proof module: $enable_module_surjectionproof])
AC_MSG_NOTICE([Building MuSig module: $enable_module_musig])
AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys])
AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig])
AC_MSG_NOTICE([Building ECDSA sign-to-contract module: $enable_module_ecdsa_s2c])
AC_MSG_NOTICE([Building ECDSA adaptor signatures module: $enable_module_ecdsa_adaptor])
AC_MSG_NOTICE([******])
@ -486,12 +484,6 @@ else
if test x"$enable_module_musig" = x"yes"; then
AC_MSG_ERROR([MuSig module is experimental. Use --enable-experimental to allow.])
fi
if test x"$enable_module_extrakeys" = x"yes"; then
AC_MSG_ERROR([extrakeys module is experimental. Use --enable-experimental to allow.])
fi
if test x"$enable_module_schnorrsig" = x"yes"; then
AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.])
fi
if test x"$enable_module_ecdsa_s2c" = x"yes"; then
AC_MSG_ERROR([ECDSA sign-to-contract module module is experimental. Use --enable-experimental to allow.])
fi
@ -527,9 +519,10 @@ AC_SUBST(SECP_TEST_LIBS)
AC_SUBST(SECP_TEST_INCLUDES)
AC_SUBST(SECP_CFLAGS)
AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"])
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"])
AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
@ -540,27 +533,24 @@ AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_S2C], [test x"$enable_module_ecdsa_s2c" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_ADAPTOR], [test x"$enable_module_ecdsa_adaptor" = x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = 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([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"])
AM_CONDITIONAL([USE_REDUCED_SURJECTION_PROOF_SIZE], [test x"$use_reduced_surjection_proof_size" = x"yes"])
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT)
AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION)
AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE)
# Make sure nothing new is exported so that we don't break the cache.
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
unset PKG_CONFIG_PATH
PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
AC_OUTPUT
echo
echo "Build Options:"
echo " with external callbacks = $use_external_default_callbacks"
echo " with benchmarks = $use_benchmark"
echo " with tests = $use_tests"
echo " with external callbacks = $enable_external_default_callbacks"
echo " with benchmarks = $enable_benchmark"
echo " with tests = $enable_tests"
echo " with coverage = $enable_coverage"
echo " with examples = $enable_examples"
echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo " module extrakeys = $enable_module_extrakeys"

121
examples/EXAMPLES_COPYING Normal file
View File

@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

127
examples/ecdh.c Normal file
View File

@ -0,0 +1,127 @@
/*************************************************************************
* Written in 2020-2022 by Elichai Turkel *
* To the extent possible under law, the author(s) have dedicated all *
* copyright and related and neighboring rights to the software in this *
* file to the public domain worldwide. This software is distributed *
* without any warranty. For the CC0 Public Domain Dedication, see *
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
*************************************************************************/
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <secp256k1.h>
#include <secp256k1_ecdh.h>
#include "random.h"
int main(void) {
unsigned char seckey1[32];
unsigned char seckey2[32];
unsigned char compressed_pubkey1[33];
unsigned char compressed_pubkey2[33];
unsigned char shared_secret1[32];
unsigned char shared_secret2[32];
unsigned char randomize[32];
int return_val;
size_t len;
secp256k1_pubkey pubkey1;
secp256k1_pubkey pubkey2;
/* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create`
* needs a context object initialized for signing, which is why we create
* a context with the SECP256K1_CONTEXT_SIGN flag.
* (The docs for `secp256k1_ecdh` don't require any special context, just
* some initialized context) */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;
}
/* Randomizing the context is recommended to protect against side-channel
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
* information about it. This should never fail. */
return_val = secp256k1_context_randomize(ctx, randomize);
assert(return_val);
/*** Key Generation ***/
/* If the secret key is zero or out of range (bigger than secp256k1's
* order), we try to sample a new key. Note that the probability of this
* happening is negligible. */
while (1) {
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
printf("Failed to generate randomness\n");
return 1;
}
if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) {
break;
}
}
/* Public key creation using a valid context with a verified secret key should never fail */
return_val = secp256k1_ec_pubkey_create(ctx, &pubkey1, seckey1);
assert(return_val);
return_val = secp256k1_ec_pubkey_create(ctx, &pubkey2, seckey2);
assert(return_val);
/* Serialize pubkey1 in a compressed form (33 bytes), should always return 1 */
len = sizeof(compressed_pubkey1);
return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey1, &len, &pubkey1, SECP256K1_EC_COMPRESSED);
assert(return_val);
/* Should be the same size as the size of the output, because we passed a 33 byte array. */
assert(len == sizeof(compressed_pubkey1));
/* Serialize pubkey2 in a compressed form (33 bytes) */
len = sizeof(compressed_pubkey2);
return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey2, &len, &pubkey2, SECP256K1_EC_COMPRESSED);
assert(return_val);
/* Should be the same size as the size of the output, because we passed a 33 byte array. */
assert(len == sizeof(compressed_pubkey2));
/*** Creating the shared secret ***/
/* Perform ECDH with seckey1 and pubkey2. Should never fail with a verified
* seckey and valid pubkey */
return_val = secp256k1_ecdh(ctx, shared_secret1, &pubkey2, seckey1, NULL, NULL);
assert(return_val);
/* Perform ECDH with seckey2 and pubkey1. Should never fail with a verified
* seckey and valid pubkey */
return_val = secp256k1_ecdh(ctx, shared_secret2, &pubkey1, seckey2, NULL, NULL);
assert(return_val);
/* Both parties should end up with the same shared secret */
return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1));
assert(return_val == 0);
printf("Secret Key1: ");
print_hex(seckey1, sizeof(seckey1));
printf("Compressed Pubkey1: ");
print_hex(compressed_pubkey1, sizeof(compressed_pubkey1));
printf("\nSecret Key2: ");
print_hex(seckey2, sizeof(seckey2));
printf("Compressed Pubkey2: ");
print_hex(compressed_pubkey2, sizeof(compressed_pubkey2));
printf("\nShared Secret: ");
print_hex(shared_secret1, sizeof(shared_secret1));
/* This will clear everything from the context and free the memory */
secp256k1_context_destroy(ctx);
/* It's best practice to try to clear secrets from memory after using them.
* This is done because some bugs can allow an attacker to leak memory, for
* example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
*
* TODO: Prevent these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */
memset(seckey1, 0, sizeof(seckey1));
memset(seckey2, 0, sizeof(seckey2));
memset(shared_secret1, 0, sizeof(shared_secret1));
memset(shared_secret2, 0, sizeof(shared_secret2));
return 0;
}

137
examples/ecdsa.c Normal file
View File

@ -0,0 +1,137 @@
/*************************************************************************
* Written in 2020-2022 by Elichai Turkel *
* To the extent possible under law, the author(s) have dedicated all *
* copyright and related and neighboring rights to the software in this *
* file to the public domain worldwide. This software is distributed *
* without any warranty. For the CC0 Public Domain Dedication, see *
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
*************************************************************************/
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <secp256k1.h>
#include "random.h"
int main(void) {
/* Instead of signing the message directly, we must sign a 32-byte hash.
* Here the message is "Hello, world!" and the hash function was SHA-256.
* An actual implementation should just call SHA-256, but this example
* hardcodes the output to avoid depending on an additional library.
* See https://bitcoin.stackexchange.com/questions/81115/if-someone-wanted-to-pretend-to-be-satoshi-by-posting-a-fake-signature-to-defrau/81116#81116 */
unsigned char msg_hash[32] = {
0x31, 0x5F, 0x5B, 0xDB, 0x76, 0xD0, 0x78, 0xC4,
0x3B, 0x8A, 0xC0, 0x06, 0x4E, 0x4A, 0x01, 0x64,
0x61, 0x2B, 0x1F, 0xCE, 0x77, 0xC8, 0x69, 0x34,
0x5B, 0xFC, 0x94, 0xC7, 0x58, 0x94, 0xED, 0xD3,
};
unsigned char seckey[32];
unsigned char randomize[32];
unsigned char compressed_pubkey[33];
unsigned char serialized_signature[64];
size_t len;
int is_signature_valid;
int return_val;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
/* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create` needs
* a context object initialized for signing and `secp256k1_ecdsa_verify` needs
* a context initialized for verification, which is why we create a context
* for both signing and verification with the SECP256K1_CONTEXT_SIGN and
* SECP256K1_CONTEXT_VERIFY flags. */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;
}
/* Randomizing the context is recommended to protect against side-channel
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
* information about it. This should never fail. */
return_val = secp256k1_context_randomize(ctx, randomize);
assert(return_val);
/*** Key Generation ***/
/* If the secret key is zero or out of range (bigger than secp256k1's
* order), we try to sample a new key. Note that the probability of this
* happening is negligible. */
while (1) {
if (!fill_random(seckey, sizeof(seckey))) {
printf("Failed to generate randomness\n");
return 1;
}
if (secp256k1_ec_seckey_verify(ctx, seckey)) {
break;
}
}
/* Public key creation using a valid context with a verified secret key should never fail */
return_val = secp256k1_ec_pubkey_create(ctx, &pubkey, seckey);
assert(return_val);
/* Serialize the pubkey in a compressed form(33 bytes). Should always return 1. */
len = sizeof(compressed_pubkey);
return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey, &len, &pubkey, SECP256K1_EC_COMPRESSED);
assert(return_val);
/* Should be the same size as the size of the output, because we passed a 33 byte array. */
assert(len == sizeof(compressed_pubkey));
/*** Signing ***/
/* Generate an ECDSA signature `noncefp` and `ndata` allows you to pass a
* custom nonce function, passing `NULL` will use the RFC-6979 safe default.
* Signing with a valid context, verified secret key
* and the default nonce function should never fail. */
return_val = secp256k1_ecdsa_sign(ctx, &sig, msg_hash, seckey, NULL, NULL);
assert(return_val);
/* Serialize the signature in a compact form. Should always return 1
* according to the documentation in secp256k1.h. */
return_val = secp256k1_ecdsa_signature_serialize_compact(ctx, serialized_signature, &sig);
assert(return_val);
/*** Verification ***/
/* Deserialize the signature. This will return 0 if the signature can't be parsed correctly. */
if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, serialized_signature)) {
printf("Failed parsing the signature\n");
return 1;
}
/* Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */
if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) {
printf("Failed parsing the public key\n");
return 1;
}
/* Verify a signature. This will return 1 if it's valid and 0 if it's not. */
is_signature_valid = secp256k1_ecdsa_verify(ctx, &sig, msg_hash, &pubkey);
printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false");
printf("Secret Key: ");
print_hex(seckey, sizeof(seckey));
printf("Public Key: ");
print_hex(compressed_pubkey, sizeof(compressed_pubkey));
printf("Signature: ");
print_hex(serialized_signature, sizeof(serialized_signature));
/* This will clear everything from the context and free the memory */
secp256k1_context_destroy(ctx);
/* It's best practice to try to clear secrets from memory after using them.
* This is done because some bugs can allow an attacker to leak memory, for
* example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
*
* TODO: Prevent these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */
memset(seckey, 0, sizeof(seckey));
return 0;
}

View File

@ -1,8 +1,11 @@
/***********************************************************************
* Copyright (c) 2018 Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/*************************************************************************
* Written in 2018 by Jonas Nick *
* To the extent possible under law, the author(s) have dedicated all *
* copyright and related and neighboring rights to the software in this *
* file to the public domain worldwide. This software is distributed *
* without any warranty. For the CC0 Public Domain Dedication, see *
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
*************************************************************************/
/** This file demonstrates how to use the MuSig module to create a
* 3-of-3 multisignature. Additionally, see the documentation in
@ -15,6 +18,8 @@
#include <secp256k1_schnorrsig.h>
#include <secp256k1_musig.h>
#include "random.h"
struct signer_secrets {
secp256k1_keypair keypair;
secp256k1_musig_secnonce secnonce;
@ -31,20 +36,14 @@ struct signer {
/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */
int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) {
unsigned char seckey[32];
FILE *frand = fopen("/dev/urandom", "r");
if (frand == NULL) {
return 0;
}
do {
if(!fread(seckey, sizeof(seckey), 1, frand)) {
fclose(frand);
return 0;
}
/* The probability that this not a valid secret key is approximately 2^-128 */
} while (!secp256k1_ec_seckey_verify(ctx, seckey));
fclose(frand);
if (!secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) {
return 0;
while (1) {
if (!fill_random(seckey, sizeof(seckey))) {
printf("Failed to generate randomness\n");
return 1;
}
if (secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) {
break;
}
}
if (!secp256k1_keypair_xonly_pub(ctx, &signer->pubkey, NULL, &signer_secrets->keypair)) {
return 0;
@ -100,21 +99,14 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
secp256k1_musig_session session;
for (i = 0; i < N_SIGNERS; i++) {
FILE *frand;
unsigned char seckey[32];
unsigned char session_id[32];
/* Create random session ID. It is absolutely necessary that the session ID
* is unique for every call of secp256k1_musig_nonce_gen. Otherwise
* it's trivial for an attacker to extract the secret key! */
frand = fopen("/dev/urandom", "r");
if(frand == NULL) {
if (!fill_random(session_id, sizeof(session_id))) {
return 0;
}
if (!fread(session_id, 32, 1, frand)) {
fclose(frand);
return 0;
}
fclose(frand);
if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) {
return 0;
}

73
examples/random.h Normal file
View File

@ -0,0 +1,73 @@
/*************************************************************************
* Copyright (c) 2020-2021 Elichai Turkel *
* Distributed under the CC0 software license, see the accompanying file *
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
*************************************************************************/
/*
* This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems.
* It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below.
*
* Platform randomness sources:
* Linux -> `getrandom(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. http://man7.org/linux/man-pages/man2/getrandom.2.html, https://linux.die.net/man/4/urandom
* macOS -> `getentropy(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. https://www.unix.com/man-page/mojave/2/getentropy, https://opensource.apple.com/source/xnu/xnu-517.12.7/bsd/man/man4/random.4.auto.html
* FreeBSD -> `getrandom(2)`(`sys/random.h`), if not available `kern.arandom` should be used. https://www.freebsd.org/cgi/man.cgi?query=getrandom, https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
* OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom
* Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
*/
#if defined(_WIN32)
#include <windows.h>
#include <ntstatus.h>
#include <bcrypt.h>
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/random.h>
#elif defined(__OpenBSD__)
#include <unistd.h>
#else
#error "Couldn't identify the OS"
#endif
#include <stddef.h>
#include <limits.h>
#include <stdio.h>
/* Returns 1 on success, and 0 on failure. */
static int fill_random(unsigned char* data, size_t size) {
#if defined(_WIN32)
NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
if (res != STATUS_SUCCESS || size > ULONG_MAX) {
return 0;
} else {
return 1;
}
#elif defined(__linux__) || defined(__FreeBSD__)
/* If `getrandom(2)` is not available you should fallback to /dev/urandom */
ssize_t res = getrandom(data, size, 0);
if (res < 0 || (size_t)res != size ) {
return 0;
} else {
return 1;
}
#elif defined(__APPLE__) || defined(__OpenBSD__)
/* If `getentropy(2)` is not available you should fallback to either
* `SecRandomCopyBytes` or /dev/urandom */
int res = getentropy(data, size);
if (res == 0) {
return 1;
} else {
return 0;
}
#endif
return 0;
}
static void print_hex(unsigned char* data, size_t size) {
size_t i;
printf("0x");
for (i = 0; i < size; i++) {
printf("%02x", data[i]);
}
printf("\n");
}

152
examples/schnorr.c Normal file
View File

@ -0,0 +1,152 @@
/*************************************************************************
* Written in 2020-2022 by Elichai Turkel *
* To the extent possible under law, the author(s) have dedicated all *
* copyright and related and neighboring rights to the software in this *
* file to the public domain worldwide. This software is distributed *
* without any warranty. For the CC0 Public Domain Dedication, see *
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
*************************************************************************/
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <secp256k1.h>
#include <secp256k1_extrakeys.h>
#include <secp256k1_schnorrsig.h>
#include "random.h"
int main(void) {
unsigned char msg[12] = "Hello World!";
unsigned char msg_hash[32];
unsigned char tag[17] = "my_fancy_protocol";
unsigned char seckey[32];
unsigned char randomize[32];
unsigned char auxiliary_rand[32];
unsigned char serialized_pubkey[32];
unsigned char signature[64];
int is_signature_valid;
int return_val;
secp256k1_xonly_pubkey pubkey;
secp256k1_keypair keypair;
/* The specification in secp256k1_extrakeys.h states that `secp256k1_keypair_create`
* needs a context object initialized for signing. And in secp256k1_schnorrsig.h
* they state that `secp256k1_schnorrsig_verify` needs a context initialized for
* verification, which is why we create a context for both signing and verification
* with the SECP256K1_CONTEXT_SIGN and SECP256K1_CONTEXT_VERIFY flags. */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;
}
/* Randomizing the context is recommended to protect against side-channel
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
* information about it. This should never fail. */
return_val = secp256k1_context_randomize(ctx, randomize);
assert(return_val);
/*** Key Generation ***/
/* If the secret key is zero or out of range (bigger than secp256k1's
* order), we try to sample a new key. Note that the probability of this
* happening is negligible. */
while (1) {
if (!fill_random(seckey, sizeof(seckey))) {
printf("Failed to generate randomness\n");
return 1;
}
/* Try to create a keypair with a valid context, it should only fail if
* the secret key is zero or out of range. */
if (secp256k1_keypair_create(ctx, &keypair, seckey)) {
break;
}
}
/* Extract the X-only public key from the keypair. We pass NULL for
* `pk_parity` as the parity isn't needed for signing or verification.
* `secp256k1_keypair_xonly_pub` supports returning the parity for
* other use cases such as tests or verifying Taproot tweaks.
* This should never fail with a valid context and public key. */
return_val = secp256k1_keypair_xonly_pub(ctx, &pubkey, NULL, &keypair);
assert(return_val);
/* Serialize the public key. Should always return 1 for a valid public key. */
return_val = secp256k1_xonly_pubkey_serialize(ctx, serialized_pubkey, &pubkey);
assert(return_val);
/*** Signing ***/
/* Instead of signing (possibly very long) messages directly, we sign a
* 32-byte hash of the message in this example.
*
* We use secp256k1_tagged_sha256 to create this hash. This function expects
* a context-specific "tag", which restricts the context in which the signed
* messages should be considered valid. For example, if protocol A mandates
* to use the tag "my_fancy_protocol" and protocol B mandates to use the tag
* "my_boring_protocol", then signed messages from protocol A will never be
* valid in protocol B (and vice versa), even if keys are reused across
* protocols. This implements "domain separation", which is considered good
* practice. It avoids attacks in which users are tricked into signing a
* message that has intended consequences in the intended context (e.g.,
* protocol A) but would have unintended consequences if it were valid in
* some other context (e.g., protocol B). */
return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg));
assert(return_val);
/* Generate 32 bytes of randomness to use with BIP-340 schnorr signing. */
if (!fill_random(auxiliary_rand, sizeof(auxiliary_rand))) {
printf("Failed to generate randomness\n");
return 1;
}
/* Generate a Schnorr signature.
*
* We use the secp256k1_schnorrsig_sign32 function that provides a simple
* interface for signing 32-byte messages (which in our case is a hash of
* the actual message). BIP-340 recommends passing 32 bytes of randomness
* to the signing function to improve security against side-channel attacks.
* Signing with a valid context, a 32-byte message, a verified keypair, and
* any 32 bytes of auxiliary random data should never fail. */
return_val = secp256k1_schnorrsig_sign32(ctx, signature, msg_hash, &keypair, auxiliary_rand);
assert(return_val);
/*** Verification ***/
/* Deserialize the public key. This will return 0 if the public key can't
* be parsed correctly */
if (!secp256k1_xonly_pubkey_parse(ctx, &pubkey, serialized_pubkey)) {
printf("Failed parsing the public key\n");
return 1;
}
/* Compute the tagged hash on the received messages using the same tag as the signer. */
return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg));
assert(return_val);
/* Verify a signature. This will return 1 if it's valid and 0 if it's not. */
is_signature_valid = secp256k1_schnorrsig_verify(ctx, signature, msg_hash, 32, &pubkey);
printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false");
printf("Secret Key: ");
print_hex(seckey, sizeof(seckey));
printf("Public Key: ");
print_hex(serialized_pubkey, sizeof(serialized_pubkey));
printf("Signature: ");
print_hex(signature, sizeof(signature));
/* This will clear everything from the context and free the memory */
secp256k1_context_destroy(ctx);
/* It's best practice to try to clear secrets from memory after using them.
* This is done because some bugs can allow an attacker to leak memory, for
* example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
*
* TODO: Prevent these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */
memset(seckey, 0, sizeof(seckey));
return 0;
}

View File

@ -169,6 +169,17 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_ARG_NONNULL(_x)
# endif
/** Attribute for marking functions, types, and variables as deprecated */
#if !defined(SECP256K1_BUILD) && defined(__has_attribute)
# if __has_attribute(__deprecated__)
# define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg)))
# else
# define SECP256K1_DEPRECATED(_msg)
# endif
#else
# define SECP256K1_DEPRECATED(_msg)
#endif
/** All flags' lower 8 bits indicate what they're for. Do not use directly. */
#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
@ -641,7 +652,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
const secp256k1_context* ctx,
unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2)
SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead");
/** Negates a public key in place.
*
@ -681,7 +693,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
const secp256k1_context* ctx,
unsigned char *seckey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_add instead");
/** Tweak a public key by adding tweak times the generator to it.
*
@ -727,7 +740,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
const secp256k1_context* ctx,
unsigned char *seckey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_mul instead");
/** Tweak a public key by multiplying it by a tweak value.
*
@ -800,7 +814,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
* implementations optimized for a specific tag can precompute the SHA256 state
* after hashing the tag hashes.
*
* Returns 0 if the arguments are invalid and 1 otherwise.
* Returns: 1 always.
* Args: ctx: pointer to a context object
* Out: hash32: pointer to a 32-byte array to store the resulting hash
* In: tag: pointer to an array containing the tag

View File

@ -81,8 +81,7 @@ SECP256K1_API int secp256k1_xonly_pubkey_cmp(
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
*
* Returns: 1 if the public key was successfully converted
* 0 otherwise
* Returns: 1 always.
*
* Args: ctx: pointer to a context object.
* Out: xonly_pubkey: pointer to an x-only public key object for placing the converted public key.
@ -186,7 +185,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
/** Get the secret key from a keypair.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
* Returns: 1 always.
* Args: ctx: pointer to a context object.
* Out: seckey: pointer to a 32-byte buffer for the secret key.
* In: keypair: pointer to a keypair.
@ -199,7 +198,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
/** Get the public key from a keypair.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
* Returns: 1 always.
* Args: ctx: pointer to a context object.
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to
* the keypair public key. If not, it's set to an invalid value.
@ -216,7 +215,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
* This is the same as calling secp256k1_keypair_pub and then
* secp256k1_xonly_pubkey_from_pubkey.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
* Returns: 1 always.
* Args: ctx: pointer to a context object.
* Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set
* to the keypair public key after converting it to an

View File

@ -116,7 +116,7 @@ typedef struct {
* BIP-340 "Default Signing" for a full explanation of this
* argument and for guidance if randomness is expensive.
*/
SECP256K1_API int secp256k1_schnorrsig_sign(
SECP256K1_API int secp256k1_schnorrsig_sign32(
const secp256k1_context* ctx,
unsigned char *sig64,
const unsigned char *msg32,
@ -124,6 +124,17 @@ SECP256K1_API int secp256k1_schnorrsig_sign(
const unsigned char *aux_rand32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Same as secp256k1_schnorrsig_sign32, but DEPRECATED. Will be removed in
* future versions. */
SECP256K1_API int secp256k1_schnorrsig_sign(
const secp256k1_context* ctx,
unsigned char *sig64,
const unsigned char *msg32,
const secp256k1_keypair *keypair,
const unsigned char *aux_rand32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
SECP256K1_DEPRECATED("Use secp256k1_schnorrsig_sign32 instead");
/** Create a Schnorr signature with a more flexible API.
*
* Same arguments as secp256k1_schnorrsig_sign except that it allows signing

View File

@ -164,6 +164,9 @@ class constraints:
def negate(self):
return constraints(zero=self.nonzero, nonzero=self.zero)
def map(self, fun):
return constraints(zero={fun(k): v for k, v in self.zero.items()}, nonzero={fun(k): v for k, v in self.nonzero.items()})
def __add__(self, other):
zero = self.zero.copy()
zero.update(other.zero)
@ -177,6 +180,30 @@ class constraints:
def __repr__(self):
return "%s" % self
def normalize_factor(p):
"""Normalizes the sign of primitive polynomials (as returned by factor())
This function ensures that the polynomial has a positive leading coefficient.
This is necessary because recent sage versions (starting with v9.3 or v9.4,
we don't know) are inconsistent about the placement of the minus sign in
polynomial factorizations:
```
sage: R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex')
sage: R((-2 * (bx - ax)) ^ 1).factor()
(-2) * (bx - ax)
sage: R((-2 * (bx - ax)) ^ 2).factor()
(4) * (-bx + ax)^2
sage: R((-2 * (bx - ax)) ^ 3).factor()
(8) * (-bx + ax)^3
```
"""
# Assert p is not 0 and that its non-zero coeffients are coprime.
# (We could just work with the primitive part p/p.content() but we want to be
# aware if factor() does not return a primitive part in future sage versions.)
assert p.content() == 1
# Ensure that the first non-zero coefficient is positive.
return p if p.lc() > 0 else -p
def conflicts(R, con):
"""Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
@ -204,10 +231,10 @@ def get_nonzero_set(R, assume):
nonzero = set()
for nz in map(numerator, assume.nonzero):
for (f,n) in nz.factor():
nonzero.add(f)
nonzero.add(normalize_factor(f))
rnz = zero.reduce(nz)
for (f,n) in rnz.factor():
nonzero.add(f)
nonzero.add(normalize_factor(f))
return nonzero
@ -222,27 +249,27 @@ def prove_nonzero(R, exprs, assume):
return (False, [exprs[expr]])
allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1)
for (f, n) in allexprs.factor():
if f not in nonzero:
if normalize_factor(f) not in nonzero:
ok = False
if ok:
return (True, None)
ok = True
for (f, n) in zero.reduce(numerator(allexprs)).factor():
if f not in nonzero:
for (f, n) in zero.reduce(allexprs).factor():
if normalize_factor(f) not in nonzero:
ok = False
if ok:
return (True, None)
ok = True
for expr in exprs:
for (f,n) in numerator(expr).factor():
if f not in nonzero:
if normalize_factor(f) not in nonzero:
ok = False
if ok:
return (True, None)
ok = True
for expr in exprs:
for (f,n) in zero.reduce(numerator(expr)).factor():
if f not in nonzero:
if normalize_factor(f) not in nonzero:
expl.add(exprs[expr])
if expl:
return (False, list(expl))
@ -254,7 +281,7 @@ def prove_zero(R, exprs, assume):
"""Check whether all of the passed expressions are provably zero, given assumptions"""
r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)
if not r:
return (False, map(lambda x: "Possibly zero denominator: %s" % x, e))
return (False, list(map(lambda x: "Possibly zero denominator: %s" % x, e)))
zero = R.ideal(list(map(numerator, assume.zero)))
nonzero = prod(x for x in assume.nonzero)
expl = []
@ -279,8 +306,8 @@ def describe_extra(R, assume, assumeExtra):
if base not in zero:
add = []
for (f, n) in numerator(base).factor():
if f not in nonzero:
add += ["%s" % f]
if normalize_factor(f) not in nonzero:
add += ["%s" % normalize_factor(f)]
if add:
ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base])
# Iterate over the extra nonzero expressions
@ -288,8 +315,8 @@ def describe_extra(R, assume, assumeExtra):
nzr = zeroextra.reduce(numerator(nz))
if nzr not in zeroextra:
for (f,n) in nzr.factor():
if zeroextra.reduce(f) not in nonzero:
ret.add("%s != 0" % zeroextra.reduce(f))
if normalize_factor(zeroextra.reduce(f)) not in nonzero:
ret.add("%s != 0" % normalize_factor(zeroextra.reduce(f)))
return ", ".join(x for x in ret)
@ -299,22 +326,21 @@ def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require):
if conflicts(R, assume):
# This formula does not apply
return None
return (True, None)
describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert)
if describe != "":
describe = " (assuming " + describe + ")"
ok, msg = prove_zero(R, require.zero, assume)
if not ok:
return "FAIL, %s fails (assuming %s)" % (str(msg), describe)
return (False, "FAIL, %s fails%s" % (str(msg), describe))
res, expl = prove_nonzero(R, require.nonzero, assume)
if not res:
return "FAIL, %s fails (assuming %s)" % (str(expl), describe)
return (False, "FAIL, %s fails%s" % (str(expl), describe))
if describe != "":
return "OK (assuming %s)" % describe
else:
return "OK"
return (True, "OK%s" % describe)
def concrete_verify(c):

View File

@ -8,25 +8,20 @@ load("weierstrass_prover.sage")
def formula_secp256k1_gej_double_var(a):
"""libsecp256k1's secp256k1_gej_double_var, used by various addition functions"""
rz = a.Z * a.Y
rz = rz * 2
t1 = a.X^2
t1 = t1 * 3
t2 = t1^2
t3 = a.Y^2
t3 = t3 * 2
t4 = t3^2
t4 = t4 * 2
t3 = t3 * a.X
rx = t3
rx = rx * 4
rx = -rx
rx = rx + t2
t2 = -t2
t3 = t3 * 6
t3 = t3 + t2
ry = t1 * t3
t2 = -t4
ry = ry + t2
s = a.Y^2
l = a.X^2
l = l * 3
l = l / 2
t = -s
t = t * a.X
rx = l^2
rx = rx + t
rx = rx + t
s = s^2
t = t + rx
ry = t * l
ry = ry + s
ry = -ry
return jacobianpoint(rx, ry, rz)
def formula_secp256k1_gej_add_var(branch, a, b):
@ -197,7 +192,8 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
rr_alt = rr
m_alt = m
n = m_alt^2
q = n * t
q = -t
q = q * n
n = n^2
if degenerate:
n = m
@ -210,8 +206,6 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
zeroes.update({rz : 'r.z=0'})
else:
nonzeroes.update({rz : 'r.z!=0'})
rz = rz * 2
q = -q
t = t + q
rx = t
t = t * 2
@ -219,8 +213,7 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
t = t * rr_alt
t = t + n
ry = -t
rx = rx * 4
ry = ry * 4
ry = ry / 2
if a_infinity:
rx = b.X
ry = b.Y
@ -292,15 +285,18 @@ def formula_secp256k1_gej_add_ge_old(branch, a, b):
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz))
if __name__ == "__main__":
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)
success = True
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
success = success & (not check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old))
if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
success = success & (not check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43))
sys.exit(int(not success))

View File

@ -184,6 +184,7 @@ def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
if r:
points.append(point)
ret = True
for za in range(1, p):
for zb in range(1, p):
for pa in points:
@ -211,8 +212,11 @@ def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
match = True
r, e = concrete_verify(require)
if not r:
ret = False
print(" failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e))
print()
return ret
def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
@ -244,15 +248,21 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
print("Formula " + name + ":")
count = 0
ret = True
for branch in range(branches):
assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
assumeBranch = assumeBranch.map(lift)
assumeFormula = assumeFormula.map(lift)
pC.X = lift(pC.X)
pC.Y = lift(pC.Y)
pC.Z = lift(pC.Z)
pC.Infinity = lift(pC.Infinity)
for key in laws_jacobian_weierstrass:
res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))
success, msg = check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC)
if not success:
ret = False
res[key].append((msg, branch))
for key in res:
print(" %s:" % key)
@ -262,3 +272,4 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
print(" branch %i: %s" % (x[1], x[0]))
print()
return ret

View File

@ -140,6 +140,15 @@ void bench_scalar_inverse_var(void* arg, int iters) {
CHECK(j <= iters);
}
void bench_field_half(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
secp256k1_fe_half(&data->fe[0]);
}
}
void bench_field_normalize(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -372,6 +381,7 @@ int main(int argc, char **argv) {
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "half")) run_benchmark("field_half", bench_field_half, bench_setup, NULL, &data, 10, iters*100);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, iters*100);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, iters*100);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10);

View File

@ -19,13 +19,10 @@
* It only operates on tables sized for WINDOW_A wnaf multiples.
*/
static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
/* Compute the odd multiples in Jacobian form. */
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a);
/* Bring them to the same Z denominator. */
secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr);
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr, globalz, a);
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr);
}
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */

View File

@ -47,7 +47,7 @@
/* The number of objects allocated on the scratch space for ecmult_multi algorithms */
#define PIPPENGER_SCRATCH_OBJECTS 6
#define STRAUSS_SCRATCH_OBJECTS 7
#define STRAUSS_SCRATCH_OBJECTS 5
#define PIPPENGER_MAX_BUCKET_WINDOW 12
@ -56,14 +56,23 @@
#define ECMULT_MAX_POINTS_PER_BATCH 5000000
/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain
* the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will
* contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z.
* Prej's Z values are undefined, except for the last value.
/** Fill a table 'pre_a' with precomputed odd multiples of a.
* pre_a will contain [1*a,3*a,...,(2*n-1)*a], so it needs space for n group elements.
* zr needs space for n field elements.
*
* Although pre_a is an array of _ge rather than _gej, it actually represents elements
* in Jacobian coordinates with their z coordinates omitted. The omitted z-coordinates
* can be recovered using z and zr. Using the notation z(b) to represent the omitted
* z coordinate of b:
* - z(pre_a[n-1]) = 'z'
* - z(pre_a[i-1]) = z(pre_a[i]) / zr[i] for n > i > 0
*
* Lastly the zr[0] value, which isn't used above, is set so that:
* - a.z = z(pre_a[0]) / zr[0]
*/
static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) {
secp256k1_gej d;
secp256k1_ge a_ge, d_ge;
static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) {
secp256k1_gej d, ai;
secp256k1_ge d_ge;
int i;
VERIFY_CHECK(!a->infinity);
@ -71,56 +80,74 @@ static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, sec
secp256k1_gej_double_var(&d, a, NULL);
/*
* Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate
* of 'd', and scale the 1P starting value's x/y coordinates without changing its z.
* Perform the additions using an isomorphic curve Y^2 = X^3 + 7*C^6 where C := d.z.
* The isomorphism, phi, maps a secp256k1 point (x, y) to the point (x*C^2, y*C^3) on the other curve.
* In Jacobian coordinates phi maps (x, y, z) to (x*C^2, y*C^3, z) or, equivalently to (x, y, z/C).
*
* phi(x, y, z) = (x*C^2, y*C^3, z) = (x, y, z/C)
* d_ge := phi(d) = (d.x, d.y, 1)
* ai := phi(a) = (a.x*C^2, a.y*C^3, a.z)
*
* The group addition functions work correctly on these isomorphic curves.
* In particular phi(d) is easy to represent in affine coordinates under this isomorphism.
* This lets us use the faster secp256k1_gej_add_ge_var group addition function that we wouldn't be able to use otherwise.
*/
d_ge.x = d.x;
d_ge.y = d.y;
d_ge.infinity = 0;
secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z);
prej[0].x = a_ge.x;
prej[0].y = a_ge.y;
prej[0].z = a->z;
prej[0].infinity = 0;
secp256k1_ge_set_xy(&d_ge, &d.x, &d.y);
secp256k1_ge_set_gej_zinv(&pre_a[0], a, &d.z);
secp256k1_gej_set_ge(&ai, &pre_a[0]);
ai.z = a->z;
/* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equvalent to a.
* Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z.
*/
zr[0] = d.z;
for (i = 1; i < n; i++) {
secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]);
secp256k1_gej_add_ge_var(&ai, &ai, &d_ge, &zr[i]);
secp256k1_ge_set_xy(&pre_a[i], &ai.x, &ai.y);
}
/*
* Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only
* the final point's z coordinate is actually used though, so just update that.
/* Multiply the last z-coordinate by C to undo the isomorphism.
* Since the z-coordinates of the pre_a values are implied by the zr array of z-coordinate ratios,
* undoing the isomorphism here undoes the isomorphism for all pre_a values.
*/
secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z);
secp256k1_fe_mul(z, &ai.z, &d.z);
}
/** The following two macro retrieves a particular odd multiple from a table
* of precomputed multiples. */
#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \
#define SECP256K1_ECMULT_TABLE_VERIFY(n,w) \
VERIFY_CHECK(((n) & 1) == 1); \
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
if ((n) > 0) { \
*(r) = (pre)[((n)-1)/2]; \
} else { \
*(r) = (pre)[(-(n)-1)/2]; \
secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
} \
} while(0)
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1));
#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \
VERIFY_CHECK(((n) & 1) == 1); \
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
if ((n) > 0) { \
secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \
} else { \
secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \
secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
} \
} while(0)
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge(secp256k1_ge *r, const secp256k1_ge *pre, int n, int w) {
SECP256K1_ECMULT_TABLE_VERIFY(n,w)
if (n > 0) {
*r = pre[(n-1)/2];
} else {
*r = pre[(-n-1)/2];
secp256k1_fe_negate(&(r->y), &(r->y), 1);
}
}
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_lambda(secp256k1_ge *r, const secp256k1_ge *pre, const secp256k1_fe *x, int n, int w) {
SECP256K1_ECMULT_TABLE_VERIFY(n,w)
if (n > 0) {
secp256k1_ge_set_xy(r, &x[(n-1)/2], &pre[(n-1)/2].y);
} else {
secp256k1_ge_set_xy(r, &x[(-n-1)/2], &pre[(-n-1)/2].y);
secp256k1_fe_negate(&(r->y), &(r->y), 1);
}
}
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_storage(secp256k1_ge *r, const secp256k1_ge_storage *pre, int n, int w) {
SECP256K1_ECMULT_TABLE_VERIFY(n,w)
if (n > 0) {
secp256k1_ge_from_storage(r, &pre[(n-1)/2]);
} else {
secp256k1_ge_from_storage(r, &pre[(-n-1)/2]);
secp256k1_fe_negate(&(r->y), &(r->y), 1);
}
}
/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits),
* with the following guarantees:
@ -182,19 +209,16 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
}
struct secp256k1_strauss_point_state {
secp256k1_scalar na_1, na_lam;
int wnaf_na_1[129];
int wnaf_na_lam[129];
int bits_na_1;
int bits_na_lam;
size_t input_pos;
};
struct secp256k1_strauss_state {
secp256k1_gej* prej;
secp256k1_fe* zr;
/* aux is used to hold z-ratios, and then used to hold pre_a[i].x * BETA values. */
secp256k1_fe* aux;
secp256k1_ge* pre_a;
secp256k1_ge* pre_a_lam;
struct secp256k1_strauss_point_state* ps;
};
@ -212,17 +236,19 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
size_t np;
size_t no = 0;
secp256k1_fe_set_int(&Z, 1);
for (np = 0; np < num; ++np) {
secp256k1_gej tmp;
secp256k1_scalar na_1, na_lam;
if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) {
continue;
}
state->ps[no].input_pos = np;
/* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
secp256k1_scalar_split_lambda(&state->ps[no].na_1, &state->ps[no].na_lam, &na[np]);
secp256k1_scalar_split_lambda(&na_1, &na_lam, &na[np]);
/* build wnaf representation for na_1 and na_lam. */
state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &state->ps[no].na_1, WINDOW_A);
state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &state->ps[no].na_lam, WINDOW_A);
state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A);
state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A);
VERIFY_CHECK(state->ps[no].bits_na_1 <= 129);
VERIFY_CHECK(state->ps[no].bits_na_lam <= 129);
if (state->ps[no].bits_na_1 > bits) {
@ -231,40 +257,36 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
if (state->ps[no].bits_na_lam > bits) {
bits = state->ps[no].bits_na_lam;
}
/* Calculate odd multiples of a.
* All multiples are brought to the same Z 'denominator', which is stored
* in Z. Due to secp256k1' isomorphism we can do all operations pretending
* that the Z coordinate was 1, use affine addition formulae, and correct
* the Z coordinate of the result once at the end.
* The exception is the precomputed G table points, which are actually
* affine. Compared to the base used for other points, they have a Z ratio
* of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same
* isomorphism to efficiently add with a known Z inverse.
*/
tmp = a[np];
if (no) {
#ifdef VERIFY
secp256k1_fe_normalize_var(&Z);
#endif
secp256k1_gej_rescale(&tmp, &Z);
}
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp);
if (no) secp256k1_fe_mul(state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &(a[np].z));
++no;
}
/* Calculate odd multiples of a.
* All multiples are brought to the same Z 'denominator', which is stored
* in Z. Due to secp256k1' isomorphism we can do all operations pretending
* that the Z coordinate was 1, use affine addition formulae, and correct
* the Z coordinate of the result once at the end.
* The exception is the precomputed G table points, which are actually
* affine. Compared to the base used for other points, they have a Z ratio
* of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same
* isomorphism to efficiently add with a known Z inverse.
*/
if (no > 0) {
/* Compute the odd multiples in Jacobian form. */
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej, state->zr, &a[state->ps[0].input_pos]);
for (np = 1; np < no; ++np) {
secp256k1_gej tmp = a[state->ps[np].input_pos];
#ifdef VERIFY
secp256k1_fe_normalize_var(&(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
#endif
secp256k1_gej_rescale(&tmp, &(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &tmp);
secp256k1_fe_mul(state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &(a[state->ps[np].input_pos].z));
}
/* Bring them to the same Z denominator. */
secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, &Z, state->prej, state->zr);
} else {
secp256k1_fe_set_int(&Z, 1);
}
/* Bring them to the same Z denominator. */
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux);
for (np = 0; np < no; ++np) {
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
secp256k1_ge_mul_lambda(&state->pre_a_lam[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i]);
secp256k1_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i].x, &secp256k1_const_beta);
}
}
@ -290,20 +312,20 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
secp256k1_gej_double_var(r, r, NULL);
for (np = 0; np < no; ++np) {
if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) {
ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
secp256k1_ecmult_table_get_ge(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
}
if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) {
ECMULT_TABLE_GET_GE(&tmpa, state->pre_a_lam + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
secp256k1_ecmult_table_get_ge_lambda(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
}
}
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, secp256k1_pre_g, n, WINDOW_G);
secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g, n, WINDOW_G);
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
}
if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, secp256k1_pre_g_128, n, WINDOW_G);
secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g_128, n, WINDOW_G);
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
}
}
@ -314,23 +336,19 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
}
static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_fe aux[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
struct secp256k1_strauss_point_state ps[1];
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
struct secp256k1_strauss_state state;
state.prej = prej;
state.zr = zr;
state.aux = aux;
state.pre_a = pre_a;
state.pre_a_lam = pre_a_lam;
state.ps = ps;
secp256k1_ecmult_strauss_wnaf(&state, r, 1, a, na, ng);
}
static size_t secp256k1_strauss_scratch_size(size_t n_points) {
static const size_t point_size = (2 * sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar);
static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar);
return n_points*point_size;
}
@ -351,13 +369,11 @@ static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callba
* constant and strauss_scratch_size accordingly. */
points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej));
scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar));
state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej));
state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
state.aux = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
state.pre_a_lam = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state));
if (points == NULL || scalars == NULL || state.prej == NULL || state.zr == NULL || state.pre_a == NULL || state.pre_a_lam == NULL || state.ps == NULL) {
if (points == NULL || scalars == NULL || state.aux == NULL || state.pre_a == NULL || state.ps == NULL) {
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 0;
}

View File

@ -32,6 +32,12 @@
#error "Please select wide multiplication implementation"
#endif
static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
);
/** Normalize a field element. This brings the field element to a canonical representation, reduces
* its magnitude to 1, and reduces it modulo field size `p`.
*/
@ -127,4 +133,13 @@ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_f
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
/** Halves the value of a field element modulo the field prime. Constant-time.
* For an input magnitude 'm', the output magnitude is set to 'floor(m/2) + 1'.
* The output is not guaranteed to be normalized, regardless of the input. */
static void secp256k1_fe_half(secp256k1_fe *r);
/** Sets each limb of 'r' to its upper bound at magnitude 'm'. The output will also have its
* magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
#endif /* SECP256K1_FIELD_H */

View File

@ -49,6 +49,26 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
}
#endif
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
VERIFY_CHECK(m >= 0);
VERIFY_CHECK(m <= 2048);
r->n[0] = 0x3FFFFFFUL * 2 * m;
r->n[1] = 0x3FFFFFFUL * 2 * m;
r->n[2] = 0x3FFFFFFUL * 2 * m;
r->n[3] = 0x3FFFFFFUL * 2 * m;
r->n[4] = 0x3FFFFFFUL * 2 * m;
r->n[5] = 0x3FFFFFFUL * 2 * m;
r->n[6] = 0x3FFFFFFUL * 2 * m;
r->n[7] = 0x3FFFFFFUL * 2 * m;
r->n[8] = 0x3FFFFFFUL * 2 * m;
r->n[9] = 0x03FFFFFUL * 2 * m;
#ifdef VERIFY
r->magnitude = m;
r->normalized = (m == 0);
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_normalize(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@ -1133,6 +1153,82 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
#endif
}
static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
uint32_t one = (uint32_t)1;
uint32_t mask = -(t0 & one) >> 6;
#ifdef VERIFY
secp256k1_fe_verify(r);
VERIFY_CHECK(r->magnitude < 32);
#endif
/* Bounds analysis (over the rationals).
*
* Let m = r->magnitude
* C = 0x3FFFFFFUL * 2
* D = 0x03FFFFFUL * 2
*
* Initial bounds: t0..t8 <= C * m
* t9 <= D * m
*/
t0 += 0x3FFFC2FUL & mask;
t1 += 0x3FFFFBFUL & mask;
t2 += mask;
t3 += mask;
t4 += mask;
t5 += mask;
t6 += mask;
t7 += mask;
t8 += mask;
t9 += mask >> 4;
VERIFY_CHECK((t0 & one) == 0);
/* t0..t8: added <= C/2
* t9: added <= D/2
*
* Current bounds: t0..t8 <= C * (m + 1/2)
* t9 <= D * (m + 1/2)
*/
r->n[0] = (t0 >> 1) + ((t1 & one) << 25);
r->n[1] = (t1 >> 1) + ((t2 & one) << 25);
r->n[2] = (t2 >> 1) + ((t3 & one) << 25);
r->n[3] = (t3 >> 1) + ((t4 & one) << 25);
r->n[4] = (t4 >> 1) + ((t5 & one) << 25);
r->n[5] = (t5 >> 1) + ((t6 & one) << 25);
r->n[6] = (t6 >> 1) + ((t7 & one) << 25);
r->n[7] = (t7 >> 1) + ((t8 & one) << 25);
r->n[8] = (t8 >> 1) + ((t9 & one) << 25);
r->n[9] = (t9 >> 1);
/* t0..t8: shifted right and added <= C/4 + 1/2
* t9: shifted right
*
* Current bounds: t0..t8 <= C * (m/2 + 1/2)
* t9 <= D * (m/2 + 1/4)
*/
#ifdef VERIFY
/* Therefore the output magnitude (M) has to be set such that:
* t0..t8: C * M >= C * (m/2 + 1/2)
* t9: D * M >= D * (m/2 + 1/4)
*
* It suffices for all limbs that, for any input magnitude m:
* M >= m/2 + 1/2
*
* and since we want the smallest such integer value for M:
* M == floor(m/2) + 1
*/
r->magnitude = (r->magnitude >> 1) + 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint32_t mask0, mask1;
VG_CHECK_VERIFY(r->n, sizeof(r->n));

View File

@ -58,6 +58,21 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
}
#endif
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
VERIFY_CHECK(m >= 0);
VERIFY_CHECK(m <= 2048);
r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m;
#ifdef VERIFY
r->magnitude = m;
r->normalized = (m == 0);
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_normalize(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
@ -477,6 +492,71 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
#endif
}
static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
uint64_t one = (uint64_t)1;
uint64_t mask = -(t0 & one) >> 12;
#ifdef VERIFY
secp256k1_fe_verify(r);
VERIFY_CHECK(r->magnitude < 32);
#endif
/* Bounds analysis (over the rationals).
*
* Let m = r->magnitude
* C = 0xFFFFFFFFFFFFFULL * 2
* D = 0x0FFFFFFFFFFFFULL * 2
*
* Initial bounds: t0..t3 <= C * m
* t4 <= D * m
*/
t0 += 0xFFFFEFFFFFC2FULL & mask;
t1 += mask;
t2 += mask;
t3 += mask;
t4 += mask >> 4;
VERIFY_CHECK((t0 & one) == 0);
/* t0..t3: added <= C/2
* t4: added <= D/2
*
* Current bounds: t0..t3 <= C * (m + 1/2)
* t4 <= D * (m + 1/2)
*/
r->n[0] = (t0 >> 1) + ((t1 & one) << 51);
r->n[1] = (t1 >> 1) + ((t2 & one) << 51);
r->n[2] = (t2 >> 1) + ((t3 & one) << 51);
r->n[3] = (t3 >> 1) + ((t4 & one) << 51);
r->n[4] = (t4 >> 1);
/* t0..t3: shifted right and added <= C/4 + 1/2
* t4: shifted right
*
* Current bounds: t0..t3 <= C * (m/2 + 1/2)
* t4 <= D * (m/2 + 1/4)
*/
#ifdef VERIFY
/* Therefore the output magnitude (M) has to be set such that:
* t0..t3: C * M >= C * (m/2 + 1/2)
* t4: D * M >= D * (m/2 + 1/4)
*
* It suffices for all limbs that, for any input magnitude m:
* M >= m/2 + 1/2
*
* and since we want the smallest such integer value for M:
* M == floor(m/2) + 1
*/
r->magnitude = (r->magnitude >> 1) + 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint64_t mask0, mask1;
VG_CHECK_VERIFY(r->n, sizeof(r->n));

View File

@ -140,6 +140,4 @@ static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
return secp256k1_fe_sqrt(&r, a);
}
static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
#endif /* SECP256K1_FIELD_IMPL_H */

View File

@ -9,7 +9,10 @@
#include "field.h"
/** A group element of the secp256k1 curve, in affine coordinates. */
/** A group element in affine coordinates on the secp256k1 curve,
* or occasionally on an isomorphic curve of the form y^2 = x^3 + 7*t^6.
* Note: For exhaustive test mode, secp256k1 is replaced by a small subgroup of a different curve.
*/
typedef struct {
secp256k1_fe x;
secp256k1_fe y;
@ -19,7 +22,9 @@ typedef struct {
#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0}
#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. */
/** 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.
*/
typedef struct {
secp256k1_fe x; /* actual X: x/z^2 */
secp256k1_fe y; /* actual Y: y/z^3 */
@ -70,12 +75,24 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a);
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len);
/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to
* the same global z "denominator". zr must contain the known z-ratios such
* that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y
* coordinates of the result are stored in r, the common z coordinate is
* stored in globalz. */
static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr);
/** Bring a batch of inputs to the same global z "denominator", based on ratios between
* (omitted) z coordinates of adjacent elements.
*
* Although the elements a[i] are _ge rather than _gej, they actually represent elements
* in Jacobian coordinates with their z coordinates omitted.
*
* Using the notation z(b) to represent the omitted z coordinate of b, the array zr of
* z coordinate ratios must satisfy zr[i] == z(a[i]) / z(a[i-1]) for 0 < 'i' < len.
* The zr[0] value is unused.
*
* This function adjusts the coordinates of 'a' in place so that for all 'i', z(a[i]) == z(a[len-1]).
* In other words, the initial value of z(a[len-1]) becomes the global z "denominator". Only the
* a[i].x and a[i].y coordinates are explicitly modified; the adjustment of the omitted z coordinate is
* implicit.
*
* The coordinates of the final element a[len-1] are not changed.
*/
static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr);
/** Set a group element (affine) equal to the point at infinity. */
static void secp256k1_ge_set_infinity(secp256k1_ge *r);

View File

@ -161,27 +161,26 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
}
}
static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) {
static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr) {
size_t i = len - 1;
secp256k1_fe zs;
if (len > 0) {
/* The z of the final point gives us the "global Z" for the table. */
r[i].x = a[i].x;
r[i].y = a[i].y;
/* Ensure all y values are in weak normal form for fast negation of points */
secp256k1_fe_normalize_weak(&r[i].y);
*globalz = a[i].z;
r[i].infinity = 0;
secp256k1_fe_normalize_weak(&a[i].y);
zs = zr[i];
/* Work our way backwards, using the z-ratios to scale the x/y values. */
while (i > 0) {
secp256k1_gej tmpa;
if (i != len - 1) {
secp256k1_fe_mul(&zs, &zs, &zr[i]);
}
i--;
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs);
tmpa.x = a[i].x;
tmpa.y = a[i].y;
tmpa.infinity = 0;
secp256k1_ge_set_gej_zinv(&a[i], &tmpa, &zs);
}
}
}
@ -276,37 +275,35 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
}
static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) {
/* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
*
* Note that there is an implementation described at
* https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
* which trades a multiply for a square, but in practice this is actually slower,
* mainly because it requires more normalizations.
*/
secp256k1_fe t1,t2,t3,t4;
/* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */
secp256k1_fe l, s, t;
r->infinity = a->infinity;
secp256k1_fe_mul(&r->z, &a->z, &a->y);
secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */
secp256k1_fe_sqr(&t1, &a->x);
secp256k1_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */
secp256k1_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */
secp256k1_fe_sqr(&t3, &a->y);
secp256k1_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */
secp256k1_fe_sqr(&t4, &t3);
secp256k1_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */
secp256k1_fe_mul(&t3, &t3, &a->x); /* T3 = 2*X*Y^2 (1) */
r->x = t3;
secp256k1_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */
secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */
secp256k1_fe_add(&r->x, &t2); /* X' = 9*X^4 - 8*X*Y^2 (6) */
secp256k1_fe_negate(&t2, &t2, 1); /* T2 = -9*X^4 (2) */
secp256k1_fe_mul_int(&t3, 6); /* T3 = 12*X*Y^2 (6) */
secp256k1_fe_add(&t3, &t2); /* T3 = 12*X*Y^2 - 9*X^4 (8) */
secp256k1_fe_mul(&r->y, &t1, &t3); /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */
secp256k1_fe_negate(&t2, &t4, 2); /* T2 = -8*Y^4 (3) */
secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
/* Formula used:
* L = (3/2) * X1^2
* S = Y1^2
* T = -X1*S
* X3 = L^2 + 2*T
* Y3 = -(L*(X3 + T) + S^2)
* Z3 = Y1*Z1
*/
secp256k1_fe_mul(&r->z, &a->z, &a->y); /* Z3 = Y1*Z1 (1) */
secp256k1_fe_sqr(&s, &a->y); /* S = Y1^2 (1) */
secp256k1_fe_sqr(&l, &a->x); /* L = X1^2 (1) */
secp256k1_fe_mul_int(&l, 3); /* L = 3*X1^2 (3) */
secp256k1_fe_half(&l); /* L = 3/2*X1^2 (2) */
secp256k1_fe_negate(&t, &s, 1); /* T = -S (2) */
secp256k1_fe_mul(&t, &t, &a->x); /* T = -X1*S (1) */
secp256k1_fe_sqr(&r->x, &l); /* X3 = L^2 (1) */
secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + T (2) */
secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + 2*T (3) */
secp256k1_fe_sqr(&s, &s); /* S' = S^2 (1) */
secp256k1_fe_add(&t, &r->x); /* T' = X3 + T (4) */
secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */
secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */
secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */
}
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
@ -331,7 +328,6 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
if (rzr != NULL) {
*rzr = a->y;
secp256k1_fe_normalize_weak(rzr);
secp256k1_fe_mul_int(rzr, 2);
}
secp256k1_gej_double(r, a);
@ -497,8 +493,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) {
/* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */
static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
/* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
secp256k1_fe m_alt, rr_alt;
int infinity, degenerate;
@ -519,11 +514,11 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
* Z = Z1*Z2
* T = U1+U2
* M = S1+S2
* Q = T*M^2
* Q = -T*M^2
* R = T^2-U1*U2
* X3 = 4*(R^2-Q)
* Y3 = 4*(R*(3*Q-2*R^2)-M^4)
* Z3 = 2*M*Z
* X3 = R^2+Q
* Y3 = -(R*(2*X3+Q)+M^4)/2
* Z3 = M*Z
* (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.)
*
* This formula has the benefit of being the same for both addition
@ -587,7 +582,8 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
* and denominator of lambda; R and M represent the explicit
* expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */
secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */
secp256k1_fe_negate(&q, &t, 2); /* q = -T (3) */
secp256k1_fe_mul(&q, &q, &n); /* q = Q = -T*Malt^2 (1) */
/* These two lines use the observation that either M == Malt or M == 0,
* so M^3 * Malt is either Malt^4 (which is computed by squaring), or
* zero (which is "computed" by cmov). So the cost is one squaring
@ -595,26 +591,21 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_sqr(&n, &n);
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */
secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */
secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */
infinity = secp256k1_fe_normalizes_to_zero(&r->z) & ~a->infinity;
secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */
secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */
secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */
secp256k1_fe_normalize_weak(&t);
r->x = t; /* r->x = Ralt^2-Q (1) */
secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */
secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */
secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */
secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */
secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */
secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */
secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */
secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */
r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */
secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */
secp256k1_fe_add(&t, &q); /* t = 2*X3 + Q (5) */
secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*X3 + Q) (1) */
secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (3) */
secp256k1_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */
secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */
/** In case a->infinity == 1, replace r with (b->x, b->y, 1). */
secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
secp256k1_fe_cmov(&r->y, &b->y, a->infinity);
secp256k1_fe_cmov(&r->z, &fe_1, a->infinity);
secp256k1_fe_cmov(&r->z, &secp256k1_fe_one, a->infinity);
r->infinity = infinity;
}
@ -660,12 +651,8 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r,
}
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
static const secp256k1_fe beta = SECP256K1_FE_CONST(
0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
);
*r = *a;
secp256k1_fe_mul(&r->x, &r->x, &beta);
secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta);
}
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {

View File

@ -12,8 +12,8 @@
typedef struct {
uint32_t s[8];
uint32_t buf[16]; /* In big endian */
size_t bytes;
unsigned char buf[64];
uint64_t bytes;
} secp256k1_sha256;
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);

View File

@ -28,12 +28,6 @@
(h) = t1 + t2; \
} while(0)
#if defined(SECP256K1_BIG_ENDIAN)
#define BE32(x) (x)
#elif defined(SECP256K1_LITTLE_ENDIAN)
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#endif
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
hash->s[0] = 0x6a09e667ul;
hash->s[1] = 0xbb67ae85ul;
@ -47,26 +41,26 @@ static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
}
/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */
static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) {
static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) {
uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0]));
Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1]));
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2]));
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3]));
Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4]));
Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5]));
Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6]));
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7]));
Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8]));
Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9]));
Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10]));
Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11]));
Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12]));
Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13]));
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14]));
Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15]));
Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = secp256k1_read_be32(&buf[0]));
Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = secp256k1_read_be32(&buf[4]));
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = secp256k1_read_be32(&buf[8]));
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = secp256k1_read_be32(&buf[12]));
Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = secp256k1_read_be32(&buf[16]));
Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = secp256k1_read_be32(&buf[20]));
Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = secp256k1_read_be32(&buf[24]));
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = secp256k1_read_be32(&buf[28]));
Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = secp256k1_read_be32(&buf[32]));
Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = secp256k1_read_be32(&buf[36]));
Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = secp256k1_read_be32(&buf[40]));
Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = secp256k1_read_be32(&buf[44]));
Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = secp256k1_read_be32(&buf[48]));
Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = secp256k1_read_be32(&buf[52]));
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = secp256k1_read_be32(&buf[56]));
Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = secp256k1_read_be32(&buf[60]));
Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
@ -136,7 +130,7 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
while (len >= 64 - bufsize) {
/* Fill the buffer, and process it. */
size_t chunk_len = 64 - bufsize;
memcpy(((unsigned char*)hash->buf) + bufsize, data, chunk_len);
memcpy(hash->buf + bufsize, data, chunk_len);
data += chunk_len;
len -= chunk_len;
secp256k1_sha256_transform(hash->s, hash->buf);
@ -149,19 +143,19 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
}
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) {
static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32_t sizedesc[2];
uint32_t out[8];
int i = 0;
sizedesc[0] = BE32(hash->bytes >> 29);
sizedesc[1] = BE32(hash->bytes << 3);
static const unsigned char pad[64] = {0x80};
unsigned char sizedesc[8];
int i;
/* The maximum message size of SHA256 is 2^64-1 bits. */
VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61));
secp256k1_write_be32(&sizedesc[0], hash->bytes >> 29);
secp256k1_write_be32(&sizedesc[4], hash->bytes << 3);
secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8);
secp256k1_sha256_write(hash, sizedesc, 8);
for (i = 0; i < 8; i++) {
out[i] = BE32(hash->s[i]);
secp256k1_write_be32(&out32[4*i], hash->s[i]);
hash->s[i] = 0;
}
memcpy(out32, (const unsigned char*)out, 32);
}
/* Initializes a sha256 struct and writes the 64 byte string
@ -285,7 +279,6 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
rng->retry = 0;
}
#undef BE32
#undef Round
#undef sigma1
#undef sigma0

View File

@ -60,7 +60,7 @@ void test_ecdh_generator_basepoint(void) {
s_one[31] = 1;
/* Check against pubkey creation when the basepoint is the generator */
for (i = 0; i < 100; ++i) {
for (i = 0; i < 2 * count; ++i) {
secp256k1_sha256 sha;
unsigned char s_b32[32];
unsigned char output_ecdh[65];
@ -123,10 +123,43 @@ void test_bad_scalar(void) {
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
}
/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */
void test_result_basepoint(void) {
secp256k1_pubkey point;
secp256k1_scalar rand;
unsigned char s[32];
unsigned char s_inv[32];
unsigned char out[32];
unsigned char out_inv[32];
unsigned char out_base[32];
int i;
unsigned char s_one[32] = { 0 };
s_one[31] = 1;
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_one) == 1);
CHECK(secp256k1_ecdh(ctx, out_base, &point, s_one, NULL, NULL) == 1);
for (i = 0; i < 2 * count; i++) {
random_scalar_order(&rand);
secp256k1_scalar_get_b32(s, &rand);
secp256k1_scalar_inverse(&rand, &rand);
secp256k1_scalar_get_b32(s_inv, &rand);
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s) == 1);
CHECK(secp256k1_ecdh(ctx, out, &point, s_inv, NULL, NULL) == 1);
CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0);
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_inv) == 1);
CHECK(secp256k1_ecdh(ctx, out_inv, &point, s, NULL, NULL) == 1);
CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0);
}
}
void run_ecdh_tests(void) {
test_ecdh_api();
test_ecdh_generator_basepoint();
test_bad_scalar();
test_result_basepoint();
}
#endif /* SECP256K1_MODULE_ECDH_TESTS_H */

View File

@ -192,11 +192,15 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi
return ret;
}
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
int secp256k1_schnorrsig_sign32(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
/* We cast away const from the passed aux_rand32 argument since we know the default nonce function does not modify it. */
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg32, 32, keypair, secp256k1_nonce_function_bip340, (unsigned char*)aux_rand32);
}
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
return secp256k1_schnorrsig_sign32(ctx, sig64, msg32, keypair, aux_rand32);
}
int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_schnorrsig_extraparams *extraparams) {
secp256k1_nonce_function_hardened noncefp = NULL;
void *ndata = NULL;

View File

@ -160,21 +160,21 @@ void test_schnorrsig_api(void) {
/** main test body **/
ecount = 0;
CHECK(secp256k1_schnorrsig_sign(none, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_sign32(none, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_sign(vrfy, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_sign32(vrfy, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_sign(sign, NULL, msg, &keypairs[0], NULL) == 0);
CHECK(secp256k1_schnorrsig_sign32(sign, NULL, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_sign(sign, sig, NULL, &keypairs[0], NULL) == 0);
CHECK(secp256k1_schnorrsig_sign32(sign, sig, NULL, &keypairs[0], NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, NULL, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, NULL, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &invalid_keypair, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &invalid_keypair, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_sign(sttc, sig, msg, &keypairs[0], NULL) == 0);
CHECK(secp256k1_schnorrsig_sign32(sttc, sig, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 5);
ecount = 0;
@ -202,7 +202,7 @@ void test_schnorrsig_api(void) {
CHECK(ecount == 6);
ecount = 0;
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(none, sig, msg, sizeof(msg), &pk[0]) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_verify(sign, sig, msg, sizeof(msg), &pk[0]) == 1);
@ -247,7 +247,7 @@ void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const un
secp256k1_xonly_pubkey pk, pk_expected;
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg32, &keypair, aux_rand));
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg32, &keypair, aux_rand));
CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk_expected, pk_serialized));
@ -740,8 +740,11 @@ void test_schnorrsig_sign(void) {
secp256k1_testrand256(aux_rand);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL) == 1);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk));
/* Check that deprecated alias gives the same result */
CHECK(secp256k1_schnorrsig_sign(ctx, sig2, msg, &keypair, NULL) == 1);
CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
/* Test different nonce functions */
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
@ -764,7 +767,7 @@ void test_schnorrsig_sign(void) {
extraparams.noncefp = NULL;
extraparams.ndata = aux_rand;
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
CHECK(secp256k1_schnorrsig_sign(ctx, sig2, msg, &keypair, extraparams.ndata) == 1);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig2, msg, &keypair, extraparams.ndata) == 1);
CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
}
@ -787,7 +790,7 @@ void test_schnorrsig_sign_verify(void) {
for (i = 0; i < N_SIGS; i++) {
secp256k1_testrand256(msg[i]);
CHECK(secp256k1_schnorrsig_sign(ctx, sig[i], msg[i], &keypair, NULL));
CHECK(secp256k1_schnorrsig_sign32(ctx, sig[i], msg[i], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], sizeof(msg[i]), &pk));
}
@ -816,13 +819,13 @@ void test_schnorrsig_sign_verify(void) {
}
/* Test overflowing s */
CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL));
CHECK(secp256k1_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
memset(&sig[0][32], 0xFF, 32);
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
/* Test negative s */
CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL));
CHECK(secp256k1_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
secp256k1_scalar_set_b32(&s, &sig[0][32], NULL);
secp256k1_scalar_negate(&s, &s);
@ -873,7 +876,7 @@ void test_schnorrsig_taproot(void) {
/* Key spend */
secp256k1_testrand256(msg);
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL) == 1);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1);
/* Verify key spend */
CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &output_pk) == 1);

View File

@ -446,8 +446,12 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
unsigned int offset = 0;
secp256k1_rfc6979_hmac_sha256 rng;
unsigned int i;
secp256k1_scalar msg;
unsigned char msgmod32[32];
secp256k1_scalar_set_b32(&msg, msg32, NULL);
secp256k1_scalar_get_b32(msgmod32, &msg);
/* We feed a byte array to the PRNG as input, consisting of:
* - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d.
* - the private key (32 bytes) and reduced message (32 bytes), see RFC 6979 3.2d.
* - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data.
* - optionally 16 extra bytes with the algorithm name.
* Because the arguments have distinct fixed lengths it is not possible for
@ -455,7 +459,7 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
* nonces.
*/
buffer_append(keydata, &offset, key32, 32);
buffer_append(keydata, &offset, msg32, 32);
buffer_append(keydata, &offset, msgmod32, 32);
if (data != NULL) {
buffer_append(keydata, &offset, data, 32);
}

View File

@ -28,6 +28,8 @@
#include "modinv64_impl.h"
#endif
#define CONDITIONAL_TEST(cnt, nam) if (count < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else
static int count = 64;
static secp256k1_context *ctx = NULL;
@ -495,14 +497,18 @@ void run_ctz_tests(void) {
/***** HASH TESTS *****/
void run_sha256_tests(void) {
static const char *inputs[8] = {
void run_sha256_known_output_tests(void) {
static const char *inputs[] = {
"", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"For this sample, this 63-byte string will be used as input data",
"This is exactly 64 bytes long, not counting the terminating byte"
"This is exactly 64 bytes long, not counting the terminating byte",
"aaaaa",
};
static const unsigned char outputs[8][32] = {
static const unsigned int repeat[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1000000/5
};
static const unsigned char outputs[][32] = {
{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55},
{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad},
{0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50},
@ -510,27 +516,146 @@ void run_sha256_tests(void) {
{0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30},
{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1},
{0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42},
{0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8}
{0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8},
{0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0},
};
int i;
for (i = 0; i < 8; i++) {
unsigned int i, ninputs;
/* Skip last input vector for low iteration counts */
ninputs = sizeof(inputs)/sizeof(inputs[0]) - 1;
CONDITIONAL_TEST(16, "run_sha256_known_output_tests 1000000") ninputs++;
for (i = 0; i < ninputs; i++) {
unsigned char out[32];
secp256k1_sha256 hasher;
unsigned int j;
/* 1. Run: simply write the input bytestrings */
j = repeat[i];
secp256k1_sha256_initialize(&hasher);
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
while (j > 0) {
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
j--;
}
secp256k1_sha256_finalize(&hasher, out);
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
/* 2. Run: split the input bytestrings randomly before writing */
if (strlen(inputs[i]) > 0) {
int split = secp256k1_testrand_int(strlen(inputs[i]));
secp256k1_sha256_initialize(&hasher);
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
j = repeat[i];
while (j > 0) {
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
j--;
}
secp256k1_sha256_finalize(&hasher, out);
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
}
}
}
/** SHA256 counter tests
The tests verify that the SHA256 counter doesn't wrap around at message length
2^i bytes for i = 20, ..., 33. This wide range aims at being independent of the
implementation of the counter and it catches multiple natural 32-bit overflows
(e.g., counting bits, counting bytes, counting blocks, ...).
The test vectors have been generated using following Python script which relies
on https://github.com/cloudtools/sha256/ (v0.3 on Python v3.10.2).
```
from sha256 import sha256
from copy import copy
def midstate_c_definition(hasher):
ret = ' {{0x' + hasher.state[0].hex('_', 4).replace('_', ', 0x') + '},\n'
ret += ' {0x00}, ' + str(hex(hasher.state[1])) + '}'
return ret
def output_c_literal(hasher):
return '{0x' + hasher.digest().hex('_').replace('_', ', 0x') + '}'
MESSAGE = b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno'
assert(len(MESSAGE) == 64)
BYTE_BOUNDARIES = [(2**b)//len(MESSAGE) - 1 for b in range(20, 34)]
midstates = []
digests = []
hasher = sha256()
for i in range(BYTE_BOUNDARIES[-1] + 1):
if i in BYTE_BOUNDARIES:
midstates.append(midstate_c_definition(hasher))
hasher_copy = copy(hasher)
hasher_copy.update(MESSAGE)
digests.append(output_c_literal(hasher_copy))
hasher.update(MESSAGE)
for x in midstates:
print(x + ',')
for x in digests:
print(x + ',')
```
*/
void run_sha256_counter_tests(void) {
static const char *input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno";
static const secp256k1_sha256 midstates[] = {
{{0xa2b5c8bb, 0x26c88bb3, 0x2abdc3d2, 0x9def99a3, 0xdfd21a6e, 0x41fe585b, 0x7ef2c440, 0x2b79adda},
{0x00}, 0xfffc0},
{{0xa0d29445, 0x9287de66, 0x76aabd71, 0x41acd765, 0x0c7528b4, 0x84e14906, 0x942faec6, 0xcc5a7b26},
{0x00}, 0x1fffc0},
{{0x50449526, 0xb9f1d657, 0xa0fc13e9, 0x50860f10, 0xa550c431, 0x3fbc97c1, 0x7bbb2d89, 0xdb67bac1},
{0x00}, 0x3fffc0},
{{0x54a6efdc, 0x46762e7b, 0x88bfe73f, 0xbbd149c7, 0x41620c43, 0x1168da7b, 0x2c5960f9, 0xeccffda6},
{0x00}, 0x7fffc0},
{{0x2515a8f5, 0x5faa2977, 0x3a850486, 0xac858cad, 0x7b7276ee, 0x235c0385, 0xc53a157c, 0x7cb3e69c},
{0x00}, 0xffffc0},
{{0x34f39828, 0x409fedb7, 0x4bbdd0fb, 0x3b643634, 0x7806bf2e, 0xe0d1b713, 0xca3f2e1e, 0xe38722c2},
{0x00}, 0x1ffffc0},
{{0x389ef5c5, 0x38c54167, 0x8f5d56ab, 0x582a75cc, 0x8217caef, 0xf10947dd, 0x6a1998a8, 0x048f0b8c},
{0x00}, 0x3ffffc0},
{{0xd6c3f394, 0x0bee43b9, 0x6783f497, 0x29fa9e21, 0x6ce491c1, 0xa81fe45e, 0x2fc3859a, 0x269012d0},
{0x00}, 0x7ffffc0},
{{0x6dd3c526, 0x44d88aa0, 0x806a1bae, 0xfbcc0d32, 0x9d6144f3, 0x9d2bd757, 0x9851a957, 0xb50430ad},
{0x00}, 0xfffffc0},
{{0x2add4021, 0xdfe8a9e6, 0xa56317c6, 0x7a15f5bb, 0x4a48aacd, 0x5d368414, 0x4f00e6f0, 0xd9355023},
{0x00}, 0x1fffffc0},
{{0xb66666b4, 0xdbeac32b, 0x0ea351ae, 0xcba9da46, 0x6278b874, 0x8c508e23, 0xe16ca776, 0x8465bac1},
{0x00}, 0x3fffffc0},
{{0xb6744789, 0x9cce87aa, 0xc4c478b7, 0xf38404d8, 0x2e38ba62, 0xa3f7019b, 0x50458fe7, 0x3047dbec},
{0x00}, 0x7fffffc0},
{{0x8b1297ba, 0xba261a80, 0x2ba1b0dd, 0xfbc67d6d, 0x61072c4e, 0x4b5a2a0f, 0x52872760, 0x2dfeb162},
{0x00}, 0xffffffc0},
{{0x24f33cf7, 0x41ad6583, 0x41c8ff5d, 0xca7ef35f, 0x50395756, 0x021b743e, 0xd7126cd7, 0xd037473a},
{0x00}, 0x1ffffffc0},
};
static const unsigned char outputs[][32] = {
{0x0e, 0x83, 0xe2, 0xc9, 0x4f, 0xb2, 0xb8, 0x2b, 0x89, 0x06, 0x92, 0x78, 0x04, 0x03, 0x48, 0x5c, 0x48, 0x44, 0x67, 0x61, 0x77, 0xa4, 0xc7, 0x90, 0x9e, 0x92, 0x55, 0x10, 0x05, 0xfe, 0x39, 0x15},
{0x1d, 0x1e, 0xd7, 0xb8, 0xa3, 0xa7, 0x8a, 0x79, 0xfd, 0xa0, 0x05, 0x08, 0x9c, 0xeb, 0xf0, 0xec, 0x67, 0x07, 0x9f, 0x8e, 0x3c, 0x0d, 0x8e, 0xf9, 0x75, 0x55, 0x13, 0xc1, 0xe8, 0x77, 0xf8, 0xbb},
{0x66, 0x95, 0x6c, 0xc9, 0xe0, 0x39, 0x65, 0xb6, 0xb0, 0x05, 0xd1, 0xaf, 0xaf, 0xf3, 0x1d, 0xb9, 0xa4, 0xda, 0x6f, 0x20, 0xcd, 0x3a, 0xae, 0x64, 0xc2, 0xdb, 0xee, 0xf5, 0xb8, 0x8d, 0x57, 0x0e},
{0x3c, 0xbb, 0x1c, 0x12, 0x5e, 0x17, 0xfd, 0x54, 0x90, 0x45, 0xa7, 0x7b, 0x61, 0x6c, 0x1d, 0xfe, 0xe6, 0xcc, 0x7f, 0xee, 0xcf, 0xef, 0x33, 0x35, 0x50, 0x62, 0x16, 0x70, 0x2f, 0x87, 0xc3, 0xc9},
{0x53, 0x4d, 0xa8, 0xe7, 0x1e, 0x98, 0x73, 0x8d, 0xd9, 0xa3, 0x54, 0xa5, 0x0e, 0x59, 0x2c, 0x25, 0x43, 0x6f, 0xaa, 0xa2, 0xf5, 0x21, 0x06, 0x3e, 0xc9, 0x82, 0x06, 0x94, 0x98, 0x72, 0x9d, 0xa7},
{0xef, 0x7e, 0xe9, 0x6b, 0xd3, 0xe5, 0xb7, 0x41, 0x4c, 0xc8, 0xd3, 0x07, 0x52, 0x9a, 0x5a, 0x8b, 0x4e, 0x1e, 0x75, 0xa4, 0x17, 0x78, 0xc8, 0x36, 0xcd, 0xf8, 0x2e, 0xd9, 0x57, 0xe3, 0xd7, 0x07},
{0x87, 0x16, 0xfb, 0xf9, 0xa5, 0xf8, 0xc4, 0x56, 0x2b, 0x48, 0x52, 0x8e, 0x2d, 0x30, 0x85, 0xb6, 0x4c, 0x56, 0xb5, 0xd1, 0x16, 0x9c, 0xcf, 0x32, 0x95, 0xad, 0x03, 0xe8, 0x05, 0x58, 0x06, 0x76},
{0x75, 0x03, 0x80, 0x28, 0xf2, 0xa7, 0x63, 0x22, 0x1a, 0x26, 0x9c, 0x68, 0xe0, 0x58, 0xfc, 0x73, 0xeb, 0x42, 0xf6, 0x86, 0x16, 0x24, 0x4b, 0xbc, 0x24, 0xf7, 0x02, 0xc8, 0x3d, 0x90, 0xe2, 0xb0},
{0xdf, 0x49, 0x0f, 0x15, 0x7b, 0x7d, 0xbf, 0xe0, 0xd4, 0xcf, 0x47, 0xc0, 0x80, 0x93, 0x4a, 0x61, 0xaa, 0x03, 0x07, 0x66, 0xb3, 0x38, 0x5d, 0xc8, 0xc9, 0x07, 0x61, 0xfb, 0x97, 0x10, 0x2f, 0xd8},
{0x77, 0x19, 0x40, 0x56, 0x41, 0xad, 0xbc, 0x59, 0xda, 0x1e, 0xc5, 0x37, 0x14, 0x63, 0x7b, 0xfb, 0x79, 0xe2, 0x7a, 0xb1, 0x55, 0x42, 0x99, 0x42, 0x56, 0xfe, 0x26, 0x9d, 0x0f, 0x7e, 0x80, 0xc6},
{0x50, 0xe7, 0x2a, 0x0e, 0x26, 0x44, 0x2f, 0xe2, 0x55, 0x2d, 0xc3, 0x93, 0x8a, 0xc5, 0x86, 0x58, 0x22, 0x8c, 0x0c, 0xbf, 0xb1, 0xd2, 0xca, 0x87, 0x2a, 0xe4, 0x35, 0x26, 0x6f, 0xcd, 0x05, 0x5e},
{0xe4, 0x80, 0x6f, 0xdb, 0x3d, 0x7d, 0xba, 0xde, 0x50, 0x3f, 0xea, 0x00, 0x3d, 0x46, 0x59, 0x64, 0xfd, 0x58, 0x1c, 0xa1, 0xb8, 0x7d, 0x5f, 0xac, 0x94, 0x37, 0x9e, 0xa0, 0xc0, 0x9c, 0x93, 0x8b},
{0x2c, 0xf3, 0xa9, 0xf6, 0x15, 0x25, 0x80, 0x70, 0x76, 0x99, 0x7d, 0xf1, 0xc3, 0x2f, 0xa3, 0x31, 0xff, 0x92, 0x35, 0x2e, 0x8d, 0x04, 0x13, 0x33, 0xd8, 0x0d, 0xdb, 0x4a, 0xf6, 0x8c, 0x03, 0x34},
{0xec, 0x12, 0x24, 0x9f, 0x35, 0xa4, 0x29, 0x8b, 0x9e, 0x4a, 0x95, 0xf8, 0x61, 0xaf, 0x61, 0xc5, 0x66, 0x55, 0x3e, 0x3f, 0x2a, 0x98, 0xea, 0x71, 0x16, 0x6b, 0x1c, 0xd9, 0xe4, 0x09, 0xd2, 0x8e},
};
unsigned int i;
for (i = 0; i < sizeof(midstates)/sizeof(midstates[0]); i++) {
unsigned char out[32];
secp256k1_sha256 hasher = midstates[i];
secp256k1_sha256_write(&hasher, (const unsigned char*)input, strlen(input));
secp256k1_sha256_finalize(&hasher, out);
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
}
}
void run_hmac_sha256_tests(void) {
static const char *keys[6] = {
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
@ -2625,6 +2750,55 @@ int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) {
return ret;
}
void run_field_half(void) {
secp256k1_fe t, u;
int m;
/* Check magnitude 0 input */
secp256k1_fe_get_bounds(&t, 0);
secp256k1_fe_half(&t);
#ifdef VERIFY
CHECK(t.magnitude == 1);
CHECK(t.normalized == 0);
#endif
CHECK(secp256k1_fe_normalizes_to_zero(&t));
/* Check non-zero magnitudes in the supported range */
for (m = 1; m < 32; m++) {
/* Check max-value input */
secp256k1_fe_get_bounds(&t, m);
u = t;
secp256k1_fe_half(&u);
#ifdef VERIFY
CHECK(u.magnitude == (m >> 1) + 1);
CHECK(u.normalized == 0);
#endif
secp256k1_fe_normalize_weak(&u);
secp256k1_fe_add(&u, &u);
CHECK(check_fe_equal(&t, &u));
/* Check worst-case input: ensure the LSB is 1 so that P will be added,
* which will also cause all carries to be 1, since all limbs that can
* generate a carry are initially even and all limbs of P are odd in
* every existing field implementation. */
secp256k1_fe_get_bounds(&t, m);
CHECK(t.n[0] > 0);
CHECK((t.n[0] & 1) == 0);
--t.n[0];
u = t;
secp256k1_fe_half(&u);
#ifdef VERIFY
CHECK(u.magnitude == (m >> 1) + 1);
CHECK(u.normalized == 0);
#endif
secp256k1_fe_normalize_weak(&u);
secp256k1_fe_add(&u, &u);
CHECK(check_fe_equal(&t, &u));
}
}
void run_field_misc(void) {
secp256k1_fe x;
secp256k1_fe y;
@ -2632,9 +2806,13 @@ void run_field_misc(void) {
secp256k1_fe q;
secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5);
int i, j;
for (i = 0; i < 5*count; i++) {
for (i = 0; i < 1000 * count; i++) {
secp256k1_fe_storage xs, ys, zs;
random_fe(&x);
if (i & 1) {
random_fe(&x);
} else {
random_fe_test(&x);
}
random_fe_non_zero(&y);
/* Test the fe equality and comparison operations. */
CHECK(secp256k1_fe_cmp_var(&x, &x) == 0);
@ -2702,6 +2880,14 @@ void run_field_misc(void) {
secp256k1_fe_add(&q, &x);
CHECK(check_fe_equal(&y, &z));
CHECK(check_fe_equal(&q, &y));
/* Check secp256k1_fe_half. */
z = x;
secp256k1_fe_half(&z);
secp256k1_fe_add(&z, &z);
CHECK(check_fe_equal(&x, &z));
secp256k1_fe_add(&z, &z);
secp256k1_fe_half(&z);
CHECK(check_fe_equal(&x, &z));
}
}
@ -5014,8 +5200,8 @@ void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, se
}
}
void test_ecmult_constants(void) {
/* Test ecmult_gen for:
void test_ecmult_constants_2bit(void) {
/* Using test_ecmult_accumulate, test ecmult for:
* - For i in 0..36:
* - Key i
* - Key -i
@ -5058,8 +5244,81 @@ void test_ecmult_constants(void) {
secp256k1_scratch_space_destroy(ctx, scratch);
}
void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) {
/* Using test_ecmult_accumulate, test ecmult for:
* - Key 0
* - Key 1
* - Key -1
* - For i in range(iter):
* - Key SHA256(LE32(prefix) || LE16(i))
*/
secp256k1_scalar x;
secp256k1_sha256 acc;
unsigned char b32[32];
unsigned char inp[6];
size_t i;
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 65536);
inp[0] = prefix & 0xFF;
inp[1] = (prefix >> 8) & 0xFF;
inp[2] = (prefix >> 16) & 0xFF;
inp[3] = (prefix >> 24) & 0xFF;
secp256k1_sha256_initialize(&acc);
secp256k1_scalar_set_int(&x, 0);
test_ecmult_accumulate(&acc, &x, scratch);
secp256k1_scalar_set_int(&x, 1);
test_ecmult_accumulate(&acc, &x, scratch);
secp256k1_scalar_negate(&x, &x);
test_ecmult_accumulate(&acc, &x, scratch);
for (i = 0; i < iter; ++i) {
secp256k1_sha256 gen;
inp[4] = i & 0xff;
inp[5] = (i >> 8) & 0xff;
secp256k1_sha256_initialize(&gen);
secp256k1_sha256_write(&gen, inp, sizeof(inp));
secp256k1_sha256_finalize(&gen, b32);
secp256k1_scalar_set_b32(&x, b32, NULL);
test_ecmult_accumulate(&acc, &x, scratch);
}
secp256k1_sha256_finalize(&acc, b32);
CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0);
secp256k1_scratch_space_destroy(ctx, scratch);
}
void run_ecmult_constants(void) {
test_ecmult_constants();
/* Expected hashes of all points in the tests below. Computed using an
* independent implementation. */
static const unsigned char expected32_6bit20[32] = {
0x68, 0xb6, 0xed, 0x6f, 0x28, 0xca, 0xc9, 0x7f,
0x8e, 0x8b, 0xd6, 0xc0, 0x61, 0x79, 0x34, 0x6e,
0x5a, 0x8f, 0x2b, 0xbc, 0x3e, 0x1f, 0xc5, 0x2e,
0x2a, 0xd0, 0x45, 0x67, 0x7f, 0x95, 0x95, 0x8e
};
static const unsigned char expected32_8bit8[32] = {
0x8b, 0x65, 0x8e, 0xea, 0x86, 0xae, 0x3c, 0x95,
0x90, 0xb6, 0x77, 0xa4, 0x8c, 0x76, 0xd9, 0xec,
0xf5, 0xab, 0x8a, 0x2f, 0xfd, 0xdb, 0x19, 0x12,
0x1a, 0xee, 0xe6, 0xb7, 0x6e, 0x05, 0x3f, 0xc6
};
/* For every combination of 6 bit positions out of 256, restricted to
* 20-bit windows (i.e., the first and last bit position are no more than
* 19 bits apart), all 64 bit patterns occur in the input scalars used in
* this test. */
CONDITIONAL_TEST(1, "test_ecmult_constants_sha 1024") {
test_ecmult_constants_sha(4808378u, 1024, expected32_6bit20);
}
/* For every combination of 8 consecutive bit positions, all 256 bit
* patterns occur in the input scalars used in this test. */
CONDITIONAL_TEST(3, "test_ecmult_constants_sha 2048") {
test_ecmult_constants_sha(1607366309u, 2048, expected32_8bit8);
}
CONDITIONAL_TEST(35, "test_ecmult_constants_2bit") {
test_ecmult_constants_2bit();
}
}
void test_ecmult_gen_blind(void) {
@ -6918,6 +7177,19 @@ void run_secp256k1_memczero_test(void) {
CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0);
}
void run_secp256k1_byteorder_tests(void) {
const uint32_t x = 0xFF03AB45;
const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45};
unsigned char buf[4];
uint32_t x_;
secp256k1_write_be32(buf, x);
CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0);
x_ = secp256k1_read_be32(buf);
CHECK(x == x_);
}
void int_cmov_test(void) {
int r = INT_MAX;
int a = 0;
@ -7119,7 +7391,8 @@ int main(int argc, char **argv) {
run_modinv_tests();
run_inverse_tests();
run_sha256_tests();
run_sha256_known_output_tests();
run_sha256_counter_tests();
run_hmac_sha256_tests();
run_rfc6979_hmac_sha256_tests();
run_tagged_sha256_tests();
@ -7128,6 +7401,7 @@ int main(int argc, char **argv) {
run_scalar_tests();
/* field tests */
run_field_half();
run_field_misc();
run_field_convert();
run_fe_mul();
@ -7222,6 +7496,7 @@ int main(int argc, char **argv) {
/* util tests */
run_secp256k1_memczero_test();
run_secp256k1_byteorder_tests();
run_cmov_tests();

View File

@ -364,4 +364,20 @@ static SECP256K1_INLINE int secp256k1_ctz64_var(uint64_t x) {
#endif
}
/* Read a uint32_t in big endian */
SECP256K1_INLINE static uint32_t secp256k1_read_be32(const unsigned char* p) {
return (uint32_t)p[0] << 24 |
(uint32_t)p[1] << 16 |
(uint32_t)p[2] << 8 |
(uint32_t)p[3];
}
/* Write a uint32_t in big endian */
SECP256K1_INLINE static void secp256k1_write_be32(unsigned char* p, uint32_t x) {
p[3] = x;
p[2] = x >> 8;
p[1] = x >> 16;
p[0] = x >> 24;
}
#endif /* SECP256K1_UTIL_H */

View File

@ -179,7 +179,7 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
ret = secp256k1_keypair_create(ctx, &keypair, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
CHECK(ret == 1);
ret = secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL);
ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
CHECK(ret == 1);
#endif