27 Commits

Author SHA1 Message Date
Gregory Sanders
1e2fda1480 Fix generator makefile
Include test_impl.h
2017-08-15 22:39:26 -04:00
Andrew Poelstra
4564081e26 Merge pull request #11 from jonasnick/blind_sum_doc_fix
Fix pedersen_blind_generator_blind_sum return value documentation
2017-07-18 14:04:25 +00:00
Jonas Nick
619b8f16dc Fix pedersen_blind_generator_blind_sum return value documentation 2017-07-11 16:35:39 +02:00
Andrew Poelstra
8584c066c7 Merge pull request #10 from jonasnick/whitelist-verify-nkeys
Add n_keys argument to whitelist_verify
2017-07-10 17:08:23 +00:00
Jonas Nick
d5b3440c3b Add n_keys argument to whitelist_verify 2017-07-10 18:51:16 +02:00
Andrew Poelstra
12bd9fd8e5 Merge pull request #8 from jonasnick/whitelist_api_fix
Fix checks of whitelist serialize/parse arguments
2017-06-27 13:59:43 +00:00
Jonas Nick
a809ac484f Fix checks of whitelist serialize/parse arguments 2017-06-27 15:02:40 +02:00
Andrew Poelstra
cb8a394102 Merge pull request #7 from apoelstra/whitelist-api-fix
whitelist: fix serialize/parse API to take serialized length
2017-06-26 17:57:03 +00:00
Andrew Poelstra
0f21e05dfa whitelist: fix serialize/parse API to take serialized length 2017-06-26 17:08:47 +00:00
Andrew Poelstra
4f7a50e173 Merge pull request #6 from jonasnick/doc-fixes
Fix include/secp256k1_rangeproof.h function argument documentation.
2017-05-09 10:26:47 +00:00
Jonas Nick
5b72133255 Fix include/secp256k1_rangeproof.h function argument documentation. 2017-05-09 02:00:14 +02:00
Andrew Poelstra
7dd7883de6 Merge pull request #5 from apoelstra/test-cleanup
Additional rangeproof and surjection proof tests
2017-05-08 09:45:04 +00:00
Andrew Poelstra
0cfa29f87a rangeproof: add API tests 2017-05-08 09:44:11 +00:00
Andrew Poelstra
d8295970d2 surjectionproof: rename unit test functions to be more consistent with other modules 2017-05-08 09:44:11 +00:00
Andrew Poelstra
5eae1b9793 surjectionproof: add API unit tests 2017-05-08 09:44:11 +00:00
Andrew Poelstra
8454a98521 surjectionproof: tests_impl.h s/assert/CHECK/g 2017-05-08 09:44:08 +00:00
Andrew Poelstra
d702d210b8 rangeproof: fix memory leak in unit tests 2017-05-02 16:55:48 +00:00
Andrew Poelstra
d78f12b04e add surjection proof module
Includes fix and tests by Jonas Nick.
2017-04-03 08:18:52 -07:00
Andrew Poelstra
da035050f8 Implement ring-signature based whitelist delegation scheme 2017-04-03 08:18:52 -07:00
Andrew Poelstra
6eebf82d8a rangeproof: add summing function for blinded generators; drop excess and gen from verify_tally 2017-04-03 08:18:52 -07:00
Pieter Wuille
4577c24234 Expose generator in pedersen/rangeproof API 2017-04-03 07:53:53 -07:00
Pieter Wuille
e7f7b3c941 Constant-time generator module 2017-04-03 07:53:52 -07:00
Andrew Poelstra
9722b11506 rangeproof: expose sidechannel message field in the signing API
Including a fix by Jonas Nick.
2017-04-03 07:46:53 -07:00
Andrew Poelstra
9f21e1b518 [RANGEPROOF BREAK] Use quadratic residue for tie break and modularity cleanup
Switch to secp256k1_pedersen_commitment by Andrew Poelstra.
Switch to quadratic residue based disambiguation by Pieter Wuille.
2017-04-03 07:46:53 -07:00
Pieter Wuille
dc05520096 Get rid of precomputed H tables 2017-04-03 07:46:52 -07:00
Gregory Maxwell
8de58308d8 Pedersen commitments, borromean ring signatures, and ZK range proofs.
This commit adds three new cryptosystems to libsecp256k1:

Pedersen commitments are a system for making blinded commitments
 to a value.  Functionally they work like:
  commit_b,v = H(blind_b || value_v),
 except they are additively homorphic, e.g.
  C(b1, v1) - C(b2, v2) = C(b1 - b2, v1 - v2) and
  C(b1, v1) - C(b1, v1) = 0, etc.
 The commitments themselves are EC points, serialized as 33 bytes.
 In addition to the commit function this implementation includes
 utility functions for verifying that a set of commitments sums
 to zero, and for picking blinding factors that sum to zero.
 If the blinding factors are uniformly random, pedersen commitments
 have information theoretic privacy.

Borromean ring signatures are a novel efficient ring signature
 construction for AND/OR admissions policies (the code here implements
 an AND of ORs, each of any size).  This construction requires
 32 bytes of signature per pubkey used plus 32 bytes of constant
 overhead. With these you can construct signatures like "Given pubkeys
 A B C D E F G, the signer knows the discrete logs
 satisifying (A || B) & (C || D || E) & (F || G)".

ZK range proofs allow someone to prove a pedersen commitment is in
 a particular range (e.g. [0..2^64)) without revealing the specific
 value.  The construction here is based on the above borromean
 ring signature and uses a radix-4 encoding and other optimizations
 to maximize efficiency.  It also supports encoding proofs with a
 non-private base-10 exponent and minimum-value to allow trading
 off secrecy for size and speed (or just avoiding wasting space
 keeping data private that was already public due to external
 constraints).

A proof for a 32-bit mantissa takes 2564 bytes, but 2048 bytes of
 this can be used to communicate a private message to a receiver
 who shares a secret random seed with the prover.
2017-04-03 07:03:48 -07:00
Greg Maxwell
f7b48c577d Add 64-bit integer utilities 2017-04-03 07:03:18 -07:00
132 changed files with 4109 additions and 14011 deletions

8
.gitignore vendored
View File

@@ -1,17 +1,13 @@
bench_inv
bench_ecdh
bench_ecmult
bench_generator
bench_rangeproof
bench_schnorrsig
bench_sign
bench_verify
bench_schnorr_verify
bench_recover
bench_internal
tests
exhaustive_tests
gen_context
valgrind_ctime_test
*.exe
*.so
*.a
@@ -33,8 +29,6 @@ libtool
*.lo
*.o
*~
*.log
*.trs
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
src/ecmult_static_context.h

View File

@@ -1,112 +1,69 @@
language: c
os:
- linux
- osx
dist: bionic
# Valgrind currently supports upto macOS 10.13, the latest xcode of that version is 10.1
osx_image: xcode10.1
sudo: false
addons:
apt:
packages:
- libgmp-dev
- valgrind
- libtool-bin
packages: libgmp-dev
compiler:
- clang
- gcc
cache:
directories:
- src/java/guava/
env:
global:
- WIDEMUL=auto BIGNUM=auto STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check WITH_VALGRIND=yes RUN_VALGRIND=no EXTRAFLAGS= HOST= ECDH=no RECOVERY=no ECDSA_S2C=no EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2 GENERATOR=no RANGEPROOF=no WHITELIST=no SCHNORRSIG=no MUSIG=no
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no
- GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
matrix:
- WIDEMUL=int64 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
- WIDEMUL=int128 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
- WIDEMUL=int64 RECOVERY=yes
- WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes
- WIDEMUL=int128
- WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes
- WIDEMUL=int128 ECDH=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes
- WIDEMUL=int128 ASM=x86_64
- SCALAR=32bit RECOVERY=yes
- SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
- SCALAR=64bit
- FIELD=64bit RECOVERY=yes
- FIELD=64bit ENDOMORPHISM=yes
- FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
- FIELD=64bit ASM=x86_64
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
- FIELD=32bit ENDOMORPHISM=yes
- BIGNUM=no
- BIGNUM=no RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
- BIGNUM=no RECOVERY=yes EXPERIMENTAL=yes ECDSA_S2C=yes SCHNORRSIG=yes MUSIG=yes
- BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes
- BIGNUM=no STATICPRECOMPUTATION=no
- BUILD=distcheck WITH_VALGRIND=no CTIMETEST=no BENCH=no
- CPPFLAGS=-DDETERMINISTIC
- CFLAGS=-O0 CTIMETEST=no
- CFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST=no
- ECMULTGENPRECISION=2
- ECMULTGENPRECISION=8
- RUN_VALGRIND=yes BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes EXTRAFLAGS="--disable-openssl-tests" BUILD=
- BUILD=distcheck
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
- EXTRAFLAGS=CFLAGS=-O0
- BUILD=check-java ECDH=yes EXPERIMENTAL=yes
matrix:
fast_finish: true
include:
- compiler: clang
os: linux
env: HOST=i686-linux-gnu
env: HOST=i686-linux-gnu ENDOMORPHISM=yes
addons:
apt:
packages:
- gcc-multilib
- libgmp-dev:i386
- valgrind
- libtool-bin
- libc6-dbg:i386
- compiler: clang
env: HOST=i686-linux-gnu
os: linux
addons:
apt:
packages:
- gcc-multilib
- valgrind
- libtool-bin
- libc6-dbg:i386
- compiler: gcc
env: HOST=i686-linux-gnu
os: linux
env: HOST=i686-linux-gnu ENDOMORPHISM=yes
addons:
apt:
packages:
- gcc-multilib
- valgrind
- libtool-bin
- libc6-dbg:i386
- compiler: gcc
os: linux
env: HOST=i686-linux-gnu
addons:
apt:
packages:
- gcc-multilib
- libgmp-dev:i386
- valgrind
- libtool-bin
- libc6-dbg:i386
# S390x build (big endian system)
- compiler: gcc
env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST=
arch: s390x
# We use this to install macOS dependencies instead of the built in `homebrew` plugin,
# because in xcode earlier than 11 they have a bug requiring updating the system which overall takes ~8 minutes.
# https://travis-ci.community/t/macos-build-fails-because-of-homebrew-bundle-unknown-command/7296
before_install:
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then HOMEBREW_NO_AUTO_UPDATE=1 brew install gmp valgrind gcc@9; fi
before_install: mkdir -p `dirname $GUAVA_JAR`
install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi
before_script: ./autogen.sh
# travis auto terminates jobs that go for 10 minutes without printing to stdout, but travis_wait doesn't work well with forking programs like valgrind (https://docs.travis-ci.com/user/common-build-problems/#build-times-out-because-no-output-was-received https://github.com/bitcoin-core/secp256k1/pull/750#issuecomment-623476860)
script:
- function keep_alive() { while true; do echo -en "\a"; sleep 60; done }
- keep_alive &
- ./contrib/travis.sh
- kill %keep_alive
after_script:
- cat ./tests.log
- cat ./exhaustive_tests.log
- cat ./valgrind_ctime_test.log
- cat ./bench.log
- $CC --version
- valgrind --version
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
os: linux

View File

@@ -1,8 +1,13 @@
ACLOCAL_AMFLAGS = -I build-aux/m4
lib_LTLIBRARIES = libsecp256k1.la
if USE_JNI
JNI_LIB = libsecp256k1_jni.la
noinst_LTLIBRARIES = $(JNI_LIB)
else
JNI_LIB =
endif
include_HEADERS = include/secp256k1.h
include_HEADERS += include/secp256k1_preallocated.h
noinst_HEADERS =
noinst_HEADERS += src/scalar.h
noinst_HEADERS += src/scalar_4x64.h
@@ -16,8 +21,6 @@ noinst_HEADERS += src/group.h
noinst_HEADERS += src/group_impl.h
noinst_HEADERS += src/num_gmp.h
noinst_HEADERS += src/num_gmp_impl.h
noinst_HEADERS += src/eccommit.h
noinst_HEADERS += src/eccommit_impl.h
noinst_HEADERS += src/ecdsa.h
noinst_HEADERS += src/ecdsa_impl.h
noinst_HEADERS += src/eckey.h
@@ -36,11 +39,9 @@ noinst_HEADERS += src/field_5x52.h
noinst_HEADERS += src/field_5x52_impl.h
noinst_HEADERS += src/field_5x52_int128_impl.h
noinst_HEADERS += src/field_5x52_asm_impl.h
noinst_HEADERS += src/assumptions.h
noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h
noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/scratch.h
noinst_HEADERS += src/scratch_impl.h
noinst_HEADERS += src/selftest.h
noinst_HEADERS += src/testrand.h
noinst_HEADERS += src/testrand_impl.h
noinst_HEADERS += src/hash.h
@@ -71,27 +72,21 @@ endif
libsecp256k1_la_SOURCES = src/secp256k1.c
libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB)
libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB)
if VALGRIND_ENABLED
libsecp256k1_la_CPPFLAGS += -DVALGRIND
endif
libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c
libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)
noinst_PROGRAMS =
if USE_BENCHMARK
noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_ecmult
noinst_PROGRAMS += bench_verify bench_sign bench_internal
bench_verify_SOURCES = src/bench_verify.c
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
# SECP_TEST_INCLUDES are only used here for CRYPTO_CPPFLAGS
bench_verify_CPPFLAGS = -DSECP256K1_BUILD $(SECP_TEST_INCLUDES)
bench_sign_SOURCES = src/bench_sign.c
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_internal_SOURCES = src/bench_internal.c
bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
bench_ecmult_SOURCES = src/bench_ecmult.c
bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB)
bench_ecmult_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
endif
TESTS =
@@ -99,12 +94,6 @@ if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
if VALGRIND_ENABLED
tests_CPPFLAGS += -DVALGRIND
noinst_PROGRAMS += valgrind_ctime_test
valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c
valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_LIBS) $(COMMON_LIB)
endif
if !ENABLE_COVERAGE
tests_CPPFLAGS += -DVERIFY
endif
@@ -120,43 +109,69 @@ exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDE
if !ENABLE_COVERAGE
exhaustive_tests_CPPFLAGS += -DVERIFY
endif
exhaustive_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB)
exhaustive_tests_LDADD = $(SECP_LIBS)
exhaustive_tests_LDFLAGS = -static
TESTS += exhaustive_tests
endif
JAVAROOT=src/java
JAVAORG=org/bitcoin
JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar
CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA)
JAVA_FILES= \
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \
$(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java
if USE_JNI
$(JAVA_GUAVA):
@echo Guava is missing. Fetch it via: \
wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@)
@false
.stamp-java: $(JAVA_FILES)
@echo Compiling $^
$(AM_V_at)$(CLASSPATH_ENV) javac $^
@touch $@
if USE_TESTS
check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java
$(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test
endif
endif
if USE_ECMULT_STATIC_PRECOMPUTATION
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) -I$(builddir)/src
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)
CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function
gen_context_OBJECTS = gen_context.o
gen_context_BIN = gen_context$(BUILD_EXEEXT)
gen_%.o: src/gen_%.c src/libsecp256k1-config.h
gen_%.o: src/gen_%.c
$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@
$(gen_context_BIN): $(gen_context_OBJECTS)
$(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) $^ -o $@
$(CC_FOR_BUILD) $^ -o $@
$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h
$(tests_OBJECTS): src/ecmult_static_context.h
$(bench_internal_OBJECTS): src/ecmult_static_context.h
$(bench_ecmult_OBJECTS): src/ecmult_static_context.h
src/ecmult_static_context.h: $(gen_context_BIN)
./$(gen_context_BIN)
CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h
CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java
endif
EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h
EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES)
if ENABLE_MODULE_ECDH
include src/modules/ecdh/Makefile.am.include
endif
if ENABLE_MODULE_MUSIG
include src/modules/musig/Makefile.am.include
endif
if ENABLE_MODULE_RECOVERY
include src/modules/recovery/Makefile.am.include
endif
@@ -176,16 +191,3 @@ endif
if ENABLE_MODULE_SURJECTIONPROOF
include src/modules/surjection/Makefile.am.include
endif
if ENABLE_MODULE_EXTRAKEYS
include src/modules/extrakeys/Makefile.am.include
endif
if ENABLE_MODULE_SCHNORRSIG
include src/modules/schnorrsig/Makefile.am.include
endif
if ENABLE_MODULE_ECDSA_S2C
include src/modules/ecdsa_s2c/Makefile.am.include
endif

View File

@@ -3,22 +3,17 @@ libsecp256k1
[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1)
Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.
Optimized C library for EC operations on curve secp256k1.
This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose.
This library is a work in progress and is being used to research best practices. Use at your own risk.
Features:
* secp256k1 ECDSA signing/verification and key generation.
* Additive and multiplicative tweaking of secret/public keys.
* Serialization/parsing of secret keys, public keys, signatures.
* Constant time, constant memory access signing and public key generation.
* Derandomized ECDSA (via RFC6979 or with a caller provided function.)
* Adding/multiplying private/public keys.
* Serialization/parsing of private keys, public keys, signatures.
* Constant time, constant memory access signing and pubkey generation.
* Derandomized DSA (via RFC6979 or with a caller provided function.)
* Very efficient implementation.
* Suitable for embedded systems.
* Optional module for public key recovery.
* Optional module for ECDH key exchange.
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.
Implementation details
----------------------
@@ -28,12 +23,11 @@ Implementation details
* Extensive testing infrastructure.
* Structured to facilitate review and analysis.
* Intended to be portable to any system with a C89 compiler and uint64_t support.
* No use of floating types.
* Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
* Field operations
* 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).
* Using 10 26-bit limbs.
* Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman).
* Scalar operations
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
@@ -48,14 +42,12 @@ Implementation details
* Use wNAF notation for point multiplicands.
* Use a much larger window for multiples of G, using precomputed multiples.
* Use Shamir's trick to do the multiplication with the public key and the generator simultaneously.
* Use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
* Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
* Point multiplication for signing
* Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.
* Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains)
* Access the table with branch-free conditional moves so memory access is uniform.
* No data-dependent branches
* Optional runtime blinding which attempts to frustrate differential power analysis.
* The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally.
* Access the table with branch-free conditional moves so memory access is uniform.
* No data-dependent branches
* The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally.
Build steps
-----------
@@ -65,40 +57,5 @@ libsecp256k1 is built using autotools:
$ ./autogen.sh
$ ./configure
$ make
$ make check
$ ./tests
$ sudo make install # optional
Exhaustive tests
-----------
$ ./exhaustive_tests
With valgrind, you might need to increase the max stack size:
$ valgrind --max-stackframe=2500000 ./exhaustive_tests
Test coverage
-----------
This library aims to have full coverage of the reachable lines and branches.
To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary):
$ ./configure --enable-coverage
Run the tests:
$ make check
To create a report, `gcovr` is recommended, as it includes branch coverage reporting:
$ gcovr --exclude 'src/bench*' --print-summary
To create a HTML report with coloured and annotated source code:
$ gcovr --exclude 'src/bench*' --html --html-details -o coverage.html
Reporting a vulnerability
------------
See [SECURITY.md](SECURITY.md)

View File

@@ -1,15 +0,0 @@
# Security Policy
## Reporting a Vulnerability
To report security issues send an email to secp256k1-security@bitcoincore.org (not for support).
The following keys may be used to communicate sensitive information to developers:
| Name | Fingerprint |
|------|-------------|
| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 |
| Andrew Poelstra | 699A 63EF C17A D3A9 A34C FFC0 7AD0 A91C 40BD 0091 |
| Tim Ruffing | 09E0 3F87 1092 E40E 106E 902B 33BC 86AB 80FF 5516 |
You can import a key by running the following command with that individuals fingerprint: `gpg --recv-keys "<fingerprint>"` Ensure that you put quotes around fingerprints containing spaces.

3
TODO Normal file
View File

@@ -0,0 +1,3 @@
* Unit tests for fieldelem/groupelem, including ones intended to
trigger fieldelem's boundary cases.
* Complete constant-time operations for signing/keygen

View File

@@ -0,0 +1,140 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_JNI_INCLUDE_DIR
#
# DESCRIPTION
#
# AX_JNI_INCLUDE_DIR finds include directories needed for compiling
# programs using the JNI interface.
#
# JNI include directories are usually in the Java distribution. This is
# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in
# that order. When this macro completes, a list of directories is left in
# the variable JNI_INCLUDE_DIRS.
#
# Example usage follows:
#
# AX_JNI_INCLUDE_DIR
#
# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
# do
# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR"
# done
#
# If you want to force a specific compiler:
#
# - at the configure.in level, set JAVAC=yourcompiler before calling
# AX_JNI_INCLUDE_DIR
#
# - at the configure level, setenv JAVAC
#
# Note: This macro can work with the autoconf M4 macros for Java programs.
# This particular macro is not part of the original set of macros.
#
# LICENSE
#
# Copyright (c) 2008 Don Anderson <dda@sleepycat.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 10
AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
AC_DEFUN([AX_JNI_INCLUDE_DIR],[
JNI_INCLUDE_DIRS=""
if test "x$JAVA_HOME" != x; then
_JTOPDIR="$JAVA_HOME"
else
if test "x$JAVAC" = x; then
JAVAC=javac
fi
AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
if test "x$_ACJNI_JAVAC" = xno; then
AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME])
fi
_ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
_JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
fi
case "$host_os" in
darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
_JINC="$_JTOPDIR/Headers";;
*) _JINC="$_JTOPDIR/include";;
esac
_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
_AS_ECHO_LOG([_JINC=$_JINC])
# On Mac OS X 10.6.4, jni.h is a symlink:
# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
# -> ../../CurrentJDK/Headers/jni.h.
AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,
[
if test -f "$_JINC/jni.h"; then
ac_cv_jni_header_path="$_JINC"
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
else
_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
if test -f "$_JTOPDIR/include/jni.h"; then
ac_cv_jni_header_path="$_JTOPDIR/include"
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
else
ac_cv_jni_header_path=none
fi
fi
])
# get the likely subdirectories for system specific java includes
case "$host_os" in
bsdi*) _JNI_INC_SUBDIRS="bsdos";;
darwin*) _JNI_INC_SUBDIRS="darwin";;
freebsd*) _JNI_INC_SUBDIRS="freebsd";;
linux*) _JNI_INC_SUBDIRS="linux genunix";;
osf*) _JNI_INC_SUBDIRS="alpha";;
solaris*) _JNI_INC_SUBDIRS="solaris";;
mingw*) _JNI_INC_SUBDIRS="win32";;
cygwin*) _JNI_INC_SUBDIRS="win32";;
*) _JNI_INC_SUBDIRS="genunix";;
esac
if test "x$ac_cv_jni_header_path" != "xnone"; then
# add any subdirectories that are present
for JINCSUBDIR in $_JNI_INC_SUBDIRS
do
if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
fi
done
fi
])
# _ACJNI_FOLLOW_SYMLINKS <path>
# Follows symbolic links on <path>,
# finally setting variable _ACJNI_FOLLOWED
# ----------------------------------------
AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
# find the include directory relative to the javac executable
_cur="$1"
while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
AC_MSG_CHECKING([symlink for $_cur])
_slink=`ls -ld "$_cur" | sed 's/.* -> //'`
case "$_slink" in
/*) _cur="$_slink";;
# 'X' avoids triggering unwanted echo options.
*) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
esac
AC_MSG_RESULT([$_cur])
done
_ACJNI_FOLLOWED="$_cur"
])# _ACJNI

View File

@@ -1,3 +1,8 @@
dnl libsecp25k1 helper checks
AC_DEFUN([SECP_INT128_CHECK],[
has_int128=$ac_cv_type___int128
])
dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
AC_DEFUN([SECP_64BIT_ASM_CHECK],[
AC_MSG_CHECKING(for x86_64 assembly availability)
@@ -33,45 +38,20 @@ AC_DEFUN([SECP_OPENSSL_CHECK],[
fi
if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
AC_MSG_CHECKING(for EC functions in libcrypto)
CPPFLAGS_TEMP="$CPPFLAGS"
CPPFLAGS="$CRYPTO_CPPFLAGS $CPPFLAGS"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>]],[[
# if OPENSSL_VERSION_NUMBER < 0x10100000L
void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) {(void)sig->r; (void)sig->s;}
# endif
unsigned int zero = 0;
const unsigned char *zero_ptr = (unsigned char*)&zero;
EC_KEY_free(EC_KEY_new_by_curve_name(NID_secp256k1));
EC_KEY *eckey = EC_KEY_new();
EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp256k1);
EC_KEY_set_group(eckey, group);
ECDSA_sign(0, NULL, 0, NULL, &zero, eckey);
EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);
ECDSA_verify(0, NULL, 0, NULL, 0, eckey);
o2i_ECPublicKey(&eckey, &zero_ptr, 0);
d2i_ECPrivateKey(&eckey, &zero_ptr, 0);
EC_KEY_check_key(eckey);
EC_KEY_free(eckey);
EC_GROUP_free(group);
ECDSA_SIG *sig_openssl;
sig_openssl = ECDSA_SIG_new();
d2i_ECDSA_SIG(&sig_openssl, &zero_ptr, 0);
i2d_ECDSA_SIG(sig_openssl, NULL);
ECDSA_SIG_get0(sig_openssl, NULL, NULL);
(void)sig_openssl->r;
ECDSA_SIG_free(sig_openssl);
const BIGNUM *bignum = BN_value_one();
BN_is_negative(bignum);
BN_num_bits(bignum);
if (sizeof(zero) >= BN_num_bytes(bignum)) {
BN_bn2bin(bignum, (unsigned char*)&zero);
}
]])],[has_openssl_ec=yes],[has_openssl_ec=no])
AC_MSG_RESULT([$has_openssl_ec])
CPPFLAGS="$CPPFLAGS_TEMP"
fi
])

View File

@@ -7,11 +7,6 @@ AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
AH_TOP([#define LIBSECP256K1_CONFIG_H])
AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
AM_INIT_AUTOMAKE([foreign subdir-objects])
# Set -g if CFLAGS are not already set, which matches the default autoconf
# behavior (see PROG_CC in the Autoconf manual) with the exception that we don't
# set -O2 here because we set it in any case (see further down).
: ${CFLAGS="-g"}
LT_INIT
dnl make the compilation flags quiet unless V=1 is used
@@ -24,6 +19,10 @@ AC_PATH_TOOL(RANLIB, ranlib)
AC_PATH_TOOL(STRIP, strip)
AX_PROG_CC_FOR_BUILD
if test "x$CFLAGS" = "x"; then
CFLAGS="-g"
fi
AM_PROG_CC_C_O
AC_PROG_CC_C89
@@ -46,7 +45,6 @@ case $host_os in
if test x$openssl_prefix != x; then
PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
export PKG_CONFIG_PATH
CRYPTO_CPPFLAGS="-I$openssl_prefix/include"
fi
if test x$gmp_prefix != x; then
GMP_CPPFLAGS="-I$gmp_prefix/include"
@@ -65,11 +63,11 @@ case $host_os in
;;
esac
CFLAGS="-W $CFLAGS"
CFLAGS="$CFLAGS -W"
warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef -Wno-unused-function -Wno-long-long -Wno-overlength-strings"
warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings"
saved_CFLAGS="$CFLAGS"
CFLAGS="$warn_CFLAGS $CFLAGS"
CFLAGS="$CFLAGS $warn_CFLAGS"
AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
[ AC_MSG_RESULT([yes]) ],
@@ -78,7 +76,7 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
])
saved_CFLAGS="$CFLAGS"
CFLAGS="-fvisibility=hidden $CFLAGS"
CFLAGS="$CFLAGS -fvisibility=hidden"
AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
[ AC_MSG_RESULT([yes]) ],
@@ -87,149 +85,106 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
])
AC_ARG_ENABLE(benchmark,
AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]),
AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]),
[use_benchmark=$enableval],
[use_benchmark=yes])
[use_benchmark=no])
AC_ARG_ENABLE(coverage,
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]),
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]),
[enable_coverage=$enableval],
[enable_coverage=no])
AC_ARG_ENABLE(tests,
AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]),
AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]),
[use_tests=$enableval],
[use_tests=yes])
AC_ARG_ENABLE(openssl_tests,
AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests [default=auto]]),
AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]),
[enable_openssl_tests=$enableval],
[enable_openssl_tests=auto])
AC_ARG_ENABLE(experimental,
AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]),
AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]),
[use_experimental=$enableval],
[use_experimental=no])
AC_ARG_ENABLE(exhaustive_tests,
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]),
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]),
[use_exhaustive_tests=$enableval],
[use_exhaustive_tests=yes])
AC_ARG_ENABLE(endomorphism,
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
[use_endomorphism=$enableval],
[use_endomorphism=no])
AC_ARG_ENABLE(ecmult_static_precomputation,
AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing [default=auto]]),
AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]),
[use_ecmult_static_precomputation=$enableval],
[use_ecmult_static_precomputation=auto])
AC_ARG_ENABLE(module_ecdh,
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation]),
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]),
[enable_module_ecdh=$enableval],
[enable_module_ecdh=no])
AC_ARG_ENABLE(module_musig,
AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]),
[enable_module_musig=$enableval],
[enable_module_musig=no])
AC_ARG_ENABLE(module_recovery,
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]),
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]),
[enable_module_recovery=$enableval],
[enable_module_recovery=no])
AC_ARG_ENABLE(module_generator,
AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module [default=no]]),
AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module (default is no)]),
[enable_module_generator=$enableval],
[enable_module_generator=no])
AC_ARG_ENABLE(module_rangeproof,
AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module [default=no]]),
AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module (default is no)]),
[enable_module_rangeproof=$enableval],
[enable_module_rangeproof=no])
AC_ARG_ENABLE(module_whitelist,
AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module [default=no]]),
AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module (default is no)]),
[enable_module_whitelist=$enableval],
[enable_module_whitelist=no])
AC_ARG_ENABLE(module_extrakeys,
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module (experimental)]),
[enable_module_extrakeys=$enableval],
[enable_module_extrakeys=no])
AC_ARG_ENABLE(module_schnorrsig,
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]),
[enable_module_schnorrsig=$enableval],
[enable_module_schnorrsig=no])
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])
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])
AC_ARG_ENABLE(jni,
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
[use_jni=$enableval],
[use_jni=auto])
AC_ARG_ENABLE(module_surjectionproof,
AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module [default=no]]),
AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module (default is no)]),
[enable_module_surjectionproof=$enableval],
[enable_module_surjectionproof=no])
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])
dnl Test-only override of the (autodetected by the C code) "widemul" setting.
dnl Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
[bignum implementation to use [default=auto]])],[req_bignum=$withval], [req_bignum=auto])
[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto])
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
[assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto])
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto])
AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto],
[window size for ecmult precomputation for verification, specified as integer in range [2..24].]
[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.]
[The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.]
["auto" is a reasonable setting for desktop machines (currently 15). [default=auto]]
)],
[req_ecmult_window=$withval], [req_ecmult_window=auto])
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto]
[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto])
AC_ARG_WITH([ecmult-gen-precision], [AS_HELP_STRING([--with-ecmult-gen-precision=2|4|8|auto],
[Precision bits to tune the precomputed table size for signing.]
[The size of the table is 32kB for 2 bits, 64kB for 4 bits, 512kB for 8 bits of precision.]
[A larger table size usually results in possible faster signing.]
["auto" is a reasonable setting for desktop machines (currently 4). [default=auto]]
)],
[req_ecmult_gen_precision=$withval], [req_ecmult_gen_precision=auto])
AC_CHECK_TYPES([__int128])
AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto],
[Build with extra checks for running inside Valgrind [default=auto]]
)],
[req_valgrind=$withval], [req_valgrind=auto])
if test x"$req_valgrind" = x"no"; then
enable_valgrind=no
else
AC_CHECK_HEADER([valgrind/memcheck.h], [enable_valgrind=yes], [
if test x"$req_valgrind" = x"yes"; then
AC_MSG_ERROR([Valgrind support explicitly requested but valgrind/memcheck.h header not available])
fi
enable_valgrind=no
], [])
fi
AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"])
AC_MSG_CHECKING([for __builtin_expect])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
[ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ],
[ AC_MSG_RESULT([no])
])
if test x"$enable_coverage" = x"yes"; then
AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
CFLAGS="-O0 --coverage $CFLAGS"
LDFLAGS="--coverage $LDFLAGS"
CFLAGS="$CFLAGS -O0 --coverage"
LDFLAGS="--coverage"
else
CFLAGS="-O2 $CFLAGS"
CFLAGS="$CFLAGS -O3"
fi
AC_MSG_CHECKING([for __builtin_popcount])
@@ -239,54 +194,27 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_popcount(0);}]])],
])
if test x"$use_ecmult_static_precomputation" != x"no"; then
# Temporarily switch to an environment for the native compiler
save_cross_compiling=$cross_compiling
cross_compiling=no
SAVE_CC="$CC"
TEMP_CC="$CC"
CC="$CC_FOR_BUILD"
SAVE_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS_FOR_BUILD"
SAVE_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS_FOR_BUILD"
SAVE_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS_FOR_BUILD"
warn_CFLAGS_FOR_BUILD="-Wall -Wextra -Wno-unused-function"
saved_CFLAGS="$CFLAGS"
CFLAGS="$warn_CFLAGS_FOR_BUILD $CFLAGS"
AC_MSG_CHECKING([if native ${CC_FOR_BUILD} supports ${warn_CFLAGS_FOR_BUILD}])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
CFLAGS="$saved_CFLAGS"
])
AC_MSG_CHECKING([for working native compiler: ${CC_FOR_BUILD}])
AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([], [])],
[AC_LANG_PROGRAM([], [return 0])],
[working_native_cc=yes],
[working_native_cc=no],[:])
CFLAGS_FOR_BUILD="$CFLAGS"
# Restore the environment
[working_native_cc=no],[dnl])
CC="$TEMP_CC"
cross_compiling=$save_cross_compiling
CC="$SAVE_CC"
CFLAGS="$SAVE_CFLAGS"
CPPFLAGS="$SAVE_CPPFLAGS"
LDFLAGS="$SAVE_LDFLAGS"
if test x"$working_native_cc" = x"no"; then
AC_MSG_RESULT([no])
set_precomp=no
m4_define([please_set_for_build], [Please set CC_FOR_BUILD, CFLAGS_FOR_BUILD, CPPFLAGS_FOR_BUILD, and/or LDFLAGS_FOR_BUILD.])
if test x"$use_ecmult_static_precomputation" = x"yes"; then
AC_MSG_ERROR([native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
else
AC_MSG_WARN([Disabling statically generated ecmult table because the native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
fi
else
AC_MSG_RESULT([yes])
AC_MSG_RESULT([ok])
set_precomp=yes
fi
else
@@ -326,6 +254,63 @@ else
esac
fi
if test x"$req_field" = x"auto"; then
if test x"set_asm" = x"x86_64"; then
set_field=64bit
fi
if test x"$set_field" = x; then
SECP_INT128_CHECK
if test x"$has_int128" = x"yes"; then
set_field=64bit
fi
fi
if test x"$set_field" = x; then
set_field=32bit
fi
else
set_field=$req_field
case $set_field in
64bit)
if test x"$set_asm" != x"x86_64"; then
SECP_INT128_CHECK
if test x"$has_int128" != x"yes"; then
AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available])
fi
fi
;;
32bit)
;;
*)
AC_MSG_ERROR([invalid field implementation selection])
;;
esac
fi
if test x"$req_scalar" = x"auto"; then
SECP_INT128_CHECK
if test x"$has_int128" = x"yes"; then
set_scalar=64bit
fi
if test x"$set_scalar" = x; then
set_scalar=32bit
fi
else
set_scalar=$req_scalar
case $set_scalar in
64bit)
SECP_INT128_CHECK
if test x"$has_int128" != x"yes"; then
AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available])
fi
;;
32bit)
;;
*)
AC_MSG_ERROR([invalid scalar implementation selected])
;;
esac
fi
if test x"$req_bignum" = x"auto"; then
SECP_GMP_CHECK
if test x"$has_gmp" = x"yes"; then
@@ -369,18 +354,16 @@ no)
;;
esac
# select wide multiplication implementation
case $set_widemul in
int128)
AC_DEFINE(USE_FORCE_WIDEMUL_INT128, 1, [Define this symbol to force the use of the (unsigned) __int128 based wide multiplication implementation])
# select field implementation
case $set_field in
64bit)
AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation])
;;
int64)
AC_DEFINE(USE_FORCE_WIDEMUL_INT64, 1, [Define this symbol to force the use of the (u)int64_t based wide multiplication implementation])
;;
auto)
32bit)
AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation])
;;
*)
AC_MSG_ERROR([invalid wide multiplication implementation])
AC_MSG_ERROR([invalid field implementation])
;;
esac
@@ -402,50 +385,25 @@ no)
;;
esac
#set ecmult window size
if test x"$req_ecmult_window" = x"auto"; then
set_ecmult_window=15
else
set_ecmult_window=$req_ecmult_window
fi
error_window_size=['window size for ecmult precomputation not an integer in range [2..24] or "auto"']
case $set_ecmult_window in
''|*[[!0-9]]*)
# no valid integer
AC_MSG_ERROR($error_window_size)
#select scalar implementation
case $set_scalar in
64bit)
AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation])
;;
32bit)
AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation])
;;
*)
if test "$set_ecmult_window" -lt 2 -o "$set_ecmult_window" -gt 24 ; then
# not in range
AC_MSG_ERROR($error_window_size)
fi
AC_DEFINE_UNQUOTED(ECMULT_WINDOW_SIZE, $set_ecmult_window, [Set window size for ecmult precomputation])
;;
esac
#set ecmult gen precision
if test x"$req_ecmult_gen_precision" = x"auto"; then
set_ecmult_gen_precision=4
else
set_ecmult_gen_precision=$req_ecmult_gen_precision
fi
case $set_ecmult_gen_precision in
2|4|8)
AC_DEFINE_UNQUOTED(ECMULT_GEN_PREC_BITS, $set_ecmult_gen_precision, [Set ecmult gen precision bits])
;;
*)
AC_MSG_ERROR(['ecmult gen precision not 2, 4, 8 or "auto"'])
AC_MSG_ERROR([invalid scalar implementation])
;;
esac
if test x"$use_tests" = x"yes"; then
SECP_OPENSSL_CHECK
if test x"$enable_openssl_tests" != x"no" && test x"$has_openssl_ec" = x"yes"; then
enable_openssl_tests=yes
if test x"$has_openssl_ec" = x"yes"; then
if test x"$enable_openssl_tests" != x"no"; then
AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS $CRYPTO_CPPFLAGS"
SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
SECP_TEST_LIBS="$CRYPTO_LIBS"
case $host in
@@ -453,17 +411,39 @@ if test x"$use_tests" = x"yes"; then
SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
;;
esac
fi
else
if test x"$enable_openssl_tests" = x"yes"; then
AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available])
fi
enable_openssl_tests=no
fi
else
if test x"$enable_openssl_tests" = x"yes"; then
AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled])
fi
enable_openssl_tests=no
fi
if test x"$use_jni" != x"no"; then
AX_JNI_INCLUDE_DIR
have_jni_dependencies=yes
if test x"$enable_module_ecdh" = x"no"; then
have_jni_dependencies=no
fi
if test "x$JNI_INCLUDE_DIRS" = "x"; then
have_jni_dependencies=no
fi
if test "x$have_jni_dependencies" = "xno"; then
if test x"$use_jni" = x"yes"; then
AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.])
fi
AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])
use_jni=no
else
use_jni=yes
for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR"
done
fi
fi
if test x"$set_bignum" = x"gmp"; then
@@ -471,6 +451,10 @@ if test x"$set_bignum" = x"gmp"; then
SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS"
fi
if test x"$use_endomorphism" = x"yes"; then
AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])
fi
if test x"$set_precomp" = x"yes"; then
AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table])
fi
@@ -479,10 +463,6 @@ if test x"$enable_module_ecdh" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
fi
if test x"$enable_module_musig" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_MUSIG, 1, [Define this symbol to enable the MuSig module])
fi
if test x"$enable_module_recovery" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
fi
@@ -503,54 +483,34 @@ if test x"$enable_module_surjectionproof" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_SURJECTIONPROOF, 1, [Define this symbol to enable the surjection proof module])
fi
if test x"$enable_module_schnorrsig" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module])
enable_module_extrakeys=yes
fi
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
# module to set enable_module_extrakeys=yes
if test x"$enable_module_extrakeys" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module])
fi
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
AC_C_BIGENDIAN()
if test x"$use_external_asm" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
fi
if test x"$use_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
if test x"$use_reduced_surjection_proof_size" = x"yes"; then
AC_DEFINE(USE_REDUCED_SURJECTION_PROOF_SIZE, 1, [Define this symbol to reduce SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS to 16, disabling parsing and verification])
fi
AC_MSG_NOTICE([Using static precomputation: $set_precomp])
AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
AC_MSG_NOTICE([Using field implementation: $set_field])
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage])
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
AC_MSG_NOTICE([Using jni: $use_jni])
if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([******])
AC_MSG_NOTICE([WARNING: experimental build])
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
AC_MSG_NOTICE([Building NUMS generator module: $enable_module_generator])
AC_MSG_NOTICE([Building range proof module: $enable_module_rangeproof])
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([******])
if test x"$enable_module_schnorrsig" != x"yes"; then
if test x"$enable_module_musig" = x"yes"; then
AC_MSG_ERROR([MuSig module requires the schnorrsig module. Use --enable-module-schnorrsig to allow.])
fi
fi
if test x"$enable_module_generator" != x"yes"; then
if test x"$enable_module_rangeproof" = x"yes"; then
AC_MSG_ERROR([Rangeproof module requires the generator module. Use --enable-module-generator to allow.])
@@ -566,17 +526,8 @@ if test x"$enable_experimental" = x"yes"; then
fi
fi
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.])
if test x"$enable_module_ecdh" = x"yes"; then
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
fi
if test x"$set_asm" = x"arm"; then
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
@@ -597,6 +548,7 @@ fi
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
AC_SUBST(JNI_INCLUDES)
AC_SUBST(SECP_INCLUDES)
AC_SUBST(SECP_LIBS)
AC_SUBST(SECP_TEST_LIBS)
@@ -607,18 +559,14 @@ 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_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = 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"])
AM_CONDITIONAL([ENABLE_MODULE_GENERATOR], [test x"$enable_module_generator" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_S2C], [test x"$enable_module_ecdsa_s2c" = x"yes"])
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_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"])
dnl make sure nothing new is exported so that we don't break the cache
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
@@ -626,33 +574,3 @@ unset PKG_CONFIG_PATH
PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
AC_OUTPUT
echo
echo "Build Options:"
echo " with ecmult precomp = $set_precomp"
echo " with external callbacks = $use_external_default_callbacks"
echo " with benchmarks = $use_benchmark"
echo " with tests = $use_tests"
echo " with openssl tests = $enable_openssl_tests"
echo " with coverage = $enable_coverage"
echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo " module extrakeys = $enable_module_extrakeys"
echo " module schnorrsig = $enable_module_schnorrsig"
echo " module ecdsa-s2c = $enable_module_ecdsa_s2c"
echo
echo " asm = $set_asm"
echo " bignum = $set_bignum"
echo " ecmult window size = $set_ecmult_window"
echo " ecmult gen prec. bits = $set_ecmult_gen_precision"
dnl Hide test-only options unless they're used.
if test x"$set_widemul" != xauto; then
echo " wide multiplication = $set_widemul"
fi
echo
echo " valgrind = $enable_valgrind"
echo " CC = $CC"
echo " CFLAGS = $CFLAGS"
echo " CPPFLAGS = $CPPFLAGS"
echo " LDFLAGS = $LDFLAGS"
echo

View File

@@ -32,7 +32,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (lenbyte > inputlen - pos) {
if (pos + lenbyte > inputlen) {
return 0;
}
pos += lenbyte;
@@ -51,7 +51,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (lenbyte > inputlen - pos) {
if (pos + lenbyte > inputlen) {
return 0;
}
while (lenbyte > 0 && input[pos] == 0) {
@@ -89,7 +89,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (lenbyte > inputlen - pos) {
if (pos + lenbyte > inputlen) {
return 0;
}
while (lenbyte > 0 && input[pos] == 0) {
@@ -112,6 +112,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
return 0;
}
spos = pos;
pos += slen;
/* Ignore leading zeroes in R */
while (rlen > 0 && input[rpos] == 0) {

View File

@@ -48,14 +48,14 @@
* 8.3.1.
*/
#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H
#define SECP256K1_CONTRIB_LAX_DER_PARSING_H
#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
#include <secp256k1.h>
#ifdef __cplusplus
# ifdef __cplusplus
extern "C" {
#endif
# endif
/** Parse a signature in "lax DER" format
*
@@ -88,4 +88,4 @@ int ecdsa_signature_parse_der_lax(
}
#endif
#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */
#endif

View File

@@ -25,14 +25,14 @@
* library are sufficient.
*/
#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H
#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H
#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
#include <secp256k1.h>
#ifdef __cplusplus
# ifdef __cplusplus
extern "C" {
#endif
# endif
/** Export a private key in DER format.
*
@@ -87,4 +87,4 @@ SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der(
}
#endif
#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */
#endif

View File

@@ -1,70 +0,0 @@
#!/bin/sh
set -e
set -x
if [ "$HOST" = "i686-linux-gnu" ]
then
export CC="$CC -m32"
fi
if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$TRAVIS_COMPILER" = "gcc" ]
then
export CC="gcc-9"
fi
./configure \
--enable-experimental="$EXPERIMENTAL" \
--with-test-override-wide-multiply="$WIDEMUL" --with-bignum="$BIGNUM" --with-asm="$ASM" \
--enable-ecmult-static-precomputation="$STATICPRECOMPUTATION" --with-ecmult-gen-precision="$ECMULTGENPRECISION" \
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
--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"\
--with-valgrind="$WITH_VALGRIND" \
--host="$HOST" $EXTRAFLAGS
if [ -n "$BUILD" ]
then
make -j2 "$BUILD"
fi
if [ "$RUN_VALGRIND" = "yes" ]
then
make -j2
# the `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (http://valgrind.org/docs/manual/manual-core.html)
valgrind --error-exitcode=42 ./tests 16
valgrind --error-exitcode=42 ./exhaustive_tests
fi
if [ "$BENCH" = "yes" ]
then
if [ "$RUN_VALGRIND" = "yes" ]
then
# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool
EXEC='./libtool --mode=execute valgrind --error-exitcode=42'
else
EXEC=
fi
# This limits the iterations in the benchmarks below to ITER(set in .travis.yml) iterations.
export SECP256K1_BENCH_ITERS="$ITERS"
{
$EXEC ./bench_ecmult
$EXEC ./bench_internal
$EXEC ./bench_sign
$EXEC ./bench_verify
} >> bench.log 2>&1
if [ "$RECOVERY" = "yes" ]
then
$EXEC ./bench_recover >> bench.log 2>&1
fi
if [ "$ECDH" = "yes" ]
then
$EXEC ./bench_ecdh >> bench.log 2>&1
fi
if [ "$SCHNORRSIG" = "yes" ]
then
$EXEC ./bench_schnorrsig >> bench.log 2>&1
fi
fi
if [ "$CTIMETEST" = "yes" ]
then
./libtool --mode=execute valgrind --error-exitcode=42 ./valgrind_ctime_test > valgrind_ctime_test.log 2>&1
fi

View File

@@ -1,9 +1,9 @@
#ifndef SECP256K1_H
#define SECP256K1_H
#ifndef _SECP256K1_
# define _SECP256K1_
#ifdef __cplusplus
# ifdef __cplusplus
extern "C" {
#endif
# endif
#include <stddef.h>
@@ -14,7 +14,7 @@ extern "C" {
* 2. Array lengths always immediately the follow the argument whose length
* they describe, even if this violates rule 1.
* 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated
* later go first. This means: signatures, public nonces, secret nonces,
* later go first. This means: signatures, public nonces, private nonces,
* messages, public keys, secret keys, tweaks.
* 4. Arguments that are not data pointers go last, from more complex to less
* complex: function pointers, algorithm names, messages, void pointers,
@@ -33,29 +33,15 @@ extern "C" {
* verification).
*
* A constructed context can safely be used from multiple threads
* simultaneously, but API calls that take a non-const pointer to a context
* simultaneously, but API call that take a non-const pointer to a context
* need exclusive access to it. In particular this is the case for
* secp256k1_context_destroy, secp256k1_context_preallocated_destroy,
* and secp256k1_context_randomize.
* secp256k1_context_destroy and secp256k1_context_randomize.
*
* Regarding randomization, either do it once at creation time (in which case
* you do not need any locking for the other calls), or use a read-write lock.
*/
typedef struct secp256k1_context_struct secp256k1_context;
/** Opaque data structure that holds rewriteable "scratch space"
*
* The purpose of this structure is to replace dynamic memory allocations,
* because we target architectures where this may not be available. It is
* essentially a resizable (within specified parameters) block of bytes,
* which is initially created either by memory allocation or TODO as a pointer
* into some fixed rewritable space.
*
* Unlike the context object, this cannot safely be shared between threads
* without additional synchronization logic.
*/
typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
/** Opaque data structure that holds a parsed and valid public key.
*
* The exact representation of data inside is implementation defined and not
@@ -75,7 +61,7 @@ typedef struct {
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use the secp256k1_ecdsa_signature_serialize_* and
* secp256k1_ecdsa_signature_parse_* functions.
* secp256k1_ecdsa_signature_serialize_* functions.
*/
typedef struct {
unsigned char data[64];
@@ -134,7 +120,7 @@ typedef int (*secp256k1_nonce_function)(
# else
# define SECP256K1_API
# endif
# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
# elif defined(__GNUC__) && defined(SECP256K1_BUILD)
# define SECP256K1_API __attribute__ ((visibility ("default")))
# else
# define SECP256K1_API
@@ -162,39 +148,18 @@ typedef int (*secp256k1_nonce_function)(
/** The higher bits contain the actual data. Do not use directly. */
#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)
#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
#define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10)
#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
/** Flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and
* secp256k1_context_preallocated_create. */
/** Flags to pass to secp256k1_context_create. */
#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
#define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY)
#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
/** Flag to pass to secp256k1_ec_pubkey_serialize. */
/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */
#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION)
/** Prefix byte used to tag various encoded curvepoints for specific purposes */
#define SECP256K1_TAG_PUBKEY_EVEN 0x02
#define SECP256K1_TAG_PUBKEY_ODD 0x03
#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04
#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
/** A simple secp256k1 context object with no precomputed tables. These are useful for
* type serialization/parsing functions which require a context object to maintain
* API consistency, but currently do not require expensive precomputations or dynamic
* allocations.
*/
SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp;
/** Create a secp256k1 context object (in dynamically allocated memory).
*
* This function uses malloc to allocate memory. It is guaranteed that malloc is
* called at most once for every call of this function. If you need to avoid dynamic
* memory allocation entirely, see the functions in secp256k1_preallocated.h.
/** Create a secp256k1 context object.
*
* Returns: a newly created context object.
* In: flags: which parts of the context to initialize.
@@ -205,11 +170,7 @@ SECP256K1_API secp256k1_context* secp256k1_context_create(
unsigned int flags
) SECP256K1_WARN_UNUSED_RESULT;
/** Copy a secp256k1 context object (into dynamically allocated memory).
*
* This function uses malloc to allocate memory. It is guaranteed that malloc is
* called at most once for every call of this function. If you need to avoid dynamic
* memory allocation entirely, see the functions in secp256k1_preallocated.h.
/** Copies a secp256k1 context object.
*
* Returns: a newly created context object.
* Args: ctx: an existing context to copy (cannot be NULL)
@@ -218,18 +179,10 @@ SECP256K1_API secp256k1_context* secp256k1_context_clone(
const secp256k1_context* ctx
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
/** Destroy a secp256k1 context object (created in dynamically allocated memory).
/** Destroy a secp256k1 context object.
*
* The context pointer may not be used afterwards.
*
* The context to destroy must have been created using secp256k1_context_create
* or secp256k1_context_clone. If the context has instead been created using
* secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone, the
* behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must
* be used instead.
*
* Args: ctx: an existing context to destroy, constructed using
* secp256k1_context_create or secp256k1_context_clone
* Args: ctx: an existing context to destroy (cannot be NULL)
*/
SECP256K1_API void secp256k1_context_destroy(
secp256k1_context* ctx
@@ -249,28 +202,11 @@ SECP256K1_API void secp256k1_context_destroy(
* to cause a crash, though its return value and output arguments are
* undefined.
*
* When this function has not been called (or called with fn==NULL), then the
* default handler will be used. The library provides a default handler which
* writes the message to stderr and calls abort. This default handler can be
* replaced at link time if the preprocessor macro
* USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build
* has been configured with --enable-external-default-callbacks. Then the
* following two symbols must be provided to link against:
* - void secp256k1_default_illegal_callback_fn(const char* message, void* data);
* - void secp256k1_default_error_callback_fn(const char* message, void* data);
* The library can call these default handlers even before a proper callback data
* pointer could have been set using secp256k1_context_set_illegal_callback or
* secp256k1_context_set_error_callback, e.g., when the creation of a context
* fails. In this case, the corresponding default handler will be called with
* the data pointer argument set to NULL.
*
* Args: ctx: an existing context object (cannot be NULL)
* In: fun: a pointer to a function to call when an illegal argument is
* passed to the API, taking a message and an opaque pointer.
* (NULL restores the default handler.)
* passed to the API, taking a message and an opaque pointer
* (NULL restores a default handler that calls abort).
* data: the opaque pointer to pass to fun above.
*
* See also secp256k1_context_set_error_callback.
*/
SECP256K1_API void secp256k1_context_set_illegal_callback(
secp256k1_context* ctx,
@@ -290,12 +226,9 @@ SECP256K1_API void secp256k1_context_set_illegal_callback(
*
* Args: ctx: an existing context object (cannot be NULL)
* In: fun: a pointer to a function to call when an internal error occurs,
* taking a message and an opaque pointer (NULL restores the
* default handler, see secp256k1_context_set_illegal_callback
* for details).
* taking a message and an opaque pointer (NULL restores a default
* handler that calls abort).
* data: the opaque pointer to pass to fun above.
*
* See also secp256k1_context_set_illegal_callback.
*/
SECP256K1_API void secp256k1_context_set_error_callback(
secp256k1_context* ctx,
@@ -303,29 +236,6 @@ SECP256K1_API void secp256k1_context_set_error_callback(
const void* data
) SECP256K1_ARG_NONNULL(1);
/** Create a secp256k1 scratch space object.
*
* Returns: a newly created scratch space.
* Args: ctx: an existing context object (cannot be NULL)
* In: size: amount of memory to be available as scratch space. Some extra
* (<100 bytes) will be allocated for extra accounting.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_scratch_space_create(
const secp256k1_context* ctx,
size_t size
) SECP256K1_ARG_NONNULL(1);
/** Destroy a secp256k1 scratch space.
*
* The pointer may not be used afterwards.
* Args: ctx: a secp256k1 context object.
* scratch: space to destroy
*/
SECP256K1_API void secp256k1_scratch_space_destroy(
const secp256k1_context* ctx,
secp256k1_scratch_space* scratch
) SECP256K1_ARG_NONNULL(1);
/** Parse a variable-length public key into the pubkey object.
*
* Returns: 1 if the public key was fully valid.
@@ -531,7 +441,7 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def
/** Create an ECDSA signature.
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the secret key was invalid.
* 0: the nonce generation function failed, or the private key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
@@ -552,11 +462,6 @@ SECP256K1_API int secp256k1_ecdsa_sign(
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Verify an ECDSA secret key.
*
* A secret key is valid if it is not 0 and less than the secp256k1 curve order
* when interpreted as an integer (most significant byte first). The
* probability of choosing a 32-byte string uniformly at random which is an
* invalid secret key is negligible.
*
* Returns: 1: secret key is valid
* 0: secret key is invalid
@@ -574,7 +479,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
* 0: secret was invalid, try again
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: pubkey: pointer to the created public key (cannot be NULL)
* In: seckey: pointer to a 32-byte secret key (cannot be NULL)
* In: seckey: pointer to a 32-byte private key (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
const secp256k1_context* ctx,
@@ -582,24 +487,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Negates a secret key in place.
/** Negates a private key in place.
*
* Returns: 0 if the given secret key is invalid according to
* secp256k1_ec_seckey_verify. 1 otherwise
* Args: ctx: pointer to a context object
* In/Out: seckey: pointer to the 32-byte secret key to be negated. If the
* secret key is invalid according to
* secp256k1_ec_seckey_verify, this function returns 0 and
* seckey will be set to some unspecified value. (cannot be
* NULL)
* Returns: 1 always
* Args: ctx: pointer to a context object
* In/Out: pubkey: pointer to the public key to be negated (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
const secp256k1_context* ctx,
unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in
* future versions. */
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
const secp256k1_context* ctx,
unsigned char *seckey
@@ -616,29 +509,15 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
secp256k1_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Tweak a secret key by adding tweak to it.
*
* Returns: 0 if the arguments are invalid or the resulting secret key would be
* invalid (only when the tweak is the negation of the secret key). 1
* otherwise.
* Args: ctx: pointer to a context object (cannot be NULL).
* In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
* invalid according to secp256k1_ec_seckey_verify, this
* function returns 0. seckey will be set to some unspecified
* value if this function returns 0. (cannot be NULL)
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
* secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128) (cannot be NULL).
/** Tweak a private key by adding tweak to it.
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
* uniformly random 32-byte arrays, or if the resulting private key
* would be invalid (only when the tweak is the complement of the
* private key). 1 otherwise.
* Args: ctx: pointer to a context object (cannot be NULL).
* In/Out: seckey: pointer to a 32-byte private key.
* In: tweak: pointer to a 32-byte tweak.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
const secp256k1_context* ctx,
unsigned char *seckey,
const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in
* future versions. */
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
const secp256k1_context* ctx,
unsigned char *seckey,
@@ -646,18 +525,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Tweak a public key by adding tweak times the generator to it.
*
* Returns: 0 if the arguments are invalid or the resulting public key would be
* invalid (only when the tweak is the negation of the corresponding
* secret key). 1 otherwise.
* Args: ctx: pointer to a context object initialized for validation
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
* uniformly random 32-byte arrays, or if the resulting public key
* would be invalid (only when the tweak is the complement of the
* corresponding private key). 1 otherwise.
* Args: ctx: pointer to a context object initialized for validation
* (cannot be NULL).
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
* invalid value if this function returns 0 (cannot be NULL).
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
* secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128) (cannot be NULL).
* In/Out: pubkey: pointer to a public key object.
* In: tweak: pointer to a 32-byte tweak.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
const secp256k1_context* ctx,
@@ -665,27 +540,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Tweak a secret key by multiplying it by a tweak.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
* Args: ctx: pointer to a context object (cannot be NULL).
* In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
* invalid according to secp256k1_ec_seckey_verify, this
* function returns 0. seckey will be set to some unspecified
* value if this function returns 0. (cannot be NULL)
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
* secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128) (cannot be NULL).
/** Tweak a private key by multiplying it by a tweak.
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
* uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
* Args: ctx: pointer to a context object (cannot be NULL).
* In/Out: seckey: pointer to a 32-byte private key.
* In: tweak: pointer to a 32-byte tweak.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
const secp256k1_context* ctx,
unsigned char *seckey,
const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in
* future versions. */
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
const secp256k1_context* ctx,
unsigned char *seckey,
@@ -693,16 +554,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Tweak a public key by multiplying it by a tweak value.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
* Args: ctx: pointer to a context object initialized for validation
* (cannot be NULL).
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
* invalid value if this function returns 0 (cannot be NULL).
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
* secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128) (cannot be NULL).
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
* uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
* Args: ctx: pointer to a context object initialized for validation
* (cannot be NULL).
* In/Out: pubkey: pointer to a public key obkect.
* In: tweak: pointer to a 32-byte tweak.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
const secp256k1_context* ctx,
@@ -711,7 +568,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Updates the context randomization to protect against side-channel leakage.
* Returns: 1: randomization successfully updated or nothing to randomize
* Returns: 1: randomization successfully updated
* 0: error
* Args: ctx: pointer to a context object (cannot be NULL)
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
@@ -726,14 +583,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
* that it does not affect function results, but shields against attacks which
* rely on any input-dependent behaviour.
*
* This function has currently an effect only on contexts initialized for signing
* because randomization is currently used only for signing. However, this is not
* guaranteed and may change in the future. It is safe to call this function on
* contexts not initialized for signing; then it will have no effect and return 1.
*
* You should call this after secp256k1_context_create or
* secp256k1_context_clone (and secp256k1_context_preallocated_create or
* secp256k1_context_clone, resp.), and you may call this repeatedly afterwards.
* secp256k1_context_clone, and may call this repeatedly afterwards.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
secp256k1_context* ctx,
@@ -741,7 +592,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
) SECP256K1_ARG_NONNULL(1);
/** Add a number of public keys together.
*
* Returns: 1: the sum of the public keys is valid.
* 0: the sum of the public keys is not valid.
* Args: ctx: pointer to a context object
@@ -757,8 +607,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
size_t n
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
#ifdef __cplusplus
# ifdef __cplusplus
}
#endif
# endif
#endif /* SECP256K1_H */
#endif

View File

@@ -1,62 +1,31 @@
#ifndef SECP256K1_ECDH_H
#define SECP256K1_ECDH_H
#ifndef _SECP256K1_ECDH_
# define _SECP256K1_ECDH_
#include "secp256k1.h"
# include "secp256k1.h"
#ifdef __cplusplus
# ifdef __cplusplus
extern "C" {
#endif
/** A pointer to a function that hashes an EC point to obtain an ECDH secret
*
* Returns: 1 if the point was successfully hashed.
* 0 will cause secp256k1_ecdh to fail and return 0.
* Other return values are not allowed, and the behaviour of
* secp256k1_ecdh is undefined for other return values.
* Out: output: pointer to an array to be filled by the function
* In: x32: pointer to a 32-byte x coordinate
* y32: pointer to a 32-byte y coordinate
* data: arbitrary data pointer that is passed through
*/
typedef int (*secp256k1_ecdh_hash_function)(
unsigned char *output,
const unsigned char *x32,
const unsigned char *y32,
void *data
);
/** An implementation of SHA256 hash function that applies to compressed public key.
* Populates the output parameter with 32 bytes. */
SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256).
* Populates the output parameter with 32 bytes. */
SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
# endif
/** Compute an EC Diffie-Hellman secret in constant time
*
* Returns: 1: exponentiation was successful
* 0: scalar was invalid (zero or overflow) or hashfp returned 0
* 0: scalar was invalid (zero or overflow)
* Args: ctx: pointer to a context object (cannot be NULL)
* Out: output: pointer to an array to be filled by hashfp
* Out: result: a 32-byte array which will be populated by an ECDH
* secret computed from the point and scalar
* In: pubkey: a pointer to a secp256k1_pubkey containing an
* initialized public key
* seckey: a 32-byte scalar with which to multiply the point
* hashfp: pointer to a hash function. If NULL, secp256k1_ecdh_hash_function_sha256 is used
* (in which case, 32 bytes will be written to output)
* data: arbitrary data pointer that is passed through to hashfp
* privkey: a 32-byte scalar with which to multiply the point
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
const secp256k1_context* ctx,
unsigned char *output,
unsigned char *result,
const secp256k1_pubkey *pubkey,
const unsigned char *seckey,
secp256k1_ecdh_hash_function hashfp,
void *data
const unsigned char *privkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
#ifdef __cplusplus
# ifdef __cplusplus
}
#endif
# endif
#endif /* SECP256K1_ECDH_H */
#endif

View File

@@ -1,234 +0,0 @@
#ifndef SECP256K1_ECDSA_S2C_H
#define SECP256K1_ECDSA_S2C_H
#include "secp256k1.h"
/** This module implements the sign-to-contract scheme for ECDSA signatures, as
* well as the "ECDSA Anti-Klepto Protocol" that is based on sign-to-contract
* and is specified further down. The sign-to-contract scheme allows creating a
* signature that also commits to some data. This works by offsetting the public
* nonce point of the signature R by hash(R, data)*G where G is the secp256k1
* group generator.
*/
#ifdef __cplusplus
extern "C" {
#endif
/** Data structure that holds a sign-to-contract ("s2c") opening information.
* Sign-to-contract allows a signer to commit to some data as part of a signature. It
* can be used as an Out-argument in certain signing functions.
*
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use secp256k1_ecdsa_s2c_opening_serialize and secp256k1_ecdsa_s2c_opening_parse.
*/
typedef struct {
unsigned char data[64];
} secp256k1_ecdsa_s2c_opening;
/** Parse a sign-to-contract opening.
*
* Returns: 1 if the opening could be parsed
* 0 if the opening could not be parsed
* Args: ctx: a secp256k1 context object.
* Out: opening: pointer to an opening object. If 1 is returned, it is set to a
* parsed version of input. If not, its value is unspecified.
* In: input33: pointer to 33-byte array with a serialized opening
*
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_parse(
const secp256k1_context* ctx,
secp256k1_ecdsa_s2c_opening* opening,
const unsigned char* input33
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize a sign-to-contract opening into a byte sequence.
*
* Returns: 1 if the opening was successfully serialized.
* 0 if the opening could not be serialized
* Args: ctx: a secp256k1 context object
* Out: output33: pointer to a 33-byte array to place the serialized opening in
* In: opening: a pointer to an initialized `secp256k1_ecdsa_s2c_opening`
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_serialize(
const secp256k1_context* ctx,
unsigned char* output33,
const secp256k1_ecdsa_s2c_opening* opening
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Same as secp256k1_ecdsa_sign, but s2c_data32 is committed to inside the nonce
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the private key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* s2c_opening: if non-NULL, pointer to an secp256k1_ecdsa_s2c_opening structure to populate
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* s2c_data32: pointer to a 32-byte data to commit to in the nonce (cannot be NULL)
*/
SECP256K1_API int secp256k1_ecdsa_s2c_sign(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature* sig,
secp256k1_ecdsa_s2c_opening* s2c_opening,
const unsigned char* msg32,
const unsigned char* seckey,
const unsigned char* s2c_data32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
/** Verify a sign-to-contract commitment.
*
* Returns: 1: the signature contains a commitment to data32 (though it does
* not necessarily need to be a valid siganture!)
* 0: incorrect opening
* Args: ctx: a secp256k1 context object, initialized for verification.
* In: sig: the signature containing the sign-to-contract commitment (cannot be NULL)
* data32: the 32-byte data that was committed to (cannot be NULL)
* opening: pointer to the opening created during signing (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_verify_commit(
const secp256k1_context* ctx,
const secp256k1_ecdsa_signature *sig,
const unsigned char *data32,
const secp256k1_ecdsa_s2c_opening *opening
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** ECDSA Anti-Klepto Protocol
*
* The ecdsa_anti_klepto_* functions can be used to prevent a signing device from
* exfiltrating the secret signing keys through biased signature nonces. The general
* idea is that a host provides additional randomness to the signing device client
* and the client commits to the randomness in the nonce using sign-to-contract.
*
* The following scheme is described by Stepan Snigirev here:
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-February/017655.html
* and by Pieter Wuille (as "Scheme 6") here:
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-March/017667.html
*
* In order to ensure the host cannot trick the signing device into revealing its
* keys, or the signing device to bias the nonce despite the host's contributions,
* the host and client must engage in a commit-reveal protocol as follows:
* 1. The host draws randomness `rho` and computes a sha256 commitment to it using
* `secp256k1_ecdsa_anti_klepto_host_commit`. It sends this to the signing device.
* 2. The signing device computes a public nonce `R` using the host's commitment
* as auxiliary randomness, using `secp256k1_ecdsa_anti_klepto_signer_commit`.
* The signing device sends the resulting `R` to the host as a s2c_opening.
*
* If, at any point from this step onward, the hardware device fails, it is
* okay to restart the protocol using **exactly the same `rho`** and checking
* that the hardware device proposes **exactly the same** `R`. Otherwise, the
* hardware device may be selectively aborting and thereby biasing the set of
* nonces that are used in actual signatures.
*
* It takes many (>100) such aborts before there is a plausible attack, given
* current knowledge in 2020. However such aborts accumulate even across a total
* replacement of all relevant devices (but not across replacement of the actual
* signing keys with new independently random ones).
*
* In case the hardware device cannot be made to sign with the given `rho`, `R`
* pair, wallet authors should alert the user and present a very scary message
* implying that if this happens more than even a few times, say 20 or more times
* EVER, they should change hardware vendors and perhaps sweep their coins.
*
* 3. The host replies with `rho` generated in step 1.
* 4. The device signs with `secp256k1_anti_klepto_sign`, using `rho` as `host_data32`,
* and sends the signature to the host.
* 5. The host verifies that the signature's public nonce matches the opening from
* step 2 and its original randomness `rho`, using `secp256k1_anti_klepto_host_verify`.
*
* Rationale:
* - The reason for having a host commitment is to allow the signing device to
* deterministically derive a unique nonce even if the host restarts the protocol
* using the same message and keys. Otherwise the signer might reuse the original
* nonce in two iterations of the protocol with different `rho`, which leaks the
* the secret key.
* - The signer does not need to check that the host commitment matches the host's
* claimed `rho`. Instead it re-derives the commitment (and its original `R`) from
* the provided `rho`. If this differs from the original commitment, the result
* will be an invalid `s2c_opening`, but since `R` was unique there is no risk to
* the signer's secret keys. Because of this, the signing device does not need to
* maintain any state about the progress of the protocol.
*/
/** Create the initial host commitment to `rho`. Part of the ECDSA Anti-Klepto Protocol.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object (cannot be NULL)
* Out: rand_commitment32: pointer to 32-byte array to store the returned commitment (cannot be NULL)
* In: rand32: the 32-byte randomness to commit to (cannot be NULL). It must come from
* a cryptographically secure RNG. As per the protocol, this value must not
* be revealed to the client until after the host has received the client
* commitment.
*/
SECP256K1_API int secp256k1_ecdsa_anti_klepto_host_commit(
const secp256k1_context* ctx,
unsigned char* rand_commitment32,
const unsigned char* rand32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Compute signer's original nonce. Part of the ECDSA Anti-Klepto Protocol.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: s2c_opening: pointer to an s2c_opening where the signer's public nonce will be
* placed. (cannot be NULL)
* In: msg32: the 32-byte message hash to be signed (cannot be NULL)
* seckey32: the 32-byte secret key used for signing (cannot be NULL)
* rand_commitment32: the 32-byte randomness commitment from the host (cannot be NULL)
*/
SECP256K1_API int secp256k1_ecdsa_anti_klepto_signer_commit(
const secp256k1_context* ctx,
secp256k1_ecdsa_s2c_opening* s2c_opening,
const unsigned char* msg32,
const unsigned char* seckey32,
const unsigned char* rand_commitment32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Same as secp256k1_ecdsa_sign, but commits to host randomness in the nonce. Part of the
* ECDSA Anti-Klepto Protocol.
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the private key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* host_data32: pointer to 32-byte host-provided randomness (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_anti_klepto_sign(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature* sig,
const unsigned char* msg32,
const unsigned char* seckey,
const unsigned char* host_data32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Verify a signature was correctly constructed using the ECDSA Anti-Klepto Protocol.
*
* Returns: 1: the signature is valid and contains a commitment to host_data32
* 0: incorrect opening
* Args: ctx: a secp256k1 context object, initialized for verification.
* In: sig: the signature produced by the signer (cannot be NULL)
* msghash32: the 32-byte message hash being verified (cannot be NULL)
* pubkey: pointer to the signer's public key (cannot be NULL)
* host_data32: the 32-byte data provided by the host (cannot be NULL)
* opening: the s2c opening provided by the signer (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_anti_klepto_host_verify(
const secp256k1_context* ctx,
const secp256k1_ecdsa_signature *sig,
const unsigned char *msg32,
const secp256k1_pubkey *pubkey,
const unsigned char *host_data32,
const secp256k1_ecdsa_s2c_opening *opening
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
#ifdef __cplusplus
}
#endif
#endif /* SECP256K1_ECDSA_S2C_H */

View File

@@ -1,236 +0,0 @@
#ifndef SECP256K1_EXTRAKEYS_H
#define SECP256K1_EXTRAKEYS_H
#include "secp256k1.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Opaque data structure that holds a parsed and valid "x-only" public key.
* An x-only pubkey encodes a point whose Y coordinate is even. It is
* serialized using only its X coordinate (32 bytes). See BIP-340 for more
* information about x-only pubkeys.
*
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use secp256k1_xonly_pubkey_serialize and
* secp256k1_xonly_pubkey_parse.
*/
typedef struct {
unsigned char data[64];
} secp256k1_xonly_pubkey;
/** Opaque data structure that holds a keypair consisting of a secret and a
* public key.
*
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is
* however guaranteed to be 96 bytes in size, and can be safely copied/moved.
*/
typedef struct {
unsigned char data[96];
} secp256k1_keypair;
/** Parse a 32-byte sequence into a xonly_pubkey object.
*
* Returns: 1 if the public key was fully valid.
* 0 if the public key could not be parsed or is invalid.
*
* Args: ctx: a secp256k1 context object (cannot be NULL).
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
* parsed version of input. If not, it's set to an invalid value.
* (cannot be NULL).
* In: input32: pointer to a serialized xonly_pubkey (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
const secp256k1_context* ctx,
secp256k1_xonly_pubkey* pubkey,
const unsigned char *input32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize an xonly_pubkey object into a 32-byte sequence.
*
* Returns: 1 always.
*
* Args: ctx: a secp256k1 context object (cannot be NULL).
* Out: output32: a pointer to a 32-byte array to place the serialized key in
* (cannot be NULL).
* In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an
* initialized public key (cannot be NULL).
*/
SECP256K1_API int secp256k1_xonly_pubkey_serialize(
const secp256k1_context* ctx,
unsigned char *output32,
const secp256k1_xonly_pubkey* pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
*
* Returns: 1 if the public key was successfully converted
* 0 otherwise
*
* Args: ctx: pointer to a context object (cannot be NULL)
* Out: xonly_pubkey: pointer to an x-only public key object for placing the
* converted public key (cannot be NULL)
* pk_parity: pointer to an integer that will be set to 1 if the point
* encoded by xonly_pubkey is the negation of the pubkey and
* set to 0 otherwise. (can be NULL)
* In: pubkey: pointer to a public key that is converted (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey(
const secp256k1_context* ctx,
secp256k1_xonly_pubkey *xonly_pubkey,
int *pk_parity,
const secp256k1_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
/** Tweak an x-only public key by adding the generator multiplied with tweak32
* to it.
*
* Note that the resulting point can not in general be represented by an x-only
* pubkey because it may have an odd Y coordinate. Instead, the output_pubkey
* is a normal secp256k1_pubkey.
*
* Returns: 0 if the arguments are invalid or the resulting public key would be
* invalid (only when the tweak is the negation of the corresponding
* secret key). 1 otherwise.
*
* Args: ctx: pointer to a context object initialized for verification
* (cannot be NULL)
* Out: output_pubkey: pointer to a public key to store the result. Will be set
* to an invalid value if this function returns 0 (cannot
* be NULL)
* In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to.
* (cannot be NULL).
* tweak32: pointer to a 32-byte tweak. If the tweak is invalid
* according to secp256k1_ec_seckey_verify, this function
* returns 0. For uniformly random 32-byte arrays the
* chance of being invalid is negligible (around 1 in
* 2^128) (cannot be NULL).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
const secp256k1_context* ctx,
secp256k1_pubkey *output_pubkey,
const secp256k1_xonly_pubkey *internal_pubkey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Checks that a tweaked pubkey is the result of calling
* secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32.
*
* The tweaked pubkey is represented by its 32-byte x-only serialization and
* its pk_parity, which can both be obtained by converting the result of
* tweak_add to a secp256k1_xonly_pubkey.
*
* Note that this alone does _not_ verify that the tweaked pubkey is a
* commitment. If the tweak is not chosen in a specific way, the tweaked pubkey
* can easily be the result of a different internal_pubkey and tweak.
*
* Returns: 0 if the arguments are invalid or the tweaked pubkey is not the
* result of tweaking the internal_pubkey with tweak32. 1 otherwise.
* Args: ctx: pointer to a context object initialized for verification
* (cannot be NULL)
* In: tweaked_pubkey32: pointer to a serialized xonly_pubkey (cannot be NULL)
* tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization
* is passed in as tweaked_pubkey32). This must match the
* pk_parity value that is returned when calling
* secp256k1_xonly_pubkey with the tweaked pubkey, or
* this function will fail.
* internal_pubkey: pointer to an x-only public key object to apply the
* tweak to (cannot be NULL)
* tweak32: pointer to a 32-byte tweak (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check(
const secp256k1_context* ctx,
const unsigned char *tweaked_pubkey32,
int tweaked_pk_parity,
const secp256k1_xonly_pubkey *internal_pubkey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Compute the keypair for a secret key.
*
* Returns: 1: secret was valid, keypair is ready to use
* 0: secret was invalid, try again with a different secret
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: keypair: pointer to the created keypair (cannot be NULL)
* In: seckey: pointer to a 32-byte secret key (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
const secp256k1_context* ctx,
secp256k1_keypair *keypair,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Get the public key from a keypair.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
* Args: ctx: pointer to a context object (cannot be NULL)
* 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.
* (cannot be NULL)
* In: keypair: pointer to a keypair (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
const secp256k1_context* ctx,
secp256k1_pubkey *pubkey,
const secp256k1_keypair *keypair
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Get the x-only public key from a keypair.
*
* 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.
* Args: ctx: pointer to a context object (cannot be NULL)
* 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
* xonly_pubkey. If not, it's set to an invalid value (cannot be
* NULL).
* pk_parity: pointer to an integer that will be set to the pk_parity
* argument of secp256k1_xonly_pubkey_from_pubkey (can be NULL).
* In: keypair: pointer to a keypair (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
const secp256k1_context* ctx,
secp256k1_xonly_pubkey *pubkey,
int *pk_parity,
const secp256k1_keypair *keypair
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
/** Tweak a keypair by adding tweak32 to the secret key and updating the public
* key accordingly.
*
* Calling this function and then secp256k1_keypair_pub results in the same
* public key as calling secp256k1_keypair_xonly_pub and then
* secp256k1_xonly_pubkey_tweak_add.
*
* Returns: 0 if the arguments are invalid or the resulting keypair would be
* invalid (only when the tweak is the negation of the keypair's
* secret key). 1 otherwise.
*
* Args: ctx: pointer to a context object initialized for verification
* (cannot be NULL)
* In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to
* an invalid value if this function returns 0 (cannot be
* NULL).
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according
* to secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128) (cannot be NULL).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add(
const secp256k1_context* ctx,
secp256k1_keypair *keypair,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
#ifdef __cplusplus
}
#endif
#endif /* SECP256K1_EXTRAKEYS_H */

View File

@@ -13,24 +13,27 @@ extern "C" {
*
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use secp256k1_generator_serialize and secp256k1_generator_parse.
* however guaranteed to be 33 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage or transmission, use
* the secp256k1_generator_serialize_*.
*
* Furthermore, it is guaranteed to identical points will have identical
* representation, so they can be memcmp'ed.
*/
typedef struct {
unsigned char data[64];
unsigned char data[33];
} secp256k1_generator;
/** Parse a 33-byte generator byte sequence into a generator object.
*
* Returns: 1 if input contains a valid generator.
* Args: ctx: a secp256k1 context object.
* Out: gen: pointer to the output generator object
* Out: commit: pointer to the output generator object
* In: input: pointer to a 33-byte serialized generator
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_parse(
const secp256k1_context* ctx,
secp256k1_generator* gen,
secp256k1_generator* commit,
const unsigned char *input
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -39,12 +42,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_parse(
* Returns: 1 always.
* Args: ctx: a secp256k1 context object.
* Out: output: a pointer to a 33-byte byte array
* In: gen: a pointer to a generator
* In: commit: a pointer to a generator
*/
SECP256K1_API int secp256k1_generator_serialize(
const secp256k1_context* ctx,
unsigned char *output,
const secp256k1_generator* gen
const secp256k1_generator* commit
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Generate a generator for the curve.
@@ -55,9 +58,9 @@ SECP256K1_API int secp256k1_generator_serialize(
* Out: gen: a generator object
* In: seed32: a 32-byte seed
*
* If successful a valid generator will be placed in gen. The produced
* If succesful, a valid generator will be placed in gen. The produced
* generators are distributed uniformly over the curve, and will not have a
* known discrete logarithm with respect to any other generator produced,
* known dicrete logarithm with respect to any other generator produced,
* or to the base generator G.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate(
@@ -70,7 +73,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate(
*
* Returns: 0 in the highly unlikely case the seed is not acceptable or when
* blind is out of range. 1 otherwise.
* Args: ctx: a secp256k1 context object, initialized for signing
* Args: ctx: a secp256k1 context object
* Out: gen: a generator object
* In: seed32: a 32-byte seed
* blind32: a 32-byte secret value to blind the generator with.

View File

@@ -1,488 +0,0 @@
#ifndef SECP256K1_MUSIG_H
#define SECP256K1_MUSIG_H
#include "secp256k1_extrakeys.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/** This module implements a Schnorr-based multi-signature scheme called MuSig
* (https://eprint.iacr.org/2018/068.pdf). It is compatible with bip-schnorr.
* There's an example C source file in the module's directory
* (src/modules/musig/example.c) that demonstrates how it can be used.
*
* The documentation in this include file is for reference and may not be sufficient
* for users to begin using the library. A full description of API usage can be found
* in src/modules/musig/musig.md
*/
/** Data structure containing auxiliary data generated in `pubkey_combine` and
* required for `session_*_init`.
* Fields:
* magic: Set during initialization in `pubkey_combine` to allow
* detecting an uninitialized object.
* pk_hash: The 32-byte hash of the original public keys
* pk_parity: Whether the MuSig-aggregated point was negated when
* converting it to the combined xonly pubkey.
* is_tweaked: Whether the combined pubkey was tweaked
* tweak: If is_tweaked, array with the 32-byte tweak
* internal_key_parity: If is_tweaked, the parity of the combined pubkey
* before tweaking
*/
typedef struct {
uint64_t magic;
unsigned char pk_hash[32];
int pk_parity;
int is_tweaked;
unsigned char tweak[32];
int internal_key_parity;
} secp256k1_musig_pre_session;
/** Data structure containing data related to a signing session resulting in a single
* signature.
*
* This structure is not opaque, but it MUST NOT be copied or read or written to it
* directly. A signer who is online throughout the whole process and can keep this
* structure in memory can use the provided API functions for a safe standard
* workflow. See https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/
* for more details about the risks associated with serializing or deserializing this
* structure.
*
* Fields:
* magic: Set in `musig_session_init` to allow detecting an
* uninitialized object.
* round: Current round of the session
* pre_session: Auxiliary data created in `pubkey_combine`
* combined_pk: MuSig-computed combined xonly public key
* n_signers: Number of signers
* msg: The 32-byte message (hash) to be signed
* is_msg_set: Whether the above message has been set
* has_secret_data: Whether this session object has a signers' secret data; if this
* is `false`, it may still be used for verification purposes.
* seckey: If `has_secret_data`, the signer's secret key
* secnonce: If `has_secret_data`, the signer's secret nonce
* nonce: If `has_secret_data`, the signer's public nonce
* nonce_commitments_hash: If `has_secret_data` and round >= 1, the hash of all
* signers' commitments
* combined_nonce: If round >= 2, the summed combined public nonce
* combined_nonce_parity: If round >= 2, the parity of the Y coordinate of above
* nonce.
*/
typedef struct {
uint64_t magic;
int round;
secp256k1_musig_pre_session pre_session;
secp256k1_xonly_pubkey combined_pk;
uint32_t n_signers;
int is_msg_set;
unsigned char msg[32];
int has_secret_data;
unsigned char seckey[32];
unsigned char secnonce[32];
secp256k1_xonly_pubkey nonce;
int partial_nonce_parity;
unsigned char nonce_commitments_hash[32];
secp256k1_xonly_pubkey combined_nonce;
int combined_nonce_parity;
} secp256k1_musig_session;
/** Data structure containing data on all signers in a single session.
*
* The workflow for this structure is as follows:
*
* 1. This structure is initialized with `musig_session_init` or
* `musig_session_init_verifier`, which set the `index` field, and zero out
* all other fields. The public session is initialized with the signers'
* nonce_commitments.
*
* 2. In a non-public session the nonce_commitments are set with the function
* `musig_get_public_nonce`, which also returns the signer's public nonce. This
* ensures that the public nonce is not exposed until all commitments have been
* received.
*
* 3. Each individual data struct should be updated with `musig_set_nonce` once a
* nonce is available. This function takes a single signer data struct rather than
* an array because it may fail in the case that the provided nonce does not match
* the commitment. In this case, it is desirable to identify the exact party whose
* nonce was inconsistent.
*
* Fields:
* present: indicates whether the signer's nonce is set
* index: index of the signer in the MuSig key aggregation
* nonce: public nonce, must be a valid curvepoint if the signer is `present`
* nonce_commitment: commitment to the nonce, or all-bits zero if a commitment
* has not yet been set
*/
typedef struct {
int present;
uint32_t index;
secp256k1_xonly_pubkey nonce;
unsigned char nonce_commitment[32];
} secp256k1_musig_session_signer_data;
/** Opaque data structure that holds a MuSig partial signature.
*
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is however
* guaranteed to be 32 bytes in size, and can be safely copied/moved. If you need
* to convert to a format suitable for storage, transmission, or comparison, use the
* `musig_partial_signature_serialize` and `musig_partial_signature_parse`
* functions.
*/
typedef struct {
unsigned char data[32];
} secp256k1_musig_partial_signature;
/** Computes a combined public key and the hash of the given public keys.
* Different orders of `pubkeys` result in different `combined_pk`s.
*
* Returns: 1 if the public keys were successfully combined, 0 otherwise
* Args: ctx: pointer to a context object initialized for verification
* (cannot be NULL)
* scratch: scratch space used to compute the combined pubkey by
* multiexponentiation. If NULL, an inefficient algorithm is used.
* Out: combined_pk: the MuSig-combined xonly public key (cannot be NULL)
* pre_session: if non-NULL, pointer to a musig_pre_session struct to be used in
* `musig_session_init` or `musig_pubkey_tweak_add`.
* In: pubkeys: input array of public keys to combine. The order is important;
* a different order will result in a different combined public
* key (cannot be NULL)
* n_pubkeys: length of pubkeys array. Must be greater than 0.
*/
SECP256K1_API int secp256k1_musig_pubkey_combine(
const secp256k1_context* ctx,
secp256k1_scratch_space *scratch,
secp256k1_xonly_pubkey *combined_pk,
secp256k1_musig_pre_session *pre_session,
const secp256k1_xonly_pubkey *pubkeys,
size_t n_pubkeys
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
/** Tweak an x-only public key by adding the generator multiplied with tweak32
* to it. The resulting output_pubkey with the given internal_pubkey and tweak
* passes `secp256k1_xonly_pubkey_tweak_test`.
*
* This function is only useful before initializing a signing session. If you
* are only computing a public key, but not intending to create a signature for
* it, you can just use `secp256k1_xonly_pubkey_tweak_add`. Can only be called
* once with a given pre_session.
*
* Returns: 0 if the arguments are invalid or the resulting public key would be
* invalid (only when the tweak is the negation of the corresponding
* secret key). 1 otherwise.
* Args: ctx: pointer to a context object initialized for verification
* (cannot be NULL)
* pre_session: pointer to a `musig_pre_session` struct initialized in
* `musig_pubkey_combine` (cannot be NULL)
* Out: output_pubkey: pointer to a public key to store the result. Will be set
* to an invalid value if this function returns 0 (cannot
* be NULL)
* In: internal_pubkey: pointer to the `combined_pk` from
* `musig_pubkey_combine` to which the tweak is applied.
* (cannot be NULL).
* tweak32: pointer to a 32-byte tweak. If the tweak is invalid
* according to secp256k1_ec_seckey_verify, this function
* returns 0. For uniformly random 32-byte arrays the
* chance of being invalid is negligible (around 1 in
* 2^128) (cannot be NULL).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_tweak_add(
const secp256k1_context* ctx,
secp256k1_musig_pre_session *pre_session,
secp256k1_pubkey *output_pubkey,
const secp256k1_xonly_pubkey *internal_pubkey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Initializes a signing session for a signer
*
* Returns: 1: session is successfully initialized
* 0: session could not be initialized: secret key or secret nonce overflow
* Args: ctx: pointer to a context object, initialized for signing (cannot
* be NULL)
* Out: session: the session structure to initialize (cannot be NULL)
* signers: an array of signers' data to be initialized. Array length must
* equal to `n_signers` (cannot be NULL)
* nonce_commitment32: filled with a 32-byte commitment to the generated nonce
* (cannot be NULL)
* In: session_id32: a *unique* 32-byte ID to assign to this session (cannot be
* NULL). If a non-unique session_id32 was given then a partial
* signature will LEAK THE SECRET KEY.
* msg32: the 32-byte message to be signed. Shouldn't be NULL unless you
* require sharing nonce commitments before the message is known
* because it reduces nonce misuse resistance. If NULL, must be
* set with `musig_session_get_public_nonce`.
* combined_pk: the combined xonly public key of all signers (cannot be NULL)
* pre_session: pointer to a musig_pre_session struct after initializing
* it with `musig_pubkey_combine` and optionally provided to
* `musig_pubkey_tweak_add` (cannot be NULL).
* n_signers: length of signers array. Number of signers participating in
* the MuSig. Must be greater than 0 and at most 2^32 - 1.
* my_index: index of this signer in the signers array. Must be less
* than `n_signers`.
* seckey: the signer's 32-byte secret key (cannot be NULL)
*/
SECP256K1_API int secp256k1_musig_session_init(
const secp256k1_context* ctx,
secp256k1_musig_session *session,
secp256k1_musig_session_signer_data *signers,
unsigned char *nonce_commitment32,
const unsigned char *session_id32,
const unsigned char *msg32,
const secp256k1_xonly_pubkey *combined_pk,
const secp256k1_musig_pre_session *pre_session,
size_t n_signers,
size_t my_index,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(11);
/** Gets the signer's public nonce given a list of all signers' data with
* commitments. Called by participating signers after
* `secp256k1_musig_session_init` and after all nonce commitments have
* been collected
*
* Returns: 1: public nonce is written in nonce
* 0: signer data is missing commitments or session isn't initialized
* for signing
* Args: ctx: pointer to a context object (cannot be NULL)
* session: the signing session to get the nonce from (cannot be NULL)
* signers: an array of signers' data initialized with
* `musig_session_init`. Array length must equal to
* `n_commitments` (cannot be NULL)
* Out: nonce32: filled with a 32-byte public nonce which is supposed to be
* sent to the other signers and then used in `musig_set nonce`
* (cannot be NULL)
* In: commitments: array of pointers to 32-byte nonce commitments (cannot be NULL)
* n_commitments: the length of commitments and signers array. Must be the total
* number of signers participating in the MuSig.
* msg32: the 32-byte message to be signed. Must be NULL if already
* set with `musig_session_init` otherwise can not be NULL.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_public_nonce(
const secp256k1_context* ctx,
secp256k1_musig_session *session,
secp256k1_musig_session_signer_data *signers,
unsigned char *nonce32,
const unsigned char *const *commitments,
size_t n_commitments,
const unsigned char *msg32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Initializes a verifier session that can be used for verifying nonce commitments
* and partial signatures. It does not have secret key material and therefore can not
* be used to create signatures.
*
* Returns: 1 when session is successfully initialized, 0 otherwise
* Args: ctx: pointer to a context object (cannot be NULL)
* Out: session: the session structure to initialize (cannot be NULL)
* signers: an array of signers' data to be initialized. Array length must
* equal to `n_signers`(cannot be NULL)
* In: msg32: the 32-byte message to be signed (cannot be NULL)
* combined_pk: the combined xonly public key of all signers (cannot be NULL)
* pre_session: pointer to a musig_pre_session struct from
* `musig_pubkey_combine` (cannot be NULL)
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be NULL)
* commitments: array of pointers to 32-byte nonce commitments. Array
* length must equal to `n_signers` (cannot be NULL)
* n_signers: length of signers and commitments array. Number of signers
* participating in the MuSig. Must be greater than 0 and at most
* 2^32 - 1.
*/
SECP256K1_API int secp256k1_musig_session_init_verifier(
const secp256k1_context* ctx,
secp256k1_musig_session *session,
secp256k1_musig_session_signer_data *signers,
const unsigned char *msg32,
const secp256k1_xonly_pubkey *combined_pk,
const secp256k1_musig_pre_session *pre_session,
const unsigned char *const *commitments,
size_t n_signers
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
/** Checks a signer's public nonce against a commitment to said nonce, and update
* data structure if they match
*
* Returns: 1: commitment was valid, data structure updated
* 0: commitment was invalid, nothing happened
* Args: ctx: pointer to a context object (cannot be NULL)
* signer: pointer to the signer data to update (cannot be NULL). Must have
* been used with `musig_session_get_public_nonce` or initialized
* with `musig_session_init_verifier`.
* In: nonce32: signer's alleged public nonce (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_set_nonce(
const secp256k1_context* ctx,
secp256k1_musig_session_signer_data *signer,
const unsigned char *nonce32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Updates a session with the combined public nonce of all signers. The combined
* public nonce is the sum of every signer's public nonce.
*
* Returns: 1: nonces are successfully combined
* 0: a signer's nonce is missing
* Args: ctx: pointer to a context object (cannot be NULL)
* session: session to update with the combined public nonce (cannot be
* NULL)
* signers: an array of signers' data, which must have had public nonces
* set with `musig_set_nonce`. Array length must equal to `n_signers`
* (cannot be NULL)
* n_signers: the length of the signers array. Must be the total number of
* signers participating in the MuSig.
* Out: nonce_parity: if non-NULL, a pointer to an integer that indicates the
* parity of the combined public nonce. Used for adaptor
* signatures.
* adaptor: point to add to the combined public nonce. If NULL, nothing is
* added to the combined nonce.
*/
SECP256K1_API int secp256k1_musig_session_combine_nonces(
const secp256k1_context* ctx,
secp256k1_musig_session *session,
const secp256k1_musig_session_signer_data *signers,
size_t n_signers,
int *nonce_parity,
const secp256k1_pubkey *adaptor
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize a MuSig partial signature or adaptor signature
*
* Returns: 1 when the signature could be serialized, 0 otherwise
* Args: ctx: a secp256k1 context object
* Out: out32: pointer to a 32-byte array to store the serialized signature
* In: sig: pointer to the signature
*/
SECP256K1_API int secp256k1_musig_partial_signature_serialize(
const secp256k1_context* ctx,
unsigned char *out32,
const secp256k1_musig_partial_signature* sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Parse and verify a MuSig partial signature.
*
* Returns: 1 when the signature could be parsed, 0 otherwise.
* Args: ctx: a secp256k1 context object
* Out: sig: pointer to a signature object
* In: in32: pointer to the 32-byte signature to be parsed
*
* After the call, sig will always be initialized. If parsing failed or the
* encoded numbers are out of range, signature verification with it is
* guaranteed to fail for every message and public key.
*/
SECP256K1_API int secp256k1_musig_partial_signature_parse(
const secp256k1_context* ctx,
secp256k1_musig_partial_signature* sig,
const unsigned char *in32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Produces a partial signature
*
* Returns: 1: partial signature constructed
* 0: session in incorrect or inconsistent state
* Args: ctx: pointer to a context object (cannot be NULL)
* session: active signing session for which the combined nonce has been
* computed (cannot be NULL)
* Out: partial_sig: partial signature (cannot be NULL)
*/
SECP256K1_API int secp256k1_musig_partial_sign(
const secp256k1_context* ctx,
const secp256k1_musig_session *session,
secp256k1_musig_partial_signature *partial_sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Checks that an individual partial signature verifies
*
* This function is essential when using protocols with adaptor signatures.
* However, it is not essential for regular MuSig's, in the sense that if any
* partial signatures does not verify, the full signature will also not verify, so the
* problem will be caught. But this function allows determining the specific party
* who produced an invalid signature, so that signing can be restarted without them.
*
* Returns: 1: partial signature verifies
* 0: invalid signature or bad data
* Args: ctx: pointer to a context object (cannot be NULL)
* session: active session for which the combined nonce has been computed
* (cannot be NULL)
* signer: data for the signer who produced this signature (cannot be NULL)
* In: partial_sig: signature to verify (cannot be NULL)
* pubkey: public key of the signer who produced the signature (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify(
const secp256k1_context* ctx,
const secp256k1_musig_session *session,
const secp256k1_musig_session_signer_data *signer,
const secp256k1_musig_partial_signature *partial_sig,
const secp256k1_xonly_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Combines partial signatures
*
* Returns: 1: all partial signatures have values in range. Does NOT mean the
* resulting signature verifies.
* 0: some partial signature are missing or had s or r out of range
* Args: ctx: pointer to a context object (cannot be NULL)
* session: initialized session for which the combined nonce has been
* computed (cannot be NULL)
* Out: sig64: complete signature (cannot be NULL)
* In: partial_sigs: array of partial signatures to combine (cannot be NULL)
* n_sigs: number of signatures in the partial_sigs array
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combine(
const secp256k1_context* ctx,
const secp256k1_musig_session *session,
unsigned char *sig64,
const secp256k1_musig_partial_signature *partial_sigs,
size_t n_sigs
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Converts a partial signature to an adaptor signature by adding a given secret
* adaptor.
*
* Returns: 1: signature and secret adaptor contained valid values
* 0: otherwise
* Args: ctx: pointer to a context object (cannot be NULL)
* Out: adaptor_sig: adaptor signature to produce (cannot be NULL)
* In: partial_sig: partial signature to tweak with secret adaptor (cannot be NULL)
* sec_adaptor32: 32-byte secret adaptor to add to the partial signature (cannot
* be NULL)
* nonce_parity: the `nonce_parity` output of `musig_session_combine_nonces`
*/
SECP256K1_API int secp256k1_musig_partial_sig_adapt(
const secp256k1_context* ctx,
secp256k1_musig_partial_signature *adaptor_sig,
const secp256k1_musig_partial_signature *partial_sig,
const unsigned char *sec_adaptor32,
int nonce_parity
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Extracts a secret adaptor from a MuSig, given all parties' partial
* signatures. This function will not fail unless given grossly invalid data; if it
* is merely given signatures that do not verify, the returned value will be
* nonsense. It is therefore important that all data be verified at earlier steps of
* any protocol that uses this function.
*
* Returns: 1: signatures contained valid data such that an adaptor could be extracted
* 0: otherwise
* Args: ctx: pointer to a context object (cannot be NULL)
* Out:sec_adaptor32: 32-byte secret adaptor (cannot be NULL)
* In: sig64: complete 2-of-2 signature (cannot be NULL)
* partial_sigs: array of partial signatures (cannot be NULL)
* n_partial_sigs: number of elements in partial_sigs array
* nonce_parity: the `nonce_parity` output of `musig_session_combine_nonces`
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_adaptor(
const secp256k1_context* ctx,
unsigned char *sec_adaptor32,
const unsigned char *sig64,
const secp256k1_musig_partial_signature *partial_sigs,
size_t n_partial_sigs,
int nonce_parity
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,128 +0,0 @@
#ifndef SECP256K1_PREALLOCATED_H
#define SECP256K1_PREALLOCATED_H
#include "secp256k1.h"
#ifdef __cplusplus
extern "C" {
#endif
/* The module provided by this header file is intended for settings in which it
* is not possible or desirable to rely on dynamic memory allocation. It provides
* functions for creating, cloning, and destroying secp256k1 context objects in a
* contiguous fixed-size block of memory provided by the caller.
*
* Context objects created by functions in this module can be used like contexts
* objects created by functions in secp256k1.h, i.e., they can be passed to any
* API function that expects a context object (see secp256k1.h for details). The
* only exception is that context objects created by functions in this module
* must be destroyed using secp256k1_context_preallocated_destroy (in this
* module) instead of secp256k1_context_destroy (in secp256k1.h).
*
* It is guaranteed that functions in this module will not call malloc or its
* friends realloc, calloc, and free.
*/
/** Determine the memory size of a secp256k1 context object to be created in
* caller-provided memory.
*
* The purpose of this function is to determine how much memory must be provided
* to secp256k1_context_preallocated_create.
*
* Returns: the required size of the caller-provided memory block
* In: flags: which parts of the context to initialize.
*/
SECP256K1_API size_t secp256k1_context_preallocated_size(
unsigned int flags
) SECP256K1_WARN_UNUSED_RESULT;
/** Create a secp256k1 context object in caller-provided memory.
*
* The caller must provide a pointer to a rewritable contiguous block of memory
* of size at least secp256k1_context_preallocated_size(flags) bytes, suitably
* aligned to hold an object of any type.
*
* The block of memory is exclusively owned by the created context object during
* the lifetime of this context object, which begins with the call to this
* function and ends when a call to secp256k1_context_preallocated_destroy
* (which destroys the context object again) returns. During the lifetime of the
* context object, the caller is obligated not to access this block of memory,
* i.e., the caller may not read or write the memory, e.g., by copying the memory
* contents to a different location or trying to create a second context object
* in the memory. In simpler words, the prealloc pointer (or any pointer derived
* from it) should not be used during the lifetime of the context object.
*
* Returns: a newly created context object.
* In: prealloc: a pointer to a rewritable contiguous block of memory of
* size at least secp256k1_context_preallocated_size(flags)
* bytes, as detailed above (cannot be NULL)
* flags: which parts of the context to initialize.
*
* See also secp256k1_context_randomize (in secp256k1.h)
* and secp256k1_context_preallocated_destroy.
*/
SECP256K1_API secp256k1_context* secp256k1_context_preallocated_create(
void* prealloc,
unsigned int flags
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
/** Determine the memory size of a secp256k1 context object to be copied into
* caller-provided memory.
*
* Returns: the required size of the caller-provided memory block.
* In: ctx: an existing context to copy (cannot be NULL)
*/
SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
const secp256k1_context* ctx
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
/** Copy a secp256k1 context object into caller-provided memory.
*
* The caller must provide a pointer to a rewritable contiguous block of memory
* of size at least secp256k1_context_preallocated_size(flags) bytes, suitably
* aligned to hold an object of any type.
*
* The block of memory is exclusively owned by the created context object during
* the lifetime of this context object, see the description of
* secp256k1_context_preallocated_create for details.
*
* Returns: a newly created context object.
* Args: ctx: an existing context to copy (cannot be NULL)
* In: prealloc: a pointer to a rewritable contiguous block of memory of
* size at least secp256k1_context_preallocated_size(flags)
* bytes, as detailed above (cannot be NULL)
*/
SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone(
const secp256k1_context* ctx,
void* prealloc
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT;
/** Destroy a secp256k1 context object that has been created in
* caller-provided memory.
*
* The context pointer may not be used afterwards.
*
* The context to destroy must have been created using
* secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone.
* If the context has instead been created using secp256k1_context_create or
* secp256k1_context_clone, the behaviour is undefined. In that case,
* secp256k1_context_destroy must be used instead.
*
* If required, it is the responsibility of the caller to deallocate the block
* of memory properly after this function returns, e.g., by calling free on the
* preallocated pointer given to secp256k1_context_preallocated_create or
* secp256k1_context_preallocated_clone.
*
* Args: ctx: an existing context to destroy, constructed using
* secp256k1_context_preallocated_create or
* secp256k1_context_preallocated_clone (cannot be NULL)
*/
SECP256K1_API void secp256k1_context_preallocated_destroy(
secp256k1_context* ctx
);
#ifdef __cplusplus
}
#endif
#endif /* SECP256K1_PREALLOCATED_H */

View File

@@ -14,19 +14,21 @@ extern "C" {
*
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use secp256k1_pedersen_commitment_serialize and
* secp256k1_pedersen_commitment_parse.
* however guaranteed to be 33 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage or transmission, use
* secp256k1_pedersen_commitment_serialize and secp256k1_pedersen_commitment_parse.
*
* Furthermore, it is guaranteed to identical signatures will have identical
* representation, so they can be memcmp'ed.
*/
typedef struct {
unsigned char data[64];
unsigned char data[33];
} secp256k1_pedersen_commitment;
/**
* Static constant generator 'h' maintained for historical reasons.
*/
SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h;
extern const secp256k1_generator *secp256k1_generator_h;
/** Parse a 33-byte commitment into a commitment object.
*
@@ -55,6 +57,9 @@ SECP256K1_API int secp256k1_pedersen_commitment_serialize(
const secp256k1_pedersen_commitment* commit
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Initialize a context for usage with Pedersen commitments. */
void secp256k1_pedersen_context_initialize(secp256k1_context* ctx);
/** Generate a pedersen commitment.
* Returns 1: Commitment successfully created.
* 0: Error. The blinding factor is larger than the group order
@@ -158,6 +163,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generato
size_t n_inputs
);
/** Initialize a context for usage with Pedersen commitments. */
void secp256k1_rangeproof_context_initialize(secp256k1_context* ctx);
/** Verify a proof that a committed value is within a range.
* Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs.
* 0: Proof failed or other error.
@@ -197,9 +205,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
* In/Out: blind_out: storage for the 32-byte blinding factor used for the commitment
* value_out: pointer to an unsigned int64 which has the exact value of the commitment.
* message_out: pointer to a 4096 byte character array to receive message data from the proof author.
* outlen: length of message data written to message_out. This is generally not equal to the
* msg_len used by the signer. However, for all i with msg_len <= i < outlen, it is
* guaranteed that message_out[i] == 0.
* outlen: length of message data written to message_out.
* min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
* max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
*/

View File

@@ -1,11 +1,11 @@
#ifndef SECP256K1_RECOVERY_H
#define SECP256K1_RECOVERY_H
#ifndef _SECP256K1_RECOVERY_
# define _SECP256K1_RECOVERY_
#include "secp256k1.h"
# include "secp256k1.h"
#ifdef __cplusplus
# ifdef __cplusplus
extern "C" {
#endif
# endif
/** Opaque data structured that holds a parsed ECDSA signature,
* supporting pubkey recovery.
@@ -70,7 +70,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
/** Create a recoverable ECDSA signature.
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the secret key was invalid.
* 0: the nonce generation function failed, or the private key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
@@ -103,8 +103,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
const unsigned char *msg32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
#ifdef __cplusplus
# ifdef __cplusplus
}
#endif
# endif
#endif /* SECP256K1_RECOVERY_H */
#endif

View File

@@ -1,111 +0,0 @@
#ifndef SECP256K1_SCHNORRSIG_H
#define SECP256K1_SCHNORRSIG_H
#include "secp256k1.h"
#include "secp256k1_extrakeys.h"
#ifdef __cplusplus
extern "C" {
#endif
/** This module implements a variant of Schnorr signatures compliant with
* Bitcoin Improvement Proposal 340 "Schnorr Signatures for secp256k1"
* (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
*/
/** A pointer to a function to deterministically generate a nonce.
*
* Same as secp256k1_nonce function with the exception of accepting an
* additional pubkey argument and not requiring an attempt argument. The pubkey
* argument can protect signature schemes with key-prefixed challenge hash
* inputs against reusing the nonce when signing with the wrong precomputed
* pubkey.
*
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to
* return an error.
* Out: nonce32: pointer to a 32-byte array to be filled by the function.
* In: msg32: the 32-byte message hash being verified (will not be NULL)
* key32: pointer to a 32-byte secret key (will not be NULL)
* xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32
* (will not be NULL)
* algo16: pointer to a 16-byte array describing the signature
* algorithm (will not be NULL).
* data: Arbitrary data pointer that is passed through.
*
* Except for test cases, this function should compute some cryptographic hash of
* the message, the key, the pubkey, the algorithm description, and data.
*/
typedef int (*secp256k1_nonce_function_hardened)(
unsigned char *nonce32,
const unsigned char *msg32,
const unsigned char *key32,
const unsigned char *xonly_pk32,
const unsigned char *algo16,
void *data
);
/** An implementation of the nonce generation function as defined in Bitcoin
* Improvement Proposal 340 "Schnorr Signatures for secp256k1"
* (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
*
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
* auxiliary random data as defined in BIP-340. If the data pointer is NULL,
* schnorrsig_sign does not produce BIP-340 compliant signatures. The algo16
* argument must be non-NULL, otherwise the function will fail and return 0.
* The hash will be tagged with algo16 after removing all terminating null
* bytes. Therefore, to create BIP-340 compliant signatures, algo16 must be set
* to "BIP0340/nonce\0\0\0"
*/
SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
/** Create a Schnorr signature.
*
* Does _not_ strictly follow BIP-340 because it does not verify the resulting
* signature. Instead, you can manually use secp256k1_schnorrsig_verify and
* abort if it fails.
*
* Otherwise BIP-340 compliant if the noncefp argument is NULL or
* secp256k1_nonce_function_bip340 and the ndata argument is 32-byte auxiliary
* randomness.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig64: pointer to a 64-byte array to store the serialized signature (cannot be NULL)
* In: msg32: the 32-byte message being signed (cannot be NULL)
* keypair: pointer to an initialized keypair (cannot be NULL)
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bip340 is used
* ndata: pointer to arbitrary data used by the nonce generation
* function (can be NULL). If it is non-NULL and
* secp256k1_nonce_function_bip340 is used, then ndata must be a
* pointer to 32-byte auxiliary randomness as per BIP-340.
*/
SECP256K1_API int secp256k1_schnorrsig_sign(
const secp256k1_context* ctx,
unsigned char *sig64,
const unsigned char *msg32,
const secp256k1_keypair *keypair,
secp256k1_nonce_function_hardened noncefp,
void *ndata
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Verify a Schnorr signature.
*
* Returns: 1: correct signature
* 0: incorrect signature
* Args: ctx: a secp256k1 context object, initialized for verification.
* In: sig64: pointer to the 64-byte signature to verify (cannot be NULL)
* msg32: the 32-byte message being verified (cannot be NULL)
* pubkey: pointer to an x-only public key to verify with (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
const secp256k1_context* ctx,
const unsigned char *sig64,
const unsigned char *msg32,
const secp256k1_xonly_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
#ifdef __cplusplus
}
#endif
#endif /* SECP256K1_SCHNORRSIG_H */

View File

@@ -11,9 +11,6 @@ extern "C" {
/** Maximum number of inputs that may be given in a surjection proof */
#define SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS 256
/** Maximum number of inputs that may be used in a surjection proof */
#define SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS 256
/** Number of bytes a serialized surjection proof requires given the
* number of inputs and the number of used inputs.
*/
@@ -22,7 +19,7 @@ extern "C" {
/** Maximum number of bytes a serialized surjection proof requires. */
#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX \
SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS)
SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)
/** Opaque data structure that holds a parsed surjection proof
*
@@ -49,10 +46,9 @@ typedef struct {
/** Bitmap of which input tags are used in the surjection proof */
unsigned char used_inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8];
/** Borromean signature: e0, scalars */
unsigned char data[32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS)];
unsigned char data[32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)];
} secp256k1_surjectionproof;
#ifndef USE_REDUCED_SURJECTION_PROOF_SIZE
/** Parse a surjection proof
*
* Returns: 1 when the proof could be parsed, 0 otherwise.
@@ -74,7 +70,6 @@ SECP256K1_API int secp256k1_surjectionproof_parse(
const unsigned char *input,
size_t inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
#endif
/** Serialize a surjection proof
*
@@ -139,7 +134,6 @@ SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Surjection proof initialization function; decides on inputs to use
* To be used to initialize stack-allocated secp256k1_surjectionproof struct
* Returns 0: inputs could not be selected
* n: inputs were selected after n iterations of random selection
*
@@ -148,14 +142,9 @@ SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(
* e.g. in a coinjoin with others' inputs, an ephemeral tag can be given;
* this won't match the output tag but might be used in the anonymity set.)
* n_input_tags: the number of entries in the fixed_input_tags array
* n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set
* Must be <= SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS
* n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set
* fixed_output_tag: fixed output tag
* max_n_iterations: the maximum number of iterations to do before giving up. Because the
* maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is
* limited to 256 the probability of giving up is smaller than
* (255/256)^(n_input_tags_to_use*max_n_iterations).
*
* max_n_iterations: the maximum number of iterations to do before giving up
* random_seed32: a random seed to be used for input selection
* Out: proof: The proof whose bitvector will be initialized. In case of failure,
* the state of the proof is undefined.
@@ -173,51 +162,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_initial
const unsigned char *random_seed32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7);
/** Surjection proof allocation and initialization function; decides on inputs to use
* Returns 0: inputs could not be selected, or malloc failure
* n: inputs were selected after n iterations of random selection
*
* In: ctx: pointer to a context object
* proof_out_p: a pointer to a pointer to `secp256k1_surjectionproof*`.
* the newly-allocated struct pointer will be saved here.
* fixed_input_tags: fixed input tags `A_i` for all inputs. (If the fixed tag is not known,
* e.g. in a coinjoin with others' inputs, an ephemeral tag can be given;
* this won't match the output tag but might be used in the anonymity set.)
* n_input_tags: the number of entries in the fixed_input_tags array
* n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set
* fixed_output_tag: fixed output tag
* max_n_iterations: the maximum number of iterations to do before giving up. Because the
* maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is
* limited to 256 the probability of giving up is smaller than
* (255/256)^(n_input_tags_to_use*max_n_iterations).
*
* random_seed32: a random seed to be used for input selection
* Out: proof_out_p: The pointer to newly-allocated proof whose bitvector will be initialized.
* In case of failure, the pointer will be NULL.
* input_index: The index of the actual input that is secretly mapped to the output
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_allocate_initialized(
const secp256k1_context* ctx,
secp256k1_surjectionproof** proof_out_p,
size_t *input_index,
const secp256k1_fixed_asset_tag* fixed_input_tags,
const size_t n_input_tags,
const size_t n_input_tags_to_use,
const secp256k1_fixed_asset_tag* fixed_output_tag,
const size_t n_max_iterations,
const unsigned char *random_seed32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7);
/** Surjection proof destroy function
* deallocates the struct that was allocated with secp256k1_surjectionproof_allocate_initialized
*
* In: proof: pointer to secp256k1_surjectionproof struct
*/
SECP256K1_API void secp256k1_surjectionproof_destroy(
secp256k1_surjectionproof* proof
) SECP256K1_ARG_NONNULL(1);
/** Surjection proof generation function
* Returns 0: proof could not be created
* 1: proof was successfully created
@@ -243,7 +187,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_generat
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
#ifndef USE_REDUCED_SURJECTION_PROOF_SIZE
/** Surjection proof verification function
* Returns 0: proof was invalid
* 1: proof was valid
@@ -261,7 +204,6 @@ SECP256K1_API int secp256k1_surjectionproof_verify(
size_t n_ephemeral_input_tags,
const secp256k1_generator* ephemeral_output_tag
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
#endif
#ifdef __cplusplus
}

View File

@@ -8,6 +8,6 @@ Description: Optimized C library for EC operations on curve secp256k1
URL: https://github.com/bitcoin-core/secp256k1
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -lsecp256k1
Libs.private: @SECP_LIBS@
Libs: -L${libdir} -lsecp256k1

View File

@@ -1,129 +0,0 @@
# Define field size and field
P = 2^256 - 2^32 - 977
F = GF(P)
BETA = F(0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee)
assert(BETA != F(1) and BETA^3 == F(1))
orders_done = set()
results = {}
first = True
for b in range(1, P):
# There are only 6 curves (up to isomorphism) of the form y^2=x^3+B. Stop once we have tried all.
if len(orders_done) == 6:
break
E = EllipticCurve(F, [0, b])
print("Analyzing curve y^2 = x^3 + %i" % b)
n = E.order()
# Skip curves with an order we've already tried
if n in orders_done:
print("- Isomorphic to earlier curve")
continue
orders_done.add(n)
# Skip curves isomorphic to the real secp256k1
if n.is_pseudoprime():
print(" - Isomorphic to secp256k1")
continue
print("- Finding subgroups")
# Find what prime subgroups exist
for f, _ in n.factor():
print("- Analyzing subgroup of order %i" % f)
# Skip subgroups of order >1000
if f < 4 or f > 1000:
print(" - Bad size")
continue
# Iterate over X coordinates until we find one that is on the curve, has order f,
# and for which curve isomorphism exists that maps it to X coordinate 1.
for x in range(1, P):
# Skip X coordinates not on the curve, and construct the full point otherwise.
if not E.is_x_coord(x):
continue
G = E.lift_x(F(x))
print(" - Analyzing (multiples of) point with X=%i" % x)
# Skip points whose order is not a multiple of f. Project the point to have
# order f otherwise.
if (G.order() % f):
print(" - Bad order")
continue
G = G * (G.order() // f)
# Find lambda for endomorphism. Skip if none can be found.
lam = None
for l in Integers(f)(1).nth_root(3, all=True):
if int(l)*G == E(BETA*G[0], G[1]):
lam = int(l)
break
if lam is None:
print(" - No endomorphism for this subgroup")
break
# Now look for an isomorphism of the curve that gives this point an X
# coordinate equal to 1.
# If (x,y) is on y^2 = x^3 + b, then (a^2*x, a^3*y) is on y^2 = x^3 + a^6*b.
# So look for m=a^2=1/x.
m = F(1)/G[0]
if not m.is_square():
print(" - No curve isomorphism maps it to a point with X=1")
continue
a = m.sqrt()
rb = a^6*b
RE = EllipticCurve(F, [0, rb])
# Use as generator twice the image of G under the above isormorphism.
# This means that generator*(1/2 mod f) will have X coordinate 1.
RG = RE(1, a^3*G[1]) * 2
# And even Y coordinate.
if int(RG[1]) % 2:
RG = -RG
assert(RG.order() == f)
assert(lam*RG == RE(BETA*RG[0], RG[1]))
# We have found curve RE:y^2=x^3+rb with generator RG of order f. Remember it
results[f] = {"b": rb, "G": RG, "lambda": lam}
print(" - Found solution")
break
print("")
print("")
print("")
print("/* To be put in src/group_impl.h: */")
first = True
for f in sorted(results.keys()):
b = results[f]["b"]
G = results[f]["G"]
print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f))
first = False
print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(")
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
print(");")
print("static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(")
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
print(");")
print("# else")
print("# error No known generator for the specified exhaustive test group order.")
print("# endif")
print("")
print("")
print("/* To be put in src/scalar_impl.h: */")
first = True
for f in sorted(results.keys()):
lam = results[f]["lambda"]
print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f))
first = False
print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam)
print("# else")
print("# error No known lambda for the specified exhaustive test group order.")
print("# endif")
print("")

View File

@@ -3,7 +3,7 @@
# to independently set assumptions on input or intermediary variables.
#
# The general approach is:
# * A constraint is a tuple of two sets of symbolic expressions:
# * A constraint is a tuple of two sets of of symbolic expressions:
# the first of which are required to evaluate to zero, the second of which
# are required to evaluate to nonzero.
# - A constraint is said to be conflicting if any of its nonzero expressions
@@ -17,7 +17,7 @@
# - A constraint describing the requirements of the law, called "require"
# * Implementations are transliterated into functions that operate as well on
# algebraic input points, and are called once per combination of branches
# executed. Each execution returns:
# exectured. Each execution returns:
# - A constraint describing the assumptions this implementation requires
# (such as Z1=1), called "assumeFormula"
# - A constraint describing the assumptions this specific branch requires,
@@ -65,7 +65,7 @@ class fastfrac:
return self.top in I and self.bot not in I
def reduce(self,assumeZero):
zero = self.R.ideal(list(map(numerator, assumeZero)))
zero = self.R.ideal(map(numerator, assumeZero))
return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot))
def __add__(self,other):
@@ -100,7 +100,7 @@ class fastfrac:
"""Multiply something else with a fraction."""
return self.__mul__(other)
def __truediv__(self,other):
def __div__(self,other):
"""Divide two fractions."""
if parent(other) == ZZ:
return fastfrac(self.R,self.top,self.bot * other)
@@ -108,11 +108,6 @@ class fastfrac:
return fastfrac(self.R,self.top * other.bot,self.bot * other.top)
return NotImplemented
# Compatibility wrapper for Sage versions based on Python 2
def __div__(self,other):
"""Divide two fractions."""
return self.__truediv__(other)
def __pow__(self,other):
"""Compute a power of a fraction."""
if parent(other) == ZZ:
@@ -180,7 +175,7 @@ class constraints:
def conflicts(R, con):
"""Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
zero = R.ideal(list(map(numerator, con.zero)))
zero = R.ideal(map(numerator, con.zero))
if 1 in zero:
return True
# First a cheap check whether any of the individual nonzero terms conflict on
@@ -200,7 +195,7 @@ def conflicts(R, con):
def get_nonzero_set(R, assume):
"""Calculate a simple set of nonzero expressions"""
zero = R.ideal(list(map(numerator, assume.zero)))
zero = R.ideal(map(numerator, assume.zero))
nonzero = set()
for nz in map(numerator, assume.nonzero):
for (f,n) in nz.factor():
@@ -213,7 +208,7 @@ def get_nonzero_set(R, assume):
def prove_nonzero(R, exprs, assume):
"""Check whether an expression is provably nonzero, given assumptions"""
zero = R.ideal(list(map(numerator, assume.zero)))
zero = R.ideal(map(numerator, assume.zero))
nonzero = get_nonzero_set(R, assume)
expl = set()
ok = True
@@ -255,7 +250,7 @@ def prove_zero(R, exprs, assume):
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))
zero = R.ideal(list(map(numerator, assume.zero)))
zero = R.ideal(map(numerator, assume.zero))
nonzero = prod(x for x in assume.nonzero)
expl = []
for expr in exprs:
@@ -270,8 +265,8 @@ def describe_extra(R, assume, assumeExtra):
"""Describe what assumptions are added, given existing assumptions"""
zerox = assume.zero.copy()
zerox.update(assumeExtra.zero)
zero = R.ideal(list(map(numerator, assume.zero)))
zeroextra = R.ideal(list(map(numerator, zerox)))
zero = R.ideal(map(numerator, assume.zero))
zeroextra = R.ideal(map(numerator, zerox))
nonzero = get_nonzero_set(R, assume)
ret = set()
# Iterate over the extra zero expressions

View File

@@ -175,24 +175,24 @@ laws_jacobian_weierstrass = {
def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
"""Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field"""
F = Integers(p)
print("Formula %s on Z%i:" % (name, p))
print "Formula %s on Z%i:" % (name, p)
points = []
for x in range(0, p):
for y in range(0, p):
for x in xrange(0, p):
for y in xrange(0, p):
point = affinepoint(F(x), F(y))
r, e = concrete_verify(on_weierstrass_curve(A, B, point))
if r:
points.append(point)
for za in range(1, p):
for zb in range(1, p):
for za in xrange(1, p):
for zb in xrange(1, p):
for pa in points:
for pb in points:
for ia in range(2):
for ib in range(2):
for ia in xrange(2):
for ib in xrange(2):
pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia)
pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib)
for branch in range(0, branches):
for branch in xrange(0, branches):
assumeAssert, assumeBranch, pC = formula(branch, pA, pB)
pC.X = F(pC.X)
pC.Y = F(pC.Y)
@@ -206,13 +206,13 @@ def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
r, e = concrete_verify(assumeLaw)
if r:
if match:
print(" multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity))
print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity)
else:
match = True
r, e = concrete_verify(require)
if not r:
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()
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
def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
@@ -242,9 +242,9 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
for key in laws_jacobian_weierstrass:
res[key] = []
print("Formula " + name + ":")
print ("Formula " + name + ":")
count = 0
for branch in range(branches):
for branch in xrange(branches):
assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
pC.X = lift(pC.X)
pC.Y = lift(pC.Y)
@@ -255,10 +255,10 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))
for key in res:
print(" %s:" % key)
print " %s:" % key
val = res[key]
for x in val:
if x[0] is not None:
print(" branch %i: %s" % (x[1], x[0]))
print " branch %i: %s" % (x[1], x[0])
print()
print

View File

@@ -11,14 +11,20 @@ Note:
- To avoid unnecessary loads and make use of available registers, two
'passes' have every time been interleaved, with the odd passes accumulating c' and d'
which will be added to c and d respectively in the even passes
which will be added to c and d respectively in the the even passes
*/
.syntax unified
.arch armv7-a
@ eabi attributes - see readelf -A
.eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes
.eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no
.eabi_attribute 10, 0 @ Tag_FP_arch = none
.eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte
.eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP
.eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed
.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6
.text
@ Field constants

View File

@@ -1,80 +0,0 @@
/**********************************************************************
* Copyright (c) 2020 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ASSUMPTIONS_H
#define SECP256K1_ASSUMPTIONS_H
#include <limits.h>
#include "util.h"
/* This library, like most software, relies on a number of compiler implementation defined (but not undefined)
behaviours. Although the behaviours we require are essentially universal we test them specifically here to
reduce the odds of experiencing an unwelcome surprise.
*/
struct secp256k1_assumption_checker {
/* This uses a trick to implement a static assertion in C89: a type with an array of negative size is not
allowed. */
int dummy_array[(
/* Bytes are 8 bits. */
(CHAR_BIT == 8) &&
/* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32
without signed overflow, which would be undefined behaviour. */
(UINT_MAX <= UINT32_MAX) &&
/* Conversions from unsigned to signed outside of the bounds of the signed type are
implementation-defined. Verify that they function as reinterpreting the lower
bits of the input in two's complement notation. Do this for conversions:
- from uint(N)_t to int(N)_t with negative result
- from uint(2N)_t to int(N)_t with negative result
- from int(2N)_t to int(N)_t with negative result
- from int(2N)_t to int(N)_t with positive result */
/* To int8_t. */
((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55) &&
((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33) &&
((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF) &&
((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34) &&
/* To int16_t. */
((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322) &&
((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C) &&
((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4) &&
((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678) &&
/* To int32_t. */
((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B) &&
((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE) &&
((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8) &&
((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789) &&
/* To int64_t. */
((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) &&
#if defined(SECP256K1_WIDEMUL_INT128)
((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) &&
(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) &&
(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) &&
/* To int128_t. */
((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)) &&
#endif
/* Right shift on negative signed values is implementation defined. Verify that it
acts as a right shift in two's complement with sign extension (i.e duplicating
the top bit into newly added bits). */
((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA) &&
((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) &&
((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) &&
((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) &&
#if defined(SECP256K1_WIDEMUL_INT128)
((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) &&
#endif
1) * 2 - 1];
};
#endif /* SECP256K1_ASSUMPTIONS_H */

View File

@@ -4,31 +4,29 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_BASIC_CONFIG_H
#define SECP256K1_BASIC_CONFIG_H
#ifndef _SECP256K1_BASIC_CONFIG_
#define _SECP256K1_BASIC_CONFIG_
#ifdef USE_BASIC_CONFIG
#undef USE_ASM_X86_64
#undef USE_ECMULT_STATIC_PRECOMPUTATION
#undef USE_EXTERNAL_ASM
#undef USE_EXTERNAL_DEFAULT_CALLBACKS
#undef USE_ENDOMORPHISM
#undef USE_FIELD_10X26
#undef USE_FIELD_5X52
#undef USE_FIELD_INV_BUILTIN
#undef USE_FIELD_INV_NUM
#undef USE_NUM_GMP
#undef USE_NUM_NONE
#undef USE_SCALAR_4X64
#undef USE_SCALAR_8X32
#undef USE_SCALAR_INV_BUILTIN
#undef USE_SCALAR_INV_NUM
#undef USE_FORCE_WIDEMUL_INT64
#undef USE_FORCE_WIDEMUL_INT128
#undef ECMULT_WINDOW_SIZE
#define USE_NUM_NONE 1
#define USE_FIELD_INV_BUILTIN 1
#define USE_SCALAR_INV_BUILTIN 1
#define USE_WIDEMUL_64 1
#define ECMULT_WINDOW_SIZE 15
#define USE_FIELD_10X26 1
#define USE_SCALAR_8X32 1
#endif /* USE_BASIC_CONFIG */
#endif /* SECP256K1_BASIC_CONFIG_H */
#endif // USE_BASIC_CONFIG
#endif // _SECP256K1_BASIC_CONFIG_

View File

@@ -4,90 +4,47 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_BENCH_H
#define SECP256K1_BENCH_H
#ifndef _SECP256K1_BENCH_H_
#define _SECP256K1_BENCH_H_
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "sys/time.h"
static int64_t gettime_i64(void) {
static double gettimedouble(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
return tv.tv_usec * 0.000001 + tv.tv_sec;
}
#define FP_EXP (6)
#define FP_MULT (1000000LL)
/* Format fixed point number. */
void print_number(const int64_t x) {
int64_t x_abs, y;
int c, i, rounding;
size_t ptr;
char buffer[30];
if (x == INT64_MIN) {
/* Prevent UB. */
printf("ERR");
return;
void print_number(double x) {
double y = x;
int c = 0;
if (y < 0.0) {
y = -y;
}
x_abs = x < 0 ? -x : x;
/* Determine how many decimals we want to show (more than FP_EXP makes no
* sense). */
y = x_abs;
c = 0;
while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) {
y *= 10LL;
while (y < 100.0) {
y *= 10.0;
c++;
}
/* Round to 'c' decimals. */
y = x_abs;
rounding = 0;
for (i = c; i < FP_EXP; ++i) {
rounding = (y % 10) >= 5;
y /= 10;
}
y += rounding;
/* Format and print the number. */
ptr = sizeof(buffer) - 1;
buffer[ptr] = 0;
if (c != 0) {
for (i = 0; i < c; ++i) {
buffer[--ptr] = '0' + (y % 10);
y /= 10;
}
buffer[--ptr] = '.';
}
do {
buffer[--ptr] = '0' + (y % 10);
y /= 10;
} while (y != 0);
if (x < 0) {
buffer[--ptr] = '-';
}
printf("%s", &buffer[ptr]);
printf("%.*f", c, x);
}
void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) {
int i;
int64_t min = INT64_MAX;
int64_t sum = 0;
int64_t max = 0;
double min = HUGE_VAL;
double sum = 0.0;
double max = 0.0;
for (i = 0; i < count; i++) {
int64_t begin, total;
double begin, total;
if (setup != NULL) {
setup(data);
}
begin = gettime_i64();
benchmark(data, iter);
total = gettime_i64() - begin;
begin = gettimedouble();
benchmark(data);
total = gettimedouble() - begin;
if (teardown != NULL) {
teardown(data, iter);
teardown(data);
}
if (total < min) {
min = total;
@@ -98,36 +55,12 @@ void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void
sum += total;
}
printf("%s: min ", name);
print_number(min * FP_MULT / iter);
print_number(min * 1000000.0 / iter);
printf("us / avg ");
print_number(((sum * FP_MULT) / count) / iter);
print_number((sum / count) * 1000000.0 / iter);
printf("us / max ");
print_number(max * FP_MULT / iter);
print_number(max * 1000000.0 / iter);
printf("us\n");
}
int have_flag(int argc, char** argv, char *flag) {
char** argm = argv + argc;
argv++;
if (argv == argm) {
return 1;
}
while (argv != NULL && argv != argm) {
if (strcmp(*argv, flag) == 0) {
return 1;
}
argv++;
}
return 0;
}
int get_iters(int default_iters) {
char* env = getenv("SECP256K1_BENCH_ITERS");
if (env) {
return strtol(env, NULL, 0);
} else {
return default_iters;
}
}
#endif /* SECP256K1_BENCH_H */
#endif

View File

@@ -15,11 +15,11 @@ typedef struct {
secp256k1_context *ctx;
secp256k1_pubkey point;
unsigned char scalar[32];
} bench_ecdh_data;
} bench_ecdh_t;
static void bench_ecdh_setup(void* arg) {
int i;
bench_ecdh_data *data = (bench_ecdh_data*)arg;
bench_ecdh_t *data = (bench_ecdh_t*)arg;
const unsigned char point[] = {
0x03,
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
@@ -28,32 +28,27 @@ static void bench_ecdh_setup(void* arg) {
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
};
/* create a context with no capabilities */
data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
for (i = 0; i < 32; i++) {
data->scalar[i] = i + 1;
}
CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1);
}
static void bench_ecdh(void* arg, int iters) {
static void bench_ecdh(void* arg) {
int i;
unsigned char res[32];
bench_ecdh_data *data = (bench_ecdh_data*)arg;
bench_ecdh_t *data = (bench_ecdh_t*)arg;
for (i = 0; i < iters; i++) {
CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1);
for (i = 0; i < 20000; i++) {
CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1);
}
}
int main(void) {
bench_ecdh_data data;
bench_ecdh_t data;
int iters = get_iters(20000);
/* create a context with no capabilities */
data.ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, iters);
secp256k1_context_destroy(data.ctx);
run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000);
return 0;
}

View File

@@ -1,214 +0,0 @@
/**********************************************************************
* Copyright (c) 2017 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#include <stdio.h>
#include "include/secp256k1.h"
#include "util.h"
#include "hash_impl.h"
#include "num_impl.h"
#include "field_impl.h"
#include "group_impl.h"
#include "scalar_impl.h"
#include "ecmult_impl.h"
#include "bench.h"
#include "secp256k1.c"
#define POINTS 32768
typedef struct {
/* Setup once in advance */
secp256k1_context* ctx;
secp256k1_scratch_space* scratch;
secp256k1_scalar* scalars;
secp256k1_ge* pubkeys;
secp256k1_scalar* seckeys;
secp256k1_gej* expected_output;
secp256k1_ecmult_multi_func ecmult_multi;
/* Changes per test */
size_t count;
int includes_g;
/* Changes per test iteration */
size_t offset1;
size_t offset2;
/* Test output. */
secp256k1_gej* output;
} bench_data;
static int bench_callback(secp256k1_scalar* sc, secp256k1_ge* ge, size_t idx, void* arg) {
bench_data* data = (bench_data*)arg;
if (data->includes_g) ++idx;
if (idx == 0) {
*sc = data->scalars[data->offset1];
*ge = secp256k1_ge_const_g;
} else {
*sc = data->scalars[(data->offset1 + idx) % POINTS];
*ge = data->pubkeys[(data->offset2 + idx - 1) % POINTS];
}
return 1;
}
static void bench_ecmult(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
int includes_g = data->includes_g;
int iter;
int count = data->count;
iters = iters / data->count;
for (iter = 0; iter < iters; ++iter) {
data->ecmult_multi(&data->ctx->error_callback, &data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g);
data->offset1 = (data->offset1 + count) % POINTS;
data->offset2 = (data->offset2 + count - 1) % POINTS;
}
}
static void bench_ecmult_setup(void* arg) {
bench_data* data = (bench_data*)arg;
data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS;
data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS;
}
static void bench_ecmult_teardown(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
int iter;
iters = iters / data->count;
/* Verify the results in teardown, to avoid doing comparisons while benchmarking. */
for (iter = 0; iter < iters; ++iter) {
secp256k1_gej tmp;
secp256k1_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL);
CHECK(secp256k1_gej_is_infinity(&tmp));
}
}
static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
secp256k1_sha256 sha256;
unsigned char c[11] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0};
unsigned char buf[32];
int overflow = 0;
c[6] = num;
c[7] = num >> 8;
c[8] = num >> 16;
c[9] = num >> 24;
secp256k1_sha256_initialize(&sha256);
secp256k1_sha256_write(&sha256, c, sizeof(c));
secp256k1_sha256_finalize(&sha256, buf);
secp256k1_scalar_set_b32(scalar, buf, &overflow);
CHECK(!overflow);
}
static void run_test(bench_data* data, size_t count, int includes_g, int num_iters) {
char str[32];
static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
size_t iters = 1 + num_iters / count;
size_t iter;
data->count = count;
data->includes_g = includes_g;
/* Compute (the negation of) the expected results directly. */
data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS;
data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS;
for (iter = 0; iter < iters; ++iter) {
secp256k1_scalar tmp;
secp256k1_scalar total = data->scalars[(data->offset1++) % POINTS];
size_t i = 0;
for (i = 0; i + 1 < count; ++i) {
secp256k1_scalar_mul(&tmp, &data->seckeys[(data->offset2++) % POINTS], &data->scalars[(data->offset1++) % POINTS]);
secp256k1_scalar_add(&total, &total, &tmp);
}
secp256k1_scalar_negate(&total, &total);
secp256k1_ecmult(&data->ctx->ecmult_ctx, &data->expected_output[iter], NULL, &zero, &total);
}
/* Run the benchmark. */
sprintf(str, includes_g ? "ecmult_%ig" : "ecmult_%i", (int)count);
run_benchmark(str, bench_ecmult, bench_ecmult_setup, bench_ecmult_teardown, data, 10, count * iters);
}
int main(int argc, char **argv) {
bench_data data;
int i, p;
secp256k1_gej* pubkeys_gej;
size_t scratch_size;
int iters = get_iters(10000);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
data.ecmult_multi = secp256k1_ecmult_multi_var;
if (argc > 1) {
if(have_flag(argc, argv, "pippenger_wnaf")) {
printf("Using pippenger_wnaf:\n");
data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single;
} else if(have_flag(argc, argv, "strauss_wnaf")) {
printf("Using strauss_wnaf:\n");
data.ecmult_multi = secp256k1_ecmult_strauss_batch_single;
} else if(have_flag(argc, argv, "simple")) {
printf("Using simple algorithm:\n");
data.ecmult_multi = secp256k1_ecmult_multi_var;
secp256k1_scratch_space_destroy(data.ctx, data.scratch);
data.scratch = NULL;
} else {
fprintf(stderr, "%s: unrecognized argument '%s'.\n", argv[0], argv[1]);
fprintf(stderr, "Use 'pippenger_wnaf', 'strauss_wnaf', 'simple' or no argument to benchmark a combined algorithm.\n");
return 1;
}
}
/* Allocate stuff */
data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS);
data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS);
data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS);
data.expected_output = malloc(sizeof(secp256k1_gej) * (iters + 1));
data.output = malloc(sizeof(secp256k1_gej) * (iters + 1));
/* Generate a set of scalars, and private/public keypairs. */
pubkeys_gej = malloc(sizeof(secp256k1_gej) * POINTS);
secp256k1_gej_set_ge(&pubkeys_gej[0], &secp256k1_ge_const_g);
secp256k1_scalar_set_int(&data.seckeys[0], 1);
for (i = 0; i < POINTS; ++i) {
generate_scalar(i, &data.scalars[i]);
if (i) {
secp256k1_gej_double_var(&pubkeys_gej[i], &pubkeys_gej[i - 1], NULL);
secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]);
}
}
secp256k1_ge_set_all_gej_var(data.pubkeys, pubkeys_gej, POINTS);
free(pubkeys_gej);
for (i = 1; i <= 8; ++i) {
run_test(&data, i, 1, iters);
}
/* This is disabled with low count of iterations because the loop runs 77 times even with iters=1
* and the higher it goes the longer the computation takes(more points)
* So we don't run this benchmark with low iterations to prevent slow down */
if (iters > 2) {
for (p = 0; p <= 11; ++p) {
for (i = 9; i <= 16; ++i) {
run_test(&data, i << p, 1, iters);
}
}
}
if (data.scratch != NULL) {
secp256k1_scratch_space_destroy(data.ctx, data.scratch);
}
secp256k1_context_destroy(data.ctx);
free(data.scalars);
free(data.pubkeys);
free(data.seckeys);
free(data.output);
free(data.expected_output);
return(0);
}

View File

@@ -23,22 +23,22 @@ static void bench_generator_setup(void* arg) {
memset(data->blind, 0x13, 32);
}
static void bench_generator_generate(void* arg, int iters) {
static void bench_generator_generate(void* arg) {
int i;
bench_generator_t *data = (bench_generator_t*)arg;
for (i = 0; i < iters; i++) {
for (i = 0; i < 20000; i++) {
secp256k1_generator gen;
CHECK(secp256k1_generator_generate(data->ctx, &gen, data->key));
data->key[i & 31]++;
}
}
static void bench_generator_generate_blinded(void* arg, int iters) {
static void bench_generator_generate_blinded(void* arg) {
int i;
bench_generator_t *data = (bench_generator_t*)arg;
for (i = 0; i < iters; i++) {
for (i = 0; i < 20000; i++) {
secp256k1_generator gen;
CHECK(secp256k1_generator_generate_blinded(data->ctx, &gen, data->key, data->blind));
data->key[1 + (i & 30)]++;
@@ -48,12 +48,11 @@ static void bench_generator_generate_blinded(void* arg, int iters) {
int main(void) {
bench_generator_t data;
int iters = get_iters(20000);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
run_benchmark("generator_generate", bench_generator_generate, bench_generator_setup, NULL, &data, 10, iters);
run_benchmark("generator_generate_blinded", bench_generator_generate_blinded, bench_generator_setup, NULL, &data, 10, iters);
run_benchmark("generator_generate", bench_generator_generate, bench_generator_setup, NULL, &data, 10, 20000);
run_benchmark("generator_generate_blinded", bench_generator_generate_blinded, bench_generator_setup, NULL, &data, 10, 20000);
secp256k1_context_destroy(data.ctx);
return 0;

View File

@@ -7,7 +7,6 @@
#include "include/secp256k1.h"
#include "assumptions.h"
#include "util.h"
#include "hash_impl.h"
#include "num_impl.h"
@@ -20,412 +19,364 @@
#include "secp256k1.c"
typedef struct {
secp256k1_scalar scalar[2];
secp256k1_fe fe[4];
secp256k1_ge ge[2];
secp256k1_gej gej[2];
secp256k1_scalar scalar_x, scalar_y;
secp256k1_fe fe_x, fe_y;
secp256k1_ge ge_x, ge_y;
secp256k1_gej gej_x, gej_y;
unsigned char data[64];
int wnaf[256];
} bench_inv;
} bench_inv_t;
void bench_setup(void* arg) {
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
static const unsigned char init[4][32] = {
/* Initializer for scalar[0], fe[0], first half of data, the X coordinate of ge[0],
and the (implied affine) X coordinate of gej[0]. */
{
0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,
0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59,
0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83
},
/* Initializer for scalar[1], fe[1], first half of data, the X coordinate of ge[1],
and the (implied affine) X coordinate of gej[1]. */
{
0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83,
0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5,
0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9,
0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3
},
/* Initializer for fe[2] and the Z coordinate of gej[0]. */
{
0x3d, 0x2d, 0xef, 0xf4, 0x25, 0x98, 0x4f, 0x5d,
0xe2, 0xca, 0x5f, 0x41, 0x3f, 0x3f, 0xce, 0x44,
0xaa, 0x2c, 0x53, 0x8a, 0xc6, 0x59, 0x1f, 0x38,
0x38, 0x23, 0xe4, 0x11, 0x27, 0xc6, 0xa0, 0xe7
},
/* Initializer for fe[3] and the Z coordinate of gej[1]. */
{
0xbd, 0x21, 0xa5, 0xe1, 0x13, 0x50, 0x73, 0x2e,
0x52, 0x98, 0xc8, 0x9e, 0xab, 0x00, 0xa2, 0x68,
0x43, 0xf5, 0xd7, 0x49, 0x80, 0x72, 0xa7, 0xf3,
0xd7, 0x60, 0xe6, 0xab, 0x90, 0x92, 0xdf, 0xc5
}
static const unsigned char init_x[32] = {
0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,
0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59,
0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83
};
secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL);
secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL);
secp256k1_fe_set_b32(&data->fe[0], init[0]);
secp256k1_fe_set_b32(&data->fe[1], init[1]);
secp256k1_fe_set_b32(&data->fe[2], init[2]);
secp256k1_fe_set_b32(&data->fe[3], init[3]);
CHECK(secp256k1_ge_set_xo_var(&data->ge[0], &data->fe[0], 0));
CHECK(secp256k1_ge_set_xo_var(&data->ge[1], &data->fe[1], 1));
secp256k1_gej_set_ge(&data->gej[0], &data->ge[0]);
secp256k1_gej_rescale(&data->gej[0], &data->fe[2]);
secp256k1_gej_set_ge(&data->gej[1], &data->ge[1]);
secp256k1_gej_rescale(&data->gej[1], &data->fe[3]);
memcpy(data->data, init[0], 32);
memcpy(data->data + 32, init[1], 32);
static const unsigned char init_y[32] = {
0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83,
0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5,
0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9,
0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3
};
secp256k1_scalar_set_b32(&data->scalar_x, init_x, NULL);
secp256k1_scalar_set_b32(&data->scalar_y, init_y, NULL);
secp256k1_fe_set_b32(&data->fe_x, init_x);
secp256k1_fe_set_b32(&data->fe_y, init_y);
CHECK(secp256k1_ge_set_xo_var(&data->ge_x, &data->fe_x, 0));
CHECK(secp256k1_ge_set_xo_var(&data->ge_y, &data->fe_y, 1));
secp256k1_gej_set_ge(&data->gej_x, &data->ge_x);
secp256k1_gej_set_ge(&data->gej_y, &data->ge_y);
memcpy(data->data, init_x, 32);
memcpy(data->data + 32, init_y, 32);
}
void bench_scalar_add(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(j <= iters);
}
void bench_scalar_negate(void* arg, int iters) {
void bench_scalar_add(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_scalar_negate(&data->scalar[0], &data->scalar[0]);
for (i = 0; i < 2000000; i++) {
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
}
}
void bench_scalar_sqr(void* arg, int iters) {
void bench_scalar_negate(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_scalar_sqr(&data->scalar[0], &data->scalar[0]);
for (i = 0; i < 2000000; i++) {
secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x);
}
}
void bench_scalar_mul(void* arg, int iters) {
void bench_scalar_sqr(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_scalar_mul(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
for (i = 0; i < 200000; i++) {
secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x);
}
}
void bench_scalar_split(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
secp256k1_scalar_split_lambda(&data->scalar[0], &data->scalar[1], &data->scalar[0]);
j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(j <= iters);
}
void bench_scalar_inverse(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
secp256k1_scalar_inverse(&data->scalar[0], &data->scalar[0]);
j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(j <= iters);
}
void bench_scalar_inverse_var(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
secp256k1_scalar_inverse_var(&data->scalar[0], &data->scalar[0]);
j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(j <= iters);
}
void bench_field_normalize(void* arg, int iters) {
void bench_scalar_mul(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_fe_normalize(&data->fe[0]);
for (i = 0; i < 200000; i++) {
secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y);
}
}
void bench_field_normalize_weak(void* arg, int iters) {
#ifdef USE_ENDOMORPHISM
void bench_scalar_split(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_fe_normalize_weak(&data->fe[0]);
for (i = 0; i < 20000; i++) {
secp256k1_scalar l, r;
secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x);
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
}
}
#endif
void bench_field_mul(void* arg, int iters) {
void bench_scalar_inverse(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_fe_mul(&data->fe[0], &data->fe[0], &data->fe[1]);
for (i = 0; i < 2000; i++) {
secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x);
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
}
}
void bench_field_sqr(void* arg, int iters) {
void bench_scalar_inverse_var(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_fe_sqr(&data->fe[0], &data->fe[0]);
for (i = 0; i < 2000; i++) {
secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x);
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
}
}
void bench_field_inverse(void* arg, int iters) {
void bench_field_normalize(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_fe_inv(&data->fe[0], &data->fe[0]);
secp256k1_fe_add(&data->fe[0], &data->fe[1]);
for (i = 0; i < 2000000; i++) {
secp256k1_fe_normalize(&data->fe_x);
}
}
void bench_field_inverse_var(void* arg, int iters) {
void bench_field_normalize_weak(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_fe_inv_var(&data->fe[0], &data->fe[0]);
secp256k1_fe_add(&data->fe[0], &data->fe[1]);
for (i = 0; i < 2000000; i++) {
secp256k1_fe_normalize_weak(&data->fe_x);
}
}
void bench_field_sqrt(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
secp256k1_fe t;
for (i = 0; i < iters; i++) {
t = data->fe[0];
j += secp256k1_fe_sqrt(&data->fe[0], &t);
secp256k1_fe_add(&data->fe[0], &data->fe[1]);
}
CHECK(j <= iters);
}
void bench_group_double_var(void* arg, int iters) {
void bench_field_mul(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_gej_double_var(&data->gej[0], &data->gej[0], NULL);
for (i = 0; i < 200000; i++) {
secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y);
}
}
void bench_group_add_var(void* arg, int iters) {
void bench_field_sqr(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_gej_add_var(&data->gej[0], &data->gej[0], &data->gej[1], NULL);
for (i = 0; i < 200000; i++) {
secp256k1_fe_sqr(&data->fe_x, &data->fe_x);
}
}
void bench_group_add_affine(void* arg, int iters) {
void bench_field_inverse(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_gej_add_ge(&data->gej[0], &data->gej[0], &data->ge[1]);
for (i = 0; i < 20000; i++) {
secp256k1_fe_inv(&data->fe_x, &data->fe_x);
secp256k1_fe_add(&data->fe_x, &data->fe_y);
}
}
void bench_group_add_affine_var(void* arg, int iters) {
void bench_field_inverse_var(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
secp256k1_gej_add_ge_var(&data->gej[0], &data->gej[0], &data->ge[1], NULL);
for (i = 0; i < 20000; i++) {
secp256k1_fe_inv_var(&data->fe_x, &data->fe_x);
secp256k1_fe_add(&data->fe_x, &data->fe_y);
}
}
void bench_group_jacobi_var(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
j += secp256k1_gej_has_quad_y_var(&data->gej[0]);
/* Vary the Y and Z coordinates of the input (the X coordinate doesn't matter to
secp256k1_gej_has_quad_y_var). Note that the resulting coordinates will
generally not correspond to a point on the curve, but this is not a problem
for the code being benchmarked here. Adding and normalizing have less
overhead than EC operations (which could guarantee the point remains on the
curve). */
secp256k1_fe_add(&data->gej[0].y, &data->fe[1]);
secp256k1_fe_add(&data->gej[0].z, &data->fe[2]);
secp256k1_fe_normalize_var(&data->gej[0].y);
secp256k1_fe_normalize_var(&data->gej[0].z);
}
CHECK(j <= iters);
}
void bench_group_to_affine_var(void* arg, int iters) {
void bench_field_sqrt(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; ++i) {
secp256k1_ge_set_gej_var(&data->ge[1], &data->gej[0]);
/* Use the output affine X/Y coordinates to vary the input X/Y/Z coordinates.
Similar to bench_group_jacobi_var, this approach does not result in
coordinates of points on the curve. */
secp256k1_fe_add(&data->gej[0].x, &data->ge[1].y);
secp256k1_fe_add(&data->gej[0].y, &data->fe[2]);
secp256k1_fe_add(&data->gej[0].z, &data->ge[1].x);
secp256k1_fe_normalize_var(&data->gej[0].x);
secp256k1_fe_normalize_var(&data->gej[0].y);
secp256k1_fe_normalize_var(&data->gej[0].z);
for (i = 0; i < 20000; i++) {
secp256k1_fe_sqrt(&data->fe_x, &data->fe_x);
secp256k1_fe_add(&data->fe_x, &data->fe_y);
}
}
void bench_ecmult_wnaf(void* arg, int iters) {
int i, bits = 0, overflow = 0;
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
bits += secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar[0], WINDOW_A);
overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(overflow >= 0);
CHECK(bits <= 256*iters);
}
void bench_wnaf_const(void* arg, int iters) {
int i, bits = 0, overflow = 0;
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
bits += secp256k1_wnaf_const(data->wnaf, &data->scalar[0], WINDOW_A, 256);
overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
}
CHECK(overflow >= 0);
CHECK(bits <= 256*iters);
}
void bench_sha256(void* arg, int iters) {
void bench_group_double_var(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_sha256 sha;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < iters; i++) {
for (i = 0; i < 200000; i++) {
secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL);
}
}
void bench_group_add_var(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 200000; i++) {
secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL);
}
}
void bench_group_add_affine(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 200000; i++) {
secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y);
}
}
void bench_group_add_affine_var(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 200000; i++) {
secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL);
}
}
void bench_group_jacobi_var(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 20000; i++) {
secp256k1_gej_has_quad_y_var(&data->gej_x);
}
}
void bench_ecmult_wnaf(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 20000; i++) {
secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A);
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
}
}
void bench_wnaf_const(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 20000; i++) {
secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A, 256, 1);
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
}
}
void bench_sha256(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
secp256k1_sha256_t sha;
for (i = 0; i < 20000; i++) {
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, data->data, 32);
secp256k1_sha256_finalize(&sha, data->data);
}
}
void bench_hmac_sha256(void* arg, int iters) {
void bench_hmac_sha256(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_hmac_sha256 hmac;
bench_inv_t *data = (bench_inv_t*)arg;
secp256k1_hmac_sha256_t hmac;
for (i = 0; i < iters; i++) {
for (i = 0; i < 20000; i++) {
secp256k1_hmac_sha256_initialize(&hmac, data->data, 32);
secp256k1_hmac_sha256_write(&hmac, data->data, 32);
secp256k1_hmac_sha256_finalize(&hmac, data->data);
}
}
void bench_rfc6979_hmac_sha256(void* arg, int iters) {
void bench_rfc6979_hmac_sha256(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_rfc6979_hmac_sha256 rng;
bench_inv_t *data = (bench_inv_t*)arg;
secp256k1_rfc6979_hmac_sha256_t rng;
for (i = 0; i < iters; i++) {
for (i = 0; i < 20000; i++) {
secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64);
secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32);
}
}
void bench_context_verify(void* arg, int iters) {
void bench_context_verify(void* arg) {
int i;
(void)arg;
for (i = 0; i < iters; i++) {
for (i = 0; i < 20; i++) {
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY));
}
}
void bench_context_sign(void* arg, int iters) {
void bench_context_sign(void* arg) {
int i;
(void)arg;
for (i = 0; i < iters; i++) {
for (i = 0; i < 200; i++) {
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN));
}
}
#ifndef USE_NUM_NONE
void bench_num_jacobi(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
secp256k1_num nx, na, norder;
void bench_num_jacobi(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
secp256k1_num nx, norder;
secp256k1_scalar_get_num(&nx, &data->scalar[0]);
secp256k1_scalar_get_num(&nx, &data->scalar_x);
secp256k1_scalar_order_get_num(&norder);
secp256k1_scalar_get_num(&na, &data->scalar[1]);
secp256k1_scalar_get_num(&norder, &data->scalar_y);
for (i = 0; i < iters; i++) {
j += secp256k1_num_jacobi(&nx, &norder);
secp256k1_num_add(&nx, &nx, &na);
for (i = 0; i < 200000; i++) {
secp256k1_num_jacobi(&nx, &norder);
}
CHECK(j <= iters);
}
#endif
int main(int argc, char **argv) {
bench_inv data;
int iters = get_iters(20000);
int have_flag(int argc, char** argv, char *flag) {
char** argm = argv + argc;
argv++;
if (argv == argm) {
return 1;
}
while (argv != NULL && argv != argm) {
if (strcmp(*argv, flag) == 0) {
return 1;
}
argv++;
}
return 0;
}
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters);
int main(int argc, char **argv) {
bench_inv_t data;
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000);
#ifdef USE_ENDOMORPHISM
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, 20000);
#endif
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000);
if (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 (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 (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "to_affine")) run_benchmark("group_to_affine_var", bench_group_to_affine_var, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 1 + iters/1000);
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 1 + iters/100);
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20);
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200);
#ifndef USE_NUM_NONE
if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000);
#endif
return 0;
}

View File

@@ -34,11 +34,11 @@ static void bench_rangeproof_setup(void* arg) {
CHECK(secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len, NULL, 0, secp256k1_generator_h));
}
static void bench_rangeproof(void* arg, int iters) {
static void bench_rangeproof(void* arg) {
int i;
bench_rangeproof_t *data = (bench_rangeproof_t*)arg;
for (i = 0; i < iters/data->min_bits; i++) {
for (i = 0; i < 1000; i++) {
int j;
uint64_t minv;
uint64_t maxv;
@@ -51,14 +51,12 @@ static void bench_rangeproof(void* arg, int iters) {
int main(void) {
bench_rangeproof_t data;
int iters;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
data.min_bits = 32;
iters = data.min_bits*get_iters(32);
run_benchmark("rangeproof_verify_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, iters);
run_benchmark("rangeproof_verify_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, 1000 * data.min_bits);
secp256k1_context_destroy(data.ctx);
return 0;

View File

@@ -13,15 +13,15 @@ typedef struct {
secp256k1_context *ctx;
unsigned char msg[32];
unsigned char sig[64];
} bench_recover_data;
} bench_recover_t;
void bench_recover(void* arg, int iters) {
void bench_recover(void* arg) {
int i;
bench_recover_data *data = (bench_recover_data*)arg;
bench_recover_t *data = (bench_recover_t*)arg;
secp256k1_pubkey pubkey;
unsigned char pubkeyc[33];
for (i = 0; i < iters; i++) {
for (i = 0; i < 20000; i++) {
int j;
size_t pubkeylen = 33;
secp256k1_ecdsa_recoverable_signature sig;
@@ -38,7 +38,7 @@ void bench_recover(void* arg, int iters) {
void bench_recover_setup(void* arg) {
int i;
bench_recover_data *data = (bench_recover_data*)arg;
bench_recover_t *data = (bench_recover_t*)arg;
for (i = 0; i < 32; i++) {
data->msg[i] = 1 + i;
@@ -49,13 +49,11 @@ void bench_recover_setup(void* arg) {
}
int main(void) {
bench_recover_data data;
int iters = get_iters(20000);
bench_recover_t data;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, iters);
run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000);
secp256k1_context_destroy(data.ctx);
return 0;

View File

@@ -0,0 +1,73 @@
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#include <stdio.h>
#include <string.h>
#include "include/secp256k1.h"
#include "include/secp256k1_schnorr.h"
#include "util.h"
#include "bench.h"
typedef struct {
unsigned char key[32];
unsigned char sig[64];
unsigned char pubkey[33];
size_t pubkeylen;
} benchmark_schnorr_sig_t;
typedef struct {
secp256k1_context *ctx;
unsigned char msg[32];
benchmark_schnorr_sig_t sigs[64];
int numsigs;
} benchmark_schnorr_verify_t;
static void benchmark_schnorr_init(void* arg) {
int i, k;
benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
for (i = 0; i < 32; i++) {
data->msg[i] = 1 + i;
}
for (k = 0; k < data->numsigs; k++) {
secp256k1_pubkey pubkey;
for (i = 0; i < 32; i++) {
data->sigs[k].key[i] = 33 + i + k;
}
secp256k1_schnorr_sign(data->ctx, data->sigs[k].sig, data->msg, data->sigs[k].key, NULL, NULL);
data->sigs[k].pubkeylen = 33;
CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key));
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED));
}
}
static void benchmark_schnorr_verify(void* arg) {
int i;
benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
for (i = 0; i < 20000 / data->numsigs; i++) {
secp256k1_pubkey pubkey;
data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen));
CHECK(secp256k1_schnorr_verify(data->ctx, data->sigs[0].sig, data->msg, &pubkey) == ((i & 0xFF) == 0));
data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
}
}
int main(void) {
benchmark_schnorr_verify_t data;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
data.numsigs = 1;
run_benchmark("schnorr_verify", benchmark_schnorr_verify, benchmark_schnorr_init, NULL, &data, 10, 20000);
secp256k1_context_destroy(data.ctx);
return 0;
}

View File

@@ -1,102 +0,0 @@
/**********************************************************************
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#include <string.h>
#include <stdlib.h>
#include "include/secp256k1.h"
#include "include/secp256k1_schnorrsig.h"
#include "util.h"
#include "bench.h"
typedef struct {
secp256k1_context *ctx;
int n;
const secp256k1_keypair **keypairs;
const unsigned char **pk;
const unsigned char **sigs;
const unsigned char **msgs;
} bench_schnorrsig_data;
void bench_schnorrsig_sign(void* arg, int iters) {
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
int i;
unsigned char msg[32] = "benchmarkexamplemessagetemplate";
unsigned char sig[64];
for (i = 0; i < iters; i++) {
msg[0] = i;
msg[1] = i >> 8;
CHECK(secp256k1_schnorrsig_sign(data->ctx, sig, msg, data->keypairs[i], NULL, NULL));
}
}
void bench_schnorrsig_verify(void* arg, int iters) {
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
int i;
for (i = 0; i < iters; i++) {
secp256k1_xonly_pubkey pk;
CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1);
CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], &pk));
}
}
int main(void) {
int i;
bench_schnorrsig_data data;
int iters = get_iters(10000);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *));
data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
data.sigs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
for (i = 0; i < iters; i++) {
unsigned char sk[32];
unsigned char *msg = (unsigned char *)malloc(32);
unsigned char *sig = (unsigned char *)malloc(64);
secp256k1_keypair *keypair = (secp256k1_keypair *)malloc(sizeof(*keypair));
unsigned char *pk_char = (unsigned char *)malloc(32);
secp256k1_xonly_pubkey pk;
msg[0] = sk[0] = i;
msg[1] = sk[1] = i >> 8;
msg[2] = sk[2] = i >> 16;
msg[3] = sk[3] = i >> 24;
memset(&msg[4], 'm', 28);
memset(&sk[4], 's', 28);
data.keypairs[i] = keypair;
data.pk[i] = pk_char;
data.msgs[i] = msg;
data.sigs[i] = sig;
CHECK(secp256k1_keypair_create(data.ctx, keypair, sk));
CHECK(secp256k1_schnorrsig_sign(data.ctx, sig, msg, keypair, NULL, NULL));
CHECK(secp256k1_keypair_xonly_pub(data.ctx, &pk, NULL, keypair));
CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1);
}
run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, iters);
run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, iters);
for (i = 0; i < iters; i++) {
free((void *)data.keypairs[i]);
free((void *)data.pk[i]);
free((void *)data.msgs[i]);
free((void *)data.sigs[i]);
}
free(data.keypairs);
free(data.pk);
free(data.msgs);
free(data.sigs);
secp256k1_context_destroy(data.ctx);
return 0;
}

View File

@@ -12,11 +12,11 @@ typedef struct {
secp256k1_context* ctx;
unsigned char msg[32];
unsigned char key[32];
} bench_sign_data;
} bench_sign_t;
static void bench_sign_setup(void* arg) {
int i;
bench_sign_data *data = (bench_sign_data*)arg;
bench_sign_t *data = (bench_sign_t*)arg;
for (i = 0; i < 32; i++) {
data->msg[i] = i + 1;
@@ -26,12 +26,12 @@ static void bench_sign_setup(void* arg) {
}
}
static void bench_sign_run(void* arg, int iters) {
static void bench_sign(void* arg) {
int i;
bench_sign_data *data = (bench_sign_data*)arg;
bench_sign_t *data = (bench_sign_t*)arg;
unsigned char sig[74];
for (i = 0; i < iters; i++) {
for (i = 0; i < 20000; i++) {
size_t siglen = 74;
int j;
secp256k1_ecdsa_signature signature;
@@ -45,13 +45,11 @@ static void bench_sign_run(void* arg, int iters) {
}
int main(void) {
bench_sign_data data;
int iters = get_iters(20000);
bench_sign_t data;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000);
secp256k1_context_destroy(data.ctx);
return 0;

View File

@@ -17,7 +17,6 @@
#include <openssl/obj_mac.h>
#endif
typedef struct {
secp256k1_context *ctx;
unsigned char msg[32];
@@ -29,13 +28,13 @@ typedef struct {
#ifdef ENABLE_OPENSSL_TESTS
EC_GROUP* ec_group;
#endif
} bench_verify_data;
} benchmark_verify_t;
static void bench_verify(void* arg, int iters) {
static void benchmark_verify(void* arg) {
int i;
bench_verify_data* data = (bench_verify_data*)arg;
benchmark_verify_t* data = (benchmark_verify_t*)arg;
for (i = 0; i < iters; i++) {
for (i = 0; i < 20000; i++) {
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
data->sig[data->siglen - 1] ^= (i & 0xFF);
@@ -51,11 +50,11 @@ static void bench_verify(void* arg, int iters) {
}
#ifdef ENABLE_OPENSSL_TESTS
static void bench_verify_openssl(void* arg, int iters) {
static void benchmark_verify_openssl(void* arg) {
int i;
bench_verify_data* data = (bench_verify_data*)arg;
benchmark_verify_t* data = (benchmark_verify_t*)arg;
for (i = 0; i < iters; i++) {
for (i = 0; i < 20000; i++) {
data->sig[data->siglen - 1] ^= (i & 0xFF);
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
@@ -84,9 +83,7 @@ int main(void) {
int i;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
bench_verify_data data;
int iters = get_iters(20000);
benchmark_verify_t data;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
@@ -103,10 +100,10 @@ int main(void) {
data.pubkeylen = 33;
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters);
run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
#ifdef ENABLE_OPENSSL_TESTS
data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1);
run_benchmark("ecdsa_verify_openssl", bench_verify_openssl, NULL, NULL, &data, 10, iters);
run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000);
EC_GROUP_free(data.ec_group);
#endif

View File

@@ -1,108 +0,0 @@
/**********************************************************************
* Copyright (c) 2017 Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#include <stdio.h>
#include "include/secp256k1.h"
#include "include/secp256k1_whitelist.h"
#include "util.h"
#include "bench.h"
#include "hash_impl.h"
#include "num_impl.h"
#include "scalar_impl.h"
#include "testrand_impl.h"
#define MAX_N_KEYS 30
typedef struct {
secp256k1_context* ctx;
unsigned char online_seckey[MAX_N_KEYS][32];
unsigned char summed_seckey[MAX_N_KEYS][32];
secp256k1_pubkey online_pubkeys[MAX_N_KEYS];
secp256k1_pubkey offline_pubkeys[MAX_N_KEYS];
unsigned char csub[32];
secp256k1_pubkey sub_pubkey;
secp256k1_whitelist_signature sig;
size_t n_keys;
} bench_data;
static void bench_whitelist(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
int i;
for (i = 0; i < iters; i++) {
CHECK(secp256k1_whitelist_verify(data->ctx, &data->sig, data->online_pubkeys, data->offline_pubkeys, data->n_keys, &data->sub_pubkey) == 1);
}
}
static void bench_whitelist_setup(void* arg) {
bench_data* data = (bench_data*)arg;
int i = 0;
CHECK(secp256k1_whitelist_sign(data->ctx, &data->sig, data->online_pubkeys, data->offline_pubkeys, data->n_keys, &data->sub_pubkey, data->online_seckey[i], data->summed_seckey[i], i, NULL, NULL));
}
static void run_test(bench_data* data, int iters) {
char str[32];
sprintf(str, "whitelist_%i", (int)data->n_keys);
run_benchmark(str, bench_whitelist, bench_whitelist_setup, NULL, data, 100, iters);
}
void random_scalar_order(secp256k1_scalar *num) {
do {
unsigned char b32[32];
int overflow = 0;
secp256k1_testrand256(b32);
secp256k1_scalar_set_b32(num, b32, &overflow);
if (overflow || secp256k1_scalar_is_zero(num)) {
continue;
}
break;
} while(1);
}
int main(void) {
bench_data data;
size_t i;
size_t n_keys = 30;
secp256k1_scalar ssub;
int iters = get_iters(5);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
/* Start with subkey */
random_scalar_order(&ssub);
secp256k1_scalar_get_b32(data.csub, &ssub);
CHECK(secp256k1_ec_seckey_verify(data.ctx, data.csub) == 1);
CHECK(secp256k1_ec_pubkey_create(data.ctx, &data.sub_pubkey, data.csub) == 1);
/* Then offline and online whitelist keys */
for (i = 0; i < n_keys; i++) {
secp256k1_scalar son, soff;
/* Create two keys */
random_scalar_order(&son);
secp256k1_scalar_get_b32(data.online_seckey[i], &son);
CHECK(secp256k1_ec_seckey_verify(data.ctx, data.online_seckey[i]) == 1);
CHECK(secp256k1_ec_pubkey_create(data.ctx, &data.online_pubkeys[i], data.online_seckey[i]) == 1);
random_scalar_order(&soff);
secp256k1_scalar_get_b32(data.summed_seckey[i], &soff);
CHECK(secp256k1_ec_seckey_verify(data.ctx, data.summed_seckey[i]) == 1);
CHECK(secp256k1_ec_pubkey_create(data.ctx, &data.offline_pubkeys[i], data.summed_seckey[i]) == 1);
/* Make summed_seckey correspond to the sum of offline_pubkey and sub_pubkey */
secp256k1_scalar_add(&soff, &soff, &ssub);
secp256k1_scalar_get_b32(data.summed_seckey[i], &soff);
CHECK(secp256k1_ec_seckey_verify(data.ctx, data.summed_seckey[i]) == 1);
}
/* Run test */
for (i = 1; i <= n_keys; ++i) {
data.n_keys = i;
run_test(&data, iters);
}
secp256k1_context_destroy(data.ctx);
return(0);
}

View File

@@ -1,28 +0,0 @@
/**********************************************************************
* Copyright (c) 2020 The libsecp256k1-zkp Developers *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECCOMMIT_H
#define SECP256K1_ECCOMMIT_H
/** Helper function to add a 32-byte value to a scalar */
static int secp256k1_ec_seckey_tweak_add_helper(secp256k1_scalar *sec, const unsigned char *tweak);
/** Helper function to add a 32-byte value, times G, to an EC point */
static int secp256k1_ec_pubkey_tweak_add_helper(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_ge *p, const unsigned char *tweak);
/** Serializes elem as a 33 byte array. This is non-constant time with respect to
* whether pubp is the point at infinity. Thus, you may need to declassify
* pubp->infinity before calling this function. */
static int secp256k1_ec_commit_pubkey_serialize_const(secp256k1_ge *pubp, unsigned char *buf33);
/** Compute an ec commitment tweak as hash(pubkey, data). */
static int secp256k1_ec_commit_tweak(unsigned char *tweak32, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size);
/** Compute an ec commitment as pubkey + hash(pubkey, data)*G. */
static int secp256k1_ec_commit(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size);
/** Compute a secret key commitment as seckey + hash(pubkey, data). */
static int secp256k1_ec_commit_seckey(const secp256k1_ecmult_gen_context* ecmult_gen_ctx, secp256k1_scalar* seckey, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size);
/** Verify an ec commitment as pubkey + hash(pubkey, data)*G ?= commitment. */
static int secp256k1_ec_commit_verify(const secp256k1_ecmult_context* ecmult_ctx, const secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size);
#endif /* SECP256K1_ECCOMMIT_H */

View File

@@ -1,73 +0,0 @@
/**********************************************************************
* Copyright (c) 2020 The libsecp256k1 Developers *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#include <stddef.h>
#include "eckey.h"
#include "hash.h"
/* from secp256k1.c */
static int secp256k1_ec_seckey_tweak_add_helper(secp256k1_scalar *sec, const unsigned char *tweak);
static int secp256k1_ec_pubkey_tweak_add_helper(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_ge *pubp, const unsigned char *tweak);
static int secp256k1_ec_commit_pubkey_serialize_const(secp256k1_ge *pubp, unsigned char *buf33) {
if (secp256k1_ge_is_infinity(pubp)) {
return 0;
}
secp256k1_fe_normalize(&pubp->x);
secp256k1_fe_normalize(&pubp->y);
secp256k1_fe_get_b32(&buf33[1], &pubp->x);
buf33[0] = secp256k1_fe_is_odd(&pubp->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
return 1;
}
/* Compute an ec commitment tweak as hash(pubp, data). */
static int secp256k1_ec_commit_tweak(unsigned char *tweak32, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size)
{
unsigned char rbuf[33];
if (!secp256k1_ec_commit_pubkey_serialize_const(pubp, rbuf)) {
return 0;
}
secp256k1_sha256_write(sha, rbuf, sizeof(rbuf));
secp256k1_sha256_write(sha, data, data_size);
secp256k1_sha256_finalize(sha, tweak32);
return 1;
}
/* Compute an ec commitment as pubp + hash(pubp, data)*G. */
static int secp256k1_ec_commit(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
unsigned char tweak[32];
*commitp = *pubp;
return secp256k1_ec_commit_tweak(tweak, commitp, sha, data, data_size)
&& secp256k1_ec_pubkey_tweak_add_helper(ecmult_ctx, commitp, tweak);
}
/* Compute the seckey of an ec commitment from the original secret key of the pubkey as seckey +
* hash(pubp, data). */
static int secp256k1_ec_commit_seckey(secp256k1_scalar* seckey, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
unsigned char tweak[32];
return secp256k1_ec_commit_tweak(tweak, pubp, sha, data, data_size)
&& secp256k1_ec_seckey_tweak_add_helper(seckey, tweak);
}
/* Verify an ec commitment as pubp + hash(pubp, data)*G ?= commitment. */
static int secp256k1_ec_commit_verify(const secp256k1_ecmult_context* ecmult_ctx, const secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
secp256k1_gej pj;
secp256k1_ge p;
if (!secp256k1_ec_commit(ecmult_ctx, &p, pubp, sha, data, data_size)) {
return 0;
}
/* Return p == commitp */
secp256k1_ge_neg(&p, &p);
secp256k1_gej_set_ge(&pj, &p);
secp256k1_gej_add_ge_var(&pj, &pj, commitp, NULL);
return secp256k1_gej_is_infinity(&pj);
}

View File

@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECDSA_H
#define SECP256K1_ECDSA_H
#ifndef _SECP256K1_ECDSA_
#define _SECP256K1_ECDSA_
#include <stddef.h>
@@ -18,4 +18,4 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message);
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid);
#endif /* SECP256K1_ECDSA_H */
#endif

View File

@@ -5,8 +5,8 @@
**********************************************************************/
#ifndef SECP256K1_ECDSA_IMPL_H
#define SECP256K1_ECDSA_IMPL_H
#ifndef _SECP256K1_ECDSA_IMPL_H_
#define _SECP256K1_ECDSA_IMPL_H_
#include "scalar.h"
#include "field.h"
@@ -46,73 +46,70 @@ static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CON
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
);
static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const unsigned char *sigend) {
size_t lenleft;
unsigned char b1;
VERIFY_CHECK(len != NULL);
*len = 0;
static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) {
int lenleft, b1;
size_t ret = 0;
if (*sigp >= sigend) {
return 0;
return -1;
}
b1 = *((*sigp)++);
if (b1 == 0xFF) {
/* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */
return 0;
return -1;
}
if ((b1 & 0x80) == 0) {
/* X.690-0207 8.1.3.4 short form length octets */
*len = b1;
return 1;
return b1;
}
if (b1 == 0x80) {
/* Indefinite length is not allowed in DER. */
return 0;
return -1;
}
/* X.690-207 8.1.3.5 long form length octets */
lenleft = b1 & 0x7F; /* lenleft is at least 1 */
if (lenleft > (size_t)(sigend - *sigp)) {
return 0;
lenleft = b1 & 0x7F;
if (lenleft > sigend - *sigp) {
return -1;
}
if (**sigp == 0) {
/* Not the shortest possible length encoding. */
return 0;
return -1;
}
if (lenleft > sizeof(size_t)) {
if ((size_t)lenleft > sizeof(size_t)) {
/* The resulting length would exceed the range of a size_t, so
* certainly longer than the passed array size.
*/
return 0;
return -1;
}
while (lenleft > 0) {
*len = (*len << 8) | **sigp;
if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) {
}
ret = (ret << 8) | **sigp;
if (ret + lenleft > (size_t)(sigend - *sigp)) {
/* Result exceeds the length of the passed array. */
return -1;
}
(*sigp)++;
lenleft--;
}
if (*len > (size_t)(sigend - *sigp)) {
/* Result exceeds the length of the passed array. */
return 0;
}
if (*len < 128) {
if (ret < 128) {
/* Not the shortest possible length encoding. */
return 0;
return -1;
}
return 1;
return ret;
}
static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) {
int overflow = 0;
unsigned char ra[32] = {0};
size_t rlen;
int rlen;
if (*sig == sigend || **sig != 0x02) {
/* Not a primitive integer (X.690-0207 8.3.1). */
return 0;
}
(*sig)++;
if (secp256k1_der_read_len(&rlen, sig, sigend) == 0) {
return 0;
}
if (rlen == 0 || *sig + rlen > sigend) {
rlen = secp256k1_der_read_len(sig, sigend);
if (rlen <= 0 || (*sig) + rlen > sigend) {
/* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */
return 0;
}
@@ -128,11 +125,8 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char
/* Negative. */
overflow = 1;
}
/* There is at most one leading zero byte:
* if there were two leading zero bytes, we would have failed and returned 0
* because of excessive 0x00 padding already. */
if (rlen > 0 && **sig == 0) {
/* Skip leading zero byte */
while (rlen > 0 && **sig == 0) {
/* Skip leading zero bytes */
rlen--;
(*sig)++;
}
@@ -152,16 +146,18 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char
static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) {
const unsigned char *sigend = sig + size;
size_t rlen;
int rlen;
if (sig == sigend || *(sig++) != 0x30) {
/* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */
return 0;
}
if (secp256k1_der_read_len(&rlen, &sig, sigend) == 0) {
rlen = secp256k1_der_read_len(&sig, sigend);
if (rlen < 0 || sig + rlen > sigend) {
/* Tuple exceeds bounds */
return 0;
}
if (rlen != (size_t)(sigend - sig)) {
/* Tuple exceeds bounds or garage after tuple. */
if (sig + rlen != sigend) {
/* Garbage after tuple. */
return 0;
}
@@ -280,7 +276,6 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
secp256k1_ge r;
secp256k1_scalar n;
int overflow = 0;
int high;
secp256k1_ecmult_gen(ctx, &rp, nonce);
secp256k1_ge_set_gej(&r, &rp);
@@ -288,11 +283,15 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
secp256k1_fe_normalize(&r.y);
secp256k1_fe_get_b32(b, &r.x);
secp256k1_scalar_set_b32(sigr, b, &overflow);
/* These two conditions should be checked before calling */
VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr));
VERIFY_CHECK(overflow == 0);
if (recid) {
/* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log
* of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria.
*/
*recid = (overflow << 1) | secp256k1_fe_is_odd(&r.y);
*recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
}
secp256k1_scalar_mul(&n, sigr, seckey);
secp256k1_scalar_add(&n, &n, message);
@@ -301,15 +300,16 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
secp256k1_scalar_clear(&n);
secp256k1_gej_clear(&rp);
secp256k1_ge_clear(&r);
high = secp256k1_scalar_is_high(sigs);
secp256k1_scalar_cond_negate(sigs, high);
if (recid) {
*recid ^= high;
if (secp256k1_scalar_is_zero(sigs)) {
return 0;
}
/* P.x = order is on the curve, so technically sig->r could end up being zero, which would be an invalid signature.
* This is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N.
*/
return !secp256k1_scalar_is_zero(sigr) & !secp256k1_scalar_is_zero(sigs);
if (secp256k1_scalar_is_high(sigs)) {
secp256k1_scalar_negate(sigs, sigs);
if (recid) {
*recid ^= 1;
}
}
return 1;
}
#endif /* SECP256K1_ECDSA_IMPL_H */
#endif

View File

@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECKEY_H
#define SECP256K1_ECKEY_H
#ifndef _SECP256K1_ECKEY_
#define _SECP256K1_ECKEY_
#include <stddef.h>
@@ -22,4 +22,4 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx,
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak);
static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);
#endif /* SECP256K1_ECKEY_H */
#endif

View File

@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECKEY_IMPL_H
#define SECP256K1_ECKEY_IMPL_H
#ifndef _SECP256K1_ECKEY_IMPL_H_
#define _SECP256K1_ECKEY_IMPL_H_
#include "eckey.h"
@@ -15,17 +15,16 @@
#include "ecmult_gen.h"
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) {
if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
secp256k1_fe x;
return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
} else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03);
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
secp256k1_fe x, y;
if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
return 0;
}
secp256k1_ge_set_xy(elem, &x, &y);
if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) &&
secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) {
return 0;
}
return secp256k1_ge_is_valid_var(elem);
@@ -43,10 +42,10 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p
secp256k1_fe_get_b32(&pub[1], &elem->x);
if (compressed) {
*size = 33;
pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00);
} else {
*size = 65;
pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED;
pub[0] = 0x04;
secp256k1_fe_get_b32(&pub[33], &elem->y);
}
return 1;
@@ -54,7 +53,10 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
secp256k1_scalar_add(key, key, tweak);
return !secp256k1_scalar_is_zero(key);
if (secp256k1_scalar_is_zero(key)) {
return 0;
}
return 1;
}
static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {
@@ -72,11 +74,12 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx,
}
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
int ret;
ret = !secp256k1_scalar_is_zero(tweak);
if (secp256k1_scalar_is_zero(tweak)) {
return 0;
}
secp256k1_scalar_mul(key, key, tweak);
return ret;
return 1;
}
static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {
@@ -93,4 +96,4 @@ static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx,
return 1;
}
#endif /* SECP256K1_ECKEY_IMPL_H */
#endif

View File

@@ -1,46 +1,31 @@
/**********************************************************************
* Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra *
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECMULT_H
#define SECP256K1_ECMULT_H
#ifndef _SECP256K1_ECMULT_
#define _SECP256K1_ECMULT_
#include "num.h"
#include "group.h"
#include "scalar.h"
#include "scratch.h"
typedef struct {
/* For accelerating the computation of a*P + b*G: */
secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */
#ifdef USE_ENDOMORPHISM
secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */
#endif
} secp256k1_ecmult_context;
static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE;
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx);
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void **prealloc);
static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *dst, const secp256k1_ecmult_context *src);
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb);
static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,
const secp256k1_ecmult_context *src, const secp256k1_callback *cb);
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx);
static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx);
/** Double multiply: R = na*A + ng*G */
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data);
/**
* Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai.
* Chooses the right algorithm for a given number of points and scratch space
* size. Resets and overwrites the given scratch space. If the points do not
* fit in the scratch space the algorithm is repeatedly run with batches of
* points. If no scratch space is given then a simple algorithm is used that
* simply multiplies the points with the corresponding scalars and adds them up.
* Returns: 1 on success (including when inp_g_sc is NULL and n is 0)
* 0 if there is not enough scratch space for a single point or
* callback returns 0
*/
static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n);
#endif /* SECP256K1_ECMULT_H */
#endif

View File

@@ -4,17 +4,12 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECMULT_CONST_H
#define SECP256K1_ECMULT_CONST_H
#ifndef _SECP256K1_ECMULT_CONST_
#define _SECP256K1_ECMULT_CONST_
#include "scalar.h"
#include "group.h"
/**
* Multiply: R = q*A (in constant-time)
* Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus
* one because we internally sometimes add 2 to the number during the WNAF conversion.
*/
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits);
#endif /* SECP256K1_ECMULT_CONST_H */
#endif

View File

@@ -4,32 +4,28 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECMULT_CONST_IMPL_H
#define SECP256K1_ECMULT_CONST_IMPL_H
#ifndef _SECP256K1_ECMULT_CONST_IMPL_
#define _SECP256K1_ECMULT_CONST_IMPL_
#include "scalar.h"
#include "group.h"
#include "ecmult_const.h"
#include "ecmult_impl.h"
#define WNAF_SIZE(bits, w) (((bits) + (w) - 1) / (w))
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
int m = 0; \
/* Extract the sign-bit for a constant time absolute-value. */ \
int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
int abs_n = ((n) + mask) ^ mask; \
int idx_n = abs_n >> 1; \
int m; \
int abs_n = (n) * (((n) > 0) * 2 - 1); \
int idx_n = abs_n / 2; \
secp256k1_fe neg_y; \
VERIFY_CHECK(((n) & 1) == 1); \
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \
VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \
/* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one \
* or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \
(r)->x = (pre)[m].x; \
(r)->y = (pre)[m].y; \
for (m = 1; m < ECMULT_TABLE_SIZE(w); m++) { \
for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \
/* This loop is used to avoid secret data in array indices. See
* the comment in ecmult_gen_impl.h for rationale. */ \
secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \
@@ -41,20 +37,19 @@
} while(0)
/** Convert a number to WNAF notation.
* The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val.
* It has the following guarantees:
/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val)
* with the following guarantees:
* - each wnaf[i] an odd integer between -(1 << w) and (1 << w)
* - each wnaf[i] is nonzero
* - the number of words set is always WNAF_SIZE(w) + 1
* - the number of words set is returned; this is always (WNAF_BITS + w - 1) / w
*
* Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar
* Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.)
* CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlag Berlin Heidelberg 2003
* CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003
*
* Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
*/
static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w, int size) {
static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size, int maybe_negative) {
int global_sign;
int skew = 0;
int word = 0;
@@ -65,72 +60,64 @@ static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w
int flip;
int bit;
secp256k1_scalar s;
secp256k1_scalar neg_s;
int not_neg_one;
VERIFY_CHECK(w > 0);
VERIFY_CHECK(size > 0);
/* Note that we cannot handle even numbers by negating them to be odd, as is
* done in other implementations, since if our scalars were specified to have
* width < 256 for performance reasons, their negations would have width 256
* and we'd lose any performance benefit. Instead, we use a technique from
* Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
* or 2 (for odd) to the number we are encoding, returning a skew value indicating
* this, and having the caller compensate after doing the multiplication.
*
* In fact, we _do_ want to negate numbers to minimize their bit-lengths (and in
* particular, to ensure that the outputs from the endomorphism-split fit into
* 128 bits). If we negate, the parity of our number flips, inverting which of
* {1, 2} we want to add to the scalar when ensuring that it's odd. Further
* complicating things, -1 interacts badly with `secp256k1_scalar_cadd_bit` and
* we need to special-case it in this logic. */
flip = secp256k1_scalar_is_high(scalar);
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
bit = flip ^ !secp256k1_scalar_is_even(scalar);
/* We check for negative one, since adding 2 to it will cause an overflow */
secp256k1_scalar_negate(&s, scalar);
not_neg_one = !secp256k1_scalar_is_one(&s);
s = *scalar;
secp256k1_scalar_cadd_bit(&s, bit, not_neg_one);
/* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects
* that we added two to it and flipped it. In fact for -1 these operations are
* identical. We only flipped, but since skewing is required (in the sense that
* the skew must be 1 or 2, never zero) and flipping is not, we need to change
* our flags to claim that we only skewed. */
global_sign = secp256k1_scalar_cond_negate(&s, flip);
global_sign *= not_neg_one * 2 - 1;
skew = 1 << bit;
* this, and having the caller compensate after doing the multiplication. */
if (maybe_negative) {
/* Negative numbers will be negated to keep their bit representation below the maximum width */
flip = maybe_negative ? secp256k1_scalar_is_high(&s) : 0;
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
bit = flip ^ !secp256k1_scalar_is_even(&s);
/* We check for negative one, since adding 2 to it will cause an overflow */
secp256k1_scalar_negate(&neg_s, &s);
not_neg_one = !secp256k1_scalar_is_one(&neg_s);
secp256k1_scalar_cadd_bit(&s, bit, not_neg_one);
/* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects
* that we added two to it and flipped it. In fact for -1 these operations are
* identical. We only flipped, but since skewing is required (in the sense that
* the skew must be 1 or 2, never zero) and flipping is not, we need to change
* our flags to claim that we only skewed. */
global_sign = secp256k1_scalar_cond_negate(&s, flip);
global_sign *= not_neg_one * 2 - 1;
skew = 1 << bit;
} else {
VERIFY_CHECK(!secp256k1_scalar_is_high(&s));
bit = !secp256k1_scalar_is_even(&s);
skew = 1 << bit;
secp256k1_scalar_cadd_bit(&s, bit, 1);
global_sign = 1;
}
/* 4 */
u_last = secp256k1_scalar_shr_int(&s, w);
do {
int sign;
int even;
/* 4.1 4.4 */
u = secp256k1_scalar_shr_int(&s, w);
/* 4.2 */
even = ((u & 1) == 0);
/* In contrast to the original algorithm, u_last is always > 0 and
* therefore we do not need to check its sign. In particular, it's easy
* to see that u_last is never < 0 because u is never < 0. Moreover,
* u_last is never = 0 because u is never even after a loop
* iteration. The same holds analogously for the initial value of
* u_last (in the first loop iteration). */
VERIFY_CHECK(u_last > 0);
VERIFY_CHECK((u_last & 1) == 1);
u += even;
u_last -= even * (1 << w);
sign = 2 * (u_last > 0) - 1;
u += sign * even;
u_last -= sign * even * (1 << w);
/* 4.3, adapted for global sign change */
wnaf[word++] = u_last * global_sign;
u_last = u;
} while (word * w < size);
} while(word * w < size);
wnaf[word] = u * global_sign;
VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w));
VERIFY_CHECK(word == WNAF_SIZE(size, w));
return skew;
}
@@ -140,26 +127,35 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
secp256k1_fe Z;
int skew_1;
#ifdef USE_ENDOMORPHISM
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
int wnaf_1[1 + WNAF_SIZE(128, WINDOW_A - 1)];
int wnaf_lam[1 + WNAF_SIZE(128, WINDOW_A - 1)];
int skew_lam;
secp256k1_scalar q_1, q_lam;
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
#else
int wnaf_1[1 + WNAF_SIZE(256, WINDOW_A - 1)];
#endif
int i;
secp256k1_scalar sc = *scalar;
/* build wnaf representation for q. */
int rsize = size;
#ifdef USE_ENDOMORPHISM
if (size > 128) {
rsize = 128;
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar);
skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128);
skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128);
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1, 128, 1);
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1, 128, 1);
} else
#endif
{
skew_1 = secp256k1_wnaf_const(wnaf_1, scalar, WINDOW_A - 1, size);
skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1, size, size == 256);
#ifdef USE_ENDOMORPHISM
skew_lam = 0;
#endif
}
/* Calculate odd multiples of a.
@@ -173,44 +169,49 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
secp256k1_fe_normalize_weak(&pre_a[i].y);
}
#ifdef USE_ENDOMORPHISM
if (size > 128) {
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
}
}
#endif
/* first loop iteration (separated out so we can directly set r, rather
* than having it start at infinity, get doubled several times, then have
* its new value added to it) */
i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
i = wnaf_1[WNAF_SIZE(rsize, WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
secp256k1_gej_set_ge(r, &tmpa);
#ifdef USE_ENDOMORPHISM
if (size > 128) {
i = wnaf_lam[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
i = wnaf_lam[WNAF_SIZE(rsize, WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
secp256k1_gej_add_ge(r, r, &tmpa);
}
#endif
/* remaining loop iterations */
for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) {
for (i = WNAF_SIZE(rsize, WINDOW_A - 1) - 1; i >= 0; i--) {
int n;
int j;
for (j = 0; j < WINDOW_A - 1; ++j) {
secp256k1_gej_double(r, r);
secp256k1_gej_double_nonzero(r, r, NULL);
}
n = wnaf_1[i];
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
#ifdef USE_ENDOMORPHISM
if (size > 128) {
n = wnaf_lam[i];
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
}
#endif
}
secp256k1_fe_mul(&r->z, &r->z, &Z);
@@ -219,36 +220,44 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
/* Correct for wNAF skew */
secp256k1_ge correction = *a;
secp256k1_ge_storage correction_1_stor;
#ifdef USE_ENDOMORPHISM
secp256k1_ge_storage correction_lam_stor;
#endif
secp256k1_ge_storage a2_stor;
secp256k1_gej tmpj;
secp256k1_gej_set_ge(&tmpj, &correction);
secp256k1_gej_double_var(&tmpj, &tmpj, NULL);
secp256k1_ge_set_gej(&correction, &tmpj);
secp256k1_ge_to_storage(&correction_1_stor, a);
#ifdef USE_ENDOMORPHISM
if (size > 128) {
secp256k1_ge_to_storage(&correction_lam_stor, a);
}
#endif
secp256k1_ge_to_storage(&a2_stor, &correction);
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
#ifdef USE_ENDOMORPHISM
if (size > 128) {
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
}
#endif
/* Apply the correction */
secp256k1_ge_from_storage(&correction, &correction_1_stor);
secp256k1_ge_neg(&correction, &correction);
secp256k1_gej_add_ge(r, r, &correction);
#ifdef USE_ENDOMORPHISM
if (size > 128) {
secp256k1_ge_from_storage(&correction, &correction_lam_stor);
secp256k1_ge_neg(&correction, &correction);
secp256k1_ge_mul_lambda(&correction, &correction);
secp256k1_gej_add_ge(r, r, &correction);
}
#endif
}
}
#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
#endif

View File

@@ -4,41 +4,34 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECMULT_GEN_H
#define SECP256K1_ECMULT_GEN_H
#ifndef _SECP256K1_ECMULT_GEN_
#define _SECP256K1_ECMULT_GEN_
#include "scalar.h"
#include "group.h"
#if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8
# error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8."
#endif
#define ECMULT_GEN_PREC_B ECMULT_GEN_PREC_BITS
#define ECMULT_GEN_PREC_G (1 << ECMULT_GEN_PREC_B)
#define ECMULT_GEN_PREC_N (256 / ECMULT_GEN_PREC_B)
typedef struct {
/* For accelerating the computation of a*G:
* To harden against timing attacks, use the following mechanism:
* * Break up the multiplicand into groups of PREC_B bits, called n_0, n_1, n_2, ..., n_(PREC_N-1).
* * Compute sum(n_i * (PREC_G)^i * G + U_i, i=0 ... PREC_N-1), where:
* * U_i = U * 2^i, for i=0 ... PREC_N-2
* * U_i = U * (1-2^(PREC_N-1)), for i=PREC_N-1
* where U is a point with no known corresponding scalar. Note that sum(U_i, i=0 ... PREC_N-1) = 0.
* For each i, and each of the PREC_G possible values of n_i, (n_i * (PREC_G)^i * G + U_i) is
* precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0 ... PREC_N-1).
* * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63.
* * Compute sum(n_i * 16^i * G + U_i, i=0..63), where:
* * U_i = U * 2^i (for i=0..62)
* * U_i = U * (1-2^63) (for i=63)
* where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0.
* For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is
* precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63).
* None of the resulting prec group elements have a known scalar, and neither do any of
* the intermediate sums while computing a*G.
*/
secp256k1_ge_storage (*prec)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G]; /* prec[j][i] = (PREC_G)^j * i * G + U_i */
secp256k1_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */
secp256k1_scalar blind;
secp256k1_gej initial;
} secp256k1_ecmult_gen_context;
static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx);
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, void **prealloc);
static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context* src);
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb);
static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb);
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);
static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx);
@@ -47,4 +40,4 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp25
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32);
#endif /* SECP256K1_ECMULT_GEN_H */
#endif

View File

@@ -4,10 +4,9 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECMULT_GEN_IMPL_H
#define SECP256K1_ECMULT_GEN_IMPL_H
#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_
#define _SECP256K1_ECMULT_GEN_IMPL_H_
#include "util.h"
#include "scalar.h"
#include "group.h"
#include "ecmult_gen.h"
@@ -15,32 +14,23 @@
#ifdef USE_ECMULT_STATIC_PRECOMPUTATION
#include "ecmult_static_context.h"
#endif
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = ROUND_TO_ALIGN(sizeof(*((secp256k1_ecmult_gen_context*) NULL)->prec));
#else
static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = 0;
#endif
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) {
ctx->prec = NULL;
}
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, void **prealloc) {
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) {
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
secp256k1_ge prec[ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G];
secp256k1_ge prec[1024];
secp256k1_gej gj;
secp256k1_gej nums_gej;
int i, j;
size_t const prealloc_size = SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
void* const base = *prealloc;
#endif
if (ctx->prec != NULL) {
return;
}
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
ctx->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])manual_alloc(prealloc, prealloc_size, base, prealloc_size);
ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec));
/* get the generator */
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
@@ -64,39 +54,39 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx
/* compute prec. */
{
secp256k1_gej precj[ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G]; /* Jacobian versions of prec. */
secp256k1_gej precj[1024]; /* Jacobian versions of prec. */
secp256k1_gej gbase;
secp256k1_gej numsbase;
gbase = gj; /* PREC_G^j * G */
gbase = gj; /* 16^j * G */
numsbase = nums_gej; /* 2^j * nums. */
for (j = 0; j < ECMULT_GEN_PREC_N; j++) {
/* Set precj[j*PREC_G .. j*PREC_G+(PREC_G-1)] to (numsbase, numsbase + gbase, ..., numsbase + (PREC_G-1)*gbase). */
precj[j*ECMULT_GEN_PREC_G] = numsbase;
for (i = 1; i < ECMULT_GEN_PREC_G; i++) {
secp256k1_gej_add_var(&precj[j*ECMULT_GEN_PREC_G + i], &precj[j*ECMULT_GEN_PREC_G + i - 1], &gbase, NULL);
for (j = 0; j < 64; j++) {
/* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */
precj[j*16] = numsbase;
for (i = 1; i < 16; i++) {
secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL);
}
/* Multiply gbase by PREC_G. */
for (i = 0; i < ECMULT_GEN_PREC_B; i++) {
/* Multiply gbase by 16. */
for (i = 0; i < 4; i++) {
secp256k1_gej_double_var(&gbase, &gbase, NULL);
}
/* Multiply numbase by 2. */
secp256k1_gej_double_var(&numsbase, &numsbase, NULL);
if (j == ECMULT_GEN_PREC_N - 2) {
if (j == 62) {
/* In the last iteration, numsbase is (1 - 2^j) * nums instead. */
secp256k1_gej_neg(&numsbase, &numsbase);
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
}
}
secp256k1_ge_set_all_gej_var(prec, precj, ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G);
secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb);
}
for (j = 0; j < ECMULT_GEN_PREC_N; j++) {
for (i = 0; i < ECMULT_GEN_PREC_G; i++) {
secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*ECMULT_GEN_PREC_G + i]);
for (j = 0; j < 64; j++) {
for (i = 0; i < 16; i++) {
secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]);
}
}
#else
(void)prealloc;
ctx->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])secp256k1_ecmult_static_context;
(void)cb;
ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context;
#endif
secp256k1_ecmult_gen_blind(ctx, NULL);
}
@@ -105,18 +95,27 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont
return ctx->prec != NULL;
}
static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context *src) {
static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) {
if (src->prec == NULL) {
dst->prec = NULL;
} else {
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
if (src->prec != NULL) {
/* We cast to void* first to suppress a -Wcast-align warning. */
dst->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])(void*)((unsigned char*)dst + ((unsigned char*)src->prec - (unsigned char*)src));
}
dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec));
memcpy(dst->prec, src->prec, sizeof(*dst->prec));
#else
(void)dst, (void)src;
(void)cb;
dst->prec = src->prec;
#endif
dst->initial = src->initial;
dst->blind = src->blind;
}
}
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
free(ctx->prec);
#endif
secp256k1_scalar_clear(&ctx->blind);
secp256k1_gej_clear(&ctx->initial);
ctx->prec = NULL;
@@ -133,9 +132,9 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
/* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */
secp256k1_scalar_add(&gnb, gn, &ctx->blind);
add.infinity = 0;
for (j = 0; j < ECMULT_GEN_PREC_N; j++) {
bits = secp256k1_scalar_get_bits(&gnb, j * ECMULT_GEN_PREC_B, ECMULT_GEN_PREC_B);
for (i = 0; i < ECMULT_GEN_PREC_G; i++) {
for (j = 0; j < 64; j++) {
bits = secp256k1_scalar_get_bits(&gnb, j * 4, 4);
for (i = 0; i < 16; i++) {
/** This uses a conditional move to avoid any secret data in array indexes.
* _Any_ use of secret indexes has been demonstrated to result in timing
* sidechannels, even when the cache-line access patterns are uniform.
@@ -162,8 +161,8 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_gej gb;
secp256k1_fe s;
unsigned char nonce32[32];
secp256k1_rfc6979_hmac_sha256 rng;
int overflow;
secp256k1_rfc6979_hmac_sha256_t rng;
int retry;
unsigned char keydata[64] = {0};
if (seed32 == NULL) {
/* When seed is NULL, reset the initial point and blinding value. */
@@ -183,18 +182,21 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
}
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32);
memset(keydata, 0, sizeof(keydata));
/* Accept unobservably small non-uniformity. */
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
overflow = !secp256k1_fe_set_b32(&s, nonce32);
overflow |= secp256k1_fe_is_zero(&s);
secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
/* Retry for out of range results to achieve uniformity. */
do {
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
retry = !secp256k1_fe_set_b32(&s, nonce32);
retry |= secp256k1_fe_is_zero(&s);
} while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */
/* Randomize the projection to defend against multiplier sidechannels. */
secp256k1_gej_rescale(&ctx->initial, &s);
secp256k1_fe_clear(&s);
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
secp256k1_scalar_set_b32(&b, nonce32, NULL);
/* A blinding value of 0 works, but would undermine the projection hardening. */
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
do {
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
secp256k1_scalar_set_b32(&b, nonce32, &retry);
/* A blinding value of 0 works, but would undermine the projection hardening. */
retry |= secp256k1_scalar_is_zero(&b);
} while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
memset(nonce32, 0, 32);
secp256k1_ecmult_gen(ctx, &gb, &b);
@@ -205,4 +207,4 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_gej_clear(&gb);
}
#endif /* SECP256K1_ECMULT_GEN_IMPL_H */
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_FIELD_H
#define SECP256K1_FIELD_H
#ifndef _SECP256K1_FIELD_
#define _SECP256K1_FIELD_
/** Field element module.
*
@@ -22,22 +22,20 @@
#include "libsecp256k1-config.h"
#endif
#include "util.h"
#if defined(SECP256K1_WIDEMUL_INT128)
#include "field_5x52.h"
#elif defined(SECP256K1_WIDEMUL_INT64)
#if defined(USE_FIELD_10X26)
#include "field_10x26.h"
#elif defined(USE_FIELD_5X52)
#include "field_5x52.h"
#else
#error "Please select wide multiplication implementation"
#error "Please select field implementation"
#endif
/** 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`.
*/
#include "util.h"
/** Normalize a field element. */
static void secp256k1_fe_normalize(secp256k1_fe *r);
/** Weakly normalize a field element: reduce its magnitude to 1, but don't fully normalize. */
/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */
static void secp256k1_fe_normalize_weak(secp256k1_fe *r);
/** Normalize a field element, without constant-time guarantee. */
@@ -125,10 +123,10 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe
/** Convert a field element back from the storage type. */
static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
#endif /* SECP256K1_FIELD_H */
#endif

View File

@@ -4,15 +4,13 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_FIELD_REPR_H
#define SECP256K1_FIELD_REPR_H
#ifndef _SECP256K1_FIELD_REPR_
#define _SECP256K1_FIELD_REPR_
#include <stdint.h>
typedef struct {
/* X = sum(i=0..9, n[i]*2^(i*26)) mod p
* where p = 2^256 - 0x1000003D1
*/
/* X = sum(i=0..9, elem[i]*2^26) mod n */
uint32_t n[10];
#ifdef VERIFY
int magnitude;
@@ -46,5 +44,4 @@ typedef struct {
#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}
#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0]
#endif /* SECP256K1_FIELD_REPR_H */
#endif

View File

@@ -4,10 +4,11 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_FIELD_REPR_IMPL_H
#define SECP256K1_FIELD_REPR_IMPL_H
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
#define _SECP256K1_FIELD_REPR_IMPL_H_
#include "util.h"
#include "num.h"
#include "field.h"
#ifdef VERIFY
@@ -320,69 +321,45 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
}
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
int ret;
r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24);
r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22);
r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20);
r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18);
r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24);
r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22);
r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20);
r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18);
r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24);
r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14);
ret = !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));
int i;
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
for (i=0; i<32; i++) {
int j;
for (j=0; j<4; j++) {
int limb = (8*i+2*j)/26;
int shift = (8*i+2*j)%26;
r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift;
}
}
if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) {
return 0;
}
#ifdef VERIFY
r->magnitude = 1;
if (ret) {
r->normalized = 1;
secp256k1_fe_verify(r);
} else {
r->normalized = 0;
}
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
return ret;
return 1;
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
r[0] = (a->n[9] >> 14) & 0xff;
r[1] = (a->n[9] >> 6) & 0xff;
r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3);
r[3] = (a->n[8] >> 16) & 0xff;
r[4] = (a->n[8] >> 8) & 0xff;
r[5] = a->n[8] & 0xff;
r[6] = (a->n[7] >> 18) & 0xff;
r[7] = (a->n[7] >> 10) & 0xff;
r[8] = (a->n[7] >> 2) & 0xff;
r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f);
r[10] = (a->n[6] >> 12) & 0xff;
r[11] = (a->n[6] >> 4) & 0xff;
r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf);
r[13] = (a->n[5] >> 14) & 0xff;
r[14] = (a->n[5] >> 6) & 0xff;
r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3);
r[16] = (a->n[4] >> 16) & 0xff;
r[17] = (a->n[4] >> 8) & 0xff;
r[18] = a->n[4] & 0xff;
r[19] = (a->n[3] >> 18) & 0xff;
r[20] = (a->n[3] >> 10) & 0xff;
r[21] = (a->n[3] >> 2) & 0xff;
r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f);
r[23] = (a->n[2] >> 12) & 0xff;
r[24] = (a->n[2] >> 4) & 0xff;
r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf);
r[26] = (a->n[1] >> 14) & 0xff;
r[27] = (a->n[1] >> 6) & 0xff;
r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3);
r[29] = (a->n[0] >> 16) & 0xff;
r[30] = (a->n[0] >> 8) & 0xff;
r[31] = a->n[0] & 0xff;
for (i=0; i<32; i++) {
int j;
int c = 0;
for (j=0; j<4; j++) {
int limb = (8*i+2*j)/26;
int shift = (8*i+2*j)%26;
c |= ((a->n[limb] >> shift) & 0x3) << (2 * j);
}
r[31-i] = c;
}
}
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
@@ -488,8 +465,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
VERIFY_BITS(b[9], 26);
/** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n.
* for 0 <= x <= 9, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
* for 9 <= x <= 18, px is a shorthand for sum(a[i]*b[x-i], i=(x-9)..9)
* px is a shorthand for sum(a[i]*b[x-i], i=0..x).
* Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0].
*/
@@ -1072,7 +1048,6 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(r != b);
VERIFY_CHECK(a != b);
#endif
secp256k1_fe_mul_inner(r->n, a->n, b->n);
#ifdef VERIFY
@@ -1097,7 +1072,6 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint32_t mask0, mask1;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -1111,16 +1085,15 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);
r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);
#ifdef VERIFY
if (flag) {
if (a->magnitude > r->magnitude) {
r->magnitude = a->magnitude;
r->normalized = a->normalized;
}
r->normalized &= a->normalized;
#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));
mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -1164,4 +1137,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
#endif
}
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
#endif

View File

@@ -4,15 +4,13 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_FIELD_REPR_H
#define SECP256K1_FIELD_REPR_H
#ifndef _SECP256K1_FIELD_REPR_
#define _SECP256K1_FIELD_REPR_
#include <stdint.h>
typedef struct {
/* X = sum(i=0..4, n[i]*2^(i*52)) mod p
* where p = 2^256 - 0x1000003D1
*/
/* X = sum(i=0..4, elem[i]*2^52) mod n */
uint64_t n[5];
#ifdef VERIFY
int magnitude;
@@ -46,10 +44,4 @@ typedef struct {
(d6) | (((uint64_t)(d7)) << 32) \
}}
#define SECP256K1_FE_STORAGE_CONST_GET(d) \
(uint32_t)(d.n[3] >> 32), (uint32_t)d.n[3], \
(uint32_t)(d.n[2] >> 32), (uint32_t)d.n[2], \
(uint32_t)(d.n[1] >> 32), (uint32_t)d.n[1], \
(uint32_t)(d.n[0] >> 32), (uint32_t)d.n[0]
#endif /* SECP256K1_FIELD_REPR_H */
#endif

View File

@@ -11,8 +11,8 @@
* - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly
*/
#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
#define SECP256K1_FIELD_INNER5X52_IMPL_H
#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
/**
@@ -499,4 +499,4 @@ __asm__ __volatile__(
);
}
#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
#endif

View File

@@ -4,14 +4,15 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_FIELD_REPR_IMPL_H
#define SECP256K1_FIELD_REPR_IMPL_H
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
#define _SECP256K1_FIELD_REPR_IMPL_H_
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "util.h"
#include "num.h"
#include "field.h"
#if defined(USE_ASM_X86_64)
@@ -283,92 +284,44 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
}
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
int ret;
r->n[0] = (uint64_t)a[31]
| ((uint64_t)a[30] << 8)
| ((uint64_t)a[29] << 16)
| ((uint64_t)a[28] << 24)
| ((uint64_t)a[27] << 32)
| ((uint64_t)a[26] << 40)
| ((uint64_t)(a[25] & 0xF) << 48);
r->n[1] = (uint64_t)((a[25] >> 4) & 0xF)
| ((uint64_t)a[24] << 4)
| ((uint64_t)a[23] << 12)
| ((uint64_t)a[22] << 20)
| ((uint64_t)a[21] << 28)
| ((uint64_t)a[20] << 36)
| ((uint64_t)a[19] << 44);
r->n[2] = (uint64_t)a[18]
| ((uint64_t)a[17] << 8)
| ((uint64_t)a[16] << 16)
| ((uint64_t)a[15] << 24)
| ((uint64_t)a[14] << 32)
| ((uint64_t)a[13] << 40)
| ((uint64_t)(a[12] & 0xF) << 48);
r->n[3] = (uint64_t)((a[12] >> 4) & 0xF)
| ((uint64_t)a[11] << 4)
| ((uint64_t)a[10] << 12)
| ((uint64_t)a[9] << 20)
| ((uint64_t)a[8] << 28)
| ((uint64_t)a[7] << 36)
| ((uint64_t)a[6] << 44);
r->n[4] = (uint64_t)a[5]
| ((uint64_t)a[4] << 8)
| ((uint64_t)a[3] << 16)
| ((uint64_t)a[2] << 24)
| ((uint64_t)a[1] << 32)
| ((uint64_t)a[0] << 40);
ret = !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
int i;
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
for (i=0; i<32; i++) {
int j;
for (j=0; j<2; j++) {
int limb = (8*i+4*j)/52;
int shift = (8*i+4*j)%52;
r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
}
}
if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) {
return 0;
}
#ifdef VERIFY
r->magnitude = 1;
if (ret) {
r->normalized = 1;
secp256k1_fe_verify(r);
} else {
r->normalized = 0;
}
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
return ret;
return 1;
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
r[0] = (a->n[4] >> 40) & 0xFF;
r[1] = (a->n[4] >> 32) & 0xFF;
r[2] = (a->n[4] >> 24) & 0xFF;
r[3] = (a->n[4] >> 16) & 0xFF;
r[4] = (a->n[4] >> 8) & 0xFF;
r[5] = a->n[4] & 0xFF;
r[6] = (a->n[3] >> 44) & 0xFF;
r[7] = (a->n[3] >> 36) & 0xFF;
r[8] = (a->n[3] >> 28) & 0xFF;
r[9] = (a->n[3] >> 20) & 0xFF;
r[10] = (a->n[3] >> 12) & 0xFF;
r[11] = (a->n[3] >> 4) & 0xFF;
r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4);
r[13] = (a->n[2] >> 40) & 0xFF;
r[14] = (a->n[2] >> 32) & 0xFF;
r[15] = (a->n[2] >> 24) & 0xFF;
r[16] = (a->n[2] >> 16) & 0xFF;
r[17] = (a->n[2] >> 8) & 0xFF;
r[18] = a->n[2] & 0xFF;
r[19] = (a->n[1] >> 44) & 0xFF;
r[20] = (a->n[1] >> 36) & 0xFF;
r[21] = (a->n[1] >> 28) & 0xFF;
r[22] = (a->n[1] >> 20) & 0xFF;
r[23] = (a->n[1] >> 12) & 0xFF;
r[24] = (a->n[1] >> 4) & 0xFF;
r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4);
r[26] = (a->n[0] >> 40) & 0xFF;
r[27] = (a->n[0] >> 32) & 0xFF;
r[28] = (a->n[0] >> 24) & 0xFF;
r[29] = (a->n[0] >> 16) & 0xFF;
r[30] = (a->n[0] >> 8) & 0xFF;
r[31] = a->n[0] & 0xFF;
for (i=0; i<32; i++) {
int j;
int c = 0;
for (j=0; j<2; j++) {
int limb = (8*i+4*j)/52;
int shift = (8*i+4*j)%52;
c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
}
r[31-i] = c;
}
}
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
@@ -424,7 +377,6 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(r != b);
VERIFY_CHECK(a != b);
#endif
secp256k1_fe_mul_inner(r->n, a->n, b->n);
#ifdef VERIFY
@@ -449,7 +401,6 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint64_t mask0, mask1;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = flag + ~((uint64_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -458,16 +409,15 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
#ifdef VERIFY
if (flag) {
if (a->magnitude > r->magnitude) {
r->magnitude = a->magnitude;
r->normalized = a->normalized;
}
r->normalized &= a->normalized;
#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));
mask0 = flag + ~((uint64_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@@ -498,4 +448,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
#endif
}
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
#endif

View File

@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
#define SECP256K1_FIELD_INNER5X52_IMPL_H
#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
#include <stdint.h>
@@ -32,11 +32,9 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
VERIFY_BITS(b[3], 56);
VERIFY_BITS(b[4], 52);
VERIFY_CHECK(r != b);
VERIFY_CHECK(a != b);
/* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
* for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
* for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4)
* px is a shorthand for sum(a[i]*b[x-i], i=0..x).
* Note that [x 0 0 0 0 0] = [x*R].
*/
@@ -276,4 +274,4 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
#endif

View File

@@ -4,22 +4,21 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_FIELD_IMPL_H
#define SECP256K1_FIELD_IMPL_H
#ifndef _SECP256K1_FIELD_IMPL_H_
#define _SECP256K1_FIELD_IMPL_H_
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "util.h"
#include "num.h"
#if defined(SECP256K1_WIDEMUL_INT128)
#include "field_5x52_impl.h"
#elif defined(SECP256K1_WIDEMUL_INT64)
#if defined(USE_FIELD_10X26)
#include "field_10x26_impl.h"
#elif defined(USE_FIELD_5X52)
#include "field_5x52_impl.h"
#else
#error "Please select wide multiplication implementation"
#error "Please select field implementation"
#endif
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
@@ -49,8 +48,6 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
int j;
VERIFY_CHECK(r != a);
/** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
* { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
* 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
@@ -315,6 +312,4 @@ static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
#endif
}
static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
#endif /* SECP256K1_FIELD_IMPL_H */
#endif

View File

@@ -4,17 +4,10 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
// Autotools creates libsecp256k1-config.h, of which ECMULT_GEN_PREC_BITS is needed.
// ifndef guard so downstream users can define their own if they do not use autotools.
#if !defined(ECMULT_GEN_PREC_BITS)
#include "libsecp256k1-config.h"
#endif
#define USE_BASIC_CONFIG 1
#include "basic-config.h"
#include "basic-config.h"
#include "include/secp256k1.h"
#include "assumptions.h"
#include "util.h"
#include "field_impl.h"
#include "scalar_impl.h"
#include "group_impl.h"
@@ -33,7 +26,6 @@ static const secp256k1_callback default_error_callback = {
int main(int argc, char **argv) {
secp256k1_ecmult_gen_context ctx;
void *prealloc, *base;
int inner;
int outer;
FILE* fp;
@@ -46,31 +38,26 @@ int main(int argc, char **argv) {
fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n");
return -1;
}
fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
fprintf(fp, "#include \"src/group.h\"\n");
fprintf(fp, "#include \"group.h\"\n");
fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n");
fprintf(fp, "#if ECMULT_GEN_PREC_N != %d || ECMULT_GEN_PREC_G != %d\n", ECMULT_GEN_PREC_N, ECMULT_GEN_PREC_G);
fprintf(fp, " #error configuration mismatch, invalid ECMULT_GEN_PREC_N, ECMULT_GEN_PREC_G. Try deleting ecmult_static_context.h before the build.\n");
fprintf(fp, "#endif\n");
fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G] = {\n");
fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n");
base = checked_malloc(&default_error_callback, SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE);
prealloc = base;
secp256k1_ecmult_gen_context_init(&ctx);
secp256k1_ecmult_gen_context_build(&ctx, &prealloc);
for(outer = 0; outer != ECMULT_GEN_PREC_N; outer++) {
secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback);
for(outer = 0; outer != 64; outer++) {
fprintf(fp,"{\n");
for(inner = 0; inner != ECMULT_GEN_PREC_G; inner++) {
for(inner = 0; inner != 16; inner++) {
fprintf(fp," SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner]));
if (inner != ECMULT_GEN_PREC_G - 1) {
if (inner != 15) {
fprintf(fp,",\n");
} else {
fprintf(fp,"\n");
}
}
if (outer != ECMULT_GEN_PREC_N - 1) {
if (outer != 63) {
fprintf(fp,"},\n");
} else {
fprintf(fp,"}\n");
@@ -78,11 +65,10 @@ int main(int argc, char **argv) {
}
fprintf(fp,"};\n");
secp256k1_ecmult_gen_context_clear(&ctx);
free(base);
fprintf(fp, "#undef SC\n");
fprintf(fp, "#endif\n");
fclose(fp);
return 0;
}

View File

@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_GROUP_H
#define SECP256K1_GROUP_H
#ifndef _SECP256K1_GROUP_
#define _SECP256K1_GROUP_
#include "num.h"
#include "field.h"
@@ -59,14 +59,18 @@ static int secp256k1_ge_is_infinity(const secp256k1_ge *a);
/** Check whether a group element is valid (i.e., on the curve). */
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a);
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a);
/** Set a group element equal to another which is given in jacobian coordinates */
static void secp256k1_ge_set_gej(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);
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb);
/** Set a batch of group elements equal to the inputs given in jacobian
* coordinates (with known z-ratios). zr must contain the known z-ratios such
* that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */
static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, 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
@@ -75,9 +79,6 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
* 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);
/** Set a group element (affine) equal to the point at infinity. */
static void secp256k1_ge_set_infinity(secp256k1_ge *r);
/** Set a group element (jacobian) equal to the point at infinity. */
static void secp256k1_gej_set_infinity(secp256k1_gej *r);
@@ -96,13 +97,14 @@ static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
/** Check whether a group element's y coordinate is a quadratic residue. */
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a);
/** Set r equal to the double of a. Constant time. */
static void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a);
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0).
* a may not be zero. Constant time. */
static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
/** Set r equal to the double of a. If rzr is not-NULL this sets *rzr such that r->z == a->z * *rzr (where infinity means an implicit z = 0). */
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
/** Set r equal to the sum of a and b. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */
/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr);
/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */
@@ -110,14 +112,16 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient
than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time
guarantee, and b is allowed to be infinity. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */
guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr);
/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */
static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv);
#ifdef USE_ENDOMORPHISM
/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a);
#endif
/** Clear a secp256k1_gej to prevent leaking sensitive information. */
static void secp256k1_gej_clear(secp256k1_gej *r);
@@ -131,21 +135,10 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge
/** Convert a group element back from the storage type. */
static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a);
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag);
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve.
*
* In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the
* group, and this function returns always true.
*
* When compiling in exhaustive test mode, a slightly different curve equation is used, leading to a group with a
* (very) small subgroup, and that subgroup is what is used for all cryptographic operations. In that mode, this
* function checks whether a point that is on the curve is in fact also in that subgroup.
*/
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
#endif /* SECP256K1_GROUP_H */
#endif

View File

@@ -4,45 +4,56 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_GROUP_IMPL_H
#define SECP256K1_GROUP_IMPL_H
#ifndef _SECP256K1_GROUP_IMPL_H_
#define _SECP256K1_GROUP_IMPL_H_
#include "num.h"
#include "field.h"
#include "group.h"
/* These exhaustive group test orders and generators are chosen such that:
* - The field size is equal to that of secp256k1, so field code is the same.
* - The curve equation is of the form y^2=x^3+B for some constant B.
* - The subgroup has a generator 2*P, where P.x=1.
* - The subgroup has size less than 1000 to permit exhaustive testing.
* - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).
/* These points can be generated in sage as follows:
*
* These parameters are generated using sage/gen_exhaustive_groups.sage.
* 0. Setup a worksheet with the following parameters.
* b = 4 # whatever CURVE_B will be set to
* F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
* C = EllipticCurve ([F (0), F (b)])
*
* 1. Determine all the small orders available to you. (If there are
* no satisfactory ones, go back and change b.)
* print C.order().factor(limit=1000)
*
* 2. Choose an order as one of the prime factors listed in the above step.
* (You can also multiply some to get a composite order, though the
* tests will crash trying to invert scalars during signing.) We take a
* random point and scale it to drop its order to the desired value.
* There is some probability this won't work; just try again.
* order = 199
* P = C.random_point()
* P = (int(P.order()) / int(order)) * P
* assert(P.order() == order)
*
* 3. Print the values. You'll need to use a vim macro or something to
* split the hex output into 4-byte chunks.
* print "%x %x" % P.xy()
*/
#if defined(EXHAUSTIVE_TEST_ORDER)
# if EXHAUSTIVE_TEST_ORDER == 13
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0xc3459c3d, 0x35326167, 0xcd86cce8, 0x07a2417f,
0x5b8bd567, 0xde8538ee, 0x0d507b0c, 0xd128f5bb,
0x8e467fec, 0xcd30000a, 0x6cc1184e, 0x25d382c2,
0xa2f4494e, 0x2fbe9abc, 0x8b64abac, 0xd005fb24
# if EXHAUSTIVE_TEST_ORDER == 199
const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069,
0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18,
0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868,
0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED
);
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(
0x3d3486b2, 0x159a9ca5, 0xc75638be, 0xb23a69bc,
0x946a45ab, 0x24801247, 0xb4ed2b8e, 0x26b6a417
);
# elif EXHAUSTIVE_TEST_ORDER == 199
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0x226e653f, 0xc8df7744, 0x9bacbf12, 0x7d1dcbf9,
0x87f05b2a, 0xe7edbd28, 0x1f564575, 0xc48dcf18,
0xa13872c2, 0xe933bb17, 0x5d9ffd5b, 0xb5b6e10c,
0x57fe3c00, 0xbaaaa15a, 0xe003ec3e, 0x9c269bae
);
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(
0x2cca28fa, 0xfc614b80, 0x2a3db42b, 0x00ba00b1,
0xbea8d943, 0xdace9ab2, 0x9536daea, 0x0074defb
const int CURVE_B = 4;
# elif EXHAUSTIVE_TEST_ORDER == 13
const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0,
0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15,
0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e,
0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac
);
const int CURVE_B = 2;
# else
# error No known generator for the specified exhaustive test group order.
# endif
@@ -57,7 +68,7 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
);
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7);
const int CURVE_B = 7;
#endif
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
@@ -115,43 +126,46 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
r->y = a->y;
}
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
secp256k1_fe u;
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) {
secp256k1_fe *az;
secp256k1_fe *azi;
size_t i;
size_t last_i = SIZE_MAX;
size_t count = 0;
az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len);
for (i = 0; i < len; i++) {
if (!a[i].infinity) {
/* Use destination's x coordinates as scratch space */
if (last_i == SIZE_MAX) {
r[i].x = a[i].z;
} else {
secp256k1_fe_mul(&r[i].x, &r[last_i].x, &a[i].z);
}
last_i = i;
az[count++] = a[i].z;
}
}
if (last_i == SIZE_MAX) {
return;
}
secp256k1_fe_inv_var(&u, &r[last_i].x);
i = last_i;
while (i > 0) {
i--;
if (!a[i].infinity) {
secp256k1_fe_mul(&r[last_i].x, &r[i].x, &u);
secp256k1_fe_mul(&u, &u, &a[last_i].z);
last_i = i;
}
}
VERIFY_CHECK(!a[last_i].infinity);
r[last_i].x = u;
azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count);
secp256k1_fe_inv_all_var(azi, az, count);
free(az);
count = 0;
for (i = 0; i < len; i++) {
r[i].infinity = a[i].infinity;
if (!a[i].infinity) {
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]);
}
}
free(azi);
}
static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) {
size_t i = len - 1;
secp256k1_fe zi;
if (len > 0) {
/* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */
secp256k1_fe_inv(&zi, &a[i].z);
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
/* Work out way backwards, using the z-ratios to scale the x/y values. */
while (i > 0) {
secp256k1_fe_mul(&zi, &zi, &zr[i]);
i--;
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
}
}
}
@@ -164,8 +178,6 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp
/* 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;
zs = zr[i];
@@ -188,12 +200,6 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
secp256k1_fe_clear(&r->z);
}
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
r->infinity = 1;
secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y);
}
static void secp256k1_gej_clear(secp256k1_gej *r) {
r->infinity = 0;
secp256k1_fe_clear(&r->x);
@@ -208,13 +214,14 @@ static void secp256k1_ge_clear(secp256k1_ge *r) {
}
static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
secp256k1_fe x2, x3;
secp256k1_fe x2, x3, c;
r->x = *x;
secp256k1_fe_sqr(&x2, x);
secp256k1_fe_mul(&x3, x, &x2);
r->infinity = 0;
secp256k1_fe_add(&x3, &secp256k1_fe_const_b);
return secp256k1_fe_sqrt(&r->y, &x3);
secp256k1_fe_set_int(&c, CURVE_B);
secp256k1_fe_add(&c, &x3);
return secp256k1_fe_sqrt(&r->y, &c);
}
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
@@ -257,20 +264,41 @@ static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
return a->infinity;
}
static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) {
secp256k1_fe y2, x3, z2, z6;
if (a->infinity) {
return 0;
}
/** y^2 = x^3 + 7
* (Y/Z^3)^2 = (X/Z^2)^3 + 7
* Y^2 / Z^6 = X^3 / Z^6 + 7
* Y^2 = X^3 + 7*Z^6
*/
secp256k1_fe_sqr(&y2, &a->y);
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
secp256k1_fe_sqr(&z2, &a->z);
secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
secp256k1_fe_mul_int(&z6, CURVE_B);
secp256k1_fe_add(&x3, &z6);
secp256k1_fe_normalize_weak(&x3);
return secp256k1_fe_equal_var(&y2, &x3);
}
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
secp256k1_fe y2, x3;
secp256k1_fe y2, x3, c;
if (a->infinity) {
return 0;
}
/* y^2 = x^3 + 7 */
secp256k1_fe_sqr(&y2, &a->y);
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
secp256k1_fe_add(&x3, &secp256k1_fe_const_b);
secp256k1_fe_set_int(&c, CURVE_B);
secp256k1_fe_add(&x3, &c);
secp256k1_fe_normalize_weak(&x3);
return secp256k1_fe_equal_var(&y2, &x3);
}
static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) {
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
/* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
*
* Note that there is an implementation described at
@@ -279,8 +307,29 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
* mainly because it requires more normalizations.
*/
secp256k1_fe t1,t2,t3,t4;
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
*
* Having said this, if this function receives a point on a sextic twist, e.g. by
* a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
* since -6 does have a cube root mod p. For this point, this function will not set
* the infinity flag even though the point doubles to infinity, and the result
* point will be gibberish (z = 0 but infinity = 0).
*/
r->infinity = a->infinity;
if (r->infinity) {
if (rzr != NULL) {
secp256k1_fe_set_int(rzr, 1);
}
return;
}
if (rzr != NULL) {
*rzr = a->y;
secp256k1_fe_normalize_weak(rzr);
secp256k1_fe_mul_int(rzr, 2);
}
secp256k1_fe_mul(&r->z, &a->z, &a->y);
secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */
@@ -304,32 +353,9 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
}
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
*
* Having said this, if this function receives a point on a sextic twist, e.g. by
* a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
* since -6 does have a cube root mod p. For this point, this function will not set
* the infinity flag even though the point doubles to infinity, and the result
* point will be gibberish (z = 0 but infinity = 0).
*/
if (a->infinity) {
r->infinity = 1;
if (rzr != NULL) {
secp256k1_fe_set_int(rzr, 1);
}
return;
}
if (rzr != NULL) {
*rzr = a->y;
secp256k1_fe_normalize_weak(rzr);
secp256k1_fe_mul_int(rzr, 2);
}
secp256k1_gej_double(r, a);
static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
VERIFY_CHECK(!secp256k1_gej_is_infinity(a));
secp256k1_gej_double_var(r, a, rzr);
}
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
@@ -366,7 +392,7 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
if (rzr != NULL) {
secp256k1_fe_set_int(rzr, 0);
}
secp256k1_gej_set_infinity(r);
r->infinity = 1;
}
return;
}
@@ -416,7 +442,7 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
if (rzr != NULL) {
secp256k1_fe_set_int(rzr, 0);
}
secp256k1_gej_set_infinity(r);
r->infinity = 1;
}
return;
}
@@ -475,7 +501,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
secp256k1_gej_double_var(r, a, NULL);
} else {
secp256k1_gej_set_infinity(r);
r->infinity = 1;
}
return;
}
@@ -646,6 +672,7 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r,
secp256k1_fe_storage_cmov(&r->y, &a->y, flag);
}
#ifdef USE_ENDOMORPHISM
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,
@@ -654,6 +681,7 @@ static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
*r = *a;
secp256k1_fe_mul(&r->x, &r->x, &beta);
}
#endif
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
secp256k1_fe yz;
@@ -669,25 +697,4 @@ static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
return secp256k1_fe_is_quad_var(&yz);
}
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
#ifdef EXHAUSTIVE_TEST_ORDER
secp256k1_gej out;
int i;
/* A very simple EC multiplication ladder that avoids a dependecy on ecmult. */
secp256k1_gej_set_infinity(&out);
for (i = 0; i < 32; ++i) {
secp256k1_gej_double_var(&out, &out, NULL);
if ((((uint32_t)EXHAUSTIVE_TEST_ORDER) >> (31 - i)) & 1) {
secp256k1_gej_add_ge_var(&out, &out, ge, NULL);
}
}
return secp256k1_gej_is_infinity(&out);
#else
(void)ge;
/* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */
return 1;
#endif
}
#endif /* SECP256K1_GROUP_IMPL_H */

View File

@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_HASH_H
#define SECP256K1_HASH_H
#ifndef _SECP256K1_HASH_
#define _SECP256K1_HASH_
#include <stdlib.h>
#include <stdint.h>
@@ -14,28 +14,28 @@ typedef struct {
uint32_t s[8];
uint32_t buf[16]; /* In big endian */
size_t bytes;
} secp256k1_sha256;
} secp256k1_sha256_t;
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size);
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32);
static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash);
static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size);
static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32);
typedef struct {
secp256k1_sha256 inner, outer;
} secp256k1_hmac_sha256;
secp256k1_sha256_t inner, outer;
} secp256k1_hmac_sha256_t;
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size);
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size);
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32);
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size);
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size);
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32);
typedef struct {
unsigned char v[32];
unsigned char k[32];
int retry;
} secp256k1_rfc6979_hmac_sha256;
} secp256k1_rfc6979_hmac_sha256_t;
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen);
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen);
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng);
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen);
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen);
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng);
#endif /* SECP256K1_HASH_H */
#endif

View File

@@ -4,11 +4,10 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_HASH_IMPL_H
#define SECP256K1_HASH_IMPL_H
#ifndef _SECP256K1_HASH_IMPL_H_
#define _SECP256K1_HASH_IMPL_H_
#include "hash.h"
#include "util.h"
#include <stdlib.h>
#include <stdint.h>
@@ -28,13 +27,13 @@
(h) = t1 + t2; \
} while(0)
#if defined(SECP256K1_BIG_ENDIAN)
#ifdef WORDS_BIGENDIAN
#define BE32(x) (x)
#elif defined(SECP256K1_LITTLE_ENDIAN)
#else
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#endif
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) {
hash->s[0] = 0x6a09e667ul;
hash->s[1] = 0xbb67ae85ul;
hash->s[2] = 0x3c6ef372ul;
@@ -129,16 +128,14 @@ static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) {
s[7] += h;
}
static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) {
static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) {
size_t bufsize = hash->bytes & 0x3F;
hash->bytes += len;
VERIFY_CHECK(hash->bytes >= len);
while (len >= 64 - bufsize) {
while (bufsize + len >= 64) {
/* Fill the buffer, and process it. */
size_t chunk_len = 64 - bufsize;
memcpy(((unsigned char*)hash->buf) + bufsize, data, chunk_len);
data += chunk_len;
len -= chunk_len;
memcpy(((unsigned char*)hash->buf) + bufsize, data, 64 - bufsize);
data += 64 - bufsize;
len -= 64 - bufsize;
secp256k1_sha256_transform(hash->s, hash->buf);
bufsize = 0;
}
@@ -148,7 +145,7 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
}
}
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) {
static void secp256k1_sha256_finalize(secp256k1_sha256_t *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];
@@ -164,27 +161,14 @@ static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out
memcpy(out32, (const unsigned char*)out, 32);
}
/* Initializes a sha256 struct and writes the 64 byte string
* SHA256(tag)||SHA256(tag) into it. */
static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) {
unsigned char buf[32];
secp256k1_sha256_initialize(hash);
secp256k1_sha256_write(hash, tag, taglen);
secp256k1_sha256_finalize(hash, buf);
secp256k1_sha256_initialize(hash);
secp256k1_sha256_write(hash, buf, 32);
secp256k1_sha256_write(hash, buf, 32);
}
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
size_t n;
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) {
int n;
unsigned char rkey[64];
if (keylen <= sizeof(rkey)) {
if (keylen <= 64) {
memcpy(rkey, key, keylen);
memset(rkey + keylen, 0, sizeof(rkey) - keylen);
memset(rkey + keylen, 0, 64 - keylen);
} else {
secp256k1_sha256 sha256;
secp256k1_sha256_t sha256;
secp256k1_sha256_initialize(&sha256);
secp256k1_sha256_write(&sha256, key, keylen);
secp256k1_sha256_finalize(&sha256, rkey);
@@ -192,24 +176,24 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const
}
secp256k1_sha256_initialize(&hash->outer);
for (n = 0; n < sizeof(rkey); n++) {
for (n = 0; n < 64; n++) {
rkey[n] ^= 0x5c;
}
secp256k1_sha256_write(&hash->outer, rkey, sizeof(rkey));
secp256k1_sha256_write(&hash->outer, rkey, 64);
secp256k1_sha256_initialize(&hash->inner);
for (n = 0; n < sizeof(rkey); n++) {
for (n = 0; n < 64; n++) {
rkey[n] ^= 0x5c ^ 0x36;
}
secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey));
memset(rkey, 0, sizeof(rkey));
secp256k1_sha256_write(&hash->inner, rkey, 64);
memset(rkey, 0, 64);
}
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) {
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) {
secp256k1_sha256_write(&hash->inner, data, size);
}
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) {
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) {
unsigned char temp[32];
secp256k1_sha256_finalize(&hash->inner, temp);
secp256k1_sha256_write(&hash->outer, temp, 32);
@@ -218,8 +202,8 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned
}
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) {
secp256k1_hmac_sha256 hmac;
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) {
secp256k1_hmac_sha256_t hmac;
static const unsigned char zero[1] = {0x00};
static const unsigned char one[1] = {0x01};
@@ -248,11 +232,11 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2
rng->retry = 0;
}
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) {
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) {
/* RFC6979 3.2.h. */
static const unsigned char zero[1] = {0x00};
if (rng->retry) {
secp256k1_hmac_sha256 hmac;
secp256k1_hmac_sha256_t hmac;
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
secp256k1_hmac_sha256_write(&hmac, zero, 1);
@@ -263,7 +247,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256
}
while (outlen > 0) {
secp256k1_hmac_sha256 hmac;
secp256k1_hmac_sha256_t hmac;
int now = outlen;
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
@@ -279,7 +263,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256
rng->retry = 1;
}
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) {
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) {
memset(rng->k, 0, 32);
memset(rng->v, 0, 32);
rng->retry = 0;
@@ -294,4 +278,4 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
#undef Maj
#undef Ch
#endif /* SECP256K1_HASH_IMPL_H */
#endif

View File

@@ -0,0 +1,446 @@
/*
* Copyright 2013 Google Inc.
* Copyright 2014-2016 the libsecp256k1 contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoin;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.math.BigInteger;
import com.google.common.base.Preconditions;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import static org.bitcoin.NativeSecp256k1Util.*;
/**
* <p>This class holds native methods to handle ECDSA verification.</p>
*
* <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
*
* <p>To build secp256k1 for use with bitcoinj, run
* `./configure --enable-jni --enable-experimental --enable-module-ecdh`
* and `make` then copy `.libs/libsecp256k1.so` to your system library path
* or point the JVM to the folder containing it with -Djava.library.path
* </p>
*/
public class NativeSecp256k1 {
private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private static final Lock r = rwl.readLock();
private static final Lock w = rwl.writeLock();
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
/**
* Verifies the given secp256k1 signature in native code.
* Calling when enabled == false is undefined (probably library not loaded)
*
* @param data The data which was signed, must be exactly 32 bytes
* @param signature The signature
* @param pub The public key which did the signing
*/
public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null || byteBuff.capacity() < 520) {
byteBuff = ByteBuffer.allocateDirect(520);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(data);
byteBuff.put(signature);
byteBuff.put(pub);
byte[][] retByteArray;
r.lock();
try {
return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
} finally {
r.unlock();
}
}
/**
* libsecp256k1 Create an ECDSA signature.
*
* @param data Message hash, 32 bytes
* @param key Secret key, 32 bytes
*
* Return values
* @param sig byte array of signature
*/
public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
byteBuff = ByteBuffer.allocateDirect(32 + 32);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(data);
byteBuff.put(sec);
byte[][] retByteArray;
r.lock();
try {
retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
} finally {
r.unlock();
}
byte[] sigArr = retByteArray[0];
int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
assertEquals(sigArr.length, sigLen, "Got bad signature length.");
return retVal == 0 ? new byte[0] : sigArr;
}
/**
* libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
*
* @param seckey ECDSA Secret key, 32 bytes
*/
public static boolean secKeyVerify(byte[] seckey) {
Preconditions.checkArgument(seckey.length == 32);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null || byteBuff.capacity() < seckey.length) {
byteBuff = ByteBuffer.allocateDirect(seckey.length);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(seckey);
r.lock();
try {
return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;
} finally {
r.unlock();
}
}
/**
* libsecp256k1 Compute Pubkey - computes public key from secret key
*
* @param seckey ECDSA Secret key, 32 bytes
*
* Return values
* @param pubkey ECDSA Public key, 33 or 65 bytes
*/
//TODO add a 'compressed' arg
public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
Preconditions.checkArgument(seckey.length == 32);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null || byteBuff.capacity() < seckey.length) {
byteBuff = ByteBuffer.allocateDirect(seckey.length);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(seckey);
byte[][] retByteArray;
r.lock();
try {
retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
} finally {
r.unlock();
}
byte[] pubArr = retByteArray[0];
int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
return retVal == 0 ? new byte[0]: pubArr;
}
/**
* libsecp256k1 Cleanup - This destroys the secp256k1 context object
* This should be called at the end of the program for proper cleanup of the context.
*/
public static synchronized void cleanup() {
w.lock();
try {
secp256k1_destroy_context(Secp256k1Context.getContext());
} finally {
w.unlock();
}
}
public static long cloneContext() {
r.lock();
try {
return secp256k1_ctx_clone(Secp256k1Context.getContext());
} finally { r.unlock(); }
}
/**
* libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
*
* @param tweak some bytes to tweak with
* @param seckey 32-byte seckey
*/
public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
Preconditions.checkArgument(privkey.length == 32);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(privkey);
byteBuff.put(tweak);
byte[][] retByteArray;
r.lock();
try {
retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
} finally {
r.unlock();
}
byte[] privArr = retByteArray[0];
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
assertEquals(privArr.length, privLen, "Got bad pubkey length.");
assertEquals(retVal, 1, "Failed return value check.");
return privArr;
}
/**
* libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
*
* @param tweak some bytes to tweak with
* @param seckey 32-byte seckey
*/
public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
Preconditions.checkArgument(privkey.length == 32);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(privkey);
byteBuff.put(tweak);
byte[][] retByteArray;
r.lock();
try {
retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
} finally {
r.unlock();
}
byte[] privArr = retByteArray[0];
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
assertEquals(privArr.length, privLen, "Got bad pubkey length.");
assertEquals(retVal, 1, "Failed return value check.");
return privArr;
}
/**
* libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
*
* @param tweak some bytes to tweak with
* @param pubkey 32-byte seckey
*/
public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(pubkey);
byteBuff.put(tweak);
byte[][] retByteArray;
r.lock();
try {
retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
} finally {
r.unlock();
}
byte[] pubArr = retByteArray[0];
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
assertEquals(retVal, 1, "Failed return value check.");
return pubArr;
}
/**
* libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
*
* @param tweak some bytes to tweak with
* @param pubkey 32-byte seckey
*/
public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(pubkey);
byteBuff.put(tweak);
byte[][] retByteArray;
r.lock();
try {
retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
} finally {
r.unlock();
}
byte[] pubArr = retByteArray[0];
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
assertEquals(retVal, 1, "Failed return value check.");
return pubArr;
}
/**
* libsecp256k1 create ECDH secret - constant time ECDH calculation
*
* @param seckey byte array of secret key used in exponentiaion
* @param pubkey byte array of public key used in exponentiaion
*/
public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(seckey);
byteBuff.put(pubkey);
byte[][] retByteArray;
r.lock();
try {
retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
} finally {
r.unlock();
}
byte[] resArr = retByteArray[0];
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
assertEquals(resArr.length, 32, "Got bad result length.");
assertEquals(retVal, 1, "Failed return value check.");
return resArr;
}
/**
* libsecp256k1 randomize - updates the context randomization
*
* @param seed 32-byte random seed
*/
public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
Preconditions.checkArgument(seed.length == 32 || seed == null);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null || byteBuff.capacity() < seed.length) {
byteBuff = ByteBuffer.allocateDirect(seed.length);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(seed);
w.lock();
try {
return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
} finally {
w.unlock();
}
}
private static native long secp256k1_ctx_clone(long context);
private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
private static native void secp256k1_destroy_context(long context);
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
}

View File

@@ -0,0 +1,226 @@
package org.bitcoin;
import com.google.common.io.BaseEncoding;
import java.util.Arrays;
import java.math.BigInteger;
import javax.xml.bind.DatatypeConverter;
import static org.bitcoin.NativeSecp256k1Util.*;
/**
* This class holds test cases defined for testing this library.
*/
public class NativeSecp256k1Test {
//TODO improve comments/add more tests
/**
* This tests verify() for a valid signature
*/
public static void testVerifyPos() throws AssertFailException{
boolean result = false;
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
result = NativeSecp256k1.verify( data, sig, pub);
assertEquals( result, true , "testVerifyPos");
}
/**
* This tests verify() for a non-valid signature
*/
public static void testVerifyNeg() throws AssertFailException{
boolean result = false;
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
result = NativeSecp256k1.verify( data, sig, pub);
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
assertEquals( result, false , "testVerifyNeg");
}
/**
* This tests secret key verify() for a valid secretkey
*/
public static void testSecKeyVerifyPos() throws AssertFailException{
boolean result = false;
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
result = NativeSecp256k1.secKeyVerify( sec );
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
assertEquals( result, true , "testSecKeyVerifyPos");
}
/**
* This tests secret key verify() for a invalid secretkey
*/
public static void testSecKeyVerifyNeg() throws AssertFailException{
boolean result = false;
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
result = NativeSecp256k1.secKeyVerify( sec );
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
assertEquals( result, false , "testSecKeyVerifyNeg");
}
/**
* This tests public key create() for a valid secretkey
*/
public static void testPubKeyCreatePos() throws AssertFailException{
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos");
}
/**
* This tests public key create() for a invalid secretkey
*/
public static void testPubKeyCreateNeg() throws AssertFailException{
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
assertEquals( pubkeyString, "" , "testPubKeyCreateNeg");
}
/**
* This tests sign() for a valid secretkey
*/
public static void testSignPos() throws AssertFailException{
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
byte[] resultArr = NativeSecp256k1.sign(data, sec);
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
}
/**
* This tests sign() for a invalid secretkey
*/
public static void testSignNeg() throws AssertFailException{
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
byte[] resultArr = NativeSecp256k1.sign(data, sec);
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
assertEquals( sigString, "" , "testSignNeg");
}
/**
* This tests private key tweak-add
*/
public static void testPrivKeyTweakAdd_1() throws AssertFailException {
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data );
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1");
}
/**
* This tests private key tweak-mul
*/
public static void testPrivKeyTweakMul_1() throws AssertFailException {
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data );
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1");
}
/**
* This tests private key tweak-add uncompressed
*/
public static void testPrivKeyTweakAdd_2() throws AssertFailException {
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data );
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2");
}
/**
* This tests private key tweak-mul uncompressed
*/
public static void testPrivKeyTweakMul_2() throws AssertFailException {
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data );
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2");
}
/**
* This tests seed randomization
*/
public static void testRandomize() throws AssertFailException {
byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random"
boolean result = NativeSecp256k1.randomize(seed);
assertEquals( result, true, "testRandomize");
}
public static void testCreateECDHSecret() throws AssertFailException{
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub);
String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret");
}
public static void main(String[] args) throws AssertFailException{
System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n");
assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" );
//Test verify() success/fail
testVerifyPos();
testVerifyNeg();
//Test secKeyVerify() success/fail
testSecKeyVerifyPos();
testSecKeyVerifyNeg();
//Test computePubkey() success/fail
testPubKeyCreatePos();
testPubKeyCreateNeg();
//Test sign() success/fail
testSignPos();
testSignNeg();
//Test privKeyTweakAdd() 1
testPrivKeyTweakAdd_1();
//Test privKeyTweakMul() 2
testPrivKeyTweakMul_1();
//Test privKeyTweakAdd() 3
testPrivKeyTweakAdd_2();
//Test privKeyTweakMul() 4
testPrivKeyTweakMul_2();
//Test randomize()
testRandomize();
//Test ECDH
testCreateECDHSecret();
NativeSecp256k1.cleanup();
System.out.println(" All tests passed." );
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2014-2016 the libsecp256k1 contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoin;
public class NativeSecp256k1Util{
public static void assertEquals( int val, int val2, String message ) throws AssertFailException{
if( val != val2 )
throw new AssertFailException("FAIL: " + message);
}
public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{
if( val != val2 )
throw new AssertFailException("FAIL: " + message);
else
System.out.println("PASS: " + message);
}
public static void assertEquals( String val, String val2, String message ) throws AssertFailException{
if( !val.equals(val2) )
throw new AssertFailException("FAIL: " + message);
else
System.out.println("PASS: " + message);
}
public static class AssertFailException extends Exception {
public AssertFailException(String message) {
super( message );
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2014-2016 the libsecp256k1 contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoin;
/**
* This class holds the context reference used in native methods
* to handle ECDSA operations.
*/
public class Secp256k1Context {
private static final boolean enabled; //true if the library is loaded
private static final long context; //ref to pointer to context obj
static { //static initializer
boolean isEnabled = true;
long contextRef = -1;
try {
System.loadLibrary("secp256k1");
contextRef = secp256k1_init_context();
} catch (UnsatisfiedLinkError e) {
System.out.println("UnsatisfiedLinkError: " + e.toString());
isEnabled = false;
}
enabled = isEnabled;
context = contextRef;
}
public static boolean isEnabled() {
return enabled;
}
public static long getContext() {
if(!enabled) return -1; //sanity check
return context;
}
private static native long secp256k1_init_context();
}

View File

@@ -0,0 +1,377 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "org_bitcoin_NativeSecp256k1.h"
#include "include/secp256k1.h"
#include "include/secp256k1_ecdh.h"
#include "include/secp256k1_recovery.h"
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
(JNIEnv* env, jclass classObject, jlong ctx_l)
{
const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx);
(void)classObject;(void)env;
return ctx_clone_l;
}
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
{
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
(void)classObject;
return secp256k1_context_randomize(ctx, seed);
}
SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
(JNIEnv* env, jclass classObject, jlong ctx_l)
{
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
secp256k1_context_destroy(ctx);
(void)classObject;(void)env;
}
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen)
{
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
const unsigned char* sigdata = { (unsigned char*) (data + 32) };
const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) };
secp256k1_ecdsa_signature sig;
secp256k1_pubkey pubkey;
int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);
if( ret ) {
ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
if( ret ) {
ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey);
}
}
(void)classObject;
return ret;
}
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
{
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
unsigned char* secKey = (unsigned char*) (data + 32);
jobjectArray retArray;
jbyteArray sigArray, intsByteArray;
unsigned char intsarray[2];
secp256k1_ecdsa_signature sig[72];
int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL );
unsigned char outputSer[72];
size_t outputLen = 72;
if( ret ) {
int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2;
}
intsarray[0] = outputLen;
intsarray[1] = ret;
retArray = (*env)->NewObjectArray(env, 2,
(*env)->FindClass(env, "[B"),
(*env)->NewByteArray(env, 1));
sigArray = (*env)->NewByteArray(env, outputLen);
(*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
intsByteArray = (*env)->NewByteArray(env, 2);
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
(void)classObject;
return retArray;
}
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
{
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
(void)classObject;
return secp256k1_ec_seckey_verify(ctx, secKey);
}
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
{
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
secp256k1_pubkey pubkey;
jobjectArray retArray;
jbyteArray pubkeyArray, intsByteArray;
unsigned char intsarray[2];
int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey);
unsigned char outputSer[65];
size_t outputLen = 65;
if( ret ) {
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
}
intsarray[0] = outputLen;
intsarray[1] = ret;
retArray = (*env)->NewObjectArray(env, 2,
(*env)->FindClass(env, "[B"),
(*env)->NewByteArray(env, 1));
pubkeyArray = (*env)->NewByteArray(env, outputLen);
(*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer);
(*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray);
intsByteArray = (*env)->NewByteArray(env, 2);
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
(void)classObject;
return retArray;
}
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
{
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
const unsigned char* tweak = (unsigned char*) (privkey + 32);
jobjectArray retArray;
jbyteArray privArray, intsByteArray;
unsigned char intsarray[2];
int privkeylen = 32;
int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak);
intsarray[0] = privkeylen;
intsarray[1] = ret;
retArray = (*env)->NewObjectArray(env, 2,
(*env)->FindClass(env, "[B"),
(*env)->NewByteArray(env, 1));
privArray = (*env)->NewByteArray(env, privkeylen);
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
(*env)->SetObjectArrayElement(env, retArray, 0, privArray);
intsByteArray = (*env)->NewByteArray(env, 2);
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
(void)classObject;
return retArray;
}
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
{
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
const unsigned char* tweak = (unsigned char*) (privkey + 32);
jobjectArray retArray;
jbyteArray privArray, intsByteArray;
unsigned char intsarray[2];
int privkeylen = 32;
int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak);
intsarray[0] = privkeylen;
intsarray[1] = ret;
retArray = (*env)->NewObjectArray(env, 2,
(*env)->FindClass(env, "[B"),
(*env)->NewByteArray(env, 1));
privArray = (*env)->NewByteArray(env, privkeylen);
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
(*env)->SetObjectArrayElement(env, retArray, 0, privArray);
intsByteArray = (*env)->NewByteArray(env, 2);
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
(void)classObject;
return retArray;
}
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
{
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
const unsigned char* tweak = (unsigned char*) (pkey + publen);
jobjectArray retArray;
jbyteArray pubArray, intsByteArray;
unsigned char intsarray[2];
unsigned char outputSer[65];
size_t outputLen = 65;
secp256k1_pubkey pubkey;
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
if( ret ) {
ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak);
}
if( ret ) {
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
}
intsarray[0] = outputLen;
intsarray[1] = ret;
retArray = (*env)->NewObjectArray(env, 2,
(*env)->FindClass(env, "[B"),
(*env)->NewByteArray(env, 1));
pubArray = (*env)->NewByteArray(env, outputLen);
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
intsByteArray = (*env)->NewByteArray(env, 2);
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
(void)classObject;
return retArray;
}
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
{
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
const unsigned char* tweak = (unsigned char*) (pkey + publen);
jobjectArray retArray;
jbyteArray pubArray, intsByteArray;
unsigned char intsarray[2];
unsigned char outputSer[65];
size_t outputLen = 65;
secp256k1_pubkey pubkey;
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
if ( ret ) {
ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak);
}
if( ret ) {
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
}
intsarray[0] = outputLen;
intsarray[1] = ret;
retArray = (*env)->NewObjectArray(env, 2,
(*env)->FindClass(env, "[B"),
(*env)->NewByteArray(env, 1));
pubArray = (*env)->NewByteArray(env, outputLen);
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
intsByteArray = (*env)->NewByteArray(env, 2);
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
(void)classObject;
return retArray;
}
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine
(JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys)
{
(void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys;
return 0;
}
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
{
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);
const unsigned char* pubdata = (const unsigned char*) (secdata + 32);
jobjectArray retArray;
jbyteArray outArray, intsByteArray;
unsigned char intsarray[1];
secp256k1_pubkey pubkey;
unsigned char nonce_res[32];
size_t outputLen = 32;
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
if (ret) {
ret = secp256k1_ecdh(
ctx,
nonce_res,
&pubkey,
secdata
);
}
intsarray[0] = ret;
retArray = (*env)->NewObjectArray(env, 2,
(*env)->FindClass(env, "[B"),
(*env)->NewByteArray(env, 1));
outArray = (*env)->NewByteArray(env, outputLen);
(*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res);
(*env)->SetObjectArrayElement(env, retArray, 0, outArray);
intsByteArray = (*env)->NewByteArray(env, 1);
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
(void)classObject;
return retArray;
}

View File

@@ -0,0 +1,119 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include "include/secp256k1.h"
/* Header for class org_bitcoin_NativeSecp256k1 */
#ifndef _Included_org_bitcoin_NativeSecp256k1
#define _Included_org_bitcoin_NativeSecp256k1
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ctx_clone
* Signature: (J)J
*/
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
(JNIEnv *, jclass, jlong);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_context_randomize
* Signature: (Ljava/nio/ByteBuffer;J)I
*/
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
(JNIEnv *, jclass, jobject, jlong);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_privkey_tweak_add
* Signature: (Ljava/nio/ByteBuffer;J)[[B
*/
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
(JNIEnv *, jclass, jobject, jlong);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_privkey_tweak_mul
* Signature: (Ljava/nio/ByteBuffer;J)[[B
*/
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
(JNIEnv *, jclass, jobject, jlong);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_pubkey_tweak_add
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
*/
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
(JNIEnv *, jclass, jobject, jlong, jint);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_pubkey_tweak_mul
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
*/
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
(JNIEnv *, jclass, jobject, jlong, jint);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_destroy_context
* Signature: (J)V
*/
SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
(JNIEnv *, jclass, jlong);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ecdsa_verify
* Signature: (Ljava/nio/ByteBuffer;JII)I
*/
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
(JNIEnv *, jclass, jobject, jlong, jint, jint);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ecdsa_sign
* Signature: (Ljava/nio/ByteBuffer;J)[[B
*/
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
(JNIEnv *, jclass, jobject, jlong);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ec_seckey_verify
* Signature: (Ljava/nio/ByteBuffer;J)I
*/
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
(JNIEnv *, jclass, jobject, jlong);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ec_pubkey_create
* Signature: (Ljava/nio/ByteBuffer;J)[[B
*/
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
(JNIEnv *, jclass, jobject, jlong);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ec_pubkey_parse
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
*/
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
(JNIEnv *, jclass, jobject, jlong, jint);
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ecdh
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
*/
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,15 @@
#include <stdlib.h>
#include <stdint.h>
#include "org_bitcoin_Secp256k1Context.h"
#include "include/secp256k1.h"
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
(JNIEnv* env, jclass classObject)
{
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
(void)classObject;(void)env;
return (uintptr_t)ctx;
}

View File

@@ -0,0 +1,22 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include "include/secp256k1.h"
/* Header for class org_bitcoin_Secp256k1Context */
#ifndef _Included_org_bitcoin_Secp256k1Context
#define _Included_org_bitcoin_Secp256k1Context
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_bitcoin_Secp256k1Context
* Method: secp256k1_init_context
* Signature: ()J
*/
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -4,68 +4,51 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODULE_ECDH_MAIN_H
#define SECP256K1_MODULE_ECDH_MAIN_H
#ifndef _SECP256K1_MODULE_ECDH_MAIN_
#define _SECP256K1_MODULE_ECDH_MAIN_
#include "include/secp256k1_ecdh.h"
#include "ecmult_const_impl.h"
static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
unsigned char version = (y32[31] & 0x01) | 0x02;
secp256k1_sha256 sha;
(void)data;
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, &version, 1);
secp256k1_sha256_write(&sha, x32, 32);
secp256k1_sha256_finalize(&sha, output);
return 1;
}
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256;
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256;
int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) {
int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) {
int ret = 0;
int overflow = 0;
secp256k1_gej res;
secp256k1_ge pt;
secp256k1_scalar s;
unsigned char x[32];
unsigned char y[32];
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output != NULL);
ARG_CHECK(result != NULL);
ARG_CHECK(point != NULL);
ARG_CHECK(scalar != NULL);
if (hashfp == NULL) {
hashfp = secp256k1_ecdh_hash_function_default;
}
secp256k1_pubkey_load(ctx, &pt, point);
secp256k1_scalar_set_b32(&s, scalar, &overflow);
if (overflow || secp256k1_scalar_is_zero(&s)) {
ret = 0;
} else {
unsigned char x[32];
unsigned char y[1];
secp256k1_sha256_t sha;
overflow |= secp256k1_scalar_is_zero(&s);
secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
secp256k1_ecmult_const(&res, &pt, &s, 256);
secp256k1_ge_set_gej(&pt, &res);
/* Compute a hash of the point in compressed form
* Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not
* expect its output to be secret and has a timing sidechannel. */
secp256k1_fe_normalize(&pt.x);
secp256k1_fe_normalize(&pt.y);
secp256k1_fe_get_b32(x, &pt.x);
y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y);
secp256k1_ecmult_const(&res, &pt, &s, 256);
secp256k1_ge_set_gej(&pt, &res);
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, y, sizeof(y));
secp256k1_sha256_write(&sha, x, sizeof(x));
secp256k1_sha256_finalize(&sha, result);
ret = 1;
}
/* Compute a hash of the point */
secp256k1_fe_normalize(&pt.x);
secp256k1_fe_normalize(&pt.y);
secp256k1_fe_get_b32(x, &pt.x);
secp256k1_fe_get_b32(y, &pt.y);
ret = hashfp(output, x, y, data);
memset(x, 0, 32);
memset(y, 0, 32);
secp256k1_scalar_clear(&s);
return !!ret & !overflow;
return ret;
}
#endif /* SECP256K1_MODULE_ECDH_MAIN_H */
#endif

View File

@@ -4,25 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODULE_ECDH_TESTS_H
#define SECP256K1_MODULE_ECDH_TESTS_H
int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
(void)output;
(void)x;
(void)y;
(void)data;
return 0;
}
int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
(void)data;
/* Save x and y as uncompressed public key */
output[0] = 0x04;
memcpy(output + 1, x, 32);
memcpy(output + 33, y, 32);
return 1;
}
#ifndef _SECP256K1_MODULE_ECDH_TESTS_
#define _SECP256K1_MODULE_ECDH_TESTS_
void test_ecdh_api(void) {
/* Setup context that just counts errors */
@@ -38,15 +21,15 @@ void test_ecdh_api(void) {
CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
/* Check all NULLs are detected */
CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0);
CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0);
CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0);
CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
CHECK(ecount == 3);
/* Cleanup */
@@ -61,36 +44,29 @@ 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) {
secp256k1_sha256 sha;
secp256k1_sha256_t sha;
unsigned char s_b32[32];
unsigned char output_ecdh[65];
unsigned char output_ecdh[32];
unsigned char output_ser[32];
unsigned char point_ser[65];
unsigned char point_ser[33];
size_t point_ser_len = sizeof(point_ser);
secp256k1_scalar s;
random_scalar_order(&s);
secp256k1_scalar_get_b32(s_b32, &s);
/* compute using ECDH function */
CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1);
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1);
/* compute "explicitly" */
CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1);
/* compute using ECDH function with custom hash function */
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1);
/* compute "explicitly" */
CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1);
/* compare */
CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0);
/* compute using ECDH function with default hash function */
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1);
/* compute "explicitly" */
CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
CHECK(point_ser_len == sizeof(point_ser));
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, point_ser, point_ser_len);
secp256k1_sha256_finalize(&sha, output_ser);
/* compare */
CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0);
CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0);
}
}
@@ -113,14 +89,11 @@ void test_bad_scalar(void) {
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1);
/* Try to multiply it by bad values */
CHECK(secp256k1_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0);
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0);
CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0);
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0);
/* ...and a good one */
s_overflow[31] -= 1;
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 1);
/* Hash function failure results in ecdh failure */
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1);
}
void run_ecdh_tests(void) {
@@ -129,4 +102,4 @@ void run_ecdh_tests(void) {
test_bad_scalar();
}
#endif /* SECP256K1_MODULE_ECDH_TESTS_H */
#endif

View File

@@ -1,3 +0,0 @@
include_HEADERS += include/secp256k1_ecdsa_s2c.h
noinst_HEADERS += src/modules/ecdsa_s2c/main_impl.h
noinst_HEADERS += src/modules/ecdsa_s2c/tests_impl.h

View File

@@ -1,198 +0,0 @@
/**********************************************************************
* Copyright (c) 2019-2020 Marko Bencun, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODULE_ECDSA_S2C_MAIN_H
#define SECP256K1_MODULE_ECDSA_S2C_MAIN_H
#include "include/secp256k1.h"
#include "include/secp256k1_ecdsa_s2c.h"
static void secp256k1_ecdsa_s2c_opening_save(secp256k1_ecdsa_s2c_opening* opening, secp256k1_ge* ge) {
secp256k1_pubkey_save((secp256k1_pubkey*) opening, ge);
}
static int secp256k1_ecdsa_s2c_opening_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_ecdsa_s2c_opening* opening) {
return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey*) opening);
}
int secp256k1_ecdsa_s2c_opening_parse(const secp256k1_context* ctx, secp256k1_ecdsa_s2c_opening* opening, const unsigned char* input33) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(opening != NULL);
ARG_CHECK(input33 != NULL);
return secp256k1_ec_pubkey_parse(ctx, (secp256k1_pubkey*) opening, input33, 33);
}
int secp256k1_ecdsa_s2c_opening_serialize(const secp256k1_context* ctx, unsigned char* output33, const secp256k1_ecdsa_s2c_opening* opening) {
size_t out_len = 33;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output33 != NULL);
ARG_CHECK(opening != NULL);
return secp256k1_ec_pubkey_serialize(ctx, output33, &out_len, (const secp256k1_pubkey*) opening, SECP256K1_EC_COMPRESSED);
}
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("s2c/ecdsa/point")||SHA256("s2c/ecdsa/point"). */
static void secp256k1_s2c_ecdsa_point_sha256_tagged(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0xa9b21c7bul;
sha->s[1] = 0x358c3e3eul;
sha->s[2] = 0x0b6863d1ul;
sha->s[3] = 0xc62b2035ul;
sha->s[4] = 0xb44b40ceul;
sha->s[5] = 0x254a8912ul;
sha->s[6] = 0x0f85d0d4ul;
sha->s[7] = 0x8a5bf91cul;
sha->bytes = 64;
}
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("s2c/ecdsa/data")||SHA256("s2c/ecdsa/data"). */
static void secp256k1_s2c_ecdsa_data_sha256_tagged(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0xfeefd675ul;
sha->s[1] = 0x73166c99ul;
sha->s[2] = 0xe2309cb8ul;
sha->s[3] = 0x6d458113ul;
sha->s[4] = 0x01d3a512ul;
sha->s[5] = 0x00e18112ul;
sha->s[6] = 0x37ee0874ul;
sha->s[7] = 0x421fc55ful;
sha->bytes = 64;
}
int secp256k1_ecdsa_s2c_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature* signature, secp256k1_ecdsa_s2c_opening* s2c_opening, const unsigned char
*msg32, const unsigned char *seckey, const unsigned char* s2c_data32) {
secp256k1_scalar r, s;
int ret;
unsigned char ndata[32];
secp256k1_sha256 s2c_sha;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(msg32 != NULL);
ARG_CHECK(signature != NULL);
ARG_CHECK(seckey != NULL);
ARG_CHECK(s2c_data32 != NULL);
/* Provide `s2c_data32` to the nonce function as additional data to
* derive the nonce. It is first hashed because it should be possible
* to derive nonces even if only a SHA256 commitment to the data is
* known. This is important in the ECDSA anti-klepto protocol. */
secp256k1_s2c_ecdsa_data_sha256_tagged(&s2c_sha);
secp256k1_sha256_write(&s2c_sha, s2c_data32, 32);
secp256k1_sha256_finalize(&s2c_sha, ndata);
secp256k1_s2c_ecdsa_point_sha256_tagged(&s2c_sha);
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, &s2c_sha, s2c_opening, s2c_data32, msg32, seckey, NULL, ndata);
secp256k1_scalar_cmov(&r, &secp256k1_scalar_zero, !ret);
secp256k1_scalar_cmov(&s, &secp256k1_scalar_zero, !ret);
secp256k1_ecdsa_signature_save(signature, &r, &s);
return ret;
}
int secp256k1_ecdsa_s2c_verify_commit(const secp256k1_context* ctx, const secp256k1_ecdsa_signature* sig, const unsigned char* data32, const secp256k1_ecdsa_s2c_opening* opening) {
secp256k1_ge commitment_ge;
secp256k1_ge original_pubnonce_ge;
unsigned char x_bytes[32];
secp256k1_scalar sigr, sigs, x_scalar;
secp256k1_sha256 s2c_sha;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(sig != NULL);
ARG_CHECK(data32 != NULL);
ARG_CHECK(opening != NULL);
if (!secp256k1_ecdsa_s2c_opening_load(ctx, &original_pubnonce_ge, opening)) {
return 0;
}
secp256k1_s2c_ecdsa_point_sha256_tagged(&s2c_sha);
if (!secp256k1_ec_commit(&ctx->ecmult_ctx, &commitment_ge, &original_pubnonce_ge, &s2c_sha, data32, 32)) {
return 0;
}
/* Check that sig_r == commitment_x (mod n)
* sig_r is the x coordinate of R represented by a scalar.
* commitment_x is the x coordinate of the commitment (field element).
*
* Note that we are only checking the x-coordinate -- this is because the y-coordinate
* is not part of the ECDSA signature (and therefore not part of the commitment!)
*/
secp256k1_ecdsa_signature_load(ctx, &sigr, &sigs, sig);
secp256k1_fe_normalize(&commitment_ge.x);
secp256k1_fe_get_b32(x_bytes, &commitment_ge.x);
/* Do not check overflow; overflowing a scalar does not affect whether
* or not the R value is a cryptographic commitment, only whether it
* is a valid R value for an ECDSA signature. If users care about that
* they should use `ecdsa_verify` or `anti_klepto_host_verify`. In other
* words, this check would be (at best) unnecessary, and (at worst)
* insufficient. */
secp256k1_scalar_set_b32(&x_scalar, x_bytes, NULL);
return secp256k1_scalar_eq(&sigr, &x_scalar);
}
/*** anti-klepto ***/
int secp256k1_ecdsa_anti_klepto_host_commit(const secp256k1_context* ctx, unsigned char* rand_commitment32, const unsigned char* rand32) {
secp256k1_sha256 sha;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(rand_commitment32 != NULL);
ARG_CHECK(rand32 != NULL);
secp256k1_s2c_ecdsa_data_sha256_tagged(&sha);
secp256k1_sha256_write(&sha, rand32, 32);
secp256k1_sha256_finalize(&sha, rand_commitment32);
return 1;
}
int secp256k1_ecdsa_anti_klepto_signer_commit(const secp256k1_context* ctx, secp256k1_ecdsa_s2c_opening* opening, const unsigned char* msg32, const unsigned char* seckey32, const unsigned char* rand_commitment32) {
unsigned char nonce32[32];
secp256k1_scalar k;
secp256k1_gej rj;
secp256k1_ge r;
unsigned int count = 0;
int is_nonce_valid = 0;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(opening != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(seckey32 != NULL);
ARG_CHECK(rand_commitment32 != NULL);
memset(nonce32, 0, 32);
while (!is_nonce_valid) {
/* cast to void* removes const qualifier, but secp256k1_nonce_function_default does not modify it */
if (!secp256k1_nonce_function_default(nonce32, msg32, seckey32, NULL, (void*)rand_commitment32, count)) {
secp256k1_callback_call(&ctx->error_callback, "(cryptographically unreachable) generated bad nonce");
}
is_nonce_valid = secp256k1_scalar_set_b32_seckey(&k, nonce32);
/* The nonce is still secret here, but it being invalid is is less likely than 1:2^255. */
secp256k1_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid));
count++;
}
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k);
secp256k1_ge_set_gej(&r, &rj);
secp256k1_ecdsa_s2c_opening_save(opening, &r);
memset(nonce32, 0, 32);
secp256k1_scalar_clear(&k);
return 1;
}
int secp256k1_anti_klepto_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char* msg32, const unsigned char* seckey, const unsigned char* host_data32) {
return secp256k1_ecdsa_s2c_sign(ctx, sig, NULL, msg32, seckey, host_data32);
}
int secp256k1_anti_klepto_host_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey, const unsigned char *host_data32, const secp256k1_ecdsa_s2c_opening *opening) {
return secp256k1_ecdsa_s2c_verify_commit(ctx, sig, host_data32, opening) &&
secp256k1_ecdsa_verify(ctx, sig, msg32, pubkey);
}
#endif /* SECP256K1_ECDSA_S2C_MAIN_H */

View File

@@ -1,416 +0,0 @@
/**********************************************************************
* Copyright (c) 2019-2020 Marko Bencun, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODULE_ECDSA_S2C_TESTS_H
#define SECP256K1_MODULE_ECDSA_S2C_TESTS_H
#include "include/secp256k1_ecdsa_s2c.h"
static void test_ecdsa_s2c_tagged_hash(void) {
unsigned char tag_data[14] = "s2c/ecdsa/data";
unsigned char tag_point[15] = "s2c/ecdsa/point";
secp256k1_sha256 sha;
secp256k1_sha256 sha_optimized;
unsigned char output[32];
unsigned char output_optimized[32];
secp256k1_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data));
secp256k1_s2c_ecdsa_data_sha256_tagged(&sha_optimized);
secp256k1_sha256_finalize(&sha, output);
secp256k1_sha256_finalize(&sha_optimized, output_optimized);
CHECK(secp256k1_memcmp_var(output, output_optimized, 32) == 0);
secp256k1_sha256_initialize_tagged(&sha, tag_point, sizeof(tag_point));
secp256k1_s2c_ecdsa_point_sha256_tagged(&sha_optimized);
secp256k1_sha256_finalize(&sha, output);
secp256k1_sha256_finalize(&sha_optimized, output_optimized);
CHECK(secp256k1_memcmp_var(output, output_optimized, 32) == 0);
}
void run_s2c_opening_test(void) {
int i = 0;
unsigned char output[33];
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
unsigned char input[33] = {
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02
};
secp256k1_ecdsa_s2c_opening opening;
int32_t ecount = 0;
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
/* First parsing, then serializing works */
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 1);
CHECK(secp256k1_ecdsa_s2c_opening_serialize(none, output, &opening) == 1);
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, NULL, input) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 1);
CHECK(secp256k1_ecdsa_s2c_opening_serialize(none, NULL, &opening) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_s2c_opening_serialize(none, output, NULL) == 0);
CHECK(ecount == 4);
/* Invalid pubkey makes parsing fail */
input[0] = 0; /* bad oddness bit */
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 0);
input[0] = 2;
input[31] = 1; /* point not on the curve */
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 0);
CHECK(ecount == 4); /* neither of the above are API errors */
/* Try parsing and serializing a bunch of openings */
for (i = 0; i < count; i++) {
/* This is expected to fail in about 50% of iterations because the
* points' x-coordinates are uniformly random */
if (secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 1) {
CHECK(secp256k1_ecdsa_s2c_opening_serialize(none, output, &opening) == 1);
CHECK(memcmp(output, input, sizeof(output)) == 0);
}
secp256k1_testrand256(&input[1]);
/* Set pubkey oddness tag to first bit of input[1] */
input[0] = (input[1] & 1) + 2;
}
secp256k1_context_destroy(none);
}
static void test_ecdsa_s2c_api(void) {
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
secp256k1_ecdsa_s2c_opening s2c_opening;
secp256k1_ecdsa_signature sig;
const unsigned char msg[32] = "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm";
const unsigned char sec[32] = "ssssssssssssssssssssssssssssssss";
const unsigned char s2c_data[32] = "dddddddddddddddddddddddddddddddd";
const unsigned char hostrand[32] = "hrhrhrhrhrhrhrhrhrhrhrhrhrhrhrhr";
unsigned char hostrand_commitment[32];
secp256k1_pubkey pk;
int32_t ecount;
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sec));
ecount = 0;
CHECK(secp256k1_ecdsa_s2c_sign(both, NULL, &s2c_opening, msg, sec, s2c_data) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, NULL, msg, sec, s2c_data) == 1);
CHECK(ecount == 1); /* NULL opening is not an API error */
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, &s2c_opening, NULL, sec, s2c_data) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, &s2c_opening, msg, NULL, s2c_data) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, &s2c_opening, msg, sec, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_s2c_sign(none, &sig, &s2c_opening, msg, sec, s2c_data) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_s2c_sign(vrfy, &sig, &s2c_opening, msg, sec, s2c_data) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_ecdsa_s2c_sign(sign, &sig, &s2c_opening, msg, sec, s2c_data) == 1);
CHECK(ecount == 6);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pk) == 1);
ecount = 0;
CHECK(secp256k1_ecdsa_s2c_verify_commit(both, NULL, s2c_data, &s2c_opening) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(both, &sig, NULL, &s2c_opening) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_s2c_verify_commit(both, &sig, s2c_data, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_s2c_verify_commit(none, &sig, s2c_data, &s2c_opening) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_s2c_verify_commit(sign, &sig, s2c_data, &s2c_opening) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_s2c_verify_commit(vrfy, &sig, s2c_data, &s2c_opening) == 1);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_s2c_verify_commit(vrfy, &sig, sec, &s2c_opening) == 0);
CHECK(ecount == 5); /* wrong data is not an API error */
/* Signing with NULL s2c_opening gives the same result */
CHECK(secp256k1_ecdsa_s2c_sign(sign, &sig, NULL, msg, sec, s2c_data) == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(vrfy, &sig, s2c_data, &s2c_opening) == 1);
/* anti-klepto */
ecount = 0;
CHECK(secp256k1_ecdsa_anti_klepto_host_commit(none, NULL, hostrand) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_anti_klepto_host_commit(none, hostrand_commitment, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_anti_klepto_host_commit(none, hostrand_commitment, hostrand) == 1);
CHECK(ecount == 2);
ecount = 0;
CHECK(secp256k1_ecdsa_anti_klepto_signer_commit(both, NULL, msg, sec, hostrand_commitment) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_anti_klepto_signer_commit(both, &s2c_opening, NULL, sec, hostrand_commitment) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_anti_klepto_signer_commit(both, &s2c_opening, msg, NULL, hostrand_commitment) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_anti_klepto_signer_commit(both, &s2c_opening, msg, sec, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_anti_klepto_signer_commit(none, &s2c_opening, msg, sec, hostrand_commitment) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_anti_klepto_signer_commit(vrfy, &s2c_opening, msg, sec, hostrand_commitment) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_ecdsa_anti_klepto_signer_commit(sign, &s2c_opening, msg, sec, hostrand_commitment) == 1);
CHECK(ecount == 6);
ecount = 0;
CHECK(secp256k1_anti_klepto_sign(both, NULL, msg, sec, hostrand) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_anti_klepto_sign(both, &sig, NULL, sec, hostrand) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_anti_klepto_sign(both, &sig, msg, NULL, hostrand) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_anti_klepto_sign(both, &sig, msg, sec, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_anti_klepto_sign(none, &sig, msg, sec, hostrand) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_anti_klepto_sign(vrfy, &sig, msg, sec, hostrand) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_anti_klepto_sign(both, &sig, msg, sec, hostrand) == 1);
CHECK(ecount == 6);
ecount = 0;
CHECK(secp256k1_anti_klepto_host_verify(both, NULL, msg, &pk, hostrand, &s2c_opening) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_anti_klepto_host_verify(both, &sig, NULL, &pk, hostrand, &s2c_opening) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_anti_klepto_host_verify(both, &sig, msg, NULL, hostrand, &s2c_opening) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_anti_klepto_host_verify(both, &sig, msg, &pk, NULL, &s2c_opening) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_anti_klepto_host_verify(both, &sig, msg, &pk, hostrand, NULL) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_anti_klepto_host_verify(none, &sig, msg, &pk, hostrand, &s2c_opening) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_anti_klepto_host_verify(sign, &sig, msg, &pk, hostrand, &s2c_opening) == 0);
CHECK(ecount == 7);
CHECK(secp256k1_anti_klepto_host_verify(vrfy, &sig, msg, &pk, hostrand, &s2c_opening) == 1);
CHECK(ecount == 7);
secp256k1_context_destroy(both);
secp256k1_context_destroy(vrfy);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(none);
}
/* When using sign-to-contract commitments, the nonce function is fixed, so we can use fixtures to test. */
typedef struct {
/* Data to commit to */
unsigned char s2c_data[32];
/* Original nonce */
unsigned char expected_s2c_opening[33];
/* Original nonce (anti-klepto protocol, which mixes in host randomness) */
unsigned char expected_s2c_klepto_opening[33];
} ecdsa_s2c_test;
static ecdsa_s2c_test ecdsa_s2c_tests[] = {
{
"\x1b\xf6\xfb\x42\xf4\x1e\xb8\x76\xc4\xd7\xaa\x0d\x67\x24\x2b\x00\xba\xab\x99\xdc\x20\x84\x49\x3e\x4e\x63\x27\x7f\xa1\xf7\x7f\x22",
"\x03\xf0\x30\xde\xf3\x18\x8c\x0f\x56\xfc\xea\x87\x43\x5b\x30\x76\x43\xf4\x5d\xaf\xe2\x2c\xbc\x82\xfd\x56\x03\x4f\xae\x97\x41\x7d\x3a",
"\x02\xdf\x63\x75\x5d\x1f\x32\x92\xbf\xfe\xd8\x29\x86\xb1\x06\x49\x7c\x93\xb1\xf8\xbd\xc0\x45\x4b\x6b\x0b\x0a\x47\x79\xc0\xef\x71\x88",
},
{
"\x35\x19\x9a\x8f\xbf\x84\xad\x6e\xf6\x9a\x18\x4c\x1b\x19\x28\x5b\xef\xbe\x06\xe6\x0b\x62\x64\xe6\xd3\x73\x89\x3f\x68\x55\xe2\x4a",
"\x03\x90\x17\x17\xce\x7c\x74\x84\xa2\xce\x1b\x7d\xc7\x40\x3b\x14\xe0\x35\x49\x71\x39\x3e\xc0\x92\xa7\xf3\xe0\xc8\xe4\xe2\xd2\x63\x9d",
"\x02\xc0\x4a\xc7\xf7\x71\xe8\xeb\xdb\xf3\x15\xff\x5e\x58\xb7\xfe\x95\x16\x10\x21\x03\x50\x00\x66\x17\x2c\x4f\xac\x5b\x20\xf9\xe0\xea",
},
};
static void test_ecdsa_s2c_fixed_vectors(void) {
const unsigned char privkey[32] = {
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
};
const unsigned char message[32] = {
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
};
size_t i;
for (i = 0; i < sizeof(ecdsa_s2c_tests) / sizeof(ecdsa_s2c_tests[0]); i++) {
secp256k1_ecdsa_s2c_opening s2c_opening;
unsigned char opening_ser[33];
const ecdsa_s2c_test *test = &ecdsa_s2c_tests[i];
secp256k1_ecdsa_signature signature;
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, test->s2c_data) == 1);
CHECK(secp256k1_ecdsa_s2c_opening_serialize(ctx, opening_ser, &s2c_opening) == 1);
CHECK(memcmp(test->expected_s2c_opening, opening_ser, sizeof(opening_ser)) == 0);
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, test->s2c_data, &s2c_opening) == 1);
}
}
static void test_ecdsa_s2c_sign_verify(void) {
unsigned char privkey[32];
secp256k1_pubkey pubkey;
unsigned char message[32];
unsigned char noncedata[32];
unsigned char s2c_data[32];
unsigned char s2c_data2[32];
secp256k1_ecdsa_signature signature;
secp256k1_ecdsa_s2c_opening s2c_opening;
/* Generate a random key, message, noncedata and s2c_data. */
{
secp256k1_scalar key;
random_scalar_order_test(&key);
secp256k1_scalar_get_b32(privkey, &key);
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
secp256k1_testrand256_test(message);
secp256k1_testrand256_test(noncedata);
secp256k1_testrand256_test(s2c_data);
secp256k1_testrand256_test(s2c_data2);
}
{ /* invalid privkeys */
unsigned char zero_privkey[32] = {0};
unsigned char overflow_privkey[32] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, NULL, message, zero_privkey, s2c_data) == 0);
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, NULL, message, overflow_privkey, s2c_data) == 0);
}
/* Check that the sign-to-contract signature is valid, with s2c_data. Also check the commitment. */
{
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, s2c_data) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature, message, &pubkey) == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, s2c_data, &s2c_opening) == 1);
}
/* Check that an invalid commitment does not verify */
{
unsigned char sigbytes[64];
size_t i;
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, s2c_data) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature, message, &pubkey) == 1);
CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sigbytes, &signature) == 1);
for(i = 0; i < 32; i++) {
/* change one byte */
sigbytes[i] = (((int)sigbytes[i]) + 1) % 256;
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature, sigbytes) == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, s2c_data, &s2c_opening) == 0);
/* revert */
sigbytes[i] = (((int)sigbytes[i]) + 255) % 256;
}
}
}
static void test_ecdsa_anti_klepto_signer_commit(void) {
size_t i;
unsigned char privkey[32] = {
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
};
unsigned char message[32] = {
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
};
/* Check that original pubnonce is derived from s2c_data */
for (i = 0; i < sizeof(ecdsa_s2c_tests) / sizeof(ecdsa_s2c_tests[0]); i++) {
secp256k1_ecdsa_s2c_opening s2c_opening;
unsigned char buf[33];
const ecdsa_s2c_test *test = &ecdsa_s2c_tests[i];
CHECK(secp256k1_ecdsa_anti_klepto_signer_commit(ctx, &s2c_opening, message, privkey, test->s2c_data) == 1);
CHECK(secp256k1_ecdsa_s2c_opening_serialize(ctx, buf, &s2c_opening) == 1);
CHECK(memcmp(test->expected_s2c_klepto_opening, buf, sizeof(buf)) == 0);
}
}
/* This tests the full ECDSA Anti-Klepto Protocol */
static void test_ecdsa_anti_klepto(void) {
unsigned char signer_privkey[32];
unsigned char host_msg[32];
unsigned char host_commitment[32];
unsigned char host_nonce_contribution[32];
secp256k1_pubkey signer_pubkey;
secp256k1_ecdsa_signature signature;
secp256k1_ecdsa_s2c_opening s2c_opening;
/* Generate a random key, message. */
{
secp256k1_scalar key;
random_scalar_order_test(&key);
secp256k1_scalar_get_b32(signer_privkey, &key);
CHECK(secp256k1_ec_pubkey_create(ctx, &signer_pubkey, signer_privkey) == 1);
secp256k1_testrand256_test(host_msg);
secp256k1_testrand256_test(host_nonce_contribution);
}
/* Protocol step 1. */
CHECK(secp256k1_ecdsa_anti_klepto_host_commit(ctx, host_commitment, host_nonce_contribution) == 1);
/* Protocol step 2. */
CHECK(secp256k1_ecdsa_anti_klepto_signer_commit(ctx, &s2c_opening, host_msg, signer_privkey, host_commitment) == 1);
/* Protocol step 3: host_nonce_contribution send to signer to be used in step 4. */
/* Protocol step 4. */
CHECK(secp256k1_anti_klepto_sign(ctx, &signature, host_msg, signer_privkey, host_nonce_contribution) == 1);
/* Protocol step 5. */
CHECK(secp256k1_anti_klepto_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 1);
/* Protocol step 5 (explicitly) */
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, host_nonce_contribution, &s2c_opening) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature, host_msg, &signer_pubkey) == 1);
{ /* host_verify: commitment does not match */
unsigned char sigbytes[64];
size_t i;
CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sigbytes, &signature) == 1);
for(i = 0; i < 32; i++) {
/* change one byte */
sigbytes[i] += 1;
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature, sigbytes) == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, host_nonce_contribution, &s2c_opening) == 0);
CHECK(secp256k1_anti_klepto_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 0);
/* revert */
sigbytes[i] -= 1;
}
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature, sigbytes) == 1);
}
{ /* host_verify: message does not match */
unsigned char bad_msg[32];
secp256k1_testrand256_test(bad_msg);
CHECK(secp256k1_anti_klepto_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 1);
CHECK(secp256k1_anti_klepto_host_verify(ctx, &signature, bad_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 0);
}
{ /* s2c_sign: host provided data that didn't match commitment */
secp256k1_ecdsa_s2c_opening orig_opening = s2c_opening;
unsigned char bad_nonce_contribution[32] = { 1, 2, 3, 4 };
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, host_msg, signer_privkey, bad_nonce_contribution) == 1);
/* good signature but the opening (original public nonce does not match the original */
CHECK(secp256k1_ecdsa_verify(ctx, &signature, host_msg, &signer_pubkey) == 1);
CHECK(secp256k1_anti_klepto_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 0);
CHECK(secp256k1_anti_klepto_host_verify(ctx, &signature, host_msg, &signer_pubkey, bad_nonce_contribution, &s2c_opening) == 1);
CHECK(memcmp(&s2c_opening, &orig_opening, sizeof(s2c_opening)) != 0);
}
}
static void run_ecdsa_s2c_tests(void) {
run_s2c_opening_test();
test_ecdsa_s2c_tagged_hash();
test_ecdsa_s2c_api();
test_ecdsa_s2c_fixed_vectors();
test_ecdsa_s2c_sign_verify();
test_ecdsa_anti_klepto_signer_commit();
test_ecdsa_anti_klepto();
}
#endif /* SECP256K1_MODULE_ECDSA_S2C_TESTS_H */

View File

@@ -1,4 +0,0 @@
include_HEADERS += include/secp256k1_extrakeys.h
noinst_HEADERS += src/modules/extrakeys/tests_impl.h
noinst_HEADERS += src/modules/extrakeys/tests_exhaustive_impl.h
noinst_HEADERS += src/modules/extrakeys/main_impl.h

View File

@@ -1,251 +0,0 @@
/**********************************************************************
* Copyright (c) 2020 Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_EXTRAKEYS_MAIN_
#define _SECP256K1_MODULE_EXTRAKEYS_MAIN_
#include "include/secp256k1.h"
#include "include/secp256k1_extrakeys.h"
static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) {
return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey);
}
static SECP256K1_INLINE void secp256k1_xonly_pubkey_save(secp256k1_xonly_pubkey *pubkey, secp256k1_ge *ge) {
secp256k1_pubkey_save((secp256k1_pubkey *) pubkey, ge);
}
int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, const unsigned char *input32) {
secp256k1_ge pk;
secp256k1_fe x;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pubkey != NULL);
memset(pubkey, 0, sizeof(*pubkey));
ARG_CHECK(input32 != NULL);
if (!secp256k1_fe_set_b32(&x, input32)) {
return 0;
}
if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) {
return 0;
}
if (!secp256k1_ge_is_in_correct_subgroup(&pk)) {
return 0;
}
secp256k1_xonly_pubkey_save(pubkey, &pk);
return 1;
}
int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output32, const secp256k1_xonly_pubkey *pubkey) {
secp256k1_ge pk;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output32 != NULL);
memset(output32, 0, 32);
ARG_CHECK(pubkey != NULL);
if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) {
return 0;
}
secp256k1_fe_get_b32(output32, &pk.x);
return 1;
}
/** Keeps a group element as is if it has an even Y and otherwise negates it.
* y_parity is set to 0 in the former case and to 1 in the latter case.
* Requires that the coordinates of r are normalized. */
static int secp256k1_extrakeys_ge_even_y(secp256k1_ge *r) {
int y_parity = 0;
VERIFY_CHECK(!secp256k1_ge_is_infinity(r));
if (secp256k1_fe_is_odd(&r->y)) {
secp256k1_fe_negate(&r->y, &r->y, 1);
y_parity = 1;
}
return y_parity;
}
int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, const secp256k1_pubkey *pubkey) {
secp256k1_ge pk;
int tmp;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(xonly_pubkey != NULL);
ARG_CHECK(pubkey != NULL);
if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) {
return 0;
}
tmp = secp256k1_extrakeys_ge_even_y(&pk);
if (pk_parity != NULL) {
*pk_parity = tmp;
}
secp256k1_xonly_pubkey_save(xonly_pubkey, &pk);
return 1;
}
int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
secp256k1_ge pk;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output_pubkey != NULL);
memset(output_pubkey, 0, sizeof(*output_pubkey));
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(internal_pubkey != NULL);
ARG_CHECK(tweak32 != NULL);
if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey)
|| !secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32)) {
return 0;
}
secp256k1_pubkey_save(output_pubkey, &pk);
return 1;
}
int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
secp256k1_ge pk;
unsigned char pk_expected32[32];
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(internal_pubkey != NULL);
ARG_CHECK(tweaked_pubkey32 != NULL);
ARG_CHECK(tweak32 != NULL);
if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey)
|| !secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32)) {
return 0;
}
secp256k1_fe_normalize_var(&pk.x);
secp256k1_fe_normalize_var(&pk.y);
secp256k1_fe_get_b32(pk_expected32, &pk.x);
return secp256k1_memcmp_var(&pk_expected32, tweaked_pubkey32, 32) == 0
&& secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity;
}
static void secp256k1_keypair_save(secp256k1_keypair *keypair, const secp256k1_scalar *sk, secp256k1_ge *pk) {
secp256k1_scalar_get_b32(&keypair->data[0], sk);
secp256k1_pubkey_save((secp256k1_pubkey *)&keypair->data[32], pk);
}
static int secp256k1_keypair_seckey_load(const secp256k1_context* ctx, secp256k1_scalar *sk, const secp256k1_keypair *keypair) {
int ret;
ret = secp256k1_scalar_set_b32_seckey(sk, &keypair->data[0]);
/* We can declassify ret here because sk is only zero if a keypair function
* failed (which zeroes the keypair) and its return value is ignored. */
secp256k1_declassify(ctx, &ret, sizeof(ret));
ARG_CHECK(ret);
return ret;
}
/* Load a keypair into pk and sk (if non-NULL). This function declassifies pk
* and ARG_CHECKs that the keypair is not invalid. It always initializes sk and
* pk with dummy values. */
static int secp256k1_keypair_load(const secp256k1_context* ctx, secp256k1_scalar *sk, secp256k1_ge *pk, const secp256k1_keypair *keypair) {
int ret;
const secp256k1_pubkey *pubkey = (const secp256k1_pubkey *)&keypair->data[32];
/* Need to declassify the pubkey because pubkey_load ARG_CHECKs if it's
* invalid. */
secp256k1_declassify(ctx, pubkey, sizeof(*pubkey));
ret = secp256k1_pubkey_load(ctx, pk, pubkey);
if (sk != NULL) {
ret = ret && secp256k1_keypair_seckey_load(ctx, sk, keypair);
}
if (!ret) {
*pk = secp256k1_ge_const_g;
if (sk != NULL) {
*sk = secp256k1_scalar_one;
}
}
return ret;
}
int secp256k1_keypair_create(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *seckey32) {
secp256k1_scalar sk;
secp256k1_ge pk;
int ret = 0;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(keypair != NULL);
memset(keypair, 0, sizeof(*keypair));
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(seckey32 != NULL);
ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &sk, &pk, seckey32);
secp256k1_keypair_save(keypair, &sk, &pk);
secp256k1_memczero(keypair, sizeof(*keypair), !ret);
secp256k1_scalar_clear(&sk);
return ret;
}
int secp256k1_keypair_pub(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pubkey != NULL);
memset(pubkey, 0, sizeof(*pubkey));
ARG_CHECK(keypair != NULL);
memcpy(pubkey->data, &keypair->data[32], sizeof(*pubkey));
return 1;
}
int secp256k1_keypair_xonly_pub(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, const secp256k1_keypair *keypair) {
secp256k1_ge pk;
int tmp;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pubkey != NULL);
memset(pubkey, 0, sizeof(*pubkey));
ARG_CHECK(keypair != NULL);
if (!secp256k1_keypair_load(ctx, NULL, &pk, keypair)) {
return 0;
}
tmp = secp256k1_extrakeys_ge_even_y(&pk);
if (pk_parity != NULL) {
*pk_parity = tmp;
}
secp256k1_xonly_pubkey_save(pubkey, &pk);
return 1;
}
int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *tweak32) {
secp256k1_ge pk;
secp256k1_scalar sk;
int y_parity;
int ret;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(keypair != NULL);
ARG_CHECK(tweak32 != NULL);
ret = secp256k1_keypair_load(ctx, &sk, &pk, keypair);
memset(keypair, 0, sizeof(*keypair));
y_parity = secp256k1_extrakeys_ge_even_y(&pk);
if (y_parity == 1) {
secp256k1_scalar_negate(&sk, &sk);
}
ret &= secp256k1_ec_seckey_tweak_add_helper(&sk, tweak32);
ret &= secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32);
secp256k1_declassify(ctx, &ret, sizeof(ret));
if (ret) {
secp256k1_keypair_save(keypair, &sk, &pk);
}
secp256k1_scalar_clear(&sk);
return ret;
}
#endif

View File

@@ -1,68 +0,0 @@
/**********************************************************************
* Copyright (c) 2020 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_
#define _SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_
#include "src/modules/extrakeys/main_impl.h"
#include "include/secp256k1_extrakeys.h"
static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) {
secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1];
secp256k1_pubkey pubkey[EXHAUSTIVE_TEST_ORDER - 1];
secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1];
int parities[EXHAUSTIVE_TEST_ORDER - 1];
unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32];
int i;
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) {
secp256k1_fe fe;
secp256k1_scalar scalar_i;
unsigned char buf[33];
int parity;
secp256k1_scalar_set_int(&scalar_i, i);
secp256k1_scalar_get_b32(buf, &scalar_i);
/* Construct pubkey and keypair. */
CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf));
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey[i - 1], buf));
/* Construct serialized xonly_pubkey from keypair. */
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parities[i - 1], &keypair[i - 1]));
CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1]));
/* Parse the xonly_pubkey back and verify it matches the previously serialized value. */
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pubkey[i - 1], xonly_pubkey_bytes[i - 1]));
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1]));
CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0);
/* Construct the xonly_pubkey from the pubkey, and verify it matches the same. */
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pubkey[i - 1], &parity, &pubkey[i - 1]));
CHECK(parity == parities[i - 1]);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1]));
CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0);
/* Compare the xonly_pubkey bytes against the precomputed group. */
secp256k1_fe_set_b32(&fe, xonly_pubkey_bytes[i - 1]);
CHECK(secp256k1_fe_equal_var(&fe, &group[i].x));
/* Check the parity against the precomputed group. */
fe = group[i].y;
secp256k1_fe_normalize_var(&fe);
CHECK(secp256k1_fe_is_odd(&fe) == parities[i - 1]);
/* Verify that the higher half is identical to the lower half mirrored. */
if (i > EXHAUSTIVE_TEST_ORDER / 2) {
CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - i - 1], 32) == 0);
CHECK(parities[i - 1] == 1 - parities[EXHAUSTIVE_TEST_ORDER - i - 1]);
}
}
/* TODO: keypair/xonly_pubkey tweak tests */
}
#endif

View File

@@ -1,524 +0,0 @@
/**********************************************************************
* Copyright (c) 2020 Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_EXTRAKEYS_TESTS_
#define _SECP256K1_MODULE_EXTRAKEYS_TESTS_
#include "secp256k1_extrakeys.h"
static secp256k1_context* api_test_context(int flags, int *ecount) {
secp256k1_context *ctx0 = secp256k1_context_create(flags);
secp256k1_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount);
secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount);
return ctx0;
}
void test_xonly_pubkey(void) {
secp256k1_pubkey pk;
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
secp256k1_ge pk1;
secp256k1_ge pk2;
secp256k1_fe y;
unsigned char sk[32];
unsigned char xy_sk[32];
unsigned char buf32[32];
unsigned char ones32[32];
unsigned char zeros64[64] = { 0 };
int pk_parity;
int i;
int ecount;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
secp256k1_testrand256(sk);
memset(ones32, 0xFF, 32);
secp256k1_testrand256(xy_sk);
CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
/* Test xonly_pubkey_from_pubkey */
ecount = 0;
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_parity, &pk) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, NULL) == 0);
CHECK(ecount == 2);
memset(&pk, 0, sizeof(pk));
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 0);
CHECK(ecount == 3);
/* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */
memset(sk, 0, sizeof(sk));
sk[0] = 1;
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0);
CHECK(pk_parity == 0);
/* Choose a secret key such that pubkey and xonly_pubkey are each others
* negation. */
sk[0] = 2;
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0);
CHECK(pk_parity == 1);
secp256k1_pubkey_load(ctx, &pk1, &pk);
secp256k1_pubkey_load(ctx, &pk2, (secp256k1_pubkey *) &xonly_pk);
CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1);
secp256k1_fe_negate(&y, &pk2.y, 1);
CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1);
/* Test xonly_pubkey_serialize and xonly_pubkey_parse */
ecount = 0;
CHECK(secp256k1_xonly_pubkey_serialize(none, NULL, &xonly_pk) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, NULL) == 0);
CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0);
CHECK(ecount == 2);
{
/* A pubkey filled with 0s will fail to serialize due to pubkey_load
* special casing. */
secp256k1_xonly_pubkey pk_tmp;
memset(&pk_tmp, 0, sizeof(pk_tmp));
CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &pk_tmp) == 0);
}
/* pubkey_load called illegal callback */
CHECK(ecount == 3);
CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &xonly_pk) == 1);
ecount = 0;
CHECK(secp256k1_xonly_pubkey_parse(none, NULL, buf32) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, NULL) == 0);
CHECK(ecount == 2);
/* Serialization and parse roundtrip */
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1);
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0);
/* Test parsing invalid field elements */
memset(&xonly_pk, 1, sizeof(xonly_pk));
/* Overflowing field element */
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, ones32) == 0);
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
memset(&xonly_pk, 1, sizeof(xonly_pk));
/* There's no point with x-coordinate 0 on secp256k1 */
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, zeros64) == 0);
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
/* If a random 32-byte string can not be parsed with ec_pubkey_parse
* (because interpreted as X coordinate it does not correspond to a point on
* the curve) then xonly_pubkey_parse should fail as well. */
for (i = 0; i < count; i++) {
unsigned char rand33[33];
secp256k1_testrand256(&rand33[1]);
rand33[0] = SECP256K1_TAG_PUBKEY_EVEN;
if (!secp256k1_ec_pubkey_parse(ctx, &pk, rand33, 33)) {
memset(&xonly_pk, 1, sizeof(xonly_pk));
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 0);
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
} else {
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 1);
}
}
CHECK(ecount == 2);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(verify);
}
void test_xonly_pubkey_tweak(void) {
unsigned char zeros64[64] = { 0 };
unsigned char overflows[32];
unsigned char sk[32];
secp256k1_pubkey internal_pk;
secp256k1_xonly_pubkey internal_xonly_pk;
secp256k1_pubkey output_pk;
int pk_parity;
unsigned char tweak[32];
int i;
int ecount;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
memset(overflows, 0xff, sizeof(overflows));
secp256k1_testrand256(tweak);
secp256k1_testrand256(sk);
CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
ecount = 0;
CHECK(secp256k1_xonly_pubkey_tweak_add(none, &output_pk, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &output_pk, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, NULL, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, NULL, tweak) == 0);
CHECK(ecount == 4);
/* NULL internal_xonly_pk zeroes the output_pk */
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, NULL) == 0);
CHECK(ecount == 5);
/* NULL tweak zeroes the output_pk */
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
/* Invalid tweak zeroes the output_pk */
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
/* A zero tweak is fine */
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, zeros64) == 1);
/* Fails if the resulting key was infinity */
for (i = 0; i < count; i++) {
secp256k1_scalar scalar_tweak;
/* Because sk may be negated before adding, we need to try with tweak =
* sk as well as tweak = -sk. */
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
secp256k1_scalar_get_b32(tweak, &scalar_tweak);
CHECK((secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, sk) == 0)
|| (secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0));
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
}
/* Invalid pk with a valid tweak */
memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk));
secp256k1_testrand256(tweak);
ecount = 0;
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(verify);
}
void test_xonly_pubkey_tweak_check(void) {
unsigned char zeros64[64] = { 0 };
unsigned char overflows[32];
unsigned char sk[32];
secp256k1_pubkey internal_pk;
secp256k1_xonly_pubkey internal_xonly_pk;
secp256k1_pubkey output_pk;
secp256k1_xonly_pubkey output_xonly_pk;
unsigned char output_pk32[32];
unsigned char buf32[32];
int pk_parity;
unsigned char tweak[32];
int ecount;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
memset(overflows, 0xff, sizeof(overflows));
secp256k1_testrand256(tweak);
secp256k1_testrand256(sk);
CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
ecount = 0;
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &output_xonly_pk, &pk_parity, &output_pk) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &output_xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(none, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(sign, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, NULL, pk_parity, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 3);
/* invalid pk_parity value */
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, 2, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, NULL, tweak) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, NULL) == 0);
CHECK(ecount == 5);
memset(tweak, 1, sizeof(tweak));
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, NULL, &internal_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &pk_parity, &output_pk) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk32, &output_xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1);
/* Wrong pk_parity */
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0);
/* Wrong public key */
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &internal_xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
/* Overflowing tweak not allowed */
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
CHECK(ecount == 5);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(verify);
}
/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1
* additional pubkeys by calling tweak_add. Then verifies every tweak starting
* from the last pubkey. */
#define N_PUBKEYS 32
void test_xonly_pubkey_tweak_recursive(void) {
unsigned char sk[32];
secp256k1_pubkey pk[N_PUBKEYS];
unsigned char pk_serialized[32];
unsigned char tweak[N_PUBKEYS - 1][32];
int i;
secp256k1_testrand256(sk);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk) == 1);
/* Add tweaks */
for (i = 0; i < N_PUBKEYS - 1; i++) {
secp256k1_xonly_pubkey xonly_pk;
memset(tweak[i], i + 1, sizeof(tweak[i]));
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i]) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &pk[i + 1], &xonly_pk, tweak[i]) == 1);
}
/* Verify tweaks */
for (i = N_PUBKEYS - 1; i > 0; i--) {
secp256k1_xonly_pubkey xonly_pk;
int pk_parity;
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk[i]) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk_serialized, &xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i - 1]) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1);
}
}
#undef N_PUBKEYS
void test_keypair(void) {
unsigned char sk[32];
unsigned char zeros96[96] = { 0 };
unsigned char overflows[32];
secp256k1_keypair keypair;
secp256k1_pubkey pk, pk_tmp;
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
int pk_parity, pk_parity_tmp;
int ecount;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
CHECK(sizeof(zeros96) == sizeof(keypair));
memset(overflows, 0xFF, sizeof(overflows));
/* Test keypair_create */
ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(none, &keypair, sk) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_keypair_create(verify, &keypair, sk) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
CHECK(secp256k1_keypair_create(sign, NULL, sk) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_keypair_create(sign, &keypair, NULL) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(ecount == 4);
/* Invalid secret key */
CHECK(secp256k1_keypair_create(sign, &keypair, zeros96) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(secp256k1_keypair_create(sign, &keypair, overflows) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
/* Test keypair_pub */
ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1);
CHECK(secp256k1_keypair_pub(none, NULL, &keypair) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_keypair_pub(none, &pk, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
/* Using an invalid keypair is fine for keypair_pub */
memset(&keypair, 0, sizeof(keypair));
CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
/* keypair holds the same pubkey as pubkey_create */
CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
CHECK(secp256k1_keypair_pub(none, &pk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0);
/** Test keypair_xonly_pub **/
ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1);
CHECK(secp256k1_keypair_xonly_pub(none, NULL, &pk_parity, &keypair) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, NULL, &keypair) == 1);
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
/* Using an invalid keypair will set the xonly_pk to 0 (first reset
* xonly_pk). */
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1);
memset(&keypair, 0, sizeof(keypair));
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
CHECK(ecount == 3);
/** keypair holds the same xonly pubkey as pubkey_create **/
CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0);
CHECK(pk_parity == pk_parity_tmp);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(verify);
}
void test_keypair_add(void) {
unsigned char sk[32];
secp256k1_keypair keypair;
unsigned char overflows[32];
unsigned char zeros96[96] = { 0 };
unsigned char tweak[32];
int i;
int ecount = 0;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
CHECK(sizeof(zeros96) == sizeof(keypair));
secp256k1_testrand256(sk);
secp256k1_testrand256(tweak);
memset(overflows, 0xFF, 32);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(none, &keypair, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(sign, &keypair, tweak) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(verify, NULL, tweak) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, NULL) == 0);
CHECK(ecount == 4);
/* This does not set the keypair to zeroes */
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0);
/* Invalid tweak zeroes the keypair */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, overflows) == 0);
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
/* A zero tweak is fine */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, zeros96) == 1);
/* Fails if the resulting keypair was (sk=0, pk=infinity) */
for (i = 0; i < count; i++) {
secp256k1_scalar scalar_tweak;
secp256k1_keypair keypair_tmp;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
memcpy(&keypair_tmp, &keypair, sizeof(keypair));
/* Because sk may be negated before adding, we need to try with tweak =
* sk as well as tweak = -sk. */
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
secp256k1_scalar_get_b32(tweak, &scalar_tweak);
CHECK((secp256k1_keypair_xonly_tweak_add(ctx, &keypair, sk) == 0)
|| (secp256k1_keypair_xonly_tweak_add(ctx, &keypair_tmp, tweak) == 0));
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0
|| secp256k1_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0);
}
/* Invalid keypair with a valid tweak */
memset(&keypair, 0, sizeof(keypair));
secp256k1_testrand256(tweak);
ecount = 0;
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
/* Only seckey part of keypair invalid */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
memset(&keypair, 0, 32);
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
CHECK(ecount == 2);
/* Only pubkey part of keypair invalid */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
memset(&keypair.data[32], 0, 64);
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
CHECK(ecount == 3);
/* Check that the keypair_tweak_add implementation is correct */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
for (i = 0; i < count; i++) {
secp256k1_xonly_pubkey internal_pk;
secp256k1_xonly_pubkey output_pk;
secp256k1_pubkey output_pk_xy;
secp256k1_pubkey output_pk_expected;
unsigned char pk32[32];
int pk_parity;
secp256k1_testrand256(tweak);
CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1);
/* Check that it passes xonly_pubkey_tweak_add_check */
CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk32, &output_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk32, pk_parity, &internal_pk, tweak) == 1);
/* Check that the resulting pubkey matches xonly_pubkey_tweak_add */
CHECK(secp256k1_keypair_pub(ctx, &output_pk_xy, &keypair) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk_expected, &internal_pk, tweak) == 1);
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
/* Check that the secret key in the keypair is tweaked correctly */
CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, &keypair.data[0]) == 1);
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
}
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(verify);
}
void run_extrakeys_tests(void) {
/* xonly key test cases */
test_xonly_pubkey();
test_xonly_pubkey_tweak();
test_xonly_pubkey_tweak_check();
test_xonly_pubkey_tweak_recursive();
/* keypair tests */
test_keypair();
test_keypair_add();
}
#endif

View File

@@ -15,55 +15,36 @@
#include "scalar.h"
static void secp256k1_generator_load(secp256k1_ge* ge, const secp256k1_generator* gen) {
int succeed;
succeed = secp256k1_fe_set_b32(&ge->x, &gen->data[0]);
VERIFY_CHECK(succeed != 0);
succeed = secp256k1_fe_set_b32(&ge->y, &gen->data[32]);
VERIFY_CHECK(succeed != 0);
ge->infinity = 0;
(void) succeed;
secp256k1_fe fe;
secp256k1_fe_set_b32(&fe, &gen->data[1]);
secp256k1_ge_set_xquad(ge, &fe);
if (gen->data[0] & 1) {
secp256k1_ge_neg(ge, ge);
}
}
static void secp256k1_generator_save(secp256k1_generator *gen, secp256k1_ge* ge) {
VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
secp256k1_fe_normalize_var(&ge->x);
secp256k1_fe_normalize_var(&ge->y);
secp256k1_fe_get_b32(&gen->data[0], &ge->x);
secp256k1_fe_get_b32(&gen->data[32], &ge->y);
static void secp256k1_generator_save(secp256k1_generator* commit, secp256k1_ge* ge) {
secp256k1_fe_normalize(&ge->x);
secp256k1_fe_get_b32(&commit->data[1], &ge->x);
commit->data[0] = 11 ^ secp256k1_fe_is_quad_var(&ge->y);
}
int secp256k1_generator_parse(const secp256k1_context* ctx, secp256k1_generator* gen, const unsigned char *input) {
secp256k1_fe x;
secp256k1_ge ge;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(gen != NULL);
ARG_CHECK(input != NULL);
if ((input[0] & 0xFE) != 10 ||
!secp256k1_fe_set_b32(&x, &input[1]) ||
!secp256k1_ge_set_xquad(&ge, &x)) {
if ((input[0] & 0xFE) != 10) {
return 0;
}
if (input[0] & 1) {
secp256k1_ge_neg(&ge, &ge);
}
secp256k1_generator_save(gen, &ge);
memcpy(gen->data, input, sizeof(gen->data));
return 1;
}
int secp256k1_generator_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_generator* gen) {
secp256k1_ge ge;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output != NULL);
ARG_CHECK(gen != NULL);
secp256k1_generator_load(&ge, gen);
output[0] = 11 ^ secp256k1_fe_is_quad_var(&ge.y);
secp256k1_fe_normalize_var(&ge.x);
secp256k1_fe_get_b32(&output[1], &ge.x);
memcpy(output, gen->data, sizeof(gen->data));
return 1;
}
@@ -161,13 +142,13 @@ static void shallue_van_de_woestijne(secp256k1_ge* ge, const secp256k1_fe* t) {
}
static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, secp256k1_generator* gen, const unsigned char *key32, const unsigned char *blind32) {
static const unsigned char prefix1[17] = "1st generation: ";
static const unsigned char prefix2[17] = "2nd generation: ";
static const unsigned char prefix1[16] = "1st generation: ";
static const unsigned char prefix2[16] = "2nd generation: ";
secp256k1_fe t = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 4);
secp256k1_ge add;
secp256k1_gej accum;
int overflow;
secp256k1_sha256 sha256;
secp256k1_sha256_t sha256;
unsigned char b32[32];
int ret = 1;
@@ -175,6 +156,7 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s
secp256k1_scalar blind;
secp256k1_scalar_set_b32(&blind, blind32, &overflow);
ret = !overflow;
CHECK(ret);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &accum, &blind);
}
@@ -183,6 +165,7 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s
secp256k1_sha256_write(&sha256, key32, 32);
secp256k1_sha256_finalize(&sha256, b32);
ret &= secp256k1_fe_set_b32(&t, b32);
CHECK(ret);
shallue_van_de_woestijne(&add, &t);
if (blind32) {
secp256k1_gej_add_ge(&accum, &accum, &add);
@@ -195,6 +178,7 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s
secp256k1_sha256_write(&sha256, key32, 32);
secp256k1_sha256_finalize(&sha256, b32);
ret &= secp256k1_fe_set_b32(&t, b32);
CHECK(ret);
shallue_van_de_woestijne(&add, &t);
secp256k1_gej_add_ge(&accum, &accum, &add);
@@ -207,6 +191,7 @@ int secp256k1_generator_generate(const secp256k1_context* ctx, secp256k1_generat
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(gen != NULL);
ARG_CHECK(key32 != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
return secp256k1_generator_generate_internal(ctx, gen, key32, NULL);
}

View File

@@ -17,65 +17,6 @@
#include "include/secp256k1_generator.h"
void test_generator_api(void) {
unsigned char key[32];
unsigned char blind[32];
unsigned char sergen[33];
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
secp256k1_generator gen;
int32_t ecount = 0;
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_testrand256(key);
secp256k1_testrand256(blind);
CHECK(secp256k1_generator_generate(none, &gen, key) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_generator_generate(none, NULL, key) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_generator_generate(none, &gen, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_generator_generate_blinded(sign, &gen, key, blind) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_generator_generate_blinded(vrfy, &gen, key, blind) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_generator_generate_blinded(none, &gen, key, blind) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_generator_generate_blinded(vrfy, NULL, key, blind) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_generator_generate_blinded(vrfy, &gen, NULL, blind) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_generator_generate_blinded(vrfy, &gen, key, NULL) == 0);
CHECK(ecount == 7);
CHECK(secp256k1_generator_serialize(none, sergen, &gen) == 1);
CHECK(ecount == 7);
CHECK(secp256k1_generator_serialize(none, NULL, &gen) == 0);
CHECK(ecount == 8);
CHECK(secp256k1_generator_serialize(none, sergen, NULL) == 0);
CHECK(ecount == 9);
CHECK(secp256k1_generator_serialize(none, sergen, &gen) == 1);
CHECK(secp256k1_generator_parse(none, &gen, sergen) == 1);
CHECK(ecount == 9);
CHECK(secp256k1_generator_parse(none, NULL, sergen) == 0);
CHECK(ecount == 10);
CHECK(secp256k1_generator_parse(none, &gen, NULL) == 0);
CHECK(ecount == 11);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(vrfy);
}
void test_shallue_van_de_woestijne(void) {
/* Matches with the output of the shallue_van_de_woestijne.sage SAGE program */
static const secp256k1_ge_storage results[32] = {
@@ -173,7 +114,7 @@ void test_generator_generate(void) {
secp256k1_ge_storage ges;
int i;
unsigned char v[32];
unsigned char s[32] = {0};
static const unsigned char s[32] = {0};
secp256k1_scalar sc;
secp256k1_scalar_set_b32(&sc, s, NULL);
for (i = 1; i <= 32; i++) {
@@ -188,39 +129,10 @@ void test_generator_generate(void) {
secp256k1_ge_to_storage(&ges, &ge);
CHECK(memcmp(&ges, &results[i - 1], sizeof(secp256k1_ge_storage)) == 0);
}
/* There is no range restriction on the value, but the blinder must be a
* valid scalar. Check that an invalid blinder causes the call to fail
* but not crash. */
memset(v, 0xff, 32);
CHECK(secp256k1_generator_generate(ctx, &gen, v));
memset(s, 0xff, 32);
CHECK(!secp256k1_generator_generate_blinded(ctx, &gen, v, s));
}
void test_generator_fixed_vector(void) {
const unsigned char two_g[33] = {
0x0b,
0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8,
0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5
};
unsigned char result[33];
secp256k1_generator parse;
CHECK(secp256k1_generator_parse(ctx, &parse, two_g));
CHECK(secp256k1_generator_serialize(ctx, result, &parse));
CHECK(memcmp(two_g, result, 33) == 0);
result[0] = 0x0a;
CHECK(secp256k1_generator_parse(ctx, &parse, result));
result[0] = 0x08;
CHECK(!secp256k1_generator_parse(ctx, &parse, result));
}
void run_generator_tests(void) {
test_shallue_van_de_woestijne();
test_generator_fixed_vector();
test_generator_api();
test_generator_generate();
}

View File

@@ -1,16 +0,0 @@
include_HEADERS += include/secp256k1_musig.h
noinst_HEADERS += src/modules/musig/main_impl.h
noinst_HEADERS += src/modules/musig/tests_impl.h
noinst_PROGRAMS += example_musig
example_musig_SOURCES = src/modules/musig/example.c
example_musig_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include $(SECP_INCLUDES)
if !ENABLE_COVERAGE
example_musig_CPPFLAGS += -DVERIFY
endif
example_musig_LDADD = libsecp256k1.la $(SECP_LIBS)
example_musig_LDFLAGS = -static
if USE_TESTS
TESTS += example_musig
endif

View File

@@ -1,168 +0,0 @@
/**********************************************************************
* Copyright (c) 2018 Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/**
* This file demonstrates how to use the MuSig module to create a multisignature.
* Additionally, see the documentation in include/secp256k1_musig.h.
*/
#include <stdio.h>
#include <assert.h>
#include <secp256k1.h>
#include <secp256k1_schnorrsig.h>
#include <secp256k1_musig.h>
/* Number of public keys involved in creating the aggregate signature */
#define N_SIGNERS 3
/* Create a key pair and store it in seckey and pubkey */
int create_keypair(const secp256k1_context* ctx, unsigned char *seckey, secp256k1_xonly_pubkey *pubkey) {
int ret;
secp256k1_keypair keypair;
FILE *frand = fopen("/dev/urandom", "r");
if (frand == NULL) {
return 0;
}
do {
if(!fread(seckey, 32, 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);
ret = secp256k1_keypair_create(ctx, &keypair, seckey);
ret &= secp256k1_keypair_xonly_pub(ctx, pubkey, NULL, &keypair);
return ret;
}
/* Sign a message hash with the given key pairs and store the result in sig */
int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_xonly_pubkey* pubkeys, const unsigned char* msg32, unsigned char *sig64) {
secp256k1_musig_session musig_session[N_SIGNERS];
unsigned char nonce_commitment[N_SIGNERS][32];
const unsigned char *nonce_commitment_ptr[N_SIGNERS];
secp256k1_musig_session_signer_data signer_data[N_SIGNERS][N_SIGNERS];
unsigned char nonce[N_SIGNERS][32];
int i, j;
secp256k1_musig_partial_signature partial_sig[N_SIGNERS];
for (i = 0; i < N_SIGNERS; i++) {
FILE *frand;
unsigned char session_id32[32];
secp256k1_xonly_pubkey combined_pk;
secp256k1_musig_pre_session pre_session;
/* Create combined pubkey and initialize signer data */
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, &pre_session, pubkeys, N_SIGNERS)) {
return 0;
}
/* Create random session ID. It is absolutely necessary that the session ID
* is unique for every call of secp256k1_musig_session_init. Otherwise
* it's trivial for an attacker to extract the secret key! */
frand = fopen("/dev/urandom", "r");
if(frand == NULL) {
return 0;
}
if (!fread(session_id32, 32, 1, frand)) {
fclose(frand);
return 0;
}
fclose(frand);
/* Initialize session */
if (!secp256k1_musig_session_init(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, &pre_session, N_SIGNERS, i, seckeys[i])) {
return 0;
}
nonce_commitment_ptr[i] = &nonce_commitment[i][0];
}
/* Communication round 1: Exchange nonce commitments */
for (i = 0; i < N_SIGNERS; i++) {
/* Set nonce commitments in the signer data and get the own public nonce */
if (!secp256k1_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], nonce[i], nonce_commitment_ptr, N_SIGNERS, NULL)) {
return 0;
}
}
/* Communication round 2: Exchange nonces */
for (i = 0; i < N_SIGNERS; i++) {
for (j = 0; j < N_SIGNERS; j++) {
if (!secp256k1_musig_set_nonce(ctx, &signer_data[i][j], nonce[j])) {
/* Signer j's nonce does not match the nonce commitment. In this case
* abort the protocol. If you make another attempt at finishing the
* protocol, create a new session (with a fresh session ID!). */
return 0;
}
}
if (!secp256k1_musig_session_combine_nonces(ctx, &musig_session[i], signer_data[i], N_SIGNERS, NULL, NULL)) {
return 0;
}
}
for (i = 0; i < N_SIGNERS; i++) {
if (!secp256k1_musig_partial_sign(ctx, &musig_session[i], &partial_sig[i])) {
return 0;
}
}
/* Communication round 3: Exchange partial signatures */
for (i = 0; i < N_SIGNERS; i++) {
for (j = 0; j < N_SIGNERS; j++) {
/* To check whether signing was successful, it suffices to either verify
* the combined signature with the combined public key using
* secp256k1_schnorrsig_verify, or verify all partial signatures of all
* signers individually. Verifying the combined signature is cheaper but
* verifying the individual partial signatures has the advantage that it
* can be used to determine which of the partial signatures are invalid
* (if any), i.e., which of the partial signatures cause the combined
* signature to be invalid and thus the protocol run to fail. It's also
* fine to first verify the combined sig, and only verify the individual
* sigs if it does not work.
*/
if (!secp256k1_musig_partial_sig_verify(ctx, &musig_session[i], &signer_data[i][j], &partial_sig[j], &pubkeys[j])) {
return 0;
}
}
}
return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig64, partial_sig, N_SIGNERS);
}
int main(void) {
secp256k1_context* ctx;
int i;
unsigned char seckeys[N_SIGNERS][32];
secp256k1_xonly_pubkey pubkeys[N_SIGNERS];
secp256k1_xonly_pubkey combined_pk;
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!";
unsigned char sig[64];
/* Create a context for signing and verification */
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
printf("Creating key pairs......");
for (i = 0; i < N_SIGNERS; i++) {
if (!create_keypair(ctx, seckeys[i], &pubkeys[i])) {
printf("FAILED\n");
return 1;
}
}
printf("ok\n");
printf("Combining public keys...");
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, NULL, pubkeys, N_SIGNERS)) {
printf("FAILED\n");
return 1;
}
printf("ok\n");
printf("Signing message.........");
if (!sign(ctx, seckeys, pubkeys, msg, sig)) {
printf("FAILED\n");
return 1;
}
printf("ok\n");
printf("Verifying signature.....");
if (!secp256k1_schnorrsig_verify(ctx, sig, msg, &combined_pk)) {
printf("FAILED\n");
return 1;
}
printf("ok\n");
secp256k1_context_destroy(ctx);
return 0;
}

View File

@@ -1,702 +0,0 @@
/**********************************************************************
* Copyright (c) 2018 Andrew Poelstra, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_MUSIG_MAIN_
#define _SECP256K1_MODULE_MUSIG_MAIN_
#include <stdint.h>
#include "include/secp256k1.h"
#include "include/secp256k1_musig.h"
#include "hash.h"
/* Computes ell = SHA256(pk[0], ..., pk[np-1]) */
static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_xonly_pubkey *pk, size_t np) {
secp256k1_sha256 sha;
size_t i;
secp256k1_sha256_initialize(&sha);
for (i = 0; i < np; i++) {
unsigned char ser[32];
if (!secp256k1_xonly_pubkey_serialize(ctx, ser, &pk[i])) {
return 0;
}
secp256k1_sha256_write(&sha, ser, 32);
}
secp256k1_sha256_finalize(&sha, ell);
return 1;
}
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("MuSig coefficient")||SHA256("MuSig coefficient"). */
static void secp256k1_musig_sha256_init_tagged(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0x0fd0690cul;
sha->s[1] = 0xfefeae97ul;
sha->s[2] = 0x996eac7ful;
sha->s[3] = 0x5c30d864ul;
sha->s[4] = 0x8c4a0573ul;
sha->s[5] = 0xaca1a22ful;
sha->s[6] = 0x6f43b801ul;
sha->s[7] = 0x85ce27cdul;
sha->bytes = 64;
}
/* Compute r = SHA256(ell, idx). The four bytes of idx are serialized least significant byte first. */
static void secp256k1_musig_coefficient(secp256k1_scalar *r, const unsigned char *ell, uint32_t idx) {
secp256k1_sha256 sha;
unsigned char buf[32];
size_t i;
secp256k1_musig_sha256_init_tagged(&sha);
secp256k1_sha256_write(&sha, ell, 32);
/* We're hashing the index of the signer instead of its public key as specified
* in the MuSig paper. This reduces the total amount of data that needs to be
* hashed.
* Additionally, it prevents creating identical musig_coefficients for identical
* public keys. A participant Bob could choose his public key to be the same as
* Alice's, then replay Alice's messages (nonce and partial signature) to create
* a valid partial signature. This is not a problem for MuSig per se, but could
* result in subtle issues with protocols building on threshold signatures.
* With the assumption that public keys are unique, hashing the index is
* equivalent to hashing the public key. Because the public key can be
* identified by the index given the ordered list of public keys (included in
* ell), the index is just a different encoding of the public key.*/
for (i = 0; i < sizeof(uint32_t); i++) {
unsigned char c = idx;
secp256k1_sha256_write(&sha, &c, 1);
idx >>= 8;
}
secp256k1_sha256_finalize(&sha, buf);
secp256k1_scalar_set_b32(r, buf, NULL);
}
typedef struct {
const secp256k1_context *ctx;
unsigned char ell[32];
const secp256k1_xonly_pubkey *pks;
} secp256k1_musig_pubkey_combine_ecmult_data;
/* Callback for batch EC multiplication to compute ell_0*P0 + ell_1*P1 + ... */
static int secp256k1_musig_pubkey_combine_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
secp256k1_musig_pubkey_combine_ecmult_data *ctx = (secp256k1_musig_pubkey_combine_ecmult_data *) data;
secp256k1_musig_coefficient(sc, ctx->ell, idx);
return secp256k1_xonly_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]);
}
static void secp256k1_musig_signers_init(secp256k1_musig_session_signer_data *signers, uint32_t n_signers) {
uint32_t i;
for (i = 0; i < n_signers; i++) {
memset(&signers[i], 0, sizeof(signers[i]));
signers[i].index = i;
signers[i].present = 0;
}
}
static const uint64_t pre_session_magic = 0xf4adbbdf7c7dd304UL;
int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const secp256k1_xonly_pubkey *pubkeys, size_t n_pubkeys) {
secp256k1_musig_pubkey_combine_ecmult_data ecmult_data;
secp256k1_gej pkj;
secp256k1_ge pkp;
int pk_parity;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(combined_pk != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(pubkeys != NULL);
ARG_CHECK(n_pubkeys > 0);
ecmult_data.ctx = ctx;
ecmult_data.pks = pubkeys;
if (!secp256k1_musig_compute_ell(ctx, ecmult_data.ell, pubkeys, n_pubkeys)) {
return 0;
}
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &pkj, NULL, secp256k1_musig_pubkey_combine_callback, (void *) &ecmult_data, n_pubkeys)) {
return 0;
}
secp256k1_ge_set_gej(&pkp, &pkj);
secp256k1_fe_normalize(&pkp.y);
pk_parity = secp256k1_extrakeys_ge_even_y(&pkp);
secp256k1_xonly_pubkey_save(combined_pk, &pkp);
if (pre_session != NULL) {
pre_session->magic = pre_session_magic;
memcpy(pre_session->pk_hash, ecmult_data.ell, 32);
pre_session->pk_parity = pk_parity;
pre_session->is_tweaked = 0;
}
return 1;
}
int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_musig_pre_session *pre_session, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
secp256k1_ge pk;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pre_session != NULL);
ARG_CHECK(pre_session->magic == pre_session_magic);
/* This function can only be called once because otherwise signing would not
* succeed */
ARG_CHECK(pre_session->is_tweaked == 0);
pre_session->internal_key_parity = pre_session->pk_parity;
if(!secp256k1_xonly_pubkey_tweak_add(ctx, output_pubkey, internal_pubkey, tweak32)) {
return 0;
}
memcpy(pre_session->tweak, tweak32, 32);
pre_session->is_tweaked = 1;
if (!secp256k1_pubkey_load(ctx, &pk, output_pubkey)) {
return 0;
}
pre_session->pk_parity = secp256k1_extrakeys_ge_even_y(&pk);
return 1;
}
static const uint64_t session_magic = 0xd92e6fc1ee41b4cbUL;
int secp256k1_musig_session_init(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, size_t n_signers, size_t my_index, const unsigned char *seckey) {
unsigned char combined_ser[32];
int overflow;
secp256k1_scalar secret;
secp256k1_scalar mu;
secp256k1_sha256 sha;
secp256k1_gej pj;
secp256k1_ge p;
unsigned char nonce_ser[32];
size_t nonce_ser_size = sizeof(nonce_ser);
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(session != NULL);
ARG_CHECK(signers != NULL);
ARG_CHECK(nonce_commitment32 != NULL);
ARG_CHECK(session_id32 != NULL);
ARG_CHECK(combined_pk != NULL);
ARG_CHECK(pre_session != NULL);
ARG_CHECK(pre_session->magic == pre_session_magic);
ARG_CHECK(seckey != NULL);
ARG_CHECK(n_signers > 0);
ARG_CHECK(n_signers <= UINT32_MAX);
ARG_CHECK(my_index < n_signers);
memset(session, 0, sizeof(*session));
session->magic = session_magic;
if (msg32 != NULL) {
memcpy(session->msg, msg32, 32);
session->is_msg_set = 1;
} else {
session->is_msg_set = 0;
}
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
session->pre_session = *pre_session;
session->has_secret_data = 1;
session->n_signers = (uint32_t) n_signers;
secp256k1_musig_signers_init(signers, session->n_signers);
/* Compute secret key */
secp256k1_scalar_set_b32(&secret, seckey, &overflow);
if (overflow) {
secp256k1_scalar_clear(&secret);
return 0;
}
secp256k1_musig_coefficient(&mu, session->pre_session.pk_hash, (uint32_t) my_index);
/* Compute the signer's public key point and determine if the secret is
* negated before signing. That happens if if the signer's pubkey has an odd
* Y coordinate XOR the MuSig-combined pubkey has an odd Y coordinate XOR
* (if tweaked) the internal key has an odd Y coordinate.
*
* This can be seen by looking at the secret key belonging to `combined_pk`.
* Let's define
* P' := mu_0*|P_0| + ... + mu_n*|P_n| where P_i is the i-th public key
* point x_i*G, mu_i is the i-th musig coefficient and |.| is a function
* that normalizes a point to an even Y by negating if necessary similar to
* secp256k1_extrakeys_ge_even_y. Then we have
* P := |P'| + t*G where t is the tweak.
* And the combined xonly public key is
* |P| = x*G
* where x = sum_i(b_i*mu_i*x_i) + b'*t
* b' = -1 if P != |P|, 1 otherwise
* b_i = -1 if (P_i != |P_i| XOR P' != |P'| XOR P != |P|) and 1
* otherwise.
*/
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret);
secp256k1_ge_set_gej(&p, &pj);
secp256k1_fe_normalize(&p.y);
if((secp256k1_fe_is_odd(&p.y)
+ session->pre_session.pk_parity
+ (session->pre_session.is_tweaked
&& session->pre_session.internal_key_parity))
% 2 == 1) {
secp256k1_scalar_negate(&secret, &secret);
}
secp256k1_scalar_mul(&secret, &secret, &mu);
secp256k1_scalar_get_b32(session->seckey, &secret);
/* Compute secret nonce */
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, session_id32, 32);
if (session->is_msg_set) {
secp256k1_sha256_write(&sha, msg32, 32);
}
secp256k1_xonly_pubkey_serialize(ctx, combined_ser, combined_pk);
secp256k1_sha256_write(&sha, combined_ser, 32);
secp256k1_sha256_write(&sha, seckey, 32);
secp256k1_sha256_finalize(&sha, session->secnonce);
secp256k1_scalar_set_b32(&secret, session->secnonce, &overflow);
if (overflow) {
secp256k1_scalar_clear(&secret);
return 0;
}
/* Compute public nonce and commitment */
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret);
secp256k1_ge_set_gej(&p, &pj);
secp256k1_fe_normalize_var(&p.y);
session->partial_nonce_parity = secp256k1_extrakeys_ge_even_y(&p);
secp256k1_xonly_pubkey_save(&session->nonce, &p);
secp256k1_sha256_initialize(&sha);
secp256k1_xonly_pubkey_serialize(ctx, nonce_ser, &session->nonce);
secp256k1_sha256_write(&sha, nonce_ser, nonce_ser_size);
secp256k1_sha256_finalize(&sha, nonce_commitment32);
session->round = 0;
secp256k1_scalar_clear(&secret);
return 1;
}
int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce, const unsigned char *const *commitments, size_t n_commitments, const unsigned char *msg32) {
secp256k1_sha256 sha;
unsigned char nonce_commitments_hash[32];
size_t i;
unsigned char nonce_ser[32];
size_t nonce_ser_size = sizeof(nonce_ser);
(void) ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(session->magic == session_magic);
ARG_CHECK(signers != NULL);
ARG_CHECK(nonce != NULL);
ARG_CHECK(commitments != NULL);
ARG_CHECK(session->round == 0);
/* If the message was not set during initialization it must be set now. */
ARG_CHECK(!(!session->is_msg_set && msg32 == NULL));
/* The message can only be set once. */
ARG_CHECK(!(session->is_msg_set && msg32 != NULL));
ARG_CHECK(session->has_secret_data);
ARG_CHECK(n_commitments == session->n_signers);
for (i = 0; i < n_commitments; i++) {
ARG_CHECK(commitments[i] != NULL);
}
if (msg32 != NULL) {
memcpy(session->msg, msg32, 32);
session->is_msg_set = 1;
}
secp256k1_sha256_initialize(&sha);
for (i = 0; i < n_commitments; i++) {
memcpy(signers[i].nonce_commitment, commitments[i], 32);
secp256k1_sha256_write(&sha, commitments[i], 32);
}
secp256k1_sha256_finalize(&sha, nonce_commitments_hash);
memcpy(session->nonce_commitments_hash, nonce_commitments_hash, 32);
secp256k1_xonly_pubkey_serialize(ctx, nonce_ser, &session->nonce);
memcpy(nonce, &nonce_ser, nonce_ser_size);
session->round = 1;
return 1;
}
int secp256k1_musig_session_init_verifier(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, const unsigned char *const *commitments, size_t n_signers) {
size_t i;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(signers != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(combined_pk != NULL);
ARG_CHECK(pre_session != NULL);
ARG_CHECK(pre_session->magic == pre_session_magic);
ARG_CHECK(commitments != NULL);
/* Check n_signers before checking commitments to allow testing the case where
* n_signers is big without allocating the space. */
ARG_CHECK(n_signers > 0);
ARG_CHECK(n_signers <= UINT32_MAX);
for (i = 0; i < n_signers; i++) {
ARG_CHECK(commitments[i] != NULL);
}
(void) ctx;
memset(session, 0, sizeof(*session));
session->magic = session_magic;
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
session->pre_session = *pre_session;
session->n_signers = (uint32_t) n_signers;
secp256k1_musig_signers_init(signers, session->n_signers);
session->pre_session = *pre_session;
session->is_msg_set = 1;
memcpy(session->msg, msg32, 32);
session->has_secret_data = 0;
for (i = 0; i < n_signers; i++) {
memcpy(signers[i].nonce_commitment, commitments[i], 32);
}
session->round = 1;
return 1;
}
int secp256k1_musig_set_nonce(const secp256k1_context* ctx, secp256k1_musig_session_signer_data *signer, const unsigned char *nonce) {
secp256k1_sha256 sha;
unsigned char commit[32];
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(signer != NULL);
ARG_CHECK(nonce != NULL);
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, nonce, 32);
secp256k1_sha256_finalize(&sha, commit);
if (memcmp(commit, signer->nonce_commitment, 32) != 0) {
return 0;
}
memcpy(&signer->nonce, nonce, sizeof(*nonce));
if (!secp256k1_xonly_pubkey_parse(ctx, &signer->nonce, nonce)) {
return 0;
}
signer->present = 1;
return 1;
}
int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signers, size_t n_signers, int *nonce_parity, const secp256k1_pubkey *adaptor) {
secp256k1_gej combined_noncej;
secp256k1_ge combined_noncep;
secp256k1_ge noncep;
secp256k1_sha256 sha;
unsigned char nonce_commitments_hash[32];
size_t i;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(signers != NULL);
ARG_CHECK(session->magic == session_magic);
ARG_CHECK(session->round == 1);
ARG_CHECK(n_signers == session->n_signers);
secp256k1_sha256_initialize(&sha);
secp256k1_gej_set_infinity(&combined_noncej);
for (i = 0; i < n_signers; i++) {
if (!signers[i].present) {
return 0;
}
secp256k1_sha256_write(&sha, signers[i].nonce_commitment, 32);
secp256k1_xonly_pubkey_load(ctx, &noncep, &signers[i].nonce);
secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL);
}
secp256k1_sha256_finalize(&sha, nonce_commitments_hash);
/* If the signers' commitments changed between get_public_nonce and now we
* have to abort because in that case they may have seen our nonce before
* creating their commitment. That can happen if the signer_data given to
* this function is different to the signer_data given to get_public_nonce.
* */
if (session->has_secret_data
&& memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) {
return 0;
}
/* Add public adaptor to nonce */
if (adaptor != NULL) {
secp256k1_pubkey_load(ctx, &noncep, adaptor);
secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL);
}
/* Negate nonce if Y coordinate is not square */
secp256k1_ge_set_gej(&combined_noncep, &combined_noncej);
secp256k1_fe_normalize_var(&combined_noncep.y);
session->combined_nonce_parity = secp256k1_extrakeys_ge_even_y(&combined_noncep);
if (nonce_parity != NULL) {
*nonce_parity = session->combined_nonce_parity;
}
secp256k1_xonly_pubkey_save(&session->combined_nonce, &combined_noncep);
session->round = 2;
return 1;
}
int secp256k1_musig_partial_signature_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_signature* sig) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(out32 != NULL);
ARG_CHECK(sig != NULL);
memcpy(out32, sig->data, 32);
return 1;
}
int secp256k1_musig_partial_signature_parse(const secp256k1_context* ctx, secp256k1_musig_partial_signature* sig, const unsigned char *in32) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(in32 != NULL);
memcpy(sig->data, in32, 32);
return 1;
}
/* Compute msghash = SHA256(combined_nonce, combined_pk, msg) */
static void secp256k1_musig_compute_messagehash(const secp256k1_context *ctx, unsigned char *msghash, const secp256k1_musig_session *session) {
unsigned char buf[32];
secp256k1_ge rp;
secp256k1_sha256 sha;
VERIFY_CHECK(session->round >= 2);
secp256k1_schnorrsig_sha256_tagged(&sha);
secp256k1_xonly_pubkey_load(ctx, &rp, &session->combined_nonce);
secp256k1_fe_get_b32(buf, &rp.x);
secp256k1_sha256_write(&sha, buf, 32);
secp256k1_xonly_pubkey_serialize(ctx, buf, &session->combined_pk);
secp256k1_sha256_write(&sha, buf, 32);
secp256k1_sha256_write(&sha, session->msg, 32);
secp256k1_sha256_finalize(&sha, msghash);
}
int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_musig_partial_signature *partial_sig) {
unsigned char msghash[32];
int overflow;
secp256k1_scalar sk;
secp256k1_scalar e, k;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(partial_sig != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(session->magic == session_magic);
ARG_CHECK(session->round == 2);
ARG_CHECK(session->has_secret_data);
/* build message hash */
secp256k1_musig_compute_messagehash(ctx, msghash, session);
secp256k1_scalar_set_b32(&e, msghash, NULL);
secp256k1_scalar_set_b32(&sk, session->seckey, &overflow);
if (overflow) {
secp256k1_scalar_clear(&sk);
return 0;
}
secp256k1_scalar_set_b32(&k, session->secnonce, &overflow);
if (overflow || secp256k1_scalar_is_zero(&k)) {
secp256k1_scalar_clear(&sk);
secp256k1_scalar_clear(&k);
return 0;
}
if (session->partial_nonce_parity != session->combined_nonce_parity) {
secp256k1_scalar_negate(&k, &k);
}
/* Sign */
secp256k1_scalar_mul(&e, &e, &sk);
secp256k1_scalar_add(&e, &e, &k);
secp256k1_scalar_get_b32(&partial_sig->data[0], &e);
secp256k1_scalar_clear(&sk);
secp256k1_scalar_clear(&k);
return 1;
}
int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs) {
size_t i;
secp256k1_scalar s;
secp256k1_ge noncep;
(void) ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig64 != NULL);
ARG_CHECK(partial_sigs != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(session->magic == session_magic);
ARG_CHECK(session->round == 2);
if (n_sigs != session->n_signers) {
return 0;
}
secp256k1_scalar_clear(&s);
for (i = 0; i < n_sigs; i++) {
int overflow;
secp256k1_scalar term;
secp256k1_scalar_set_b32(&term, partial_sigs[i].data, &overflow);
if (overflow) {
return 0;
}
secp256k1_scalar_add(&s, &s, &term);
}
/* If there is a tweak then add (or subtract) `msghash` times `tweak` to `s`.*/
if (session->pre_session.is_tweaked) {
unsigned char msghash[32];
secp256k1_scalar e, scalar_tweak;
int overflow = 0;
secp256k1_musig_compute_messagehash(ctx, msghash, session);
secp256k1_scalar_set_b32(&e, msghash, NULL);
secp256k1_scalar_set_b32(&scalar_tweak, session->pre_session.tweak, &overflow);
if (overflow || !secp256k1_eckey_privkey_tweak_mul(&e, &scalar_tweak)) {
/* This mimics the behavior of secp256k1_ec_seckey_tweak_mul regarding
* overflow and tweak being 0. */
return 0;
}
if (session->pre_session.pk_parity) {
secp256k1_scalar_negate(&e, &e);
}
secp256k1_scalar_add(&s, &s, &e);
}
secp256k1_xonly_pubkey_load(ctx, &noncep, &session->combined_nonce);
VERIFY_CHECK(!secp256k1_fe_is_odd(&noncep.y));
secp256k1_fe_normalize(&noncep.x);
secp256k1_fe_get_b32(&sig64[0], &noncep.x);
secp256k1_scalar_get_b32(&sig64[32], &s);
return 1;
}
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, const secp256k1_musig_partial_signature *partial_sig, const secp256k1_xonly_pubkey *pubkey) {
unsigned char msghash[32];
secp256k1_scalar s;
secp256k1_scalar e;
secp256k1_scalar mu;
secp256k1_gej pkj;
secp256k1_gej rj;
secp256k1_ge pkp;
secp256k1_ge rp;
int overflow;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(session != NULL);
ARG_CHECK(signer != NULL);
ARG_CHECK(partial_sig != NULL);
ARG_CHECK(pubkey != NULL);
ARG_CHECK(session->magic == session_magic);
ARG_CHECK(session->round == 2);
ARG_CHECK(signer->present);
secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow);
if (overflow) {
return 0;
}
secp256k1_musig_compute_messagehash(ctx, msghash, session);
secp256k1_scalar_set_b32(&e, msghash, NULL);
/* Multiplying the messagehash by the musig coefficient is equivalent
* to multiplying the signer's public key by the coefficient, except
* much easier to do. */
secp256k1_musig_coefficient(&mu, session->pre_session.pk_hash, signer->index);
secp256k1_scalar_mul(&e, &e, &mu);
if (!secp256k1_xonly_pubkey_load(ctx, &rp, &signer->nonce)) {
return 0;
}
/* If the MuSig-combined point has an odd Y coordinate, the signers will
* sign for the negation of their individual xonly public key such that the
* combined signature is valid for the MuSig aggregated xonly key. If the
* MuSig-combined point was tweaked then `e` is negated if the combined key
* has an odd Y coordinate XOR the internal key has an odd Y coordinate.*/
if (session->pre_session.pk_parity
!= (session->pre_session.is_tweaked
&& session->pre_session.internal_key_parity)) {
secp256k1_scalar_negate(&e, &e);
}
/* Compute rj = s*G + (-e)*pkj */
secp256k1_scalar_negate(&e, &e);
if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) {
return 0;
}
secp256k1_gej_set_ge(&pkj, &pkp);
secp256k1_ecmult(&ctx->ecmult_ctx, &rj, &pkj, &e, &s);
if (!session->combined_nonce_parity) {
secp256k1_ge_neg(&rp, &rp);
}
secp256k1_gej_add_ge_var(&rj, &rj, &rp, NULL);
return secp256k1_gej_is_infinity(&rj);
}
int secp256k1_musig_partial_sig_adapt(const secp256k1_context* ctx, secp256k1_musig_partial_signature *adaptor_sig, const secp256k1_musig_partial_signature *partial_sig, const unsigned char *sec_adaptor32, int nonce_parity) {
secp256k1_scalar s;
secp256k1_scalar t;
int overflow;
(void) ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(adaptor_sig != NULL);
ARG_CHECK(partial_sig != NULL);
ARG_CHECK(sec_adaptor32 != NULL);
secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow);
if (overflow) {
return 0;
}
secp256k1_scalar_set_b32(&t, sec_adaptor32, &overflow);
if (overflow) {
secp256k1_scalar_clear(&t);
return 0;
}
if (nonce_parity) {
secp256k1_scalar_negate(&t, &t);
}
secp256k1_scalar_add(&s, &s, &t);
secp256k1_scalar_get_b32(adaptor_sig->data, &s);
secp256k1_scalar_clear(&t);
return 1;
}
int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigned char *sec_adaptor32, const unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_parity) {
secp256k1_scalar t;
secp256k1_scalar s;
int overflow;
size_t i;
(void) ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sec_adaptor32 != NULL);
ARG_CHECK(sig64 != NULL);
ARG_CHECK(partial_sigs != NULL);
secp256k1_scalar_set_b32(&t, &sig64[32], &overflow);
if (overflow) {
return 0;
}
secp256k1_scalar_negate(&t, &t);
for (i = 0; i < n_partial_sigs; i++) {
secp256k1_scalar_set_b32(&s, partial_sigs[i].data, &overflow);
if (overflow) {
secp256k1_scalar_clear(&t);
return 0;
}
secp256k1_scalar_add(&t, &t, &s);
}
if (!nonce_parity) {
secp256k1_scalar_negate(&t, &t);
}
secp256k1_scalar_get_b32(sec_adaptor32, &t);
secp256k1_scalar_clear(&t);
return 1;
}
#endif

View File

@@ -1,198 +0,0 @@
MuSig - Rogue-Key-Resistant Multisignatures Module
===========================
This module implements the MuSig [1] multisignature scheme. The majority of
the module is an API designed to be used by signing or auditing participants
in a multisignature scheme. This involves a somewhat complex state machine
and significant effort has been taken to prevent accidental misuse of the
API in ways that could lead to accidental signatures or loss of key material.
The resulting signatures are valid Schnorr signatures as described in [2].
# Theory
In MuSig all signers contribute key material to a single signing key,
using the equation
P = sum_i µ_i * P_i
where `P_i` is the public key of the `i`th signer and `µ_i` is a so-called
_MuSig coefficient_ computed according to the following equation
L = H(P_1 || P_2 || ... || P_n)
µ_i = H(L || i)
where H is a hash function modelled as a random oracle.
To produce a multisignature `(s, R)` on a message `m` using verification key
`P`, signers act as follows:
1. Each computes a nonce, or ephemeral keypair, `(k_i, R_i)`. Every signer
communicates `H(R_i)` to every participant (both signers and auditors).
2. Upon receipt of every `H(R_i)`, each signer communicates `R_i` to every
participant. The recipients check that each `R_i` is consistent with the
previously-communicated hash.
3. Each signer computes a combined nonce
`R = sum_i R_i`
and shared challenge
`e = H(R || P || m)`
and partial signature
`s_i = k_i + µ_i*x_i*e`
where `x_i` is the secret key corresponding to `P_i`.
The complete signature is then the `(s, R)` where `s = sum_i s_i` and `R = sum_i R_i`.
# API Usage
The following sections describe use of our API, and are mirrored in code in `src/modules/musig/example.c`.
It is essential to security that signers use a unique uniformly random nonce for all
signing sessions, and that they do not reuse these nonces even in the case that a
signing session fails to complete. To that end, all signing state is encapsulated
in the data structure `secp256k1_musig_session`. The API does not expose any
functionality to serialize or deserialize this structure; it is designed to exist
only in memory.
Users who need to persist this structure must take additional security measures
which cannot be enforced by a C API. Some guidance is provided in the documentation
for this data structure in `include/secp256k1_musig.h`.
## Key Generation
To use MuSig, users must first compute their combined public key `P`, which is
suitable for use on a blockchain or other public key repository. They do this
by calling `secp256k1_musig_pubkey_combine`.
This function takes as input a list of public keys `P_i` in the argument
`pubkeys`. It outputs the combined public key `P` in the out-pointer `combined_pk`
and hash `L` in the out-pointer `pk_hash32`, if this pointer is non-NULL.
## Signing
A participant who wishes to sign a message (as opposed to observing/auditing the
signature process, which is also a supported mode) acts as follows.
### Signing Participant
1. The signer starts the session by calling `secp256k1_musig_session_init`.
This function outputs
- an initialized session state in the out-pointer `session`
- an array of initialized signer data in the out-pointer `signers`
- a commitment `H(R_i)` to a nonce in the out-pointer `nonce_commitment32`
It takes as input
- a unique session ID `session_id32`
- (optionally) a message to be signed `msg32`
- the combined public key output from `secp256k1_musig_pubkey_combine`
- the public key hash output from `secp256k1_musig_pubkey_combine`
- the signer's index `i` `my_index`
- the signer's secret key `seckey`
2. The signer then communicates `H(R_i)` to all other signers, and receives
commitments `H(R_j)` from all other signers `j`. These hashes are simply
length-32 byte arrays which can be communicated however is communicated.
3. Once all signers nonce commitments have been received, the signer records
these commitments with the function `secp256k1_musig_session_get_public_nonce`.
If the signer did not provide a message to `secp256k1_musig_session_init`,
a message must be provided now.
This function updates in place
- the session state `session`
- the array of signer data `signers`
taking in as input the list of commitments `commitments` and outputting the
signer's public nonce `R_i` in the out-pointer `nonce`.
4. The signer then communicates `R_i` to all other signers, and receives `R_j`
from each signer `j`. On receipt of a nonce `R_j` he calls the function
`secp256k1_musig_set_nonce` to record this fact. This function checks that
the received nonce is consistent with the previously-received nonce and will
return 0 in this case. The signer must also call this function with his own
nonce and his own index `i`.
These nonces `R_i` are secp256k1 public keys; they should be serialized using
`secp256k1_ec_pubkey_serialize` and parsed with `secp256k1_ec_pubkey_parse`.
5. Once all nonces have been exchanged in this way, signers are able to compute
their partial signatures. They do so by calling `secp256k1_musig_session_combine_nonces`
which updates in place
- the session state `session`
- the array of signer data `signers`
It outputs an auxiliary integer `nonce_is_negated` and has an auxiliary input
`adaptor`. Both of these may be set to NULL for ordinary signing purposes.
6. The signer computes a partial signature `s_i` using the function
`secp256k1_musig_partial_sign` which takes the session state as input and
partial signature as output.
7. The signer then communicates the partial signature `s_i` to all other signers, or
to a central coordinator. These partial signatures should be serialized using
`musig_partial_signature_serialize` and parsed using `musig_partial_signature_parse`.
8. Each signer calls `secp256k1_musig_partial_sig_verify` on the other signers' partial
signatures to verify their correctness. If only the validity of the final signature
is important, not assigning blame, this step can be skipped.
9. Any signer, or central coordinator, may combine the partial signatures to obtain
a complete signature using `secp256k1_musig_partial_sig_combine`. This function takes
a signing session and array of MuSig partial signatures, and outputs a single
Schnorr signature.
### Non-signing Participant
A participant who wants to verify the signing process, i.e. check that nonce commitments
are consistent and partial signatures are correct without contributing a partial signature,
may do so using the above instructions except for the following changes:
1. A signing session should be produced using `musig_session_init_verifier`
rather than `musig_session_init`; this function takes no secret data or
signer index.
2. The participant receives nonce commitments, public nonces and partial signatures,
but does not produce these values. Therefore `secp256k1_musig_session_get_public_nonce`
and `secp256k1_musig_partial_sign` are not called.
### Verifier
The final signature is simply a valid Schnorr signature using the combined public key. It
can be verified using the `secp256k1_schnorrsig_verify` with the correct message and
public key output from `secp256k1_musig_pubkey_combine`.
## Atomic Swaps
The signing API supports the production of "adaptor signatures", modified partial signatures
which are offset by an auxiliary secret known to one party. That is,
1. One party generates a (secret) adaptor `t` with corresponding (public) adaptor `T = t*G`.
2. When combining nonces, each party adds `T` to the total nonce used in the signature.
3. The party who knows `t` must "adapt" their partial signature with `t` to complete the
signature.
4. Any party who sees both the final signature and the original partial signatures
can compute `t`.
Using these adaptor signatures, two 2-of-2 MuSig signing protocols can be executed in
parallel such that one party's partial signatures are made atomic. That is, when the other
party learns one partial signature, she automatically learns the other. This has applications
in cross-chain atomic swaps.
Such a protocol can be executed as follows. Consider two participants, Alice and Bob, who
are simultaneously producing 2-of-2 multisignatures for two blockchains A and B. They act
as follows.
1. Before the protocol begins, Bob chooses a 32-byte auxiliary secret `t` at random and
computes a corresponding public point `T` by calling `secp256k1_ec_pubkey_create`.
He communicates `T` to Alice.
2. Together, the parties execute steps 1-4 of the signing protocol above.
3. At step 5, when combining the two parties' public nonces, both parties call
`secp256k1_musig_session_combine_nonces` with `adaptor` set to `T` and `nonce_is_negated`
set to a non-NULL pointer to int.
4. Steps 6 and 7 proceed as before. Step 8, verifying the partial signatures, is now
essential to the security of the protocol and must not be omitted!
The above steps are executed identically for both signing sessions. However, step 9 will
not work as before, since the partial signatures will not add up to a valid total signature.
Additional steps must be taken, and it is at this point that the two signing sessions
diverge. From here on we consider "Session A" which benefits Alice (e.g. which sends her
coins) and "Session B" which benefits Bob (e.g. which sends him coins).
5. In Session B, Bob calls `secp256k1_musig_partial_sig_adapt` with his partial signature
and `t`, to produce an adaptor signature. He can then call `secp256k1_musig_partial_sig_combine`
with this adaptor signature and Alice's partial signature, to produce a complete
signature for blockchain B.
6. Alice reads this signature from blockchain B. She calls `secp256k1_musig_extract_secret_adaptor`,
passing the complete signature along with her and Bob's partial signatures from Session B.
This function outputs `t`, which until this point was only known to Bob.
7. In Session A, Alice is now able to replicate Bob's action, calling
`secp256k1_musig_partial_sig_adapt` with her own partial signature and `t`, ultimately
producing a complete signature on blockchain A.
[1] https://eprint.iacr.org/2018/068
[2] https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki

View File

@@ -1,969 +0,0 @@
/**********************************************************************
* Copyright (c) 2018 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_MUSIG_TESTS_
#define _SECP256K1_MODULE_MUSIG_TESTS_
#include "secp256k1_musig.h"
int secp256k1_xonly_pubkey_create(secp256k1_xonly_pubkey *pk, const unsigned char *seckey) {
int ret;
secp256k1_keypair keypair;
ret = secp256k1_keypair_create(ctx, &keypair, seckey);
ret &= secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair);
return ret;
}
/* Just a simple (non-adaptor, non-tweaked) 2-of-2 MuSig combine, sign, verify
* test. */
void musig_simple_test(secp256k1_scratch_space *scratch) {
unsigned char sk[2][32];
secp256k1_musig_session session[2];
secp256k1_musig_session_signer_data signer0[2];
secp256k1_musig_session_signer_data signer1[2];
unsigned char nonce_commitment[2][32];
unsigned char msg[32];
secp256k1_xonly_pubkey combined_pk;
secp256k1_musig_pre_session pre_session;
unsigned char session_id[2][32];
secp256k1_xonly_pubkey pk[2];
const unsigned char *ncs[2];
unsigned char public_nonce[3][32];
secp256k1_musig_partial_signature partial_sig[2];
unsigned char final_sig[64];
secp256k1_testrand256(session_id[0]);
secp256k1_testrand256(session_id[1]);
secp256k1_testrand256(sk[0]);
secp256k1_testrand256(sk[1]);
secp256k1_testrand256(msg);
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
ncs[0] = nonce_commitment[0];
ncs[1] = nonce_commitment[1];
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signer0, public_nonce[0], ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signer1, public_nonce[1], ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signer0[0], public_nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signer0[1], public_nonce[1]) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signer1[0], public_nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signer1[1], public_nonce[1]) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signer0, 2, NULL, NULL) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signer1, 2, NULL, NULL) == 1);
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1);
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signer0[1], &partial_sig[1], &pk[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1);
CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], final_sig, partial_sig, 2) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, &combined_pk) == 1);
}
void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_scratch_space *scratch_small;
secp256k1_musig_session session[2];
secp256k1_musig_session session_uninitialized;
secp256k1_musig_session verifier_session;
secp256k1_musig_session_signer_data signer0[2];
secp256k1_musig_session_signer_data signer1[2];
secp256k1_musig_session_signer_data verifier_signer_data[2];
secp256k1_musig_partial_signature partial_sig[2];
secp256k1_musig_partial_signature partial_sig_adapted[2];
secp256k1_musig_partial_signature partial_sig_overflow;
unsigned char final_sig[64];
unsigned char final_sig_cmp[64];
unsigned char buf[32];
unsigned char sk[2][32];
unsigned char ones[32];
unsigned char session_id[2][32];
unsigned char nonce_commitment[2][32];
int combined_nonce_parity;
const unsigned char *ncs[2];
unsigned char msg[32];
secp256k1_xonly_pubkey combined_pk;
secp256k1_musig_pre_session pre_session;
secp256k1_musig_pre_session pre_session_uninitialized;
secp256k1_xonly_pubkey pk[2];
unsigned char tweak[32];
unsigned char sec_adaptor[32];
unsigned char sec_adaptor1[32];
secp256k1_pubkey adaptor;
/** setup **/
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
int ecount;
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
memset(ones, 0xff, 32);
/* Simulate structs being uninitialized by setting it to 0s. We don't want
* to produce undefined behavior by actually providing uninitialized
* structs. */
memset(&pre_session_uninitialized, 0, sizeof(pre_session_uninitialized));
memset(&session_uninitialized, 0, sizeof(session_uninitialized));
secp256k1_testrand256(session_id[0]);
secp256k1_testrand256(session_id[1]);
secp256k1_testrand256(sk[0]);
secp256k1_testrand256(sk[1]);
secp256k1_testrand256(msg);
secp256k1_testrand256(sec_adaptor);
secp256k1_testrand256(tweak);
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor) == 1);
/** main test body **/
/* Key combination */
ecount = 0;
CHECK(secp256k1_musig_pubkey_combine(none, scratch, &combined_pk, &pre_session, pk, 2) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_pubkey_combine(sign, scratch, &combined_pk, &pre_session, pk, 2) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(ecount == 2);
/* pubkey_combine does not require a scratch space */
CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(ecount == 2);
/* A small scratch space works too, but will result in using an ineffecient algorithm */
scratch_small = secp256k1_scratch_space_create(ctx, 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, &pre_session, pk, 2) == 1);
secp256k1_scratch_space_destroy(ctx, scratch_small);
CHECK(ecount == 2);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, &pre_session, pk, 2) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, NULL, pk, 2) == 1);
CHECK(ecount == 3);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 2) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 0) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 0) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
/** Tweaking */
ecount = 0;
{
secp256k1_xonly_pubkey tmp_internal_pk = combined_pk;
secp256k1_pubkey tmp_output_pk;
secp256k1_musig_pre_session tmp_pre_session = pre_session;
CHECK(secp256k1_musig_pubkey_tweak_add(ctx, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 1);
/* Reset pre_session */
tmp_pre_session = pre_session;
CHECK(secp256k1_musig_pubkey_tweak_add(none, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_pubkey_tweak_add(sign, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 1);
CHECK(ecount == 2);
tmp_pre_session = pre_session;
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, NULL, &tmp_output_pk, &tmp_internal_pk, tweak) == 0);
CHECK(ecount == 3);
/* Uninitialized pre_session */
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &pre_session_uninitialized, &tmp_output_pk, &tmp_internal_pk, tweak) == 0);
CHECK(ecount == 4);
/* Using the same pre_session twice does not work */
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 1);
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 0);
CHECK(ecount == 5);
tmp_pre_session = pre_session;
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, NULL, &tmp_internal_pk, tweak) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, NULL, tweak) == 0);
CHECK(ecount == 7);
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, NULL) == 0);
CHECK(ecount == 8);
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, ones) == 0);
CHECK(ecount == 8);
}
/** Session creation **/
ecount = 0;
CHECK(secp256k1_musig_session_init(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_init(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_init(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_session_init(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
CHECK(ecount == 6);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, &pre_session, 2, 0, sk[0]) == 0);
CHECK(ecount == 7);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, NULL, 2, 0, sk[0]) == 0);
CHECK(ecount == 8);
/* Uninitialized pre_session */
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session_uninitialized, 2, 0, sk[0]) == 0);
CHECK(ecount == 9);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 0, 0, sk[0]) == 0);
CHECK(ecount == 10);
/* If more than UINT32_MAX fits in a size_t, test that session_init
* rejects n_signers that high. */
if (SIZE_MAX > UINT32_MAX) {
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, ((size_t) UINT32_MAX) + 2, 0, sk[0]) == 0);
}
CHECK(ecount == 11);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, NULL) == 0);
CHECK(ecount == 12);
/* secret key overflows */
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, ones) == 0);
CHECK(ecount == 12);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_session_init(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
ncs[0] = nonce_commitment[0];
ncs[1] = nonce_commitment[1];
ecount = 0;
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_musig_session_init_verifier(none, NULL, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, &pre_session, ncs, 2) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, &pre_session, ncs, 2) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, NULL, ncs, 2) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, NULL, 2) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 0) == 0);
CHECK(ecount == 6);
if (SIZE_MAX > UINT32_MAX) {
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, ((size_t) UINT32_MAX) + 2) == 0);
}
CHECK(ecount == 7);
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 1);
/** Signing step 0 -- exchange nonce commitments */
ecount = 0;
{
unsigned char nonce[32];
secp256k1_musig_session session_0_tmp;
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
/* Can obtain public nonce after commitments have been exchanged; still can't sign */
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, nonce, ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_partial_sign(none, &session_0_tmp, &partial_sig[0]) == 0);
CHECK(ecount == 1);
}
/** Signing step 1 -- exchange nonces */
ecount = 0;
{
unsigned char public_nonce[3][32];
secp256k1_musig_session session_0_tmp;
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, public_nonce[0], ncs, 2, NULL) == 1);
CHECK(ecount == 0);
/* Reset session */
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
CHECK(secp256k1_musig_session_get_public_nonce(none, NULL, signer0, public_nonce[0], ncs, 2, NULL) == 0);
CHECK(ecount == 1);
/* uninitialized session */
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_uninitialized, signer0, public_nonce[0], ncs, 2, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, NULL, public_nonce[0], ncs, 2, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, NULL, ncs, 2, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, public_nonce[0], NULL, 2, NULL) == 0);
CHECK(ecount == 5);
/* Number of commitments and number of signers are different */
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, public_nonce[0], ncs, 1, NULL) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, public_nonce[0], ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[1], signer1, public_nonce[1], ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_set_nonce(none, &signer0[0], public_nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], public_nonce[0]) == 0);
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], public_nonce[1]) == 1);
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], public_nonce[1]) == 1);
CHECK(ecount == 6);
CHECK(secp256k1_musig_set_nonce(none, NULL, public_nonce[0]) == 0);
CHECK(ecount == 7);
CHECK(secp256k1_musig_set_nonce(none, &signer1[0], NULL) == 0);
CHECK(ecount == 8);
CHECK(secp256k1_musig_set_nonce(none, &signer1[0], public_nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(none, &signer1[1], public_nonce[1]) == 1);
CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[0], public_nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[1], public_nonce[1]) == 1);
ecount = 0;
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 2, &combined_nonce_parity, &adaptor) == 1);
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
CHECK(secp256k1_musig_session_combine_nonces(none, NULL, signer0, 2, &combined_nonce_parity, &adaptor) == 0);
CHECK(ecount == 1);
/* Uninitialized session */
CHECK(secp256k1_musig_session_combine_nonces(none, &session_uninitialized, signer0, 2, &combined_nonce_parity, &adaptor) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, NULL, 2, &combined_nonce_parity, &adaptor) == 0);
CHECK(ecount == 3);
/* Number of signers differs from number during intialization */
CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 1, &combined_nonce_parity, &adaptor) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 2, NULL, &adaptor) == 1);
CHECK(ecount == 4);
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 2, &combined_nonce_parity, NULL) == 1);
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &combined_nonce_parity, &adaptor) == 1);
CHECK(secp256k1_musig_session_combine_nonces(none, &session[1], signer0, 2, &combined_nonce_parity, &adaptor) == 1);
CHECK(secp256k1_musig_session_combine_nonces(none, &verifier_session, verifier_signer_data, 2, &combined_nonce_parity, &adaptor) == 1);
}
/** Signing step 2 -- partial signatures */
ecount = 0;
CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_musig_partial_sign(none, NULL, &partial_sig[0]) == 0);
CHECK(ecount == 1);
/* Uninitialized session */
CHECK(secp256k1_musig_partial_sign(none, &session_uninitialized, &partial_sig[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sign(none, &session[0], NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1);
CHECK(secp256k1_musig_partial_sign(none, &session[1], &partial_sig[1]) == 1);
/* observer can't sign */
CHECK(secp256k1_musig_partial_sign(none, &verifier_session, &partial_sig[2]) == 0);
CHECK(ecount == 4);
ecount = 0;
CHECK(secp256k1_musig_partial_signature_serialize(none, buf, &partial_sig[0]) == 1);
CHECK(secp256k1_musig_partial_signature_serialize(none, NULL, &partial_sig[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_partial_signature_serialize(none, buf, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig[0], buf) == 1);
CHECK(secp256k1_musig_partial_signature_parse(none, NULL, buf) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig[0], NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig_overflow, ones) == 1);
/** Partial signature verification */
ecount = 0;
CHECK(secp256k1_musig_partial_sig_verify(none, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_partial_sig_verify(sign, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[1], &pk[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, NULL, &signer0[0], &partial_sig[0], &pk[0]) == 0);
CHECK(ecount == 3);
/* Unitialized session */
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session_uninitialized, &signer0[0], &partial_sig[0], &pk[0]) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], NULL, &partial_sig[0], &pk[0]) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], NULL, &pk[0]) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig_overflow, &pk[0]) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], NULL) == 0);
CHECK(ecount == 7);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[1], &signer1[0], &partial_sig[0], &pk[0]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[1], &partial_sig[1], &pk[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[0], &partial_sig[0], &pk[0]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[1], &partial_sig[1], &pk[1]) == 1);
CHECK(ecount == 7);
/** Adaptor signature verification */
memcpy(&partial_sig_adapted[1], &partial_sig[1], sizeof(partial_sig_adapted[1]));
ecount = 0;
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], sec_adaptor, combined_nonce_parity) == 1);
CHECK(secp256k1_musig_partial_sig_adapt(none, NULL, &partial_sig[0], sec_adaptor, 0) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], NULL, sec_adaptor, 0) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig_overflow, sec_adaptor, combined_nonce_parity) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], NULL, 0) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], ones, combined_nonce_parity) == 0);
CHECK(ecount == 3);
/** Signing combining and verification */
ecount = 0;
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig_cmp, partial_sig_adapted, 2) == 1);
CHECK(memcmp(final_sig, final_sig_cmp, sizeof(final_sig)) == 0);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig_cmp, partial_sig_adapted, 2) == 1);
CHECK(memcmp(final_sig, final_sig_cmp, sizeof(final_sig)) == 0);
CHECK(secp256k1_musig_partial_sig_combine(none, NULL, final_sig, partial_sig_adapted, 2) == 0);
CHECK(ecount == 1);
/* Unitialized session */
CHECK(secp256k1_musig_partial_sig_combine(none, &session_uninitialized, final_sig, partial_sig_adapted, 2) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, NULL, 2) == 0);
CHECK(ecount == 4);
{
secp256k1_musig_partial_signature partial_sig_tmp[2];
partial_sig_tmp[0] = partial_sig_adapted[0];
partial_sig_tmp[1] = partial_sig_overflow;
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_tmp, 2) == 0);
}
CHECK(ecount == 4);
/* Wrong number of partial sigs */
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 1) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_verify(vrfy, final_sig, msg, &combined_pk) == 1);
/** Secret adaptor can be extracted from signature */
ecount = 0;
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 2, combined_nonce_parity) == 1);
CHECK(memcmp(sec_adaptor, sec_adaptor1, 32) == 0);
CHECK(secp256k1_musig_extract_secret_adaptor(none, NULL, final_sig, partial_sig, 2, 0) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, NULL, partial_sig, 2, 0) == 0);
CHECK(ecount == 2);
{
unsigned char final_sig_tmp[64];
memcpy(final_sig_tmp, final_sig, sizeof(final_sig_tmp));
memcpy(&final_sig_tmp[32], ones, 32);
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig_tmp, partial_sig, 2, combined_nonce_parity) == 0);
}
CHECK(ecount == 2);
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, NULL, 2, 0) == 0);
CHECK(ecount == 3);
{
secp256k1_musig_partial_signature partial_sig_tmp[2];
partial_sig_tmp[0] = partial_sig[0];
partial_sig_tmp[1] = partial_sig_overflow;
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig_tmp, 2, combined_nonce_parity) == 0);
}
CHECK(ecount == 3);
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 0, 0) == 1);
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 2, 1) == 1);
/** cleanup **/
memset(&session, 0, sizeof(session));
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(vrfy);
}
/* Initializes two sessions, one use the given parameters (session_id,
* nonce_commitments, etc.) except that `session_tmp` uses new signers with different
* public keys. The point of this test is to call `musig_session_get_public_nonce`
* with signers from `session_tmp` who have different public keys than the correct
* ones and return the resulting messagehash. This should not result in a different
* messagehash because the public keys of the signers are only used during session
* initialization. */
void musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256k1_xonly_pubkey *pks, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const unsigned char * const *nonce_commitments, unsigned char *msg, unsigned char *nonce_other, unsigned char *sk, unsigned char *session_id) {
secp256k1_musig_session session;
secp256k1_musig_session session_tmp;
unsigned char nonce_commitment[32];
secp256k1_musig_session_signer_data signers[2];
secp256k1_musig_session_signer_data signers_tmp[2];
unsigned char sk_dummy[32];
secp256k1_xonly_pubkey pks_tmp[2];
secp256k1_xonly_pubkey combined_pk_tmp;
secp256k1_musig_pre_session pre_session_tmp;
unsigned char nonce[32];
/* Set up signers with different public keys */
secp256k1_testrand256(sk_dummy);
pks_tmp[0] = pks[0];
CHECK(secp256k1_xonly_pubkey_create(&pks_tmp[1], sk_dummy) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, &pre_session_tmp, pks_tmp, 2) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, &pre_session_tmp, 2, 1, sk_dummy) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 0, sk) == 1);
CHECK(memcmp(nonce_commitment, nonce_commitments[1], 32) == 0);
/* Call get_public_nonce with different signers than the signers the session was
* initialized with. */
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session_tmp, signers, nonce, nonce_commitments, 2, NULL) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers_tmp, nonce, nonce_commitments, 2, NULL) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1);
secp256k1_musig_compute_messagehash(ctx, msghash, &session);
}
/* Creates a new session (with a different session id) and tries to use that session
* to combine nonces with given signers_other. This should fail, because the nonce
* commitments of signers_other do not match the nonce commitments the new session
* was initialized with. If do_test is 0, the correct signers are being used and
* therefore the function should return 1. */
int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, unsigned char *nonce_commitment_other, unsigned char *nonce_other, unsigned char *msg, unsigned char *sk, secp256k1_musig_session_signer_data *signers_other, int do_test) {
secp256k1_musig_session session;
secp256k1_musig_session_signer_data signers[2];
secp256k1_musig_session_signer_data *signers_to_use;
unsigned char nonce_commitment[32];
unsigned char session_id[32];
unsigned char nonce[32];
const unsigned char *ncs[2];
/* Initialize new signers */
secp256k1_testrand256(session_id);
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 1, sk) == 1);
ncs[0] = nonce_commitment_other;
ncs[1] = nonce_commitment;
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, nonce, ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1);
secp256k1_musig_session_combine_nonces(ctx, &session, signers_other, 2, NULL, NULL);
if (do_test) {
signers_to_use = signers_other;
} else {
signers_to_use = signers;
}
return secp256k1_musig_session_combine_nonces(ctx, &session, signers_to_use, 2, NULL, NULL);
}
/* Initializaes a session with the given session_id, signers, pk, msg etc.
* parameters but without a message. Will test that the message must be
* provided with `get_public_nonce`.
*/
void musig_state_machine_late_msg_test(secp256k1_xonly_pubkey *pks, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, unsigned char *nonce_commitment_other, unsigned char *nonce_other, unsigned char *sk, unsigned char *session_id, unsigned char *msg) {
/* Create context for testing ARG_CHECKs by setting an illegal_callback. */
secp256k1_context *ctx_tmp = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
int ecount = 0;
secp256k1_musig_session session;
secp256k1_musig_session_signer_data signers[2];
unsigned char nonce_commitment[32];
const unsigned char *ncs[2];
unsigned char nonce[32];
secp256k1_musig_partial_signature partial_sig;
secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount);
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, NULL, combined_pk, pre_session, 2, 1, sk) == 1);
ncs[0] = nonce_commitment_other;
ncs[1] = nonce_commitment;
/* Trying to get the nonce without providing a message fails. */
CHECK(ecount == 0);
CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session, signers, nonce, ncs, 2, NULL) == 0);
CHECK(ecount == 1);
/* Providing a message should make get_public_nonce succeed. */
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, nonce, ncs, 2, msg) == 1);
/* Trying to set the message again fails. */
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session, signers, nonce, ncs, 2, msg) == 0);
CHECK(ecount == 2);
/* Check that it's working */
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1);
CHECK(secp256k1_musig_partial_sign(ctx, &session, &partial_sig));
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session, &signers[1], &partial_sig, &pks[1]));
secp256k1_context_destroy(ctx_tmp);
}
void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
secp256k1_context *ctx_tmp = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_VERIFY);
size_t i;
secp256k1_musig_session session[2];
secp256k1_musig_session_signer_data signers0[2];
secp256k1_musig_session_signer_data signers1[2];
unsigned char nonce_commitment[2][32];
unsigned char session_id[2][32];
unsigned char msg[32];
unsigned char sk[2][32];
secp256k1_xonly_pubkey pk[2];
secp256k1_xonly_pubkey combined_pk;
secp256k1_musig_pre_session pre_session;
unsigned char nonce[2][32];
const unsigned char *ncs[2];
secp256k1_musig_partial_signature partial_sig[2];
unsigned char sig[64];
unsigned char msghash1[32];
unsigned char msghash2[32];
int ecount;
secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount);
ecount = 0;
/* Run state machine with the same objects twice to test that it's allowed to
* reinitialize session and session_signer_data. */
for (i = 0; i < 2; i++) {
/* Setup */
secp256k1_testrand256(session_id[0]);
secp256k1_testrand256(session_id[1]);
secp256k1_testrand256(sk[0]);
secp256k1_testrand256(sk[1]);
secp256k1_testrand256(msg);
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
/* Can't combine nonces unless we're through round 1 already */
ecount = 0;
CHECK(secp256k1_musig_session_combine_nonces(ctx_tmp, &session[0], signers0, 2, NULL, NULL) == 0);
CHECK(ecount == 1);
/* Set nonce commitments */
ncs[0] = nonce_commitment[0];
ncs[1] = nonce_commitment[1];
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, nonce[0], ncs, 2, NULL) == 1);
/* Calling the function again is not okay */
ecount = 0;
CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session[0], signers0, nonce[0], ncs, 2, NULL) == 0);
CHECK(ecount == 1);
/* Get nonce for signer 1 */
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, nonce[1], ncs, 2, NULL) == 1);
/* Set nonces */
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[0], nonce[0]) == 1);
/* Can't set nonce that doesn't match nonce commitment */
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], nonce[0]) == 0);
/* Set correct nonce */
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], nonce[1]) == 1);
/* Combine nonces */
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signers0, 2, NULL, NULL) == 1);
/* Not everyone is present from signer 1's view */
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 0);
/* Make everyone present */
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[0], nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[1], nonce[1]) == 1);
/* Can't combine nonces from signers of a different session */
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, &pre_session, nonce_commitment[0], nonce[0], msg, sk[1], signers1, 1) == 0);
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, &pre_session, nonce_commitment[0], nonce[0], msg, sk[1], signers1, 0) == 1);
/* Partially sign */
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1);
/* Can't verify, sign or combine signatures until nonce is combined */
ecount = 0;
CHECK(secp256k1_musig_partial_sig_verify(ctx_tmp, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_partial_sign(ctx_tmp, &session[1], &partial_sig[1]) == 0);
CHECK(ecount == 2);
memset(&partial_sig[1], 0, sizeof(partial_sig[1]));
CHECK(secp256k1_musig_partial_sig_combine(ctx_tmp, &session[1], sig, partial_sig, 2) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1);
/* messagehash should be the same as a session whose get_public_nonce was called
* with different signers (i.e. they diff in public keys). This is because the
* public keys of the signers is set in stone when initializing the session. */
secp256k1_musig_compute_messagehash(ctx, msghash1, &session[1]);
musig_state_machine_diff_signer_msghash_test(msghash2, pk, &combined_pk, &pre_session, ncs, msg, nonce[0], sk[1], session_id[1]);
CHECK(memcmp(msghash1, msghash2, 32) == 0);
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[1], &pk[1]) == 1);
/* Wrong signature */
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[0], &pk[1]) == 0);
/* Can't get the public nonce until msg is set */
musig_state_machine_late_msg_test(pk, &combined_pk, &pre_session, nonce_commitment[0], nonce[0], sk[1], session_id[1], msg);
}
secp256k1_context_destroy(ctx_tmp);
}
void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
/* Throughout this test "a" and "b" refer to two hypothetical blockchains,
* while the indices 0 and 1 refer to the two signers. Here signer 0 is
* sending a-coins to signer 1, while signer 1 is sending b-coins to signer
* 0. Signer 0 produces the adaptor signatures. */
unsigned char final_sig_a[64];
unsigned char final_sig_b[64];
secp256k1_musig_partial_signature partial_sig_a[2];
secp256k1_musig_partial_signature partial_sig_b_adapted[2];
secp256k1_musig_partial_signature partial_sig_b[2];
unsigned char sec_adaptor[32];
unsigned char sec_adaptor_extracted[32];
secp256k1_pubkey pub_adaptor;
unsigned char seckey_a[2][32];
unsigned char seckey_b[2][32];
secp256k1_xonly_pubkey pk_a[2];
secp256k1_xonly_pubkey pk_b[2];
secp256k1_musig_pre_session pre_session_a;
secp256k1_musig_pre_session pre_session_b;
secp256k1_xonly_pubkey combined_pk_a;
secp256k1_xonly_pubkey combined_pk_b;
secp256k1_musig_session musig_session_a[2];
secp256k1_musig_session musig_session_b[2];
unsigned char noncommit_a[2][32];
unsigned char noncommit_b[2][32];
const unsigned char *noncommit_a_ptr[2];
const unsigned char *noncommit_b_ptr[2];
unsigned char pubnon_a[2][32];
unsigned char pubnon_b[2][32];
int combined_nonce_parity_a;
int combined_nonce_parity_b;
secp256k1_musig_session_signer_data data_a[2];
secp256k1_musig_session_signer_data data_b[2];
const unsigned char seed[32] = "still tired of choosing seeds...";
const unsigned char msg32_a[32] = "this is the message blockchain a";
const unsigned char msg32_b[32] = "this is the message blockchain b";
/* Step 1: key setup */
secp256k1_testrand256(seckey_a[0]);
secp256k1_testrand256(seckey_a[1]);
secp256k1_testrand256(seckey_b[0]);
secp256k1_testrand256(seckey_b[1]);
secp256k1_testrand256(sec_adaptor);
CHECK(secp256k1_xonly_pubkey_create(&pk_a[0], seckey_a[0]));
CHECK(secp256k1_xonly_pubkey_create(&pk_a[1], seckey_a[1]));
CHECK(secp256k1_xonly_pubkey_create(&pk_b[0], seckey_b[0]));
CHECK(secp256k1_xonly_pubkey_create(&pk_b[1], seckey_b[1]));
CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor));
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_a, &pre_session_a, pk_a, 2));
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_b, &pre_session_b, pk_b, 2));
CHECK(secp256k1_musig_session_init(ctx, &musig_session_a[0], data_a, noncommit_a[0], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, 0, seckey_a[0]));
CHECK(secp256k1_musig_session_init(ctx, &musig_session_a[1], data_a, noncommit_a[1], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, 1, seckey_a[1]));
noncommit_a_ptr[0] = noncommit_a[0];
noncommit_a_ptr[1] = noncommit_a[1];
CHECK(secp256k1_musig_session_init(ctx, &musig_session_b[0], data_b, noncommit_b[0], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, 0, seckey_b[0]));
CHECK(secp256k1_musig_session_init(ctx, &musig_session_b[1], data_b, noncommit_b[1], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, 1, seckey_b[1]));
noncommit_b_ptr[0] = noncommit_b[0];
noncommit_b_ptr[1] = noncommit_b[1];
/* Step 2: Exchange nonces */
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[0], data_a, pubnon_a[0], noncommit_a_ptr, 2, NULL));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[1], data_a, pubnon_a[1], noncommit_a_ptr, 2, NULL));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[0], data_b, pubnon_b[0], noncommit_b_ptr, 2, NULL));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[1], data_b, pubnon_b[1], noncommit_b_ptr, 2, NULL));
CHECK(secp256k1_musig_set_nonce(ctx, &data_a[0], pubnon_a[0]));
CHECK(secp256k1_musig_set_nonce(ctx, &data_a[1], pubnon_a[1]));
CHECK(secp256k1_musig_set_nonce(ctx, &data_b[0], pubnon_b[0]));
CHECK(secp256k1_musig_set_nonce(ctx, &data_b[1], pubnon_b[1]));
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_a[0], data_a, 2, &combined_nonce_parity_a, &pub_adaptor));
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_a[1], data_a, 2, NULL, &pub_adaptor));
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[0], data_b, 2, &combined_nonce_parity_b, &pub_adaptor));
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[1], data_b, 2, NULL, &pub_adaptor));
/* Step 3: Signer 0 produces partial signatures for both chains. */
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[0], &partial_sig_a[0]));
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_b[0], &partial_sig_b[0]));
/* Step 4: Signer 1 receives partial signatures, verifies them and creates a
* partial signature to send B-coins to signer 0. */
CHECK(secp256k1_musig_partial_sig_verify(ctx, &musig_session_a[1], data_a, &partial_sig_a[0], &pk_a[0]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &musig_session_b[1], data_b, &partial_sig_b[0], &pk_b[0]) == 1);
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_b[1], &partial_sig_b[1]));
/* Step 5: Signer 0 adapts its own partial signature and combines it with the
* partial signature from signer 1. This results in a complete signature which
* is broadcasted by signer 0 to take B-coins. */
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_b_adapted[0], &partial_sig_b[0], sec_adaptor, combined_nonce_parity_b));
memcpy(&partial_sig_b_adapted[1], &partial_sig_b[1], sizeof(partial_sig_b_adapted[1]));
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_b[0], final_sig_b, partial_sig_b_adapted, 2) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_b, msg32_b, &combined_pk_b) == 1);
/* Step 6: Signer 1 extracts adaptor from the published signature, applies it to
* other partial signature, and takes A-coins. */
CHECK(secp256k1_musig_extract_secret_adaptor(ctx, sec_adaptor_extracted, final_sig_b, partial_sig_b, 2, combined_nonce_parity_b) == 1);
CHECK(memcmp(sec_adaptor_extracted, sec_adaptor, sizeof(sec_adaptor)) == 0); /* in real life we couldn't check this, of course */
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_a[0], &partial_sig_a[0], sec_adaptor_extracted, combined_nonce_parity_a));
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[1], &partial_sig_a[1]));
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_a[1], final_sig_a, partial_sig_a, 2) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_a, msg32_a, &combined_pk_a) == 1);
}
/* Checks that hash initialized by secp256k1_musig_sha256_init_tagged has the
* expected state. */
void sha256_tag_test(void) {
char tag[17] = "MuSig coefficient";
secp256k1_sha256 sha;
secp256k1_sha256 sha_tagged;
unsigned char buf[32];
unsigned char buf2[32];
size_t i;
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, (unsigned char *) tag, 17);
secp256k1_sha256_finalize(&sha, buf);
/* buf = SHA256("MuSig coefficient") */
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, buf, 32);
secp256k1_sha256_write(&sha, buf, 32);
/* Is buffer fully consumed? */
CHECK((sha.bytes & 0x3F) == 0);
/* Compare with tagged SHA */
secp256k1_musig_sha256_init_tagged(&sha_tagged);
for (i = 0; i < 8; i++) {
CHECK(sha_tagged.s[i] == sha.s[i]);
}
secp256k1_sha256_write(&sha, buf, 32);
secp256k1_sha256_write(&sha_tagged, buf, 32);
secp256k1_sha256_finalize(&sha, buf);
secp256k1_sha256_finalize(&sha_tagged, buf2);
CHECK(memcmp(buf, buf2, 32) == 0);
}
/* Attempts to create a signature for the combined public key using given secret
* keys and pre_session. */
void musig_tweak_test_helper(const secp256k1_xonly_pubkey* combined_pubkey, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_pre_session *pre_session) {
secp256k1_musig_session session[2];
secp256k1_musig_session_signer_data signers0[2];
secp256k1_musig_session_signer_data signers1[2];
secp256k1_xonly_pubkey pk[2];
unsigned char session_id[2][32];
unsigned char msg[32];
unsigned char nonce_commitment[2][32];
unsigned char nonce[2][32];
const unsigned char *ncs[2];
secp256k1_musig_partial_signature partial_sig[2];
unsigned char final_sig[64];
secp256k1_testrand256(session_id[0]);
secp256k1_testrand256(session_id[1]);
secp256k1_testrand256(msg);
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk0) == 1);
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk1) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, combined_pubkey, pre_session, 2, 0, sk0) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, combined_pubkey, pre_session, 2, 1, sk1) == 1);
/* Set nonce commitments */
ncs[0] = nonce_commitment[0];
ncs[1] = nonce_commitment[1];
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, nonce[0], ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, nonce[1], ncs, 2, NULL) == 1);
/* Set nonces */
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[0], nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], nonce[1]) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[0], nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[1], nonce[1]) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signers0, 2, NULL, NULL) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 1);
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1);
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signers0[1], &partial_sig[1], &pk[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1);
CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], final_sig, partial_sig, 2));
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, combined_pubkey) == 1);
}
/* In this test we create a combined public key P and a commitment Q = P +
* hash(P, contract)*G. Then we test that we can sign for both public keys. In
* order to sign for Q we use the tweak32 argument of partial_sig_combine. */
void musig_tweak_test(secp256k1_scratch_space *scratch) {
unsigned char sk[2][32];
secp256k1_xonly_pubkey pk[2];
secp256k1_musig_pre_session pre_session_P;
secp256k1_musig_pre_session pre_session_Q;
secp256k1_xonly_pubkey P;
unsigned char P_serialized[32];
secp256k1_pubkey Q;
int Q_parity;
secp256k1_xonly_pubkey Q_xonly;
unsigned char Q_serialized[32];
secp256k1_sha256 sha;
unsigned char contract[32];
unsigned char ec_commit_tweak[32];
/* Setup */
secp256k1_testrand256(sk[0]);
secp256k1_testrand256(sk[1]);
secp256k1_testrand256(contract);
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &P, &pre_session_P, pk, 2) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, P_serialized, &P) == 1);
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, P_serialized, 32);
secp256k1_sha256_write(&sha, contract, 32);
secp256k1_sha256_finalize(&sha, ec_commit_tweak);
pre_session_Q = pre_session_P;
CHECK(secp256k1_musig_pubkey_tweak_add(ctx, &pre_session_Q, &Q, &P, ec_commit_tweak) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &Q_xonly, &Q_parity, &Q));
CHECK(secp256k1_xonly_pubkey_serialize(ctx, Q_serialized, &Q_xonly));
/* Check that musig_pubkey_tweak_add produces same result as
* xonly_pubkey_tweak_add. */
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, Q_serialized, Q_parity, &P, ec_commit_tweak) == 1);
/* Test signing for P */
musig_tweak_test_helper(&P, sk[0], sk[1], &pre_session_P);
/* Test signing for Q */
musig_tweak_test_helper(&Q_xonly, sk[0], sk[1], &pre_session_Q);
}
void run_musig_tests(void) {
int i;
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024);
for (i = 0; i < count; i++) {
musig_simple_test(scratch);
}
musig_api_tests(scratch);
musig_state_machine_tests(scratch);
for (i = 0; i < count; i++) {
/* Run multiple times to ensure that pk and nonce have different y
* parities */
scriptless_atomic_swap(scratch);
musig_tweak_test(scratch);
}
sha256_tag_test();
secp256k1_scratch_space_destroy(ctx, scratch);
}
#endif

View File

@@ -20,9 +20,9 @@
#include <limits.h>
#include <string.h>
#if defined(SECP256K1_BIG_ENDIAN)
#ifdef WORDS_BIGENDIAN
#define BE32(x) (x)
#elif defined(SECP256K1_LITTLE_ENDIAN)
#else
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#endif
@@ -30,7 +30,7 @@ SECP256K1_INLINE static void secp256k1_borromean_hash(unsigned char *hash, const
size_t ridx, size_t eidx) {
uint32_t ring;
uint32_t epos;
secp256k1_sha256 sha256_en;
secp256k1_sha256_t sha256_en;
secp256k1_sha256_initialize(&sha256_en);
ring = BE32((uint32_t)ridx);
epos = BE32((uint32_t)eidx);
@@ -60,7 +60,7 @@ int secp256k1_borromean_verify(const secp256k1_ecmult_context* ecmult_ctx, secp2
secp256k1_gej rgej;
secp256k1_ge rge;
secp256k1_scalar ens;
secp256k1_sha256 sha256_e0;
secp256k1_sha256_t sha256_e0;
unsigned char tmp[33];
size_t i;
size_t j;
@@ -115,7 +115,7 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_context* ecmult_ctx, const s
secp256k1_gej rgej;
secp256k1_ge rge;
secp256k1_scalar ens;
secp256k1_sha256 sha256_e0;
secp256k1_sha256_t sha256_e0;
unsigned char tmp[33];
size_t i;
size_t j;

View File

@@ -14,21 +14,15 @@
#include "modules/rangeproof/rangeproof_impl.h"
/** Alternative generator for secp256k1.
* This is the sha256 of 'g' after standard encoding (without compression),
* which happens to be a point on the curve. More precisely, the generator is
* derived by running the following script with the sage mathematics software.
import hashlib
F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
G = '0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
H = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256(G.decode('hex')).hexdigest(),16)))
print('%x %x' % H.xy())
* This is the sha256 of 'g' after DER encoding (without compression),
* which happens to be a point on the curve.
* sage: G2 = EllipticCurve ([F (0), F (7)]).lift_x(int(hashlib.sha256('0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'.decode('hex')).hexdigest(),16))
* sage: '%x %x' % (11 - G2.xy()[1].is_square(), G2.xy()[0])
*/
static const secp256k1_generator secp256k1_generator_h_internal = {{
0x11,
0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e,
0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0,
0x31, 0xd3, 0xc6, 0x86, 0x39, 0x73, 0x92, 0x6e, 0x04, 0x9e, 0x63, 0x7c, 0xb1, 0xb5, 0xf4, 0x0a,
0x36, 0xda, 0xc2, 0x8a, 0xf1, 0x76, 0x69, 0x68, 0xc3, 0x0c, 0x23, 0x13, 0xf3, 0xa3, 0x89, 0x04
0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0
}};
const secp256k1_generator *secp256k1_generator_h = &secp256k1_generator_h_internal;
@@ -49,38 +43,22 @@ static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* co
}
int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_pedersen_commitment* commit, const unsigned char *input) {
secp256k1_fe x;
secp256k1_ge ge;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(commit != NULL);
ARG_CHECK(input != NULL);
(void) ctx;
if ((input[0] & 0xFE) != 8 ||
!secp256k1_fe_set_b32(&x, &input[1]) ||
!secp256k1_ge_set_xquad(&ge, &x)) {
if ((input[0] & 0xFE) != 8) {
return 0;
}
if (input[0] & 1) {
secp256k1_ge_neg(&ge, &ge);
}
secp256k1_pedersen_commitment_save(commit, &ge);
memcpy(commit->data, input, sizeof(commit->data));
return 1;
}
int secp256k1_pedersen_commitment_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pedersen_commitment* commit) {
secp256k1_ge ge;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output != NULL);
ARG_CHECK(commit != NULL);
secp256k1_pedersen_commitment_load(&ge, commit);
output[0] = 9 ^ secp256k1_fe_is_quad_var(&ge.y);
secp256k1_fe_normalize_var(&ge.x);
secp256k1_fe_get_b32(&output[1], &ge.x);
memcpy(output, commit->data, sizeof(commit->data));
return 1;
}

View File

@@ -63,7 +63,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar *sec,
size_t *rsizes, size_t rings, const unsigned char *nonce, const secp256k1_ge *commit, const unsigned char *proof, size_t len, const secp256k1_ge* genp) {
unsigned char tmp[32];
unsigned char rngseed[32 + 33 + 33 + 10];
secp256k1_rfc6979_hmac_sha256 rng;
secp256k1_rfc6979_hmac_sha256_t rng;
secp256k1_scalar acc;
int overflow;
int ret;
@@ -199,7 +199,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
secp256k1_scalar sec[32]; /* Blinding factors for the correct digits. */
secp256k1_scalar k[32]; /* Nonces for our non-forged signatures. */
secp256k1_scalar stmp;
secp256k1_sha256 sha256_m;
secp256k1_sha256_t sha256_m;
unsigned char prep[4096];
unsigned char tmp[33];
unsigned char *signs; /* Location of sign flags in the proof. */
@@ -547,7 +547,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm
secp256k1_ge c;
secp256k1_scalar s[128];
secp256k1_scalar evalues[128]; /* Challenges, only used during proof rewind. */
secp256k1_sha256 sha256_m;
secp256k1_sha256_t sha256_m;
size_t rsizes[32];
int ret;
size_t i;
@@ -609,10 +609,8 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm
}
for(i = 0; i < rings - 1; i++) {
secp256k1_fe fe;
if (!secp256k1_fe_set_b32(&fe, &proof[offset]) ||
!secp256k1_ge_set_xquad(&c, &fe)) {
return 0;
}
secp256k1_fe_set_b32(&fe, &proof[offset]);
secp256k1_ge_set_xquad(&c, &fe);
if (signs[i]) {
secp256k1_ge_neg(&c, &c);
}

View File

@@ -23,9 +23,9 @@ static void test_pedersen_api(const secp256k1_context *none, const secp256k1_con
unsigned char blind_out[32];
const unsigned char *blind_ptr = blind;
unsigned char *blind_out_ptr = blind_out;
uint64_t val = secp256k1_testrand32();
uint64_t val = secp256k1_rand32();
secp256k1_testrand256(blind);
secp256k1_rand256(blind);
CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, secp256k1_generator_h) == 0);
CHECK(*ecount == 1);
CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, secp256k1_generator_h) == 0);
@@ -80,8 +80,8 @@ static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_c
unsigned char proof[5134];
unsigned char blind[32];
secp256k1_pedersen_commitment commit;
uint64_t vmin = secp256k1_testrand32();
uint64_t val = vmin + secp256k1_testrand32();
uint64_t vmin = secp256k1_rand32();
uint64_t val = vmin + secp256k1_rand32();
size_t len = sizeof(proof);
/* we'll switch to dylan thomas for this one */
const unsigned char message[68] = "My tears are like the quiet drift / Of petals from some magic rose;";
@@ -89,7 +89,7 @@ static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_c
const unsigned char ext_commit[72] = "And all my grief flows from the rift / Of unremembered skies and snows.";
size_t ext_commit_len = sizeof(ext_commit);
secp256k1_testrand256(blind);
secp256k1_rand256(blind);
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, val, secp256k1_generator_h));
CHECK(secp256k1_rangeproof_sign(none, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
@@ -271,8 +271,8 @@ static void test_pedersen(void) {
int inputs;
int outputs;
int total;
inputs = (secp256k1_testrand32() & 7) + 1;
outputs = (secp256k1_testrand32() & 7) + 2;
inputs = (secp256k1_rand32() & 7) + 1;
outputs = (secp256k1_rand32() & 7) + 2;
total = inputs + outputs;
for (i = 0; i < 19; i++) {
cptr[i] = &commits[i];
@@ -280,11 +280,11 @@ static void test_pedersen(void) {
}
totalv = 0;
for (i = 0; i < inputs; i++) {
values[i] = secp256k1_testrandi64(0, INT64_MAX - totalv);
values[i] = secp256k1_rands64(0, INT64_MAX - totalv);
totalv += values[i];
}
for (i = 0; i < outputs - 1; i++) {
values[i + inputs] = secp256k1_testrandi64(0, totalv);
values[i + inputs] = secp256k1_rands64(0, totalv);
totalv -= values[i + inputs];
}
values[total - 1] = totalv;
@@ -331,27 +331,27 @@ static void test_borromean(void) {
size_t i;
size_t j;
int c;
secp256k1_testrand256_test(m);
nrings = 1 + (secp256k1_testrand32()&7);
secp256k1_rand256_test(m);
nrings = 1 + (secp256k1_rand32()&7);
c = 0;
secp256k1_scalar_set_int(&one, 1);
if (secp256k1_testrand32()&1) {
if (secp256k1_rand32()&1) {
secp256k1_scalar_negate(&one, &one);
}
for (i = 0; i < nrings; i++) {
rsizes[i] = 1 + (secp256k1_testrand32()&7);
secidx[i] = secp256k1_testrand32() % rsizes[i];
rsizes[i] = 1 + (secp256k1_rand32()&7);
secidx[i] = secp256k1_rand32() % rsizes[i];
random_scalar_order(&sec[i]);
random_scalar_order(&k[i]);
if(secp256k1_testrand32()&7) {
if(secp256k1_rand32()&7) {
sec[i] = one;
}
if(secp256k1_testrand32()&7) {
if(secp256k1_rand32()&7) {
k[i] = one;
}
for (j = 0; j < rsizes[i]; j++) {
random_scalar_order(&s[c + j]);
if(secp256k1_testrand32()&7) {
if(secp256k1_rand32()&7) {
s[i] = one;
}
if (j == secidx[i]) {
@@ -365,14 +365,14 @@ static void test_borromean(void) {
}
CHECK(secp256k1_borromean_sign(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, e0, s, pubs, k, sec, rsizes, secidx, nrings, m, 32));
CHECK(secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32));
i = secp256k1_testrand32() % c;
i = secp256k1_rand32() % c;
secp256k1_scalar_negate(&s[i],&s[i]);
CHECK(!secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32));
secp256k1_scalar_negate(&s[i],&s[i]);
secp256k1_scalar_set_int(&one, 1);
for(j = 0; j < 4; j++) {
i = secp256k1_testrand32() % c;
if (secp256k1_testrand32() & 1) {
i = secp256k1_rand32() % c;
if (secp256k1_rand32() & 1) {
secp256k1_gej_double_var(&pubs[i],&pubs[i], NULL);
} else {
secp256k1_scalar_add(&s[i],&s[i],&one);
@@ -385,7 +385,7 @@ static void test_rangeproof(void) {
const uint64_t testvs[11] = {0, 1, 5, 11, 65535, 65537, INT32_MAX, UINT32_MAX, INT64_MAX - 1, INT64_MAX, UINT64_MAX};
secp256k1_pedersen_commitment commit;
secp256k1_pedersen_commitment commit2;
unsigned char proof[5134 + 1]; /* One additional byte to test if trailing bytes are rejected */
unsigned char proof[5134];
unsigned char blind[32];
unsigned char blindout[32];
unsigned char message[4096];
@@ -408,7 +408,7 @@ static void test_rangeproof(void) {
memcpy(&message_long[i], message_short, sizeof(message_short));
}
secp256k1_testrand256(blind);
secp256k1_rand256(blind);
for (i = 0; i < 11; i++) {
v = testvs[i];
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
@@ -464,7 +464,7 @@ static void test_rangeproof(void) {
CHECK(maxv == v);
}
}
secp256k1_testrand256(blind);
secp256k1_rand256(blind);
v = INT64_MAX - 1;
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
for (i = 0; i < 19; i++) {
@@ -477,17 +477,14 @@ static void test_rangeproof(void) {
/* Make sure it fails when validating with a committed message */
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), secp256k1_generator_h));
}
secp256k1_testrand256(blind);
secp256k1_rand256(blind);
{
/*Malleability test.*/
v = secp256k1_testrandi64(0, 255);
v = secp256k1_rands64(0, 255);
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
len = 5134;
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, 0, 3, v, NULL, 0, NULL, 0, secp256k1_generator_h));
CHECK(len <= 5134);
/* Test if trailing bytes are rejected. */
proof[len] = v;
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len + 1, NULL, 0, secp256k1_generator_h));
for (i = 0; i < len*8; i++) {
proof[i >> 3] ^= 1 << (i & 7);
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
@@ -498,22 +495,22 @@ static void test_rangeproof(void) {
CHECK(maxv >= v);
}
memcpy(&commit2, &commit, sizeof(commit));
for (i = 0; i < (size_t) count; i++) {
for (i = 0; i < 10 * (size_t) count; i++) {
int exp;
int min_bits;
v = secp256k1_testrandi64(0, UINT64_MAX >> (secp256k1_testrand32()&63));
v = secp256k1_rands64(0, UINT64_MAX >> (secp256k1_rand32()&63));
vmin = 0;
if ((v < INT64_MAX) && (secp256k1_testrand32()&1)) {
vmin = secp256k1_testrandi64(0, v);
if ((v < INT64_MAX) && (secp256k1_rand32()&1)) {
vmin = secp256k1_rands64(0, v);
}
secp256k1_testrand256(blind);
secp256k1_rand256(blind);
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
len = 5134;
exp = (int)secp256k1_testrandi64(0,18)-(int)secp256k1_testrandi64(0,18);
exp = (int)secp256k1_rands64(0,18)-(int)secp256k1_rands64(0,18);
if (exp < 0) {
exp = -exp;
}
min_bits = (int)secp256k1_testrandi64(0,64)-(int)secp256k1_testrandi64(0,64);
min_bits = (int)secp256k1_rands64(0,64)-(int)secp256k1_rands64(0,64);
if (min_bits < 0) {
min_bits = -min_bits;
}
@@ -526,29 +523,29 @@ static void test_rangeproof(void) {
}
CHECK(mlen <= 4096);
CHECK(memcmp(blindout, blind, 32) == 0);
CHECK(vout == v);
CHECK(minv <= v);
CHECK(maxv >= v);
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
memcpy(&commit2, &commit, sizeof(commit));
}
for (j = 0; j < 3; j++) {
for (j = 0; j < 10; j++) {
for (i = 0; i < 96; i++) {
secp256k1_testrand256(&proof[i * 32]);
secp256k1_rand256(&proof[i * 32]);
}
for (k = 0; k < 128; k += 3) {
for (k = 0; k < 128; k++) {
len = k;
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, secp256k1_generator_h));
}
len = secp256k1_testrandi64(0, 3072);
len = secp256k1_rands64(0, 3072);
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, secp256k1_generator_h));
}
}
#define MAX_N_GENS 30
void test_multiple_generators(void) {
const size_t n_inputs = (secp256k1_testrand32() % (MAX_N_GENS / 2)) + 1;
const size_t n_outputs = (secp256k1_testrand32() % (MAX_N_GENS / 2)) + 1;
const size_t n_inputs = (secp256k1_rand32() % (MAX_N_GENS / 2)) + 1;
const size_t n_outputs = (secp256k1_rand32() % (MAX_N_GENS / 2)) + 1;
const size_t n_generators = n_inputs + n_outputs;
unsigned char *generator_blind[MAX_N_GENS];
unsigned char *pedersen_blind[MAX_N_GENS];
@@ -582,11 +579,11 @@ void test_multiple_generators(void) {
/* Compute all the values -- can be positive or negative */
total_value = 0;
for (i = 0; i < n_outputs; i++) {
value[n_inputs + i] = secp256k1_testrandi64(0, INT64_MAX - total_value);
value[n_inputs + i] = secp256k1_rands64(0, INT64_MAX - total_value);
total_value += value[n_inputs + i];
}
for (i = 0; i < n_inputs - 1; i++) {
value[i] = secp256k1_testrandi64(0, total_value);
value[i] = secp256k1_rands64(0, total_value);
total_value -= value[i];
}
value[i] = total_value;
@@ -607,99 +604,13 @@ void test_multiple_generators(void) {
}
}
void test_rangeproof_fixed_vectors(void) {
const unsigned char vector_1[] = {
0x62, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x02, 0x2a, 0x5c, 0x42, 0x0e, 0x1d,
0x51, 0xe1, 0xb7, 0xf3, 0x69, 0x04, 0xb5, 0xbb, 0x9b, 0x41, 0x66, 0x14, 0xf3, 0x64, 0x42, 0x26,
0xe3, 0xa7, 0x6a, 0x06, 0xbb, 0xa8, 0x5a, 0x49, 0x6f, 0x19, 0x76, 0xfb, 0xe5, 0x75, 0x77, 0x88,
0xab, 0xa9, 0x66, 0x44, 0x80, 0xea, 0x29, 0x95, 0x7f, 0xdf, 0x72, 0x4a, 0xaf, 0x02, 0xbe, 0xdd,
0x5d, 0x15, 0xd8, 0xae, 0xff, 0x74, 0xc9, 0x8c, 0x1a, 0x67, 0x0e, 0xb2, 0x57, 0x22, 0x99, 0xc3,
0x21, 0x46, 0x6f, 0x15, 0x58, 0x0e, 0xdb, 0xe6, 0x6e, 0xc4, 0x0d, 0xfe, 0x6f, 0x04, 0x6b, 0x0d,
0x18, 0x3d, 0x78, 0x40, 0x98, 0x56, 0x4e, 0xe4, 0x4a, 0x74, 0x90, 0xa7, 0xac, 0x9c, 0x16, 0xe0,
0x3e, 0x81, 0xaf, 0x0f, 0xe3, 0x4f, 0x34, 0x99, 0x52, 0xf7, 0xa7, 0xf6, 0xd3, 0x83, 0xa0, 0x17,
0x4b, 0x2d, 0xa7, 0xd4, 0xfd, 0xf7, 0x84, 0x45, 0xc4, 0x11, 0x71, 0x3d, 0x4a, 0x22, 0x34, 0x09,
0x9c, 0xa7, 0xe5, 0xc8, 0xba, 0x04, 0xbf, 0xfd, 0x25, 0x11, 0x7d, 0xa4, 0x43, 0x45, 0xc7, 0x62,
0x9e, 0x7b, 0x80, 0xf6, 0x09, 0xbb, 0x1b, 0x2e, 0xf3, 0xcd, 0x23, 0xe0, 0xed, 0x81, 0x43, 0x42,
0xbe, 0xc4, 0x9f, 0x58, 0x8a, 0x0d, 0x66, 0x79, 0x09, 0x70, 0x11, 0x68, 0x3d, 0x87, 0x38, 0x1c,
0x3c, 0x85, 0x52, 0x5b, 0x62, 0xf7, 0x3e, 0x7e, 0x87, 0xa2, 0x99, 0x24, 0xd0, 0x7d, 0x18, 0x63,
0x56, 0x48, 0xa4, 0x3a, 0xfe, 0x65, 0xfa, 0xa4, 0xd0, 0x67, 0xaa, 0x98, 0x65, 0x4d, 0xe4, 0x22,
0x75, 0x45, 0x52, 0xe8, 0x41, 0xc7, 0xed, 0x38, 0xeb, 0xf5, 0x02, 0x90, 0xc9, 0x45, 0xa3, 0xb0,
0x4d, 0x03, 0xd7, 0xab, 0x43, 0xe4, 0x21, 0xfc, 0x83, 0xd6, 0x12, 0x1d, 0x76, 0xb1, 0x3c, 0x67,
0x63, 0x1f, 0x52, 0x9d, 0xc3, 0x23, 0x5c, 0x4e, 0xa6, 0x8d, 0x01, 0x4a, 0xba, 0x9a, 0xf4, 0x16,
0x5b, 0x67, 0xc8, 0xe1, 0xd2, 0x42, 0x6d, 0xdf, 0xcd, 0x08, 0x6a, 0x73, 0x41, 0x6a, 0xc2, 0x84,
0xc6, 0x31, 0xbe, 0x57, 0xcb, 0x0e, 0xde, 0xbf, 0x71, 0xd5, 0x8a, 0xf7, 0x24, 0xb2, 0xa7, 0x89,
0x96, 0x62, 0x4f, 0xd9, 0xf7, 0xc3, 0xde, 0x4c, 0xab, 0x13, 0x72, 0xb4, 0xb3, 0x35, 0x04, 0x82,
0xa8, 0x75, 0x1d, 0xde, 0x46, 0xa8, 0x0d, 0xb8, 0x23, 0x44, 0x00, 0x44, 0xfa, 0x53, 0x6c, 0x2d,
0xce, 0xd3, 0xa6, 0x80, 0xa1, 0x20, 0xca, 0xd1, 0x63, 0xbb, 0xbe, 0x39, 0x5f, 0x9d, 0x27, 0x69,
0xb3, 0x33, 0x1f, 0xdb, 0xda, 0x67, 0x05, 0x37, 0xbe, 0x65, 0xe9, 0x7e, 0xa9, 0xc3, 0xff, 0x37,
0x8a, 0xb4, 0x2d, 0xfe, 0xf2, 0x16, 0x85, 0xc7, 0x0f, 0xd9, 0xbe, 0x14, 0xd1, 0x80, 0x14, 0x9f,
0x58, 0x56, 0x98, 0x41, 0xf6, 0x26, 0xf7, 0xa2, 0x71, 0x66, 0xb4, 0x7a, 0x9c, 0x12, 0x73, 0xd3,
0xdf, 0x77, 0x2b, 0x49, 0xe5, 0xca, 0x50, 0x57, 0x44, 0x6e, 0x3f, 0x58, 0x56, 0xbc, 0x21, 0x70,
0x4f, 0xc6, 0xaa, 0x12, 0xff, 0x7c, 0xa7, 0x3d, 0xed, 0x46, 0xc1, 0x40, 0xe6, 0x58, 0x09, 0x2a,
0xda, 0xb3, 0x76, 0xab, 0x44, 0xb5, 0x4e, 0xb3, 0x12, 0xe0, 0x26, 0x8a, 0x52, 0xac, 0x49, 0x1d,
0xe7, 0x06, 0x53, 0x3a, 0x01, 0x35, 0x21, 0x2e, 0x86, 0x48, 0xc5, 0x75, 0xc1, 0xa2, 0x7d, 0x22,
0x53, 0xf6, 0x3f, 0x41, 0xc5, 0xb3, 0x08, 0x7d, 0xa3, 0x67, 0xc0, 0xbb, 0xb6, 0x8d, 0xf0, 0xd3,
0x01, 0x72, 0xd3, 0x63, 0x82, 0x01, 0x1a, 0xe7, 0x1d, 0x22, 0xfa, 0x95, 0x33, 0xf6, 0xf2, 0xde,
0xa2, 0x53, 0x86, 0x55, 0x5a, 0xb4, 0x2e, 0x75, 0x75, 0xc6, 0xd5, 0x93, 0x9c, 0x57, 0xa9, 0x1f,
0xb9, 0x3e, 0xe8, 0x1c, 0xbf, 0xac, 0x1c, 0x54, 0x6f, 0xf5, 0xab, 0x41, 0xee, 0xb3, 0x0e, 0xd0,
0x76, 0xc4, 0x1a, 0x45, 0xcd, 0xf1, 0xd6, 0xcc, 0xb0, 0x83, 0x70, 0x73, 0xbc, 0x88, 0x74, 0xa0,
0x5b, 0xe7, 0x98, 0x10, 0x36, 0xbf, 0xec, 0x23, 0x1c, 0xc2, 0xb5, 0xba, 0x4b, 0x9d, 0x7f, 0x8c,
0x8a, 0xe2, 0xda, 0x18, 0xdd, 0xab, 0x27, 0x8a, 0x15, 0xeb, 0xb0, 0xd4, 0x3a, 0x8b, 0x77, 0x00,
0xc7, 0xbb, 0xcc, 0xfa, 0xba, 0xa4, 0x6a, 0x17, 0x5c, 0xf8, 0x51, 0x5d, 0x8d, 0x16, 0xcd, 0xa7,
0x0e, 0x71, 0x97, 0x98, 0x78, 0x5a, 0x41, 0xb3, 0xf0, 0x1f, 0x87, 0x2d, 0x65, 0xcd, 0x29, 0x49,
0xd2, 0x87, 0x2c, 0x91, 0xa9, 0x5f, 0xcc, 0xa9, 0xd8, 0xbb, 0x53, 0x18, 0xe7, 0xd6, 0xec, 0x65,
0xa6, 0x45, 0xf6, 0xce, 0xcf, 0x48, 0xf6, 0x1e, 0x3d, 0xd2, 0xcf, 0xcb, 0x3a, 0xcd, 0xbb, 0x92,
0x29, 0x24, 0x16, 0x7f, 0x8a, 0xa8, 0x5c, 0x0c, 0x45, 0x71, 0x33
};
const unsigned char commit_1[] = {
0x08,
0xf5, 0x1e, 0x0d, 0xc5, 0x86, 0x78, 0x51, 0xa9, 0x00, 0x00, 0xef, 0x4d, 0xe2, 0x94, 0x60, 0x89,
0x83, 0x04, 0xb4, 0x0e, 0x90, 0x10, 0x05, 0x1c, 0x7f, 0xd7, 0x33, 0x92, 0x1f, 0xe7, 0x74, 0x59
};
uint64_t min_value_1;
uint64_t max_value_1;
secp256k1_pedersen_commitment pc;
CHECK(secp256k1_pedersen_commitment_parse(ctx, &pc, commit_1));
CHECK(secp256k1_rangeproof_verify(
ctx,
&min_value_1, &max_value_1,
&pc,
vector_1, sizeof(vector_1),
NULL, 0,
secp256k1_generator_h
));
}
void test_pedersen_commitment_fixed_vector(void) {
const unsigned char two_g[33] = {
0x09,
0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8,
0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5
};
unsigned char result[33];
secp256k1_pedersen_commitment parse;
CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, two_g));
CHECK(secp256k1_pedersen_commitment_serialize(ctx, result, &parse));
CHECK(memcmp(two_g, result, 33) == 0);
result[0] = 0x08;
CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, result));
result[0] = 0x0c;
CHECK(!secp256k1_pedersen_commitment_parse(ctx, &parse, result));
}
void run_rangeproof_tests(void) {
int i;
test_api();
test_rangeproof_fixed_vectors();
test_pedersen_commitment_fixed_vector();
for (i = 0; i < count / 2 + 1; i++) {
for (i = 0; i < 10*count; i++) {
test_pedersen();
}
for (i = 0; i < count / 2 + 1; i++) {
for (i = 0; i < 10*count; i++) {
test_borromean();
}
test_rangeproof();

View File

@@ -1,7 +1,6 @@
include_HEADERS += include/secp256k1_recovery.h
noinst_HEADERS += src/modules/recovery/main_impl.h
noinst_HEADERS += src/modules/recovery/tests_impl.h
noinst_HEADERS += src/modules/recovery/tests_exhaustive_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_recover
bench_recover_SOURCES = src/bench_recover.c

45
src/modules/recovery/main_impl.h Normal file → Executable file
View File

@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H
#define SECP256K1_MODULE_RECOVERY_MAIN_H
#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_
#define _SECP256K1_MODULE_RECOVERY_MAIN_
#include "include/secp256k1_recovery.h"
@@ -122,15 +122,48 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, cons
int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
secp256k1_scalar r, s;
int ret, recid;
secp256k1_scalar sec, non, msg;
int recid;
int ret = 0;
int overflow = 0;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(msg32 != NULL);
ARG_CHECK(signature != NULL);
ARG_CHECK(seckey != NULL);
if (noncefp == NULL) {
noncefp = secp256k1_nonce_function_default;
}
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, NULL, NULL, NULL, msg32, seckey, noncefp, noncedata);
secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
/* Fail if the secret key is invalid. */
if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
unsigned char nonce32[32];
unsigned int count = 0;
secp256k1_scalar_set_b32(&msg, msg32, NULL);
while (1) {
ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
if (!ret) {
break;
}
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
break;
}
}
count++;
}
memset(nonce32, 0, 32);
secp256k1_scalar_clear(&msg);
secp256k1_scalar_clear(&non);
secp256k1_scalar_clear(&sec);
}
if (ret) {
secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
} else {
memset(signature, 0, sizeof(*signature));
}
return ret;
}
@@ -157,4 +190,4 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk
}
}
#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */
#endif

View File

@@ -1,149 +0,0 @@
/**********************************************************************
* Copyright (c) 2016 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
#include "src/modules/recovery/main_impl.h"
#include "include/secp256k1_recovery.h"
void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {
int i, j, k;
uint64_t iter = 0;
/* Loop */
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */
for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */
if (skip_section(&iter)) continue;
for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */
const int starting_k = k;
secp256k1_fe r_dot_y_normalized;
secp256k1_ecdsa_recoverable_signature rsig;
secp256k1_ecdsa_signature sig;
secp256k1_scalar sk, msg, r, s, expected_r;
unsigned char sk32[32], msg32[32];
int expected_recid;
int recid;
int overflow;
secp256k1_scalar_set_int(&msg, i);
secp256k1_scalar_set_int(&sk, j);
secp256k1_scalar_get_b32(sk32, &sk);
secp256k1_scalar_get_b32(msg32, &msg);
secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k);
/* Check directly */
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig);
r_from_k(&expected_r, group, k, &overflow);
CHECK(r == expected_r);
CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER ||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER);
/* The recid's second bit is for conveying overflow (R.x value >= group order).
* In the actual secp256k1 this is an astronomically unlikely event, but in the
* small group used here, it will be the case for all points except the ones where
* R.x=1 (which the group is specifically selected to have).
* Note that this isn't actually useful; full recovery would need to convey
* floor(R.x / group_order), but only one bit is used as that is sufficient
* in the real group. */
expected_recid = overflow ? 2 : 0;
r_dot_y_normalized = group[k].y;
secp256k1_fe_normalize(&r_dot_y_normalized);
/* Also the recovery id is flipped depending if we hit the low-s branch */
if ((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER) {
expected_recid |= secp256k1_fe_is_odd(&r_dot_y_normalized);
} else {
expected_recid |= !secp256k1_fe_is_odd(&r_dot_y_normalized);
}
CHECK(recid == expected_recid);
/* Convert to a standard sig then check */
secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig);
/* Note that we compute expected_r *after* signing -- this is important
* because our nonce-computing function function might change k during
* signing. */
r_from_k(&expected_r, group, k, NULL);
CHECK(r == expected_r);
CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER ||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER);
/* Overflow means we've tried every possible nonce */
if (k < starting_k) {
break;
}
}
}
}
}
void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) {
/* This is essentially a copy of test_exhaustive_verify, with recovery added */
int s, r, msg, key;
uint64_t iter = 0;
for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) {
for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) {
for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) {
for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) {
secp256k1_ge nonconst_ge;
secp256k1_ecdsa_recoverable_signature rsig;
secp256k1_ecdsa_signature sig;
secp256k1_pubkey pk;
secp256k1_scalar sk_s, msg_s, r_s, s_s;
secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s;
int recid = 0;
int k, should_verify;
unsigned char msg32[32];
if (skip_section(&iter)) continue;
secp256k1_scalar_set_int(&s_s, s);
secp256k1_scalar_set_int(&r_s, r);
secp256k1_scalar_set_int(&msg_s, msg);
secp256k1_scalar_set_int(&sk_s, key);
secp256k1_scalar_get_b32(msg32, &msg_s);
/* Verify by hand */
/* Run through every k value that gives us this r and check that *one* works.
* Note there could be none, there could be multiple, ECDSA is weird. */
should_verify = 0;
for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) {
secp256k1_scalar check_x_s;
r_from_k(&check_x_s, group, k, NULL);
if (r_s == check_x_s) {
secp256k1_scalar_set_int(&s_times_k_s, k);
secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s);
secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s);
secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s);
should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s);
}
}
/* nb we have a "high s" rule */
should_verify &= !secp256k1_scalar_is_high(&s_s);
/* We would like to try recovering the pubkey and checking that it matches,
* but pubkey recovery is impossible in the exhaustive tests (the reason
* being that there are 12 nonzero r values, 12 nonzero points, and no
* overlap between the sets, so there are no valid signatures). */
/* Verify by converting to a standard signature and calling verify */
secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid);
secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge));
secp256k1_pubkey_save(&pk, &nonconst_ge);
CHECK(should_verify ==
secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk));
}
}
}
}
}
static void test_exhaustive_recovery(const secp256k1_context *ctx, const secp256k1_ge *group) {
test_exhaustive_recovery_sign(ctx, group);
test_exhaustive_recovery_verify(ctx, group);
}
#endif /* SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H */

View File

@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H
#define SECP256K1_MODULE_RECOVERY_TESTS_H
#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_
#define _SECP256K1_MODULE_RECOVERY_TESTS_
static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
(void) msg32;
@@ -25,7 +25,7 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c
}
/* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */
memset(nonce32, 1, 32);
return secp256k1_testrand_bits(1);
return secp256k1_rand_bits(1);
}
void test_ecdsa_recovery_api(void) {
@@ -184,7 +184,7 @@ void test_ecdsa_recovery_end_to_end(void) {
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
CHECK(secp256k1_memcmp_var(&signature[4], &signature[0], 64) == 0);
CHECK(memcmp(&signature[4], &signature[0], 64) == 0);
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
memset(&rsignature[4], 0, sizeof(rsignature[4]));
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
@@ -193,16 +193,16 @@ void test_ecdsa_recovery_end_to_end(void) {
/* Parse compact (with recovery id) and recover. */
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1);
CHECK(secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
/* Serialize/destroy/parse signature and verify again. */
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
sig[secp256k1_testrand_bits(6)] += 1 + secp256k1_testrand_int(255);
sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0);
/* Recover again */
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 ||
secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
}
/* Tests several edge cases. */
@@ -215,7 +215,7 @@ void test_ecdsa_recovery_edge_cases(void) {
};
const unsigned char sig64[64] = {
/* Generated by signing the above message with nonce 'This is the nonce we will use...'
* and secret key 0 (which is not valid), resulting in recid 1. */
* and secret key 0 (which is not valid), resulting in recid 0. */
0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,
0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,
0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,
@@ -390,4 +390,4 @@ void run_recovery_tests(void) {
test_ecdsa_recovery_edge_cases();
}
#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */
#endif

Some files were not shown because too many files have changed in this diff Show More