diff --git a/.cirrus.yml b/.cirrus.yml
index 60928eb015f..48c9be8c0f1 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -23,6 +23,7 @@ env:
WHITELIST: no
MUSIG: no
ECDSAADAPTOR: no
+ BPPP: no
### test options
SECP256K1_TEST_ITERS:
BENCH: yes
@@ -72,12 +73,12 @@ task:
<< : *LINUX_CONTAINER
matrix: &ENV_MATRIX
- env: {WIDEMUL: int64, RECOVERY: yes}
- - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
+ - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
- env: {WIDEMUL: int128}
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
- - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
+ - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
- env: {WIDEMUL: int128, ASM: x86_64}
- - env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
+ - env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
- env: {CPPFLAGS: -DDETERMINISTIC}
- env: {CFLAGS: -O0, CTIMETEST: no}
@@ -108,6 +109,7 @@ task:
GENERATOR: yes
MUSIG: yes
ECDSAADAPTOR: yes
+ BPPP: yes
matrix:
- env:
CC: i686-linux-gnu-gcc
@@ -119,63 +121,29 @@ task:
<< : *CAT_LOGS
task:
- name: "x86_64: macOS Catalina"
+ name: "arm64: macOS Ventura"
macos_instance:
- image: catalina-base
+ image: ghcr.io/cirruslabs/macos-ventura-base:latest
# tasks with valgrind enabled take about 90 minutes
timeout_in: 120m
env:
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
- # Cirrus gives us a fixed number of 12 virtual CPUs. Not that we even have that many jobs at the moment...
- MAKEFLAGS: -j13
+ # Cirrus gives us a fixed number of 4 virtual CPUs. Not that we even have that many jobs at the moment...
+ MAKEFLAGS: -j5
matrix:
<< : *ENV_MATRIX
+ env:
+ ASM: no
+ WITH_VALGRIND: no
+ CTIMETEST: no
matrix:
- env:
- CC: gcc-9
+ CC: gcc
- env:
CC: clang
- # Update Command Line Tools
- # Uncomment this if the Command Line Tools on the CirrusCI macOS image are too old to brew valgrind.
- # See https://apple.stackexchange.com/a/195963 for the implementation.
- ## update_clt_script:
- ## - system_profiler SPSoftwareDataType
- ## - touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
- ## - |-
- ## PROD=$(softwareupdate -l | grep "*.*Command Line" | tail -n 1 | awk -F"*" '{print $2}' | sed -e 's/^ *//' | sed 's/Label: //g' | tr -d '\n')
- ## # For debugging
- ## - softwareupdate -l && echo "PROD: $PROD"
- ## - softwareupdate -i "$PROD" --verbose
- ## - rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
- ##
- brew_valgrind_pre_script:
- # Retry a few times because this tends to fail randomly.
- - for i in {1..5}; do brew update && break || sleep 15; done
- - brew config
- - brew tap LouisBrunner/valgrind
- # Fetch valgrind source but don't build it yet.
- - brew fetch --HEAD LouisBrunner/valgrind/valgrind
- brew_valgrind_cache:
- # This is $(brew --cellar valgrind) but command substition does not work here.
- folder: /usr/local/Cellar/valgrind
- # Rebuild cache if ...
- fingerprint_script:
- # ... macOS version changes:
- - sw_vers
- # ... brew changes:
- - brew config
- # ... valgrind changes:
- - git -C "$(brew --cache)/valgrind--git" rev-parse HEAD
- populate_script:
- # If there's no hit in the cache, build and install valgrind.
- - brew install --HEAD LouisBrunner/valgrind/valgrind
- brew_valgrind_post_script:
- # If we have restored valgrind from the cache, tell brew to create symlink to the PATH.
- # If we haven't restored from cached (and just run brew install), this is a no-op.
- - brew link valgrind
brew_script:
- - brew install automake libtool gcc@9
+ - brew install automake libtool gcc
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
@@ -199,6 +167,7 @@ task:
GENERATOR: yes
MUSIG: yes
ECDSAADAPTOR: yes
+ BPPP: yes
CTIMETEST: no
<< : *MERGE_BASE
test_script:
@@ -293,6 +262,7 @@ task:
GENERATOR: yes
MUSIG: yes
ECDSAADAPTOR: yes
+ BPPP: yes
CTIMETEST: no
matrix:
- name: "Valgrind (memcheck)"
diff --git a/.gitignore b/.gitignore
index 1ec887ded7c..9be37772b12 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,12 @@
bench
+bench_bppp
bench_ecmult
bench_generator
bench_rangeproof
bench_internal
+bench_whitelist
tests
+example_musig
exhaustive_tests
precompute_ecmult_gen
precompute_ecmult
@@ -66,4 +69,4 @@ src/stamp-h1
libsecp256k1.pc
contrib/gh-pr-create.sh
-musig_example
\ No newline at end of file
+musig_example
diff --git a/Makefile.am b/Makefile.am
index 0b50f7a8b9a..482d870d051 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -226,6 +226,10 @@ clean-precomp:
EXTRA_DIST = autogen.sh SECURITY.md
+if ENABLE_MODULE_BPPP
+include src/modules/bppp/Makefile.am.include
+endif
+
if ENABLE_MODULE_ECDH
include src/modules/ecdh/Makefile.am.include
endif
diff --git a/README.md b/README.md
index 7ac1e0a0760..b0ce01e358f 100644
--- a/README.md
+++ b/README.md
@@ -1,69 +1,24 @@
-libsecp256k1
-============
-
-[![Build Status](https://api.cirrus-ci.com/github/bitcoin-core/secp256k1.svg?branch=master)](https://cirrus-ci.com/github/bitcoin-core/secp256k1)
-
-Optimized C library for ECDSA signatures and secret/public key 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.
-
-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.)
-* Very efficient implementation.
-* Suitable for embedded systems.
-* Optional module for public key recovery.
-* Optional module for ECDH key exchange.
-* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
-* Optional module for ECDSA adaptor signatures (experimental).
-
-Experimental features have not received enough scrutiny to satisfy the standard of quality of this library but are made available for testing and review by the community. The APIs of these features should not be considered stable.
-
-Implementation details
-----------------------
-
-* General
- * No runtime heap allocation.
- * 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).
- * This is an experimental feature that has not received enough scrutiny to satisfy the standard of quality of this library but is made available for testing and review by the community.
-* Scalar operations
- * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
- * Using 4 64-bit limbs (relying on __int128 support in the compiler).
- * Using 8 32-bit limbs.
-* Modular inverses (both field elements and scalars) based on [safegcd](https://gcd.cr.yp.to/index.html) with some modifications, and a variable-time variant (by Peter Dettman).
-* Group operations
- * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7).
- * Use addition between points in Jacobian and affine coordinates where possible.
- * Use a unified addition/doubling formula where necessary to avoid data-dependent branches.
- * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space.
-* Point multiplication for verification (a*P + b*G).
- * 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.
-* 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.
+libsecp256k1-zkp
+================
+
+[![Build Status](https://api.cirrus-ci.com/github/BlockstreamResearch/secp256k1-zkp.svg?branch=master)](https://cirrus-ci.com/github/BlockstreamResearch/secp256k1-zkp)
+
+A fork of [libsecp256k1](https://github.com/bitcoin-core/secp256k1) with support for advanced and experimental features such as Confidential Assets and MuSig2
+
+Added features:
+* Experimental module for ECDSA adaptor signatures.
+* Experimental module for ECDSA sign-to-contract.
+* Experimental module for [MuSig2](src/modules/musig/musig.md).
+* Experimental module for Confidential Assets (Pedersen commitments, range proofs, and [surjection proofs](src/modules/surjection/surjection.md)).
+* Experimental module for Bulletproofs++ range proofs.
+* Experimental module for [address whitelisting](src/modules/whitelist/whitelist.md).
+
+Experimental features are made available for testing and review by the community. The APIs of these features should not be considered stable.
Build steps
-----------
-libsecp256k1 is built using autotools:
+libsecp256k1-zkp is built using autotools:
$ ./autogen.sh
$ ./configure
@@ -71,15 +26,11 @@ libsecp256k1 is built using autotools:
$ make check # run the test suite
$ sudo make install # optional
-To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags.
+To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags. For experimental modules, you will also need `--enable-experimental` as well as a flag for each individual module, e.g. `--enable-module-musig`.
Usage examples
-----------
Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
- * [ECDSA example](examples/ecdsa.c)
- * [Schnorr signatures example](examples/schnorr.c)
- * [Deriving a shared secret (ECDH) example](examples/ecdh.c)
- To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
Test coverage
-----------
@@ -105,7 +56,7 @@ To create a HTML report with coloured and annotated source code:
Benchmark
------------
-If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1 functions will be present in the root directory after the build.
+If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1-zkp functions will be present in the root directory after the build.
To print the benchmark result to the command line:
diff --git a/ci/cirrus.sh b/ci/cirrus.sh
index 431d35e4634..14c8dbe9ebd 100755
--- a/ci/cirrus.sh
+++ b/ci/cirrus.sh
@@ -19,6 +19,7 @@ valgrind --version || true
--with-ecmult-gen-precision="$ECMULTGENPRECISION" \
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
--enable-module-ecdsa-s2c="$ECDSA_S2C" \
+ --enable-module-bppp="$BPPP" \
--enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
--enable-module-schnorrsig="$SCHNORRSIG" \
@@ -51,6 +52,10 @@ then
$EXEC ./bench_ecmult
$EXEC ./bench_internal
$EXEC ./bench
+ if [ "$BPPP" = "yes" ]
+ then
+ $EXEC ./bench_bppp
+ fi
} >> bench.log 2>&1
fi
diff --git a/configure.ac b/configure.ac
index d79fe6e640b..c168694cd0b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -140,6 +140,11 @@ AC_ARG_ENABLE(examples,
AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [],
[SECP_SET_DEFAULT([enable_examples], [no], [yes])])
+AC_ARG_ENABLE(module_bppp,
+ AS_HELP_STRING([--enable-module-bppp],[enable Bulletproofs++ module (experimental)]),
+ [],
+ [SECP_SET_DEFAULT([enable_module_bppp], [no], [yes])])
+
AC_ARG_ENABLE(module_ecdh,
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])])
@@ -385,6 +390,10 @@ SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
### Handle module options
###
+# Besides testing whether modules are enabled, the following code also enables
+# module dependencies. The order of the tests matters: the dependency must be
+# tested first.
+
if test x"$enable_module_ecdh" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
fi
@@ -398,30 +407,35 @@ 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
-if test x"$enable_module_generator" = x"yes"; then
- AC_DEFINE(ENABLE_MODULE_GENERATOR, 1, [Define this symbol to enable the NUMS generator module])
+if test x"$enable_module_whitelist" = x"yes"; then
+ enable_module_rangeproof=yes
+ AC_DEFINE(ENABLE_MODULE_WHITELIST, 1, [Define this symbol to enable the key whitelisting module])
+fi
+
+if test x"$enable_module_surjectionproof" = x"yes"; then
+ enable_module_rangeproof=yes
+ AC_DEFINE(ENABLE_MODULE_SURJECTIONPROOF, 1, [Define this symbol to enable the surjection proof module])
fi
if test x"$enable_module_rangeproof" = x"yes"; then
+ enable_module_generator=yes
AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module])
fi
-if test x"$enable_module_whitelist" = x"yes"; then
- AC_DEFINE(ENABLE_MODULE_WHITELIST, 1, [Define this symbol to enable the key whitelisting module])
+if test x"$enable_module_bppp" = x"yes"; then
+ enable_module_generator=yes
+ AC_DEFINE(ENABLE_MODULE_BPPP, 1, [Define this symbol to enable the Bulletproofs++ module])
fi
-if test x"$enable_module_surjectionproof" = x"yes"; then
- AC_DEFINE(ENABLE_MODULE_SURJECTIONPROOF, 1, [Define this symbol to enable the surjection proof module])
+if test x"$enable_module_generator" = x"yes"; then
+ AC_DEFINE(ENABLE_MODULE_GENERATOR, 1, [Define this symbol to enable the NUMS generator module])
fi
-# Test if extrakeys is set _after_ the MuSig module to allow the MuSig
-# module to set enable_module_schnorrsig=yes
+
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
@@ -450,37 +464,27 @@ 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 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 ECDSA sign-to-contract module: $enable_module_ecdsa_s2c])
- AC_MSG_NOTICE([Building ECDSA adaptor signatures module: $enable_module_ecdsa_adaptor])
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
+else
+ # The order of the following tests matters. If the user enables a dependent
+ # module (which automatically enables the module dependencies) we want to
+ # print an error for the dependent module, not the module dependency. Hence,
+ # we first test dependent modules.
+ if test x"$enable_module_bppp" = x"yes"; then
+ AC_MSG_ERROR([Bulletproofs++ module is experimental. Use --enable-experimental to allow.])
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.])
- fi
+ if test x"$enable_module_whitelist" = x"yes"; then
+ AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.])
fi
-
- if test x"$enable_module_rangeproof" != x"yes"; then
- if test x"$enable_module_whitelist" = x"yes"; then
- AC_MSG_ERROR([Whitelist module requires the rangeproof module. Use --enable-module-rangeproof to allow.])
- fi
- if test x"$enable_module_surjectionproof" = x"yes"; then
- AC_MSG_ERROR([Surjection proof module requires the rangeproof module. Use --enable-module-rangeproof to allow.])
- fi
+ if test x"$enable_module_surjectionproof" = x"yes"; then
+ AC_MSG_ERROR([Surjection proof module is experimental. Use --enable-experimental to allow.])
+ fi
+ if test x"$enable_module_rangeproof" = x"yes"; then
+ AC_MSG_ERROR([Range proof module is experimental. Use --enable-experimental to allow.])
+ fi
+ if test x"$enable_module_generator" = x"yes"; then
+ AC_MSG_ERROR([NUMS generator module is experimental. Use --enable-experimental to allow.])
fi
-else
if test x"$enable_module_musig" = x"yes"; then
AC_MSG_ERROR([MuSig module is experimental. Use --enable-experimental to allow.])
fi
@@ -493,18 +497,6 @@ else
if test x"$set_asm" = x"arm"; then
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
fi
- if test x"$enable_module_generator" = x"yes"; then
- AC_MSG_ERROR([NUMS generator module is experimental. Use --enable-experimental to allow.])
- fi
- if test x"$enable_module_rangeproof" = x"yes"; then
- AC_MSG_ERROR([Range proof module is experimental. Use --enable-experimental to allow.])
- fi
- if test x"$enable_module_whitelist" = x"yes"; then
- AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.])
- fi
- if test x"$enable_module_surjectionproof" = x"yes"; then
- AC_MSG_ERROR([Surjection proof module is experimental. Use --enable-experimental to allow.])
- fi
fi
###
@@ -523,6 +515,7 @@ AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"])
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"])
AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"])
+AM_CONDITIONAL([ENABLE_MODULE_BPPP], [test x"$enable_module_bppp" = 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"])
@@ -555,9 +548,14 @@ 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 generator = $enable_module_generator"
+echo " module rangeproof = $enable_module_rangeproof"
+echo " module surjectionproof = $enable_module_surjectionproof"
+echo " module whitelist = $enable_module_whitelist"
echo " module musig = $enable_module_musig"
echo " module ecdsa-s2c = $enable_module_ecdsa_s2c"
echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor"
+echo " module bppp = $enable_module_bppp"
echo
echo " asm = $set_asm"
echo " ecmult window size = $set_ecmult_window"
diff --git a/contrib/musig2-vectors.py b/contrib/musig2-vectors.py
new file mode 100755
index 00000000000..8df3870f76f
--- /dev/null
+++ b/contrib/musig2-vectors.py
@@ -0,0 +1,656 @@
+#!/usr/bin/env python
+
+import sys
+import json
+import textwrap
+
+max_pubkeys = 0
+
+if len(sys.argv) < 2:
+ print(
+ "This script converts BIP MuSig2 test vectors in a given directory to a C file that can be used in the test framework."
+ )
+ print("Usage: %s
" % sys.argv[0])
+ sys.exit(1)
+
+
+def hexstr_to_intarray(str):
+ return ", ".join([f"0x{b:02X}" for b in bytes.fromhex(str)])
+
+
+def create_init(name):
+ return """
+static const struct musig_%s_vector musig_%s_vector = {
+""" % (
+ name,
+ name,
+ )
+
+
+def init_array(key):
+ return textwrap.indent("{ %s },\n" % hexstr_to_intarray(data[key]), 4 * " ")
+
+
+def init_arrays(key):
+ s = textwrap.indent("{\n", 4 * " ")
+ s += textwrap.indent(
+ ",\n".join(["{ %s }" % hexstr_to_intarray(x) for x in data[key]]), 8 * " "
+ )
+ s += textwrap.indent("\n},\n", 4 * " ")
+ return s
+
+
+def init_indices(array):
+ return " %d, { %s }" % (
+ len(array),
+ ", ".join(map(str, array) if len(array) > 0 else "0"),
+ )
+
+
+def init_is_xonly(case):
+ if len(case["tweak_indices"]) > 0:
+ return ", ".join(map(lambda x: "1" if x else "0", case["is_xonly"]))
+ return "0"
+
+
+def init_optional_expected(case):
+ return hexstr_to_intarray(case["expected"]) if "expected" in case else 0
+
+
+def init_cases(cases, f):
+ s = textwrap.indent("{\n", 4 * " ")
+ for (i, case) in enumerate(cases):
+ s += textwrap.indent("%s\n" % f(case), 8 * " ")
+ s += textwrap.indent("},\n", 4 * " ")
+ return s
+
+
+def finish_init():
+ return "};\n"
+
+
+s = (
+ """/**
+ * Automatically generated by %s.
+ *
+ * The test vectors for the KeySort function are included in this file. They can
+ * be found in src/modules/extrakeys/tests_impl.h. */
+"""
+ % sys.argv[0]
+)
+
+
+s += """
+enum MUSIG_ERROR {
+ MUSIG_PUBKEY,
+ MUSIG_TWEAK,
+ MUSIG_PUBNONCE,
+ MUSIG_AGGNONCE,
+ MUSIG_SECNONCE,
+ MUSIG_SIG,
+ MUSIG_SIG_VERIFY,
+ MUSIG_OTHER
+};
+"""
+
+# key agg vectors
+with open(sys.argv[1] + "/key_agg_vectors.json", "r") as f:
+ data = json.load(f)
+
+ max_key_indices = max(
+ len(test_case["key_indices"]) for test_case in data["valid_test_cases"]
+ )
+ max_tweak_indices = max(
+ len(test_case["tweak_indices"]) for test_case in data["error_test_cases"]
+ )
+ num_pubkeys = len(data["pubkeys"])
+ max_pubkeys = max(num_pubkeys, max_pubkeys)
+ num_tweaks = len(data["tweaks"])
+ num_valid_cases = len(data["valid_test_cases"])
+ num_error_cases = len(data["error_test_cases"])
+
+ # Add structures for valid and error cases
+ s += (
+ """
+struct musig_key_agg_valid_test_case {
+ size_t key_indices_len;
+ size_t key_indices[%d];
+ unsigned char expected[32];
+};
+"""
+ % max_key_indices
+ )
+ s += """
+struct musig_key_agg_error_test_case {
+ size_t key_indices_len;
+ size_t key_indices[%d];
+ size_t tweak_indices_len;
+ size_t tweak_indices[%d];
+ int is_xonly[%d];
+ enum MUSIG_ERROR error;
+};
+""" % (
+ max_key_indices,
+ max_tweak_indices,
+ max_tweak_indices,
+ )
+
+ # Add structure for entire vector
+ s += """
+struct musig_key_agg_vector {
+ unsigned char pubkeys[%d][33];
+ unsigned char tweaks[%d][32];
+ struct musig_key_agg_valid_test_case valid_case[%d];
+ struct musig_key_agg_error_test_case error_case[%d];
+};
+""" % (
+ num_pubkeys,
+ num_tweaks,
+ num_valid_cases,
+ num_error_cases,
+ )
+
+ s += create_init("key_agg")
+ # Add pubkeys and tweaks to the vector
+ s += init_arrays("pubkeys")
+ s += init_arrays("tweaks")
+
+ # Add valid cases to the vector
+ s += init_cases(
+ data["valid_test_cases"],
+ lambda case: "{ %s, { %s }},"
+ % (init_indices(case["key_indices"]), hexstr_to_intarray(case["expected"])),
+ )
+
+ def comment_to_error(case):
+ comment = case["comment"]
+ if "public key" in comment.lower():
+ return "MUSIG_PUBKEY"
+ elif "tweak" in comment.lower():
+ return "MUSIG_TWEAK"
+ else:
+ sys.exit("Unknown error")
+
+ # Add error cases to the vector
+ s += init_cases(
+ data["error_test_cases"],
+ lambda case: "{ %s, %s, { %s }, %s },"
+ % (
+ init_indices(case["key_indices"]),
+ init_indices(case["tweak_indices"]),
+ init_is_xonly(case),
+ comment_to_error(case),
+ ),
+ )
+
+ s += finish_init()
+
+# nonce gen vectors
+with open(sys.argv[1] + "/nonce_gen_vectors.json", "r") as f:
+ data = json.load(f)
+
+ # The MuSig2 implementation only allows messages of length 32
+ data["test_cases"] = list(
+ filter(lambda c: c["msg"] is None or len(c["msg"]) == 64, data["test_cases"])
+ )
+
+ num_tests = len(data["test_cases"])
+
+ s += """
+struct musig_nonce_gen_test_case {
+ unsigned char rand_[32];
+ int has_sk;
+ unsigned char sk[32];
+ unsigned char pk[33];
+ int has_aggpk;
+ unsigned char aggpk[32];
+ int has_msg;
+ unsigned char msg[32];
+ int has_extra_in;
+ unsigned char extra_in[32];
+ unsigned char expected_secnonce[97];
+ unsigned char expected_pubnonce[66];
+};
+"""
+
+ s += (
+ """
+struct musig_nonce_gen_vector {
+ struct musig_nonce_gen_test_case test_case[%d];
+};
+"""
+ % num_tests
+ )
+
+ s += create_init("nonce_gen")
+
+ def init_array_maybe(array):
+ return "%d , { %s }" % (
+ 0 if array is None else 1,
+ hexstr_to_intarray(array) if array is not None else 0,
+ )
+
+ s += init_cases(
+ data["test_cases"],
+ lambda case: "{ { %s }, %s, { %s }, %s, %s, %s, { %s }, { %s } },"
+ % (
+ hexstr_to_intarray(case["rand_"]),
+ init_array_maybe(case["sk"]),
+ hexstr_to_intarray(case["pk"]),
+ init_array_maybe(case["aggpk"]),
+ init_array_maybe(case["msg"]),
+ init_array_maybe(case["extra_in"]),
+ hexstr_to_intarray(case["expected_secnonce"]),
+ hexstr_to_intarray(case["expected_pubnonce"]),
+ ),
+ )
+
+ s += finish_init()
+
+# nonce agg vectors
+with open(sys.argv[1] + "/nonce_agg_vectors.json", "r") as f:
+ data = json.load(f)
+
+ num_pnonces = len(data["pnonces"])
+ num_valid_cases = len(data["valid_test_cases"])
+ num_error_cases = len(data["error_test_cases"])
+
+ pnonce_indices_len = 2
+ for case in data["valid_test_cases"] + data["error_test_cases"]:
+ assert len(case["pnonce_indices"]) == pnonce_indices_len
+
+ # Add structures for valid and error cases
+ s += """
+struct musig_nonce_agg_test_case {
+ size_t pnonce_indices[2];
+ /* if valid case */
+ unsigned char expected[66];
+ /* if error case */
+ int invalid_nonce_idx;
+};
+"""
+ # Add structure for entire vector
+ s += """
+struct musig_nonce_agg_vector {
+ unsigned char pnonces[%d][66];
+ struct musig_nonce_agg_test_case valid_case[%d];
+ struct musig_nonce_agg_test_case error_case[%d];
+};
+""" % (
+ num_pnonces,
+ num_valid_cases,
+ num_error_cases,
+ )
+
+ s += create_init("nonce_agg")
+ s += init_arrays("pnonces")
+
+ for cases in (data["valid_test_cases"], data["error_test_cases"]):
+ s += init_cases(
+ cases,
+ lambda case: "{ { %s }, { %s }, %d },"
+ % (
+ ", ".join(map(str, case["pnonce_indices"])),
+ init_optional_expected(case),
+ case["error"]["signer"] if "error" in case else 0,
+ ),
+ )
+ s += finish_init()
+
+# sign/verify vectors
+with open(sys.argv[1] + "/sign_verify_vectors.json", "r") as f:
+ data = json.load(f)
+
+ # The MuSig2 implementation only allows messages of length 32
+ assert list(filter(lambda x: len(x) == 64, data["msgs"]))[0] == data["msgs"][0]
+ data["msgs"] = [data["msgs"][0]]
+
+ def filter_msg32(k):
+ return list(filter(lambda x: x["msg_index"] == 0, data[k]))
+
+ data["valid_test_cases"] = filter_msg32("valid_test_cases")
+ data["sign_error_test_cases"] = filter_msg32("sign_error_test_cases")
+ data["verify_error_test_cases"] = filter_msg32("verify_error_test_cases")
+ data["verify_fail_test_cases"] = filter_msg32("verify_fail_test_cases")
+
+ num_pubkeys = len(data["pubkeys"])
+ max_pubkeys = max(num_pubkeys, max_pubkeys)
+ num_secnonces = len(data["secnonces"])
+ num_pubnonces = len(data["pnonces"])
+ num_aggnonces = len(data["aggnonces"])
+ num_msgs = len(data["msgs"])
+ num_valid_cases = len(data["valid_test_cases"])
+ num_sign_error_cases = len(data["sign_error_test_cases"])
+ num_verify_fail_cases = len(data["verify_fail_test_cases"])
+ num_verify_error_cases = len(data["verify_error_test_cases"])
+
+ all_cases = (
+ data["valid_test_cases"]
+ + data["sign_error_test_cases"]
+ + data["verify_error_test_cases"]
+ + data["verify_fail_test_cases"]
+ )
+ max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases)
+ max_nonce_indices = max(
+ len(test_case["nonce_indices"]) if "nonce_indices" in test_case else 0
+ for test_case in all_cases
+ )
+ # Add structures for valid and error cases
+ s += (
+ """
+/* Omit pubnonces in the test vectors because our partial signature verification
+ * implementation is able to accept the aggnonce directly. */
+struct musig_valid_case {
+ size_t key_indices_len;
+ size_t key_indices[%d];
+ size_t aggnonce_index;
+ size_t msg_index;
+ size_t signer_index;
+ unsigned char expected[32];
+};
+"""
+ % max_key_indices
+ )
+
+ s += (
+ """
+struct musig_sign_error_case {
+ size_t key_indices_len;
+ size_t key_indices[%d];
+ size_t aggnonce_index;
+ size_t msg_index;
+ size_t secnonce_index;
+ enum MUSIG_ERROR error;
+};
+"""
+ % max_key_indices
+ )
+
+ s += """
+struct musig_verify_fail_error_case {
+ unsigned char sig[32];
+ size_t key_indices_len;
+ size_t key_indices[%d];
+ size_t nonce_indices_len;
+ size_t nonce_indices[%d];
+ size_t msg_index;
+ size_t signer_index;
+ enum MUSIG_ERROR error;
+};
+""" % (
+ max_key_indices,
+ max_nonce_indices,
+ )
+
+ # Add structure for entire vector
+ s += """
+struct musig_sign_verify_vector {
+ unsigned char sk[32];
+ unsigned char pubkeys[%d][33];
+ unsigned char secnonces[%d][194];
+ unsigned char pubnonces[%d][194];
+ unsigned char aggnonces[%d][66];
+ unsigned char msgs[%d][32];
+ struct musig_valid_case valid_case[%d];
+ struct musig_sign_error_case sign_error_case[%d];
+ struct musig_verify_fail_error_case verify_fail_case[%d];
+ struct musig_verify_fail_error_case verify_error_case[%d];
+};
+""" % (
+ num_pubkeys,
+ num_secnonces,
+ num_pubnonces,
+ num_aggnonces,
+ num_msgs,
+ num_valid_cases,
+ num_sign_error_cases,
+ num_verify_fail_cases,
+ num_verify_error_cases,
+ )
+
+ s += create_init("sign_verify")
+ s += init_array("sk")
+ s += init_arrays("pubkeys")
+ s += init_arrays("secnonces")
+ s += init_arrays("pnonces")
+ s += init_arrays("aggnonces")
+ s += init_arrays("msgs")
+
+ s += init_cases(
+ data["valid_test_cases"],
+ lambda case: "{ %s, %d, %d, %d, { %s }},"
+ % (
+ init_indices(case["key_indices"]),
+ case["aggnonce_index"],
+ case["msg_index"],
+ case["signer_index"],
+ init_optional_expected(case),
+ ),
+ )
+
+ def sign_error(case):
+ comment = case["comment"]
+ if "pubkey" in comment or "public key" in comment:
+ return "MUSIG_PUBKEY"
+ elif "Aggregate nonce" in comment:
+ return "MUSIG_AGGNONCE"
+ elif "Secnonce" in comment:
+ return "MUSIG_SECNONCE"
+ else:
+ sys.exit("Unknown sign error")
+
+ s += init_cases(
+ data["sign_error_test_cases"],
+ lambda case: "{ %s, %d, %d, %d, %s },"
+ % (
+ init_indices(case["key_indices"]),
+ case["aggnonce_index"],
+ case["msg_index"],
+ case["secnonce_index"],
+ sign_error(case),
+ ),
+ )
+
+ def verify_error(case):
+ comment = case["comment"]
+ if "exceeds" in comment:
+ return "MUSIG_SIG"
+ elif "Wrong signer" in comment or "Wrong signature" in comment:
+ return "MUSIG_SIG_VERIFY"
+ elif "pubnonce" in comment:
+ return "MUSIG_PUBNONCE"
+ elif "pubkey" in comment:
+ return "MUSIG_PUBKEY"
+ else:
+ sys.exit("Unknown verify error")
+
+ for cases in ("verify_fail_test_cases", "verify_error_test_cases"):
+ s += init_cases(
+ data[cases],
+ lambda case: "{ { %s }, %s, %s, %d, %d, %s },"
+ % (
+ hexstr_to_intarray(case["sig"]),
+ init_indices(case["key_indices"]),
+ init_indices(case["nonce_indices"]),
+ case["msg_index"],
+ case["signer_index"],
+ verify_error(case),
+ ),
+ )
+
+ s += finish_init()
+
+# tweak vectors
+with open(sys.argv[1] + "/tweak_vectors.json", "r") as f:
+ data = json.load(f)
+
+ num_pubkeys = len(data["pubkeys"])
+ max_pubkeys = max(num_pubkeys, max_pubkeys)
+ num_pubnonces = len(data["pnonces"])
+ num_tweaks = len(data["tweaks"])
+ num_valid_cases = len(data["valid_test_cases"])
+ num_error_cases = len(data["error_test_cases"])
+
+ all_cases = data["valid_test_cases"] + data["error_test_cases"]
+ max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases)
+ max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases)
+ max_nonce_indices = max(len(test_case["nonce_indices"]) for test_case in all_cases)
+ # Add structures for valid and error cases
+ s += """
+struct musig_tweak_case {
+ size_t key_indices_len;
+ size_t key_indices[%d];
+ size_t nonce_indices_len;
+ size_t nonce_indices[%d];
+ size_t tweak_indices_len;
+ size_t tweak_indices[%d];
+ int is_xonly[%d];
+ size_t signer_index;
+ unsigned char expected[32];
+};
+""" % (
+ max_key_indices,
+ max_nonce_indices,
+ max_tweak_indices,
+ max_tweak_indices,
+ )
+
+ # Add structure for entire vector
+ s += """
+struct musig_tweak_vector {
+ unsigned char sk[32];
+ unsigned char secnonce[97];
+ unsigned char aggnonce[66];
+ unsigned char msg[32];
+ unsigned char pubkeys[%d][33];
+ unsigned char pubnonces[%d][194];
+ unsigned char tweaks[%d][32];
+ struct musig_tweak_case valid_case[%d];
+ struct musig_tweak_case error_case[%d];
+};
+""" % (
+ num_pubkeys,
+ num_pubnonces,
+ num_tweaks,
+ num_valid_cases,
+ num_error_cases,
+ )
+ s += create_init("tweak")
+ s += init_array("sk")
+ s += init_array("secnonce")
+ s += init_array("aggnonce")
+ s += init_array("msg")
+ s += init_arrays("pubkeys")
+ s += init_arrays("pnonces")
+ s += init_arrays("tweaks")
+
+ s += init_cases(
+ data["valid_test_cases"],
+ lambda case: "{ %s, %s, %s, { %s }, %d, { %s }},"
+ % (
+ init_indices(case["key_indices"]),
+ init_indices(case["nonce_indices"]),
+ init_indices(case["tweak_indices"]),
+ init_is_xonly(case),
+ case["signer_index"],
+ init_optional_expected(case),
+ ),
+ )
+
+ s += init_cases(
+ data["error_test_cases"],
+ lambda case: "{ %s, %s, %s, { %s }, %d, { %s }},"
+ % (
+ init_indices(case["key_indices"]),
+ init_indices(case["nonce_indices"]),
+ init_indices(case["tweak_indices"]),
+ init_is_xonly(case),
+ case["signer_index"],
+ init_optional_expected(case),
+ ),
+ )
+
+ s += finish_init()
+
+# sigagg vectors
+with open(sys.argv[1] + "/sig_agg_vectors.json", "r") as f:
+ data = json.load(f)
+
+ num_pubkeys = len(data["pubkeys"])
+ max_pubkeys = max(num_pubkeys, max_pubkeys)
+ num_tweaks = len(data["tweaks"])
+ num_psigs = len(data["psigs"])
+ num_valid_cases = len(data["valid_test_cases"])
+ num_error_cases = len(data["error_test_cases"])
+
+ all_cases = data["valid_test_cases"] + data["error_test_cases"]
+ max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases)
+ max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases)
+ max_psig_indices = max(len(test_case["psig_indices"]) for test_case in all_cases)
+
+ # Add structures for valid and error cases
+ s += """
+/* Omit pubnonces in the test vectors because they're only needed for
+ * implementations that do not directly accept an aggnonce. */
+struct musig_sig_agg_case {
+ size_t key_indices_len;
+ size_t key_indices[%d];
+ size_t tweak_indices_len;
+ size_t tweak_indices[%d];
+ int is_xonly[%d];
+ unsigned char aggnonce[66];
+ size_t psig_indices_len;
+ size_t psig_indices[%d];
+ /* if valid case */
+ unsigned char expected[64];
+ /* if error case */
+ int invalid_sig_idx;
+};
+""" % (
+ max_key_indices,
+ max_tweak_indices,
+ max_tweak_indices,
+ max_psig_indices,
+ )
+
+ # Add structure for entire vector
+ s += """
+struct musig_sig_agg_vector {
+ unsigned char pubkeys[%d][33];
+ unsigned char tweaks[%d][32];
+ unsigned char psigs[%d][32];
+ unsigned char msg[32];
+ struct musig_sig_agg_case valid_case[%d];
+ struct musig_sig_agg_case error_case[%d];
+};
+""" % (
+ num_pubkeys,
+ num_tweaks,
+ num_psigs,
+ num_valid_cases,
+ num_error_cases,
+ )
+
+ s += create_init("sig_agg")
+ s += init_arrays("pubkeys")
+ s += init_arrays("tweaks")
+ s += init_arrays("psigs")
+ s += init_array("msg")
+
+ for cases in (data["valid_test_cases"], data["error_test_cases"]):
+ s += init_cases(
+ cases,
+ lambda case: "{ %s, %s, { %s }, { %s }, %s, { %s }, %d },"
+ % (
+ init_indices(case["key_indices"]),
+ init_indices(case["tweak_indices"]),
+ init_is_xonly(case),
+ hexstr_to_intarray(case["aggnonce"]),
+ init_indices(case["psig_indices"]),
+ init_optional_expected(case),
+ case["error"]["signer"] if "error" in case else 0,
+ ),
+ )
+ s += finish_init()
+s += "enum { MUSIG_VECTORS_MAX_PUBKEYS = %d };" % max_pubkeys
+print(s)
diff --git a/contrib/sync-upstream.sh b/contrib/sync-upstream.sh
index 687420d8873..1489227d9bd 100755
--- a/contrib/sync-upstream.sh
+++ b/contrib/sync-upstream.sh
@@ -3,12 +3,13 @@
set -eou pipefail
help() {
- echo "$0 range [end]"
- echo " merges every merge commit present in upstream and missing locally."
+ echo "$0 [-b ] range [end]"
+ echo " merges every merge commit present in upstream and missing in (default: master)."
echo " If the optional [end] commit is provided, only merges up to [end]."
+ echo " If the optional [-b branch] provided, then ."
echo
- echo "$0 select ... "
- echo " merges every selected merge commit"
+ echo "$0 [-b ] select ... "
+ echo " merges every selected merge commit into (default: master)"
echo
echo "This tool creates a branch and a script that can be executed to create the"
echo "PR automatically. The script requires the github-cli tool (aka gh)."
@@ -17,12 +18,9 @@ help() {
exit 1
}
-if [ "$#" -lt 1 ]; then
- help
-fi
-
REMOTE=upstream
REMOTE_BRANCH="$REMOTE/master"
+LOCAL_BRANCH="master"
# Makes sure you have a remote "upstream" that is up-to-date
setup() {
ret=0
@@ -41,7 +39,7 @@ setup() {
}
range() {
- RANGESTART_COMMIT=$(git merge-base "$REMOTE_BRANCH" master)
+ RANGESTART_COMMIT=$(git merge-base "$REMOTE_BRANCH" "$LOCAL_BRANCH")
RANGEEND_COMMIT=$(git rev-parse "$REMOTE_BRANCH")
if [ "$#" = 1 ]; then
RANGEEND_COMMIT=$1
@@ -57,18 +55,37 @@ range() {
esac
}
+# Process -b argument
+while getopts "b:" opt; do
+ case $opt in
+ b)
+ LOCAL_BRANCH=$OPTARG
+ ;;
+ \?)
+ echo "Invalid option: -$OPTARG" >&2
+ ;;
+ esac
+done
+
+# Shift off the processed options
+shift $((OPTIND -1))
+
+if [ "$#" -lt 1 ]; then
+ help
+fi
+
case $1 in
range)
shift
setup
range "$@"
- REPRODUCE_COMMAND="$0 range $RANGEEND_COMMIT"
+ REPRODUCE_COMMAND="$0 range -b $LOCAL_BRANCH $RANGEEND_COMMIT"
;;
select)
shift
setup
COMMITS=$*
- REPRODUCE_COMMAND="$0 $@"
+ REPRODUCE_COMMAND="$0 select -b $LOCAL_BRANCH $@"
;;
help)
help
@@ -88,7 +105,7 @@ done
# Remove trailing ","
TITLE=${TITLE%?}
-BODY=$(printf "%s\n\n%s" "$BODY" "This PR can be recreated with \`$REPRODUCE_COMMAND\`.")
+BODY=$(printf "%s\n\n%s" "$BODY" "This PR can be recreated with \`$REPRODUCE_COMMAND\`.")
echo "-----------------------------------"
echo "$TITLE"
@@ -96,8 +113,8 @@ echo "-----------------------------------"
echo "$BODY"
echo "-----------------------------------"
# Create branch from PR commit and create PR
-git checkout master
-git pull
+git checkout "$LOCAL_BRANCH"
+git pull --autostash
git checkout -b temp-merge-"$PRNUM"
# Escape single quote
@@ -115,7 +132,7 @@ cat < "$FNAME"
#!/bin/sh
gh pr create -t '$TITLE' -b '$BODY' --web
# Remove temporary branch
-git checkout master
+git checkout "$LOCAL_BRANCH"
git branch -D temp-merge-"$PRNUM"
EOT
chmod +x "$FNAME"
diff --git a/examples/musig.c b/examples/musig.c
index 3a657410862..a34e7e78f1f 100644
--- a/examples/musig.c
+++ b/examples/musig.c
@@ -26,7 +26,7 @@ struct signer_secrets {
};
struct signer {
- secp256k1_xonly_pubkey pubkey;
+ secp256k1_pubkey pubkey;
secp256k1_musig_pubnonce pubnonce;
secp256k1_musig_partial_sig partial_sig;
};
@@ -45,7 +45,7 @@ int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_s
break;
}
}
- if (!secp256k1_keypair_xonly_pub(ctx, &signer->pubkey, NULL, &signer_secrets->keypair)) {
+ if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) {
return 0;
}
return 1;
@@ -55,13 +55,13 @@ int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_s
* and return the tweaked aggregate pk. */
int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) {
secp256k1_pubkey output_pk;
- unsigned char ordinary_tweak[32] = "this could be a BIP32 tweak....";
+ unsigned char plain_tweak[32] = "this could be a BIP32 tweak....";
unsigned char xonly_tweak[32] = "this could be a taproot tweak..";
- /* Ordinary tweaking which, for example, allows deriving multiple child
+ /* Plain tweaking which, for example, allows deriving multiple child
* public keys from a single aggregate key using BIP32 */
- if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, ordinary_tweak)) {
+ if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) {
return 0;
}
/* Note that we did not provided an output_pk argument, because the
@@ -112,7 +112,7 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
}
/* Initialize session and create secret nonce for signing and public
* nonce to send to the other signers. */
- if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, seckey, msg32, NULL, NULL)) {
+ if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, seckey, &signer[i].pubkey, msg32, NULL, NULL)) {
return 0;
}
pubnonces[i] = &signer[i].pubnonce;
@@ -164,7 +164,7 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
int i;
struct signer_secrets signer_secrets[N_SIGNERS];
struct signer signers[N_SIGNERS];
- const secp256k1_xonly_pubkey *pubkeys_ptr[N_SIGNERS];
+ const secp256k1_pubkey *pubkeys_ptr[N_SIGNERS];
secp256k1_xonly_pubkey agg_pk;
secp256k1_musig_keyagg_cache cache;
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!";
diff --git a/include/secp256k1_bppp.h b/include/secp256k1_bppp.h
new file mode 100644
index 00000000000..8ed82c4b39f
--- /dev/null
+++ b/include/secp256k1_bppp.h
@@ -0,0 +1,73 @@
+#ifndef SECP256K1_BPPP_H
+# define SECP256K1_BPPP_H
+
+# include "secp256k1.h"
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+#include
+
+/** Opaque structure representing a large number of NUMS generators */
+typedef struct secp256k1_bppp_generators secp256k1_bppp_generators;
+
+/** Allocates and initializes a list of NUMS generators.
+ * Returns a list of generators, or calls the error callback if the allocation fails.
+ * Args: ctx: pointer to a context object
+ * n: number of NUMS generators to produce.
+ *
+ * TODO: In a followup range-proof PR, this is would still require 16 + 8 = 24 NUMS
+ * points. We will later use G = H0(required for compatibility with pedersen_commitment DS)
+ * in a separate commit to make review easier.
+ */
+SECP256K1_API secp256k1_bppp_generators *secp256k1_bppp_generators_create(
+ const secp256k1_context* ctx,
+ size_t n
+) SECP256K1_ARG_NONNULL(1);
+
+/** Allocates a list of generators from a static array
+ * Returns a list of generators or NULL in case of failure.
+ * Args: ctx: pointer to a context object
+ * In: data: data that came from `secp256k1_bppp_generators_serialize`
+ * data_len: the length of the `data` buffer
+ */
+SECP256K1_API secp256k1_bppp_generators* secp256k1_bppp_generators_parse(
+ const secp256k1_context* ctx,
+ const unsigned char* data,
+ size_t data_len
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
+
+/** Serializes a list of generators to an array
+ * Returns 1 on success, 0 if the provided array was not large enough
+ * Args: ctx: pointer to a context object
+ * gen: pointer to the generator set to be serialized
+ * Out: data: pointer to buffer into which the generators will be serialized
+ * In/Out: data_len: the length of the `data` buffer. Should be at least
+ * k = 33 * num_gens. Will be set to k on successful return
+ *
+ * TODO: For ease of review, this setting G = H0 is not included in this commit. We will
+ * add it in the follow-up rangeproof PR.
+ */
+SECP256K1_API int secp256k1_bppp_generators_serialize(
+ const secp256k1_context* ctx,
+ const secp256k1_bppp_generators* gen,
+ unsigned char* data,
+ size_t *data_len
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Destroys a list of NUMS generators, freeing allocated memory
+ * Args: ctx: pointer to a context object
+ * gen: pointer to the generator set to be destroyed
+ * (can be NULL, in which case this function is a no-op)
+ */
+SECP256K1_API void secp256k1_bppp_generators_destroy(
+ const secp256k1_context* ctx,
+ secp256k1_bppp_generators* gen
+) SECP256K1_ARG_NONNULL(1);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
diff --git a/include/secp256k1_extrakeys.h b/include/secp256k1_extrakeys.h
index 685d6316a49..d8e05398cf8 100644
--- a/include/secp256k1_extrakeys.h
+++ b/include/secp256k1_extrakeys.h
@@ -155,20 +155,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
-/** Sorts xonly public keys according to secp256k1_xonly_pubkey_cmp
- *
- * Returns: 0 if the arguments are invalid. 1 otherwise.
- *
- * Args: ctx: pointer to a context object
- * In: pubkeys: array of pointers to pubkeys to sort
- * n_pubkeys: number of elements in the pubkeys array
- */
-SECP256K1_API int secp256k1_xonly_sort(
- const secp256k1_context* ctx,
- const secp256k1_xonly_pubkey **pubkeys,
- size_t n_pubkeys
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
-
/** Compute the keypair for a secret key.
*
* Returns: 1: secret was valid, keypair is ready to use
@@ -256,6 +242,37 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+/** Compare two public keys using lexicographic order of their compressed
+ * serialization.
+ *
+ * Returns: <0 if the first public key is less than the second
+ * >0 if the first public key is greater than the second
+ * 0 if the two public keys are equal
+ * Args: ctx: a secp256k1 context object.
+ * In: pubkey1: first public key to compare
+ * pubkey2: second public key to compare
+ */
+SECP256K1_API int secp256k1_pubkey_cmp(
+ const secp256k1_context* ctx,
+ const secp256k1_pubkey* pk1,
+ const secp256k1_pubkey* pk2
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Sort public keys using lexicographic order of their compressed
+ * serialization.
+ *
+ * Returns: 0 if the arguments are invalid. 1 otherwise.
+ *
+ * Args: ctx: pointer to a context object
+ * In: pubkeys: array of pointers to pubkeys to sort
+ * n_pubkeys: number of elements in the pubkeys array
+ */
+SECP256K1_API int secp256k1_pubkey_sort(
+ const secp256k1_context* ctx,
+ const secp256k1_pubkey **pubkeys,
+ size_t n_pubkeys
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/secp256k1_generator.h b/include/secp256k1_generator.h
index cb55af91cb7..f0570dcb94c 100644
--- a/include/secp256k1_generator.h
+++ b/include/secp256k1_generator.h
@@ -1,5 +1,5 @@
-#ifndef _SECP256K1_GENERATOR_
-# define _SECP256K1_GENERATOR_
+#ifndef SECP256K1_GENERATOR_H
+# define SECP256K1_GENERATOR_H
# include "secp256k1.h"
@@ -21,6 +21,11 @@ typedef struct {
unsigned char data[64];
} secp256k1_generator;
+/**
+ * Static constant generator 'h' maintained for historical reasons.
+ */
+SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h;
+
/** Parse a 33-byte generator byte sequence into a generator object.
*
* Returns: 1 if input contains a valid generator.
@@ -86,6 +91,149 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate_blin
const unsigned char *blind32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+/** Opaque data structure that stores a Pedersen commitment
+ *
+ * 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.
+ */
+typedef struct {
+ unsigned char data[64];
+} secp256k1_pedersen_commitment;
+
+/** Parse a 33-byte commitment into a commitment object.
+ *
+ * Returns: 1 if input contains a valid commitment.
+ * Args: ctx: a secp256k1 context object.
+ * Out: commit: pointer to the output commitment object
+ * In: input: pointer to a 33-byte serialized commitment key
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_parse(
+ const secp256k1_context* ctx,
+ secp256k1_pedersen_commitment* commit,
+ const unsigned char *input
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Serialize a commitment object into a serialized byte sequence.
+ *
+ * Returns: 1 always.
+ * Args: ctx: a secp256k1 context object.
+ * Out: output: a pointer to a 33-byte byte array
+ * In: commit: a pointer to a secp256k1_pedersen_commitment containing an
+ * initialized commitment
+ */
+SECP256K1_API int secp256k1_pedersen_commitment_serialize(
+ const secp256k1_context* ctx,
+ unsigned char *output,
+ const secp256k1_pedersen_commitment* commit
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Generate a pedersen commitment.
+ * Returns 1: Commitment successfully created.
+ * 0: Error. The blinding factor is larger than the group order
+ * (probability for random 32 byte number < 2^-127) or results in the
+ * point at infinity. Retry with a different factor.
+ * In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL)
+ * blind: pointer to a 32-byte blinding factor (cannot be NULL)
+ * value: unsigned 64-bit integer value to commit to.
+ * gen: additional generator 'h'
+ * Out: commit: pointer to the commitment (cannot be NULL)
+ *
+ * Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
+ const secp256k1_context* ctx,
+ secp256k1_pedersen_commitment *commit,
+ const unsigned char *blind,
+ uint64_t value,
+ const secp256k1_generator *gen
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
+
+/** Computes the sum of multiple positive and negative blinding factors.
+ * Returns 1: Sum successfully computed.
+ * 0: Error. A blinding factor is larger than the group order
+ * (probability for random 32 byte number < 2^-127). Retry with
+ * different factors.
+ * In: ctx: pointer to a context object (cannot be NULL)
+ * blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL)
+ * n: number of factors pointed to by blinds.
+ * npositive: how many of the initial factors should be treated with a positive sign.
+ * Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
+ const secp256k1_context* ctx,
+ unsigned char *blind_out,
+ const unsigned char * const *blinds,
+ size_t n,
+ size_t npositive
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Verify a tally of pedersen commitments
+ * Returns 1: commitments successfully sum to zero.
+ * 0: Commitments do not sum to zero or other error.
+ * In: ctx: pointer to a context object (cannot be NULL)
+ * commits: pointer to array of pointers to the commitments. (cannot be NULL if pcnt is non-zero)
+ * pcnt: number of commitments pointed to by commits.
+ * ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero)
+ * ncnt: number of commitments pointed to by ncommits.
+ *
+ * This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 0.
+ *
+ * A pedersen commitment is xG + vA where G and A are generators for the secp256k1 group and x is a blinding factor,
+ * while v is the committed value. For a collection of commitments to sum to zero, for each distinct generator
+ * A all blinding factors and all values must sum to zero.
+ *
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
+ const secp256k1_context* ctx,
+ const secp256k1_pedersen_commitment * const* commits,
+ size_t pcnt,
+ const secp256k1_pedersen_commitment * const* ncommits,
+ size_t ncnt
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
+
+/** Sets the final Pedersen blinding factor correctly when the generators themselves
+ * have blinding factors.
+ *
+ * Consider a generator of the form A' = A + rG, where A is the "real" generator
+ * but A' is the generator provided to verifiers. Then a Pedersen commitment
+ * P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r')
+ * to sum to zero for multiple commitments, we take three arrays consisting of
+ * the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s
+ * and `blinding_factor`s, and sum them.
+ *
+ * The function then subtracts the sum of all (vr + r') from the last element
+ * of the `blinding_factor` array, setting the total sum to zero.
+ *
+ * Returns 1: Blinding factor successfully computed.
+ * 0: Error. A blinding_factor or generator_blind are larger than the group
+ * order (probability for random 32 byte number < 2^-127). Retry with
+ * different values.
+ *
+ * In: ctx: pointer to a context object
+ * value: array of asset values, `v` in the above paragraph.
+ * May not be NULL unless `n_total` is 0.
+ * generator_blind: array of asset blinding factors, `r` in the above paragraph
+ * May not be NULL unless `n_total` is 0.
+ * n_total: Total size of the above arrays
+ * n_inputs: How many of the initial array elements represent commitments that
+ * will be negated in the final sum
+ * In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph
+ * May not be NULL unless `n_total` is 0.
+ * the last value will be modified to get the total sum to zero.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generator_blind_sum(
+ const secp256k1_context* ctx,
+ const uint64_t *value,
+ const unsigned char* const* generator_blind,
+ unsigned char* const* blinding_factor,
+ size_t n_total,
+ size_t n_inputs
+);
+
# ifdef __cplusplus
}
# endif
diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h
index adcc060fcab..fdf60e51881 100644
--- a/include/secp256k1_musig.h
+++ b/include/secp256k1_musig.h
@@ -9,11 +9,11 @@ extern "C" {
#include
-/** This module implements a Schnorr-based multi-signature scheme called MuSig2
- * (https://eprint.iacr.org/2020/1261, see Appendix B for the exact variant).
- * Signatures are compatible with BIP-340 ("Schnorr").
- * There's an example C source file in the module's directory
- * (examples/musig.c) that demonstrates how it can be used.
+/** This module implements BIP 327 "MuSig2 for BIP340-compatible
+ * Multi-Signatures"
+ * (https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki)
+ * v1.0.0. You can find an example demonstrating the musig module in
+ * examples/musig.c.
*
* The module also supports BIP-341 ("Taproot") public key tweaking and adaptor
* signatures as described in
@@ -22,12 +22,8 @@ extern "C" {
* It is recommended to read the documentation in this include file carefully.
* Further notes on API usage can be found in src/modules/musig/musig.md
*
- * You may know that the MuSig2 scheme uses two "nonces" instead of one. This
- * is not wrong, but only a technical detail we don't want to bother the user
- * with. Therefore, the API only uses the singular term "nonce".
- *
- * Since the first version of MuSig is essentially replaced by MuSig2, when
- * writing MuSig or musig here we mean MuSig2.
+ * Since the first version of MuSig is essentially replaced by MuSig2, we use
+ * MuSig, musig and MuSig2 synonymously unless noted otherwise.
*/
/** Opaque data structures
@@ -40,16 +36,16 @@ extern "C" {
/** Opaque data structure that caches information about public key aggregation.
*
- * Guaranteed to be 165 bytes in size. It can be safely copied/moved. No
+ * Guaranteed to be 197 bytes in size. It can be safely copied/moved. No
* serialization and parsing functions (yet).
*/
typedef struct {
- unsigned char data[165];
+ unsigned char data[197];
} secp256k1_musig_keyagg_cache;
/** Opaque data structure that holds a signer's _secret_ nonce.
*
- * Guaranteed to be 68 bytes in size.
+ * Guaranteed to be 132 bytes in size.
*
* WARNING: This structure MUST NOT be copied or read or written to directly. A
* signer who is online throughout the whole process and can keep this
@@ -63,7 +59,7 @@ typedef struct {
* leak the secret signing key.
*/
typedef struct {
- unsigned char data[68];
+ unsigned char data[132];
} secp256k1_musig_secnonce;
/** Opaque data structure that holds a signer's public nonce.
@@ -190,8 +186,8 @@ SECP256K1_API int secp256k1_musig_partial_sig_parse(
*
* Different orders of `pubkeys` result in different `agg_pk`s.
*
- * The pubkeys can be sorted before combining with `secp256k1_xonly_sort` which
- * ensures the same `agg_pk` result for the same multiset of pubkeys.
+ * Before aggregating, the pubkeys can be sorted with `secp256k1_pubkey_sort`
+ * which ensures the same `agg_pk` result for the same multiset of pubkeys.
* This is useful to do before `pubkey_agg`, such that the order of pubkeys
* does not affect the aggregate public key.
*
@@ -219,14 +215,14 @@ SECP256K1_API int secp256k1_musig_pubkey_agg(
secp256k1_scratch_space *scratch,
secp256k1_xonly_pubkey *agg_pk,
secp256k1_musig_keyagg_cache *keyagg_cache,
- const secp256k1_xonly_pubkey * const* pubkeys,
+ const secp256k1_pubkey * const* pubkeys,
size_t n_pubkeys
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5);
/** Obtain the aggregate public key from a keyagg_cache.
*
* This is only useful if you need the non-xonly public key, in particular for
- * ordinary (non-xonly) tweaking or batch-verifying multiple key aggregations
+ * plain (non-xonly) tweaking or batch-verifying multiple key aggregations
* (not implemented).
*
* Returns: 0 if the arguments are invalid, 1 otherwise
@@ -241,7 +237,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get(
secp256k1_musig_keyagg_cache *keyagg_cache
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Apply ordinary "EC" tweaking to a public key in a given keyagg_cache by
+/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by
* adding the generator multiplied with `tweak32` to it. This is useful for
* deriving child keys from an aggregate public key via BIP32.
*
@@ -357,6 +353,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea
* unless you really know what you are doing.
* seckey: the 32-byte secret key that will later be used for signing, if
* already known (can be NULL)
+ * pubkey: public key of the signer creating the nonce. The secnonce
+ * output of this function cannot be used to sign for any
+ * other public key.
* msg32: the 32-byte message that will later be signed, if already known
* (can be NULL)
* keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate
@@ -371,10 +370,11 @@ SECP256K1_API int secp256k1_musig_nonce_gen(
secp256k1_musig_pubnonce *pubnonce,
const unsigned char *session_id32,
const unsigned char *seckey,
+ const secp256k1_pubkey *pubkey,
const unsigned char *msg32,
const secp256k1_musig_keyagg_cache *keyagg_cache,
const unsigned char *extra_input32
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6);
/** Aggregates the nonces of all signers into a single nonce
*
@@ -436,13 +436,25 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process(
* reuse. However, this is of course easily defeated if the secnonce has been
* copied (or serialized). Remember that nonce reuse will leak the secret key!
*
+ * For signing to succeed, the secnonce provided to this function must have
+ * been generated for the provided keypair. This means that when signing for a
+ * keypair consisting of a seckey and pubkey, the secnonce must have been
+ * created by calling musig_nonce_gen with that pubkey. Otherwise, the
+ * illegal_callback is called.
+ *
+ * This function does not verify the output partial signature, deviating from
+ * the BIP 327 specification. It is recommended to verify the output partial
+ * signature with `secp256k1_musig_partial_sig_verify` to prevent random or
+ * adversarially provoked computation errors.
+ *
* Returns: 0 if the arguments are invalid or the provided secnonce has already
* been used for signing, 1 otherwise
* Args: ctx: pointer to a context object
* Out: partial_sig: pointer to struct to store the partial signature
* In/Out: secnonce: pointer to the secnonce struct created in
* musig_nonce_gen that has been never used in a
- * partial_sign call before
+ * partial_sign call before and has been created for the
+ * keypair
* In: keypair: pointer to keypair to sign the message with
* keyagg_cache: pointer to the keyagg_cache that was output when the
* aggregate public key for this session
@@ -494,7 +506,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif
const secp256k1_context* ctx,
const secp256k1_musig_partial_sig *partial_sig,
const secp256k1_musig_pubnonce *pubnonce,
- const secp256k1_xonly_pubkey *pubkey,
+ const secp256k1_pubkey *pubkey,
const secp256k1_musig_keyagg_cache *keyagg_cache,
const secp256k1_musig_session *session
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
diff --git a/include/secp256k1_rangeproof.h b/include/secp256k1_rangeproof.h
index d4f35de7ac5..80a4f9676d4 100644
--- a/include/secp256k1_rangeproof.h
+++ b/include/secp256k1_rangeproof.h
@@ -1,5 +1,5 @@
-#ifndef _SECP256K1_RANGEPROOF_
-# define _SECP256K1_RANGEPROOF_
+#ifndef SECP256K1_RANGEPROOF_H
+# define SECP256K1_RANGEPROOF_H
# include "secp256k1.h"
# include "secp256k1_generator.h"
@@ -10,153 +10,14 @@ extern "C" {
#include
-/** Opaque data structure that stores a Pedersen commitment
+/** Length of a message that can be embedded into a maximally-sized rangeproof
*
- * 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.
+ * It is not be possible to fit a message of this size into a non-maximally-sized
+ * rangeproof, but it is guaranteed that any embeddable message can fit into an
+ * array of this size. This constant is intended to be used for memory allocations
+ * and sanity checks.
*/
-typedef struct {
- unsigned char data[64];
-} secp256k1_pedersen_commitment;
-
-/**
- * Static constant generator 'h' maintained for historical reasons.
- */
-SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h;
-
-/** Parse a 33-byte commitment into a commitment object.
- *
- * Returns: 1 if input contains a valid commitment.
- * Args: ctx: a secp256k1 context object.
- * Out: commit: pointer to the output commitment object
- * In: input: pointer to a 33-byte serialized commitment key
- */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_parse(
- const secp256k1_context* ctx,
- secp256k1_pedersen_commitment* commit,
- const unsigned char *input
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-
-/** Serialize a commitment object into a serialized byte sequence.
- *
- * Returns: 1 always.
- * Args: ctx: a secp256k1 context object.
- * Out: output: a pointer to a 33-byte byte array
- * In: commit: a pointer to a secp256k1_pedersen_commitment containing an
- * initialized commitment
- */
-SECP256K1_API int secp256k1_pedersen_commitment_serialize(
- const secp256k1_context* ctx,
- unsigned char *output,
- const secp256k1_pedersen_commitment* commit
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-
-/** Generate a pedersen commitment.
- * Returns 1: Commitment successfully created.
- * 0: Error. The blinding factor is larger than the group order
- * (probability for random 32 byte number < 2^-127) or results in the
- * point at infinity. Retry with a different factor.
- * In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL)
- * blind: pointer to a 32-byte blinding factor (cannot be NULL)
- * value: unsigned 64-bit integer value to commit to.
- * gen: additional generator 'h'
- * Out: commit: pointer to the commitment (cannot be NULL)
- *
- * Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA.
- */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
- const secp256k1_context* ctx,
- secp256k1_pedersen_commitment *commit,
- const unsigned char *blind,
- uint64_t value,
- const secp256k1_generator *gen
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
-
-/** Computes the sum of multiple positive and negative blinding factors.
- * Returns 1: Sum successfully computed.
- * 0: Error. A blinding factor is larger than the group order
- * (probability for random 32 byte number < 2^-127). Retry with
- * different factors.
- * In: ctx: pointer to a context object (cannot be NULL)
- * blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL)
- * n: number of factors pointed to by blinds.
- * npositive: how many of the initial factors should be treated with a positive sign.
- * Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL)
- */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
- const secp256k1_context* ctx,
- unsigned char *blind_out,
- const unsigned char * const *blinds,
- size_t n,
- size_t npositive
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-
-/** Verify a tally of pedersen commitments
- * Returns 1: commitments successfully sum to zero.
- * 0: Commitments do not sum to zero or other error.
- * In: ctx: pointer to a context object (cannot be NULL)
- * commits: pointer to array of pointers to the commitments. (cannot be NULL if pcnt is non-zero)
- * pcnt: number of commitments pointed to by commits.
- * ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero)
- * ncnt: number of commitments pointed to by ncommits.
- *
- * This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 0.
- *
- * A pedersen commitment is xG + vA where G and A are generators for the secp256k1 group and x is a blinding factor,
- * while v is the committed value. For a collection of commitments to sum to zero, for each distinct generator
- * A all blinding factors and all values must sum to zero.
- *
- */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
- const secp256k1_context* ctx,
- const secp256k1_pedersen_commitment * const* commits,
- size_t pcnt,
- const secp256k1_pedersen_commitment * const* ncommits,
- size_t ncnt
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
-
-/** Sets the final Pedersen blinding factor correctly when the generators themselves
- * have blinding factors.
- *
- * Consider a generator of the form A' = A + rG, where A is the "real" generator
- * but A' is the generator provided to verifiers. Then a Pedersen commitment
- * P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r')
- * to sum to zero for multiple commitments, we take three arrays consisting of
- * the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s
- * and `blinding_factor`s, and sum them.
- *
- * The function then subtracts the sum of all (vr + r') from the last element
- * of the `blinding_factor` array, setting the total sum to zero.
- *
- * Returns 1: Blinding factor successfully computed.
- * 0: Error. A blinding_factor or generator_blind are larger than the group
- * order (probability for random 32 byte number < 2^-127). Retry with
- * different values.
- *
- * In: ctx: pointer to a context object
- * value: array of asset values, `v` in the above paragraph.
- * May not be NULL unless `n_total` is 0.
- * generator_blind: array of asset blinding factors, `r` in the above paragraph
- * May not be NULL unless `n_total` is 0.
- * n_total: Total size of the above arrays
- * n_inputs: How many of the initial array elements represent commitments that
- * will be negated in the final sum
- * In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph
- * May not be NULL unless `n_total` is 0.
- * the last value will be modified to get the total sum to zero.
- */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generator_blind_sum(
- const secp256k1_context* ctx,
- const uint64_t *value,
- const unsigned char* const* generator_blind,
- unsigned char* const* blinding_factor,
- size_t n_total,
- size_t n_inputs
-);
+#define SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN 3968
/** 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.
@@ -227,7 +88,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
* proof: pointer to array to receive the proof, can be up to 5134 bytes. (cannot be NULL)
* min_value: constructs a proof where the verifer can tell the minimum value is at least the specified amount.
* commit: the commitment being proved.
- * blind: 32-byte blinding factor used by commit.
+ * blind: 32-byte blinding factor used by commit. The blinding factor may be all-zeros as long as min_bits is set to 3 or greater.
+ * This is a side-effect of the underlying crypto, not a deliberate API choice, but it may be useful when balancing CT transactions.
* nonce: 32-byte secret nonce used to initialize the proof (value can be reverse-engineered out of the proof if this secret is known.)
* exp: Base-10 exponent. Digits below above will be made public, but the proof will be made smaller. Allowed range is -1 to 18.
* (-1 is a special case that makes the value public. 0 is the most private.)
@@ -286,6 +148,33 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_info(
size_t plen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
+/** Returns an upper bound on the size of a rangeproof with the given parameters
+ *
+ * An actual rangeproof may be smaller, for example if the actual value
+ * is less than both the provided `max_value` and 2^`min_bits`, or if
+ * the `exp` parameter to `secp256k1_rangeproof_sign` is set such that
+ * the proven range is compressed. In particular this function will always
+ * overestimate the size of single-value proofs. Also, if `min_value`
+ * is set to 0 in the proof, the result will usually, but not always,
+ * be 8 bytes smaller than if a nonzero value had been passed.
+ *
+ * The goal of this function is to provide a useful upper bound for
+ * memory allocation or fee estimation purposes, without requiring
+ * too many parameters be fixed in advance.
+ *
+ * To obtain the size of largest possible proof, set `max_value` to
+ * `UINT64_MAX` (and `min_bits` to any valid value such as 0).
+ *
+ * In: ctx: pointer to a context object
+ * max_value: the maximum value that might be passed for `value` for the proof.
+ * min_bits: the value that will be passed as `min_bits` for the proof.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT size_t secp256k1_rangeproof_max_size(
+ const secp256k1_context* ctx,
+ uint64_t max_value,
+ int min_bits
+) SECP256K1_ARG_NONNULL(1);
+
# ifdef __cplusplus
}
# endif
diff --git a/include/secp256k1_surjectionproof.h b/include/secp256k1_surjectionproof.h
index ab7a4a9ec50..4939e327da9 100644
--- a/include/secp256k1_surjectionproof.h
+++ b/include/secp256k1_surjectionproof.h
@@ -1,5 +1,5 @@
-#ifndef _SECP256K1_SURJECTIONPROOF_
-#define _SECP256K1_SURJECTIONPROOF_
+#ifndef SECP256K1_SURJECTIONPROOF_H
+#define SECP256K1_SURJECTIONPROOF_H
#include "secp256k1.h"
#include "secp256k1_rangeproof.h"
diff --git a/include/secp256k1_whitelist.h b/include/secp256k1_whitelist.h
index 5b14df7c81d..83a053dd16d 100644
--- a/include/secp256k1_whitelist.h
+++ b/include/secp256k1_whitelist.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_WHITELIST_
-#define _SECP256K1_WHITELIST_
+#ifndef SECP256K1_WHITELIST_H
+#define SECP256K1_WHITELIST_H
#include "secp256k1.h"
diff --git a/src/bench_bppp.c b/src/bench_bppp.c
new file mode 100644
index 00000000000..83e46443328
--- /dev/null
+++ b/src/bench_bppp.c
@@ -0,0 +1,38 @@
+/**********************************************************************
+ * Copyright (c) 2020 Andrew Poelstra *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include
+
+#include "../include/secp256k1_bppp.h"
+#include "util.h"
+#include "bench.h"
+
+typedef struct {
+ secp256k1_context* ctx;
+} bench_bppp_data;
+
+static void bench_bppp_setup(void* arg) {
+ (void) arg;
+}
+
+static void bench_bppp(void* arg, int iters) {
+ bench_bppp_data *data = (bench_bppp_data*)arg;
+
+ (void) data;
+ (void) iters;
+}
+
+int main(void) {
+ bench_bppp_data data;
+ int iters = get_iters(32);
+
+ data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+
+ run_benchmark("bppp_verify_bit", bench_bppp, bench_bppp_setup, NULL, &data, 10, iters);
+
+ secp256k1_context_destroy(data.ctx);
+ return 0;
+}
diff --git a/src/bench_generator.c b/src/bench_generator.c
index d3b251e4085..175137e9ca5 100644
--- a/src/bench_generator.c
+++ b/src/bench_generator.c
@@ -7,7 +7,7 @@
#include
#include
-#include "include/secp256k1_generator.h"
+#include "../include/secp256k1_generator.h"
#include "util.h"
#include "bench.h"
diff --git a/src/bench_internal.c b/src/bench_internal.c
index 61400519ed1..898c7801c2f 100644
--- a/src/bench_internal.c
+++ b/src/bench_internal.c
@@ -98,6 +98,15 @@ void bench_scalar_negate(void* arg, int iters) {
}
}
+void bench_scalar_sqr(void* arg, int iters) {
+ int i;
+ bench_inv *data = (bench_inv*)arg;
+
+ for (i = 0; i < iters; i++) {
+ secp256k1_scalar_sqr(&data->scalar[0], &data->scalar[0]);
+ }
+}
+
void bench_scalar_mul(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@@ -376,6 +385,7 @@ int main(int argc, char **argv) {
if (d || 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 (d || 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 (d || 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 (d || 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 (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters);
diff --git a/src/bench_rangeproof.c b/src/bench_rangeproof.c
index 14e22e8a801..14f5f875132 100644
--- a/src/bench_rangeproof.c
+++ b/src/bench_rangeproof.c
@@ -6,7 +6,7 @@
#include
-#include "include/secp256k1_rangeproof.h"
+#include "../include/secp256k1_rangeproof.h"
#include "util.h"
#include "bench.h"
diff --git a/src/bench_whitelist.c b/src/bench_whitelist.c
index e4908306f94..18bfa144dcf 100644
--- a/src/bench_whitelist.c
+++ b/src/bench_whitelist.c
@@ -5,9 +5,9 @@
**********************************************************************/
#include
-#include "include/secp256k1.h"
+#include "../include/secp256k1.h"
-#include "include/secp256k1_whitelist.h"
+#include "../include/secp256k1_whitelist.h"
#include "util.h"
#include "bench.h"
#include "hash_impl.h"
diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h
index 12dbcc6c5b6..c92b2a048df 100644
--- a/src/ecmult_const_impl.h
+++ b/src/ecmult_const_impl.h
@@ -29,7 +29,7 @@ static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *p
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
int m = 0; \
/* Extract the sign-bit for a constant time absolute-value. */ \
- int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
+ int volatile mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
int abs_n = ((n) + mask) ^ mask; \
int idx_n = abs_n >> 1; \
secp256k1_fe neg_y; \
diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h
index 21742bf6eb6..0eeb8a8dead 100644
--- a/src/field_10x26_impl.h
+++ b/src/field_10x26_impl.h
@@ -1132,8 +1132,9 @@ 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;
+ volatile int vflag = flag;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
- mask0 = flag + ~((uint32_t)0);
+ mask0 = vflag + ~((uint32_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
@@ -1231,8 +1232,9 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint32_t mask0, mask1;
+ volatile int vflag = flag;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
- mask0 = flag + ~((uint32_t)0);
+ mask0 = vflag + ~((uint32_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
diff --git a/src/field_5x52_asm_impl.h b/src/field_5x52_asm_impl.h
index a2118044ab3..51e35c96bdb 100644
--- a/src/field_5x52_asm_impl.h
+++ b/src/field_5x52_asm_impl.h
@@ -278,7 +278,7 @@ __asm__ __volatile__(
"addq %%rsi,%%r8\n"
/* r[4] = c */
"movq %%r8,32(%%rdi)\n"
-: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3)
+: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
: "b"(b), "D"(r)
: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
);
@@ -493,7 +493,7 @@ __asm__ __volatile__(
"addq %%rsi,%%r8\n"
/* r[4] = c */
"movq %%r8,32(%%rdi)\n"
-: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3)
+: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
: "D"(r)
: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
);
diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h
index 6bd202f5871..dc0467db1f7 100644
--- a/src/field_5x52_impl.h
+++ b/src/field_5x52_impl.h
@@ -476,8 +476,9 @@ 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;
+ volatile int vflag = flag;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
- mask0 = flag + ~((uint64_t)0);
+ mask0 = vflag + ~((uint64_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
@@ -559,8 +560,9 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint64_t mask0, mask1;
+ volatile int vflag = flag;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
- mask0 = flag + ~((uint64_t)0);
+ mask0 = vflag + ~((uint64_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
diff --git a/src/modinv32_impl.h b/src/modinv32_impl.h
index 661c5fc04c9..fc16eaaad39 100644
--- a/src/modinv32_impl.h
+++ b/src/modinv32_impl.h
@@ -64,7 +64,7 @@ static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int3
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
int32_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4],
r5 = r->v[5], r6 = r->v[6], r7 = r->v[7], r8 = r->v[8];
- int32_t cond_add, cond_negate;
+ volatile int32_t cond_add, cond_negate;
#ifdef VERIFY
/* Verify that all limbs are in range (-2^30,2^30). */
@@ -186,7 +186,8 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
* being inside [-2^31,2^31) means that casting to signed works correctly.
*/
uint32_t u = 1, v = 0, q = 0, r = 1;
- uint32_t c1, c2, f = f0, g = g0, x, y, z;
+ volatile uint32_t c1, c2;
+ uint32_t mask1, mask2, f = f0, g = g0, x, y, z;
int i;
for (i = 0; i < 30; ++i) {
@@ -195,23 +196,25 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
VERIFY_CHECK((q * f0 + r * g0) == g << i);
/* Compute conditional masks for (zeta < 0) and for (g & 1). */
c1 = zeta >> 31;
- c2 = -(g & 1);
+ mask1 = c1;
+ c2 = g & 1;
+ mask2 = -c2;
/* Compute x,y,z, conditionally negated versions of f,u,v. */
- x = (f ^ c1) - c1;
- y = (u ^ c1) - c1;
- z = (v ^ c1) - c1;
+ x = (f ^ mask1) - mask1;
+ y = (u ^ mask1) - mask1;
+ z = (v ^ mask1) - mask1;
/* Conditionally add x,y,z to g,q,r. */
- g += x & c2;
- q += y & c2;
- r += z & c2;
- /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */
- c1 &= c2;
+ g += x & mask2;
+ q += y & mask2;
+ r += z & mask2;
+ /* In what follows, mask1 is a condition mask for (zeta < 0) and (g & 1). */
+ mask1 &= mask2;
/* Conditionally change zeta into -zeta-2 or zeta-1. */
- zeta = (zeta ^ c1) - 1;
+ zeta = (zeta ^ mask1) - 1;
/* Conditionally add g,q,r to f,u,v. */
- f += g & c1;
- u += q & c1;
- v += r & c1;
+ f += g & mask1;
+ u += q & mask1;
+ v += r & mask1;
/* Shifts */
g >>= 1;
u <<= 1;
diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h
index 0743a9c8210..905ef47be31 100644
--- a/src/modinv64_impl.h
+++ b/src/modinv64_impl.h
@@ -69,7 +69,7 @@ static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, i
static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int64_t sign, const secp256k1_modinv64_modinfo *modinfo) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4];
- int64_t cond_add, cond_negate;
+ volatile int64_t cond_add, cond_negate;
#ifdef VERIFY
/* Verify that all limbs are in range (-2^62,2^62). */
@@ -165,7 +165,8 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
* being inside [-2^63,2^63) means that casting to signed works correctly.
*/
uint64_t u = 8, v = 0, q = 0, r = 8;
- uint64_t c1, c2, f = f0, g = g0, x, y, z;
+ volatile uint64_t c1, c2;
+ uint64_t mask1, mask2, f = f0, g = g0, x, y, z;
int i;
for (i = 3; i < 62; ++i) {
@@ -174,23 +175,25 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
VERIFY_CHECK((q * f0 + r * g0) == g << i);
/* Compute conditional masks for (zeta < 0) and for (g & 1). */
c1 = zeta >> 63;
- c2 = -(g & 1);
+ mask1 = c1;
+ c2 = g & 1;
+ mask2 = -c2;
/* Compute x,y,z, conditionally negated versions of f,u,v. */
- x = (f ^ c1) - c1;
- y = (u ^ c1) - c1;
- z = (v ^ c1) - c1;
+ x = (f ^ mask1) - mask1;
+ y = (u ^ mask1) - mask1;
+ z = (v ^ mask1) - mask1;
/* Conditionally add x,y,z to g,q,r. */
- g += x & c2;
- q += y & c2;
- r += z & c2;
+ g += x & mask2;
+ q += y & mask2;
+ r += z & mask2;
/* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */
- c1 &= c2;
+ mask1 &= mask2;
/* Conditionally change zeta into -zeta-2 or zeta-1. */
- zeta = (zeta ^ c1) - 1;
+ zeta = (zeta ^ mask1) - 1;
/* Conditionally add g,q,r to f,u,v. */
- f += g & c1;
- u += q & c1;
- v += r & c1;
+ f += g & mask1;
+ u += q & mask1;
+ v += r & mask1;
/* Shifts */
g >>= 1;
u <<= 1;
diff --git a/src/modules/bppp/Makefile.am.include b/src/modules/bppp/Makefile.am.include
new file mode 100644
index 00000000000..13e8ea03d37
--- /dev/null
+++ b/src/modules/bppp/Makefile.am.include
@@ -0,0 +1,13 @@
+include_HEADERS += include/secp256k1_bppp.h
+noinst_HEADERS += src/modules/bppp/bppp_util.h
+noinst_HEADERS += src/modules/bppp/main_impl.h
+noinst_HEADERS += src/modules/bppp/bppp_transcript_impl.h
+noinst_HEADERS += src/modules/bppp/bppp_norm_product_impl.h
+noinst_HEADERS += src/modules/bppp/tests_impl.h
+
+if USE_BENCHMARK
+noinst_PROGRAMS += bench_bppp
+bench_bppp_SOURCES = src/bench_bppp.c
+bench_bppp_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_bppp_LDFLAGS = -static
+endif
diff --git a/src/modules/bppp/bppp_norm_product_impl.h b/src/modules/bppp/bppp_norm_product_impl.h
new file mode 100644
index 00000000000..848e8cde3b9
--- /dev/null
+++ b/src/modules/bppp/bppp_norm_product_impl.h
@@ -0,0 +1,544 @@
+/**********************************************************************
+ * Copyright (c) 2020 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_BPPP_PP_NORM_PRODUCT_H
+#define SECP256K1_MODULE_BPPP_PP_NORM_PRODUCT_H
+
+#include "../../group.h"
+#include "../../scalar.h"
+#include "../../ecmult.h"
+#include "../../ecmult_gen.h"
+#include "../../hash.h"
+
+#include "../bppp/main.h"
+#include "../bppp/bppp_util.h"
+#include "../bppp/bppp_transcript_impl.h"
+
+/* Computes the inner product of two vectors of scalars
+ * with elements starting from offset a and offset b
+ * skipping elements according to specified step.
+ * Returns: Sum_{i=0..len-1}(a[offset_a + i*step] * b[offset_b + i*step]) */
+static int secp256k1_scalar_inner_product(
+ secp256k1_scalar* res,
+ const secp256k1_scalar* a_vec,
+ const size_t a_offset,
+ const secp256k1_scalar* b_vec,
+ const size_t b_offset,
+ const size_t step,
+ const size_t len
+) {
+ size_t i;
+ secp256k1_scalar_set_int(res, 0);
+ for (i = 0; i < len; i++) {
+ secp256k1_scalar term;
+ secp256k1_scalar_mul(&term, &a_vec[a_offset + step*i], &b_vec[b_offset + step*i]);
+ secp256k1_scalar_add(res, res, &term);
+ }
+ return 1;
+}
+
+/* Computes the q-weighted inner product of two vectors of scalars
+ * for elements starting from offset a and offset b respectively with the
+ * given step.
+ * Returns: Sum_{i=0..len-1}(a[offset_a + step*i] * b[offset_b2 + step*i]*mu^(i+1)) */
+static int secp256k1_weighted_scalar_inner_product(
+ secp256k1_scalar* res,
+ const secp256k1_scalar* a_vec,
+ const size_t a_offset,
+ const secp256k1_scalar* b_vec,
+ const size_t b_offset,
+ const size_t step,
+ const size_t len,
+ const secp256k1_scalar* mu
+) {
+ secp256k1_scalar mu_pow;
+ size_t i;
+ secp256k1_scalar_set_int(res, 0);
+ mu_pow = *mu;
+ for (i = 0; i < len; i++) {
+ secp256k1_scalar term;
+ secp256k1_scalar_mul(&term, &a_vec[a_offset + step*i], &b_vec[b_offset + step*i]);
+ secp256k1_scalar_mul(&term, &term, &mu_pow);
+ secp256k1_scalar_mul(&mu_pow, &mu_pow, mu);
+ secp256k1_scalar_add(res, res, &term);
+ }
+ return 1;
+}
+
+/* Compute the powers of rho as rho, rho^2, rho^4 ... rho^(2^(n-1)) */
+static void secp256k1_bppp_powers_of_rho(secp256k1_scalar *powers, const secp256k1_scalar *rho, size_t n) {
+ size_t i;
+ if (n == 0) {
+ return;
+ }
+ powers[0] = *rho;
+ for (i = 1; i < n; i++) {
+ secp256k1_scalar_sqr(&powers[i], &powers[i - 1]);
+ }
+}
+
+typedef struct ecmult_bp_commit_cb_data {
+ const secp256k1_scalar *n;
+ const secp256k1_ge *g;
+ const secp256k1_scalar *l;
+ size_t g_len;
+} ecmult_bp_commit_cb_data;
+
+static int ecmult_bp_commit_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
+ ecmult_bp_commit_cb_data *data = (ecmult_bp_commit_cb_data*) cbdata;
+ *pt = data->g[idx];
+ if (idx < data->g_len) {
+ *sc = data->n[idx];
+ } else {
+ *sc = data->l[idx - data->g_len];
+ }
+ return 1;
+}
+
+/* Create a commitment `commit` = vG + n_vec*G_vec + l_vec*H_vec where
+ v = |n_vec*n_vec|_mu + . |w|_mu denotes mu-weighted norm of w and
+ denotes inner product of l and r.
+*/
+static int secp256k1_bppp_commit(
+ const secp256k1_context* ctx,
+ secp256k1_scratch_space* scratch,
+ secp256k1_ge* commit,
+ const secp256k1_bppp_generators* g_vec,
+ const secp256k1_scalar* n_vec,
+ size_t n_vec_len,
+ const secp256k1_scalar* l_vec,
+ size_t l_vec_len,
+ const secp256k1_scalar* c_vec,
+ size_t c_vec_len,
+ const secp256k1_scalar* mu
+) {
+ secp256k1_scalar v, l_c;
+ /* First n_vec_len generators are Gs, rest are Hs*/
+ VERIFY_CHECK(g_vec->n == (n_vec_len + l_vec_len));
+ VERIFY_CHECK(l_vec_len == c_vec_len);
+
+ /* It is possible to extend to support n_vec and c_vec to not be power of
+ two. For the initial iterations of the code, we stick to powers of two for simplicity.*/
+ VERIFY_CHECK(secp256k1_is_power_of_two(n_vec_len));
+ VERIFY_CHECK(secp256k1_is_power_of_two(c_vec_len));
+
+ /* Compute v = n_vec*n_vec*mu + l_vec*c_vec */
+ secp256k1_weighted_scalar_inner_product(&v, n_vec, 0 /*a offset */, n_vec, 0 /*b offset*/, 1 /*step*/, n_vec_len, mu);
+ secp256k1_scalar_inner_product(&l_c, l_vec, 0 /*a offset */, c_vec, 0 /*b offset*/, 1 /*step*/, l_vec_len);
+ secp256k1_scalar_add(&v, &v, &l_c);
+
+ {
+ ecmult_bp_commit_cb_data data;
+ secp256k1_gej commitj;
+ data.g = g_vec->gens;
+ data.n = n_vec;
+ data.l = l_vec;
+ data.g_len = n_vec_len;
+
+ if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &commitj, &v, ecmult_bp_commit_cb, (void*) &data, n_vec_len + l_vec_len)) {
+ return 0;
+ }
+ secp256k1_ge_set_gej_var(commit, &commitj);
+ }
+ return 1;
+}
+
+typedef struct ecmult_x_cb_data {
+ const secp256k1_scalar *n;
+ const secp256k1_ge *g;
+ const secp256k1_scalar *l;
+ const secp256k1_scalar *rho;
+ const secp256k1_scalar *rho_inv;
+ size_t G_GENS_LEN; /* Figure out initialization syntax so that this can also be const */
+ size_t n_len;
+} ecmult_x_cb_data;
+
+static int ecmult_x_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
+ ecmult_x_cb_data *data = (ecmult_x_cb_data*) cbdata;
+ if (idx < data->n_len) {
+ if (idx % 2 == 0) {
+ secp256k1_scalar_mul(sc, &data->n[idx + 1], data->rho);
+ *pt = data->g[idx];
+ } else {
+ secp256k1_scalar_mul(sc, &data->n[idx - 1], data->rho_inv);
+ *pt = data->g[idx];
+ }
+ } else {
+ idx -= data->n_len;
+ if (idx % 2 == 0) {
+ *sc = data->l[idx + 1];
+ *pt = data->g[data->G_GENS_LEN + idx];
+ } else {
+ *sc = data->l[idx - 1];
+ *pt = data->g[data->G_GENS_LEN + idx];
+ }
+ }
+ return 1;
+}
+
+typedef struct ecmult_r_cb_data {
+ const secp256k1_scalar *n1;
+ const secp256k1_ge *g1;
+ const secp256k1_scalar *l1;
+ size_t G_GENS_LEN;
+ size_t n_len;
+} ecmult_r_cb_data;
+
+static int ecmult_r_cb(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
+ ecmult_r_cb_data *data = (ecmult_r_cb_data*) cbdata;
+ if (idx < data->n_len) {
+ *sc = data->n1[2*idx + 1];
+ *pt = data->g1[2*idx + 1];
+ } else {
+ idx -= data->n_len;
+ *sc = data->l1[2*idx + 1];
+ *pt = data->g1[data->G_GENS_LEN + 2*idx + 1];
+ }
+ return 1;
+}
+
+/* Recursively compute the norm argument proof satisfying the relation
+ * _mu + = v for some commitment
+ * C = v*G + + . _mu is the weighted inner
+ * product of x with itself, where the weights are the first n powers of mu.
+ * _mu = mu*x_1^2 + mu^2*x_2^2 + mu^3*x_3^2 + ... + mu^n*x_n^2.
+ * The API computes mu as square of the r challenge (`r^2`).
+ *
+ * The norm argument is not zero knowledge and does not operate on any secret data.
+ * Thus the following code uses variable time operations while computing the proof.
+ * This function also modifies the values of n_vec, l_vec, c_vec and g_vec. The caller
+ * is expected to copy these values if they need to be preserved.
+ *
+ * Assumptions: This function is intended to be used in conjunction with the
+ * some parent protocol. To use this norm protocol in a standalone manner, the user
+ * should add the commitment, generators and initial public data to the transcript hash.
+*/
+static int secp256k1_bppp_rangeproof_norm_product_prove(
+ const secp256k1_context* ctx,
+ secp256k1_scratch_space* scratch,
+ unsigned char* proof,
+ size_t *proof_len,
+ secp256k1_sha256* transcript, /* Transcript hash of the parent protocol */
+ const secp256k1_scalar* rho,
+ secp256k1_ge* g_vec,
+ size_t g_vec_len,
+ secp256k1_scalar* n_vec,
+ size_t n_vec_len,
+ secp256k1_scalar* l_vec,
+ size_t l_vec_len,
+ secp256k1_scalar* c_vec,
+ size_t c_vec_len
+) {
+ secp256k1_scalar mu_f, rho_f = *rho;
+ size_t proof_idx = 0;
+ ecmult_x_cb_data x_cb_data;
+ ecmult_r_cb_data r_cb_data;
+ size_t g_len = n_vec_len, h_len = l_vec_len;
+ const size_t G_GENS_LEN = g_len;
+ size_t log_g_len, log_h_len;
+ size_t num_rounds;
+
+ VERIFY_CHECK(g_len > 0 && h_len > 0);
+ log_g_len = secp256k1_bppp_log2(g_len);
+ log_h_len = secp256k1_bppp_log2(h_len);
+ num_rounds = log_g_len > log_h_len ? log_g_len : log_h_len;
+ /* Check proof sizes.*/
+ VERIFY_CHECK(*proof_len >= 65 * num_rounds + 64);
+ VERIFY_CHECK(g_vec_len == (n_vec_len + l_vec_len) && l_vec_len == c_vec_len);
+ VERIFY_CHECK(secp256k1_is_power_of_two(n_vec_len) && secp256k1_is_power_of_two(c_vec_len));
+
+ x_cb_data.n = n_vec;
+ x_cb_data.g = g_vec;
+ x_cb_data.l = l_vec;
+ x_cb_data.G_GENS_LEN = G_GENS_LEN;
+
+ r_cb_data.n1 = n_vec;
+ r_cb_data.g1 = g_vec;
+ r_cb_data.l1 = l_vec;
+ r_cb_data.G_GENS_LEN = G_GENS_LEN;
+ secp256k1_scalar_sqr(&mu_f, &rho_f);
+
+
+ while (g_len > 1 || h_len > 1) {
+ size_t i, num_points;
+ secp256k1_scalar mu_sq, rho_inv, c0_l1, c1_l0, x_v, c1_l1, r_v;
+ secp256k1_gej rj, xj;
+ secp256k1_ge r_ge, x_ge;
+ secp256k1_scalar gamma;
+
+ secp256k1_scalar_inverse_var(&rho_inv, &rho_f);
+ secp256k1_scalar_sqr(&mu_sq, &mu_f);
+
+ /* Compute the X commitment X = WIP(rho_inv*n0,n1)_mu2 * g + r + */
+ secp256k1_scalar_inner_product(&c0_l1, c_vec, 0, l_vec, 1, 2, h_len/2);
+ secp256k1_scalar_inner_product(&c1_l0, c_vec, 1, l_vec, 0, 2, h_len/2);
+ secp256k1_weighted_scalar_inner_product(&x_v, n_vec, 0, n_vec, 1, 2, g_len/2, &mu_sq);
+ secp256k1_scalar_mul(&x_v, &x_v, &rho_inv);
+ secp256k1_scalar_add(&x_v, &x_v, &x_v);
+ secp256k1_scalar_add(&x_v, &x_v, &c0_l1);
+ secp256k1_scalar_add(&x_v, &x_v, &c1_l0);
+
+ x_cb_data.rho = &rho_f;
+ x_cb_data.rho_inv = &rho_inv;
+ x_cb_data.n_len = g_len >= 2 ? g_len : 0;
+ num_points = x_cb_data.n_len + (h_len >= 2 ? h_len : 0);
+
+ if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &xj, &x_v, ecmult_x_cb, (void*)&x_cb_data, num_points)) {
+ return 0;
+ }
+
+ secp256k1_weighted_scalar_inner_product(&r_v, n_vec, 1, n_vec, 1, 2, g_len/2, &mu_sq);
+ secp256k1_scalar_inner_product(&c1_l1, c_vec, 1, l_vec, 1, 2, h_len/2);
+ secp256k1_scalar_add(&r_v, &r_v, &c1_l1);
+
+ r_cb_data.n_len = g_len/2;
+ num_points = r_cb_data.n_len + h_len/2;
+ if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &rj, &r_v, ecmult_r_cb, (void*)&r_cb_data, num_points)) {
+ return 0;
+ }
+
+ secp256k1_ge_set_gej_var(&x_ge, &xj);
+ secp256k1_ge_set_gej_var(&r_ge, &rj);
+ secp256k1_bppp_serialize_points(&proof[proof_idx], &x_ge, &r_ge);
+ proof_idx += 65;
+
+ /* Obtain challenge gamma for the the next round */
+ secp256k1_sha256_write(transcript, &proof[proof_idx - 65], 65);
+ secp256k1_bppp_challenge_scalar(&gamma, transcript, 0);
+
+ if (g_len > 1) {
+ for (i = 0; i < g_len; i = i + 2) {
+ secp256k1_scalar nl, nr;
+ secp256k1_gej gl, gr;
+ secp256k1_scalar_mul(&nl, &n_vec[i], &rho_inv);
+ secp256k1_scalar_mul(&nr, &n_vec[i + 1], &gamma);
+ secp256k1_scalar_add(&n_vec[i/2], &nl, &nr);
+
+ secp256k1_gej_set_ge(&gl, &g_vec[i]);
+ secp256k1_ecmult(&gl, &gl, &rho_f, NULL);
+ secp256k1_gej_set_ge(&gr, &g_vec[i + 1]);
+ secp256k1_ecmult(&gr, &gr, &gamma, NULL);
+ secp256k1_gej_add_var(&gl, &gl, &gr, NULL);
+ secp256k1_ge_set_gej_var(&g_vec[i/2], &gl);
+ }
+ }
+
+ if (h_len > 1) {
+ for (i = 0; i < h_len; i = i + 2) {
+ secp256k1_scalar temp1;
+ secp256k1_gej grj;
+ secp256k1_scalar_mul(&temp1, &c_vec[i + 1], &gamma);
+ secp256k1_scalar_add(&c_vec[i/2], &c_vec[i], &temp1);
+
+ secp256k1_scalar_mul(&temp1, &l_vec[i + 1], &gamma);
+ secp256k1_scalar_add(&l_vec[i/2], &l_vec[i], &temp1);
+
+ secp256k1_gej_set_ge(&grj, &g_vec[G_GENS_LEN + i + 1]);
+ secp256k1_ecmult(&grj, &grj, &gamma, NULL);
+ secp256k1_gej_add_ge_var(&grj, &grj, &g_vec[G_GENS_LEN + i], NULL);
+ secp256k1_ge_set_gej_var(&g_vec[G_GENS_LEN + i/2], &grj);
+ }
+ }
+ g_len = g_len / 2;
+ h_len = h_len / 2;
+ rho_f = mu_f;
+ mu_f = mu_sq;
+ }
+
+ secp256k1_scalar_get_b32(&proof[proof_idx], &n_vec[0]);
+ secp256k1_scalar_get_b32(&proof[proof_idx + 32], &l_vec[0]);
+ proof_idx += 64;
+ *proof_len = proof_idx;
+ return 1;
+}
+
+typedef struct ec_mult_verify_cb_data1 {
+ const unsigned char *proof;
+ const secp256k1_ge *commit;
+ const secp256k1_scalar *gammas;
+} ec_mult_verify_cb_data1;
+
+static int ec_mult_verify_cb1(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
+ ec_mult_verify_cb_data1 *data = (ec_mult_verify_cb_data1*) cbdata;
+ if (idx == 0) {
+ *pt = *data->commit;
+ secp256k1_scalar_set_int(sc, 1);
+ return 1;
+ }
+ idx -= 1;
+ if (idx % 2 == 0) {
+ idx /= 2;
+ *sc = data->gammas[idx];
+ if (!secp256k1_bppp_parse_one_of_points(pt, &data->proof[65*idx], 0)) {
+ return 0;
+ }
+ } else {
+ secp256k1_scalar neg_one;
+ idx /= 2;
+ secp256k1_scalar_set_int(&neg_one, 1);
+ secp256k1_scalar_negate(&neg_one, &neg_one);
+ *sc = data->gammas[idx];
+ secp256k1_scalar_sqr(sc, sc);
+ secp256k1_scalar_add(sc, sc, &neg_one);
+ if (!secp256k1_bppp_parse_one_of_points(pt, &data->proof[65*idx], 1)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+typedef struct ec_mult_verify_cb_data2 {
+ const secp256k1_scalar *s_g;
+ const secp256k1_scalar *s_h;
+ const secp256k1_ge *g_vec;
+ size_t g_vec_len;
+} ec_mult_verify_cb_data2;
+
+static int ec_mult_verify_cb2(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
+ ec_mult_verify_cb_data2 *data = (ec_mult_verify_cb_data2*) cbdata;
+ if (idx < data->g_vec_len) {
+ *sc = data->s_g[idx];
+ } else {
+ *sc = data->s_h[idx - data->g_vec_len];
+ }
+ *pt = data->g_vec[idx];
+ return 1;
+}
+
+/* Verify the proof. This function modifies the generators, c_vec and the challenge r. The
+ caller should make sure to back them up if they need to be reused.
+*/
+static int secp256k1_bppp_rangeproof_norm_product_verify(
+ const secp256k1_context* ctx,
+ secp256k1_scratch_space* scratch,
+ const unsigned char* proof,
+ size_t proof_len,
+ secp256k1_sha256* transcript,
+ const secp256k1_scalar* rho,
+ const secp256k1_bppp_generators* g_vec,
+ size_t g_len,
+ const secp256k1_scalar* c_vec,
+ size_t c_vec_len,
+ const secp256k1_ge* commit
+) {
+ secp256k1_scalar rho_f, mu_f, v, n, l, rho_inv, h_c;
+ secp256k1_scalar *gammas, *s_g, *s_h, *rho_inv_pows;
+ secp256k1_gej res1, res2;
+ size_t i = 0, scratch_checkpoint;
+ int overflow;
+ size_t log_g_len, log_h_len;
+ size_t n_rounds;
+ size_t h_len = c_vec_len;
+
+ if (g_len == 0 || c_vec_len == 0) {
+ return 0;
+ }
+ log_g_len = secp256k1_bppp_log2(g_len);
+ log_h_len = secp256k1_bppp_log2(c_vec_len);
+ n_rounds = log_g_len > log_h_len ? log_g_len : log_h_len;
+
+ if (g_vec->n != (h_len + g_len) || (proof_len != 65 * n_rounds + 64)) {
+ return 0;
+ }
+
+ if (!secp256k1_is_power_of_two(g_len) || !secp256k1_is_power_of_two(h_len)) {
+ return 0;
+ }
+
+ secp256k1_scalar_set_b32(&n, &proof[n_rounds*65], &overflow); /* n */
+ if (overflow) return 0;
+ secp256k1_scalar_set_b32(&l, &proof[n_rounds*65 + 32], &overflow); /* l */
+ if (overflow) return 0;
+ if (secp256k1_scalar_is_zero(rho)) return 0;
+
+ /* Collect the gammas in a new vector */
+ scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
+ gammas = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, n_rounds * sizeof(secp256k1_scalar));
+ s_g = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(secp256k1_scalar));
+ s_h = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar));
+ rho_inv_pows = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, log_g_len * sizeof(secp256k1_scalar));
+ if (gammas == NULL || s_g == NULL || s_h == NULL || rho_inv_pows == NULL) {
+ secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
+ return 0;
+ }
+
+ /* Compute powers of rho_inv. Later used in g_factor computations*/
+ secp256k1_scalar_inverse_var(&rho_inv, rho);
+ secp256k1_bppp_powers_of_rho(rho_inv_pows, &rho_inv, log_g_len);
+
+ /* Compute rho_f = rho^(2^log_g_len) */
+ rho_f = *rho;
+ for (i = 0; i < log_g_len; i++) {
+ secp256k1_scalar_sqr(&rho_f, &rho_f);
+ }
+
+ for (i = 0; i < n_rounds; i++) {
+ secp256k1_scalar gamma;
+ secp256k1_sha256_write(transcript, &proof[i * 65], 65);
+ secp256k1_bppp_challenge_scalar(&gamma, transcript, 0);
+ gammas[i] = gamma;
+ }
+ /* s_g[0] = n * \prod_{j=0}^{log_g_len - 1} rho^(2^j)
+ * = n * rho^(2^log_g_len - 1)
+ * = n * rho_f * rho_inv */
+ secp256k1_scalar_mul(&s_g[0], &n, &rho_f);
+ secp256k1_scalar_mul(&s_g[0], &s_g[0], &rho_inv);
+ for (i = 1; i < g_len; i++) {
+ size_t log_i = secp256k1_bppp_log2(i);
+ size_t nearest_pow_of_two = (size_t)1 << log_i;
+ /* This combines the two multiplications of gammas and rho_invs in a
+ * single loop.
+ * s_g[i] = s_g[i - nearest_pow_of_two]
+ * * e[log_i] * rho_inv^(2^log_i) */
+ secp256k1_scalar_mul(&s_g[i], &s_g[i - nearest_pow_of_two], &gammas[log_i]);
+ secp256k1_scalar_mul(&s_g[i], &s_g[i], &rho_inv_pows[log_i]);
+ }
+ s_h[0] = l;
+ secp256k1_scalar_set_int(&h_c, 0);
+ for (i = 1; i < h_len; i++) {
+ size_t log_i = secp256k1_bppp_log2(i);
+ size_t nearest_pow_of_two = (size_t)1 << log_i;
+ secp256k1_scalar_mul(&s_h[i], &s_h[i - nearest_pow_of_two], &gammas[log_i]);
+ }
+ secp256k1_scalar_inner_product(&h_c, c_vec, 0 /* a_offset */ , s_h, 0 /* b_offset */, 1 /* step */, h_len);
+ /* Compute v = n*n*mu_f + l*h_c where mu_f = rho_f^2 */
+ secp256k1_scalar_sqr(&mu_f, &rho_f);
+ secp256k1_scalar_mul(&v, &n, &n);
+ secp256k1_scalar_mul(&v, &v, &mu_f);
+ secp256k1_scalar_add(&v, &v, &h_c);
+
+ {
+ ec_mult_verify_cb_data1 data;
+ data.proof = proof;
+ data.commit = commit;
+ data.gammas = gammas;
+
+ if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &res1, NULL, ec_mult_verify_cb1, &data, 2*n_rounds + 1)) {
+ secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
+ return 0;
+ }
+ }
+ {
+ ec_mult_verify_cb_data2 data;
+ data.g_vec = g_vec->gens;
+ data.g_vec_len = g_len;
+ data.s_g = s_g;
+ data.s_h = s_h;
+
+ if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &res2, &v, ec_mult_verify_cb2, &data, g_len + h_len)) {
+ secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
+ return 0;
+ }
+ }
+
+ secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
+
+ /* res1 and res2 should be equal. Could not find a simpler way to compare them */
+ secp256k1_gej_neg(&res1, &res1);
+ secp256k1_gej_add_var(&res1, &res1, &res2, NULL);
+ return secp256k1_gej_is_infinity(&res1);
+}
+#endif
diff --git a/src/modules/bppp/bppp_transcript_impl.h b/src/modules/bppp/bppp_transcript_impl.h
new file mode 100644
index 00000000000..5fe9b96c947
--- /dev/null
+++ b/src/modules/bppp/bppp_transcript_impl.h
@@ -0,0 +1,40 @@
+/**********************************************************************
+ * Copyright (c) 2022 Sanket Kanjalkar *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+#ifndef SECP256K1_MODULE_BPPP_PP_TRANSCRIPT_IMPL_H
+#define SECP256K1_MODULE_BPPP_PP_TRANSCRIPT_IMPL_H
+
+#include "../../group.h"
+#include "../../scalar.h"
+#include "bppp_util.h"
+
+/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
+ * SHA256 to SHA256("Bulletproofs_pp/v0/commitment")||SHA256("Bulletproofs_pp/v0/commitment").
+ */
+static void secp256k1_bppp_sha256_tagged_commitment_init(secp256k1_sha256 *sha) {
+ secp256k1_sha256_initialize(sha);
+ sha->s[0] = 0x52fc8185ul;
+ sha->s[1] = 0x0e7debf0ul;
+ sha->s[2] = 0xb0967270ul;
+ sha->s[3] = 0x6f5abfe1ul;
+ sha->s[4] = 0x822bdec0ul;
+ sha->s[5] = 0x36db8beful;
+ sha->s[6] = 0x03d9e1f1ul;
+ sha->s[7] = 0x8a5cef6ful;
+
+ sha->bytes = 64;
+}
+
+/* Obtain a challenge scalar from the current transcript.*/
+static void secp256k1_bppp_challenge_scalar(secp256k1_scalar* ch, const secp256k1_sha256 *transcript, uint64_t idx) {
+ unsigned char buf[32];
+ secp256k1_sha256 sha = *transcript;
+ secp256k1_bppp_le64(buf, idx);
+ secp256k1_sha256_write(&sha, buf, 8);
+ secp256k1_sha256_finalize(&sha, buf);
+ secp256k1_scalar_set_b32(ch, buf, NULL);
+}
+
+#endif
diff --git a/src/modules/bppp/bppp_util.h b/src/modules/bppp/bppp_util.h
new file mode 100644
index 00000000000..1debfb92ca3
--- /dev/null
+++ b/src/modules/bppp/bppp_util.h
@@ -0,0 +1,80 @@
+/**********************************************************************
+ * Copyright (c) 2020 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_BPPP_UTIL_H
+#define SECP256K1_MODULE_BPPP_UTIL_H
+
+#include "../../field.h"
+#include "../../group.h"
+#include "../../hash.h"
+#include "../../eckey.h"
+
+/* Outputs a pair of points, amortizing the parity byte between them
+ * Assumes both points' coordinates have been normalized.
+ */
+static void secp256k1_bppp_serialize_points(unsigned char *output, secp256k1_ge *lpt, secp256k1_ge *rpt) {
+ unsigned char tmp[33];
+ secp256k1_ge_serialize_ext(tmp, lpt);
+ output[0] = (tmp[0] & 1) << 1;
+ memcpy(&output[1], &tmp[1], 32);
+ secp256k1_ge_serialize_ext(tmp, rpt);
+ output[0] |= (tmp[0] & 1);
+ memcpy(&output[33], &tmp[1], 32);
+}
+
+static int secp256k1_bppp_parse_one_of_points(secp256k1_ge *pt, const unsigned char *in65, int idx) {
+ unsigned char tmp[33] = { 0 };
+ if (in65[0] > 3) {
+ return 0;
+ }
+ /* Check if the input array encodes the point at infinity */
+ if ((secp256k1_memcmp_var(tmp, &in65[1 + 32*idx], 32)) != 0) {
+ tmp[0] = 2 | ((in65[0] & (2 - idx)) >> (1 - idx));
+ memcpy(&tmp[1], &in65[1 + 32*idx], 32);
+ } else {
+ /* If we're parsing the point at infinity, enforce that the sign bit is
+ * 0. */
+ if ((in65[0] & (2 - idx)) != 0) {
+ return 0;
+ }
+ }
+ return secp256k1_ge_parse_ext(pt, tmp);
+}
+
+/* Outputs a serialized point in compressed form. Returns 0 at point at infinity.
+*/
+static int secp256k1_bppp_serialize_pt(unsigned char *output, secp256k1_ge *lpt) {
+ size_t size;
+ return secp256k1_eckey_pubkey_serialize(lpt, output, &size, 1 /*compressed*/);
+}
+
+/* little-endian encodes a uint64 */
+static void secp256k1_bppp_le64(unsigned char *output, const uint64_t n) {
+ output[0] = n;
+ output[1] = n >> 8;
+ output[2] = n >> 16;
+ output[3] = n >> 24;
+ output[4] = n >> 32;
+ output[5] = n >> 40;
+ output[6] = n >> 48;
+ output[7] = n >> 56;
+}
+
+/* Check if n is power of two*/
+static int secp256k1_is_power_of_two(size_t n) {
+ return n > 0 && (n & (n - 1)) == 0;
+}
+
+/* Compute the log2 of n. n must NOT be 0. If n is not a power of two, it
+ * returns the largest `k` such that 2^k <= n. Assumes 0 < n < 2^64. In
+ * Bulletproofs, this is bounded by len of input vectors which can be safely
+ * assumed to be less than 2^64.
+*/
+static size_t secp256k1_bppp_log2(size_t n) {
+ return 64 - 1 - secp256k1_clz64_var((uint64_t)n);
+}
+
+#endif
diff --git a/src/modules/bppp/main.h b/src/modules/bppp/main.h
new file mode 100644
index 00000000000..47405f45814
--- /dev/null
+++ b/src/modules/bppp/main.h
@@ -0,0 +1,13 @@
+#ifndef SECP256K1_MODULE_BPPP_MAIN_H
+#define SECP256K1_MODULE_BPPP_MAIN_H
+
+/* this type must be completed before any of the modules/bppp includes */
+struct secp256k1_bppp_generators {
+ size_t n;
+ /* n total generators; includes both G_i and H_i */
+ /* For BP++, the generators are G_i from [0..(n - 8)] and the last 8 values
+ are generators are for H_i */
+ secp256k1_ge* gens;
+};
+
+#endif
diff --git a/src/modules/bppp/main_impl.h b/src/modules/bppp/main_impl.h
new file mode 100644
index 00000000000..49a09447dea
--- /dev/null
+++ b/src/modules/bppp/main_impl.h
@@ -0,0 +1,115 @@
+/**********************************************************************
+ * Copyright (c) 2020 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_BPPP_MAIN_IMPL_H
+#define SECP256K1_MODULE_BPPP_MAIN_IMPL_H
+
+#include "../../../include/secp256k1_bppp.h"
+#include "../../../include/secp256k1_generator.h"
+#include "../generator/main_impl.h" /* for generator_{load, save} */
+#include "../../hash.h"
+#include "../../util.h"
+#include "../bppp/main.h"
+#include "../bppp/bppp_norm_product_impl.h"
+
+secp256k1_bppp_generators *secp256k1_bppp_generators_create(const secp256k1_context *ctx, size_t n) {
+ secp256k1_bppp_generators *ret;
+ secp256k1_rfc6979_hmac_sha256 rng;
+ unsigned char seed[64];
+ size_t i;
+
+ VERIFY_CHECK(ctx != NULL);
+
+ ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret));
+ if (ret == NULL) {
+ return NULL;
+ }
+ ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
+ if (ret->gens == NULL) {
+ free(ret);
+ return NULL;
+ }
+ ret->n = n;
+
+ secp256k1_fe_get_b32(&seed[0], &secp256k1_ge_const_g.x);
+ secp256k1_fe_get_b32(&seed[32], &secp256k1_ge_const_g.y);
+
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed, 64);
+ for (i = 0; i < n; i++) {
+ secp256k1_generator gen;
+ unsigned char tmp[32] = { 0 };
+ secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32);
+ CHECK(secp256k1_generator_generate(ctx, &gen, tmp));
+ secp256k1_generator_load(&ret->gens[i], &gen);
+ }
+
+ return ret;
+}
+
+secp256k1_bppp_generators* secp256k1_bppp_generators_parse(const secp256k1_context* ctx, const unsigned char* data, size_t data_len) {
+ size_t n = data_len / 33;
+ secp256k1_bppp_generators* ret;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(data != NULL);
+
+ if (data_len % 33 != 0) {
+ return NULL;
+ }
+
+ ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret));
+ if (ret == NULL) {
+ return NULL;
+ }
+ ret->n = n;
+ ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
+ if (ret->gens == NULL) {
+ free(ret);
+ return NULL;
+ }
+
+ while (n--) {
+ secp256k1_generator gen;
+ if (!secp256k1_generator_parse(ctx, &gen, &data[33 * n])) {
+ free(ret->gens);
+ free(ret);
+ return NULL;
+ }
+ secp256k1_generator_load(&ret->gens[n], &gen);
+ }
+ return ret;
+}
+
+int secp256k1_bppp_generators_serialize(const secp256k1_context* ctx, const secp256k1_bppp_generators* gens, unsigned char* data, size_t *data_len) {
+ size_t i;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(gens != NULL);
+ ARG_CHECK(data != NULL);
+ ARG_CHECK(data_len != NULL);
+ ARG_CHECK(*data_len >= 33 * gens->n);
+
+ memset(data, 0, *data_len);
+ for (i = 0; i < gens->n; i++) {
+ secp256k1_generator gen;
+ secp256k1_generator_save(&gen, &gens->gens[i]);
+ secp256k1_generator_serialize(ctx, &data[33 * i], &gen);
+ }
+
+ *data_len = 33 * gens->n;
+ return 1;
+}
+
+void secp256k1_bppp_generators_destroy(const secp256k1_context* ctx, secp256k1_bppp_generators *gens) {
+ VERIFY_CHECK(ctx != NULL);
+ (void) ctx;
+ if (gens != NULL) {
+ free(gens->gens);
+ free(gens);
+ }
+}
+
+#endif
diff --git a/src/modules/bppp/test_vectors/prove.h b/src/modules/bppp/test_vectors/prove.h
new file mode 100644
index 00000000000..06559b38d18
--- /dev/null
+++ b/src/modules/bppp/test_vectors/prove.h
@@ -0,0 +1,47 @@
+static const unsigned char prove_vector_gens[264] = { 0x03, 0xAF, 0x2C, 0x40, 0xAD, 0x03, 0xCD, 0xC5, 0x76, 0x8C, 0x07, 0x1E, 0x58, 0xD6, 0x8C, 0x73, 0x45, 0xBA, 0xEB, 0xB5, 0x3F, 0x40, 0xFA, 0x8B, 0xBF, 0x73, 0x6E, 0x7B, 0x4A, 0x54, 0x06, 0xED, 0x32, 0x03, 0xCC, 0x11, 0x19, 0x22, 0x2C, 0xA1, 0x0A, 0x45, 0x23, 0xAF, 0x9B, 0x40, 0x0D, 0xA4, 0x5E, 0x06, 0x24, 0xF4, 0x5F, 0x07, 0x89, 0x88, 0xCD, 0x71, 0xAE, 0x77, 0xC1, 0xF5, 0x87, 0x4E, 0xFC, 0xA5, 0x03, 0xDE, 0x61, 0xB1, 0x8F, 0x2C, 0xAC, 0x18, 0xF5, 0xE4, 0x06, 0x8F, 0x65, 0x55, 0xA1, 0x30, 0x5E, 0xF5, 0xF4, 0x84, 0xED, 0x6B, 0xDD, 0xC2, 0xCC, 0xE8, 0x51, 0x38, 0xB8, 0xA5, 0x4C, 0x43, 0xBD, 0x02, 0xA5, 0xF9, 0x8C, 0x1F, 0x82, 0x2D, 0xC6, 0xF3, 0x0F, 0x53, 0xDB, 0x74, 0x77, 0xC7, 0x91, 0x04, 0xB0, 0xB1, 0xA6, 0x17, 0xB2, 0x91, 0xF4, 0x8B, 0x93, 0x3E, 0xBB, 0x73, 0x15, 0x3E, 0x5A, 0xD1, 0x02, 0x44, 0xF5, 0xC6, 0x4E, 0x77, 0x60, 0x81, 0x83, 0xFF, 0xC2, 0x8E, 0x06, 0xFE, 0x67, 0x0C, 0x9A, 0x4B, 0xF2, 0x34, 0xB9, 0xEA, 0xE9, 0x37, 0xDA, 0x30, 0xE2, 0x32, 0x27, 0xF3, 0x88, 0x5F, 0x2A, 0x02, 0x1D, 0x49, 0x5D, 0x04, 0xED, 0x61, 0x95, 0x37, 0xDD, 0x95, 0xB1, 0x4F, 0x64, 0x0E, 0x1E, 0xFB, 0x47, 0x9F, 0xA7, 0xD7, 0xE0, 0x7A, 0xB1, 0x02, 0x81, 0x95, 0xD1, 0xA5, 0x7E, 0xB2, 0x74, 0x8F, 0x03, 0x26, 0xA5, 0xEC, 0xE9, 0x71, 0x46, 0x37, 0xAC, 0x3D, 0x74, 0x84, 0x26, 0xCB, 0x7C, 0xE8, 0xFE, 0x4E, 0xB0, 0x6D, 0x70, 0x3D, 0x00, 0x10, 0x1A, 0x3A, 0x5B, 0xB8, 0xAA, 0x29, 0x59, 0x93, 0x15, 0x03, 0xE1, 0xA5, 0x39, 0x44, 0x75, 0x16, 0x28, 0x5F, 0xBA, 0x69, 0xA2, 0x4A, 0x2A, 0xC3, 0x5B, 0x63, 0x1F, 0x40, 0x10, 0x36, 0xF9, 0x4C, 0xD2, 0x76, 0x0F, 0xCF, 0x7F, 0x50, 0x30, 0x6E, 0x2B, 0x1D };
+static const unsigned char prove_vector_0_n_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F } };
+static secp256k1_scalar prove_vector_0_n_vec[1];
+static const unsigned char prove_vector_0_l_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E } };
+static secp256k1_scalar prove_vector_0_l_vec[1];
+static const unsigned char prove_vector_0_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar prove_vector_0_c_vec[1];
+static const unsigned char prove_vector_0_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const unsigned char prove_vector_0_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E };
+static const int prove_vector_0_result = 1;
+static const unsigned char prove_vector_1_n_vec32[2][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F }, { 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, 0x01 } };
+static secp256k1_scalar prove_vector_1_n_vec[2];
+static const unsigned char prove_vector_1_l_vec32[4][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E }, { 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 }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 }, { 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, 0x0B } };
+static secp256k1_scalar prove_vector_1_l_vec[4];
+static const unsigned char prove_vector_1_c_vec32[4][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C }, { 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, 0x03 }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x30 }, { 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, 0x0D } };
+static secp256k1_scalar prove_vector_1_c_vec[4];
+static const unsigned char prove_vector_1_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const unsigned char prove_vector_1_proof[] = { 0x00, 0xD2, 0xEC, 0xE2, 0x53, 0x97, 0x28, 0x68, 0x22, 0x59, 0x34, 0xEF, 0xE4, 0x7B, 0x87, 0x4D, 0xE9, 0x57, 0xD5, 0xB7, 0xC7, 0x72, 0xF4, 0xC9, 0xEA, 0x66, 0x14, 0x59, 0xE1, 0xA9, 0xD5, 0xB2, 0x10, 0xDF, 0xE2, 0xFF, 0xF5, 0xA4, 0x38, 0x6B, 0xFE, 0x36, 0x89, 0xE4, 0x9D, 0x90, 0x9F, 0x71, 0x19, 0xE6, 0xA3, 0x1E, 0xAA, 0xAA, 0x4E, 0xFE, 0xC2, 0xD3, 0x37, 0xBB, 0xDE, 0xDB, 0x46, 0x43, 0xC2, 0x01, 0x42, 0x5F, 0xFC, 0xC6, 0x25, 0xA0, 0xB4, 0xF0, 0x76, 0x99, 0xF4, 0x7C, 0xE9, 0x83, 0x82, 0xED, 0x7C, 0x95, 0xBA, 0xD0, 0xE6, 0x5B, 0x88, 0xFD, 0x38, 0xEA, 0x23, 0x54, 0xD4, 0xBD, 0xD4, 0x37, 0xB8, 0x2B, 0x49, 0xAF, 0x81, 0xFD, 0xBE, 0x88, 0xB2, 0xE5, 0x3F, 0xF4, 0x30, 0x52, 0x00, 0x63, 0x9D, 0xAE, 0x82, 0x44, 0xE9, 0x62, 0x87, 0x2A, 0x23, 0x89, 0x10, 0xE4, 0x9A, 0x64, 0x9F, 0x71, 0xD9, 0x32, 0x57, 0x3B, 0xCB, 0xAC, 0x30, 0xAE, 0x71, 0x61, 0xE9, 0x50, 0x1F, 0xCB, 0x49, 0x9C, 0x52, 0xBA, 0x0C, 0xC4, 0x00, 0x58, 0x73, 0x63, 0xD3, 0x42, 0xDE, 0x42, 0x5E, 0xC5, 0x97, 0xE5, 0xDA, 0x88, 0x76, 0x49, 0x6C, 0x8B, 0x92, 0x99, 0xEE, 0xD0, 0xA9, 0xEB, 0x6E, 0xCA, 0xE1, 0x93, 0x81, 0x56, 0x2E, 0xCA, 0xF3, 0x8E, 0xF0, 0x04, 0xD2, 0x96, 0xD8, 0xDB, 0xEE, 0xEE, 0x1C, 0x44 };
+static const int prove_vector_1_result = 1;
+static const unsigned char prove_vector_2_n_vec32[4][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F }, { 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, 0x01 }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 }, { 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, 0x0B } };
+static secp256k1_scalar prove_vector_2_n_vec[4];
+static const unsigned char prove_vector_2_l_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E } };
+static secp256k1_scalar prove_vector_2_l_vec[1];
+static const unsigned char prove_vector_2_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar prove_vector_2_c_vec[1];
+static const unsigned char prove_vector_2_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 };
+static const unsigned char prove_vector_2_proof[] = { 0x00, 0xBC, 0x4C, 0x42, 0x67, 0x71, 0x69, 0x52, 0x6A, 0x65, 0xFE, 0xA0, 0xCB, 0x3F, 0x58, 0x8B, 0x48, 0x48, 0x6E, 0x59, 0xFC, 0x55, 0x51, 0x10, 0xB9, 0xBF, 0x6A, 0x7D, 0xBF, 0x32, 0x34, 0x4E, 0x7D, 0xBA, 0xD5, 0xCB, 0xCC, 0x19, 0xED, 0xAA, 0x9F, 0x8D, 0x93, 0x26, 0x5E, 0x3F, 0x3E, 0xAA, 0xDF, 0x0B, 0x1C, 0xB3, 0xDC, 0x37, 0xB6, 0xDB, 0xAE, 0x43, 0x63, 0x92, 0xB5, 0xFF, 0x0D, 0x1C, 0x77, 0x02, 0x7E, 0x2B, 0xB8, 0x87, 0x85, 0x81, 0x13, 0x70, 0x1F, 0x03, 0x65, 0x7D, 0xD8, 0x91, 0x83, 0xE5, 0x7E, 0x8B, 0x9E, 0x6F, 0x1C, 0x08, 0x9C, 0x9C, 0x5F, 0xA4, 0x12, 0x5F, 0xD3, 0xEE, 0xE2, 0x74, 0x7A, 0x2C, 0x58, 0x3A, 0x29, 0x4F, 0x64, 0x10, 0xE7, 0x89, 0xBF, 0xB2, 0xE5, 0xD9, 0xD5, 0xC5, 0x62, 0x83, 0x0C, 0xA8, 0xDD, 0x1E, 0x24, 0x6D, 0xD1, 0x58, 0x8D, 0x80, 0x74, 0xF3, 0xD9, 0x3A, 0x68, 0x7B, 0xF5, 0x12, 0xC6, 0xC2, 0x3F, 0x71, 0x47, 0xDF, 0xCF, 0xC8, 0xE2, 0xC4, 0x59, 0xDF, 0x4F, 0xEC, 0x86, 0xE9, 0xF9, 0x31, 0x94, 0x6A, 0x5F, 0xD9, 0x1E, 0x6B, 0x09, 0xCD, 0xCF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E };
+static const int prove_vector_2_result = 1;
+static const unsigned char prove_vector_3_n_vec32[1][32] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
+static secp256k1_scalar prove_vector_3_n_vec[1];
+static const unsigned char prove_vector_3_l_vec32[1][32] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
+static secp256k1_scalar prove_vector_3_l_vec[1];
+static const unsigned char prove_vector_3_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar prove_vector_3_c_vec[1];
+static const unsigned char prove_vector_3_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 };
+static const unsigned char prove_vector_3_proof[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const int prove_vector_3_result = 1;
+static const unsigned char prove_vector_4_n_vec32[2][32] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
+static secp256k1_scalar prove_vector_4_n_vec[2];
+static const unsigned char prove_vector_4_l_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A } };
+static secp256k1_scalar prove_vector_4_l_vec[1];
+static const unsigned char prove_vector_4_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar prove_vector_4_c_vec[1];
+static const unsigned char prove_vector_4_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 };
+static const unsigned char prove_vector_4_proof[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const int prove_vector_4_result = 1;
+
diff --git a/src/modules/bppp/test_vectors/verify.h b/src/modules/bppp/test_vectors/verify.h
new file mode 100644
index 00000000000..9ab43fd0b09
--- /dev/null
+++ b/src/modules/bppp/test_vectors/verify.h
@@ -0,0 +1,93 @@
+static const unsigned char verify_vector_gens[264] = { 0x03, 0xAF, 0x2C, 0x40, 0xAD, 0x03, 0xCD, 0xC5, 0x76, 0x8C, 0x07, 0x1E, 0x58, 0xD6, 0x8C, 0x73, 0x45, 0xBA, 0xEB, 0xB5, 0x3F, 0x40, 0xFA, 0x8B, 0xBF, 0x73, 0x6E, 0x7B, 0x4A, 0x54, 0x06, 0xED, 0x32, 0x03, 0xCC, 0x11, 0x19, 0x22, 0x2C, 0xA1, 0x0A, 0x45, 0x23, 0xAF, 0x9B, 0x40, 0x0D, 0xA4, 0x5E, 0x06, 0x24, 0xF4, 0x5F, 0x07, 0x89, 0x88, 0xCD, 0x71, 0xAE, 0x77, 0xC1, 0xF5, 0x87, 0x4E, 0xFC, 0xA5, 0x03, 0xDE, 0x61, 0xB1, 0x8F, 0x2C, 0xAC, 0x18, 0xF5, 0xE4, 0x06, 0x8F, 0x65, 0x55, 0xA1, 0x30, 0x5E, 0xF5, 0xF4, 0x84, 0xED, 0x6B, 0xDD, 0xC2, 0xCC, 0xE8, 0x51, 0x38, 0xB8, 0xA5, 0x4C, 0x43, 0xBD, 0x02, 0xA5, 0xF9, 0x8C, 0x1F, 0x82, 0x2D, 0xC6, 0xF3, 0x0F, 0x53, 0xDB, 0x74, 0x77, 0xC7, 0x91, 0x04, 0xB0, 0xB1, 0xA6, 0x17, 0xB2, 0x91, 0xF4, 0x8B, 0x93, 0x3E, 0xBB, 0x73, 0x15, 0x3E, 0x5A, 0xD1, 0x02, 0x44, 0xF5, 0xC6, 0x4E, 0x77, 0x60, 0x81, 0x83, 0xFF, 0xC2, 0x8E, 0x06, 0xFE, 0x67, 0x0C, 0x9A, 0x4B, 0xF2, 0x34, 0xB9, 0xEA, 0xE9, 0x37, 0xDA, 0x30, 0xE2, 0x32, 0x27, 0xF3, 0x88, 0x5F, 0x2A, 0x02, 0x1D, 0x49, 0x5D, 0x04, 0xED, 0x61, 0x95, 0x37, 0xDD, 0x95, 0xB1, 0x4F, 0x64, 0x0E, 0x1E, 0xFB, 0x47, 0x9F, 0xA7, 0xD7, 0xE0, 0x7A, 0xB1, 0x02, 0x81, 0x95, 0xD1, 0xA5, 0x7E, 0xB2, 0x74, 0x8F, 0x03, 0x26, 0xA5, 0xEC, 0xE9, 0x71, 0x46, 0x37, 0xAC, 0x3D, 0x74, 0x84, 0x26, 0xCB, 0x7C, 0xE8, 0xFE, 0x4E, 0xB0, 0x6D, 0x70, 0x3D, 0x00, 0x10, 0x1A, 0x3A, 0x5B, 0xB8, 0xAA, 0x29, 0x59, 0x93, 0x15, 0x03, 0xE1, 0xA5, 0x39, 0x44, 0x75, 0x16, 0x28, 0x5F, 0xBA, 0x69, 0xA2, 0x4A, 0x2A, 0xC3, 0x5B, 0x63, 0x1F, 0x40, 0x10, 0x36, 0xF9, 0x4C, 0xD2, 0x76, 0x0F, 0xCF, 0x7F, 0x50, 0x30, 0x6E, 0x2B, 0x1D };
+static const unsigned char verify_vector_0_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 };
+static const size_t verify_vector_0_n_vec_len = 1;
+static const unsigned char verify_vector_0_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_0_c_vec[1];
+static const unsigned char verify_vector_0_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const unsigned char verify_vector_0_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E };
+static const int verify_vector_0_result = 1;
+static const unsigned char verify_vector_1_commit33[33] = { 0x02, 0x6C, 0x09, 0xD7, 0x06, 0x2D, 0x1C, 0x07, 0x0A, 0x64, 0x34, 0x82, 0xF6, 0x46, 0x03, 0xEB, 0x24, 0x3E, 0x54, 0x0F, 0xDA, 0xAF, 0x3A, 0x69, 0x5F, 0x86, 0xB6, 0xD2, 0xC2, 0x06, 0xE9, 0x49, 0xC7 };
+static const size_t verify_vector_1_n_vec_len = 1;
+static const unsigned char verify_vector_1_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_1_c_vec[1];
+static const unsigned char verify_vector_1_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const unsigned char verify_vector_1_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E };
+static const int verify_vector_1_result = 0;
+static const unsigned char verify_vector_2_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 };
+static const size_t verify_vector_2_n_vec_len = 1;
+static const unsigned char verify_vector_2_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_2_c_vec[1];
+static const unsigned char verify_vector_2_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const unsigned char verify_vector_2_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 };
+static const int verify_vector_2_result = 0;
+static const unsigned char verify_vector_3_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 };
+static const size_t verify_vector_3_n_vec_len = 1;
+static const unsigned char verify_vector_3_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_3_c_vec[1];
+static const unsigned char verify_vector_3_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const unsigned char verify_vector_3_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 };
+static const int verify_vector_3_result = 0;
+static const unsigned char verify_vector_4_commit33[33] = { 0x03, 0xD7, 0x53, 0x31, 0x5B, 0xAA, 0x04, 0xD5, 0x7C, 0x4A, 0x34, 0x94, 0x98, 0xBC, 0xA9, 0x1E, 0xD6, 0xA3, 0xBF, 0x81, 0xFC, 0x38, 0x30, 0x7C, 0x3B, 0x7C, 0xFC, 0xC6, 0xFF, 0x1A, 0x13, 0x36, 0x72 };
+static const size_t verify_vector_4_n_vec_len = 1;
+static const unsigned char verify_vector_4_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_4_c_vec[1];
+static const unsigned char verify_vector_4_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const unsigned char verify_vector_4_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41 };
+static const int verify_vector_4_result = 0;
+static const unsigned char verify_vector_5_commit33[33] = { 0x03, 0x83, 0x6A, 0xD4, 0x2D, 0xD2, 0x02, 0x49, 0xC8, 0x6E, 0x53, 0x22, 0x53, 0x24, 0xDA, 0x52, 0x08, 0xC0, 0x62, 0x4C, 0xCB, 0xB3, 0x13, 0xD7, 0x14, 0x59, 0x68, 0x47, 0x56, 0x00, 0xC0, 0x8D, 0xBA };
+static const size_t verify_vector_5_n_vec_len = 2;
+static const unsigned char verify_vector_5_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_5_c_vec[1];
+static const unsigned char verify_vector_5_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x36 };
+static const unsigned char verify_vector_5_proof[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x4C, 0xB9, 0xD4, 0x34, 0xA2, 0xD6, 0xD5, 0x4C, 0x0F, 0x2E, 0x2C, 0xE3, 0x82, 0x17, 0x48, 0x63, 0xE0, 0xAE, 0x6B, 0xD7, 0x64, 0x9D, 0x43, 0x2B, 0x6E, 0x6E, 0x1C, 0x62, 0x55, 0x4B, 0xC5, 0x73, 0x3D, 0x74, 0x7B, 0x78, 0x43, 0xF4, 0x8B, 0x7C, 0x84, 0x10, 0x00, 0x8B, 0x12, 0xAF, 0xA4, 0xF1, 0xF4, 0x01, 0x96, 0x21, 0x8B, 0xE9, 0x05, 0x01, 0xF8, 0x23, 0x7A, 0x8F, 0x66, 0xC9, 0xDE, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E };
+static const int verify_vector_5_result = 0;
+static const unsigned char verify_vector_6_commit33[33] = { 0x03, 0xCF, 0x7F, 0x08, 0xF5, 0x8A, 0x06, 0x74, 0x5C, 0xDB, 0xCE, 0xC6, 0x51, 0xF3, 0xE5, 0xE4, 0xDC, 0xAD, 0xF4, 0x40, 0x3C, 0xFA, 0xE6, 0x78, 0xBE, 0x49, 0x2D, 0x90, 0xC8, 0xD0, 0x16, 0x3D, 0x78 };
+static const size_t verify_vector_6_n_vec_len = 2;
+static const unsigned char verify_vector_6_c_vec32[4][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C }, { 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, 0x03 }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x30 }, { 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, 0x0D } };
+static secp256k1_scalar verify_vector_6_c_vec[4];
+static const unsigned char verify_vector_6_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const unsigned char verify_vector_6_proof[] = { 0x00, 0xD2, 0xEC, 0xE2, 0x53, 0x97, 0x28, 0x68, 0x22, 0x59, 0x34, 0xEF, 0xE4, 0x7B, 0x87, 0x4D, 0xE9, 0x57, 0xD5, 0xB7, 0xC7, 0x72, 0xF4, 0xC9, 0xEA, 0x66, 0x14, 0x59, 0xE1, 0xA9, 0xD5, 0xB2, 0x10, 0xDF, 0xE2, 0xFF, 0xF5, 0xA4, 0x38, 0x6B, 0xFE, 0x36, 0x89, 0xE4, 0x9D, 0x90, 0x9F, 0x71, 0x19, 0xE6, 0xA3, 0x1E, 0xAA, 0xAA, 0x4E, 0xFE, 0xC2, 0xD3, 0x37, 0xBB, 0xDE, 0xDB, 0x46, 0x43, 0xC2, 0x01, 0x42, 0x5F, 0xFC, 0xC6, 0x25, 0xA0, 0xB4, 0xF0, 0x76, 0x99, 0xF4, 0x7C, 0xE9, 0x83, 0x82, 0xED, 0x7C, 0x95, 0xBA, 0xD0, 0xE6, 0x5B, 0x88, 0xFD, 0x38, 0xEA, 0x23, 0x54, 0xD4, 0xBD, 0xD4, 0x37, 0xB8, 0x2B, 0x49, 0xAF, 0x81, 0xFD, 0xBE, 0x88, 0xB2, 0xE5, 0x3F, 0xF4, 0x30, 0x52, 0x00, 0x63, 0x9D, 0xAE, 0x82, 0x44, 0xE9, 0x62, 0x87, 0x2A, 0x23, 0x89, 0x10, 0xE4, 0x9A, 0x64, 0x9F, 0x71, 0xD9, 0x32, 0x57, 0x3B, 0xCB, 0xAC, 0x30, 0xAE, 0x71, 0x61, 0xE9, 0x50, 0x1F, 0xCB, 0x49, 0x9C, 0x52, 0xBA, 0x0C, 0xC4, 0x00, 0x58, 0x73, 0x63, 0xD3, 0x42, 0xDE, 0x42, 0x5E, 0xC5, 0x97, 0xE5, 0xDA, 0x88, 0x76, 0x49, 0x6C, 0x8B, 0x92, 0x99, 0xEE, 0xD0, 0xA9, 0xEB, 0x6E, 0xCA, 0xE1, 0x93, 0x81, 0x56, 0x2E, 0xCA, 0xF3, 0x8E, 0xF0, 0x04, 0xD2, 0x96, 0xD8, 0xDB, 0xEE, 0xEE, 0x1C, 0x44 };
+static const int verify_vector_6_result = 1;
+static const unsigned char verify_vector_7_commit33[33] = { 0x02, 0x7A, 0xAA, 0xB2, 0x7E, 0xA5, 0x5B, 0x77, 0x08, 0xE5, 0x43, 0xB6, 0x22, 0x7F, 0xC9, 0xAC, 0x53, 0x10, 0x32, 0x61, 0x7B, 0x7D, 0xAC, 0xB1, 0xB6, 0xF6, 0xAC, 0xDE, 0x63, 0x79, 0x82, 0x9C, 0x24 };
+static const size_t verify_vector_7_n_vec_len = 4;
+static const unsigned char verify_vector_7_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_7_c_vec[1];
+static const unsigned char verify_vector_7_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 };
+static const unsigned char verify_vector_7_proof[] = { 0x00, 0xBC, 0x4C, 0x42, 0x67, 0x71, 0x69, 0x52, 0x6A, 0x65, 0xFE, 0xA0, 0xCB, 0x3F, 0x58, 0x8B, 0x48, 0x48, 0x6E, 0x59, 0xFC, 0x55, 0x51, 0x10, 0xB9, 0xBF, 0x6A, 0x7D, 0xBF, 0x32, 0x34, 0x4E, 0x7D, 0xBA, 0xD5, 0xCB, 0xCC, 0x19, 0xED, 0xAA, 0x9F, 0x8D, 0x93, 0x26, 0x5E, 0x3F, 0x3E, 0xAA, 0xDF, 0x0B, 0x1C, 0xB3, 0xDC, 0x37, 0xB6, 0xDB, 0xAE, 0x43, 0x63, 0x92, 0xB5, 0xFF, 0x0D, 0x1C, 0x77, 0x02, 0x7E, 0x2B, 0xB8, 0x87, 0x85, 0x81, 0x13, 0x70, 0x1F, 0x03, 0x65, 0x7D, 0xD8, 0x91, 0x83, 0xE5, 0x7E, 0x8B, 0x9E, 0x6F, 0x1C, 0x08, 0x9C, 0x9C, 0x5F, 0xA4, 0x12, 0x5F, 0xD3, 0xEE, 0xE2, 0x74, 0x7A, 0x2C, 0x58, 0x3A, 0x29, 0x4F, 0x64, 0x10, 0xE7, 0x89, 0xBF, 0xB2, 0xE5, 0xD9, 0xD5, 0xC5, 0x62, 0x83, 0x0C, 0xA8, 0xDD, 0x1E, 0x24, 0x6D, 0xD1, 0x58, 0x8D, 0x80, 0x74, 0xF3, 0xD9, 0x3A, 0x68, 0x7B, 0xF5, 0x12, 0xC6, 0xC2, 0x3F, 0x71, 0x47, 0xDF, 0xCF, 0xC8, 0xE2, 0xC4, 0x59, 0xDF, 0x4F, 0xEC, 0x86, 0xE9, 0xF9, 0x31, 0x94, 0x6A, 0x5F, 0xD9, 0x1E, 0x6B, 0x09, 0xCD, 0xCF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E };
+static const int verify_vector_7_result = 1;
+static const unsigned char verify_vector_8_commit33[33] = { 0x02, 0x2D, 0x4F, 0xF9, 0xB7, 0x15, 0x22, 0xBC, 0xB0, 0x8B, 0xF8, 0xBA, 0x31, 0x0A, 0x80, 0x76, 0x7A, 0xE9, 0xA9, 0x83, 0x00, 0xBC, 0x5A, 0x01, 0xCC, 0xE9, 0x00, 0x83, 0x56, 0xEA, 0x77, 0xEB, 0x75 };
+static const size_t verify_vector_8_n_vec_len = 4;
+static const unsigned char verify_vector_8_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_8_c_vec[1];
+static const unsigned char verify_vector_8_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 };
+static const unsigned char verify_vector_8_proof[] = { 0x00, 0xBC, 0x4C, 0x42, 0x67, 0x71, 0x69, 0x52, 0x6A, 0x65, 0xFE, 0xA0, 0xCB, 0x3F, 0x58, 0x8B, 0x48, 0x48, 0x6E, 0x59, 0xFC, 0x55, 0x51, 0x10, 0xB9, 0xBF, 0x6A, 0x7D, 0xBF, 0x32, 0x34, 0x4E, 0x7D, 0xBA, 0xD5, 0xCB, 0xCC, 0x19, 0xED, 0xAA, 0x9F, 0x8D, 0x93, 0x26, 0x5E, 0x3F, 0x3E, 0xAA, 0xDF, 0x0B, 0x1C, 0xB3, 0xDC, 0x37, 0xB6, 0xDB, 0xAE, 0x43, 0x63, 0x92, 0xB5, 0xFF, 0x0D, 0x1C, 0x77, 0x02, 0x7E, 0x2B, 0xB8, 0x87, 0x85, 0x81, 0x13, 0x70, 0x1F, 0x03, 0x65, 0x7D, 0xD8, 0x91, 0x83, 0xE5, 0x7E, 0x8B, 0x9E, 0x6F, 0x1C, 0x08, 0x9C, 0x9C, 0x5F, 0xA4, 0x12, 0x5F, 0xD3, 0xEE, 0xE2, 0x74, 0x7A, 0x2C, 0x58, 0x3A, 0x29, 0x4F, 0x64, 0x10, 0xE7, 0x89, 0xBF, 0xB2, 0xE5, 0xD9, 0xD5, 0xC5, 0x62, 0x83, 0x0C, 0xA8, 0xDD, 0x1E, 0x24, 0x6D, 0xD1, 0x58, 0x8D, 0x80, 0x74, 0xF3, 0xD9, 0x3A, 0x68, 0x7B, 0xF5, 0x12, 0xC6, 0xC2, 0x3F, 0x71, 0x47, 0xDF, 0xCF, 0xC8, 0xE2, 0xC4, 0x59, 0xDF, 0x4F, 0xEC, 0x86, 0xE9, 0xF9, 0x31, 0x94, 0x6A, 0x5F, 0xD9, 0x1E, 0x6B, 0x09, 0xCD, 0xCF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E };
+static const int verify_vector_8_result = 0;
+static const unsigned char verify_vector_9_commit33[33] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const size_t verify_vector_9_n_vec_len = 1;
+static const unsigned char verify_vector_9_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_9_c_vec[1];
+static const unsigned char verify_vector_9_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 };
+static const unsigned char verify_vector_9_proof[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const int verify_vector_9_result = 1;
+static const unsigned char verify_vector_10_commit33[33] = { 0x03, 0x62, 0x8A, 0xC2, 0xF1, 0xF2, 0x00, 0xE0, 0x81, 0xBD, 0xA0, 0xA9, 0x6D, 0x25, 0x53, 0xB4, 0x17, 0xC1, 0x02, 0x93, 0x50, 0x3E, 0x91, 0xD4, 0xD1, 0x3A, 0x82, 0x89, 0x02, 0x24, 0x78, 0x49, 0xA5 };
+static const size_t verify_vector_10_n_vec_len = 2;
+static const unsigned char verify_vector_10_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_10_c_vec[1];
+static const unsigned char verify_vector_10_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 };
+static const unsigned char verify_vector_10_proof[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const int verify_vector_10_result = 1;
+static const unsigned char verify_vector_11_commit33[33] = { 0x03, 0x62, 0x8A, 0xC2, 0xF1, 0xF2, 0x00, 0xE0, 0x81, 0xBD, 0xA0, 0xA9, 0x6D, 0x25, 0x53, 0xB4, 0x17, 0xC1, 0x02, 0x93, 0x50, 0x3E, 0x91, 0xD4, 0xD1, 0x3A, 0x82, 0x89, 0x02, 0x24, 0x78, 0x49, 0xA5 };
+static const size_t verify_vector_11_n_vec_len = 2;
+static const unsigned char verify_vector_11_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_11_c_vec[1];
+static const unsigned char verify_vector_11_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 };
+static const unsigned char verify_vector_11_proof[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const int verify_vector_11_result = 0;
+static const unsigned char verify_vector_12_commit33[33] = { 0x02, 0x7D, 0x5F, 0x4B, 0x11, 0xC0, 0xE4, 0x2E, 0x4C, 0x1B, 0x56, 0xAE, 0xF0, 0x5F, 0xAA, 0xD8, 0x77, 0x0C, 0x93, 0x71, 0xA2, 0x92, 0xF9, 0x89, 0xA2, 0xB4, 0x69, 0x9B, 0x46, 0x8A, 0x03, 0xF1, 0x50 };
+static const size_t verify_vector_12_n_vec_len = 0;
+static const unsigned char verify_vector_12_c_vec32[1][32] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3C } };
+static secp256k1_scalar verify_vector_12_c_vec[1];
+static const unsigned char verify_vector_12_r32[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34 };
+static const unsigned char verify_vector_12_proof[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x34, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3A };
+static const int verify_vector_12_result = 0;
+
diff --git a/src/modules/bppp/tests_impl.h b/src/modules/bppp/tests_impl.h
new file mode 100644
index 00000000000..eddb524052a
--- /dev/null
+++ b/src/modules/bppp/tests_impl.h
@@ -0,0 +1,695 @@
+/**********************************************************************
+ * Copyright (c) 2020 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_BPPP_TEST_H
+#define SECP256K1_MODULE_BPPP_TEST_H
+
+#include
+
+#include "../../../include/secp256k1_bppp.h"
+#include "bppp_norm_product_impl.h"
+#include "bppp_util.h"
+#include "bppp_transcript_impl.h"
+#include "test_vectors/verify.h"
+#include "test_vectors/prove.h"
+
+static void test_bppp_generators_api(void) {
+ /* The BP generator API requires no precomp */
+ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+
+ secp256k1_bppp_generators *gens;
+ secp256k1_bppp_generators *gens_orig;
+ unsigned char gens_ser[330];
+ size_t len = sizeof(gens_ser);
+
+ int32_t ecount = 0;
+
+ secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
+
+ /* Create */
+ gens = secp256k1_bppp_generators_create(none, 10);
+ CHECK(gens != NULL && ecount == 0);
+ gens_orig = gens; /* Preserve for round-trip test */
+
+ /* Serialize */
+ ecount = 0;
+ CHECK(!secp256k1_bppp_generators_serialize(none, NULL, gens_ser, &len));
+ CHECK(ecount == 1);
+ CHECK(!secp256k1_bppp_generators_serialize(none, gens, NULL, &len));
+ CHECK(ecount == 2);
+ CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, NULL));
+ CHECK(ecount == 3);
+ len = 0;
+ CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len));
+ CHECK(ecount == 4);
+ len = sizeof(gens_ser) - 1;
+ CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len));
+ CHECK(ecount == 5);
+ len = sizeof(gens_ser);
+ {
+ /* Output buffer can be greater than minimum needed */
+ unsigned char gens_ser_tmp[331];
+ size_t len_tmp = sizeof(gens_ser_tmp);
+ CHECK(secp256k1_bppp_generators_serialize(none, gens, gens_ser_tmp, &len_tmp));
+ CHECK(len_tmp == sizeof(gens_ser_tmp) - 1);
+ CHECK(ecount == 5);
+ }
+
+ /* Parse */
+ CHECK(secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len));
+ ecount = 0;
+ gens = secp256k1_bppp_generators_parse(none, NULL, sizeof(gens_ser));
+ CHECK(gens == NULL && ecount == 1);
+ /* Not a multiple of 33 */
+ gens = secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser) - 1);
+ CHECK(gens == NULL && ecount == 1);
+ gens = secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser));
+ CHECK(gens != NULL && ecount == 1);
+ /* Not valid generators */
+ memset(gens_ser, 1, sizeof(gens_ser));
+ CHECK(secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser)) == NULL);
+ CHECK(ecount == 1);
+
+ /* Check that round-trip succeeded */
+ CHECK(gens->n == gens_orig->n);
+ for (len = 0; len < gens->n; len++) {
+ ge_equals_ge(&gens->gens[len], &gens_orig->gens[len]);
+ }
+
+ /* Destroy (we allow destroying a NULL context, it's just a noop. like free().) */
+ ecount = 0;
+ secp256k1_bppp_generators_destroy(none, NULL);
+ secp256k1_bppp_generators_destroy(none, gens);
+ secp256k1_bppp_generators_destroy(none, gens_orig);
+ CHECK(ecount == 0);
+
+ secp256k1_context_destroy(none);
+}
+
+static void test_bppp_generators_fixed(void) {
+ secp256k1_bppp_generators *gens = secp256k1_bppp_generators_create(ctx, 3);
+ unsigned char gens_ser[330];
+ const unsigned char fixed_first_3[99] = {
+ 0x0b,
+ 0xb3, 0x4d, 0x5f, 0xa6, 0xb8, 0xf3, 0xd1, 0x38,
+ 0x49, 0xce, 0x51, 0x91, 0xb7, 0xf6, 0x76, 0x18,
+ 0xfe, 0x5b, 0xd1, 0x2a, 0x88, 0xb2, 0x0e, 0xac,
+ 0x33, 0x89, 0x45, 0x66, 0x7f, 0xb3, 0x30, 0x56,
+ 0x0a,
+ 0x62, 0x86, 0x15, 0x16, 0x92, 0x42, 0x10, 0x9e,
+ 0x9e, 0x64, 0xd4, 0xcb, 0x28, 0x81, 0x60, 0x9c,
+ 0x24, 0xb9, 0x89, 0x51, 0x2a, 0xd9, 0x01, 0xae,
+ 0xff, 0x75, 0x64, 0x9c, 0x37, 0x5d, 0xbd, 0x79,
+ 0x0a,
+ 0xed, 0xe0, 0x6e, 0x07, 0x5e, 0x79, 0xd0, 0xf7,
+ 0x7b, 0x03, 0x3e, 0xb9, 0xa9, 0x21, 0xa4, 0x5b,
+ 0x99, 0xf3, 0x9b, 0xee, 0xfe, 0xa0, 0x37, 0xa2,
+ 0x1f, 0xe9, 0xd7, 0x4f, 0x95, 0x8b, 0x10, 0xe2,
+ };
+ size_t len;
+
+ len = 99;
+ CHECK(secp256k1_bppp_generators_serialize(ctx, gens, gens_ser, &len));
+ CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0);
+
+ len = sizeof(gens_ser);
+ CHECK(secp256k1_bppp_generators_serialize(ctx, gens, gens_ser, &len));
+ CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0);
+
+ secp256k1_bppp_generators_destroy(ctx, gens);
+}
+
+static void test_bppp_tagged_hash(void) {
+ unsigned char tag_data[29] = "Bulletproofs_pp/v0/commitment";
+ secp256k1_sha256 sha;
+ secp256k1_sha256 sha_cached;
+ unsigned char output[32];
+ unsigned char output_cached[32];
+ secp256k1_scalar s;
+
+ secp256k1_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data));
+ secp256k1_bppp_sha256_tagged_commitment_init(&sha_cached);
+ secp256k1_sha256_finalize(&sha, output);
+ secp256k1_sha256_finalize(&sha_cached, output_cached);
+ CHECK(secp256k1_memcmp_var(output, output_cached, 32) == 0);
+
+ {
+ unsigned char expected[32] = { 0x21, 0x2F, 0xB6, 0x4F, 0x9D, 0x8C, 0x3B, 0xC5,
+ 0xF6, 0x91, 0x15, 0xEE, 0x74, 0xF5, 0x12, 0x67,
+ 0x8A, 0x41, 0xC6, 0x85, 0x1A, 0x79, 0x14, 0xFC,
+ 0x48, 0x15, 0xC7, 0x2D, 0xF8, 0x63, 0x8F, 0x1B };
+ secp256k1_bppp_sha256_tagged_commitment_init(&sha);
+ secp256k1_bppp_challenge_scalar(&s, &sha, 0);
+ secp256k1_scalar_get_b32(output, &s);
+ CHECK(memcmp(output, expected, sizeof(output)) == 0);
+ }
+
+ {
+ unsigned char tmp[3] = {0, 1, 2};
+ unsigned char expected[32] = { 0x8D, 0xAA, 0xB7, 0x7E, 0x3C, 0x6A, 0x9E, 0xEC,
+ 0x72, 0x7E, 0x3E, 0xB7, 0x10, 0x03, 0xF0, 0xE9,
+ 0x69, 0x4D, 0xAA, 0x96, 0xCE, 0x98, 0xBB, 0x39,
+ 0x1C, 0x2F, 0x7C, 0x2E, 0x1C, 0x17, 0x78, 0x6D };
+ secp256k1_sha256_write(&sha, tmp, sizeof(tmp));
+ secp256k1_bppp_challenge_scalar(&s, &sha, 0);
+ secp256k1_scalar_get_b32(output, &s);
+ CHECK(memcmp(output, expected, sizeof(output)) == 0);
+ }
+}
+
+void test_log_exp(void) {
+ CHECK(secp256k1_is_power_of_two(0) == 0);
+ CHECK(secp256k1_is_power_of_two(1) == 1);
+ CHECK(secp256k1_is_power_of_two(2) == 1);
+ CHECK(secp256k1_is_power_of_two(64) == 1);
+ CHECK(secp256k1_is_power_of_two(63) == 0);
+ CHECK(secp256k1_is_power_of_two(256) == 1);
+
+ CHECK(secp256k1_bppp_log2(1) == 0);
+ CHECK(secp256k1_bppp_log2(2) == 1);
+ CHECK(secp256k1_bppp_log2(255) == 7);
+ CHECK(secp256k1_bppp_log2(256) == 8);
+ CHECK(secp256k1_bppp_log2(257) == 8);
+}
+
+void test_norm_util_helpers(void) {
+ secp256k1_scalar a_vec[4], b_vec[4], rho_pows[4], res, res2, mu, rho;
+ int i;
+ /* a = {1, 2, 3, 4} b = {5, 6, 7, 8}, mu = 4, rho = 2 */
+ for (i = 0; i < 4; i++) {
+ secp256k1_scalar_set_int(&a_vec[i], i + 1);
+ secp256k1_scalar_set_int(&b_vec[i], i + 5);
+ }
+ secp256k1_scalar_set_int(&mu, 4);
+ secp256k1_scalar_set_int(&rho, 2);
+ secp256k1_scalar_inner_product(&res, a_vec, 0, b_vec, 0, 1, 4);
+ secp256k1_scalar_set_int(&res2, 70);
+ CHECK(secp256k1_scalar_eq(&res2, &res) == 1);
+
+ secp256k1_scalar_inner_product(&res, a_vec, 0, b_vec, 1, 2, 2);
+ secp256k1_scalar_set_int(&res2, 30);
+ CHECK(secp256k1_scalar_eq(&res2, &res) == 1);
+
+ secp256k1_scalar_inner_product(&res, a_vec, 1, b_vec, 0, 2, 2);
+ secp256k1_scalar_set_int(&res2, 38);
+ CHECK(secp256k1_scalar_eq(&res2, &res) == 1);
+
+ secp256k1_scalar_inner_product(&res, a_vec, 1, b_vec, 1, 2, 2);
+ secp256k1_scalar_set_int(&res2, 44);
+ CHECK(secp256k1_scalar_eq(&res2, &res) == 1);
+
+ secp256k1_weighted_scalar_inner_product(&res, a_vec, 0, a_vec, 0, 1, 4, &mu);
+ secp256k1_scalar_set_int(&res2, 4740); /*i*i*4^(i+1) */
+ CHECK(secp256k1_scalar_eq(&res2, &res) == 1);
+
+ secp256k1_bppp_powers_of_rho(rho_pows, &rho, 4);
+ secp256k1_scalar_set_int(&res, 2); CHECK(secp256k1_scalar_eq(&res, &rho_pows[0]));
+ secp256k1_scalar_set_int(&res, 4); CHECK(secp256k1_scalar_eq(&res, &rho_pows[1]));
+ secp256k1_scalar_set_int(&res, 16); CHECK(secp256k1_scalar_eq(&res, &rho_pows[2]));
+ secp256k1_scalar_set_int(&res, 256); CHECK(secp256k1_scalar_eq(&res, &rho_pows[3]));
+}
+
+
+void test_serialize_two_points_roundtrip(secp256k1_ge *X, secp256k1_ge *R) {
+ secp256k1_ge X_tmp, R_tmp;
+ unsigned char buf[65];
+ secp256k1_bppp_serialize_points(buf, X, R);
+ CHECK(secp256k1_bppp_parse_one_of_points(&X_tmp, buf, 0));
+ CHECK(secp256k1_bppp_parse_one_of_points(&R_tmp, buf, 1));
+ ge_equals_ge(X, &X_tmp);
+ ge_equals_ge(R, &R_tmp);
+}
+
+void test_serialize_two_points(void) {
+ secp256k1_ge X, R;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ random_group_element_test(&X);
+ random_group_element_test(&R);
+ test_serialize_two_points_roundtrip(&X, &R);
+ }
+
+ for (i = 0; i < count; i++) {
+ random_group_element_test(&X);
+ secp256k1_ge_set_infinity(&R);
+ test_serialize_two_points_roundtrip(&X, &R);
+ }
+
+ for (i = 0; i < count; i++) {
+ secp256k1_ge_set_infinity(&X);
+ random_group_element_test(&R);
+ test_serialize_two_points_roundtrip(&X, &R);
+ }
+
+ secp256k1_ge_set_infinity(&X);
+ secp256k1_ge_set_infinity(&R);
+ test_serialize_two_points_roundtrip(&X, &R);
+
+ /* Test invalid sign byte */
+ {
+ secp256k1_ge X_tmp, R_tmp;
+ unsigned char buf[65];
+ random_group_element_test(&X);
+ random_group_element_test(&R);
+ secp256k1_bppp_serialize_points(buf, &X, &R);
+ buf[0] |= 4 + (unsigned char)secp256k1_testrandi64(4, 255);
+ CHECK(!secp256k1_bppp_parse_one_of_points(&X_tmp, buf, 0));
+ CHECK(!secp256k1_bppp_parse_one_of_points(&R_tmp, buf, 0));
+ }
+ /* Check that sign bit is 0 for point at infinity */
+ for (i = 0; i < count; i++) {
+ secp256k1_ge X_tmp, R_tmp;
+ unsigned char buf[65];
+ int expect;
+ random_group_element_test(&X);
+ random_group_element_test(&R);
+ secp256k1_bppp_serialize_points(buf, &X, &R);
+ memset(&buf[1], 0, 32);
+ if ((buf[0] & 2) == 0) {
+ expect = 1;
+ } else {
+ expect = 0;
+ }
+ CHECK(secp256k1_bppp_parse_one_of_points(&X_tmp, buf, 0) == expect);
+ CHECK(secp256k1_bppp_parse_one_of_points(&R_tmp, buf, 1));
+ memset(&buf[33], 0, 32);
+ if ((buf[0] & 1) == 0) {
+ expect = 1;
+ } else {
+ expect = 0;
+ }
+ CHECK(secp256k1_bppp_parse_one_of_points(&R_tmp, buf, 1) == expect);
+ }
+}
+
+static void secp256k1_norm_arg_commit_initial_data(
+ secp256k1_sha256* transcript,
+ const secp256k1_scalar* rho,
+ const secp256k1_bppp_generators* gens_vec,
+ size_t g_len, /* Same as n_vec_len, g_len + c_vec_len = gens->n */
+ const secp256k1_scalar* c_vec,
+ size_t c_vec_len,
+ const secp256k1_ge* commit
+) {
+ /* Commit to the initial public values */
+ unsigned char ser_commit[33], ser_scalar[32], ser_le64[8];
+ size_t i;
+ secp256k1_ge comm = *commit;
+ secp256k1_bppp_sha256_tagged_commitment_init(transcript);
+ secp256k1_fe_normalize(&comm.x);
+ secp256k1_fe_normalize(&comm.y);
+ CHECK(secp256k1_ge_is_infinity(&comm) == 0);
+ CHECK(secp256k1_bppp_serialize_pt(&ser_commit[0], &comm));
+ secp256k1_sha256_write(transcript, ser_commit, 33);
+ secp256k1_scalar_get_b32(ser_scalar, rho);
+ secp256k1_sha256_write(transcript, ser_scalar, 32);
+ secp256k1_bppp_le64(ser_le64, g_len);
+ secp256k1_sha256_write(transcript, ser_le64, 8);
+ secp256k1_bppp_le64(ser_le64, gens_vec->n);
+ secp256k1_sha256_write(transcript, ser_le64, 8);
+ for (i = 0; i < gens_vec->n; i++) {
+ secp256k1_fe_normalize(&gens_vec->gens[i].x);
+ secp256k1_fe_normalize(&gens_vec->gens[i].y);
+ CHECK(secp256k1_bppp_serialize_pt(&ser_commit[0], &gens_vec->gens[i]));
+ secp256k1_sha256_write(transcript, ser_commit, 33);
+ }
+ secp256k1_bppp_le64(ser_le64, c_vec_len);
+ secp256k1_sha256_write(transcript, ser_le64, 8);
+ for (i = 0; i < c_vec_len; i++) {
+ secp256k1_scalar_get_b32(ser_scalar, &c_vec[i]);
+ secp256k1_sha256_write(transcript, ser_scalar, 32);
+ }
+}
+
+static void copy_vectors_into_scratch(secp256k1_scratch_space* scratch,
+ secp256k1_scalar **ns,
+ secp256k1_scalar **ls,
+ secp256k1_scalar **cs,
+ secp256k1_ge **gs,
+ const secp256k1_scalar *n_vec,
+ const secp256k1_scalar *l_vec,
+ const secp256k1_scalar *c_vec,
+ const secp256k1_ge *gens_vec,
+ size_t g_len,
+ size_t h_len) {
+ *ns = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(secp256k1_scalar));
+ *ls = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar));
+ *cs = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar));
+ *gs = (secp256k1_ge*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, (g_len + h_len) * sizeof(secp256k1_ge));
+ CHECK(ns != NULL && ls != NULL && cs != NULL && gs != NULL);
+ memcpy(*ns, n_vec, g_len * sizeof(secp256k1_scalar));
+ memcpy(*ls, l_vec, h_len * sizeof(secp256k1_scalar));
+ memcpy(*cs, c_vec, h_len * sizeof(secp256k1_scalar));
+ memcpy(*gs, gens_vec, (g_len + h_len) * sizeof(secp256k1_ge));
+}
+
+/* Same as secp256k1_bppp_rangeproof_norm_product_prove but does not modify the inputs */
+static int secp256k1_bppp_rangeproof_norm_product_prove_const(
+ secp256k1_scratch_space* scratch,
+ unsigned char* proof,
+ size_t *proof_len,
+ secp256k1_sha256 *transcript,
+ const secp256k1_scalar* rho,
+ const secp256k1_ge* g_vec,
+ size_t g_vec_len,
+ const secp256k1_scalar* n_vec,
+ size_t n_vec_len,
+ const secp256k1_scalar* l_vec,
+ size_t l_vec_len,
+ const secp256k1_scalar* c_vec,
+ size_t c_vec_len
+) {
+ secp256k1_scalar *ns, *ls, *cs;
+ secp256k1_ge *gs;
+ size_t scratch_checkpoint;
+ size_t g_len = n_vec_len, h_len = l_vec_len;
+ int res;
+
+ scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
+ copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, g_vec, g_len, h_len);
+ res = secp256k1_bppp_rangeproof_norm_product_prove(
+ ctx,
+ scratch,
+ proof,
+ proof_len,
+ transcript, /* Transcript hash of the parent protocol */
+ rho,
+ gs,
+ g_vec_len,
+ ns,
+ n_vec_len,
+ ls,
+ l_vec_len,
+ cs,
+ c_vec_len
+ );
+ secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
+ return res;
+}
+
+/* A complete norm argument. In contrast to secp256k1_bppp_rangeproof_norm_product_prove, this is meant
+ to be used as a standalone norm argument.
+ This is a simple wrapper around secp256k1_bppp_rangeproof_norm_product_prove
+ that also commits to the initial public values used in the protocol. In this case, these public
+ values are commitment.
+*/
+static int secp256k1_norm_arg_prove(
+ secp256k1_scratch_space* scratch,
+ unsigned char* proof,
+ size_t *proof_len,
+ const secp256k1_scalar* rho,
+ const secp256k1_bppp_generators* gens_vec,
+ const secp256k1_scalar* n_vec,
+ size_t n_vec_len,
+ const secp256k1_scalar* l_vec,
+ size_t l_vec_len,
+ const secp256k1_scalar* c_vec,
+ size_t c_vec_len,
+ const secp256k1_ge* commit
+) {
+ secp256k1_sha256 transcript;
+ secp256k1_norm_arg_commit_initial_data(&transcript, rho, gens_vec, n_vec_len, c_vec, c_vec_len, commit);
+
+ return secp256k1_bppp_rangeproof_norm_product_prove_const(scratch, proof, proof_len, &transcript, rho, gens_vec->gens, gens_vec->n, n_vec, n_vec_len, l_vec, l_vec_len, c_vec, c_vec_len);
+}
+
+/* Verify the proof */
+static int secp256k1_norm_arg_verify(
+ secp256k1_scratch_space* scratch,
+ const unsigned char* proof,
+ size_t proof_len,
+ const secp256k1_scalar* rho,
+ const secp256k1_bppp_generators* gens_vec,
+ size_t g_len,
+ const secp256k1_scalar* c_vec,
+ size_t c_vec_len,
+ const secp256k1_ge* commit
+) {
+ secp256k1_ge comm = *commit;
+ int res;
+ secp256k1_sha256 transcript;
+
+ /* Commit to the initial public values */
+ secp256k1_norm_arg_commit_initial_data(&transcript, rho, gens_vec, g_len, c_vec, c_vec_len, &comm);
+
+ res = secp256k1_bppp_rangeproof_norm_product_verify(
+ ctx,
+ scratch,
+ proof,
+ proof_len,
+ &transcript,
+ rho,
+ gens_vec,
+ g_len,
+ c_vec,
+ c_vec_len,
+ commit
+ );
+ return res;
+}
+
+/* Verify |c| = 0 */
+void norm_arg_verify_zero_len(void) {
+ secp256k1_scalar n_vec[64], l_vec[64], c_vec[64];
+ secp256k1_scalar rho, mu;
+ secp256k1_ge commit;
+ secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*10); /* shouldn't need much */
+ unsigned char proof[1000];
+ unsigned int n_vec_len = 1;
+ unsigned int c_vec_len = 1;
+ secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len);
+ size_t plen = sizeof(proof);
+
+ random_scalar_order(&rho);
+ secp256k1_scalar_sqr(&mu, &rho);
+
+ random_scalar_order(&n_vec[0]);
+ random_scalar_order(&c_vec[0]);
+ random_scalar_order(&l_vec[0]);
+ CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
+ CHECK(secp256k1_norm_arg_prove(scratch, proof, &plen, &rho, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit));
+ CHECK(secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit));
+ CHECK(!secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n_vec_len, c_vec, 0, &commit));
+
+ secp256k1_bppp_generators_destroy(ctx, gs);
+
+ secp256k1_scratch_space_destroy(ctx, scratch);
+}
+
+void norm_arg_test(unsigned int n, unsigned int m) {
+ secp256k1_scalar n_vec[64], l_vec[64], c_vec[64];
+ secp256k1_scalar rho, mu;
+ secp256k1_ge commit;
+ size_t i, plen;
+ int res;
+ secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n + m);
+ secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */
+ unsigned char proof[1000];
+ plen = 1000;
+ random_scalar_order(&rho);
+ secp256k1_scalar_sqr(&mu, &rho);
+
+ for (i = 0; i < n; i++) {
+ random_scalar_order(&n_vec[i]);
+ }
+
+ for (i = 0; i < m; i++) {
+ random_scalar_order(&l_vec[i]);
+ random_scalar_order(&c_vec[i]);
+ }
+
+ res = secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n, l_vec, m, c_vec, m, &mu);
+ CHECK(res == 1);
+ res = secp256k1_norm_arg_prove(scratch, proof, &plen, &rho, gs, n_vec, n, l_vec, m, c_vec, m, &commit);
+ CHECK(res == 1);
+
+ res = secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n, c_vec, m, &commit);
+ CHECK(res == 1);
+
+ /* Changing any of last two scalars should break the proof */
+ proof[plen - 1] ^= 1;
+ res = secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n, c_vec, m, &commit);
+ CHECK(res == 0);
+ proof[plen - 1 - 32] ^= 1;
+ res = secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n, c_vec, m, &commit);
+ CHECK(res == 0);
+
+ secp256k1_scratch_space_destroy(ctx, scratch);
+ secp256k1_bppp_generators_destroy(ctx, gs);
+}
+
+/* Parses generators from points compressed as pubkeys */
+secp256k1_bppp_generators* bppp_generators_parse_regular(const unsigned char* data, size_t data_len) {
+ size_t n = data_len / 33;
+ secp256k1_bppp_generators* ret;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(data != NULL);
+
+ if (data_len % 33 != 0) {
+ return NULL;
+ }
+
+ ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret));
+ if (ret == NULL) {
+ return NULL;
+ }
+ ret->n = n;
+ ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
+ if (ret->gens == NULL) {
+ free(ret);
+ return NULL;
+ }
+
+ while (n--) {
+ if (!secp256k1_eckey_pubkey_parse(&ret->gens[n], &data[33 * n], 33)) {
+ free(ret->gens);
+ free(ret);
+ return NULL;
+ }
+ }
+ return ret;
+}
+
+int norm_arg_verify_vectors_helper(secp256k1_scratch *scratch, const unsigned char *gens, const unsigned char *proof, size_t plen, const unsigned char *r32, size_t n_vec_len, const unsigned char c_vec32[][32], secp256k1_scalar *c_vec, size_t c_vec_len, const unsigned char *commit33) {
+ secp256k1_sha256 transcript;
+ secp256k1_bppp_generators *gs = bppp_generators_parse_regular(gens, 33*(n_vec_len + c_vec_len));
+ secp256k1_scalar rho;
+ secp256k1_ge commit;
+ int overflow;
+ int i;
+ int ret;
+
+ CHECK(gs != NULL);
+ secp256k1_sha256_initialize(&transcript);
+
+ secp256k1_scalar_set_b32(&rho, r32, &overflow);
+ CHECK(!overflow);
+
+ for (i = 0; i < (int)c_vec_len; i++) {
+ secp256k1_scalar_set_b32(&c_vec[i], c_vec32[i], &overflow);
+ CHECK(!overflow);
+ }
+ CHECK(secp256k1_ge_parse_ext(&commit, commit33));
+ ret = secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit);
+
+ secp256k1_bppp_generators_destroy(ctx, gs);
+ return ret;
+}
+
+#define IDX_TO_TEST(i) (norm_arg_verify_vectors_helper(scratch, verify_vector_gens, verify_vector_##i##_proof, sizeof(verify_vector_##i##_proof), verify_vector_##i##_r32, verify_vector_##i##_n_vec_len, verify_vector_##i##_c_vec32, verify_vector_##i##_c_vec, sizeof(verify_vector_##i##_c_vec)/sizeof(secp256k1_scalar), verify_vector_##i##_commit33) == verify_vector_##i##_result)
+
+void norm_arg_verify_vectors(void) {
+ secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */
+ size_t alloc = scratch->alloc_size;
+
+ CHECK(IDX_TO_TEST(0));
+ CHECK(IDX_TO_TEST(1));
+ CHECK(IDX_TO_TEST(2));
+ CHECK(IDX_TO_TEST(3));
+ CHECK(IDX_TO_TEST(4));
+ CHECK(IDX_TO_TEST(5));
+ CHECK(IDX_TO_TEST(6));
+ CHECK(IDX_TO_TEST(7));
+ CHECK(IDX_TO_TEST(8));
+ CHECK(IDX_TO_TEST(9));
+ CHECK(IDX_TO_TEST(10));
+ CHECK(IDX_TO_TEST(11));
+ CHECK(IDX_TO_TEST(12));
+
+ CHECK(alloc == scratch->alloc_size);
+ secp256k1_scratch_space_destroy(ctx, scratch);
+}
+#undef IDX_TO_TEST
+
+void norm_arg_prove_vectors_helper(secp256k1_scratch *scratch, const unsigned char *gens, const unsigned char *proof, size_t plen, const unsigned char *r32, const unsigned char n_vec32[][32], secp256k1_scalar *n_vec, size_t n_vec_len, const unsigned char l_vec32[][32], secp256k1_scalar *l_vec, const unsigned char c_vec32[][32], secp256k1_scalar *c_vec, size_t c_vec_len, int result) {
+ secp256k1_sha256 transcript;
+ secp256k1_bppp_generators *gs = bppp_generators_parse_regular(gens, 33*(n_vec_len + c_vec_len));
+ secp256k1_scalar rho, mu;
+ secp256k1_ge commit;
+ unsigned char myproof[1024];
+ size_t myplen = sizeof(myproof);
+ int overflow;
+ int i;
+
+ CHECK(gs != NULL);
+ secp256k1_sha256_initialize(&transcript);
+ secp256k1_scalar_set_b32(&rho, r32, &overflow);
+ CHECK(!overflow);
+ secp256k1_scalar_sqr(&mu, &rho);
+
+ for (i = 0; i < (int)n_vec_len; i++) {
+ secp256k1_scalar_set_b32(&n_vec[i], n_vec32[i], &overflow);
+ CHECK(!overflow);
+ }
+ for (i = 0; i < (int)c_vec_len; i++) {
+ secp256k1_scalar_set_b32(&l_vec[i], l_vec32[i], &overflow);
+ CHECK(!overflow);
+ secp256k1_scalar_set_b32(&c_vec[i], c_vec32[i], &overflow);
+ CHECK(!overflow);
+ }
+
+ CHECK(secp256k1_bppp_rangeproof_norm_product_prove_const(scratch, myproof, &myplen, &transcript, &rho, gs->gens, gs->n, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len) == result);
+ if (!result) {
+ secp256k1_bppp_generators_destroy(ctx, gs);
+ return;
+ }
+ CHECK(plen == myplen);
+ CHECK(secp256k1_memcmp_var(proof, myproof, plen) == 0);
+
+ CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
+ secp256k1_sha256_initialize(&transcript);
+ CHECK(secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit));
+ secp256k1_bppp_generators_destroy(ctx, gs);
+}
+
+
+#define IDX_TO_TEST(i) (norm_arg_prove_vectors_helper(scratch, prove_vector_gens, prove_vector_##i##_proof, sizeof(prove_vector_##i##_proof), prove_vector_##i##_r32,\
+ prove_vector_##i##_n_vec32, prove_vector_##i##_n_vec, sizeof(prove_vector_##i##_n_vec)/sizeof(secp256k1_scalar),\
+ prove_vector_##i##_l_vec32, prove_vector_##i##_l_vec,\
+ prove_vector_##i##_c_vec32, prove_vector_##i##_c_vec, sizeof(prove_vector_##i##_c_vec)/sizeof(secp256k1_scalar), \
+ prove_vector_##i##_result))
+
+void norm_arg_prove_vectors(void) {
+ secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */
+ size_t alloc = scratch->alloc_size;
+
+ IDX_TO_TEST(0);
+ IDX_TO_TEST(1);
+ IDX_TO_TEST(2);
+ IDX_TO_TEST(3);
+ IDX_TO_TEST(4);
+
+ CHECK(alloc == scratch->alloc_size);
+ secp256k1_scratch_space_destroy(ctx, scratch);
+}
+
+#undef IDX_TO_TEST
+
+void run_bppp_tests(void) {
+ test_log_exp();
+ test_norm_util_helpers();
+ test_serialize_two_points();
+ test_bppp_generators_api();
+ test_bppp_generators_fixed();
+ test_bppp_tagged_hash();
+
+ norm_arg_verify_zero_len();
+ norm_arg_test(1, 1);
+ norm_arg_test(1, 64);
+ norm_arg_test(64, 1);
+ norm_arg_test(32, 32);
+ norm_arg_test(32, 64);
+ norm_arg_test(64, 32);
+ norm_arg_test(64, 64);
+
+ norm_arg_verify_vectors();
+ norm_arg_prove_vectors();
+}
+
+#endif
diff --git a/src/modules/ecdsa_adaptor/main_impl.h b/src/modules/ecdsa_adaptor/main_impl.h
index c6d211e1a58..1e3997bd5b8 100644
--- a/src/modules/ecdsa_adaptor/main_impl.h
+++ b/src/modules/ecdsa_adaptor/main_impl.h
@@ -7,8 +7,8 @@
#ifndef SECP256K1_MODULE_ECDSA_ADAPTOR_MAIN_H
#define SECP256K1_MODULE_ECDSA_ADAPTOR_MAIN_H
-#include "include/secp256k1_ecdsa_adaptor.h"
-#include "modules/ecdsa_adaptor/dleq_impl.h"
+#include "../../../include/secp256k1_ecdsa_adaptor.h"
+#include "dleq_impl.h"
/* (R, R', s', dleq_proof) */
static int secp256k1_ecdsa_adaptor_sig_serialize(unsigned char *adaptor_sig162, secp256k1_ge *r, secp256k1_ge *rp, const secp256k1_scalar *sp, const secp256k1_scalar *dleq_proof_e, const secp256k1_scalar *dleq_proof_s) {
diff --git a/src/modules/ecdsa_adaptor/tests_impl.h b/src/modules/ecdsa_adaptor/tests_impl.h
index 37547ace85b..d0f0eb5a637 100644
--- a/src/modules/ecdsa_adaptor/tests_impl.h
+++ b/src/modules/ecdsa_adaptor/tests_impl.h
@@ -1,7 +1,7 @@
#ifndef SECP256K1_MODULE_ECDSA_ADAPTOR_TESTS_H
#define SECP256K1_MODULE_ECDSA_ADAPTOR_TESTS_H
-#include "include/secp256k1_ecdsa_adaptor.h"
+#include "../../../include/secp256k1_ecdsa_adaptor.h"
void rand_scalar(secp256k1_scalar *scalar) {
unsigned char buf32[32];
diff --git a/src/modules/ecdsa_s2c/main_impl.h b/src/modules/ecdsa_s2c/main_impl.h
index a8272720219..95cb088d8a5 100644
--- a/src/modules/ecdsa_s2c/main_impl.h
+++ b/src/modules/ecdsa_s2c/main_impl.h
@@ -7,8 +7,8 @@
#ifndef SECP256K1_MODULE_ECDSA_S2C_MAIN_H
#define SECP256K1_MODULE_ECDSA_S2C_MAIN_H
-#include "include/secp256k1.h"
-#include "include/secp256k1_ecdsa_s2c.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);
diff --git a/src/modules/ecdsa_s2c/tests_impl.h b/src/modules/ecdsa_s2c/tests_impl.h
index 1868c76b956..8f50206d0f1 100644
--- a/src/modules/ecdsa_s2c/tests_impl.h
+++ b/src/modules/ecdsa_s2c/tests_impl.h
@@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_ECDSA_S2C_TESTS_H
#define SECP256K1_MODULE_ECDSA_S2C_TESTS_H
-#include "include/secp256k1_ecdsa_s2c.h"
+#include "../../../include/secp256k1_ecdsa_s2c.h"
static void test_ecdsa_s2c_tagged_hash(void) {
unsigned char tag_data[14] = "s2c/ecdsa/data";
@@ -78,7 +78,7 @@ void run_s2c_opening_test(void) {
* 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);
+ CHECK(secp256k1_memcmp_var(output, input, sizeof(output)) == 0);
}
secp256k1_testrand256(&input[1]);
/* Set pubkey oddness tag to first bit of input[1] */
@@ -255,7 +255,7 @@ static void test_ecdsa_s2c_fixed_vectors(void) {
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_memcmp_var(test->expected_s2c_opening, opening_ser, sizeof(opening_ser)) == 0);
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, test->s2c_data, &s2c_opening) == 1);
}
}
@@ -331,7 +331,7 @@ static void test_ecdsa_anti_exfil_signer_commit(void) {
const ecdsa_s2c_test *test = &ecdsa_s2c_tests[i];
CHECK(secp256k1_ecdsa_anti_exfil_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_exfil_opening, buf, sizeof(buf)) == 0);
+ CHECK(secp256k1_memcmp_var(test->expected_s2c_exfil_opening, buf, sizeof(buf)) == 0);
}
}
@@ -397,7 +397,7 @@ static void test_ecdsa_anti_exfil(void) {
CHECK(secp256k1_ecdsa_verify(ctx, &signature, host_msg, &signer_pubkey) == 1);
CHECK(secp256k1_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 0);
CHECK(secp256k1_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, bad_nonce_contribution, &s2c_opening) == 1);
- CHECK(memcmp(&s2c_opening, &orig_opening, sizeof(s2c_opening)) != 0);
+ CHECK(secp256k1_memcmp_var(&s2c_opening, &orig_opening, sizeof(s2c_opening)) != 0);
}
}
diff --git a/src/modules/extrakeys/hsort.h b/src/modules/extrakeys/hsort.h
index 0f57227c117..5352ef1e393 100644
--- a/src/modules/extrakeys/hsort.h
+++ b/src/modules/extrakeys/hsort.h
@@ -4,8 +4,8 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
-#ifndef SECP256K1_HSORT_H_
-#define SECP256K1_HSORT_H_
+#ifndef SECP256K1_HSORT_H
+#define SECP256K1_HSORT_H
#include
#include
diff --git a/src/modules/extrakeys/hsort_impl.h b/src/modules/extrakeys/hsort_impl.h
index fcc4b10be9d..e05aefdf8f6 100644
--- a/src/modules/extrakeys/hsort_impl.h
+++ b/src/modules/extrakeys/hsort_impl.h
@@ -4,8 +4,8 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
-#ifndef SECP256K1_HSORT_IMPL_H_
-#define SECP256K1_HSORT_IMPL_H_
+#ifndef SECP256K1_HSORT_IMPL_H
+#define SECP256K1_HSORT_IMPL_H
#include "hsort.h"
@@ -23,7 +23,7 @@ static SECP256K1_INLINE size_t child2(size_t i) {
return child1(i)+1;
}
-static SECP256K1_INLINE void swap64(unsigned char *a, size_t i, size_t j, size_t stride) {
+static SECP256K1_INLINE void heap_swap64(unsigned char *a, size_t i, size_t j, size_t stride) {
unsigned char tmp[64];
VERIFY_CHECK(stride <= 64);
memcpy(tmp, a + i*stride, stride);
@@ -31,12 +31,12 @@ static SECP256K1_INLINE void swap64(unsigned char *a, size_t i, size_t j, size_t
memcpy(a + j*stride, tmp, stride);
}
-static SECP256K1_INLINE void swap(unsigned char *a, size_t i, size_t j, size_t stride) {
+static SECP256K1_INLINE void heap_swap(unsigned char *a, size_t i, size_t j, size_t stride) {
while (64 < stride) {
- swap64(a + (stride - 64), i, j, 64);
+ heap_swap64(a + (stride - 64), i, j, 64);
stride -= 64;
}
- swap64(a, i, j, stride);
+ heap_swap64(a, i, j, stride);
}
static SECP256K1_INLINE void heap_down(unsigned char *a, size_t i, size_t heap_size, size_t stride,
@@ -71,7 +71,7 @@ static SECP256K1_INLINE void heap_down(unsigned char *a, size_t i, size_t heap_s
if (child2(i) < heap_size
&& 0 <= cmp(a + child2(i)*stride, a + child1(i)*stride, cmp_data)) {
if (0 < cmp(a + child2(i)*stride, a + i*stride, cmp_data)) {
- swap(a, i, child2(i), stride);
+ heap_swap(a, i, child2(i), stride);
i = child2(i);
} else {
/* At this point we have [child2(i)] >= [child1(i)] and we have
@@ -80,7 +80,7 @@ static SECP256K1_INLINE void heap_down(unsigned char *a, size_t i, size_t heap_s
return;
}
} else if (0 < cmp(a + child1(i)*stride, a + i*stride, cmp_data)) {
- swap(a, i, child1(i), stride);
+ heap_swap(a, i, child1(i), stride);
i = child1(i);
} else {
return;
@@ -106,7 +106,7 @@ static void secp256k1_hsort(void *ptr, size_t count, size_t size,
}
for(i = count; 1 < i; --i) {
/* Extract the largest value from the heap */
- swap(ptr, 0, i-1, size);
+ heap_swap(ptr, 0, i-1, size);
/* Repair the heap condition */
heap_down(ptr, 0, i-1, size, cmp, cmp_data);
diff --git a/src/modules/extrakeys/main_impl.h b/src/modules/extrakeys/main_impl.h
index 8ed76a98afc..cadabab050e 100644
--- a/src/modules/extrakeys/main_impl.h
+++ b/src/modules/extrakeys/main_impl.h
@@ -153,28 +153,6 @@ int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const u
&& secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity;
}
-/* This struct wraps a const context pointer to satisfy the secp256k1_hsort api
- * which expects a non-const cmp_data pointer. */
-typedef struct {
- const secp256k1_context *ctx;
-} secp256k1_xonly_sort_cmp_data;
-
-static int secp256k1_xonly_sort_cmp(const void* pk1, const void* pk2, void *cmp_data) {
- return secp256k1_xonly_pubkey_cmp(((secp256k1_xonly_sort_cmp_data*)cmp_data)->ctx,
- *(secp256k1_xonly_pubkey **)pk1,
- *(secp256k1_xonly_pubkey **)pk2);
-}
-
-int secp256k1_xonly_sort(const secp256k1_context* ctx, const secp256k1_xonly_pubkey **pubkeys, size_t n_pubkeys) {
- secp256k1_xonly_sort_cmp_data cmp_data;
- VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(pubkeys != NULL);
-
- cmp_data.ctx = ctx;
- secp256k1_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), secp256k1_xonly_sort_cmp, &cmp_data);
- return 1;
-}
-
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);
@@ -304,4 +282,53 @@ int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_ke
return ret;
}
+int secp256k1_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_pubkey* pk0, const secp256k1_pubkey* pk1) {
+ unsigned char out[2][33];
+ const secp256k1_pubkey* pk[2];
+ int i;
+
+ VERIFY_CHECK(ctx != NULL);
+ pk[0] = pk0; pk[1] = pk1;
+ for (i = 0; i < 2; i++) {
+ size_t outputlen = sizeof(out[i]);
+ /* If the public key is NULL or invalid, pubkey_serialize will
+ * call the illegal_callback and return 0. In that case we will
+ * serialize the key as all zeros which is less than any valid public
+ * key. This results in consistent comparisons even if NULL or invalid
+ * pubkeys are involved and prevents edge cases such as sorting
+ * algorithms that use this function and do not terminate as a
+ * result. */
+ if (!secp256k1_ec_pubkey_serialize(ctx, out[i], &outputlen, pk[i], SECP256K1_EC_COMPRESSED)) {
+ /* Note that pubkey_serialize should already set the output to
+ * zero in that case, but it's not guaranteed by the API, we can't
+ * test it and writing a VERIFY_CHECK is more complex than
+ * explicitly memsetting (again). */
+ memset(out[i], 0, sizeof(out[i]));
+ }
+ }
+ return secp256k1_memcmp_var(out[0], out[1], sizeof(out[1]));
+}
+
+/* This struct wraps a const context pointer to satisfy the secp256k1_hsort api
+ * which expects a non-const cmp_data pointer. */
+typedef struct {
+ const secp256k1_context *ctx;
+} secp256k1_pubkey_sort_cmp_data;
+
+static int secp256k1_pubkey_sort_cmp(const void* pk1, const void* pk2, void *cmp_data) {
+ return secp256k1_pubkey_cmp(((secp256k1_pubkey_sort_cmp_data*)cmp_data)->ctx,
+ *(secp256k1_pubkey **)pk1,
+ *(secp256k1_pubkey **)pk2);
+}
+
+int secp256k1_pubkey_sort(const secp256k1_context* ctx, const secp256k1_pubkey **pubkeys, size_t n_pubkeys) {
+ secp256k1_pubkey_sort_cmp_data cmp_data;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(pubkeys != NULL);
+
+ cmp_data.ctx = ctx;
+ secp256k1_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), secp256k1_pubkey_sort_cmp, &cmp_data);
+ return 1;
+}
+
#endif
diff --git a/src/modules/extrakeys/tests_exhaustive_impl.h b/src/modules/extrakeys/tests_exhaustive_impl.h
index d4a2f5bdf40..5ecc90d50fc 100644
--- a/src/modules/extrakeys/tests_exhaustive_impl.h
+++ b/src/modules/extrakeys/tests_exhaustive_impl.h
@@ -7,8 +7,8 @@
#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
#define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
-#include "src/modules/extrakeys/main_impl.h"
#include "../../../include/secp256k1_extrakeys.h"
+#include "main_impl.h"
static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) {
secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1];
diff --git a/src/modules/extrakeys/tests_impl.h b/src/modules/extrakeys/tests_impl.h
index 4121df0c564..c4e695b4acd 100644
--- a/src/modules/extrakeys/tests_impl.h
+++ b/src/modules/extrakeys/tests_impl.h
@@ -619,14 +619,53 @@ void test_hsort(void) {
}
#undef NUM
-void test_xonly_sort_helper(secp256k1_xonly_pubkey *pk, size_t *pk_order, size_t n_pk) {
+void test_pubkey_comparison(void) {
+ unsigned char pk1_ser[33] = {
+ 0x02,
+ 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11,
+ 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23
+ };
+ const unsigned char pk2_ser[33] = {
+ 0x03,
+ 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d,
+ 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c
+ };
+ secp256k1_pubkey pk1;
+ secp256k1_pubkey pk2;
+ int ecount = 0;
+ secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
+
+ CHECK(secp256k1_ec_pubkey_parse(none, &pk1, pk1_ser, sizeof(pk1_ser)) == 1);
+ CHECK(secp256k1_ec_pubkey_parse(none, &pk2, pk2_ser, sizeof(pk2_ser)) == 1);
+
+ CHECK(secp256k1_pubkey_cmp(none, NULL, &pk2) < 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_pubkey_cmp(none, &pk1, NULL) > 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk2) < 0);
+ CHECK(secp256k1_pubkey_cmp(none, &pk2, &pk1) > 0);
+ CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk1) == 0);
+ CHECK(secp256k1_pubkey_cmp(none, &pk2, &pk2) == 0);
+ CHECK(ecount == 2);
+ memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */
+ CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk2) < 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_pubkey_cmp(none, &pk1, &pk1) == 0);
+ CHECK(ecount == 5);
+ CHECK(secp256k1_pubkey_cmp(none, &pk2, &pk1) > 0);
+ CHECK(ecount == 6);
+
+ secp256k1_context_destroy(none);
+}
+
+void test_sort_helper(secp256k1_pubkey *pk, size_t *pk_order, size_t n_pk) {
size_t i;
- const secp256k1_xonly_pubkey *pk_test[5];
+ const secp256k1_pubkey *pk_test[5];
for (i = 0; i < n_pk; i++) {
pk_test[i] = &pk[pk_order[i]];
}
- secp256k1_xonly_sort(ctx, pk_test, n_pk);
+ secp256k1_pubkey_sort(ctx, pk_test, n_pk);
for (i = 0; i < n_pk; i++) {
CHECK(secp256k1_memcmp_var(pk_test[i], &pk[i], sizeof(*pk_test[i])) == 0);
}
@@ -643,88 +682,131 @@ void permute(size_t *arr, size_t n) {
}
}
-void rand_xonly_pk(secp256k1_xonly_pubkey *pk) {
+void rand_pk(secp256k1_pubkey *pk) {
unsigned char seckey[32];
secp256k1_keypair keypair;
secp256k1_testrand256(seckey);
CHECK(secp256k1_keypair_create(ctx, &keypair, seckey) == 1);
- CHECK(secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair) == 1);
+ CHECK(secp256k1_keypair_pub(ctx, pk, &keypair) == 1);
}
-void test_xonly_sort_api(void) {
+void test_sort_api(void) {
int ecount = 0;
- secp256k1_xonly_pubkey pks[2];
- const secp256k1_xonly_pubkey *pks_ptr[2];
+ secp256k1_pubkey pks[2];
+ const secp256k1_pubkey *pks_ptr[2];
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
pks_ptr[0] = &pks[0];
pks_ptr[1] = &pks[1];
- rand_xonly_pk(&pks[0]);
- rand_xonly_pk(&pks[1]);
+ rand_pk(&pks[0]);
+ rand_pk(&pks[1]);
- CHECK(secp256k1_xonly_sort(none, pks_ptr, 2) == 1);
- CHECK(secp256k1_xonly_sort(none, NULL, 2) == 0);
+ CHECK(secp256k1_pubkey_sort(none, pks_ptr, 2) == 1);
+ CHECK(secp256k1_pubkey_sort(none, NULL, 2) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_xonly_sort(none, pks_ptr, 0) == 1);
+ CHECK(secp256k1_pubkey_sort(none, pks_ptr, 0) == 1);
/* Test illegal public keys */
memset(&pks[0], 0, sizeof(pks[0]));
- CHECK(secp256k1_xonly_sort(none, pks_ptr, 2) == 1);
+ CHECK(secp256k1_pubkey_sort(none, pks_ptr, 2) == 1);
CHECK(ecount == 2);
memset(&pks[1], 0, sizeof(pks[1]));
- CHECK(secp256k1_xonly_sort(none, pks_ptr, 2) == 1);
+ CHECK(secp256k1_pubkey_sort(none, pks_ptr, 2) == 1);
CHECK(ecount > 2);
secp256k1_context_destroy(none);
}
-void test_xonly_sort(void) {
- secp256k1_xonly_pubkey pk[5];
- unsigned char pk_ser[5][32];
+void test_sort(void) {
+ secp256k1_pubkey pk[5];
+ unsigned char pk_ser[5][33] = {
+ { 0x02, 0x08 },
+ { 0x02, 0x0b },
+ { 0x02, 0x0c },
+ { 0x03, 0x05 },
+ { 0x03, 0x0a },
+ };
int i;
size_t pk_order[5] = { 0, 1, 2, 3, 4 };
for (i = 0; i < 5; i++) {
- memset(pk_ser[i], 0, sizeof(pk_ser[i]));
- }
- pk_ser[0][0] = 5;
- pk_ser[1][0] = 8;
- pk_ser[2][0] = 0x0a;
- pk_ser[3][0] = 0x0b;
- pk_ser[4][0] = 0x0c;
- for (i = 0; i < 5; i++) {
- CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk[i], pk_ser[i]));
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pk[i], pk_ser[i], sizeof(pk_ser[i])));
}
permute(pk_order, 1);
- test_xonly_sort_helper(pk, pk_order, 1);
+ test_sort_helper(pk, pk_order, 1);
permute(pk_order, 2);
- test_xonly_sort_helper(pk, pk_order, 2);
+ test_sort_helper(pk, pk_order, 2);
permute(pk_order, 3);
- test_xonly_sort_helper(pk, pk_order, 3);
+ test_sort_helper(pk, pk_order, 3);
for (i = 0; i < count; i++) {
permute(pk_order, 4);
- test_xonly_sort_helper(pk, pk_order, 4);
+ test_sort_helper(pk, pk_order, 4);
}
for (i = 0; i < count; i++) {
permute(pk_order, 5);
- test_xonly_sort_helper(pk, pk_order, 5);
+ test_sort_helper(pk, pk_order, 5);
}
/* Check that sorting also works for random pubkeys */
for (i = 0; i < count; i++) {
int j;
- const secp256k1_xonly_pubkey *pk_ptr[5];
+ const secp256k1_pubkey *pk_ptr[5];
for (j = 0; j < 5; j++) {
- rand_xonly_pk(&pk[j]);
+ rand_pk(&pk[j]);
pk_ptr[j] = &pk[j];
}
- secp256k1_xonly_sort(ctx, pk_ptr, 5);
+ secp256k1_pubkey_sort(ctx, pk_ptr, 5);
for (j = 1; j < 5; j++) {
- CHECK(secp256k1_xonly_sort_cmp(&pk_ptr[j - 1], &pk_ptr[j], ctx) <= 0);
+ CHECK(secp256k1_pubkey_sort_cmp(&pk_ptr[j - 1], &pk_ptr[j], ctx) <= 0);
}
}
}
+/* Test vectors from BIP-MuSig2 */
+void test_sort_vectors(void) {
+ enum { N_PUBKEYS = 6 };
+ unsigned char pk_ser[N_PUBKEYS][33] = {
+ { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F,
+ 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09,
+ 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 },
+ { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34,
+ 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83,
+ 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
+ { 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18,
+ 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2,
+ 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 },
+ { 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2,
+ 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51,
+ 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 },
+ { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F,
+ 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09,
+ 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xFF },
+ { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F,
+ 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09,
+ 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 }
+ };
+ secp256k1_pubkey pubkeys[N_PUBKEYS];
+ secp256k1_pubkey *sorted[N_PUBKEYS];
+ const secp256k1_pubkey *pks_ptr[N_PUBKEYS];
+ int i;
+
+ sorted[0] = &pubkeys[3];
+ sorted[1] = &pubkeys[0];
+ sorted[2] = &pubkeys[0];
+ sorted[3] = &pubkeys[4];
+ sorted[4] = &pubkeys[1];
+ sorted[5] = &pubkeys[2];
+
+ for (i = 0; i < N_PUBKEYS; i++) {
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkeys[i], pk_ser[i], sizeof(pk_ser[i])));
+ pks_ptr[i] = &pubkeys[i];
+ }
+ CHECK(secp256k1_pubkey_sort(ctx, pks_ptr, N_PUBKEYS) == 1);
+ for (i = 0; i < N_PUBKEYS; i++) {
+ CHECK(secp256k1_memcmp_var(pks_ptr[i], sorted[i], sizeof(secp256k1_pubkey)) == 0);
+ }
+}
+
void run_extrakeys_tests(void) {
/* xonly key test cases */
test_xonly_pubkey();
@@ -738,8 +820,10 @@ void run_extrakeys_tests(void) {
test_keypair_add();
test_hsort();
- test_xonly_sort_api();
- test_xonly_sort();
+ test_pubkey_comparison();
+ test_sort_api();
+ test_sort();
+ test_sort_vectors();
}
#endif
diff --git a/src/modules/generator/Makefile.am.include b/src/modules/generator/Makefile.am.include
index 69933e999ca..4119966cc25 100644
--- a/src/modules/generator/Makefile.am.include
+++ b/src/modules/generator/Makefile.am.include
@@ -1,4 +1,6 @@
include_HEADERS += include/secp256k1_generator.h
+noinst_HEADERS += src/modules/generator/pedersen.h
+noinst_HEADERS += src/modules/generator/pedersen_impl.h
noinst_HEADERS += src/modules/generator/main_impl.h
noinst_HEADERS += src/modules/generator/tests_impl.h
if USE_BENCHMARK
diff --git a/src/modules/generator/main_impl.h b/src/modules/generator/main_impl.h
index 9217169c21b..17517847973 100644
--- a/src/modules/generator/main_impl.h
+++ b/src/modules/generator/main_impl.h
@@ -4,15 +4,38 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef SECP256K1_MODULE_GENERATOR_MAIN
-#define SECP256K1_MODULE_GENERATOR_MAIN
+#ifndef SECP256K1_MODULE_GENERATOR_MAIN_H
+#define SECP256K1_MODULE_GENERATOR_MAIN_H
#include
-#include "field.h"
-#include "group.h"
-#include "hash.h"
-#include "scalar.h"
+#include "../../field.h"
+#include "../../group.h"
+#include "../../hash.h"
+#include "../../scalar.h"
+
+#include "../generator/pedersen_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())
+ */
+static const secp256k1_generator secp256k1_generator_h_internal = {{
+ 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
+}};
+
+const secp256k1_generator *secp256k1_generator_h = &secp256k1_generator_h_internal;
+
static void secp256k1_generator_load(secp256k1_ge* ge, const secp256k1_generator* gen) {
int succeed;
@@ -219,4 +242,201 @@ int secp256k1_generator_generate_blinded(const secp256k1_context* ctx, secp256k1
return secp256k1_generator_generate_internal(ctx, gen, key32, blind32);
}
+static void secp256k1_pedersen_commitment_load(secp256k1_ge* ge, const secp256k1_pedersen_commitment* commit) {
+ secp256k1_fe fe;
+ secp256k1_fe_set_b32(&fe, &commit->data[1]);
+ secp256k1_ge_set_xquad(ge, &fe);
+ if (commit->data[0] & 1) {
+ secp256k1_ge_neg(ge, ge);
+ }
+}
+
+static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* commit, secp256k1_ge* ge) {
+ secp256k1_fe_normalize(&ge->x);
+ secp256k1_fe_get_b32(&commit->data[1], &ge->x);
+ commit->data[0] = 9 ^ secp256k1_fe_is_quad_var(&ge->y);
+}
+
+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)) {
+ return 0;
+ }
+ if (input[0] & 1) {
+ secp256k1_ge_neg(&ge, &ge);
+ }
+ secp256k1_pedersen_commitment_save(commit, &ge);
+ 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);
+ return 1;
+}
+
+/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/
+int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const secp256k1_generator* gen) {
+ secp256k1_ge genp;
+ secp256k1_gej rj;
+ secp256k1_ge r;
+ secp256k1_scalar sec;
+ int overflow;
+ int ret = 0;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(commit != NULL);
+ ARG_CHECK(blind != NULL);
+ ARG_CHECK(gen != NULL);
+ secp256k1_generator_load(&genp, gen);
+ secp256k1_scalar_set_b32(&sec, blind, &overflow);
+ if (!overflow) {
+ secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &rj, &sec, value, &genp);
+ if (!secp256k1_gej_is_infinity(&rj)) {
+ secp256k1_ge_set_gej(&r, &rj);
+ secp256k1_pedersen_commitment_save(commit, &r);
+ ret = 1;
+ }
+ secp256k1_gej_clear(&rj);
+ secp256k1_ge_clear(&r);
+ }
+ secp256k1_scalar_clear(&sec);
+ return ret;
+}
+
+/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest
+ * negative, then calculates an additional blinding value that adds to zero.
+ */
+int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *blind_out, const unsigned char * const *blinds, size_t n, size_t npositive) {
+ secp256k1_scalar acc;
+ secp256k1_scalar x;
+ size_t i;
+ int overflow;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(blind_out != NULL);
+ ARG_CHECK(blinds != NULL);
+ ARG_CHECK(npositive <= n);
+ (void) ctx;
+ secp256k1_scalar_set_int(&acc, 0);
+ for (i = 0; i < n; i++) {
+ secp256k1_scalar_set_b32(&x, blinds[i], &overflow);
+ if (overflow) {
+ return 0;
+ }
+ if (i >= npositive) {
+ secp256k1_scalar_negate(&x, &x);
+ }
+ secp256k1_scalar_add(&acc, &acc, &x);
+ }
+ secp256k1_scalar_get_b32(blind_out, &acc);
+ secp256k1_scalar_clear(&acc);
+ secp256k1_scalar_clear(&x);
+ return 1;
+}
+
+/* Takes two lists of commitments and sums the first set and subtracts the second and verifies that they sum to excess. */
+int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k1_pedersen_commitment * const* commits, size_t pcnt, const secp256k1_pedersen_commitment * const* ncommits, size_t ncnt) {
+ secp256k1_gej accj;
+ secp256k1_ge add;
+ size_t i;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(!pcnt || (commits != NULL));
+ ARG_CHECK(!ncnt || (ncommits != NULL));
+ (void) ctx;
+ secp256k1_gej_set_infinity(&accj);
+ for (i = 0; i < ncnt; i++) {
+ secp256k1_pedersen_commitment_load(&add, ncommits[i]);
+ secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
+ }
+ secp256k1_gej_neg(&accj, &accj);
+ for (i = 0; i < pcnt; i++) {
+ secp256k1_pedersen_commitment_load(&add, commits[i]);
+ secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
+ }
+ return secp256k1_gej_is_infinity(&accj);
+}
+
+int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) {
+ secp256k1_scalar sum;
+ secp256k1_scalar tmp;
+ size_t i;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(n_total == 0 || value != NULL);
+ ARG_CHECK(n_total == 0 || generator_blind != NULL);
+ ARG_CHECK(n_total == 0 || blinding_factor != NULL);
+ ARG_CHECK(n_total > n_inputs);
+ (void) ctx;
+
+ if (n_total == 0) {
+ return 1;
+ }
+
+ secp256k1_scalar_set_int(&sum, 0);
+ secp256k1_scalar_set_int(&tmp, 0);
+
+ /* Here, n_total > 0. Thus the loop runs at least once.
+ Thus we may use a do-while loop, which checks the loop
+ condition only at the end.
+
+ The do-while loop helps GCC prove that the loop runs at least
+ once and suppresses a -Wmaybe-uninitialized warning. */
+ i = 0;
+ do {
+ int overflow = 0;
+ secp256k1_scalar addend;
+ secp256k1_scalar_set_u64(&addend, value[i]); /* s = v */
+
+ secp256k1_scalar_set_b32(&tmp, generator_blind[i], &overflow);
+ if (overflow == 1) {
+ secp256k1_scalar_clear(&tmp);
+ secp256k1_scalar_clear(&addend);
+ secp256k1_scalar_clear(&sum);
+ return 0;
+ }
+ secp256k1_scalar_mul(&addend, &addend, &tmp); /* s = vr */
+
+ secp256k1_scalar_set_b32(&tmp, blinding_factor[i], &overflow);
+ if (overflow == 1) {
+ secp256k1_scalar_clear(&tmp);
+ secp256k1_scalar_clear(&addend);
+ secp256k1_scalar_clear(&sum);
+ return 0;
+ }
+ secp256k1_scalar_add(&addend, &addend, &tmp); /* s = vr + r' */
+ secp256k1_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */
+ secp256k1_scalar_add(&sum, &sum, &addend); /* sum += s */
+ secp256k1_scalar_clear(&addend);
+
+ i++;
+ } while (i < n_total);
+
+ /* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */
+ secp256k1_scalar_negate(&sum, &sum);
+ secp256k1_scalar_add(&tmp, &tmp, &sum);
+ secp256k1_scalar_get_b32(blinding_factor[n_total - 1], &tmp);
+
+ secp256k1_scalar_clear(&tmp);
+ secp256k1_scalar_clear(&sum);
+ return 1;
+}
+
#endif
diff --git a/src/modules/rangeproof/pedersen.h b/src/modules/generator/pedersen.h
similarity index 84%
rename from src/modules/rangeproof/pedersen.h
rename to src/modules/generator/pedersen.h
index 14d9920ebc4..a09f4a5e8bb 100644
--- a/src/modules/rangeproof/pedersen.h
+++ b/src/modules/generator/pedersen.h
@@ -4,12 +4,12 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_PEDERSEN_H_
-#define _SECP256K1_PEDERSEN_H_
+#ifndef SECP256K1_PEDERSEN_H
+#define SECP256K1_PEDERSEN_H
-#include "ecmult_gen.h"
-#include "group.h"
-#include "scalar.h"
+#include "../../ecmult_gen.h"
+#include "../../group.h"
+#include "../../scalar.h"
#include
diff --git a/src/modules/rangeproof/pedersen_impl.h b/src/modules/generator/pedersen_impl.h
similarity index 85%
rename from src/modules/rangeproof/pedersen_impl.h
rename to src/modules/generator/pedersen_impl.h
index 69f22e382a8..24f96bd2ccf 100644
--- a/src/modules/rangeproof/pedersen_impl.h
+++ b/src/modules/generator/pedersen_impl.h
@@ -4,18 +4,18 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
***********************************************************************/
-#ifndef _SECP256K1_PEDERSEN_IMPL_H_
-#define _SECP256K1_PEDERSEN_IMPL_H_
+#ifndef SECP256K1_PEDERSEN_IMPL_H
+#define SECP256K1_PEDERSEN_IMPL_H
#include
-#include "eckey.h"
-#include "ecmult_const.h"
-#include "ecmult_gen.h"
-#include "group.h"
-#include "field.h"
-#include "scalar.h"
-#include "util.h"
+#include "../../eckey.h"
+#include "../../ecmult_const.h"
+#include "../../ecmult_gen.h"
+#include "../../group.h"
+#include "../../field.h"
+#include "../../scalar.h"
+#include "../../util.h"
static void secp256k1_pedersen_scalar_set_u64(secp256k1_scalar *sec, uint64_t value) {
unsigned char data[32];
diff --git a/src/modules/generator/tests_impl.h b/src/modules/generator/tests_impl.h
index 068c5f39981..e81612fd597 100644
--- a/src/modules/generator/tests_impl.h
+++ b/src/modules/generator/tests_impl.h
@@ -4,18 +4,18 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef SECP256K1_MODULE_GENERATOR_TESTS
-#define SECP256K1_MODULE_GENERATOR_TESTS
+#ifndef SECP256K1_MODULE_GENERATOR_TESTS_H
+#define SECP256K1_MODULE_GENERATOR_TESTS_H
#include
#include
-#include "group.h"
-#include "scalar.h"
-#include "testrand.h"
-#include "util.h"
+#include "../../group.h"
+#include "../../scalar.h"
+#include "../../testrand.h"
+#include "../../util.h"
-#include "include/secp256k1_generator.h"
+#include "../../../include/secp256k1_generator.h"
void test_generator_api(void) {
unsigned char key[32];
@@ -134,7 +134,7 @@ void test_shallue_van_de_woestijne(void) {
shallue_van_de_woestijne(&ge, &fe);
secp256k1_ge_to_storage(&ges, &ge);
- CHECK(memcmp(&ges, &results[i * 2 + s - 2], sizeof(secp256k1_ge_storage)) == 0);
+ CHECK(secp256k1_memcmp_var(&ges, &results[i * 2 + s - 2], sizeof(secp256k1_ge_storage)) == 0);
}
}
}
@@ -188,11 +188,11 @@ void test_generator_generate(void) {
CHECK(secp256k1_generator_generate_blinded(ctx, &gen, v, s));
secp256k1_generator_load(&ge, &gen);
secp256k1_ge_to_storage(&ges, &ge);
- CHECK(memcmp(&ges, &results[i - 1], sizeof(secp256k1_ge_storage)) == 0);
+ CHECK(secp256k1_memcmp_var(&ges, &results[i - 1], sizeof(secp256k1_ge_storage)) == 0);
CHECK(secp256k1_generator_generate(ctx, &gen, v));
secp256k1_generator_load(&ge, &gen);
secp256k1_ge_to_storage(&ges, &ge);
- CHECK(memcmp(&ges, &results[i - 1], sizeof(secp256k1_ge_storage)) == 0);
+ CHECK(secp256k1_memcmp_var(&ges, &results[i - 1], sizeof(secp256k1_ge_storage)) == 0);
}
/* There is no range restriction on the value, but the blinder must be a
@@ -215,7 +215,7 @@ void test_generator_fixed_vector(void) {
CHECK(secp256k1_generator_parse(ctx, &parse, two_g));
CHECK(secp256k1_generator_serialize(ctx, result, &parse));
- CHECK(memcmp(two_g, result, 33) == 0);
+ CHECK(secp256k1_memcmp_var(two_g, result, 33) == 0);
result[0] = 0x0a;
CHECK(secp256k1_generator_parse(ctx, &parse, result));
@@ -223,11 +223,174 @@ void test_generator_fixed_vector(void) {
CHECK(!secp256k1_generator_parse(ctx, &parse, result));
}
+static void test_pedersen_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 *sttc = secp256k1_context_clone(secp256k1_context_no_precomp);
+ secp256k1_pedersen_commitment commit;
+ const secp256k1_pedersen_commitment *commit_ptr = &commit;
+ unsigned char blind[32];
+ unsigned char blind_out[32];
+ const unsigned char *blind_ptr = blind;
+ unsigned char *blind_out_ptr = blind_out;
+ uint64_t val = secp256k1_testrand32();
+ 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_error_callback(sttc, 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_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
+
+ secp256k1_testrand256(blind);
+ CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, secp256k1_generator_h) != 0);
+ CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, secp256k1_generator_h) != 0);
+ CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
+ CHECK(ecount == 0);
+ CHECK(secp256k1_pedersen_commit(sttc, &commit, blind, val, secp256k1_generator_h) == 0);
+ CHECK(ecount == 1);
+
+ CHECK(secp256k1_pedersen_commit(sign, NULL, blind, val, secp256k1_generator_h) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_pedersen_commit(sign, &commit, NULL, val, secp256k1_generator_h) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, NULL) == 0);
+ CHECK(ecount == 4);
+
+ CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0);
+ CHECK(ecount == 5);
+ CHECK(secp256k1_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0);
+ CHECK(ecount == 6);
+ CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0);
+ CHECK(ecount == 7);
+ CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0);
+ CHECK(ecount == 7);
+
+ CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
+ CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0);
+ CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0);
+ CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0);
+ CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0);
+ CHECK(ecount == 7);
+ CHECK(secp256k1_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0);
+ CHECK(ecount == 8);
+ CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0);
+ CHECK(ecount == 9);
+
+ CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0);
+ CHECK(ecount == 9);
+ CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0);
+ CHECK(ecount == 10);
+ CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0);
+ CHECK(ecount == 11);
+ CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0);
+ CHECK(ecount == 12);
+ CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0);
+ CHECK(ecount == 13);
+ CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0);
+ CHECK(ecount == 14);
+
+ secp256k1_context_destroy(none);
+ secp256k1_context_destroy(sign);
+ secp256k1_context_destroy(vrfy);
+ secp256k1_context_destroy(sttc);
+}
+
+static void test_pedersen(void) {
+ secp256k1_pedersen_commitment commits[19];
+ const secp256k1_pedersen_commitment *cptr[19];
+ unsigned char blinds[32*19];
+ const unsigned char *bptr[19];
+ secp256k1_scalar s;
+ uint64_t values[19];
+ int64_t totalv;
+ int i;
+ int inputs;
+ int outputs;
+ int total;
+ inputs = (secp256k1_testrand32() & 7) + 1;
+ outputs = (secp256k1_testrand32() & 7) + 2;
+ total = inputs + outputs;
+ for (i = 0; i < 19; i++) {
+ cptr[i] = &commits[i];
+ bptr[i] = &blinds[i * 32];
+ }
+ totalv = 0;
+ for (i = 0; i < inputs; i++) {
+ values[i] = secp256k1_testrandi64(0, INT64_MAX - totalv);
+ totalv += values[i];
+ }
+ for (i = 0; i < outputs - 1; i++) {
+ values[i + inputs] = secp256k1_testrandi64(0, totalv);
+ totalv -= values[i + inputs];
+ }
+ values[total - 1] = totalv;
+
+ for (i = 0; i < total - 1; i++) {
+ random_scalar_order(&s);
+ secp256k1_scalar_get_b32(&blinds[i * 32], &s);
+ }
+ CHECK(secp256k1_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs));
+ for (i = 0; i < total; i++) {
+ CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
+ }
+ CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs));
+ CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs));
+ if (inputs > 0 && values[0] > 0) {
+ CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs - 1, &cptr[inputs], outputs));
+ }
+ random_scalar_order(&s);
+ for (i = 0; i < 4; i++) {
+ secp256k1_scalar_get_b32(&blinds[i * 32], &s);
+ }
+ values[0] = INT64_MAX;
+ values[1] = 0;
+ values[2] = 1;
+ for (i = 0; i < 3; i++) {
+ CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
+ }
+ CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1));
+ CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1));
+}
+
+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(secp256k1_memcmp_var(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_generator_tests(void) {
+ int i;
+
test_shallue_van_de_woestijne();
test_generator_fixed_vector();
test_generator_api();
test_generator_generate();
+ test_pedersen_api();
+ test_pedersen_commitment_fixed_vector();
+ for (i = 0; i < count / 2 + 1; i++) {
+ test_pedersen();
+ }
}
#endif
diff --git a/src/modules/musig/keyagg.h b/src/modules/musig/keyagg.h
index a56dc9efebd..9ccea847e4f 100644
--- a/src/modules/musig/keyagg.h
+++ b/src/modules/musig/keyagg.h
@@ -16,7 +16,9 @@
typedef struct {
secp256k1_ge pk;
- secp256k1_fe second_pk_x;
+ /* If there is no "second" public key, second_pk is set to the point at
+ * infinity */
+ secp256k1_ge second_pk;
unsigned char pk_hash[32];
/* tweak is identical to value tacc[v] in the specification. */
secp256k1_scalar tweak;
@@ -25,13 +27,23 @@ typedef struct {
int parity_acc;
} secp256k1_keyagg_cache_internal;
-/* Requires that the saved point is not infinity */
+/* Save and load points to and from byte arrays, similar to
+ * secp256k1_pubkey_{save,load}. */
static void secp256k1_point_save(unsigned char *data, secp256k1_ge *ge);
+/* In contrast to pubkey_load, point_load does not attempt to check that data
+ * has been initialized, since it is assumed that this check already happened
+ * (e.g. by comparing magic bytes) */
static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data);
+/* point_save_ext and point_load_ext are identical to point_save and point_load
+ * except that they allow saving and loading the point at infinity */
+static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge);
+
+static void secp256k1_point_load_ext(secp256k1_ge *ge, const unsigned char *data);
+
static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache);
-static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_fe *x);
+static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk);
#endif
diff --git a/src/modules/musig/keyagg_impl.h b/src/modules/musig/keyagg_impl.h
index 33cdec2a99b..114c831abeb 100644
--- a/src/modules/musig/keyagg_impl.h
+++ b/src/modules/musig/keyagg_impl.h
@@ -47,13 +47,30 @@ static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data) {
}
}
+static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge) {
+ if (secp256k1_ge_is_infinity(ge)) {
+ memset(data, 0, 64);
+ } else {
+ secp256k1_point_save(data, ge);
+ }
+}
+
+static void secp256k1_point_load_ext(secp256k1_ge *ge, const unsigned char *data) {
+ unsigned char zeros[64] = { 0 };
+ if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) {
+ secp256k1_ge_set_infinity(ge);
+ } else {
+ secp256k1_point_load(ge, data);
+ }
+}
+
static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf };
/* A keyagg cache consists of
* - 4 byte magic set during initialization to allow detecting an uninitialized
* object.
* - 64 byte aggregate (and potentially tweaked) public key
- * - 32 byte X-coordinate of "second" public key (0 if not present)
+ * - 64 byte "second" public key (set to the point at infinity if not present)
* - 32 byte hash of all public keys
* - 1 byte the parity of the internal key (if tweaked, otherwise 0)
* - 32 byte tweak
@@ -65,8 +82,8 @@ static void secp256k1_keyagg_cache_save(secp256k1_musig_keyagg_cache *cache, sec
ptr += 4;
secp256k1_point_save(ptr, &cache_i->pk);
ptr += 64;
- secp256k1_fe_get_b32(ptr, &cache_i->second_pk_x);
- ptr += 32;
+ secp256k1_point_save_ext(ptr, &cache_i->second_pk);
+ ptr += 64;
memcpy(ptr, cache_i->pk_hash, 32);
ptr += 32;
*ptr = cache_i->parity_acc;
@@ -80,8 +97,8 @@ static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_k
ptr += 4;
secp256k1_point_load(&cache_i->pk, ptr);
ptr += 64;
- secp256k1_fe_set_b32(&cache_i->second_pk_x, ptr);
- ptr += 32;
+ secp256k1_point_load_ext(&cache_i->second_pk, ptr);
+ ptr += 64;
memcpy(cache_i->pk_hash, ptr, 32);
ptr += 32;
cache_i->parity_acc = *ptr & 1;
@@ -107,17 +124,19 @@ static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) {
}
/* Computes pk_hash = tagged_hash(pk[0], ..., pk[np-1]) */
-static int secp256k1_musig_compute_pk_hash(const secp256k1_context *ctx, unsigned char *pk_hash, const secp256k1_xonly_pubkey * const* pk, size_t np) {
+static int secp256k1_musig_compute_pk_hash(const secp256k1_context *ctx, unsigned char *pk_hash, const secp256k1_pubkey * const* pk, size_t np) {
secp256k1_sha256 sha;
size_t i;
secp256k1_musig_keyagglist_sha256(&sha);
for (i = 0; i < np; i++) {
- unsigned char ser[32];
- if (!secp256k1_xonly_pubkey_serialize(ctx, ser, pk[i])) {
+ unsigned char ser[33];
+ size_t ser_len = sizeof(ser);
+ if (!secp256k1_ec_pubkey_serialize(ctx, ser, &ser_len, pk[i], SECP256K1_EC_COMPRESSED)) {
return 0;
}
- secp256k1_sha256_write(&sha, ser, 32);
+ VERIFY_CHECK(ser_len == sizeof(ser));
+ secp256k1_sha256_write(&sha, ser, sizeof(ser));
}
secp256k1_sha256_finalize(&sha, pk_hash);
return 1;
@@ -140,52 +159,65 @@ static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) {
}
/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and
- * tagged_hash(pk_hash, x) where pk_hash is the hash of public keys otherwise.
- * second_pk_x can be 0 in case there is no second_pk. Assumes both field
- * elements x and second_pk_x are normalized. */
-static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pk_hash, const secp256k1_fe *x, const secp256k1_fe *second_pk_x) {
+ * otherwise tagged_hash(pk_hash, x) where pk_hash is the hash of public keys.
+ * second_pk is the point at infinity in case there is no second_pk. Assumes
+ * that pk is not the point at infinity and that the coordinates of pk and
+ * second_pk are normalized. */
+static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pk_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) {
secp256k1_sha256 sha;
- unsigned char buf[32];
- if (secp256k1_fe_cmp_var(x, second_pk_x) == 0) {
+ VERIFY_CHECK(!secp256k1_ge_is_infinity(pk));
+#ifdef VERIFY
+ VERIFY_CHECK(pk->x.normalized && pk->y.normalized);
+ VERIFY_CHECK(secp256k1_ge_is_infinity(second_pk) || (second_pk->x.normalized && second_pk->y.normalized));
+#endif
+
+ if (!secp256k1_ge_is_infinity(second_pk)
+ && secp256k1_fe_equal(&pk->x, &second_pk->x)
+ && secp256k1_fe_is_odd(&pk->y) == secp256k1_fe_is_odd(&second_pk->y)) {
secp256k1_scalar_set_int(r, 1);
} else {
+ unsigned char buf[33];
+ size_t buflen = sizeof(buf);
+ int ret;
secp256k1_musig_keyaggcoef_sha256(&sha);
secp256k1_sha256_write(&sha, pk_hash, 32);
- secp256k1_fe_get_b32(buf, x);
- secp256k1_sha256_write(&sha, buf, 32);
+ ret = secp256k1_eckey_pubkey_serialize(pk, buf, &buflen, 1);
+ /* Serialization does not fail since the pk is not the point at infinity
+ * (according to this function's precondition). */
+ VERIFY_CHECK(ret && buflen == sizeof(buf));
+ secp256k1_sha256_write(&sha, buf, sizeof(buf));
secp256k1_sha256_finalize(&sha, buf);
secp256k1_scalar_set_b32(r, buf, NULL);
}
-
}
/* Assumes both field elements x and second_pk_x are normalized. */
-static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_fe *x) {
- secp256k1_musig_keyaggcoef_internal(r, cache_i->pk_hash, x, &cache_i->second_pk_x);
+static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) {
+ secp256k1_musig_keyaggcoef_internal(r, cache_i->pk_hash, pk, &cache_i->second_pk);
}
typedef struct {
const secp256k1_context *ctx;
/* pk_hash is the hash of the public keys */
unsigned char pk_hash[32];
- const secp256k1_xonly_pubkey * const* pks;
- secp256k1_fe second_pk_x;
+ const secp256k1_pubkey * const* pks;
+ secp256k1_ge second_pk;
} secp256k1_musig_pubkey_agg_ecmult_data;
/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */
static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
secp256k1_musig_pubkey_agg_ecmult_data *ctx = (secp256k1_musig_pubkey_agg_ecmult_data *) data;
int ret;
- ret = secp256k1_xonly_pubkey_load(ctx->ctx, pt, ctx->pks[idx]);
+ ret = secp256k1_pubkey_load(ctx->ctx, pt, ctx->pks[idx]);
/* pubkey_load can't fail because the same pks have already been loaded in
* `musig_compute_pk_hash` (and we test this). */
VERIFY_CHECK(ret);
- secp256k1_musig_keyaggcoef_internal(sc, ctx->pk_hash, &pt->x, &ctx->second_pk_x);
+ secp256k1_musig_keyaggcoef_internal(sc, ctx->pk_hash, pt, &ctx->second_pk);
return 1;
}
-int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_xonly_pubkey * const* pubkeys, size_t n_pubkeys) {
+int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_pubkey * const* pubkeys, size_t n_pubkeys) {
secp256k1_musig_pubkey_agg_ecmult_data ecmult_data;
secp256k1_gej pkj;
secp256k1_ge pkp;
@@ -201,15 +233,15 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_s
ecmult_data.ctx = ctx;
ecmult_data.pks = pubkeys;
- /* No point on the curve has an X coordinate equal to 0 */
- secp256k1_fe_set_int(&ecmult_data.second_pk_x, 0);
+
+ secp256k1_ge_set_infinity(&ecmult_data.second_pk);
for (i = 1; i < n_pubkeys; i++) {
if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) {
- secp256k1_ge pt;
- if (!secp256k1_xonly_pubkey_load(ctx, &pt, pubkeys[i])) {
+ secp256k1_ge pk;
+ if (!secp256k1_pubkey_load(ctx, &pk, pubkeys[i])) {
return 0;
}
- ecmult_data.second_pk_x = pt.x;
+ ecmult_data.second_pk = pk;
break;
}
}
@@ -232,7 +264,7 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_s
if (keyagg_cache != NULL) {
secp256k1_keyagg_cache_internal cache_i = { 0 };
cache_i.pk = pkp;
- cache_i.second_pk_x = ecmult_data.second_pk_x;
+ cache_i.second_pk = ecmult_data.second_pk;
memcpy(cache_i.pk_hash, ecmult_data.pk_hash, sizeof(cache_i.pk_hash));
secp256k1_keyagg_cache_save(keyagg_cache, &cache_i);
}
diff --git a/src/modules/musig/main_impl.h b/src/modules/musig/main_impl.h
index 53a62979443..e69afed5fd2 100644
--- a/src/modules/musig/main_impl.h
+++ b/src/modules/musig/main_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef SECP256K1_MODULE_MUSIG_MAIN
-#define SECP256K1_MODULE_MUSIG_MAIN
+#ifndef SECP256K1_MODULE_MUSIG_MAIN_H
+#define SECP256K1_MODULE_MUSIG_MAIN_H
#include "keyagg_impl.h"
#include "session_impl.h"
diff --git a/src/modules/musig/musig.md b/src/modules/musig/musig.md
index 814cdc74638..44b0de4f29f 100644
--- a/src/modules/musig/musig.md
+++ b/src/modules/musig/musig.md
@@ -23,16 +23,16 @@ Therefore, users of the musig module must take great care to make sure of the fo
# Key Aggregation and (Taproot) Tweaking
Given a set of public keys, the aggregate public key is computed with `secp256k1_musig_pubkey_agg`.
-A (Taproot) tweak can be added to the resulting public key with `secp256k1_xonly_pubkey_tweak_add`.
+A (Taproot) tweak can be added to the resulting public key with `secp256k1_xonly_pubkey_tweak_add` and a plain tweak can be added with `secp256k1_ec_pubkey_tweak_add`.
# Signing
This is covered by `examples/musig.c`.
Essentially, the protocol proceeds in the following steps:
-1. Generate a keypair with `secp256k1_keypair_create` and obtain the xonly public key with `secp256k1_keypair_xonly_pub`.
-2. Call `secp256k1_musig_pubkey_agg` with the xonly pubkeys of all participants.
-3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_tweak_add`.
+1. Generate a keypair with `secp256k1_keypair_create` and obtain the public key with `secp256k1_keypair_pub`.
+2. Call `secp256k1_musig_pubkey_agg` with the pubkeys of all participants.
+3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_xonly_tweak_add` and a plain tweak with `secp256k1_musig_pubkey_ec_tweak_add`.
4. Generate a pair of secret and public nonce with `secp256k1_musig_nonce_gen` and send the public nonce to the other signers.
5. Someone (not necessarily the signer) aggregates the public nonce with `secp256k1_musig_nonce_agg` and sends it to the signers.
6. Process the aggregate nonce with `secp256k1_musig_nonce_process`.
@@ -42,10 +42,10 @@ Essentially, the protocol proceeds in the following steps:
The aggregate signature can be verified with `secp256k1_schnorrsig_verify`.
-Note that steps 1 to 6 can happen before the message to be signed is known to the signers.
+Note that steps 1 to 5 can happen before the message to be signed is known to the signers.
Therefore, the communication round to exchange nonces can be viewed as a pre-processing step that is run whenever convenient to the signers.
This disables some of the defense-in-depth measures that may protect against API misuse in some cases.
-Similarly, the API supports an alternative protocol flow where generating the aggregate key (steps 1 to 3) is allowed to happen after exchanging nonces (steps 4 to 6).
+Similarly, the API supports an alternative protocol flow where generating the aggregate key (steps 1 to 3) is allowed to happen after exchanging nonces (steps 4 to 5).
# Verification
diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h
index 88e27e174a9..d2d400fe74a 100644
--- a/src/modules/musig/session_impl.h
+++ b/src/modules/musig/session_impl.h
@@ -22,17 +22,19 @@
static const unsigned char secp256k1_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 };
-static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, secp256k1_scalar *k) {
+static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, const secp256k1_scalar *k, secp256k1_ge *pk) {
memcpy(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4);
secp256k1_scalar_get_b32(&secnonce->data[4], &k[0]);
secp256k1_scalar_get_b32(&secnonce->data[36], &k[1]);
+ secp256k1_point_save(&secnonce->data[68], pk);
}
-static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_musig_secnonce *secnonce) {
+static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_ge *pk, secp256k1_musig_secnonce *secnonce) {
int is_zero;
ARG_CHECK(secp256k1_memcmp_var(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4) == 0);
secp256k1_scalar_set_b32(&k[0], &secnonce->data[4], NULL);
secp256k1_scalar_set_b32(&k[1], &secnonce->data[36], NULL);
+ secp256k1_point_load(pk, &secnonce->data[68]);
/* We make very sure that the nonce isn't invalidated by checking the values
* in addition to the magic. */
is_zero = secp256k1_scalar_is_zero(&k[0]) & secp256k1_scalar_is_zero(&k[1]);
@@ -44,16 +46,18 @@ static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1
/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */
static void secp256k1_musig_secnonce_invalidate(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, int flag) {
secp256k1_memczero(secnonce->data, sizeof(secnonce->data), flag);
- /* The flag argument is usually classified. So, above code makes the magic
- * classified. However, we need the magic to be declassified to be able to
- * compare it during secnonce_load. */
+ /* The flag argument is usually classified. So, the line above makes the
+ * magic and public key classified. However, we need both to be
+ * declassified. Note that we don't declassify the entire object, because if
+ * flag is 0, then k[0] and k[1] have not been zeroed. */
secp256k1_declassify(ctx, secnonce->data, sizeof(secp256k1_musig_secnonce_magic));
+ secp256k1_declassify(ctx, &secnonce->data[68], 64);
}
static const unsigned char secp256k1_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 };
-/* Requires that none of the provided group elements is infinity. Works for both
- * musig_pubnonce and musig_aggnonce. */
+/* Saves two group elements into a pubnonce. Requires that none of the provided
+ * group elements is infinity. */
static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, secp256k1_ge* ge) {
int i;
memcpy(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4);
@@ -62,8 +66,8 @@ static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, secp2
}
}
-/* Works for both musig_pubnonce and musig_aggnonce. Returns 1 unless the nonce
- * wasn't properly initialized */
+/* Loads two group elements from a pubnonce. Returns 1 unless the nonce wasn't
+ * properly initialized */
static int secp256k1_musig_pubnonce_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_musig_pubnonce* nonce) {
int i;
@@ -74,12 +78,24 @@ static int secp256k1_musig_pubnonce_load(const secp256k1_context* ctx, secp256k1
return 1;
}
+static const unsigned char secp256k1_musig_aggnonce_magic[4] = { 0xa8, 0xb7, 0xe4, 0x67 };
+
static void secp256k1_musig_aggnonce_save(secp256k1_musig_aggnonce* nonce, secp256k1_ge* ge) {
- secp256k1_musig_pubnonce_save((secp256k1_musig_pubnonce *) nonce, ge);
+ int i;
+ memcpy(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4);
+ for (i = 0; i < 2; i++) {
+ secp256k1_point_save_ext(&nonce->data[4 + 64*i], &ge[i]);
+ }
}
static int secp256k1_musig_aggnonce_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_musig_aggnonce* nonce) {
- return secp256k1_musig_pubnonce_load(ctx, ge, (secp256k1_musig_pubnonce *) nonce);
+ int i;
+
+ ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4) == 0);
+ for (i = 0; i < 2; i++) {
+ secp256k1_point_load_ext(&ge[i], &nonce->data[4 + 64*i]);
+ }
+ return 1;
}
static const unsigned char secp256k1_musig_session_cache_magic[4] = { 0x9d, 0xed, 0xe9, 0x17 };
@@ -180,17 +196,43 @@ int secp256k1_musig_pubnonce_parse(const secp256k1_context* ctx, secp256k1_musig
return 0;
}
}
- /* The group elements can not be infinity because they were just parsed */
secp256k1_musig_pubnonce_save(nonce, ge);
return 1;
}
int secp256k1_musig_aggnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_aggnonce* nonce) {
- return secp256k1_musig_pubnonce_serialize(ctx, out66, (secp256k1_musig_pubnonce*) nonce);
+ secp256k1_ge ge[2];
+ int i;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(out66 != NULL);
+ memset(out66, 0, 66);
+ ARG_CHECK(nonce != NULL);
+
+ if (!secp256k1_musig_aggnonce_load(ctx, ge, nonce)) {
+ return 0;
+ }
+ for (i = 0; i < 2; i++) {
+ secp256k1_ge_serialize_ext(&out66[33*i], &ge[i]);
+ }
+ return 1;
}
int secp256k1_musig_aggnonce_parse(const secp256k1_context* ctx, secp256k1_musig_aggnonce* nonce, const unsigned char *in66) {
- return secp256k1_musig_pubnonce_parse(ctx, (secp256k1_musig_pubnonce*) nonce, in66);
+ secp256k1_ge ge[2];
+ int i;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(nonce != NULL);
+ ARG_CHECK(in66 != NULL);
+
+ for (i = 0; i < 2; i++) {
+ if (!secp256k1_ge_parse_ext(&ge[i], &in66[33*i])) {
+ return 0;
+ }
+ }
+ secp256k1_musig_aggnonce_save(nonce, ge);
+ return 1;
}
int secp256k1_musig_partial_sig_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_sig* sig) {
@@ -226,53 +268,73 @@ static int secp256k1_xonly_ge_serialize(unsigned char *output32, secp256k1_ge *g
return 1;
}
-static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_id, const unsigned char *msg32, const unsigned char *key32, const unsigned char *agg_pk32, const unsigned char *extra_input32) {
+/* Write optional inputs into the hash */
+static void secp256k1_nonce_function_musig_helper(secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) {
+ unsigned char zero[7] = { 0 };
+ /* The spec requires length prefixes to be between 1 and 8 bytes
+ * (inclusive) */
+ VERIFY_CHECK(prefix_size <= 8);
+ /* Since the length of all input data fits in a byte, we can always pad the
+ * length prefix with prefix_size - 1 zero bytes. */
+ secp256k1_sha256_write(sha, zero, prefix_size - 1);
+ if (data != NULL) {
+ secp256k1_sha256_write(sha, &len, 1);
+ secp256k1_sha256_write(sha, data, len);
+ } else {
+ len = 0;
+ secp256k1_sha256_write(sha, &len, 1);
+ }
+}
+
+static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_id, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) {
secp256k1_sha256 sha;
- unsigned char seed[32];
+ unsigned char rand[32];
unsigned char i;
- enum { n_extra_in = 4 };
- const unsigned char *extra_in[n_extra_in];
+ unsigned char msg_present;
- /* TODO: this doesn't have the same sidechannel resistance as the BIP340
- * nonce function because the seckey feeds directly into SHA. */
+ if (seckey32 != NULL) {
+ secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/aux", sizeof("MuSig/aux") - 1);
+ secp256k1_sha256_write(&sha, session_id, 32);
+ secp256k1_sha256_finalize(&sha, rand);
+ for (i = 0; i < 32; i++) {
+ rand[i] ^= seckey32[i];
+ }
+ } else {
+ memcpy(rand, session_id, sizeof(rand));
+ }
/* Subtract one from `sizeof` to avoid hashing the implicit null byte */
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/nonce", sizeof("MuSig/nonce") - 1);
- secp256k1_sha256_write(&sha, session_id, 32);
- extra_in[0] = msg32;
- extra_in[1] = key32;
- extra_in[2] = agg_pk32;
- extra_in[3] = extra_input32;
- for (i = 0; i < n_extra_in; i++) {
- unsigned char len;
- if (extra_in[i] != NULL) {
- len = 32;
- secp256k1_sha256_write(&sha, &len, 1);
- secp256k1_sha256_write(&sha, extra_in[i], 32);
- } else {
- len = 0;
- secp256k1_sha256_write(&sha, &len, 1);
- }
+ secp256k1_sha256_write(&sha, rand, sizeof(rand));
+ secp256k1_nonce_function_musig_helper(&sha, 1, pk33, 33);
+ secp256k1_nonce_function_musig_helper(&sha, 1, agg_pk32, 32);
+ msg_present = msg32 != NULL;
+ secp256k1_sha256_write(&sha, &msg_present, 1);
+ if (msg_present) {
+ secp256k1_nonce_function_musig_helper(&sha, 8, msg32, 32);
}
- secp256k1_sha256_finalize(&sha, seed);
+ secp256k1_nonce_function_musig_helper(&sha, 4, extra_input32, 32);
for (i = 0; i < 2; i++) {
unsigned char buf[32];
- secp256k1_sha256_initialize(&sha);
- secp256k1_sha256_write(&sha, seed, 32);
- secp256k1_sha256_write(&sha, &i, sizeof(i));
- secp256k1_sha256_finalize(&sha, buf);
+ secp256k1_sha256 sha_tmp = sha;
+ secp256k1_sha256_write(&sha_tmp, &i, 1);
+ secp256k1_sha256_finalize(&sha_tmp, buf);
secp256k1_scalar_set_b32(&k[i], buf, NULL);
}
}
-int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *session_id32, const unsigned char *seckey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) {
+int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *session_id32, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) {
secp256k1_keyagg_cache_internal cache_i;
secp256k1_scalar k[2];
secp256k1_ge nonce_pt[2];
int i;
- unsigned char pk_ser[32];
- unsigned char *pk_ser_ptr = NULL;
+ unsigned char pk_ser[33];
+ size_t pk_ser_len = sizeof(pk_ser);
+ unsigned char aggpk_ser[32];
+ unsigned char *aggpk_ser_ptr = NULL;
+ secp256k1_ge pk;
+ int pk_serialize_success;
int ret = 1;
VERIFY_CHECK(ctx != NULL);
@@ -281,6 +343,7 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn
ARG_CHECK(pubnonce != NULL);
memset(pubnonce, 0, sizeof(*pubnonce));
ARG_CHECK(session_id32 != NULL);
+ ARG_CHECK(pubkey != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
if (seckey == NULL) {
/* Check in constant time that the session_id is not 0 as a
@@ -305,16 +368,24 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
return 0;
}
- ret_tmp = secp256k1_xonly_ge_serialize(pk_ser, &cache_i.pk);
+ ret_tmp = secp256k1_xonly_ge_serialize(aggpk_ser, &cache_i.pk);
/* Serialization can not fail because the loaded point can not be infinity. */
VERIFY_CHECK(ret_tmp);
- pk_ser_ptr = pk_ser;
+ aggpk_ser_ptr = aggpk_ser;
}
- secp256k1_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser_ptr, extra_input32);
+ if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) {
+ return 0;
+ }
+ pk_serialize_success = secp256k1_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, SECP256K1_EC_COMPRESSED);
+ /* A pubkey cannot be the point at infinity */
+ VERIFY_CHECK(pk_serialize_success);
+ VERIFY_CHECK(pk_ser_len == sizeof(pk_ser));
+
+ secp256k1_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32);
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0]));
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1]));
VERIFY_CHECK(!secp256k1_scalar_eq(&k[0], &k[1]));
- secp256k1_musig_secnonce_save(secnonce, k);
+ secp256k1_musig_secnonce_save(secnonce, k, &pk);
secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret);
for (i = 0; i < 2; i++) {
@@ -361,12 +432,7 @@ int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggn
return 0;
}
for (i = 0; i < 2; i++) {
- if (secp256k1_gej_is_infinity(&aggnonce_ptj[i])) {
- /* Set to G according to the specification */
- aggnonce_pt[i] = secp256k1_ge_const_g;
- } else {
- secp256k1_ge_set_gej(&aggnonce_pt[i], &aggnonce_ptj[i]);
- }
+ secp256k1_ge_set_gej(&aggnonce_pt[i], &aggnonce_ptj[i]);
}
secp256k1_musig_aggnonce_save(aggnonce, aggnonce_pt);
return 1;
@@ -380,11 +446,7 @@ static int secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k1
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"MuSig/noncecoef", sizeof("MuSig/noncecoef") - 1);
for (i = 0; i < 2; i++) {
- size_t size;
- if (!secp256k1_eckey_pubkey_serialize(&aggnonce[i], buf, &size, 1)) {
- return 0;
- }
- VERIFY_CHECK(size == sizeof(buf));
+ secp256k1_ge_serialize_ext(buf, &aggnonce[i]);
secp256k1_sha256_write(&sha, buf, sizeof(buf));
}
secp256k1_sha256_write(&sha, agg_pk32, 32);
@@ -398,6 +460,7 @@ static int secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigne
secp256k1_ge fin_nonce_pt;
secp256k1_gej fin_nonce_ptj;
secp256k1_ge aggnonce[2];
+ int ret;
secp256k1_ge_set_gej(&aggnonce[0], &aggnoncej[0]);
secp256k1_ge_set_gej(&aggnonce[1], &aggnoncej[1]);
@@ -406,13 +469,16 @@ static int secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigne
}
/* fin_nonce = aggnonce[0] + b*aggnonce[1] */
secp256k1_scalar_set_b32(b, noncehash, NULL);
+ secp256k1_gej_set_infinity(&fin_nonce_ptj);
secp256k1_ecmult(&fin_nonce_ptj, &aggnoncej[1], b, NULL);
- secp256k1_gej_add_ge(&fin_nonce_ptj, &fin_nonce_ptj, &aggnonce[0]);
+ secp256k1_gej_add_ge_var(&fin_nonce_ptj, &fin_nonce_ptj, &aggnonce[0], NULL);
secp256k1_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj);
- if (!secp256k1_xonly_ge_serialize(fin_nonce, &fin_nonce_pt)) {
- /* unreachable with overwhelming probability */
- return 0;
+ if (secp256k1_ge_is_infinity(&fin_nonce_pt)) {
+ fin_nonce_pt = secp256k1_ge_const_g;
}
+ ret = secp256k1_xonly_ge_serialize(fin_nonce, &fin_nonce_pt);
+ /* Can't fail since fin_nonce_pt is not infinity */
+ VERIFY_CHECK(ret);
secp256k1_fe_normalize_var(&fin_nonce_pt.y);
*fin_nonce_parity = secp256k1_fe_is_odd(&fin_nonce_pt.y);
return 1;
@@ -471,7 +537,7 @@ int secp256k1_musig_nonce_process(const secp256k1_context* ctx, secp256k1_musig_
return 1;
}
-void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *k) {
+static void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *k) {
secp256k1_scalar_clear(sk);
secp256k1_scalar_clear(&k[0]);
secp256k1_scalar_clear(&k[1]);
@@ -479,7 +545,7 @@ void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *
int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_partial_sig *partial_sig, secp256k1_musig_secnonce *secnonce, const secp256k1_keypair *keypair, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
secp256k1_scalar sk;
- secp256k1_ge pk;
+ secp256k1_ge pk, keypair_pk;
secp256k1_scalar k[2];
secp256k1_scalar mu, s;
secp256k1_keyagg_cache_internal cache_i;
@@ -490,7 +556,7 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p
ARG_CHECK(secnonce != NULL);
/* Fails if the magic doesn't match */
- ret = secp256k1_musig_secnonce_load(ctx, k, secnonce);
+ ret = secp256k1_musig_secnonce_load(ctx, k, &pk, secnonce);
/* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls
* of this function to fail */
memset(secnonce, 0, sizeof(*secnonce));
@@ -504,35 +570,30 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p
ARG_CHECK(keyagg_cache != NULL);
ARG_CHECK(session != NULL);
- if (!secp256k1_keypair_load(ctx, &sk, &pk, keypair)) {
+ if (!secp256k1_keypair_load(ctx, &sk, &keypair_pk, keypair)) {
secp256k1_musig_partial_sign_clear(&sk, k);
return 0;
}
+ ARG_CHECK(secp256k1_fe_equal_var(&pk.x, &keypair_pk.x)
+ && secp256k1_fe_equal_var(&pk.y, &keypair_pk.y));
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
secp256k1_musig_partial_sign_clear(&sk, k);
return 0;
}
secp256k1_fe_normalize_var(&pk.y);
- /* The specification requires that the secret key is multiplied by
- * g[v]*g*gp. All factors are -1 or 1. The value g[v] is -1 iff
- * secp256k1_fe_is_odd(&cache_i.pk.y)), g is is -1 iff parity_acc is 1 and
- * gp is -1 if secp256k1_fe_is_odd(&pk.y). Therefore, multiplying by
- * g[v]*g*gp is equivalent to negating if
- * secp256k1_fe_is_odd(&cache_i.pk.y))
- * XOR cache_i.parity_acc
- * XOR secp256k1_fe_is_odd(&pk.y).
- */
+ /* Negate sk if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc.
+ * This corresponds to the line "Let d = gâ‹…gaccâ‹…d' mod n" in the
+ * specification. */
if ((secp256k1_fe_is_odd(&cache_i.pk.y)
- != cache_i.parity_acc)
- != secp256k1_fe_is_odd(&pk.y)) {
+ != cache_i.parity_acc)) {
secp256k1_scalar_negate(&sk, &sk);
}
/* Multiply KeyAgg coefficient */
secp256k1_fe_normalize_var(&pk.x);
/* TODO Cache mu */
- secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk.x);
+ secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk);
secp256k1_scalar_mul(&sk, &sk, &mu);
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
@@ -555,7 +616,7 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p
return 1;
}
-int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_xonly_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
+int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
secp256k1_keyagg_cache_internal cache_i;
secp256k1_musig_session_internal session_i;
secp256k1_scalar mu, e, s;
@@ -585,7 +646,7 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2
secp256k1_ecmult(&rj, &rj, &session_i.noncecoef, NULL);
secp256k1_gej_add_ge_var(&rj, &rj, &nonce_pt[0], NULL);
- if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) {
+ if (!secp256k1_pubkey_load(ctx, &pkp, pubkey)) {
return 0;
}
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
@@ -594,14 +655,12 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2
/* Multiplying the challenge by the KeyAgg coefficient is equivalent
* to multiplying the signer's public key by the coefficient, except
* much easier to do. */
- secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp.x);
+ secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp);
secp256k1_scalar_mul(&e, &session_i.challenge, &mu);
- /* The specification requires that the public key is multiplied by g[v]*g.
- * All factors are -1 or 1. The value g[v] is -1 iff
- * secp256k1_fe_is_odd(&cache_i.pk.y)) and g is is -1 iff parity_acc is 1.
- * Therefore, multiplying by g[v]*g is equivalent to negating if
- * fe_is_odd(&cache_i.pk.y) XOR parity_acc. */
+ /* Negate e if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc.
+ * This corresponds to the line "Let g' = gâ‹…gacc mod n" and the multiplication "g'â‹…e"
+ * in the specification. */
if (secp256k1_fe_is_odd(&cache_i.pk.y)
!= cache_i.parity_acc) {
secp256k1_scalar_negate(&e, &e);
diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h
index 3125d1ed6b8..b4de816709e 100644
--- a/src/modules/musig/tests_impl.h
+++ b/src/modules/musig/tests_impl.h
@@ -23,11 +23,13 @@
#include "../../hash.h"
#include "../../util.h"
-static int create_keypair_and_pk(secp256k1_keypair *keypair, secp256k1_xonly_pubkey *pk, const unsigned char *sk) {
+#include "vectors.h"
+
+static int create_keypair_and_pk(secp256k1_keypair *keypair, secp256k1_pubkey *pk, const unsigned char *sk) {
int ret;
secp256k1_keypair keypair_tmp;
ret = secp256k1_keypair_create(ctx, &keypair_tmp, sk);
- ret &= secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair_tmp);
+ ret &= secp256k1_keypair_pub(ctx, pk, &keypair_tmp);
if (keypair != NULL) {
*keypair = keypair_tmp;
}
@@ -47,8 +49,8 @@ void musig_simple_test(secp256k1_scratch_space *scratch) {
secp256k1_musig_keyagg_cache keyagg_cache;
unsigned char session_id[2][32];
secp256k1_musig_secnonce secnonce[2];
- secp256k1_xonly_pubkey pk[2];
- const secp256k1_xonly_pubkey *pk_ptr[2];
+ secp256k1_pubkey pk[2];
+ const secp256k1_pubkey *pk_ptr[2];
secp256k1_musig_partial_sig partial_sig[2];
const secp256k1_musig_partial_sig *partial_sig_ptr[2];
unsigned char final_sig[64];
@@ -64,7 +66,7 @@ void musig_simple_test(secp256k1_scratch_space *scratch) {
partial_sig_ptr[i] = &partial_sig[i];
CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i]));
- CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce[i], &pubnonce[i], session_id[i], sk[i], NULL, NULL, NULL) == 1);
+ CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce[i], &pubnonce[i], session_id[i], sk[i], &pk[i], NULL, NULL, NULL) == 1);
}
CHECK(secp256k1_musig_pubkey_agg(ctx, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1);
@@ -124,7 +126,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_keypair keypair[2];
secp256k1_keypair invalid_keypair;
unsigned char max64[64];
- unsigned char zeros68[68] = { 0 };
+ unsigned char zeros132[132] = { 0 };
unsigned char session_id[2][32];
secp256k1_musig_secnonce secnonce[2];
secp256k1_musig_secnonce secnonce_tmp;
@@ -145,11 +147,11 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_musig_keyagg_cache invalid_keyagg_cache;
secp256k1_musig_session session;
secp256k1_musig_session invalid_session;
- secp256k1_xonly_pubkey pk[2];
- const secp256k1_xonly_pubkey *pk_ptr[2];
- secp256k1_xonly_pubkey invalid_pk;
- const secp256k1_xonly_pubkey *invalid_pk_ptr2[2];
- const secp256k1_xonly_pubkey *invalid_pk_ptr3[3];
+ secp256k1_pubkey pk[2];
+ const secp256k1_pubkey *pk_ptr[2];
+ secp256k1_pubkey invalid_pk;
+ const secp256k1_pubkey *invalid_pk_ptr2[2];
+ const secp256k1_pubkey *invalid_pk_ptr3[3];
unsigned char tweak[32];
int nonce_parity;
unsigned char sec_adaptor[32];
@@ -226,19 +228,19 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, NULL, pk_ptr, 2) == 1);
CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, NULL, 2) == 0);
CHECK(ecount == 1);
- CHECK(memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
+ CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0);
CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, invalid_pk_ptr2, 2) == 0);
CHECK(ecount == 2);
- CHECK(memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
+ CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0);
CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, invalid_pk_ptr3, 3) == 0);
CHECK(ecount == 3);
- CHECK(memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
+ CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0);
CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, pk_ptr, 0) == 0);
CHECK(ecount == 4);
- CHECK(memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
+ CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0);
CHECK(secp256k1_musig_pubkey_agg(vrfy, scratch, &agg_pk, &keyagg_cache, NULL, 0) == 0);
CHECK(ecount == 5);
- CHECK(memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0);
+ CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0);
CHECK(secp256k1_musig_pubkey_agg(none, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1);
CHECK(secp256k1_musig_pubkey_agg(sign, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1);
@@ -251,7 +253,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(ecount == 1);
CHECK(secp256k1_musig_pubkey_get(none, &full_agg_pk, NULL) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_memcmp_var(&full_agg_pk, zeros68, sizeof(full_agg_pk)) == 0);
+ CHECK(secp256k1_memcmp_var(&full_agg_pk, zeros132, sizeof(full_agg_pk)) == 0);
/** Tweaking **/
{
@@ -275,63 +277,67 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
tmp_keyagg_cache = keyagg_cache;
CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, NULL, tweak) == 0);
CHECK(ecount == 1);
- CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
+ CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0);
tmp_keyagg_cache = keyagg_cache;
CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &tmp_keyagg_cache, NULL) == 0);
CHECK(ecount == 2);
- CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
+ CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0);
tmp_keyagg_cache = keyagg_cache;
CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &tmp_keyagg_cache, max64) == 0);
CHECK(ecount == 2);
- CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
+ CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0);
tmp_keyagg_cache = keyagg_cache;
/* Uninitialized keyagg_cache */
CHECK((*tweak_func[i])(vrfy, &tmp_output_pk, &invalid_keyagg_cache, tweak) == 0);
CHECK(ecount == 3);
- CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros68, sizeof(tmp_output_pk.data)) == 0);
+ CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0);
}
}
/** Session creation **/
ecount = 0;
- CHECK(secp256k1_musig_nonce_gen(none, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 1);
- CHECK(secp256k1_musig_nonce_gen(vrfy, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 1);
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 1);
+ CHECK(secp256k1_musig_nonce_gen(none, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1);
+ CHECK(secp256k1_musig_nonce_gen(vrfy, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_musig_nonce_gen(sttc, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 0);
+ CHECK(secp256k1_musig_nonce_gen(sttc, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_musig_nonce_gen(sign, NULL, &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, max64) == 0);
+ CHECK(secp256k1_musig_nonce_gen(sign, NULL, &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], NULL, session_id[0], sk[0], msg, &keyagg_cache, max64) == 0);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], NULL, session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0);
CHECK(ecount == 3);
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], NULL, sk[0], msg, &keyagg_cache, max64) == 0);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], NULL, sk[0], &pk[0], msg, &keyagg_cache, max64) == 0);
CHECK(ecount == 4);
- CHECK(memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
+ CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0);
/* no seckey and session_id is 0 */
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], zeros68, NULL, msg, &keyagg_cache, max64) == 0);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], zeros132, NULL, &pk[0], msg, &keyagg_cache, max64) == 0);
CHECK(ecount == 4);
- CHECK(memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
+ CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0);
/* session_id 0 is fine when a seckey is provided */
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], zeros68, sk[0], msg, &keyagg_cache, max64) == 1);
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], NULL, msg, &keyagg_cache, max64) == 1);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], zeros132, sk[0], &pk[0], msg, &keyagg_cache, max64) == 1);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], NULL, &pk[0], msg, &keyagg_cache, max64) == 1);
CHECK(ecount == 4);
/* invalid seckey */
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], max64, msg, &keyagg_cache, max64) == 0);
- CHECK(memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
- CHECK(ecount == 4);
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], NULL, &keyagg_cache, max64) == 1);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], max64, &pk[0], msg, &keyagg_cache, max64) == 0);
+ CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0);
CHECK(ecount == 4);
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, NULL, max64) == 1);
- CHECK(ecount == 4);
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &invalid_keyagg_cache, max64) == 0);
- CHECK(ecount == 5);
- CHECK(memcmp_and_randomize(secnonce[0].data, zeros68, sizeof(secnonce[0].data)) == 0);
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], msg, &keyagg_cache, NULL) == 1);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], NULL, msg, &keyagg_cache, max64) == 0);
CHECK(ecount == 5);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &invalid_pk, msg, &keyagg_cache, max64) == 0);
+ CHECK(ecount == 6);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], NULL, &keyagg_cache, max64) == 1);
+ CHECK(ecount == 6);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, NULL, max64) == 1);
+ CHECK(ecount == 6);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &invalid_keyagg_cache, max64) == 0);
+ CHECK(ecount == 7);
+ CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, NULL) == 1);
+ CHECK(ecount == 7);
- /* Every in-argument except session_id can be NULL */
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], NULL, NULL, NULL, NULL) == 1);
- CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[1], &pubnonce[1], session_id[1], sk[1], NULL, NULL, NULL) == 1);
+ /* Every in-argument except session_id and pubkey can be NULL */
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[0], &pubnonce[0], session_id[0], NULL, &pk[0], NULL, NULL, NULL) == 1);
+ CHECK(secp256k1_musig_nonce_gen(sign, &secnonce[1], &pubnonce[1], session_id[1], sk[1], &pk[1], NULL, NULL, NULL) == 1);
/** Serialize and parse public nonces **/
ecount = 0;
@@ -339,10 +345,10 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(ecount == 1);
CHECK(secp256k1_musig_pubnonce_serialize(none, pubnonce_ser, NULL) == 0);
CHECK(ecount == 2);
- CHECK(memcmp_and_randomize(pubnonce_ser, zeros68, sizeof(pubnonce_ser)) == 0);
+ CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0);
CHECK(secp256k1_musig_pubnonce_serialize(none, pubnonce_ser, &invalid_pubnonce) == 0);
CHECK(ecount == 3);
- CHECK(memcmp_and_randomize(pubnonce_ser, zeros68, sizeof(pubnonce_ser)) == 0);
+ CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0);
CHECK(secp256k1_musig_pubnonce_serialize(none, pubnonce_ser, &pubnonce[0]) == 1);
ecount = 0;
@@ -351,7 +357,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(ecount == 1);
CHECK(secp256k1_musig_pubnonce_parse(none, &pubnonce[0], NULL) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_musig_pubnonce_parse(none, &pubnonce[0], zeros68) == 0);
+ CHECK(secp256k1_musig_pubnonce_parse(none, &pubnonce[0], zeros132) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_pubnonce_parse(none, &pubnonce[0], pubnonce_ser) == 1);
@@ -360,7 +366,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_musig_pubnonce tmp;
CHECK(secp256k1_musig_pubnonce_serialize(none, pubnonce_ser, &pubnonce[0]) == 1);
CHECK(secp256k1_musig_pubnonce_parse(none, &tmp, pubnonce_ser) == 1);
- CHECK(memcmp(&tmp, &pubnonce[0], sizeof(tmp)) == 0);
+ CHECK(secp256k1_memcmp_var(&tmp, &pubnonce[0], sizeof(tmp)) == 0);
}
/** Receive nonces and aggregate **/
@@ -376,11 +382,11 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(ecount == 4);
CHECK(secp256k1_musig_nonce_agg(none, &aggnonce, inf_pubnonce_ptr, 2) == 1);
{
- /* Check that the aggnonce is set to G */
+ /* Check that the aggnonce encodes two points at infinity */
secp256k1_ge aggnonce_pt[2];
- secp256k1_musig_pubnonce_load(ctx, aggnonce_pt, (secp256k1_musig_pubnonce*)&aggnonce);
+ secp256k1_musig_aggnonce_load(ctx, aggnonce_pt, &aggnonce);
for (i = 0; i < 2; i++) {
- ge_equals_ge(&aggnonce_pt[i], &secp256k1_ge_const_g);
+ secp256k1_ge_is_infinity(&aggnonce_pt[i]);
}
}
CHECK(ecount == 4);
@@ -393,10 +399,10 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(ecount == 1);
CHECK(secp256k1_musig_aggnonce_serialize(none, aggnonce_ser, NULL) == 0);
CHECK(ecount == 2);
- CHECK(memcmp_and_randomize(aggnonce_ser, zeros68, sizeof(aggnonce_ser)) == 0);
+ CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0);
CHECK(secp256k1_musig_aggnonce_serialize(none, aggnonce_ser, (secp256k1_musig_aggnonce*) &invalid_pubnonce) == 0);
CHECK(ecount == 3);
- CHECK(memcmp_and_randomize(aggnonce_ser, zeros68, sizeof(aggnonce_ser)) == 0);
+ CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0);
CHECK(secp256k1_musig_aggnonce_serialize(none, aggnonce_ser, &aggnonce) == 1);
ecount = 0;
@@ -405,8 +411,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(ecount == 1);
CHECK(secp256k1_musig_aggnonce_parse(none, &aggnonce, NULL) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_musig_aggnonce_parse(none, &aggnonce, zeros68) == 0);
- CHECK(ecount == 2);
+ CHECK(secp256k1_musig_aggnonce_parse(none, &aggnonce, zeros132) == 1);
CHECK(secp256k1_musig_aggnonce_parse(none, &aggnonce, aggnonce_ser) == 1);
{
@@ -414,7 +419,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_musig_aggnonce tmp;
CHECK(secp256k1_musig_aggnonce_serialize(none, aggnonce_ser, &aggnonce) == 1);
CHECK(secp256k1_musig_aggnonce_parse(none, &tmp, aggnonce_ser) == 1);
- CHECK(memcmp(&tmp, &aggnonce, sizeof(tmp)) == 0);
+ CHECK(secp256k1_memcmp_var(&tmp, &aggnonce, sizeof(tmp)) == 0);
}
/** Process nonces **/
@@ -444,7 +449,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 1);
/* The secnonce is set to 0 and subsequent signing attempts fail */
- CHECK(memcmp(&secnonce_tmp, zeros68, sizeof(secnonce_tmp)) == 0);
+ CHECK(secp256k1_memcmp_var(&secnonce_tmp, zeros132, sizeof(secnonce_tmp)) == 0);
CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 0);
CHECK(ecount == 1);
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
@@ -461,17 +466,26 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &invalid_keypair, &keyagg_cache, &session) == 0);
CHECK(ecount == 6);
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
+ {
+ unsigned char sk_tmp[32];
+ secp256k1_keypair keypair_tmp;
+ secp256k1_testrand256(sk_tmp);
+ CHECK(secp256k1_keypair_create(ctx, &keypair_tmp, sk_tmp));
+ CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair_tmp, &keyagg_cache, &session) == 0);
+ CHECK(ecount == 7);
+ memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
+ }
CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], NULL, &session) == 0);
- CHECK(ecount == 7);
+ CHECK(ecount == 8);
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &invalid_keyagg_cache, &session) == 0);
- CHECK(ecount == 8);
+ CHECK(ecount == 9);
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, NULL) == 0);
- CHECK(ecount == 9);
+ CHECK(ecount == 10);
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &invalid_session) == 0);
- CHECK(ecount == 10);
+ CHECK(ecount == 11);
memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp));
CHECK(secp256k1_musig_partial_sign(none, &partial_sig[0], &secnonce[0], &keypair[0], &keyagg_cache, &session) == 1);
@@ -496,7 +510,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_musig_partial_sig tmp;
CHECK(secp256k1_musig_partial_sig_serialize(none, buf, &partial_sig[0]) == 1);
CHECK(secp256k1_musig_partial_sig_parse(none, &tmp, buf) == 1);
- CHECK(memcmp(&tmp, &partial_sig[0], sizeof(tmp)) == 0);
+ CHECK(secp256k1_memcmp_var(&tmp, &partial_sig[0], sizeof(tmp)) == 0);
}
/** Partial signature verification */
@@ -582,10 +596,10 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
/** Secret adaptor can be extracted from signature */
ecount = 0;
CHECK(secp256k1_musig_extract_adaptor(none, sec_adaptor1, final_sig, pre_sig, nonce_parity) == 1);
- CHECK(memcmp(sec_adaptor, sec_adaptor1, 32) == 0);
+ CHECK(secp256k1_memcmp_var(sec_adaptor, sec_adaptor1, 32) == 0);
/* wrong nonce parity */
CHECK(secp256k1_musig_extract_adaptor(none, sec_adaptor1, final_sig, pre_sig, !nonce_parity) == 1);
- CHECK(memcmp(sec_adaptor, sec_adaptor1, 32) != 0);
+ CHECK(secp256k1_memcmp_var(sec_adaptor, sec_adaptor1, 32) != 0);
CHECK(secp256k1_musig_extract_adaptor(none, NULL, final_sig, pre_sig, 0) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_extract_adaptor(none, sec_adaptor1, NULL, pre_sig, 0) == 0);
@@ -609,25 +623,27 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) {
secp256k1_scalar k1[2], k2[2];
- secp256k1_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4]);
+ secp256k1_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4], args[5]);
secp256k1_testrand_flip(args[n_flip], n_bytes);
- secp256k1_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4]);
+ secp256k1_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4], args[5]);
CHECK(secp256k1_scalar_eq(&k1[0], &k2[0]) == 0);
CHECK(secp256k1_scalar_eq(&k1[1], &k2[1]) == 0);
}
void musig_nonce_test(void) {
- unsigned char *args[5];
+ unsigned char *args[6];
unsigned char session_id[32];
unsigned char sk[32];
+ unsigned char pk[33];
unsigned char msg[32];
unsigned char agg_pk[32];
unsigned char extra_input[32];
int i, j;
- secp256k1_scalar k[5][2];
+ secp256k1_scalar k[6][2];
secp256k1_testrand_bytes_test(session_id, sizeof(session_id));
secp256k1_testrand_bytes_test(sk, sizeof(sk));
+ secp256k1_testrand_bytes_test(pk, sizeof(pk));
secp256k1_testrand_bytes_test(msg, sizeof(msg));
secp256k1_testrand_bytes_test(agg_pk, sizeof(agg_pk));
secp256k1_testrand_bytes_test(extra_input, sizeof(extra_input));
@@ -636,30 +652,35 @@ void musig_nonce_test(void) {
args[0] = session_id;
args[1] = msg;
args[2] = sk;
- args[3] = agg_pk;
- args[4] = extra_input;
+ args[3] = pk;
+ args[4] = agg_pk;
+ args[5] = extra_input;
for (i = 0; i < count; i++) {
musig_nonce_bitflip(args, 0, sizeof(session_id));
musig_nonce_bitflip(args, 1, sizeof(msg));
musig_nonce_bitflip(args, 2, sizeof(sk));
- musig_nonce_bitflip(args, 3, sizeof(agg_pk));
- musig_nonce_bitflip(args, 4, sizeof(extra_input));
+ musig_nonce_bitflip(args, 3, sizeof(pk));
+ musig_nonce_bitflip(args, 4, sizeof(agg_pk));
+ musig_nonce_bitflip(args, 5, sizeof(extra_input));
}
/* Check that if any argument is NULL, a different nonce is produced than if
* any other argument is NULL. */
memcpy(msg, session_id, sizeof(msg));
memcpy(sk, session_id, sizeof(sk));
+ memcpy(pk, session_id, sizeof(session_id));
memcpy(agg_pk, session_id, sizeof(agg_pk));
memcpy(extra_input, session_id, sizeof(extra_input));
- secp256k1_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4]);
- secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4]);
- secp256k1_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4]);
- secp256k1_nonce_function_musig(k[3], args[0], args[1], args[2], NULL, args[4]);
- secp256k1_nonce_function_musig(k[4], args[0], args[1], args[2], args[3], NULL);
- for (i = 0; i < 4; i++) {
- for (j = i+1; j < 5; j++) {
- CHECK(secp256k1_scalar_eq(&k[i][0], &k[j][0]) == 0);
- CHECK(secp256k1_scalar_eq(&k[i][1], &k[j][1]) == 0);
+ secp256k1_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4], args[5]);
+ secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4], args[5]);
+ secp256k1_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4], args[5]);
+ secp256k1_nonce_function_musig(k[3], args[0], args[1], args[2], NULL, args[4], args[5]);
+ secp256k1_nonce_function_musig(k[4], args[0], args[1], args[2], args[3], NULL, args[5]);
+ secp256k1_nonce_function_musig(k[5], args[0], args[1], args[2], args[3], args[4], NULL);
+ for (i = 0; i < 6; i++) {
+ CHECK(!secp256k1_scalar_eq(&k[i][0], &k[i][1]));
+ for (j = i+1; j < 6; j++) {
+ CHECK(!secp256k1_scalar_eq(&k[i][0], &k[j][0]));
+ CHECK(!secp256k1_scalar_eq(&k[i][1], &k[j][1]));
}
}
}
@@ -684,10 +705,10 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
unsigned char sk_b[2][32];
secp256k1_keypair keypair_a[2];
secp256k1_keypair keypair_b[2];
- secp256k1_xonly_pubkey pk_a[2];
- const secp256k1_xonly_pubkey *pk_a_ptr[2];
- secp256k1_xonly_pubkey pk_b[2];
- const secp256k1_xonly_pubkey *pk_b_ptr[2];
+ secp256k1_pubkey pk_a[2];
+ const secp256k1_pubkey *pk_a_ptr[2];
+ secp256k1_pubkey pk_b[2];
+ const secp256k1_pubkey *pk_b_ptr[2];
secp256k1_musig_keyagg_cache keyagg_cache_a;
secp256k1_musig_keyagg_cache keyagg_cache_b;
secp256k1_xonly_pubkey agg_pk_a;
@@ -729,10 +750,10 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
CHECK(secp256k1_musig_pubkey_agg(ctx, scratch, &agg_pk_a, &keyagg_cache_a, pk_a_ptr, 2) == 1);
CHECK(secp256k1_musig_pubkey_agg(ctx, scratch, &agg_pk_b, &keyagg_cache_b, pk_b_ptr, 2) == 1);
- CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_a[0], &pubnonce_a[0], seed_a[0], sk_a[0], NULL, NULL, NULL) == 1);
- CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_a[1], &pubnonce_a[1], seed_a[1], sk_a[1], NULL, NULL, NULL) == 1);
- CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_b[0], &pubnonce_b[0], seed_b[0], sk_b[0], NULL, NULL, NULL) == 1);
- CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_b[1], &pubnonce_b[1], seed_b[1], sk_b[1], NULL, NULL, NULL) == 1);
+ CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_a[0], &pubnonce_a[0], seed_a[0], sk_a[0], &pk_a[0], NULL, NULL, NULL) == 1);
+ CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_a[1], &pubnonce_a[1], seed_a[1], sk_a[1], &pk_a[1], NULL, NULL, NULL) == 1);
+ CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_b[0], &pubnonce_b[0], seed_b[0], sk_b[0], &pk_b[0], NULL, NULL, NULL) == 1);
+ CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_b[1], &pubnonce_b[1], seed_b[1], sk_b[1], &pk_b[1], NULL, NULL, NULL) == 1);
/* Step 2: Exchange nonces */
CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce_a, pubnonce_ptr_a, 2) == 1);
@@ -764,7 +785,7 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig_a[1], &secnonce_a[1], &keypair_a[1], &keyagg_cache_a, &session_a) == 1);
CHECK(secp256k1_musig_partial_sig_agg(ctx, pre_sig_a, &session_a, partial_sig_a_ptr, 2) == 1);
CHECK(secp256k1_musig_extract_adaptor(ctx, sec_adaptor_extracted, final_sig_b, pre_sig_b, 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_memcmp_var(sec_adaptor_extracted, sec_adaptor, sizeof(sec_adaptor)) == 0); /* in real life we couldn't check this, of course */
CHECK(secp256k1_musig_adapt(ctx, final_sig_a, pre_sig_a, sec_adaptor_extracted, nonce_parity_a) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_a, msg32_a, sizeof(msg32_a), &agg_pk_a) == 1);
}
@@ -794,7 +815,7 @@ void sha256_tag_test_internal(secp256k1_sha256 *sha_tagged, unsigned char *tag,
secp256k1_sha256_write(sha_tagged, buf, 32);
secp256k1_sha256_finalize(&sha, buf);
secp256k1_sha256_finalize(sha_tagged, buf2);
- CHECK(memcmp(buf, buf2, 32) == 0);
+ CHECK(secp256k1_memcmp_var(buf, buf2, 32) == 0);
}
/* Checks that the initialized tagged hashes initialized have the expected
@@ -816,7 +837,7 @@ void sha256_tag_test(void) {
/* Attempts to create a signature for the aggregate public key using given secret
* keys and keyagg_cache. */
void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_keyagg_cache *keyagg_cache) {
- secp256k1_xonly_pubkey pk[2];
+ secp256k1_pubkey pk[2];
unsigned char session_id[2][32];
unsigned char msg[32];
secp256k1_musig_secnonce secnonce[2];
@@ -840,8 +861,8 @@ void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigne
CHECK(create_keypair_and_pk(&keypair[1], &pk[1], sk1) == 1);
secp256k1_testrand256(msg);
- CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce[0], &pubnonce[0], session_id[0], sk0, NULL, NULL, NULL) == 1);
- CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce[1], &pubnonce[1], session_id[1], sk1, NULL, NULL, NULL) == 1);
+ CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce[0], &pubnonce[0], session_id[0], sk0, &pk[0], NULL, NULL, NULL) == 1);
+ CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce[1], &pubnonce[1], session_id[1], sk1, &pk[1], NULL, NULL, NULL) == 1);
CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 2) == 1);
CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, keyagg_cache, NULL) == 1);
@@ -857,11 +878,11 @@ void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigne
}
/* Create aggregate public key P[0], tweak multiple times (using xonly and
- * ordinary tweaking) and test signing. */
+ * plain tweaking) and test signing. */
void musig_tweak_test(secp256k1_scratch_space *scratch) {
unsigned char sk[2][32];
- secp256k1_xonly_pubkey pk[2];
- const secp256k1_xonly_pubkey *pk_ptr[2];
+ secp256k1_pubkey pk[2];
+ const secp256k1_pubkey *pk_ptr[2];
secp256k1_musig_keyagg_cache keyagg_cache;
enum { N_TWEAKS = 8 };
secp256k1_pubkey P[N_TWEAKS + 1];
@@ -904,538 +925,397 @@ void musig_tweak_test(secp256k1_scratch_space *scratch) {
} else {
secp256k1_pubkey tmp_key = P[i-1];
CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &tmp_key, tweak));
- CHECK(memcmp(&tmp_key, &P[i], sizeof(tmp_key)) == 0);
+ CHECK(secp256k1_memcmp_var(&tmp_key, &P[i], sizeof(tmp_key)) == 0);
}
/* Test signing for P[i] */
musig_tweak_test_helper(&P_xonly[i], sk[0], sk[1], &keyagg_cache);
}
}
-void musig_test_vectors_keyagg_helper(const unsigned char **pk_ser, int n_pks, const unsigned char *agg_pk_expected, int has_second_pk, int second_pk_idx) {
- secp256k1_xonly_pubkey *pk = malloc(n_pks * sizeof(*pk));
- const secp256k1_xonly_pubkey **pk_ptr = malloc(n_pks * sizeof(*pk_ptr));
- secp256k1_keyagg_cache_internal cache_i;
- secp256k1_xonly_pubkey agg_pk;
- unsigned char agg_pk_ser[32];
- secp256k1_musig_keyagg_cache keyagg_cache;
+int musig_vectors_keyagg_and_tweak(enum MUSIG_ERROR *error,
+ secp256k1_musig_keyagg_cache *keyagg_cache,
+ unsigned char *agg_pk_ser,
+ const unsigned char pubkeys33[][33],
+ const unsigned char tweaks32[][32],
+ size_t key_indices_len,
+ const size_t *key_indices,
+ size_t tweak_indices_len,
+ const size_t *tweak_indices,
+ const int *is_xonly) {
+ secp256k1_pubkey pubkeys[MUSIG_VECTORS_MAX_PUBKEYS];
+ const secp256k1_pubkey *pk_ptr[MUSIG_VECTORS_MAX_PUBKEYS];
int i;
+ secp256k1_pubkey agg_pk;
+ secp256k1_xonly_pubkey agg_pk_xonly;
- for (i = 0; i < n_pks; i++) {
- CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk[i], pk_ser[i]) == 1);
- pk_ptr[i] = &pk[i];
+ for (i = 0; i < (int)key_indices_len; i++) {
+ if (!secp256k1_ec_pubkey_parse(ctx, &pubkeys[i], pubkeys33[key_indices[i]], 33)) {
+ *error = MUSIG_PUBKEY;
+ return 0;
+ }
+ pk_ptr[i] = &pubkeys[i];
+ }
+ if (!secp256k1_musig_pubkey_agg(ctx, NULL, NULL, keyagg_cache, pk_ptr, key_indices_len)) {
+ *error = MUSIG_OTHER;
+ return 0;
}
- CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, &keyagg_cache, pk_ptr, n_pks) == 1);
- CHECK(secp256k1_keyagg_cache_load(ctx, &cache_i, &keyagg_cache) == 1);
- CHECK(secp256k1_fe_is_zero(&cache_i.second_pk_x) == !has_second_pk);
- if (!secp256k1_fe_is_zero(&cache_i.second_pk_x)) {
- secp256k1_ge pk_pt;
- CHECK(secp256k1_xonly_pubkey_load(ctx, &pk_pt, &pk[second_pk_idx]) == 1);
- CHECK(secp256k1_fe_equal_var(&pk_pt.x, &cache_i.second_pk_x) == 1);
+ for (i = 0; i < (int)tweak_indices_len; i++) {
+ if (is_xonly[i]) {
+ if (!secp256k1_musig_pubkey_xonly_tweak_add(ctx, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) {
+ *error = MUSIG_TWEAK;
+ return 0;
+ }
+ } else {
+ if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) {
+ *error = MUSIG_TWEAK;
+ return 0;
+ }
+ }
+ }
+ if (!secp256k1_musig_pubkey_get(ctx, &agg_pk, keyagg_cache)) {
+ *error = MUSIG_OTHER;
+ return 0;
}
- CHECK(secp256k1_xonly_pubkey_serialize(ctx, agg_pk_ser, &agg_pk) == 1);
- /* TODO: remove when test vectors are not expected to change anymore */
- /* int k, l; */
- /* printf("const unsigned char agg_pk_expected[32] = {\n"); */
- /* for (k = 0; k < 4; k++) { */
- /* printf(" "); */
- /* for (l = 0; l < 8; l++) { */
- /* printf("0x%02X, ", agg_pk_ser[k*8+l]); */
- /* } */
- /* printf("\n"); */
- /* } */
- /* printf("};\n"); */
- CHECK(secp256k1_memcmp_var(agg_pk_ser, agg_pk_expected, sizeof(agg_pk_ser)) == 0);
- free(pk);
- free(pk_ptr);
-}
-/* Test vector public keys */
-const unsigned char vec_pk[3][32] = {
- /* X1 */
- {
- 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10,
- 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29,
- 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0,
- 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9
- },
- /* X2 */
- {
- 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
- 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
- 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
- 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
- },
- /* X3 */
- {
- 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18,
- 0x15, 0xC2, 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3,
- 0x14, 0x93, 0x16, 0xC3, 0x51, 0x8C, 0xE7, 0xB7,
- 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66
+ if (!secp256k1_xonly_pubkey_from_pubkey(ctx, &agg_pk_xonly, NULL, &agg_pk)) {
+ *error = MUSIG_OTHER;
+ return 0;
}
-};
-void musig_test_vectors_keyagg(void) {
- size_t i;
- const unsigned char *pk[4];
- const unsigned char agg_pk_expected[4][32] = {
- { /* 0 */
- 0xE5, 0x83, 0x01, 0x40, 0x51, 0x21, 0x95, 0xD7,
- 0x4C, 0x83, 0x07, 0xE3, 0x96, 0x37, 0xCB, 0xE5,
- 0xFB, 0x73, 0x0E, 0xBE, 0xAB, 0x80, 0xEC, 0x51,
- 0x4C, 0xF8, 0x8A, 0x87, 0x7C, 0xEE, 0xEE, 0x0B,
- },
- { /* 1 */
- 0xD7, 0x0C, 0xD6, 0x9A, 0x26, 0x47, 0xF7, 0x39,
- 0x09, 0x73, 0xDF, 0x48, 0xCB, 0xFA, 0x2C, 0xCC,
- 0x40, 0x7B, 0x8B, 0x2D, 0x60, 0xB0, 0x8C, 0x5F,
- 0x16, 0x41, 0x18, 0x5C, 0x79, 0x98, 0xA2, 0x90,
- },
- { /* 2 */
- 0x81, 0xA8, 0xB0, 0x93, 0x91, 0x2C, 0x9E, 0x48,
- 0x14, 0x08, 0xD0, 0x97, 0x76, 0xCE, 0xFB, 0x48,
- 0xAE, 0xB8, 0xB6, 0x54, 0x81, 0xB6, 0xBA, 0xAF,
- 0xB3, 0xC5, 0x81, 0x01, 0x06, 0x71, 0x7B, 0xEB,
- },
- { /* 3 */
- 0x2E, 0xB1, 0x88, 0x51, 0x88, 0x7E, 0x7B, 0xDC,
- 0x5E, 0x83, 0x0E, 0x89, 0xB1, 0x9D, 0xDB, 0xC2,
- 0x80, 0x78, 0xF1, 0xFA, 0x88, 0xAA, 0xD0, 0xAD,
- 0x01, 0xCA, 0x06, 0xFE, 0x4F, 0x80, 0x21, 0x0B,
- },
- };
-
- for (i = 0; i < sizeof(agg_pk_expected)/sizeof(agg_pk_expected[0]); i++) {
- size_t n_pks;
- int has_second_pk;
- int second_pk_idx;
- switch (i) {
- case 0:
- /* [X1, X2, X3] */
- n_pks = 3;
- pk[0] = vec_pk[0];
- pk[1] = vec_pk[1];
- pk[2] = vec_pk[2];
- has_second_pk = 1;
- second_pk_idx = 1;
- break;
- case 1:
- /* [X3, X2, X1] */
- n_pks = 3;
- pk[2] = vec_pk[0];
- pk[1] = vec_pk[1];
- pk[0] = vec_pk[2];
- has_second_pk = 1;
- second_pk_idx = 1;
- break;
- case 2:
- /* [X1, X1, X1] */
- n_pks = 3;
- pk[0] = vec_pk[0];
- pk[1] = vec_pk[0];
- pk[2] = vec_pk[0];
- has_second_pk = 0;
- second_pk_idx = 0; /* unchecked */
- break;
- case 3:
- /* [X1, X1, X2, X2] */
- n_pks = 4;
- pk[0] = vec_pk[0];
- pk[1] = vec_pk[0];
- pk[2] = vec_pk[1];
- pk[3] = vec_pk[1];
- has_second_pk = 1;
- second_pk_idx = 2; /* second_pk_idx = 3 is equally valid */
- break;
- default:
- CHECK(0);
+ if (agg_pk_ser != NULL) {
+ if (!secp256k1_xonly_pubkey_serialize(ctx, agg_pk_ser, &agg_pk_xonly)) {
+ *error = MUSIG_OTHER;
+ return 0;
}
- musig_test_vectors_keyagg_helper(pk, n_pks, agg_pk_expected[i], has_second_pk, second_pk_idx);
}
+
+ return 1;
}
-void musig_test_vectors_noncegen(void) {
- enum { N = 3 };
- secp256k1_scalar k[N][2];
- const unsigned char k32_expected[N][2][32] = {
- {
- {
- 0x8D, 0xD0, 0x99, 0x51, 0x79, 0x50, 0x5E, 0xB1,
- 0x27, 0x3A, 0x07, 0x11, 0x58, 0x23, 0xC8, 0x6E,
- 0xF7, 0x14, 0x39, 0x0F, 0xDE, 0x2D, 0xEE, 0xB6,
- 0xF9, 0x31, 0x6A, 0xEE, 0xBE, 0x5C, 0x71, 0xFC,
- },
- {
- 0x73, 0x29, 0x2E, 0x47, 0x11, 0x34, 0x7D, 0xD3,
- 0x9E, 0x36, 0x05, 0xEE, 0xD6, 0x45, 0x65, 0x49,
- 0xB3, 0x0F, 0x3B, 0xC7, 0x16, 0x22, 0x5A, 0x18,
- 0x65, 0xBA, 0xE1, 0xD9, 0x84, 0xEF, 0xF8, 0x9D,
- },
- },
- /* msg32 is NULL */
- {
- {
- 0x67, 0x02, 0x5A, 0xF2, 0xA3, 0x56, 0x0B, 0xFC,
- 0x1D, 0x95, 0xBD, 0xA6, 0xB2, 0x0B, 0x21, 0x50,
- 0x97, 0x63, 0xDB, 0x17, 0x3B, 0xD9, 0x37, 0x30,
- 0x17, 0x24, 0x66, 0xEC, 0xAF, 0xA2, 0x60, 0x3B,
- },
- {
- 0x0B, 0x1D, 0x9E, 0x8F, 0x43, 0xBD, 0xAE, 0x69,
- 0x99, 0x6E, 0x0E, 0x3A, 0xBC, 0x30, 0x06, 0x4C,
- 0x52, 0x37, 0x3E, 0x05, 0x3E, 0x70, 0xC6, 0xD6,
- 0x18, 0x4B, 0xFA, 0xDA, 0xE0, 0xF0, 0xE2, 0xD9,
- },
- },
- /* All fields except session_id are NULL */
- {
- {
- 0xA6, 0xC3, 0x24, 0xC7, 0xE8, 0xD1, 0x8A, 0xAA,
- 0x59, 0xD7, 0xB4, 0x74, 0xDD, 0x73, 0x82, 0x6D,
- 0x7E, 0x74, 0x91, 0x3F, 0x9B, 0x36, 0x12, 0xE4,
- 0x4F, 0x28, 0x6E, 0x07, 0x54, 0x14, 0x58, 0x21,
- },
- {
- 0x4E, 0x75, 0xD3, 0x81, 0xCD, 0xB7, 0x3C, 0x68,
- 0xA0, 0x7E, 0x64, 0x15, 0xE0, 0x0E, 0x89, 0x32,
- 0x44, 0x21, 0x87, 0x4F, 0x4E, 0x03, 0xE8, 0x67,
- 0x73, 0x4E, 0x33, 0x20, 0xCE, 0x24, 0xBA, 0x8E,
- },
- },
- };
- unsigned char args[5][32];
- int i, j;
+void musig_test_vectors_keyagg(void) {
+ size_t i;
+ const struct musig_key_agg_vector *vector = &musig_key_agg_vector;
- for (i = 0; i < 5; i++) {
- memset(args[i], i, sizeof(args[i]));
+ for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) {
+ const struct musig_key_agg_valid_test_case *c = &vector->valid_case[i];
+ enum MUSIG_ERROR error;
+ secp256k1_musig_keyagg_cache keyagg_cache;
+ unsigned char agg_pk[32];
+
+ CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, 0, NULL, NULL));
+ CHECK(secp256k1_memcmp_var(agg_pk, c->expected, sizeof(agg_pk)) == 0);
}
- secp256k1_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4]);
- secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4]);
- secp256k1_nonce_function_musig(k[2], args[0], NULL, NULL, NULL, NULL);
- /* TODO: remove when test vectors are not expected to change anymore */
- /* int t, u; */
- /* printf("const unsigned char k32_expected[N][2][32] = {\n"); */
- /* for (i = 0; i < N; i++) { */
- /* printf(" {\n"); */
- /* for (j = 0; j < 2; j++) { */
- /* unsigned char k32[32]; */
- /* secp256k1_scalar_get_b32(k32, &k[i][j]); */
- /* printf(" {\n"); */
- /* for (t = 0; t < 4; t++) { */
- /* printf(" "); */
- /* for (u = 0; u < 8; u++) { */
- /* printf("0x%02X, ", k32[t*8+u]); */
- /* } */
- /* printf("\n"); */
- /* } */
- /* printf(" },\n"); */
- /* } */
- /* printf(" },\n"); */
- /* } */
- /* printf("};\n"); */
- for (i = 0; i < N; i++) {
- for (j = 0; j < 2; j++) {
- unsigned char k32[32];
- secp256k1_scalar_get_b32(k32, &k[i][j]);
- CHECK(memcmp(k32, k32_expected[i][j], 32) == 0);
+ for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) {
+ const struct musig_key_agg_error_test_case *c = &vector->error_case[i];
+ enum MUSIG_ERROR error;
+ secp256k1_musig_keyagg_cache keyagg_cache;
+
+ CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly));
+ CHECK(c->error == error);
+ }
+}
+
+void musig_test_vectors_noncegen(void) {
+ size_t i;
+ const struct musig_nonce_gen_vector *vector = &musig_nonce_gen_vector;
+
+ for (i = 0; i < sizeof(vector->test_case)/sizeof(vector->test_case[0]); i++) {
+ const struct musig_nonce_gen_test_case *c = &vector->test_case[i];
+ secp256k1_musig_keyagg_cache keyagg_cache;
+ secp256k1_musig_keyagg_cache *keyagg_cache_ptr = NULL;
+ secp256k1_musig_secnonce secnonce;
+ secp256k1_musig_pubnonce pubnonce;
+ const unsigned char *sk = NULL;
+ const unsigned char *msg = NULL;
+ const unsigned char *extra_in = NULL;
+ secp256k1_pubkey pk;
+ unsigned char pubnonce66[66];
+
+ if (c->has_sk) {
+ sk = c->sk;
+ }
+ if (c->has_aggpk) {
+ /* Create keyagg_cache from aggpk */
+ secp256k1_keyagg_cache_internal cache_i;
+ secp256k1_xonly_pubkey aggpk;
+ memset(&cache_i, 0, sizeof(cache_i));
+ CHECK(secp256k1_xonly_pubkey_parse(ctx, &aggpk, c->aggpk));
+ CHECK(secp256k1_xonly_pubkey_load(ctx, &cache_i.pk, &aggpk));
+ secp256k1_keyagg_cache_save(&keyagg_cache, &cache_i);
+ keyagg_cache_ptr = &keyagg_cache;
+ }
+ if (c->has_msg) {
+ msg = c->msg;
}
+ if (c->has_extra_in) {
+ extra_in = c->extra_in;
+ }
+
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pk, c->pk, sizeof(c->pk)));
+ CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, c->rand_, sk, &pk, msg, keyagg_cache_ptr, extra_in) == 1);
+ CHECK(secp256k1_memcmp_var(&secnonce.data[4], c->expected_secnonce, 2*32) == 0);
+ CHECK(secp256k1_memcmp_var(&secnonce.data[4+2*32], &pk, sizeof(pk)) == 0);
+
+ CHECK(secp256k1_musig_pubnonce_serialize(ctx, pubnonce66, &pubnonce) == 1);
+ CHECK(sizeof(c->expected_pubnonce) == sizeof(pubnonce66));
+ CHECK(secp256k1_memcmp_var(pubnonce66, c->expected_pubnonce, sizeof(pubnonce66)) == 0);
}
}
-void musig_test_vectors_sign_helper(secp256k1_musig_keyagg_cache *keyagg_cache, int *fin_nonce_parity, unsigned char *sig, const unsigned char *secnonce_bytes, const unsigned char *agg_pubnonce_ser, const unsigned char *sk, const unsigned char *msg, const unsigned char tweak[][32], const int *is_xonly_t, int n_tweaks, const secp256k1_pubkey *adaptor, const unsigned char **pk_ser, int signer_pos) {
- secp256k1_keypair signer_keypair;
- secp256k1_musig_secnonce secnonce;
- secp256k1_xonly_pubkey pk[3];
- const secp256k1_xonly_pubkey *pk_ptr[3];
- secp256k1_xonly_pubkey agg_pk;
- secp256k1_musig_session session;
- secp256k1_musig_aggnonce agg_pubnonce;
- secp256k1_musig_partial_sig partial_sig;
- int i;
- CHECK(create_keypair_and_pk(&signer_keypair, &pk[signer_pos], sk) == 1);
- for (i = 0; i < 3; i++) {
- if (i != signer_pos) {
- int offset = i < signer_pos ? 0 : -1;
- CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk[i], pk_ser[i + offset]) == 1);
+void musig_test_vectors_nonceagg(void) {
+ size_t i;
+ int j;
+ const struct musig_nonce_agg_vector *vector = &musig_nonce_agg_vector;
+
+ for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) {
+ const struct musig_nonce_agg_test_case *c = &vector->valid_case[i];
+ secp256k1_musig_pubnonce pubnonce[2];
+ const secp256k1_musig_pubnonce *pubnonce_ptr[2];
+ secp256k1_musig_aggnonce aggnonce;
+ unsigned char aggnonce66[66];
+
+ for (j = 0; j < 2; j++) {
+ CHECK(secp256k1_musig_pubnonce_parse(ctx, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]]) == 1);
+ pubnonce_ptr[j] = &pubnonce[j];
}
- pk_ptr[i] = &pk[i];
+ CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 2));
+ CHECK(secp256k1_musig_aggnonce_serialize(ctx, aggnonce66, &aggnonce));
+ CHECK(secp256k1_memcmp_var(aggnonce66, c->expected, 33) == 0);
}
- CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, keyagg_cache, pk_ptr, 3) == 1);
- for (i = 0; i < n_tweaks; i++) {
- if (is_xonly_t[i]) {
- CHECK(secp256k1_musig_pubkey_xonly_tweak_add(ctx, NULL, keyagg_cache, tweak[i]) == 1);
- } else {
- CHECK(secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, keyagg_cache, tweak[i]) == 1);
+ for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) {
+ const struct musig_nonce_agg_test_case *c = &vector->error_case[i];
+ secp256k1_musig_pubnonce pubnonce[2];
+ for (j = 0; j < 2; j++) {
+ int expected = c->invalid_nonce_idx != j;
+ CHECK(expected == secp256k1_musig_pubnonce_parse(ctx, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]]));
}
}
- memcpy(&secnonce.data[0], secp256k1_musig_secnonce_magic, 4);
- memcpy(&secnonce.data[4], secnonce_bytes, sizeof(secnonce.data) - 4);
- CHECK(secp256k1_musig_aggnonce_parse(ctx, &agg_pubnonce, agg_pubnonce_ser) == 1);
- CHECK(secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg, keyagg_cache, adaptor) == 1);
- CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &signer_keypair, keyagg_cache, &session) == 1);
- CHECK(secp256k1_musig_nonce_parity(ctx, fin_nonce_parity, &session) == 1);
- memcpy(sig, &partial_sig.data[4], 32);
}
-int musig_test_pk_parity(const secp256k1_musig_keyagg_cache *keyagg_cache) {
- secp256k1_keyagg_cache_internal cache_i;
- CHECK(secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache) == 1);
- return secp256k1_fe_is_odd(&cache_i.pk.y);
-}
+void musig_test_set_secnonce(secp256k1_musig_secnonce *secnonce, const unsigned char *secnonce64, const secp256k1_pubkey *pubkey) {
+ secp256k1_ge pk;
+ secp256k1_scalar k[2];
-int musig_test_is_second_pk(const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *sk) {
- secp256k1_ge pkp;
- secp256k1_xonly_pubkey pk;
- secp256k1_keyagg_cache_internal cache_i;
- CHECK(create_keypair_and_pk(NULL, &pk, sk));
- CHECK(secp256k1_xonly_pubkey_load(ctx, &pkp, &pk));
- CHECK(secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache));
- return secp256k1_fe_equal_var(&cache_i.second_pk_x, &pkp.x);
+ secp256k1_scalar_set_b32(&k[0], &secnonce64[0], NULL);
+ secp256k1_scalar_set_b32(&k[1], &secnonce64[32], NULL);
+ CHECK(secp256k1_pubkey_load(ctx, &pk, pubkey));
+ secp256k1_musig_secnonce_save(secnonce, k, &pk);
}
-/* TODO: Add test vectors for failed signing */
-void musig_test_vectors_sign(void) {
- unsigned char sig[32];
- secp256k1_musig_keyagg_cache keyagg_cache;
- int fin_nonce_parity;
- const unsigned char secnonce[64] = {
- 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6,
- 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98,
- 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF,
- 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61,
- 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85,
- 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5,
- 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5,
- 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7,
- };
- /* The nonces are already aggregated */
- const unsigned char agg_pubnonce[66] = {
- 0x02,
- 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44,
- 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B,
- 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65,
- 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61,
- 0x03,
- 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45,
- 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C,
- 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29,
- 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9,
- };
- const unsigned char sk[32] = {
- 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE,
- 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB,
- 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE,
- 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71,
- };
- const unsigned char msg[32] = {
- 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68,
- 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5,
- 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5,
- 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF,
- };
- const unsigned char *pk[2] = { vec_pk[0], vec_pk[1] };
-
- {
- /* This is a test where the combined public key point has an _odd_ y
- * coordinate, the signer _is not_ the second pubkey in the list and the
- * nonce parity is 1. */
- const unsigned char sig_expected[32] = {
- 0x68, 0x53, 0x7C, 0xC5, 0x23, 0x4E, 0x50, 0x5B,
- 0xD1, 0x40, 0x61, 0xF8, 0xDA, 0x9E, 0x90, 0xC2,
- 0x20, 0xA1, 0x81, 0x85, 0x5F, 0xD8, 0xBD, 0xB7,
- 0xF1, 0x27, 0xBB, 0x12, 0x40, 0x3B, 0x4D, 0x3B,
- };
- musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, NULL, 0, NULL, pk, 0);
- /* TODO: remove when test vectors are not expected to change anymore */
- /* int k, l; */
- /* printf("const unsigned char sig_expected[32] = {\n"); */
- /* for (k = 0; k < 4; k++) { */
- /* printf(" "); */
- /* for (l = 0; l < 8; l++) { */
- /* printf("0x%02X, ", sig[k*8+l]); */
- /* } */
- /* printf("\n"); */
- /* } */
- /* printf("};\n"); */
-
- /* Check that the description of the test vector is correct */
- CHECK(musig_test_pk_parity(&keyagg_cache) == 1);
- CHECK(!musig_test_is_second_pk(&keyagg_cache, sk));
- CHECK(fin_nonce_parity == 1);
- CHECK(memcmp(sig, sig_expected, 32) == 0);
+void musig_test_vectors_signverify(void) {
+ size_t i;
+ const struct musig_sign_verify_vector *vector = &musig_sign_verify_vector;
+
+ for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) {
+ const struct musig_valid_case *c = &vector->valid_case[i];
+ enum MUSIG_ERROR error;
+ secp256k1_musig_keyagg_cache keyagg_cache;
+ secp256k1_pubkey pubkey;
+ secp256k1_musig_pubnonce pubnonce;
+ secp256k1_musig_aggnonce aggnonce;
+ secp256k1_musig_session session;
+ secp256k1_musig_partial_sig partial_sig;
+ secp256k1_musig_secnonce secnonce;
+ secp256k1_keypair keypair;
+ unsigned char partial_sig32[32];
+
+ CHECK(secp256k1_keypair_create(ctx, &keypair, vector->sk));
+ CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL));
+
+ CHECK(secp256k1_musig_aggnonce_parse(ctx, &aggnonce, vector->aggnonces[c->aggnonce_index]));
+ CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache, NULL));
+
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0])));
+ musig_test_set_secnonce(&secnonce, vector->secnonces[0], &pubkey);
+ CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session));
+ CHECK(secp256k1_musig_partial_sig_serialize(ctx, partial_sig32, &partial_sig));
+ CHECK(secp256k1_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0);
+
+ CHECK(secp256k1_musig_pubnonce_parse(ctx, &pubnonce, vector->pubnonces[0]));
+ CHECK(secp256k1_musig_partial_sig_verify(ctx, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session));
}
- {
- /* This is a test where the aggregate public key point has an _even_ y
- * coordinate, the signer _is_ the second pubkey in the list and the
- * nonce parity is 0. */
- const unsigned char sig_expected[32] = {
- 0x2D, 0xF6, 0x7B, 0xFF, 0xF1, 0x8E, 0x3D, 0xE7,
- 0x97, 0xE1, 0x3C, 0x64, 0x75, 0xC9, 0x63, 0x04,
- 0x81, 0x38, 0xDA, 0xEC, 0x5C, 0xB2, 0x0A, 0x35,
- 0x7C, 0xEC, 0xA7, 0xC8, 0x42, 0x42, 0x95, 0xEA,
- };
- musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, NULL, 0, NULL, pk, 1);
- /* Check that the description of the test vector is correct */
- CHECK(musig_test_pk_parity(&keyagg_cache) == 0);
- CHECK(musig_test_is_second_pk(&keyagg_cache, sk));
- CHECK(fin_nonce_parity == 0);
- CHECK(memcmp(sig, sig_expected, 32) == 0);
+ for (i = 0; i < sizeof(vector->sign_error_case)/sizeof(vector->sign_error_case[0]); i++) {
+ const struct musig_sign_error_case *c = &vector->sign_error_case[i];
+ enum MUSIG_ERROR error;
+ secp256k1_musig_keyagg_cache keyagg_cache;
+ secp256k1_pubkey pubkey;
+ secp256k1_musig_aggnonce aggnonce;
+ secp256k1_musig_session session;
+ secp256k1_musig_partial_sig partial_sig;
+ secp256k1_musig_secnonce secnonce;
+ secp256k1_keypair keypair;
+ int expected;
+
+ if (i == 0) {
+ /* Skip this vector since the implementation does not error out when
+ * the signing key does not belong to any pubkey. */
+ continue;
+ }
+ expected = c->error != MUSIG_PUBKEY;
+ CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL));
+ CHECK(expected || c->error == error);
+ if (!expected) {
+ continue;
+ }
+
+ expected = c->error != MUSIG_AGGNONCE;
+ CHECK(expected == secp256k1_musig_aggnonce_parse(ctx, &aggnonce, vector->aggnonces[c->aggnonce_index]));
+ if (!expected) {
+ continue;
+ }
+ CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache, NULL));
+
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0])));
+ musig_test_set_secnonce(&secnonce, vector->secnonces[c->secnonce_index], &pubkey);
+ {
+ /* In the last test vector we sign with an invalid secnonce, which
+ * triggers an illegal_callback. Hence, we need to use a custom
+ * context that does not abort in this case. */
+ secp256k1_context *ctx_tmp = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+ int32_t ecount = 0;
+ secp256k1_context_set_error_callback(ctx_tmp, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount);
+ expected = c->error != MUSIG_SECNONCE;
+ CHECK(expected == secp256k1_musig_partial_sign(ctx_tmp, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session));
+ CHECK((!expected) == ecount);
+ secp256k1_context_destroy(ctx_tmp);
+ }
}
- {
- /* This is a test where the parity of aggregate public key point (1) is unequal to the
- * nonce parity (0). */
- const unsigned char sig_expected[32] = {
- 0x0D, 0x5B, 0x65, 0x1E, 0x6D, 0xE3, 0x4A, 0x29,
- 0xA1, 0x2D, 0xE7, 0xA8, 0xB4, 0x18, 0x3B, 0x4A,
- 0xE6, 0xA7, 0xF7, 0xFB, 0xE1, 0x5C, 0xDC, 0xAF,
- 0xA4, 0xA3, 0xD1, 0xBC, 0xAA, 0xBC, 0x75, 0x17,
- };
- musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, NULL, 0, NULL, pk, 2);
- /* Check that the description of the test vector is correct */
- CHECK(musig_test_pk_parity(&keyagg_cache) == 1);
- CHECK(fin_nonce_parity == 0);
- CHECK(!musig_test_is_second_pk(&keyagg_cache, sk));
- CHECK(memcmp(sig, sig_expected, 32) == 0);
+ for (i = 0; i < sizeof(vector->verify_fail_case)/sizeof(vector->verify_fail_case[0]); i++) {
+ const struct musig_verify_fail_error_case *c = &vector->verify_fail_case[i];
+ enum MUSIG_ERROR error;
+ secp256k1_musig_keyagg_cache keyagg_cache;
+ secp256k1_musig_aggnonce aggnonce;
+ secp256k1_musig_session session;
+ secp256k1_musig_partial_sig partial_sig;
+ enum { NUM_PUBNONCES = 3 };
+ secp256k1_musig_pubnonce pubnonce[NUM_PUBNONCES];
+ const secp256k1_musig_pubnonce *pubnonce_ptr[NUM_PUBNONCES];
+ secp256k1_pubkey pubkey;
+ int expected;
+ size_t j;
+
+ CHECK(NUM_PUBNONCES <= c->nonce_indices_len);
+ for (j = 0; j < c->nonce_indices_len; j++) {
+ CHECK(secp256k1_musig_pubnonce_parse(ctx, &pubnonce[j], vector->pubnonces[c->nonce_indices[j]]));
+ pubnonce_ptr[j] = &pubnonce[j];
+ }
+
+ CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL));
+ CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, c->nonce_indices_len) == 1);
+ CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache, NULL));
+
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, vector->pubkeys[c->signer_index], sizeof(vector->pubkeys[0])));
+
+ expected = c->error != MUSIG_SIG;
+ CHECK(expected == secp256k1_musig_partial_sig_parse(ctx, &partial_sig, c->sig));
+ if (!expected) {
+ continue;
+ }
+ expected = c->error != MUSIG_SIG_VERIFY;
+ CHECK(expected == secp256k1_musig_partial_sig_verify(ctx, &partial_sig, pubnonce, &pubkey, &keyagg_cache, &session));
}
- {
- /* This is a test that includes an xonly public key tweak. */
- const unsigned char sig_expected[32] = {
- 0x5E, 0x24, 0xC7, 0x49, 0x6B, 0x56, 0x5D, 0xEB,
- 0xC3, 0xB9, 0x63, 0x9E, 0x6F, 0x13, 0x04, 0xA2,
- 0x15, 0x97, 0xF9, 0x60, 0x3D, 0x3A, 0xB0, 0x5B,
- 0x49, 0x13, 0x64, 0x17, 0x75, 0xE1, 0x37, 0x5B,
- };
- const unsigned char tweak[1][32] = {{
- 0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF,
- 0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D,
- 0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79,
- 0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB,
- }};
- int is_xonly_t[1] = { 1 };
- musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, is_xonly_t, 1, NULL, pk, 2);
-
- CHECK(musig_test_pk_parity(&keyagg_cache) == 1);
- CHECK(!musig_test_is_second_pk(&keyagg_cache, sk));
- CHECK(fin_nonce_parity == 1);
- CHECK(memcmp(sig, sig_expected, 32) == 0);
+ for (i = 0; i < sizeof(vector->verify_error_case)/sizeof(vector->verify_error_case[0]); i++) {
+ const struct musig_verify_fail_error_case *c = &vector->verify_error_case[i];
+ enum MUSIG_ERROR error;
+ secp256k1_musig_keyagg_cache keyagg_cache;
+ secp256k1_musig_pubnonce pubnonce;
+ int expected;
+
+ expected = c->error != MUSIG_PUBKEY;
+ CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL));
+ CHECK(expected || c->error == error);
+ if (!expected) {
+ continue;
+ }
+ expected = c->error != MUSIG_PUBNONCE;
+ CHECK(expected == secp256k1_musig_pubnonce_parse(ctx, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]]));
}
- {
- /* This is a test that includes an ordinary public key tweak. */
- const unsigned char sig_expected[32] = {
- 0x78, 0x40, 0x8D, 0xDC, 0xAB, 0x48, 0x13, 0xD1,
- 0x39, 0x4C, 0x97, 0xD4, 0x93, 0xEF, 0x10, 0x84,
- 0x19, 0x5C, 0x1D, 0x4B, 0x52, 0xE6, 0x3E, 0xCD,
- 0x7B, 0xC5, 0x99, 0x16, 0x44, 0xE4, 0x4D, 0xDD,
- };
- const unsigned char tweak[1][32] = {{
- 0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF,
- 0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D,
- 0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79,
- 0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB,
- }};
- int is_xonly_t[1] = { 0 };
- musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, is_xonly_t, 1, NULL, pk, 2);
-
- CHECK(musig_test_pk_parity(&keyagg_cache) == 1);
- CHECK(!musig_test_is_second_pk(&keyagg_cache, sk));
- CHECK(fin_nonce_parity == 0);
- CHECK(memcmp(sig, sig_expected, 32) == 0);
+}
+
+void musig_test_vectors_tweak(void) {
+ size_t i;
+ const struct musig_tweak_vector *vector = &musig_tweak_vector;
+ secp256k1_pubkey pubkey;
+ secp256k1_musig_aggnonce aggnonce;
+ secp256k1_musig_secnonce secnonce;
+
+ CHECK(secp256k1_musig_aggnonce_parse(ctx, &aggnonce, vector->aggnonce));
+ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0])));
+
+ for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) {
+ const struct musig_tweak_case *c = &vector->valid_case[i];
+ enum MUSIG_ERROR error;
+ secp256k1_musig_keyagg_cache keyagg_cache;
+ secp256k1_musig_pubnonce pubnonce;
+ secp256k1_musig_session session;
+ secp256k1_musig_partial_sig partial_sig;
+ secp256k1_keypair keypair;
+ unsigned char partial_sig32[32];
+
+ musig_test_set_secnonce(&secnonce, vector->secnonce, &pubkey);
+
+ CHECK(secp256k1_keypair_create(ctx, &keypair, vector->sk));
+ CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly));
+
+ CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, vector->msg, &keyagg_cache, NULL));
+
+ CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session));
+ CHECK(secp256k1_musig_partial_sig_serialize(ctx, partial_sig32, &partial_sig));
+ CHECK(secp256k1_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0);
+
+ CHECK(secp256k1_musig_pubnonce_parse(ctx, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]]));
+ CHECK(secp256k1_musig_partial_sig_verify(ctx, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session));
}
- {
- /* This is a test that includes an ordinary and an x-only public key tweak. */
- const unsigned char sig_expected[32] = {
- 0xC3, 0xA8, 0x29, 0xA8, 0x14, 0x80, 0xE3, 0x6E,
- 0xC3, 0xAB, 0x05, 0x29, 0x64, 0x50, 0x9A, 0x94,
- 0xEB, 0xF3, 0x42, 0x10, 0x40, 0x3D, 0x16, 0xB2,
- 0x26, 0xA6, 0xF1, 0x6E, 0xC8, 0x5B, 0x73, 0x57,
- };
-
- const unsigned char tweak[2][32] = {
- {
- 0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF,
- 0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D,
- 0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79,
- 0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB,
- },
- {
- 0xAE, 0x2E, 0xA7, 0x97, 0xCC, 0x0F, 0xE7, 0x2A,
- 0xC5, 0xB9, 0x7B, 0x97, 0xF3, 0xC6, 0x95, 0x7D,
- 0x7E, 0x41, 0x99, 0xA1, 0x67, 0xA5, 0x8E, 0xB0,
- 0x8B, 0xCA, 0xFF, 0xDA, 0x70, 0xAC, 0x04, 0x55,
- },
- };
- int is_xonly_t[2] = { 0, 1 };
- musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, is_xonly_t, 2, NULL, pk, 2);
- CHECK(musig_test_pk_parity(&keyagg_cache) == 0);
- CHECK(!musig_test_is_second_pk(&keyagg_cache, sk));
- CHECK(fin_nonce_parity == 0);
- CHECK(memcmp(sig, sig_expected, 32) == 0);
+ for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) {
+ const struct musig_tweak_case *c = &vector->error_case[i];
+ enum MUSIG_ERROR error;
+ secp256k1_musig_keyagg_cache keyagg_cache;
+ CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly));
+ CHECK(error == MUSIG_TWEAK);
}
- {
- /* This is a test with four tweaks: x-only, ordinary, x-only, ordinary. */
- const unsigned char sig_expected[32] = {
- 0x8C, 0x44, 0x73, 0xC6, 0xA3, 0x82, 0xBD, 0x3C,
- 0x4A, 0xD7, 0xBE, 0x59, 0x81, 0x8D, 0xA5, 0xED,
- 0x7C, 0xF8, 0xCE, 0xC4, 0xBC, 0x21, 0x99, 0x6C,
- 0xFD, 0xA0, 0x8B, 0xB4, 0x31, 0x6B, 0x8B, 0xC7,
- };
- const unsigned char tweak[4][32] = {
- {
- 0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF,
- 0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D,
- 0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79,
- 0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB,
- },
- {
- 0xAE, 0x2E, 0xA7, 0x97, 0xCC, 0x0F, 0xE7, 0x2A,
- 0xC5, 0xB9, 0x7B, 0x97, 0xF3, 0xC6, 0x95, 0x7D,
- 0x7E, 0x41, 0x99, 0xA1, 0x67, 0xA5, 0x8E, 0xB0,
- 0x8B, 0xCA, 0xFF, 0xDA, 0x70, 0xAC, 0x04, 0x55,
- },
- {
- 0xF5, 0x2E, 0xCB, 0xC5, 0x65, 0xB3, 0xD8, 0xBE,
- 0xA2, 0xDF, 0xD5, 0xB7, 0x5A, 0x4F, 0x45, 0x7E,
- 0x54, 0x36, 0x98, 0x09, 0x32, 0x2E, 0x41, 0x20,
- 0x83, 0x16, 0x26, 0xF2, 0x90, 0xFA, 0x87, 0xE0,
- },
- {
- 0x19, 0x69, 0xAD, 0x73, 0xCC, 0x17, 0x7F, 0xA0,
- 0xB4, 0xFC, 0xED, 0x6D, 0xF1, 0xF7, 0xBF, 0x99,
- 0x07, 0xE6, 0x65, 0xFD, 0xE9, 0xBA, 0x19, 0x6A,
- 0x74, 0xFE, 0xD0, 0xA3, 0xCF, 0x5A, 0xEF, 0x9D,
- },
- };
- int is_xonly_t[4] = { 1, 0, 1, 0 };
- musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, tweak, is_xonly_t, 4, NULL, pk, 2);
- CHECK(musig_test_pk_parity(&keyagg_cache) == 0);
- CHECK(!musig_test_is_second_pk(&keyagg_cache, sk));
- CHECK(fin_nonce_parity == 1);
- CHECK(memcmp(sig, sig_expected, 32) == 0);
+}
+
+void musig_test_vectors_sigagg(void) {
+ size_t i, j;
+ const struct musig_sig_agg_vector *vector = &musig_sig_agg_vector;
+
+ for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) {
+ const struct musig_sig_agg_case *c = &vector->valid_case[i];
+ enum MUSIG_ERROR error;
+ unsigned char final_sig[64];
+ secp256k1_musig_keyagg_cache keyagg_cache;
+ unsigned char agg_pk32[32];
+ secp256k1_xonly_pubkey agg_pk;
+ secp256k1_musig_aggnonce aggnonce;
+ secp256k1_musig_session session;
+ secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))];
+ const secp256k1_musig_partial_sig *partial_sig_ptr[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))];
+
+ CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk32, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly));
+ CHECK(secp256k1_musig_aggnonce_parse(ctx, &aggnonce, c->aggnonce));
+ CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, vector->msg, &keyagg_cache, NULL));
+ for (j = 0; j < c->psig_indices_len; j++) {
+ CHECK(secp256k1_musig_partial_sig_parse(ctx, &partial_sig[j], vector->psigs[c->psig_indices[j]]));
+ partial_sig_ptr[j] = &partial_sig[j];
+ }
+
+ CHECK(secp256k1_musig_partial_sig_agg(ctx, final_sig, &session, partial_sig_ptr, c->psig_indices_len) == 1);
+ CHECK(secp256k1_memcmp_var(final_sig, c->expected, sizeof(final_sig)) == 0);
+
+ CHECK(secp256k1_xonly_pubkey_parse(ctx, &agg_pk, agg_pk32));
+ CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, vector->msg, sizeof(vector->msg), &agg_pk) == 1);
}
- {
- /* This is a test that includes an adaptor. */
- const unsigned char sig_expected[32] = {
- 0xD7, 0x67, 0xD0, 0x7D, 0x9A, 0xB8, 0x19, 0x8C,
- 0x9F, 0x64, 0xE3, 0xFD, 0x9F, 0x7B, 0x8B, 0xAA,
- 0xC6, 0x05, 0xF1, 0x8D, 0xFF, 0x18, 0x95, 0x24,
- 0x2D, 0x93, 0x95, 0xD9, 0xC8, 0xE6, 0xDD, 0x7C,
- };
- const unsigned char sec_adaptor[32] = {
- 0xD5, 0x6A, 0xD1, 0x85, 0x00, 0xF2, 0xD7, 0x8A,
- 0xB9, 0x54, 0x80, 0x53, 0x76, 0xF3, 0x9D, 0x1B,
- 0x6D, 0x62, 0x04, 0x95, 0x12, 0x39, 0x04, 0x6D,
- 0x99, 0x3A, 0x9C, 0x31, 0xE0, 0xF4, 0x78, 0x71,
- };
- secp256k1_pubkey pub_adaptor;
- CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor) == 1);
- musig_test_vectors_sign_helper(&keyagg_cache, &fin_nonce_parity, sig, secnonce, agg_pubnonce, sk, msg, NULL, NULL, 0, &pub_adaptor, pk, 2);
-
- CHECK(musig_test_pk_parity(&keyagg_cache) == 1);
- CHECK(!musig_test_is_second_pk(&keyagg_cache, sk));
- CHECK(fin_nonce_parity == 1);
- CHECK(memcmp(sig, sig_expected, 32) == 0);
+ for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) {
+ const struct musig_sig_agg_case *c = &vector->error_case[i];
+ secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))];
+ for (j = 0; j < c->psig_indices_len; j++) {
+ int expected = c->invalid_sig_idx != (int)j;
+ CHECK(expected == secp256k1_musig_partial_sig_parse(ctx, &partial_sig[j], vector->psigs[c->psig_indices[j]]));
+ }
}
}
@@ -1457,7 +1337,10 @@ void run_musig_tests(void) {
sha256_tag_test();
musig_test_vectors_keyagg();
musig_test_vectors_noncegen();
- musig_test_vectors_sign();
+ musig_test_vectors_nonceagg();
+ musig_test_vectors_signverify();
+ musig_test_vectors_tweak();
+ musig_test_vectors_sigagg();
secp256k1_scratch_space_destroy(ctx, scratch);
}
diff --git a/src/modules/musig/vectors.h b/src/modules/musig/vectors.h
new file mode 100644
index 00000000000..b959e0a2792
--- /dev/null
+++ b/src/modules/musig/vectors.h
@@ -0,0 +1,346 @@
+/**
+ * Automatically generated by contrib/musig2-vectors.py.
+ *
+ * The test vectors for the KeySort function are included in this file. They can
+ * be found in src/modules/extrakeys/tests_impl.h. */
+
+enum MUSIG_ERROR {
+ MUSIG_PUBKEY,
+ MUSIG_TWEAK,
+ MUSIG_PUBNONCE,
+ MUSIG_AGGNONCE,
+ MUSIG_SECNONCE,
+ MUSIG_SIG,
+ MUSIG_SIG_VERIFY,
+ MUSIG_OTHER
+};
+
+struct musig_key_agg_valid_test_case {
+ size_t key_indices_len;
+ size_t key_indices[4];
+ unsigned char expected[32];
+};
+
+struct musig_key_agg_error_test_case {
+ size_t key_indices_len;
+ size_t key_indices[4];
+ size_t tweak_indices_len;
+ size_t tweak_indices[1];
+ int is_xonly[1];
+ enum MUSIG_ERROR error;
+};
+
+struct musig_key_agg_vector {
+ unsigned char pubkeys[7][33];
+ unsigned char tweaks[2][32];
+ struct musig_key_agg_valid_test_case valid_case[4];
+ struct musig_key_agg_error_test_case error_case[5];
+};
+
+static const struct musig_key_agg_vector musig_key_agg_vector = {
+ {
+ { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
+ { 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 },
+ { 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2, 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51, 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 },
+ { 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, 0x05 },
+ { 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 },
+ { 0x04, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
+ { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }
+ },
+ {
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 },
+ { 0x25, 0x2E, 0x4B, 0xD6, 0x74, 0x10, 0xA7, 0x6C, 0xDF, 0x93, 0x3D, 0x30, 0xEA, 0xA1, 0x60, 0x82, 0x14, 0x03, 0x7F, 0x1B, 0x10, 0x5A, 0x01, 0x3E, 0xCC, 0xD3, 0xC5, 0xC1, 0x84, 0xA6, 0x11, 0x0B }
+ },
+ {
+ { 3, { 0, 1, 2 }, { 0x90, 0x53, 0x9E, 0xED, 0xE5, 0x65, 0xF5, 0xD0, 0x54, 0xF3, 0x2C, 0xC0, 0xC2, 0x20, 0x12, 0x68, 0x89, 0xED, 0x1E, 0x5D, 0x19, 0x3B, 0xAF, 0x15, 0xAE, 0xF3, 0x44, 0xFE, 0x59, 0xD4, 0x61, 0x0C }},
+ { 3, { 2, 1, 0 }, { 0x62, 0x04, 0xDE, 0x8B, 0x08, 0x34, 0x26, 0xDC, 0x6E, 0xAF, 0x95, 0x02, 0xD2, 0x70, 0x24, 0xD5, 0x3F, 0xC8, 0x26, 0xBF, 0x7D, 0x20, 0x12, 0x14, 0x8A, 0x05, 0x75, 0x43, 0x5D, 0xF5, 0x4B, 0x2B }},
+ { 3, { 0, 0, 0 }, { 0xB4, 0x36, 0xE3, 0xBA, 0xD6, 0x2B, 0x8C, 0xD4, 0x09, 0x96, 0x9A, 0x22, 0x47, 0x31, 0xC1, 0x93, 0xD0, 0x51, 0x16, 0x2D, 0x8C, 0x5A, 0xE8, 0xB1, 0x09, 0x30, 0x61, 0x27, 0xDA, 0x3A, 0xA9, 0x35 }},
+ { 4, { 0, 0, 1, 1 }, { 0x69, 0xBC, 0x22, 0xBF, 0xA5, 0xD1, 0x06, 0x30, 0x6E, 0x48, 0xA2, 0x06, 0x79, 0xDE, 0x1D, 0x73, 0x89, 0x38, 0x61, 0x24, 0xD0, 0x75, 0x71, 0xD0, 0xD8, 0x72, 0x68, 0x60, 0x28, 0xC2, 0x6A, 0x3E }},
+ },
+ {
+ { 2, { 0, 3 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY },
+ { 2, { 0, 4 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY },
+ { 2, { 5, 0 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY },
+ { 2, { 0, 1 }, 1, { 0 }, { 1 }, MUSIG_TWEAK },
+ { 1, { 6 }, 1, { 1 }, { 0 }, MUSIG_TWEAK },
+ },
+};
+
+struct musig_nonce_gen_test_case {
+ unsigned char rand_[32];
+ int has_sk;
+ unsigned char sk[32];
+ unsigned char pk[33];
+ int has_aggpk;
+ unsigned char aggpk[32];
+ int has_msg;
+ unsigned char msg[32];
+ int has_extra_in;
+ unsigned char extra_in[32];
+ unsigned char expected_secnonce[97];
+ unsigned char expected_pubnonce[66];
+};
+
+struct musig_nonce_gen_vector {
+ struct musig_nonce_gen_test_case test_case[2];
+};
+
+static const struct musig_nonce_gen_vector musig_nonce_gen_vector = {
+ {
+ { { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 1 , { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, { 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, 1 , { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 }, 1 , { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, 1 , { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, { 0xB1, 0x14, 0xE5, 0x02, 0xBE, 0xAA, 0x4E, 0x30, 0x1D, 0xD0, 0x8A, 0x50, 0x26, 0x41, 0x72, 0xC8, 0x4E, 0x41, 0x65, 0x0E, 0x6C, 0xB7, 0x26, 0xB4, 0x10, 0xC0, 0x69, 0x4D, 0x59, 0xEF, 0xFB, 0x64, 0x95, 0xB5, 0xCA, 0xF2, 0x8D, 0x04, 0x5B, 0x97, 0x3D, 0x63, 0xE3, 0xC9, 0x9A, 0x44, 0xB8, 0x07, 0xBD, 0xE3, 0x75, 0xFD, 0x6C, 0xB3, 0x9E, 0x46, 0xDC, 0x4A, 0x51, 0x17, 0x08, 0xD0, 0xE9, 0xD2, 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, { 0x02, 0xF7, 0xBE, 0x70, 0x89, 0xE8, 0x37, 0x6E, 0xB3, 0x55, 0x27, 0x23, 0x68, 0x76, 0x6B, 0x17, 0xE8, 0x8E, 0x7D, 0xB7, 0x20, 0x47, 0xD0, 0x5E, 0x56, 0xAA, 0x88, 0x1E, 0xA5, 0x2B, 0x3B, 0x35, 0xDF, 0x02, 0xC2, 0x9C, 0x80, 0x46, 0xFD, 0xD0, 0xDE, 0xD4, 0xC7, 0xE5, 0x58, 0x69, 0x13, 0x72, 0x00, 0xFB, 0xDB, 0xFE, 0x2E, 0xB6, 0x54, 0x26, 0x7B, 0x6D, 0x70, 0x13, 0x60, 0x2C, 0xAE, 0xD3, 0x11, 0x5A } },
+ { { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 0 , { 0 }, { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, 0 , { 0 }, 0 , { 0 }, 0 , { 0 }, { 0x89, 0xBD, 0xD7, 0x87, 0xD0, 0x28, 0x4E, 0x5E, 0x4D, 0x5F, 0xC5, 0x72, 0xE4, 0x9E, 0x31, 0x6B, 0xAB, 0x7E, 0x21, 0xE3, 0xB1, 0x83, 0x0D, 0xE3, 0x7D, 0xFE, 0x80, 0x15, 0x6F, 0xA4, 0x1A, 0x6D, 0x0B, 0x17, 0xAE, 0x8D, 0x02, 0x4C, 0x53, 0x67, 0x96, 0x99, 0xA6, 0xFD, 0x79, 0x44, 0xD9, 0xC4, 0xA3, 0x66, 0xB5, 0x14, 0xBA, 0xF4, 0x30, 0x88, 0xE0, 0x70, 0x8B, 0x10, 0x23, 0xDD, 0x28, 0x97, 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, { 0x02, 0xC9, 0x6E, 0x7C, 0xB1, 0xE8, 0xAA, 0x5D, 0xAC, 0x64, 0xD8, 0x72, 0x94, 0x79, 0x14, 0x19, 0x8F, 0x60, 0x7D, 0x90, 0xEC, 0xDE, 0x52, 0x00, 0xDE, 0x52, 0x97, 0x8A, 0xD5, 0xDE, 0xD6, 0x3C, 0x00, 0x02, 0x99, 0xEC, 0x51, 0x17, 0xC2, 0xD2, 0x9E, 0xDE, 0xE8, 0xA2, 0x09, 0x25, 0x87, 0xC3, 0x90, 0x9B, 0xE6, 0x94, 0xD5, 0xCF, 0xF0, 0x66, 0x7D, 0x6C, 0x02, 0xEA, 0x40, 0x59, 0xF7, 0xCD, 0x97, 0x86 } },
+ },
+};
+
+struct musig_nonce_agg_test_case {
+ size_t pnonce_indices[2];
+ /* if valid case */
+ unsigned char expected[66];
+ /* if error case */
+ int invalid_nonce_idx;
+};
+
+struct musig_nonce_agg_vector {
+ unsigned char pnonces[7][66];
+ struct musig_nonce_agg_test_case valid_case[2];
+ struct musig_nonce_agg_test_case error_case[3];
+};
+
+static const struct musig_nonce_agg_vector musig_nonce_agg_vector = {
+ {
+ { 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x03, 0xBA, 0x47, 0xFB, 0xC1, 0x83, 0x44, 0x37, 0xB3, 0x21, 0x2E, 0x89, 0xA8, 0x4D, 0x84, 0x25, 0xE7, 0xBF, 0x12, 0xE0, 0x24, 0x5D, 0x98, 0x26, 0x22, 0x68, 0xEB, 0xDC, 0xB3, 0x85, 0xD5, 0x06, 0x41 },
+ { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 },
+ { 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
+ { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x03, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
+ { 0x04, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 },
+ { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x31 },
+ { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 }
+ },
+ {
+ { { 0, 1 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x02, 0x47, 0x25, 0x37, 0x73, 0x45, 0xBD, 0xE0, 0xE9, 0xC3, 0x3A, 0xF3, 0xC4, 0x3C, 0x0A, 0x29, 0xA9, 0x24, 0x9F, 0x2F, 0x29, 0x56, 0xFA, 0x8C, 0xFE, 0xB5, 0x5C, 0x85, 0x73, 0xD0, 0x26, 0x2D, 0xC8 }, 0 },
+ { { 2, 3 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0 },
+ },
+ {
+ { { 0, 4 }, { 0 }, 1 },
+ { { 5, 1 }, { 0 }, 0 },
+ { { 6, 1 }, { 0 }, 0 },
+ },
+};
+
+/* Omit pubnonces in the test vectors because our partial signature verification
+ * implementation is able to accept the aggnonce directly. */
+struct musig_valid_case {
+ size_t key_indices_len;
+ size_t key_indices[3];
+ size_t aggnonce_index;
+ size_t msg_index;
+ size_t signer_index;
+ unsigned char expected[32];
+};
+
+struct musig_sign_error_case {
+ size_t key_indices_len;
+ size_t key_indices[3];
+ size_t aggnonce_index;
+ size_t msg_index;
+ size_t secnonce_index;
+ enum MUSIG_ERROR error;
+};
+
+struct musig_verify_fail_error_case {
+ unsigned char sig[32];
+ size_t key_indices_len;
+ size_t key_indices[3];
+ size_t nonce_indices_len;
+ size_t nonce_indices[3];
+ size_t msg_index;
+ size_t signer_index;
+ enum MUSIG_ERROR error;
+};
+
+struct musig_sign_verify_vector {
+ unsigned char sk[32];
+ unsigned char pubkeys[4][33];
+ unsigned char secnonces[2][194];
+ unsigned char pubnonces[5][194];
+ unsigned char aggnonces[5][66];
+ unsigned char msgs[1][32];
+ struct musig_valid_case valid_case[4];
+ struct musig_sign_error_case sign_error_case[6];
+ struct musig_verify_fail_error_case verify_fail_case[3];
+ struct musig_verify_fail_error_case verify_error_case[2];
+};
+
+static const struct musig_sign_verify_vector musig_sign_verify_vector = {
+ { 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 },
+ {
+ { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
+ { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
+ { 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x61 },
+ { 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, 0x07 }
+ },
+ {
+ { 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }
+ },
+ {
+ { 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 },
+ { 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
+ { 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 },
+ { 0x02, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x03, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 },
+ { 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, 0x09, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }
+ },
+ {
+ { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x04, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 },
+ { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 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, 0x09 },
+ { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 }
+ },
+ {
+ { 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF }
+ },
+ {
+ { 3, { 0, 1, 2 }, 0, 0, 0, { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }},
+ { 3, { 1, 0, 2 }, 0, 0, 1, { 0x9F, 0xF2, 0xF7, 0xAA, 0xA8, 0x56, 0x15, 0x0C, 0xC8, 0x81, 0x92, 0x54, 0x21, 0x8D, 0x3A, 0xDE, 0xEB, 0x05, 0x35, 0x26, 0x90, 0x51, 0x89, 0x77, 0x24, 0xF9, 0xDB, 0x37, 0x89, 0x51, 0x3A, 0x52 }},
+ { 3, { 1, 2, 0 }, 0, 0, 2, { 0xFA, 0x23, 0xC3, 0x59, 0xF6, 0xFA, 0xC4, 0xE7, 0x79, 0x6B, 0xB9, 0x3B, 0xC9, 0xF0, 0x53, 0x2A, 0x95, 0x46, 0x8C, 0x53, 0x9B, 0xA2, 0x0F, 0xF8, 0x6D, 0x7C, 0x76, 0xED, 0x92, 0x22, 0x79, 0x00 }},
+ { 2, { 0, 1 }, 1, 0, 0, { 0xAE, 0x38, 0x60, 0x64, 0xB2, 0x61, 0x05, 0x40, 0x47, 0x98, 0xF7, 0x5D, 0xE2, 0xEB, 0x9A, 0xF5, 0xED, 0xA5, 0x38, 0x7B, 0x06, 0x4B, 0x83, 0xD0, 0x49, 0xCB, 0x7C, 0x5E, 0x08, 0x87, 0x95, 0x31 }},
+ },
+ {
+ { 2, { 1, 2 }, 0, 0, 0, MUSIG_PUBKEY },
+ { 3, { 1, 0, 3 }, 0, 0, 0, MUSIG_PUBKEY },
+ { 3, { 1, 2, 0 }, 2, 0, 0, MUSIG_AGGNONCE },
+ { 3, { 1, 2, 0 }, 3, 0, 0, MUSIG_AGGNONCE },
+ { 3, { 1, 2, 0 }, 4, 0, 0, MUSIG_AGGNONCE },
+ { 3, { 0, 1, 2 }, 0, 0, 1, MUSIG_SECNONCE },
+ },
+ {
+ { { 0x97, 0xAC, 0x83, 0x3A, 0xDC, 0xB1, 0xAF, 0xA4, 0x2E, 0xBF, 0x9E, 0x07, 0x25, 0x61, 0x6F, 0x3C, 0x9A, 0x0D, 0x5B, 0x61, 0x4F, 0x6F, 0xE2, 0x83, 0xCE, 0xAA, 0xA3, 0x7A, 0x8F, 0xFA, 0xF4, 0x06 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG_VERIFY },
+ { { 0x68, 0x53, 0x7C, 0xC5, 0x23, 0x4E, 0x50, 0x5B, 0xD1, 0x40, 0x61, 0xF8, 0xDA, 0x9E, 0x90, 0xC2, 0x20, 0xA1, 0x81, 0x85, 0x5F, 0xD8, 0xBD, 0xB7, 0xF1, 0x27, 0xBB, 0x12, 0x40, 0x3B, 0x4D, 0x3B }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 1, MUSIG_SIG_VERIFY },
+ { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG },
+ },
+ {
+ { { 0x68, 0x53, 0x7C, 0xC5, 0x23, 0x4E, 0x50, 0x5B, 0xD1, 0x40, 0x61, 0xF8, 0xDA, 0x9E, 0x90, 0xC2, 0x20, 0xA1, 0x81, 0x85, 0x5F, 0xD8, 0xBD, 0xB7, 0xF1, 0x27, 0xBB, 0x12, 0x40, 0x3B, 0x4D, 0x3B }, 3, { 0, 1, 2 }, 3, { 4, 1, 2 }, 0, 0, MUSIG_PUBNONCE },
+ { { 0x68, 0x53, 0x7C, 0xC5, 0x23, 0x4E, 0x50, 0x5B, 0xD1, 0x40, 0x61, 0xF8, 0xDA, 0x9E, 0x90, 0xC2, 0x20, 0xA1, 0x81, 0x85, 0x5F, 0xD8, 0xBD, 0xB7, 0xF1, 0x27, 0xBB, 0x12, 0x40, 0x3B, 0x4D, 0x3B }, 3, { 3, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_PUBKEY },
+ },
+};
+
+struct musig_tweak_case {
+ size_t key_indices_len;
+ size_t key_indices[3];
+ size_t nonce_indices_len;
+ size_t nonce_indices[3];
+ size_t tweak_indices_len;
+ size_t tweak_indices[4];
+ int is_xonly[4];
+ size_t signer_index;
+ unsigned char expected[32];
+};
+
+struct musig_tweak_vector {
+ unsigned char sk[32];
+ unsigned char secnonce[97];
+ unsigned char aggnonce[66];
+ unsigned char msg[32];
+ unsigned char pubkeys[3][33];
+ unsigned char pubnonces[3][194];
+ unsigned char tweaks[5][32];
+ struct musig_tweak_case valid_case[5];
+ struct musig_tweak_case error_case[1];
+};
+
+static const struct musig_tweak_vector musig_tweak_vector = {
+ { 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 },
+ { 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
+ { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 },
+ { 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF },
+ {
+ { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
+ { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
+ { 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }
+ },
+ {
+ { 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 },
+ { 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
+ { 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 }
+ },
+ {
+ { 0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF, 0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D, 0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79, 0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB },
+ { 0xAE, 0x2E, 0xA7, 0x97, 0xCC, 0x0F, 0xE7, 0x2A, 0xC5, 0xB9, 0x7B, 0x97, 0xF3, 0xC6, 0x95, 0x7D, 0x7E, 0x41, 0x99, 0xA1, 0x67, 0xA5, 0x8E, 0xB0, 0x8B, 0xCA, 0xFF, 0xDA, 0x70, 0xAC, 0x04, 0x55 },
+ { 0xF5, 0x2E, 0xCB, 0xC5, 0x65, 0xB3, 0xD8, 0xBE, 0xA2, 0xDF, 0xD5, 0xB7, 0x5A, 0x4F, 0x45, 0x7E, 0x54, 0x36, 0x98, 0x09, 0x32, 0x2E, 0x41, 0x20, 0x83, 0x16, 0x26, 0xF2, 0x90, 0xFA, 0x87, 0xE0 },
+ { 0x19, 0x69, 0xAD, 0x73, 0xCC, 0x17, 0x7F, 0xA0, 0xB4, 0xFC, 0xED, 0x6D, 0xF1, 0xF7, 0xBF, 0x99, 0x07, 0xE6, 0x65, 0xFD, 0xE9, 0xBA, 0x19, 0x6A, 0x74, 0xFE, 0xD0, 0xA3, 0xCF, 0x5A, 0xEF, 0x9D },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }
+ },
+ {
+ { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 1 }, 2, { 0xE2, 0x8A, 0x5C, 0x66, 0xE6, 0x1E, 0x17, 0x8C, 0x2B, 0xA1, 0x9D, 0xB7, 0x7B, 0x6C, 0xF9, 0xF7, 0xE2, 0xF0, 0xF5, 0x6C, 0x17, 0x91, 0x8C, 0xD1, 0x31, 0x35, 0xE6, 0x0C, 0xC8, 0x48, 0xFE, 0x91 }},
+ { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 0 }, 2, { 0x38, 0xB0, 0x76, 0x77, 0x98, 0x25, 0x2F, 0x21, 0xBF, 0x57, 0x02, 0xC4, 0x80, 0x28, 0xB0, 0x95, 0x42, 0x83, 0x20, 0xF7, 0x3A, 0x4B, 0x14, 0xDB, 0x1E, 0x25, 0xDE, 0x58, 0x54, 0x3D, 0x2D, 0x2D }},
+ { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 2, { 0, 1 }, { 0, 1 }, 2, { 0x40, 0x8A, 0x0A, 0x21, 0xC4, 0xA0, 0xF5, 0xDA, 0xCA, 0xF9, 0x64, 0x6A, 0xD6, 0xEB, 0x6F, 0xEC, 0xD7, 0xF7, 0xA1, 0x1F, 0x03, 0xED, 0x1F, 0x48, 0xDF, 0xFF, 0x21, 0x85, 0xBC, 0x2C, 0x24, 0x08 }},
+ { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 0, 0, 1, 1 }, 2, { 0x45, 0xAB, 0xD2, 0x06, 0xE6, 0x1E, 0x3D, 0xF2, 0xEC, 0x9E, 0x26, 0x4A, 0x6F, 0xEC, 0x82, 0x92, 0x14, 0x1A, 0x63, 0x3C, 0x28, 0x58, 0x63, 0x88, 0x23, 0x55, 0x41, 0xF9, 0xAD, 0xE7, 0x54, 0x35 }},
+ { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 1, 0, 1, 0 }, 2, { 0xB2, 0x55, 0xFD, 0xCA, 0xC2, 0x7B, 0x40, 0xC7, 0xCE, 0x78, 0x48, 0xE2, 0xD3, 0xB7, 0xBF, 0x5E, 0xA0, 0xED, 0x75, 0x6D, 0xA8, 0x15, 0x65, 0xAC, 0x80, 0x4C, 0xCC, 0xA3, 0xE1, 0xD5, 0xD2, 0x39 }},
+ },
+ {
+ { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 4 }, { 0 }, 2, { 0 }},
+ },
+};
+
+/* Omit pubnonces in the test vectors because they're only needed for
+ * implementations that do not directly accept an aggnonce. */
+struct musig_sig_agg_case {
+ size_t key_indices_len;
+ size_t key_indices[2];
+ size_t tweak_indices_len;
+ size_t tweak_indices[3];
+ int is_xonly[3];
+ unsigned char aggnonce[66];
+ size_t psig_indices_len;
+ size_t psig_indices[2];
+ /* if valid case */
+ unsigned char expected[64];
+ /* if error case */
+ int invalid_sig_idx;
+};
+
+struct musig_sig_agg_vector {
+ unsigned char pubkeys[4][33];
+ unsigned char tweaks[3][32];
+ unsigned char psigs[9][32];
+ unsigned char msg[32];
+ struct musig_sig_agg_case valid_case[4];
+ struct musig_sig_agg_case error_case[1];
+};
+
+static const struct musig_sig_agg_vector musig_sig_agg_vector = {
+ {
+ { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
+ { 0x02, 0xD2, 0xDC, 0x6F, 0x5D, 0xF7, 0xC5, 0x6A, 0xCF, 0x38, 0xC7, 0xFA, 0x0A, 0xE7, 0xA7, 0x59, 0xAE, 0x30, 0xE1, 0x9B, 0x37, 0x35, 0x9D, 0xFD, 0xE0, 0x15, 0x87, 0x23, 0x24, 0xC7, 0xEF, 0x6E, 0x05 },
+ { 0x03, 0xC7, 0xFB, 0x10, 0x1D, 0x97, 0xFF, 0x93, 0x0A, 0xCD, 0x0C, 0x67, 0x60, 0x85, 0x2E, 0xF6, 0x4E, 0x69, 0x08, 0x3D, 0xE0, 0xB0, 0x6A, 0xC6, 0x33, 0x57, 0x24, 0x75, 0x4B, 0xB4, 0xB0, 0x52, 0x2C },
+ { 0x02, 0x35, 0x24, 0x33, 0xB2, 0x1E, 0x7E, 0x05, 0xD3, 0xB4, 0x52, 0xB8, 0x1C, 0xAE, 0x56, 0x6E, 0x06, 0xD2, 0xE0, 0x03, 0xEC, 0xE1, 0x6D, 0x10, 0x74, 0xAA, 0xBA, 0x42, 0x89, 0xE0, 0xE3, 0xD5, 0x81 }
+ },
+ {
+ { 0xB5, 0x11, 0xDA, 0x49, 0x21, 0x82, 0xA9, 0x1B, 0x0F, 0xFB, 0x9A, 0x98, 0x02, 0x0D, 0x55, 0xF2, 0x60, 0xAE, 0x86, 0xD7, 0xEC, 0xBD, 0x03, 0x99, 0xC7, 0x38, 0x3D, 0x59, 0xA5, 0xF2, 0xAF, 0x7C },
+ { 0xA8, 0x15, 0xFE, 0x04, 0x9E, 0xE3, 0xC5, 0xAA, 0xB6, 0x63, 0x10, 0x47, 0x7F, 0xBC, 0x8B, 0xCC, 0xCA, 0xC2, 0xF3, 0x39, 0x5F, 0x59, 0xF9, 0x21, 0xC3, 0x64, 0xAC, 0xD7, 0x8A, 0x2F, 0x48, 0xDC },
+ { 0x75, 0x44, 0x8A, 0x87, 0x27, 0x4B, 0x05, 0x64, 0x68, 0xB9, 0x77, 0xBE, 0x06, 0xEB, 0x1E, 0x9F, 0x65, 0x75, 0x77, 0xB7, 0x32, 0x0B, 0x0A, 0x33, 0x76, 0xEA, 0x51, 0xFD, 0x42, 0x0D, 0x18, 0xA8 }
+ },
+ {
+ { 0xB1, 0x5D, 0x2C, 0xD3, 0xC3, 0xD2, 0x2B, 0x04, 0xDA, 0xE4, 0x38, 0xCE, 0x65, 0x3F, 0x6B, 0x4E, 0xCF, 0x04, 0x2F, 0x42, 0xCF, 0xDE, 0xD7, 0xC4, 0x1B, 0x64, 0xAA, 0xF9, 0xB4, 0xAF, 0x53, 0xFB },
+ { 0x61, 0x93, 0xD6, 0xAC, 0x61, 0xB3, 0x54, 0xE9, 0x10, 0x5B, 0xBD, 0xC8, 0x93, 0x7A, 0x34, 0x54, 0xA6, 0xD7, 0x05, 0xB6, 0xD5, 0x73, 0x22, 0xA5, 0xA4, 0x72, 0xA0, 0x2C, 0xE9, 0x9F, 0xCB, 0x64 },
+ { 0x9A, 0x87, 0xD3, 0xB7, 0x9E, 0xC6, 0x72, 0x28, 0xCB, 0x97, 0x87, 0x8B, 0x76, 0x04, 0x9B, 0x15, 0xDB, 0xD0, 0x5B, 0x81, 0x58, 0xD1, 0x7B, 0x5B, 0x91, 0x14, 0xD3, 0xC2, 0x26, 0x88, 0x75, 0x05 },
+ { 0x66, 0xF8, 0x2E, 0xA9, 0x09, 0x23, 0x68, 0x9B, 0x85, 0x5D, 0x36, 0xC6, 0xB7, 0xE0, 0x32, 0xFB, 0x99, 0x70, 0x30, 0x14, 0x81, 0xB9, 0x9E, 0x01, 0xCD, 0xB4, 0xD6, 0xAC, 0x7C, 0x34, 0x7A, 0x15 },
+ { 0x4F, 0x5A, 0xEE, 0x41, 0x51, 0x08, 0x48, 0xA6, 0x44, 0x7D, 0xCD, 0x1B, 0xBC, 0x78, 0x45, 0x7E, 0xF6, 0x90, 0x24, 0x94, 0x4C, 0x87, 0xF4, 0x02, 0x50, 0xD3, 0xEF, 0x2C, 0x25, 0xD3, 0x3E, 0xFE },
+ { 0xDD, 0xEF, 0x42, 0x7B, 0xBB, 0x84, 0x7C, 0xC0, 0x27, 0xBE, 0xFF, 0x4E, 0xDB, 0x01, 0x03, 0x81, 0x48, 0x91, 0x78, 0x32, 0x25, 0x3E, 0xBC, 0x35, 0x5F, 0xC3, 0x3F, 0x4A, 0x8E, 0x2F, 0xCC, 0xE4 },
+ { 0x97, 0xB8, 0x90, 0xA2, 0x6C, 0x98, 0x1D, 0xA8, 0x10, 0x2D, 0x3B, 0xC2, 0x94, 0x15, 0x9D, 0x17, 0x1D, 0x72, 0x81, 0x0F, 0xDF, 0x7C, 0x6A, 0x69, 0x1D, 0xEF, 0x02, 0xF0, 0xF7, 0xAF, 0x3F, 0xDC },
+ { 0x53, 0xFA, 0x9E, 0x08, 0xBA, 0x52, 0x43, 0xCB, 0xCB, 0x0D, 0x79, 0x7C, 0x5E, 0xE8, 0x3B, 0xC6, 0x72, 0x8E, 0x53, 0x9E, 0xB7, 0x6C, 0x2D, 0x0B, 0xF0, 0xF9, 0x71, 0xEE, 0x4E, 0x90, 0x99, 0x71 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }
+ },
+ { 0x59, 0x9C, 0x67, 0xEA, 0x41, 0x0D, 0x00, 0x5B, 0x9D, 0xA9, 0x08, 0x17, 0xCF, 0x03, 0xED, 0x3B, 0x1C, 0x86, 0x8E, 0x4D, 0xA4, 0xED, 0xF0, 0x0A, 0x58, 0x80, 0xB0, 0x08, 0x2C, 0x23, 0x78, 0x69 },
+ {
+ { 2, { 0, 1 }, 0, { 0 }, { 0 }, { 0x03, 0x41, 0x43, 0x27, 0x22, 0xC5, 0xCD, 0x02, 0x68, 0xD8, 0x29, 0xC7, 0x02, 0xCF, 0x0D, 0x1C, 0xBC, 0xE5, 0x70, 0x33, 0xEE, 0xD2, 0x01, 0xFD, 0x33, 0x51, 0x91, 0x38, 0x52, 0x27, 0xC3, 0x21, 0x0C, 0x03, 0xD3, 0x77, 0xF2, 0xD2, 0x58, 0xB6, 0x4A, 0xAD, 0xC0, 0xE1, 0x6F, 0x26, 0x46, 0x23, 0x23, 0xD7, 0x01, 0xD2, 0x86, 0x04, 0x6A, 0x2E, 0xA9, 0x33, 0x65, 0x65, 0x6A, 0xFD, 0x98, 0x75, 0x98, 0x2B }, 2, { 0, 1 }, { 0x04, 0x1D, 0xA2, 0x22, 0x23, 0xCE, 0x65, 0xC9, 0x2C, 0x9A, 0x0D, 0x6C, 0x2C, 0xAC, 0x82, 0x8A, 0xAF, 0x1E, 0xEE, 0x56, 0x30, 0x4F, 0xEC, 0x37, 0x1D, 0xDF, 0x91, 0xEB, 0xB2, 0xB9, 0xEF, 0x09, 0x12, 0xF1, 0x03, 0x80, 0x25, 0x85, 0x7F, 0xED, 0xEB, 0x3F, 0xF6, 0x96, 0xF8, 0xB9, 0x9F, 0xA4, 0xBB, 0x2C, 0x58, 0x12, 0xF6, 0x09, 0x5A, 0x2E, 0x00, 0x04, 0xEC, 0x99, 0xCE, 0x18, 0xDE, 0x1E }, 0 },
+ { 2, { 0, 2 }, 0, { 0 }, { 0 }, { 0x02, 0x24, 0xAF, 0xD3, 0x6C, 0x90, 0x20, 0x84, 0x05, 0x8B, 0x51, 0xB5, 0xD3, 0x66, 0x76, 0xBB, 0xA4, 0xDC, 0x97, 0xC7, 0x75, 0x87, 0x37, 0x68, 0xE5, 0x88, 0x22, 0xF8, 0x7F, 0xE4, 0x37, 0xD7, 0x92, 0x02, 0x8C, 0xB1, 0x59, 0x29, 0x09, 0x9E, 0xEE, 0x2F, 0x5D, 0xAE, 0x40, 0x4C, 0xD3, 0x93, 0x57, 0x59, 0x1B, 0xA3, 0x2E, 0x9A, 0xF4, 0xE1, 0x62, 0xB8, 0xD3, 0xE7, 0xCB, 0x5E, 0xFE, 0x31, 0xCB, 0x20 }, 2, { 2, 3 }, { 0x10, 0x69, 0xB6, 0x7E, 0xC3, 0xD2, 0xF3, 0xC7, 0xC0, 0x82, 0x91, 0xAC, 0xCB, 0x17, 0xA9, 0xC9, 0xB8, 0xF2, 0x81, 0x9A, 0x52, 0xEB, 0x5D, 0xF8, 0x72, 0x6E, 0x17, 0xE7, 0xD6, 0xB5, 0x2E, 0x9F, 0x01, 0x80, 0x02, 0x60, 0xA7, 0xE9, 0xDA, 0xC4, 0x50, 0xF4, 0xBE, 0x52, 0x2D, 0xE4, 0xCE, 0x12, 0xBA, 0x91, 0xAE, 0xAF, 0x2B, 0x42, 0x79, 0x21, 0x9E, 0xF7, 0x4B, 0xE1, 0xD2, 0x86, 0xAD, 0xD9 }, 0 },
+ { 2, { 0, 2 }, 1, { 0 }, { 0 }, { 0x02, 0x08, 0xC5, 0xC4, 0x38, 0xC7, 0x10, 0xF4, 0xF9, 0x6A, 0x61, 0xE9, 0xFF, 0x3C, 0x37, 0x75, 0x88, 0x14, 0xB8, 0xC3, 0xAE, 0x12, 0xBF, 0xEA, 0x0E, 0xD2, 0xC8, 0x7F, 0xF6, 0x95, 0x4F, 0xF1, 0x86, 0x02, 0x0B, 0x18, 0x16, 0xEA, 0x10, 0x4B, 0x4F, 0xCA, 0x2D, 0x30, 0x4D, 0x73, 0x3E, 0x0E, 0x19, 0xCE, 0xAD, 0x51, 0x30, 0x3F, 0xF6, 0x42, 0x0B, 0xFD, 0x22, 0x23, 0x35, 0xCA, 0xA4, 0x02, 0x91, 0x6D }, 2, { 4, 5 }, { 0x5C, 0x55, 0x8E, 0x1D, 0xCA, 0xDE, 0x86, 0xDA, 0x0B, 0x2F, 0x02, 0x62, 0x6A, 0x51, 0x2E, 0x30, 0xA2, 0x2C, 0xF5, 0x25, 0x5C, 0xAE, 0xA7, 0xEE, 0x32, 0xC3, 0x8E, 0x9A, 0x71, 0xA0, 0xE9, 0x14, 0x8B, 0xA6, 0xC0, 0xE6, 0xEC, 0x76, 0x83, 0xB6, 0x42, 0x20, 0xF0, 0x29, 0x86, 0x96, 0xF1, 0xB8, 0x78, 0xCD, 0x47, 0xB1, 0x07, 0xB8, 0x1F, 0x71, 0x88, 0x81, 0x2D, 0x59, 0x39, 0x71, 0xE0, 0xCC }, 0 },
+ { 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 6, 7 }, { 0x83, 0x9B, 0x08, 0x82, 0x0B, 0x68, 0x1D, 0xBA, 0x8D, 0xAF, 0x4C, 0xC7, 0xB1, 0x04, 0xE8, 0xF2, 0x63, 0x8F, 0x93, 0x88, 0xF8, 0xD7, 0xA5, 0x55, 0xDC, 0x17, 0xB6, 0xE6, 0x97, 0x1D, 0x74, 0x26, 0xCE, 0x07, 0xBF, 0x6A, 0xB0, 0x1F, 0x1D, 0xB5, 0x0E, 0x4E, 0x33, 0x71, 0x92, 0x95, 0xF4, 0x09, 0x45, 0x72, 0xB7, 0x98, 0x68, 0xE4, 0x40, 0xFB, 0x3D, 0xEF, 0xD3, 0xFA, 0xC1, 0xDB, 0x58, 0x9E }, 0 },
+ },
+ {
+ { 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 7, 8 }, { 0 }, 1 },
+ },
+};
+enum { MUSIG_VECTORS_MAX_PUBKEYS = 7 };
diff --git a/src/modules/rangeproof/Makefile.am.include b/src/modules/rangeproof/Makefile.am.include
index ff8b8d38031..5272f229316 100644
--- a/src/modules/rangeproof/Makefile.am.include
+++ b/src/modules/rangeproof/Makefile.am.include
@@ -1,7 +1,5 @@
include_HEADERS += include/secp256k1_rangeproof.h
noinst_HEADERS += src/modules/rangeproof/main_impl.h
-noinst_HEADERS += src/modules/rangeproof/pedersen.h
-noinst_HEADERS += src/modules/rangeproof/pedersen_impl.h
noinst_HEADERS += src/modules/rangeproof/borromean.h
noinst_HEADERS += src/modules/rangeproof/borromean_impl.h
noinst_HEADERS += src/modules/rangeproof/rangeproof.h
diff --git a/src/modules/rangeproof/borromean.h b/src/modules/rangeproof/borromean.h
index efd4da1624b..c3ce76c942b 100644
--- a/src/modules/rangeproof/borromean.h
+++ b/src/modules/rangeproof/borromean.h
@@ -5,14 +5,14 @@
**********************************************************************/
-#ifndef _SECP256K1_BORROMEAN_H_
-#define _SECP256K1_BORROMEAN_H_
+#ifndef SECP256K1_BORROMEAN_H
+#define SECP256K1_BORROMEAN_H
-#include "scalar.h"
-#include "field.h"
-#include "group.h"
-#include "ecmult.h"
-#include "ecmult_gen.h"
+#include "../../scalar.h"
+#include "../../field.h"
+#include "../../group.h"
+#include "../../ecmult.h"
+#include "../../ecmult_gen.h"
int secp256k1_borromean_verify(secp256k1_scalar *evalues, const unsigned char *e0, const secp256k1_scalar *s,
const secp256k1_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen);
diff --git a/src/modules/rangeproof/borromean_impl.h b/src/modules/rangeproof/borromean_impl.h
index 0b8dcd47895..fb5e44db04f 100644
--- a/src/modules/rangeproof/borromean_impl.h
+++ b/src/modules/rangeproof/borromean_impl.h
@@ -5,16 +5,16 @@
**********************************************************************/
-#ifndef _SECP256K1_BORROMEAN_IMPL_H_
-#define _SECP256K1_BORROMEAN_IMPL_H_
+#ifndef SECP256K1_BORROMEAN_IMPL_H
+#define SECP256K1_BORROMEAN_IMPL_H
-#include "scalar.h"
-#include "field.h"
-#include "group.h"
-#include "hash.h"
-#include "eckey.h"
-#include "ecmult.h"
-#include "ecmult_gen.h"
+#include "../../scalar.h"
+#include "../../field.h"
+#include "../../group.h"
+#include "../../hash.h"
+#include "../../eckey.h"
+#include "../../ecmult.h"
+#include "../../ecmult_gen.h"
#include "borromean.h"
#include
@@ -105,7 +105,7 @@ int secp256k1_borromean_verify(secp256k1_scalar *evalues, const unsigned char *e
}
secp256k1_sha256_write(&sha256_e0, m, mlen);
secp256k1_sha256_finalize(&sha256_e0, tmp);
- return memcmp(e0, tmp, 32) == 0;
+ return secp256k1_memcmp_var(e0, tmp, 32) == 0;
}
int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
diff --git a/src/modules/rangeproof/main_impl.h b/src/modules/rangeproof/main_impl.h
index 9129e4c304c..32614caa9bd 100644
--- a/src/modules/rangeproof/main_impl.h
+++ b/src/modules/rangeproof/main_impl.h
@@ -4,230 +4,14 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef SECP256K1_MODULE_RANGEPROOF_MAIN
-#define SECP256K1_MODULE_RANGEPROOF_MAIN
+#ifndef SECP256K1_MODULE_RANGEPROOF_MAIN_H
+#define SECP256K1_MODULE_RANGEPROOF_MAIN_H
-#include "group.h"
+#include "../../group.h"
-#include "modules/rangeproof/pedersen_impl.h"
-#include "modules/rangeproof/borromean_impl.h"
-#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())
- */
-static const secp256k1_generator secp256k1_generator_h_internal = {{
- 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
-}};
-
-const secp256k1_generator *secp256k1_generator_h = &secp256k1_generator_h_internal;
-
-static void secp256k1_pedersen_commitment_load(secp256k1_ge* ge, const secp256k1_pedersen_commitment* commit) {
- secp256k1_fe fe;
- secp256k1_fe_set_b32(&fe, &commit->data[1]);
- secp256k1_ge_set_xquad(ge, &fe);
- if (commit->data[0] & 1) {
- secp256k1_ge_neg(ge, ge);
- }
-}
-
-static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* commit, secp256k1_ge* ge) {
- secp256k1_fe_normalize(&ge->x);
- secp256k1_fe_get_b32(&commit->data[1], &ge->x);
- commit->data[0] = 9 ^ secp256k1_fe_is_quad_var(&ge->y);
-}
-
-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)) {
- return 0;
- }
- if (input[0] & 1) {
- secp256k1_ge_neg(&ge, &ge);
- }
- secp256k1_pedersen_commitment_save(commit, &ge);
- 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);
- return 1;
-}
-
-/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/
-int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const secp256k1_generator* gen) {
- secp256k1_ge genp;
- secp256k1_gej rj;
- secp256k1_ge r;
- secp256k1_scalar sec;
- int overflow;
- int ret = 0;
- VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
- ARG_CHECK(commit != NULL);
- ARG_CHECK(blind != NULL);
- ARG_CHECK(gen != NULL);
- secp256k1_generator_load(&genp, gen);
- secp256k1_scalar_set_b32(&sec, blind, &overflow);
- if (!overflow) {
- secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &rj, &sec, value, &genp);
- if (!secp256k1_gej_is_infinity(&rj)) {
- secp256k1_ge_set_gej(&r, &rj);
- secp256k1_pedersen_commitment_save(commit, &r);
- ret = 1;
- }
- secp256k1_gej_clear(&rj);
- secp256k1_ge_clear(&r);
- }
- secp256k1_scalar_clear(&sec);
- return ret;
-}
-
-/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest
- * negative, then calculates an additional blinding value that adds to zero.
- */
-int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *blind_out, const unsigned char * const *blinds, size_t n, size_t npositive) {
- secp256k1_scalar acc;
- secp256k1_scalar x;
- size_t i;
- int overflow;
- VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(blind_out != NULL);
- ARG_CHECK(blinds != NULL);
- ARG_CHECK(npositive <= n);
- (void) ctx;
- secp256k1_scalar_set_int(&acc, 0);
- for (i = 0; i < n; i++) {
- secp256k1_scalar_set_b32(&x, blinds[i], &overflow);
- if (overflow) {
- return 0;
- }
- if (i >= npositive) {
- secp256k1_scalar_negate(&x, &x);
- }
- secp256k1_scalar_add(&acc, &acc, &x);
- }
- secp256k1_scalar_get_b32(blind_out, &acc);
- secp256k1_scalar_clear(&acc);
- secp256k1_scalar_clear(&x);
- return 1;
-}
-
-/* Takes two lists of commitments and sums the first set and subtracts the second and verifies that they sum to excess. */
-int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k1_pedersen_commitment * const* commits, size_t pcnt, const secp256k1_pedersen_commitment * const* ncommits, size_t ncnt) {
- secp256k1_gej accj;
- secp256k1_ge add;
- size_t i;
- VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(!pcnt || (commits != NULL));
- ARG_CHECK(!ncnt || (ncommits != NULL));
- (void) ctx;
- secp256k1_gej_set_infinity(&accj);
- for (i = 0; i < ncnt; i++) {
- secp256k1_pedersen_commitment_load(&add, ncommits[i]);
- secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
- }
- secp256k1_gej_neg(&accj, &accj);
- for (i = 0; i < pcnt; i++) {
- secp256k1_pedersen_commitment_load(&add, commits[i]);
- secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
- }
- return secp256k1_gej_is_infinity(&accj);
-}
-
-int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) {
- secp256k1_scalar sum;
- secp256k1_scalar tmp;
- size_t i;
-
- VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(n_total == 0 || value != NULL);
- ARG_CHECK(n_total == 0 || generator_blind != NULL);
- ARG_CHECK(n_total == 0 || blinding_factor != NULL);
- ARG_CHECK(n_total > n_inputs);
- (void) ctx;
-
- if (n_total == 0) {
- return 1;
- }
-
- secp256k1_scalar_set_int(&sum, 0);
-
- /* Here, n_total > 0. Thus the loop runs at least once.
- Thus we may use a do-while loop, which checks the loop
- condition only at the end.
-
- The do-while loop helps GCC prove that the loop runs at least
- once and suppresses a -Wmaybe-uninitialized warning. */
- i = 0;
- do {
- int overflow = 0;
- secp256k1_scalar addend;
- secp256k1_scalar_set_u64(&addend, value[i]); /* s = v */
-
- secp256k1_scalar_set_b32(&tmp, generator_blind[i], &overflow);
- if (overflow == 1) {
- secp256k1_scalar_clear(&tmp);
- secp256k1_scalar_clear(&addend);
- secp256k1_scalar_clear(&sum);
- return 0;
- }
- secp256k1_scalar_mul(&addend, &addend, &tmp); /* s = vr */
-
- secp256k1_scalar_set_b32(&tmp, blinding_factor[i], &overflow);
- if (overflow == 1) {
- secp256k1_scalar_clear(&tmp);
- secp256k1_scalar_clear(&addend);
- secp256k1_scalar_clear(&sum);
- return 0;
- }
- secp256k1_scalar_add(&addend, &addend, &tmp); /* s = vr + r' */
- secp256k1_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */
- secp256k1_scalar_add(&sum, &sum, &addend); /* sum += s */
- secp256k1_scalar_clear(&addend);
-
- i++;
- } while (i < n_total);
-
- /* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */
- secp256k1_scalar_negate(&sum, &sum);
- secp256k1_scalar_add(&tmp, &tmp, &sum);
- secp256k1_scalar_get_b32(blinding_factor[n_total - 1], &tmp);
-
- secp256k1_scalar_clear(&tmp);
- secp256k1_scalar_clear(&sum);
- return 1;
-}
+#include "../generator/main_impl.h"
+#include "../rangeproof/borromean_impl.h"
+#include "../rangeproof/rangeproof_impl.h"
int secp256k1_rangeproof_info(const secp256k1_context* ctx, int *exp, int *mantissa,
uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) {
@@ -304,4 +88,16 @@ int secp256k1_rangeproof_sign(const secp256k1_context* ctx, unsigned char *proof
proof, plen, min_value, &commitp, blind, nonce, exp, min_bits, value, message, msg_len, extra_commit, extra_commit_len, &genp);
}
+size_t secp256k1_rangeproof_max_size(const secp256k1_context* ctx, uint64_t max_value, int min_bits) {
+ const int val_mantissa = max_value > 0 ? 64 - secp256k1_clz64_var(max_value) : 1;
+ const int mantissa = min_bits > val_mantissa ? min_bits : val_mantissa;
+ const size_t rings = (mantissa + 1) / 2;
+ const size_t npubs = rings * 4 - 2 * (mantissa % 2);
+
+ VERIFY_CHECK(ctx != NULL);
+ (void) ctx;
+
+ return 10 + 32 * (npubs + rings - 1) + 32 + ((rings - 1 + 7) / 8);
+}
+
#endif
diff --git a/src/modules/rangeproof/rangeproof.h b/src/modules/rangeproof/rangeproof.h
index fd8cf9505c2..fa118e662fd 100644
--- a/src/modules/rangeproof/rangeproof.h
+++ b/src/modules/rangeproof/rangeproof.h
@@ -4,13 +4,13 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_RANGEPROOF_H_
-#define _SECP256K1_RANGEPROOF_H_
+#ifndef SECP256K1_RANGEPROOF_H
+#define SECP256K1_RANGEPROOF_H
-#include "scalar.h"
-#include "group.h"
-#include "ecmult.h"
-#include "ecmult_gen.h"
+#include "../../scalar.h"
+#include "../../group.h"
+#include "../../ecmult.h"
+#include "../../ecmult_gen.h"
static int secp256k1_rangeproof_verify_impl(const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce,
diff --git a/src/modules/rangeproof/rangeproof_impl.h b/src/modules/rangeproof/rangeproof_impl.h
index 184b798822a..c08f817ebdb 100644
--- a/src/modules/rangeproof/rangeproof_impl.h
+++ b/src/modules/rangeproof/rangeproof_impl.h
@@ -4,19 +4,18 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_RANGEPROOF_IMPL_H_
-#define _SECP256K1_RANGEPROOF_IMPL_H_
+#ifndef SECP256K1_RANGEPROOF_IMPL_H
+#define SECP256K1_RANGEPROOF_IMPL_H
-#include "eckey.h"
-#include "scalar.h"
-#include "group.h"
-#include "rangeproof.h"
-#include "hash_impl.h"
-#include "pedersen_impl.h"
-#include "util.h"
+#include "../../eckey.h"
+#include "../../scalar.h"
+#include "../../group.h"
+#include "../../hash_impl.h"
+#include "../../util.h"
-#include "modules/rangeproof/pedersen.h"
-#include "modules/rangeproof/borromean.h"
+#include "../generator/pedersen.h"
+#include "../rangeproof/borromean.h"
+#include "../rangeproof/rangeproof.h"
SECP256K1_INLINE static void secp256k1_rangeproof_pub_expand(secp256k1_gej *pubs,
int exp, size_t *rsizes, size_t rings, const secp256k1_ge* genp) {
@@ -402,7 +401,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar *
idx = npub + rsizes[rings - 1] - 1 - j;
secp256k1_scalar_get_b32(tmp, &s[idx]);
secp256k1_rangeproof_ch32xor(tmp, &prep[idx * 32]);
- if ((tmp[0] & 128) && (memcmp(&tmp[16], &tmp[24], 8) == 0) && (memcmp(&tmp[8], &tmp[16], 8) == 0)) {
+ if ((tmp[0] & 128) && (secp256k1_memcmp_var(&tmp[16], &tmp[24], 8) == 0) && (secp256k1_memcmp_var(&tmp[8], &tmp[16], 8) == 0)) {
value = 0;
for (i = 0; i < 8; i++) {
value = (value << 8) + tmp[24 + i];
diff --git a/src/modules/rangeproof/tests_impl.h b/src/modules/rangeproof/tests_impl.h
index 41c4d616f8d..33b67ed107e 100644
--- a/src/modules/rangeproof/tests_impl.h
+++ b/src/modules/rangeproof/tests_impl.h
@@ -4,77 +4,17 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef SECP256K1_MODULE_RANGEPROOF_TESTS
-#define SECP256K1_MODULE_RANGEPROOF_TESTS
+#ifndef SECP256K1_MODULE_RANGEPROOF_TESTS_H
+#define SECP256K1_MODULE_RANGEPROOF_TESTS_H
#include
-#include "group.h"
-#include "scalar.h"
-#include "testrand.h"
-#include "util.h"
+#include "../../group.h"
+#include "../../scalar.h"
+#include "../../testrand.h"
+#include "../../util.h"
-#include "include/secp256k1_rangeproof.h"
-
-static void test_pedersen_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const secp256k1_context *sttc, const int32_t *ecount) {
- secp256k1_pedersen_commitment commit;
- const secp256k1_pedersen_commitment *commit_ptr = &commit;
- unsigned char blind[32];
- unsigned char blind_out[32];
- const unsigned char *blind_ptr = blind;
- unsigned char *blind_out_ptr = blind_out;
- uint64_t val = secp256k1_testrand32();
-
- secp256k1_testrand256(blind);
- CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, secp256k1_generator_h) != 0);
- CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, secp256k1_generator_h) != 0);
- CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
- CHECK(*ecount == 0);
- CHECK(secp256k1_pedersen_commit(sttc, &commit, blind, val, secp256k1_generator_h) == 0);
- CHECK(*ecount == 1);
-
- CHECK(secp256k1_pedersen_commit(sign, NULL, blind, val, secp256k1_generator_h) == 0);
- CHECK(*ecount == 2);
- CHECK(secp256k1_pedersen_commit(sign, &commit, NULL, val, secp256k1_generator_h) == 0);
- CHECK(*ecount == 3);
- CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, NULL) == 0);
- CHECK(*ecount == 4);
-
- CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0);
- CHECK(*ecount == 4);
- CHECK(secp256k1_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0);
- CHECK(*ecount == 5);
- CHECK(secp256k1_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0);
- CHECK(*ecount == 6);
- CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0);
- CHECK(*ecount == 7);
- CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0);
- CHECK(*ecount == 7);
-
- CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
- CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0);
- CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0);
- CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0);
- CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0);
- CHECK(*ecount == 7);
- CHECK(secp256k1_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0);
- CHECK(*ecount == 8);
- CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0);
- CHECK(*ecount == 9);
-
- CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0);
- CHECK(*ecount == 9);
- CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0);
- CHECK(*ecount == 10);
- CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0);
- CHECK(*ecount == 11);
- CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0);
- CHECK(*ecount == 12);
- CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0);
- CHECK(*ecount == 13);
- CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0);
- CHECK(*ecount == 14);
-}
+#include "../../../include/secp256k1_rangeproof.h"
static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const secp256k1_context *both, const secp256k1_context *sttc, const int32_t *ecount) {
unsigned char proof[5134];
@@ -196,7 +136,7 @@ static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_c
CHECK(max_value >= val);
CHECK(value_out == val);
CHECK(message_len == sizeof(message_out));
- CHECK(memcmp(message, message_out, sizeof(message_out)) == 0);
+ CHECK(secp256k1_memcmp_var(message, message_out, sizeof(message_out)) == 0);
CHECK(secp256k1_rangeproof_rewind(both, NULL, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
CHECK(*ecount == 21); /* blindout may be NULL */
@@ -225,6 +165,11 @@ static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_c
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0);
CHECK(*ecount == 29);
}
+
+ /* This constant is hardcoded in these tests and elsewhere, so we
+ * consider it to be part of the API and test it here. */
+ CHECK(secp256k1_rangeproof_max_size(none, 0, 64) == 5134);
+ CHECK(secp256k1_rangeproof_max_size(none, UINT64_MAX, 0) == 5134);
}
static void test_api(void) {
@@ -248,8 +193,6 @@ static void test_api(void) {
secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
for (i = 0; i < count; i++) {
- ecount = 0;
- test_pedersen_api(none, sign, vrfy, sttc, &ecount);
ecount = 0;
test_rangeproof_api(none, sign, vrfy, both, sttc, &ecount);
}
@@ -261,63 +204,6 @@ static void test_api(void) {
secp256k1_context_destroy(sttc);
}
-static void test_pedersen(void) {
- secp256k1_pedersen_commitment commits[19];
- const secp256k1_pedersen_commitment *cptr[19];
- unsigned char blinds[32*19];
- const unsigned char *bptr[19];
- secp256k1_scalar s;
- uint64_t values[19];
- int64_t totalv;
- int i;
- int inputs;
- int outputs;
- int total;
- inputs = (secp256k1_testrand32() & 7) + 1;
- outputs = (secp256k1_testrand32() & 7) + 2;
- total = inputs + outputs;
- for (i = 0; i < 19; i++) {
- cptr[i] = &commits[i];
- bptr[i] = &blinds[i * 32];
- }
- totalv = 0;
- for (i = 0; i < inputs; i++) {
- values[i] = secp256k1_testrandi64(0, INT64_MAX - totalv);
- totalv += values[i];
- }
- for (i = 0; i < outputs - 1; i++) {
- values[i + inputs] = secp256k1_testrandi64(0, totalv);
- totalv -= values[i + inputs];
- }
- values[total - 1] = totalv;
-
- for (i = 0; i < total - 1; i++) {
- random_scalar_order(&s);
- secp256k1_scalar_get_b32(&blinds[i * 32], &s);
- }
- CHECK(secp256k1_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs));
- for (i = 0; i < total; i++) {
- CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
- }
- CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs));
- CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs));
- if (inputs > 0 && values[0] > 0) {
- CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs - 1, &cptr[inputs], outputs));
- }
- random_scalar_order(&s);
- for (i = 0; i < 4; i++) {
- secp256k1_scalar_get_b32(&blinds[i * 32], &s);
- }
- values[0] = INT64_MAX;
- values[1] = 0;
- values[2] = 1;
- for (i = 0; i < 3; i++) {
- CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
- }
- CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1));
- CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1));
-}
-
static void test_borromean(void) {
unsigned char e0[32];
secp256k1_scalar s[64];
@@ -431,24 +317,26 @@ static void test_rangeproof(void) {
len = 5134;
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, 0, 0, v, input_message, input_message_len, NULL, 0, secp256k1_generator_h));
CHECK(len <= 5134);
+ CHECK(len <= secp256k1_rangeproof_max_size(ctx, v, 0));
mlen = 4096;
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
if (input_message != NULL) {
- CHECK(memcmp(message, input_message, input_message_len) == 0);
+ CHECK(secp256k1_memcmp_var(message, input_message, input_message_len) == 0);
}
for (j = input_message_len; j < mlen; j++) {
CHECK(message[j] == 0);
}
CHECK(mlen <= 4096);
- CHECK(memcmp(blindout, blind, 32) == 0);
+ CHECK(secp256k1_memcmp_var(blindout, blind, 32) == 0);
CHECK(vout == v);
CHECK(minv <= v);
CHECK(maxv >= v);
len = 5134;
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, NULL, 0, secp256k1_generator_h));
CHECK(len <= 73);
+ CHECK(len <= secp256k1_rangeproof_max_size(ctx, v, 0));
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
- CHECK(memcmp(blindout, blind, 32) == 0);
+ CHECK(secp256k1_memcmp_var(blindout, blind, 32) == 0);
CHECK(vout == v);
CHECK(minv == v);
CHECK(maxv == v);
@@ -457,10 +345,11 @@ static void test_rangeproof(void) {
len = 5134;
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, message_short, sizeof(message_short), secp256k1_generator_h));
CHECK(len <= 73);
+ CHECK(len <= secp256k1_rangeproof_max_size(ctx, v, 0));
CHECK(!secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
CHECK(!secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_long, sizeof(message_long), secp256k1_generator_h));
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), secp256k1_generator_h));
- CHECK(memcmp(blindout, blind, 32) == 0);
+ CHECK(secp256k1_memcmp_var(blindout, blind, 32) == 0);
CHECK(vout == v);
CHECK(minv == v);
CHECK(maxv == v);
@@ -472,6 +361,7 @@ static void test_rangeproof(void) {
for (i = 0; i < 19; i++) {
len = 5134;
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, i, 0, v, NULL, 0, NULL, 0, secp256k1_generator_h));
+ CHECK(len <= secp256k1_rangeproof_max_size(ctx, v, 0));
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
CHECK(len <= 5134);
CHECK(minv <= v);
@@ -487,6 +377,7 @@ static void test_rangeproof(void) {
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);
+ CHECK(len <= secp256k1_rangeproof_max_size(ctx, v, 3));
/* 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));
@@ -521,13 +412,14 @@ static void test_rangeproof(void) {
}
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, exp, min_bits, v, NULL, 0, NULL, 0, secp256k1_generator_h));
CHECK(len <= 5134);
+ CHECK(len <= secp256k1_rangeproof_max_size(ctx, v, min_bits));
mlen = 4096;
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
for (j = 0; j < mlen; j++) {
CHECK(message[j] == 0);
}
CHECK(mlen <= 4096);
- CHECK(memcmp(blindout, blind, 32) == 0);
+ CHECK(secp256k1_memcmp_var(blindout, blind, 32) == 0);
CHECK(minv <= v);
CHECK(maxv >= v);
@@ -547,8 +439,149 @@ static void test_rangeproof(void) {
}
}
+static void test_rangeproof_null_blinder(void) {
+ unsigned char proof[5134];
+ const unsigned char blind[32] = { 0 };
+ const uint64_t v = 1111;
+ uint64_t minv, maxv;
+ secp256k1_pedersen_commitment commit;
+ size_t len;
+
+ CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
+
+ /* Try a 32-bit proof; should work */
+ len = 5134;
+ CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 1, &commit, blind, commit.data, 0, 32, v, NULL, 0, NULL, 0, secp256k1_generator_h));
+ CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
+ CHECK(minv == 1);
+ CHECK(maxv == 1ULL << 32);
+
+ /* Try a 3-bit proof; should work */
+ len = 5134;
+ CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v - 1, &commit, blind, commit.data, 0, 3, v, NULL, 0, NULL, 0, secp256k1_generator_h));
+ CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
+ CHECK(minv == 1110);
+ CHECK(maxv == 1117);
+
+ /* But a 2-bits will not because then it does not have any subcommitments (which rerandomize
+ * the blinding factors that get passed into the borromean logic ... passing 0s will fail) */
+ len = 5134;
+ CHECK(!secp256k1_rangeproof_sign(ctx, proof, &len, v - 1, &commit, blind, commit.data, 0, 2, v, NULL, 0, NULL, 0, secp256k1_generator_h));
+
+ /* Rewinding with 3-bits works */
+ {
+ uint64_t value_out;
+ unsigned char msg[128];
+ unsigned char msg_out[128];
+ unsigned char blind_out[32];
+ size_t msg_len = sizeof(msg);
+
+ len = 1000;
+ secp256k1_testrand256(msg);
+ secp256k1_testrand256(&msg[32]);
+ secp256k1_testrand256(&msg[64]);
+ secp256k1_testrand256(&msg[96]);
+ CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, 0, 3, v, msg, sizeof(msg), NULL, 0, secp256k1_generator_h));
+ CHECK(secp256k1_rangeproof_rewind(ctx, blind_out, &value_out, msg_out, &msg_len, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h) != 0);
+ CHECK(secp256k1_memcmp_var(blind, blind_out, sizeof(blind)) == 0);
+ CHECK(secp256k1_memcmp_var(msg, msg_out, sizeof(msg)) == 0);
+ CHECK(value_out == v);
+ CHECK(minv == v);
+ CHECK(maxv == v + 7);
+ }
+}
+
+static void test_single_value_proof(uint64_t val) {
+ unsigned char proof[5000];
+ secp256k1_pedersen_commitment commit;
+ unsigned char blind[32];
+ unsigned char blind_out[32];
+ unsigned char nonce[32];
+ const unsigned char message[1] = " "; /* no message will fit into a single-value proof */
+ unsigned char message_out[sizeof(proof)] = { 0 };
+ size_t plen = sizeof(proof);
+ uint64_t min_val_out = 0;
+ uint64_t max_val_out = 0;
+
+ uint64_t val_out = 0;
+ size_t m_len_out = 0;
+
+ secp256k1_testrand256(blind);
+ secp256k1_testrand256(nonce);
+ CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, val, secp256k1_generator_h));
+
+ CHECK(secp256k1_rangeproof_sign(
+ ctx,
+ proof, &plen,
+ val, /* min_val */
+ &commit, blind, nonce,
+ -1, /* exp: -1 is magic value to indicate a single-value proof */
+ 0, /* min_bits */
+ val, /* val */
+ message, sizeof(message), /* Will cause this to fail */
+ NULL, 0,
+ secp256k1_generator_h
+ ) == 0);
+
+ plen = sizeof(proof);
+ CHECK(secp256k1_rangeproof_sign(
+ ctx,
+ proof, &plen,
+ val, /* min_val */
+ &commit, blind, nonce,
+ -1, /* exp: -1 is magic value to indicate a single-value proof */
+ 0, /* min_bits */
+ val, /* val */
+ NULL, 0,
+ NULL, 0,
+ secp256k1_generator_h
+ ) == 1);
+ CHECK(plen <= secp256k1_rangeproof_max_size(ctx, val, 0));
+
+ /* Different proof sizes are unfortunate but is caused by `min_value` of
+ * zero being special-cased and encoded more efficiently. */
+ if (val == 0) {
+ CHECK(plen == 65);
+ } else {
+ CHECK(plen == 73);
+ }
+
+ CHECK(secp256k1_rangeproof_verify(
+ ctx,
+ &min_val_out, &max_val_out,
+ &commit,
+ proof, plen,
+ NULL, 0,
+ secp256k1_generator_h
+ ) == 1);
+ CHECK(min_val_out == val);
+ CHECK(max_val_out == val);
+
+ memset(message_out, 0, sizeof(message_out));
+ m_len_out = sizeof(message_out);
+ CHECK(secp256k1_rangeproof_rewind(
+ ctx,
+ blind_out, &val_out,
+ message_out, &m_len_out,
+ nonce,
+ &min_val_out, &max_val_out,
+ &commit,
+ proof, plen,
+ NULL, 0,
+ secp256k1_generator_h
+ ));
+ CHECK(val_out == val);
+ CHECK(min_val_out == val);
+ CHECK(max_val_out == val);
+ CHECK(m_len_out == 0);
+ CHECK(secp256k1_memcmp_var(blind, blind_out, 32) == 0);
+ for (m_len_out = 0; m_len_out < sizeof(message_out); m_len_out++) {
+ CHECK(message_out[m_len_out] == 0);
+ }
+}
+
#define MAX_N_GENS 30
-void test_multiple_generators(void) {
+static 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_generators = n_inputs + n_outputs;
@@ -610,7 +643,18 @@ void test_multiple_generators(void) {
}
void test_rangeproof_fixed_vectors(void) {
- const unsigned char vector_1[] = {
+ size_t i;
+ unsigned char blind[32];
+ uint64_t value;
+ uint64_t min_value;
+ uint64_t max_value;
+ secp256k1_pedersen_commitment pc;
+ unsigned char message[4000] = {0};
+ size_t m_len = sizeof(message);
+
+ /* Vector 1: no message */
+{
+ static 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,
@@ -653,58 +697,728 @@ void test_rangeproof_fixed_vectors(void) {
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[] = {
+ static 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;
+ static const unsigned char blind_1[] = {
+ 0x98, 0x44, 0xfc, 0x7a, 0x64, 0xa9, 0xca, 0xdf, 0xf3, 0x2f, 0x9f, 0x02, 0xba, 0x46, 0xc7, 0xd9,
+ 0x77, 0x47, 0xa4, 0xd3, 0x53, 0x17, 0xc6, 0x44, 0x30, 0x73, 0x84, 0xeb, 0x1f, 0xbe, 0xa1, 0xfb
+ };
CHECK(secp256k1_pedersen_commitment_parse(ctx, &pc, commit_1));
-
CHECK(secp256k1_rangeproof_verify(
ctx,
- &min_value_1, &max_value_1,
+ &min_value, &max_value,
+ &pc,
+ vector_1, sizeof(vector_1),
+ NULL, 0,
+ secp256k1_generator_h
+ ));
+ CHECK(min_value == 86);
+ CHECK(max_value == 25586);
+
+ CHECK(secp256k1_rangeproof_rewind(
+ ctx,
+ blind, &value,
+ message, &m_len,
+ pc.data,
+ &min_value, &max_value,
&pc,
vector_1, sizeof(vector_1),
NULL, 0,
secp256k1_generator_h
));
+
+ CHECK(secp256k1_memcmp_var(blind, blind_1, 32) == 0);
+ CHECK(value == 86);
+ CHECK(min_value == 86);
+ CHECK(max_value == 25586);
+ CHECK(m_len == 448); /* length of the sidechannel in the proof */
+ for (i = 0; i < m_len; i++) {
+ /* No message encoded in this vector */
+ CHECK(message[i] == 0);
+ }
}
-void test_pedersen_commitment_fixed_vector(void) {
- const unsigned char two_g[33] = {
+ /* Vector 2: embedded message */
+{
+ static const unsigned char vector_2[] = {
+ 0x40, 0x03, 0x00, 0x90, 0x1a, 0x61, 0x64, 0xbb, 0x85, 0x1a, 0x78, 0x35, 0x1e, 0xe0, 0xd5, 0x96,
+ 0x71, 0x0f, 0x18, 0x8e, 0xf3, 0x33, 0xf0, 0x75, 0xfe, 0xd6, 0xc6, 0x11, 0x6b, 0x42, 0x89, 0xea,
+ 0xa2, 0x0c, 0x89, 0x25, 0x37, 0x81, 0x10, 0xf9, 0xf0, 0x9b, 0xda, 0x68, 0x2a, 0xd9, 0x2e, 0x0c,
+ 0x45, 0x17, 0x54, 0x6d, 0x02, 0xd2, 0x21, 0x5d, 0xbc, 0x10, 0xf8, 0x8f, 0xf1, 0x92, 0x40, 0xa9,
+ 0xc7, 0x24, 0x00, 0x1b, 0xc8, 0x75, 0x0f, 0xf6, 0x8f, 0x93, 0x8b, 0x78, 0x62, 0x73, 0x3c, 0x86,
+ 0x4b, 0x61, 0x7c, 0x0f, 0xc6, 0x41, 0xc9, 0xb3, 0xc1, 0x30, 0x7f, 0xd4, 0xee, 0x9f, 0x37, 0x08,
+ 0x9b, 0x64, 0x23, 0xd5, 0xe6, 0x1a, 0x03, 0x54, 0x74, 0x9b, 0x0b, 0xae, 0x6f, 0x2b, 0x1e, 0xf5,
+ 0x40, 0x44, 0xaa, 0x12, 0xe8, 0xbd, 0xe0, 0xa6, 0x85, 0x89, 0xf1, 0xa9, 0xd0, 0x3f, 0x2e, 0xc6,
+ 0x1f, 0x11, 0xf5, 0x44, 0x69, 0x99, 0x31, 0x10, 0x2e, 0x64, 0xc6, 0x44, 0xdb, 0x47, 0x06, 0x6d,
+ 0xd5, 0xf2, 0x8d, 0x19, 0x00, 0x39, 0xb8, 0xca, 0xda, 0x5c, 0x1d, 0x83, 0xbd, 0xa3, 0x6d, 0xbf,
+ 0x97, 0xdd, 0x83, 0x86, 0xc9, 0x56, 0xe2, 0xbb, 0x37, 0x4b, 0x2d, 0xb5, 0x9d, 0xf2, 0x7a, 0x6a,
+ 0x25, 0x47, 0xfa, 0x03, 0x05, 0xc5, 0xda, 0x73, 0xe1, 0x96, 0x15, 0x21, 0x23, 0xe5, 0xef, 0x55,
+ 0x36, 0xdd, 0xf1, 0xb1, 0x3f, 0x33, 0x1a, 0x91, 0x6c, 0x73, 0x64, 0xd3, 0x88, 0xe7, 0xc6, 0xc9,
+ 0x04, 0x29, 0xae, 0x55, 0x27, 0xa0, 0x80, 0x60, 0xaf, 0x0c, 0x09, 0x2f, 0xc8, 0x1b, 0xe6, 0x16,
+ 0x9e, 0xed, 0x29, 0xc7, 0x93, 0xce, 0xc7, 0x0d, 0xdf, 0x1f, 0x28, 0xba, 0xf3, 0x38, 0xc3, 0xaa,
+ 0x99, 0xd9, 0x21, 0x41, 0xb8, 0x10, 0xa5, 0x48, 0x37, 0xec, 0x60, 0xda, 0x64, 0x5a, 0x73, 0x55,
+ 0xd7, 0xff, 0x23, 0xfa, 0xf6, 0xc6, 0xf4, 0xe2, 0xca, 0x99, 0x2f, 0x30, 0x36, 0x48, 0x73, 0x8b,
+ 0x57, 0xa6, 0x62, 0x12, 0xa3, 0xe7, 0x5c, 0xa8, 0xd1, 0xe6, 0x85, 0x05, 0x59, 0xfe, 0x2b, 0x44,
+ 0xe4, 0x73, 0x1c, 0xc3, 0x56, 0x32, 0x07, 0x65, 0x4a, 0x58, 0xaf, 0x2b, 0x3f, 0x36, 0xca, 0xb4,
+ 0x1d, 0x5c, 0x2a, 0x46, 0x1f, 0xf7, 0x63, 0x59, 0x4f, 0x2b, 0xd0, 0xf6, 0xfc, 0xcf, 0x04, 0x09,
+ 0xb7, 0x65, 0x1b
+ };
+ static const unsigned char commit_2[] = {
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
+ 0x25, 0xa4, 0xbd, 0xc4, 0x57, 0x69, 0xeb, 0x4f, 0x34, 0x0f, 0xea, 0xb8, 0xe4, 0x72, 0x04, 0x54,
+ 0x06, 0xe5, 0xd6, 0x85, 0x15, 0x42, 0xea, 0x6e, 0x1d, 0x11, 0x11, 0x9c, 0x56, 0xf8, 0x10, 0x45
+ };
+ static const unsigned char blind_2[] = {
+ 0xdc, 0x79, 0x07, 0x89, 0x2d, 0xc4, 0xe3, 0x76, 0xf9, 0x13, 0x38, 0xd6, 0x4b, 0x46, 0xed, 0x9d,
+ 0x9b, 0xf6, 0x70, 0x3d, 0x04, 0xcf, 0x96, 0x8c, 0xfd, 0xb5, 0xff, 0x0a, 0x06, 0xc7, 0x08, 0x8b
};
- unsigned char result[33];
- secp256k1_pedersen_commitment parse;
+ static const unsigned char message_2[] = "When I see my own likeness in the depths of someone else's consciousness, I always experience a moment of panic.";
+
+ CHECK(secp256k1_pedersen_commitment_parse(ctx, &pc, commit_2));
+ CHECK(secp256k1_rangeproof_verify(
+ ctx,
+ &min_value, &max_value,
+ &pc,
+ vector_2, sizeof(vector_2),
+ NULL, 0,
+ secp256k1_generator_h
+ ));
+ CHECK(min_value == 0);
+ CHECK(max_value == 15);
+
+ CHECK(secp256k1_rangeproof_rewind(
+ ctx,
+ blind, &value,
+ message, &m_len,
+ pc.data,
+ &min_value, &max_value,
+ &pc,
+ vector_2, sizeof(vector_2),
+ NULL, 0,
+ secp256k1_generator_h
+ ));
+
+ CHECK(secp256k1_memcmp_var(blind, blind_2, 32) == 0);
+ CHECK(value == 11);
+ CHECK(min_value == 0);
+ CHECK(max_value == 15);
+ CHECK(m_len == 192); /* length of the sidechannel in the proof */
+ CHECK(secp256k1_memcmp_var(message, message_2, sizeof(message_2)) == 0);
+ for (i = sizeof(message_2); i < m_len; i++) {
+ CHECK(message[i] == 0);
+ }
+}
+
+ /* Vector 3: single-value proof of UINT64_MAX */
+{
+ static const unsigned char vector_3[] = {
+ 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0x7d, 0x0b, 0x79, 0x0e, 0xaf, 0x41,
+ 0xa5, 0x8e, 0x9b, 0x0c, 0x5b, 0xa3, 0xee, 0x7d, 0xfd, 0x3d, 0x6b, 0xf3, 0xac, 0x04, 0x8a, 0x43,
+ 0x75, 0xb0, 0xb7, 0x0e, 0x92, 0xd7, 0xdf, 0xf0, 0x76, 0xc4, 0xa5, 0xb6, 0x2f, 0xf1, 0xb5, 0xfb,
+ 0xb4, 0xb6, 0x29, 0xea, 0x34, 0x9b, 0x16, 0x30, 0x0d, 0x06, 0xf1, 0xb4, 0x3f, 0x0d, 0x73, 0x59,
+ 0x75, 0xbf, 0x5d, 0x19, 0x59, 0xef, 0x11, 0xf0, 0xbf
+ };
+ static const unsigned char commit_3[] = {
+ 0x08,
+ 0xc7, 0xea, 0x40, 0x7d, 0x26, 0x38, 0xa2, 0x99, 0xb9, 0x40, 0x22, 0x78, 0x17, 0x57, 0x65, 0xb3,
+ 0x36, 0x82, 0x18, 0x42, 0xc5, 0x57, 0x04, 0x5e, 0x58, 0x5e, 0xf6, 0x40, 0x8b, 0x24, 0x73, 0x10
+ };
+ static const unsigned char nonce_3[] = {
+ 0x84, 0x50, 0x94, 0x69, 0xa3, 0x4b, 0x6c, 0x62, 0x1a, 0xc7, 0xe2, 0x0e, 0x07, 0x9a, 0x6f, 0x85,
+ 0x5f, 0x26, 0x50, 0xcd, 0x88, 0x5a, 0x9f, 0xaa, 0x23, 0x5e, 0x0a, 0xe0, 0x7e, 0xc5, 0xe9, 0xf1
+ };
+ static const unsigned char blind_3[] = {
+ 0x68, 0x89, 0x47, 0x8c, 0x77, 0xec, 0xcc, 0x2b, 0x65, 0x01, 0x78, 0x6b, 0x06, 0x8b, 0x38, 0x94,
+ 0xc0, 0x6b, 0x9b, 0x4c, 0x02, 0xa6, 0xc8, 0xf6, 0xc0, 0x34, 0xea, 0x35, 0x57, 0xf4, 0xe1, 0x37
+ };
+
+ CHECK(secp256k1_pedersen_commitment_parse(ctx, &pc, commit_3));
+ CHECK(secp256k1_rangeproof_verify(
+ ctx,
+ &min_value, &max_value,
+ &pc,
+ vector_3, sizeof(vector_3),
+ NULL, 0,
+ secp256k1_generator_h
+ ));
+ CHECK(min_value == UINT64_MAX);
+ CHECK(max_value == UINT64_MAX);
+
+ CHECK(secp256k1_rangeproof_rewind(
+ ctx,
+ blind, &value,
+ message, &m_len,
+ nonce_3,
+ &min_value, &max_value,
+ &pc,
+ vector_3, sizeof(vector_3),
+ NULL, 0,
+ secp256k1_generator_h
+ ));
+ CHECK(secp256k1_memcmp_var(blind, blind_3, 32) == 0);
+ CHECK(value == UINT64_MAX);
+ CHECK(min_value == UINT64_MAX);
+ CHECK(max_value == UINT64_MAX);
+ CHECK(m_len == 0);
+}
+}
+
+static void print_vector_helper(unsigned char *buf, size_t buf_len) {
+ size_t j;
+ printf(" ");
+ for (j = 0; j < buf_len; j++) {
+ printf("0x%02x", buf[j]);
+ if (j == buf_len-1) {
+ printf(",\n");
+ } else if ((j+1) % 16 != 0) {
+ printf(", ");
+ } else {
+ printf(",\n");
+ printf(" ");
+ }
+ }
+ printf("};\n");
+}
- CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, two_g));
- CHECK(secp256k1_pedersen_commitment_serialize(ctx, result, &parse));
- CHECK(memcmp(two_g, result, 33) == 0);
+static void print_vector(int i, unsigned char *proof, size_t p_len, secp256k1_pedersen_commitment *commit) {
+ unsigned char commit_output[33];
- result[0] = 0x08;
- CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, result));
- result[0] = 0x0c;
- CHECK(!secp256k1_pedersen_commitment_parse(ctx, &parse, result));
+ printf("unsigned char vector_%d[] = {\n", i);
+ print_vector_helper(proof, p_len);
+
+ CHECK(secp256k1_pedersen_commitment_serialize(ctx, commit_output, commit));
+ printf("unsigned char commit_%d[] = {\n", i);
+ print_vector_helper(commit_output, sizeof(commit_output));
+}
+
+
+/* Use same nonce and blinding value for all "reproducible" test vectors */
+static unsigned char vector_blind[] = {
+ 0x48, 0x26, 0xad, 0x41, 0x37, 0x4c, 0x25, 0x62, 0x52, 0x14, 0x78, 0x82, 0x89, 0x9c, 0x86, 0x27,
+ 0xa1, 0x19, 0xf6, 0xe1, 0xfa, 0x44, 0xe4, 0x29, 0x08, 0xa7, 0xb3, 0x45, 0xad, 0x35, 0xb2, 0xd9,
+};
+static unsigned char vector_nonce[] = {
+ 0xc8, 0x5c, 0x7e, 0x6c, 0xa1, 0xfa, 0x11, 0x35, 0xc7, 0x45, 0x24, 0x8a, 0xb5, 0x28, 0x6d, 0x1a,
+ 0x88, 0x00, 0xff, 0xca, 0x96, 0x0f, 0xc7, 0x77, 0xa5, 0x96, 0x7a, 0x5e, 0xf8, 0x88, 0x2d, 0xd4,
+};
+
+/* Maximum length of a message that can be embedded into a rangeproof */
+void test_rangeproof_fixed_vectors_reproducible_helper(unsigned char *vector, size_t vector_len, unsigned char *commit, uint64_t *value_r, uint64_t *min_value_r, uint64_t *max_value_r, unsigned char *message_r, size_t *m_len_r) {
+ secp256k1_pedersen_commitment pc;
+ unsigned char blind_r[32];
+
+ CHECK(secp256k1_pedersen_commitment_parse(ctx, &pc, commit));
+ CHECK(secp256k1_rangeproof_verify(
+ ctx,
+ min_value_r, max_value_r,
+ &pc,
+ vector, vector_len,
+ NULL, 0,
+ secp256k1_generator_h
+ ));
+
+ *m_len_r = SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN;
+ CHECK(secp256k1_rangeproof_rewind(
+ ctx,
+ blind_r, value_r,
+ message_r, m_len_r,
+ vector_nonce,
+ min_value_r, max_value_r,
+ &pc,
+ vector, vector_len,
+ NULL, 0,
+ secp256k1_generator_h
+ ));
+ CHECK(secp256k1_memcmp_var(blind_r, vector_blind, sizeof(vector_blind)) == 0);
+}
+
+void test_rangeproof_fixed_vectors_reproducible(void) {
+ uint64_t value_r;
+ uint64_t min_value_r;
+ uint64_t max_value_r;
+ unsigned char message[SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN], message_r[SECP256K1_RANGEPROOF_MAX_MESSAGE_LEN];
+ size_t m_len_r;
+ memset(message, 0xFF, sizeof(message));
+
+ /* Test maximum values for value, min_bits, m_len and exp */
+ {
+ uint64_t value = UINT64_MAX;
+ uint64_t min_value = 0;
+ size_t m_len = sizeof(message); /* maximum message length */
+
+ int min_bits = 64;
+ int exp = 18;
+ unsigned char proof[5126];
+ size_t p_len = sizeof(proof);
+ secp256k1_pedersen_commitment pc;
+
+ unsigned char vector_0[] = {
+ 0x40, 0x3f, 0xd1, 0x77, 0x65, 0x05, 0x87, 0x88, 0xd0, 0x3d, 0xb2, 0x24, 0x60, 0x7a, 0x08, 0x76,
+ 0xf8, 0x9f, 0x5a, 0x00, 0x73, 0x32, 0x6b, 0x5b, 0x0b, 0x59, 0xda, 0xa0, 0x6d, 0x2b, 0x66, 0xb8,
+ 0xfa, 0xa4, 0x8c, 0xf9, 0x78, 0x5e, 0xe3, 0xc7, 0x30, 0xea, 0xb4, 0x31, 0x77, 0x3a, 0xe4, 0xe3,
+ 0xf0, 0x76, 0x15, 0x21, 0x07, 0xb3, 0x6e, 0x84, 0x36, 0xdb, 0x45, 0xe6, 0x2b, 0x14, 0x50, 0xf3,
+ 0x53, 0x5d, 0x79, 0xf8, 0x6d, 0xc4, 0x99, 0x36, 0xa4, 0x7c, 0xc1, 0x14, 0x90, 0x99, 0xa8, 0x4b,
+ 0xf0, 0x01, 0x9f, 0xe7, 0xd4, 0xf9, 0xf1, 0x74, 0xb0, 0x7f, 0xf5, 0x90, 0x8d, 0x27, 0x9e, 0x61,
+ 0x9e, 0xc5, 0xd0, 0xa6, 0x32, 0xe8, 0x64, 0x4a, 0x02, 0x8b, 0xbf, 0xf7, 0xb8, 0x31, 0xa3, 0x4d,
+ 0x99, 0xbe, 0x12, 0x77, 0x4b, 0x07, 0x4a, 0xef, 0x75, 0xb4, 0xb3, 0x6e, 0x96, 0x95, 0xff, 0xe9,
+ 0xf7, 0xfc, 0x27, 0x17, 0x62, 0xfa, 0x99, 0xed, 0x00, 0x3c, 0xdd, 0xaa, 0xae, 0x9e, 0x80, 0xc1,
+ 0x29, 0x73, 0x4d, 0xfc, 0x41, 0xe6, 0xb4, 0x21, 0xe2, 0x62, 0x78, 0xf5, 0x46, 0xef, 0xcd, 0xcf,
+ 0x15, 0x2a, 0x05, 0x80, 0xb9, 0x95, 0xaa, 0xa5, 0xe9, 0x69, 0x5f, 0xfd, 0x58, 0x12, 0x00, 0x51,
+ 0xc4, 0x8f, 0xa2, 0xce, 0x03, 0x7f, 0x16, 0x19, 0xb1, 0x77, 0xc2, 0x98, 0xbe, 0xaa, 0x18, 0x6a,
+ 0x80, 0x0b, 0x4a, 0x81, 0x85, 0xc0, 0xc2, 0x62, 0xb3, 0xec, 0xae, 0xe7, 0x95, 0xbf, 0xd3, 0xe0,
+ 0xcd, 0xa3, 0xdd, 0x02, 0x70, 0x98, 0x6c, 0xf3, 0x4b, 0x43, 0xec, 0x8d, 0x07, 0xf4, 0x3e, 0xb0,
+ 0x00, 0x7c, 0xb7, 0x1a, 0x85, 0x9a, 0x94, 0xe8, 0x57, 0xc9, 0x7e, 0x24, 0xb4, 0x7a, 0x84, 0x17,
+ 0x08, 0xe6, 0xae, 0x91, 0x14, 0xcb, 0x94, 0xf3, 0xe9, 0x13, 0x25, 0x35, 0x54, 0xbf, 0x22, 0xe9,
+ 0xab, 0x8e, 0xa4, 0xa1, 0x18, 0x78, 0x6c, 0xee, 0x13, 0x26, 0xfc, 0x79, 0xf1, 0xe5, 0x51, 0x1e,
+ 0x0c, 0xac, 0xa5, 0xef, 0x0d, 0xee, 0xe8, 0x5f, 0x93, 0xa4, 0x88, 0x4a, 0x32, 0x95, 0x8a, 0x61,
+ 0x76, 0xd8, 0xac, 0x2d, 0x36, 0x9a, 0x6b, 0xa4, 0x7c, 0x30, 0xa3, 0x09, 0x38, 0xbb, 0xbc, 0x51,
+ 0x1a, 0x10, 0xae, 0x9e, 0x18, 0x9f, 0xd8, 0xc8, 0xce, 0xfa, 0x63, 0xab, 0x28, 0xc9, 0x76, 0x28,
+ 0x32, 0x61, 0x39, 0x83, 0x99, 0x0a, 0x41, 0xc0, 0x55, 0x1c, 0x65, 0x6c, 0xcf, 0xc3, 0x72, 0x47,
+ 0xe7, 0xb1, 0x99, 0xb5, 0x04, 0x44, 0xb9, 0xde, 0x4b, 0x83, 0x37, 0x66, 0xb2, 0xee, 0x9f, 0x07,
+ 0xf1, 0x4f, 0x4d, 0x59, 0xee, 0x37, 0x79, 0x47, 0x0e, 0x31, 0x70, 0x3a, 0xfa, 0xe0, 0xa1, 0xef,
+ 0xa2, 0x1f, 0xeb, 0xe8, 0xd7, 0x4f, 0xcb, 0xc2, 0xce, 0xdc, 0x82, 0xa6, 0x36, 0xed, 0x1d, 0xdd,
+ 0xa6, 0x40, 0x10, 0x38, 0x4f, 0x28, 0x90, 0xc3, 0xe3, 0xb6, 0xa4, 0x74, 0xbb, 0x56, 0x23, 0x01,
+ 0x3a, 0xb6, 0xb1, 0xad, 0x94, 0x4b, 0x52, 0x42, 0x0a, 0x9d, 0xd6, 0x89, 0xdd, 0xa7, 0x0f, 0x66,
+ 0xdb, 0x4e, 0x5b, 0xa4, 0xc2, 0x11, 0xd7, 0xd5, 0xf7, 0x0a, 0xf1, 0xc8, 0x35, 0x16, 0xc0, 0x7d,
+ 0x29, 0x5d, 0x5c, 0x62, 0x6b, 0xe0, 0x1b, 0x74, 0x8d, 0x14, 0x9e, 0x08, 0xb6, 0x18, 0x0d, 0x2b,
+ 0x3a, 0xfb, 0x22, 0x9e, 0xd6, 0x77, 0x05, 0x1b, 0xd4, 0x5d, 0x25, 0x27, 0x97, 0x40, 0x93, 0x58,
+ 0x35, 0xad, 0xc5, 0x19, 0x96, 0x62, 0xbb, 0x10, 0x2d, 0x4e, 0x24, 0x62, 0xc0, 0x1a, 0xe6, 0x12,
+ 0x84, 0xac, 0x1b, 0x5e, 0x25, 0xa9, 0xc7, 0x5d, 0xa0, 0x34, 0x85, 0x70, 0xf1, 0x08, 0xd8, 0xf9,
+ 0x1c, 0x1b, 0x71, 0xcc, 0x72, 0xec, 0xce, 0x30, 0x91, 0x67, 0xac, 0xe5, 0x4e, 0x51, 0xa6, 0x47,
+ 0x74, 0x09, 0x19, 0xee, 0x9d, 0x2d, 0x3f, 0xf2, 0x49, 0x5a, 0xf0, 0x6c, 0x8f, 0xe9, 0x1f, 0x10,
+ 0xcc, 0x32, 0x2f, 0x8d, 0x3e, 0xfa, 0xba, 0x0c, 0x37, 0x51, 0xe2, 0x3e, 0xcc, 0xdd, 0x81, 0xd5,
+ 0xef, 0xef, 0x56, 0x3a, 0xd2, 0x96, 0x10, 0xfb, 0x19, 0xce, 0x90, 0xbf, 0x82, 0x11, 0xf6, 0xe6,
+ 0x28, 0x7e, 0x4d, 0x16, 0x61, 0x87, 0xdd, 0xc5, 0x61, 0x5d, 0x85, 0xa9, 0x02, 0xea, 0xdf, 0x7a,
+ 0x2c, 0x92, 0xdd, 0xc3, 0xa3, 0xc9, 0xec, 0xd9, 0xc0, 0x54, 0xbd, 0xf2, 0x77, 0x00, 0x5e, 0x18,
+ 0x8c, 0x0a, 0x63, 0xdf, 0x8f, 0xf9, 0x1e, 0x45, 0x1c, 0xd1, 0xf7, 0x11, 0x1e, 0xbd, 0x20, 0x30,
+ 0x1c, 0x27, 0x45, 0xfe, 0xb7, 0xe6, 0x93, 0xae, 0x2a, 0xc1, 0xdc, 0xe2, 0xf6, 0xd1, 0x54, 0x42,
+ 0xa3, 0x26, 0x79, 0xd6, 0xb3, 0x5c, 0xb0, 0xd2, 0x97, 0x3e, 0xc0, 0x0e, 0xce, 0xf4, 0x82, 0x42,
+ 0x99, 0x49, 0xb7, 0xad, 0x33, 0xd6, 0x67, 0x81, 0xaf, 0x40, 0xa2, 0xbd, 0x71, 0x7e, 0x82, 0x66,
+ 0x8d, 0x97, 0x3b, 0x9d, 0x30, 0xe8, 0x4b, 0x4d, 0xcd, 0xf0, 0x1e, 0xfb, 0x33, 0xbd, 0xcd, 0xb2,
+ 0xca, 0x7e, 0x5d, 0xa2, 0xe5, 0x6a, 0xa1, 0xc0, 0xbd, 0xae, 0x8c, 0x65, 0x93, 0x9d, 0x53, 0x6f,
+ 0x8d, 0xce, 0x4f, 0xc2, 0xb1, 0x54, 0x7d, 0x7a, 0x59, 0x08, 0xc0, 0xaa, 0xfc, 0x12, 0xa9, 0x41,
+ 0x9b, 0x11, 0x3c, 0x24, 0x3a, 0x89, 0x8f, 0x2f, 0x5a, 0x49, 0x44, 0x64, 0x83, 0x17, 0xbe, 0xa2,
+ 0xff, 0x6f, 0xcb, 0x65, 0x04, 0x6f, 0x75, 0x4c, 0x5d, 0x15, 0x06, 0x7b, 0x3b, 0x3e, 0xc1, 0xed,
+ 0xcb, 0xdc, 0xde, 0x04, 0x03, 0x30, 0x74, 0xc2, 0x6b, 0x50, 0x53, 0x6b, 0x8c, 0xcd, 0x1b, 0xe7,
+ 0xd5, 0xf8, 0x42, 0xe5, 0x07, 0x16, 0xc3, 0x70, 0x83, 0x49, 0x25, 0xa4, 0x1e, 0x61, 0xa8, 0xc4,
+ 0x13, 0x82, 0xfe, 0x56, 0xd7, 0x04, 0xbe, 0x4d, 0x59, 0x05, 0xb8, 0x35, 0xcc, 0xd2, 0xaf, 0x40,
+ 0x24, 0xf3, 0xbc, 0x48, 0x58, 0x0e, 0x01, 0xe6, 0x47, 0x19, 0x9d, 0xb6, 0xe3, 0x6f, 0x17, 0x5e,
+ 0xab, 0x6c, 0xa3, 0x5a, 0x9a, 0xdd, 0x95, 0x2a, 0x18, 0x22, 0x42, 0x36, 0x07, 0xa0, 0x47, 0xb1,
+ 0x2e, 0x8f, 0xc8, 0x78, 0xcc, 0x7d, 0x16, 0x61, 0x5f, 0x34, 0x66, 0xee, 0x01, 0x17, 0x60, 0xa3,
+ 0x3f, 0x4d, 0xb1, 0xcc, 0xcc, 0x13, 0x99, 0x51, 0x3e, 0x78, 0x69, 0x7b, 0x83, 0x49, 0x5f, 0xf3,
+ 0x89, 0xa9, 0x9e, 0x24, 0x18, 0x08, 0x4d, 0xdb, 0x8a, 0xb1, 0xd8, 0xd7, 0xae, 0x30, 0x82, 0x4d,
+ 0x3d, 0x4f, 0xce, 0xbe, 0x17, 0xe5, 0x47, 0x5d, 0xa6, 0x03, 0x8c, 0xae, 0xe7, 0xa2, 0x63, 0xf3,
+ 0xe8, 0x88, 0x21, 0xf4, 0xfd, 0xa9, 0x32, 0x15, 0x93, 0x0c, 0xbe, 0x61, 0xe8, 0x35, 0x6c, 0xb5,
+ 0xc9, 0xa9, 0xec, 0x1c, 0x7f, 0x34, 0x5b, 0xb0, 0x80, 0x6d, 0x0a, 0x52, 0x87, 0x74, 0x12, 0x90,
+ 0x3a, 0xf7, 0x40, 0x41, 0xe1, 0x62, 0xa5, 0xb7, 0xf0, 0x5d, 0x45, 0x3e, 0x55, 0x1a, 0x30, 0xec,
+ 0x5d, 0x52, 0x00, 0x76, 0x38, 0x10, 0x0d, 0xf0, 0x2f, 0x7f, 0xf2, 0x3e, 0x34, 0x1f, 0x1a, 0xd9,
+ 0xf8, 0xb9, 0x86, 0xf9, 0xdc, 0x05, 0xe0, 0xcf, 0x28, 0x49, 0xfd, 0x21, 0x64, 0xf6, 0xa1, 0xc4,
+ 0xf7, 0xce, 0x91, 0xb2, 0x15, 0xdf, 0x82, 0x39, 0x30, 0x60, 0xf3, 0xd1, 0xa6, 0x18, 0xc4, 0x3b,
+ 0xf7, 0xd2, 0x64, 0xe8, 0xab, 0x67, 0x23, 0xb8, 0x2c, 0x57, 0x84, 0x17, 0xc0, 0x2c, 0x21, 0xfc,
+ 0x55, 0x8b, 0xb6, 0x06, 0xbf, 0x79, 0x7e, 0x29, 0x5a, 0xfb, 0x5c, 0xa5, 0x5a, 0xe4, 0x46, 0xac,
+ 0x16, 0x8e, 0xf4, 0x03, 0xb7, 0xbb, 0xb0, 0x7b, 0xbf, 0xd3, 0x84, 0xbe, 0xb5, 0x6a, 0xc8, 0x28,
+ 0xe8, 0x2c, 0x2d, 0x0b, 0x7d, 0x0a, 0x65, 0xd3, 0xee, 0x54, 0x8c, 0xbf, 0xd9, 0xda, 0x84, 0x21,
+ 0x80, 0x07, 0x68, 0x09, 0x75, 0xbd, 0xa8, 0xd0, 0xbf, 0xa0, 0xf3, 0xc7, 0xc5, 0xb5, 0xf2, 0xf8,
+ 0xf1, 0x74, 0x6e, 0x7d, 0xad, 0x80, 0xbd, 0x87, 0xe9, 0x83, 0x2e, 0xda, 0x61, 0x28, 0x03, 0x74,
+ 0xe5, 0x45, 0x74, 0x0d, 0x1f, 0x47, 0x46, 0x10, 0x7f, 0xef, 0x12, 0x9f, 0x78, 0xec, 0x03, 0xed,
+ 0x22, 0x86, 0x6f, 0x1a, 0x31, 0x14, 0xf4, 0x3a, 0x7f, 0xef, 0x98, 0x3e, 0x64, 0x86, 0xb9, 0x0e,
+ 0x5b, 0x0d, 0x55, 0xba, 0xcc, 0x6d, 0x04, 0xc7, 0x9c, 0x1e, 0xd4, 0xf7, 0xf0, 0x60, 0x6d, 0x54,
+ 0x75, 0x70, 0x3b, 0x99, 0xd3, 0x01, 0x9f, 0x34, 0x44, 0x98, 0xab, 0xd1, 0x6b, 0xc8, 0xaa, 0xfd,
+ 0xd9, 0x5a, 0xd3, 0xee, 0x5d, 0x2c, 0x54, 0x38, 0x06, 0x1f, 0x93, 0xb3, 0x5c, 0x87, 0x10, 0x5e,
+ 0xcb, 0xcd, 0xd3, 0x4a, 0x89, 0xd2, 0x0d, 0xac, 0xeb, 0x42, 0x67, 0x2b, 0xd1, 0x75, 0x12, 0x58,
+ 0xdd, 0x19, 0xe3, 0x21, 0x33, 0x75, 0xf6, 0x51, 0x25, 0xeb, 0xa6, 0x43, 0x44, 0x82, 0x64, 0xae,
+ 0xb8, 0x97, 0x01, 0xff, 0x17, 0x8f, 0xce, 0x96, 0xc8, 0xc3, 0x86, 0xa0, 0x05, 0xb2, 0x2c, 0x33,
+ 0x01, 0x27, 0x25, 0x84, 0x83, 0x85, 0x33, 0xe2, 0xd0, 0xc5, 0x65, 0x89, 0x85, 0x45, 0x81, 0x3f,
+ 0x2d, 0xb4, 0xb1, 0x8b, 0x1d, 0x04, 0x5d, 0x4c, 0xd8, 0x46, 0x8a, 0x04, 0x3a, 0x3b, 0xa7, 0x76,
+ 0x47, 0x5e, 0xcc, 0xc0, 0x16, 0xb2, 0x3a, 0x38, 0x9a, 0x6a, 0x50, 0x3a, 0x8b, 0x82, 0xb7, 0x6b,
+ 0xf2, 0x60, 0x53, 0x4e, 0xdf, 0x8a, 0x02, 0x9f, 0xc6, 0x27, 0x4f, 0xf5, 0x2a, 0xf1, 0xf1, 0x2f,
+ 0x4a, 0xaa, 0xc7, 0x94, 0xc0, 0xdc, 0xdb, 0x8c, 0x41, 0xd9, 0x16, 0x13, 0xa2, 0xae, 0x37, 0x2a,
+ 0x7e, 0x26, 0x6f, 0xdf, 0x46, 0x07, 0x74, 0x88, 0x62, 0xab, 0x28, 0x64, 0x12, 0x7c, 0xca, 0xd5,
+ 0xbb, 0x6f, 0x7f, 0x3b, 0x44, 0x99, 0x20, 0x93, 0x9a, 0xa0, 0xac, 0x17, 0xed, 0x82, 0xf9, 0x43,
+ 0xc2, 0x98, 0x6b, 0xcf, 0x54, 0x91, 0xfe, 0x3c, 0x9e, 0xfa, 0x7b, 0x57, 0x38, 0xe2, 0x64, 0x58,
+ 0x9c, 0xe0, 0x41, 0x95, 0x8a, 0xa0, 0xa3, 0x3d, 0x7b, 0x3e, 0x99, 0xea, 0xc7, 0xec, 0x82, 0xc8,
+ 0xa8, 0xae, 0xbd, 0xf9, 0x5c, 0x7e, 0xa2, 0x20, 0x78, 0xce, 0x4a, 0x6c, 0x74, 0x2a, 0xe7, 0x31,
+ 0xdb, 0xc1, 0x02, 0x49, 0x4b, 0x83, 0x0b, 0x0e, 0x7e, 0xeb, 0x69, 0x59, 0xf9, 0x3c, 0x13, 0x47,
+ 0xaf, 0xbd, 0x58, 0xec, 0x7f, 0xae, 0x7e, 0x4b, 0xf3, 0x3d, 0x18, 0xbf, 0xb0, 0x79, 0x92, 0x59,
+ 0x9e, 0x5f, 0x03, 0x30, 0x15, 0xba, 0xec, 0xd1, 0xaf, 0x2e, 0xf7, 0x88, 0xde, 0x50, 0xae, 0x9e,
+ 0x59, 0x14, 0xf3, 0xa5, 0x78, 0x25, 0xd7, 0xd9, 0x1a, 0x33, 0x81, 0x29, 0x8b, 0x93, 0xf6, 0xfa,
+ 0x90, 0x3d, 0x13, 0xaa, 0x0d, 0xa7, 0x8e, 0x79, 0xc0, 0x36, 0x45, 0x29, 0xa5, 0xf1, 0xfe, 0x92,
+ 0x1b, 0x57, 0x42, 0x58, 0xe0, 0x85, 0x15, 0xa2, 0xc9, 0xb1, 0x50, 0x08, 0x6a, 0x02, 0x46, 0xc6,
+ 0x1d, 0xd0, 0xf0, 0xb4, 0x5a, 0xcc, 0xd5, 0x54, 0x9d, 0xab, 0x13, 0x47, 0x9f, 0x82, 0x60, 0x9b,
+ 0x11, 0x64, 0x35, 0xfa, 0xef, 0x89, 0xb4, 0x87, 0x43, 0x48, 0x6e, 0x78, 0x64, 0x01, 0xbe, 0x09,
+ 0xd1, 0xd0, 0x40, 0xdf, 0x77, 0x6b, 0xee, 0x92, 0xc5, 0xff, 0x77, 0xcf, 0x20, 0x95, 0x36, 0x78,
+ 0x35, 0x1f, 0x1e, 0xaf, 0x4b, 0xa7, 0x66, 0x71, 0x9d, 0x5e, 0xb7, 0xd9, 0x70, 0x6e, 0xaa, 0x35,
+ 0x49, 0x3c, 0x9a, 0x23, 0x53, 0xaf, 0x3e, 0x9d, 0x60, 0x72, 0xb5, 0x27, 0x33, 0x80, 0x33, 0xd2,
+ 0x11, 0x4b, 0xff, 0xfb, 0x53, 0xab, 0x14, 0x4c, 0xe4, 0xe7, 0xbc, 0x2f, 0x5c, 0xd8, 0xbf, 0x81,
+ 0x5c, 0xf7, 0x4d, 0x5d, 0xb8, 0x84, 0x62, 0xf3, 0xd2, 0x0a, 0x53, 0x66, 0xd3, 0x13, 0xff, 0xb0,
+ 0xeb, 0x4b, 0x1f, 0x10, 0x1d, 0xa9, 0xba, 0x5c, 0xad, 0xe2, 0x52, 0x91, 0xae, 0xbe, 0x5d, 0x05,
+ 0x54, 0x6d, 0x72, 0x1e, 0xc1, 0x14, 0xb5, 0x9b, 0x22, 0x3f, 0x78, 0x73, 0x5e, 0x99, 0x50, 0xde,
+ 0xa8, 0x41, 0x31, 0xd0, 0x44, 0xf3, 0x2f, 0x31, 0xd9, 0x0b, 0x72, 0x1a, 0xd3, 0x70, 0xbe, 0x84,
+ 0xfc, 0xe1, 0xed, 0x15, 0xb9, 0xe9, 0x69, 0xe2, 0xbe, 0x50, 0xa2, 0xda, 0x4e, 0x7a, 0x83, 0xc5,
+ 0x56, 0xea, 0xaf, 0x2c, 0xc9, 0x8f, 0xcc, 0x83, 0x1a, 0xa5, 0x0e, 0x74, 0xaa, 0x64, 0x96, 0xb5,
+ 0x5a, 0x4a, 0x72, 0xad, 0x86, 0x5a, 0xb8, 0x5a, 0x04, 0x0d, 0x68, 0x21, 0x63, 0x23, 0x7b, 0x17,
+ 0x9d, 0xfd, 0x1b, 0x3f, 0xac, 0x80, 0x98, 0x97, 0xb5, 0xd4, 0xb7, 0x08, 0x50, 0xf4, 0x18, 0xf9,
+ 0x16, 0xb1, 0x57, 0xfa, 0xff, 0xa8, 0x02, 0x6e, 0x62, 0x7b, 0x15, 0x8d, 0xc0, 0x17, 0xdd, 0xa3,
+ 0x45, 0x98, 0x5a, 0xa0, 0xda, 0xe2, 0xd1, 0x17, 0x91, 0x3d, 0xda, 0x18, 0x16, 0x19, 0x3a, 0xfb,
+ 0xfd, 0x44, 0x72, 0x03, 0x97, 0x72, 0x1d, 0xbf, 0x11, 0xca, 0x95, 0x05, 0x6a, 0x9e, 0x41, 0x3d,
+ 0x85, 0xb4, 0xd9, 0xb3, 0x88, 0xd4, 0xd9, 0xfb, 0x1c, 0xd2, 0x35, 0x31, 0x12, 0xcc, 0xf3, 0x03,
+ 0x50, 0x8a, 0xfb, 0x0e, 0x72, 0xeb, 0x86, 0x65, 0xd5, 0x96, 0x0f, 0x53, 0x1e, 0x13, 0x99, 0x91,
+ 0xa7, 0x70, 0xab, 0x4c, 0xa6, 0x1a, 0xb7, 0x0d, 0x71, 0x0e, 0xb6, 0x17, 0x85, 0xdf, 0x9b, 0x74,
+ 0x19, 0x4a, 0xc7, 0x55, 0x0e, 0xe9, 0x22, 0x6b, 0x8e, 0xa8, 0x5e, 0x45, 0xc4, 0x0f, 0x36, 0xbb,
+ 0x21, 0xda, 0x97, 0xcf, 0xed, 0x41, 0xb5, 0x00, 0x26, 0xb1, 0x70, 0x43, 0x5c, 0x60, 0x59, 0x23,
+ 0x19, 0xc5, 0xdb, 0x49, 0xef, 0xdd, 0x5d, 0x19, 0x5f, 0x58, 0xaa, 0x20, 0xd9, 0x09, 0x17, 0x09,
+ 0xc7, 0x5f, 0xb9, 0x65, 0x8f, 0x0a, 0xe8, 0x4d, 0x7d, 0x60, 0x88, 0x7a, 0x53, 0x9e, 0xf1, 0x25,
+ 0xcd, 0xa1, 0x3e, 0xc6, 0xc5, 0x86, 0xf2, 0xee, 0x60, 0x0f, 0x11, 0x3e, 0xe3, 0x90, 0x4d, 0xff,
+ 0x49, 0x0b, 0x2f, 0x85, 0x7f, 0x18, 0x53, 0x4e, 0xe2, 0x5c, 0x06, 0x61, 0x51, 0x08, 0xca, 0x55,
+ 0x80, 0x83, 0xa4, 0x80, 0x05, 0x26, 0xe7, 0x29, 0xdb, 0xab, 0x94, 0x66, 0xe9, 0xbf, 0xf8, 0xd2,
+ 0x79, 0x71, 0x61, 0x05, 0x33, 0xc8, 0x6b, 0x5c, 0x62, 0x01, 0x7f, 0x82, 0xef, 0x5f, 0xa3, 0xf6,
+ 0x29, 0x86, 0xb6, 0x0a, 0xa5, 0xed, 0x3a, 0xae, 0x34, 0x12, 0xba, 0xb0, 0x80, 0xd4, 0x53, 0x79,
+ 0x57, 0x7d, 0xa2, 0x38, 0xfd, 0x39, 0xc1, 0xaf, 0x07, 0x8d, 0x23, 0x6b, 0xcd, 0x97, 0xe0, 0xf6,
+ 0x83, 0x74, 0x7c, 0x3c, 0x95, 0xdb, 0xb1, 0xf0, 0xf7, 0x9e, 0xe9, 0xe4, 0x68, 0x67, 0x18, 0x0e,
+ 0x00, 0x12, 0x70, 0x79, 0xc2, 0xfe, 0xde, 0x00, 0x12, 0x87, 0x00, 0xd3, 0x8a, 0xc5, 0x1b, 0xb4,
+ 0xd7, 0x46, 0x1d, 0x73, 0x5c, 0x51, 0x93, 0x19, 0x83, 0x1b, 0x28, 0xb9, 0x70, 0x87, 0x20, 0x34,
+ 0xb6, 0x7e, 0xb9, 0x1f, 0x9d, 0x15, 0xdb, 0xd7, 0xfb, 0x30, 0x92, 0xe8, 0x21, 0x6c, 0x5c, 0xdb,
+ 0xaf, 0x5c, 0xd5, 0xa5, 0x76, 0x4b, 0x5f, 0xc3, 0xa8, 0x73, 0x9a, 0x42, 0x04, 0x21, 0xf1, 0x49,
+ 0xbc, 0x47, 0xa0, 0xa7, 0x4a, 0xda, 0x16, 0x34, 0xcd, 0x62, 0xe1, 0xe0, 0x9a, 0x35, 0xf2, 0xf9,
+ 0xb2, 0x3c, 0xcf, 0xa6, 0x4f, 0xd7, 0x23, 0xc2, 0xd2, 0xa5, 0x5a, 0xf9, 0xfd, 0x7d, 0x25, 0x84,
+ 0xda, 0xda, 0x66, 0xb9, 0x99, 0x7f, 0xec, 0xfc, 0x82, 0x7c, 0xea, 0x6b, 0x23, 0x89, 0x6e, 0xab,
+ 0xe9, 0x43, 0xcb, 0x88, 0xcd, 0x18, 0x6e, 0xae, 0x2d, 0xf5, 0xc7, 0xe3, 0x92, 0x55, 0x0b, 0xc0,
+ 0x4d, 0xc8, 0xee, 0x4b, 0x7e, 0xfe, 0x84, 0x8c, 0x32, 0x33, 0xc8, 0xf1, 0xfb, 0xd8, 0x11, 0x22,
+ 0xd9, 0x0d, 0x2b, 0x16, 0x19, 0xba, 0x65, 0xe4, 0x99, 0x26, 0x7b, 0xa7, 0x04, 0x11, 0xfc, 0xb8,
+ 0x05, 0x48, 0x36, 0x43, 0x82, 0x14, 0xb7, 0x31, 0x50, 0xfd, 0x38, 0x89, 0xc1, 0x36, 0xa1, 0xd5,
+ 0x8e, 0x52, 0x76, 0x99, 0xc8, 0x38, 0x49, 0xb4, 0x94, 0x02, 0x96, 0x35, 0x8c, 0xc1, 0x9c, 0x7c,
+ 0x2b, 0xbe, 0x73, 0x62, 0x0a, 0xd3, 0x57, 0x3d, 0xdb, 0x81, 0x14, 0x7c, 0xd0, 0x4a, 0xe5, 0x2f,
+ 0x63, 0xbd, 0xac, 0xcf, 0x83, 0x10, 0xfd, 0x06, 0x54, 0xc0, 0x5c, 0xba, 0x96, 0x72, 0x0b, 0xcf,
+ 0x0a, 0x74, 0xe2, 0xbf, 0xbc, 0x1c, 0xc6, 0xd8, 0x9e, 0x7f, 0x5f, 0xbb, 0x00, 0xfe, 0x2a, 0xbd,
+ 0x36, 0x02, 0x56, 0x5b, 0xa2, 0x30, 0x75, 0x44, 0x62, 0xf8, 0x22, 0x24, 0x14, 0x04, 0x30, 0x26,
+ 0xe5, 0xb4, 0x06, 0x3d, 0xfe, 0x5c, 0x3a, 0xc7, 0xd8, 0x1d, 0x1b, 0xc9, 0x99, 0xbb, 0xa5, 0x2c,
+ 0x92, 0x3b, 0xaa, 0x92, 0xf2, 0x12, 0x59, 0xc1, 0xd7, 0xec, 0xae, 0x89, 0x45, 0xfb, 0xe6, 0x15,
+ 0xa7, 0xe8, 0xad, 0x26, 0xf9, 0xb3, 0xe0, 0xd5, 0x57, 0xab, 0x4c, 0xab, 0xda, 0xe0, 0xc2, 0x9d,
+ 0xb1, 0x12, 0x6f, 0xc9, 0x84, 0x2b, 0x66, 0x89, 0x05, 0x37, 0x2a, 0x6b, 0x8d, 0xe8, 0x21, 0xa4,
+ 0xbb, 0x28, 0xc4, 0xb4, 0xa6, 0x93, 0xc2, 0xc9, 0x54, 0x39, 0x38, 0x84, 0xae, 0x70, 0x9b, 0xcf,
+ 0xc5, 0xc5, 0x3c, 0x56, 0x21, 0xb4, 0x95, 0xb0, 0xa7, 0x2a, 0x30, 0xd8, 0xcb, 0x18, 0x22, 0x31,
+ 0x59, 0x01, 0x62, 0x43, 0xe2, 0x65, 0xb9, 0xf3, 0xc6, 0x5c, 0x9c, 0xe1, 0xea, 0x48, 0x6f, 0x10,
+ 0xc2, 0x27, 0x3a, 0xd6, 0xd1, 0x15, 0xeb, 0x7f, 0xc9, 0x2b, 0x21, 0x25, 0xae, 0x91, 0x34, 0xd0,
+ 0x6b, 0xfe, 0xe3, 0x79, 0x52, 0xb9, 0xb2, 0x17, 0xd6, 0x6b, 0xf0, 0xfa, 0x3f, 0x15, 0xb5, 0x74,
+ 0x10, 0xf9, 0xd9, 0xb0, 0xc5, 0xdb, 0x72, 0x1a, 0x76, 0xeb, 0x41, 0x6f, 0xb5, 0x9b, 0x8d, 0xb9,
+ 0x8f, 0x75, 0x6d, 0xc8, 0x25, 0xfa, 0xee, 0xdb, 0x1c, 0x3c, 0x01, 0x80, 0x38, 0x5b, 0x83, 0x01,
+ 0xc0, 0x02, 0xa1, 0x1c, 0x71, 0xef, 0xbc, 0x58, 0xa5, 0xf6, 0x49, 0xb7, 0xef, 0x9c, 0xa7, 0x7d,
+ 0x39, 0xcc, 0x2a, 0x0b, 0xdb, 0x78, 0xb7, 0x5d, 0x22, 0x36, 0xb1, 0x36, 0x72, 0x56, 0x62, 0x19,
+ 0xf1, 0x5c, 0x0a, 0x63, 0x02, 0x6a, 0x59, 0x8e, 0x24, 0xb6, 0x32, 0x21, 0x11, 0x96, 0xd2, 0x8c,
+ 0xf1, 0xaf, 0x84, 0x3f, 0xf5, 0x98, 0x0d, 0x22, 0x14, 0x15, 0xda, 0x9f, 0x44, 0x0b, 0x08, 0x33,
+ 0x13, 0x11, 0x53, 0x78, 0xe1, 0xf1, 0x4b, 0x40, 0x1c, 0x43, 0x73, 0x5d, 0x86, 0x06, 0xe1, 0x02,
+ 0x79, 0x3f, 0x68, 0x00, 0xb7, 0xb0, 0xcb, 0x3b, 0x2e, 0x12, 0x4e, 0x81, 0x77, 0x2a, 0xc5, 0x74,
+ 0xc4, 0xd9, 0xa0, 0x1e, 0xa3, 0x74, 0x17, 0x61, 0x15, 0xaf, 0xa7, 0xb4, 0x25, 0x61, 0x85, 0x60,
+ 0x70, 0x85, 0xfb, 0x43, 0xb9, 0x43, 0x4f, 0x87, 0x44, 0x1a, 0x7b, 0xee, 0x68, 0xbb, 0x74, 0x99,
+ 0xff, 0x81, 0x22, 0xb4, 0x8d, 0x94, 0xf0, 0x4a, 0x3e, 0x28, 0xf5, 0xbd, 0x5c, 0xa1, 0x7f, 0x5c,
+ 0xea, 0xe6, 0xba, 0xf2, 0x5d, 0x85, 0xf2, 0xed, 0xd7, 0xfd, 0x93, 0xf0, 0xbb, 0xba, 0x86, 0x23,
+ 0xb5, 0xee, 0xb5, 0x5b, 0xd9, 0x91, 0xbf, 0xdc, 0xe3, 0xdc, 0xbe, 0x82, 0x92, 0xce, 0xb4, 0x0f,
+ 0xbf, 0xf1, 0x80, 0x0f, 0xe8, 0xc3, 0x04, 0x49, 0x3e, 0x95, 0x72, 0xf8, 0x36, 0x44, 0xce, 0xf4,
+ 0x3a, 0x6a, 0xeb, 0xdd, 0x88, 0x28, 0x8d, 0xf3, 0x04, 0x65, 0xd8, 0xfd, 0x9d, 0xb1, 0x22, 0xbd,
+ 0x44, 0xe7, 0xcf, 0x0f, 0x2f, 0xfc, 0xb6, 0xd6, 0x60, 0x7a, 0x6e, 0x6a, 0x93, 0x83, 0xf1, 0x86,
+ 0xf4, 0xf1, 0x23, 0xb2, 0xfd, 0x4a, 0xb6, 0xcf, 0x97, 0x70, 0xae, 0xa9, 0x44, 0x94, 0x7a, 0x4e,
+ 0xf9, 0x1e, 0xf8, 0xdc, 0x1f, 0xf0, 0x06, 0x16, 0xdf, 0x69, 0xde, 0x70, 0xea, 0x64, 0x98, 0xe6,
+ 0x1f, 0x9f, 0x3a, 0xcf, 0xf6, 0xb6, 0x10, 0xb1, 0x3c, 0xd1, 0x76, 0x67, 0x6c, 0xaf, 0x3c, 0x0a,
+ 0xc3, 0x46, 0x31, 0x89, 0xf7, 0x7a, 0x0f, 0x9b, 0x7d, 0xd8, 0x9a, 0x81, 0x57, 0x0c, 0x37, 0xda,
+ 0xf7, 0xc3, 0xe5, 0x4b, 0x14, 0xe9, 0x0e, 0x8c, 0x27, 0xdc, 0x68, 0xdb, 0xd8, 0xdb, 0x8b, 0xee,
+ 0x4e, 0x9f, 0x93, 0x18, 0x4c, 0x75, 0xec, 0x41, 0x6f, 0xbe, 0x89, 0xe3, 0x77, 0x64, 0xbd, 0x22,
+ 0xa1, 0x0a, 0x16, 0x93, 0xbc, 0x7a, 0xec, 0x6e, 0x3c, 0x2d, 0x97, 0x4a, 0xb1, 0x7d, 0xb6, 0xfc,
+ 0x01, 0x8b, 0x87, 0x2b, 0x60, 0xe4, 0x53, 0xde, 0x72, 0xef, 0xa5, 0xdf, 0xeb, 0x2d, 0x3c, 0x01,
+ 0xdc, 0xfd, 0xd8, 0x3b, 0x2a, 0x16, 0x74, 0x1b, 0x26, 0x40, 0x5c, 0x4d, 0x11, 0x7f, 0xa8, 0x3f,
+ 0xc9, 0xe8, 0x8f, 0x6b, 0xe4, 0x96, 0x3f, 0x2b, 0x4e, 0xfa, 0x1f, 0xa5, 0x73, 0x85, 0xbb, 0xe5,
+ 0x6f, 0xd7, 0x0c, 0xf4, 0x46, 0x81, 0xfd, 0x0d, 0x0f, 0x70, 0x3c, 0x51, 0x46, 0x47, 0x5d, 0x37,
+ 0x02, 0x94, 0x52, 0x44, 0x4b, 0xac, 0x30, 0xc3, 0x72, 0xd1, 0x50, 0x5e, 0x29, 0xa2, 0x4a, 0xfb,
+ 0xbe, 0x8e, 0x60, 0x16, 0xb0, 0xb1, 0x82, 0xd8, 0x29, 0xf5, 0x3c, 0x72, 0x3c, 0x79, 0x9d, 0xa8,
+ 0x64, 0x15, 0x57, 0x7a, 0x10, 0x0f, 0xb4, 0xc0, 0x02, 0xdb, 0xc6, 0x6c, 0x37, 0xa1, 0xf3, 0x52,
+ 0x5c, 0xb5, 0xcd, 0x42, 0xf1, 0x43, 0x31, 0xfe, 0x0b, 0xaa, 0xcb, 0xd5, 0x0a, 0xf4, 0x69, 0x64,
+ 0xf5, 0x98, 0x41, 0x53, 0xed, 0x04, 0x27, 0x56, 0x4a, 0xe9, 0x4c, 0x96, 0x64, 0x29, 0xff, 0xe2,
+ 0xe1, 0x79, 0xf5, 0x78, 0x69, 0x43, 0xe6, 0x4e, 0x4e, 0xa8, 0x8a, 0x50, 0x15, 0x37, 0x44, 0x73,
+ 0x41, 0xe8, 0x21, 0xe4, 0x0a, 0x2e, 0x43, 0x2d, 0x4b, 0xd1, 0xfe, 0xf5, 0xc5, 0x30, 0x31, 0x39,
+ 0xfa, 0x53, 0x7a, 0x3c, 0xd5, 0x63, 0x7a, 0x5c, 0xff, 0x18, 0xf8, 0x79, 0x84, 0x73, 0x84, 0x55,
+ 0x61, 0x17, 0x2f, 0xad, 0x34, 0xd3, 0xf2, 0xf3, 0x2b, 0xe6, 0xe3, 0xc2, 0x0e, 0x2b, 0x28, 0xc4,
+ 0x92, 0xd0, 0xd3, 0x14, 0x06, 0x58, 0xbb, 0x2f, 0xdf, 0xe6, 0x3d, 0x0d, 0x6b, 0x71, 0x40, 0xc2,
+ 0xbf, 0x6b, 0x41, 0xae, 0x85, 0x39, 0x1c, 0xdf, 0x02, 0xf3, 0x6e, 0x85, 0x15, 0x1d, 0xb8, 0xe4,
+ 0xbe, 0x32, 0x77, 0x70, 0x22, 0x5b, 0xe7, 0x03, 0xd6, 0x1c, 0xab, 0x90, 0x9b, 0x0d, 0x03, 0x40,
+ 0x0f, 0x3d, 0x82, 0x9b, 0xb8, 0x32, 0x03, 0x99, 0xee, 0xe4, 0xa9, 0x63, 0x35, 0xec, 0xe2, 0x29,
+ 0xb3, 0xda, 0x4c, 0x3c, 0x4c, 0x6b, 0x4f, 0x67, 0x0a, 0x8e, 0x35, 0xe2, 0xe5, 0x3d, 0x97, 0xe6,
+ 0xec, 0xb2, 0x99, 0xa2, 0x7d, 0x1c, 0xf0, 0xb0, 0x6d, 0xc7, 0x14, 0xe6, 0xb1, 0x77, 0x75, 0x2d,
+ 0x73, 0x0e, 0xa6, 0x3b, 0x4b, 0x90, 0xac, 0xe4, 0x34, 0x60, 0x6d, 0x03, 0xba, 0xb2, 0xb4, 0xb8,
+ 0x11, 0xe1, 0x1c, 0xb2, 0x27, 0xbb, 0x39, 0x61, 0x47, 0x53, 0x3e, 0xb0, 0x5b, 0x0d, 0x5a, 0xc9,
+ 0x36, 0xd5, 0xd3, 0x99, 0xa8, 0xdb, 0x74, 0x32, 0x5b, 0x05, 0x95, 0x0d, 0x2f, 0x19, 0xa7, 0x99,
+ 0x2e, 0x57, 0x19, 0xde, 0x4b, 0xb9, 0x08, 0x57, 0xdc, 0x37, 0x15, 0x7d, 0x1f, 0xe5, 0x12, 0x33,
+ 0x91, 0xa1, 0xdd, 0xe3, 0x30, 0x2b, 0x84, 0x4c, 0xe9, 0xbd, 0x0c, 0x8b, 0x6d, 0xe4, 0x75, 0x12,
+ 0x41, 0x98, 0x4b, 0xab, 0x25, 0xda, 0x4b, 0xc0, 0x92, 0xb1, 0x4a, 0x32, 0x06, 0x5a, 0xac, 0x93,
+ 0xf2, 0x6f, 0x01, 0x4d, 0xc1, 0xac, 0xf2, 0x37, 0x8b, 0x4e, 0x03, 0xbb, 0xd0, 0x06, 0x4f, 0xfa,
+ 0x7d, 0xb5, 0xdc, 0x1e, 0xf3, 0x2d, 0x05, 0x29, 0x1b, 0x7e, 0x6e, 0x0e, 0x26, 0x3c, 0x11, 0x5c,
+ 0xaf, 0x97, 0x55, 0x5a, 0xc9, 0x4f, 0x75, 0xb5, 0x24, 0x72, 0xa7, 0x07, 0x0b, 0x02, 0xd9, 0xa2,
+ 0xa3, 0xb0, 0xde, 0x30, 0x22, 0xfc, 0x54, 0x14, 0xfa, 0x7b, 0x19, 0x58, 0x19, 0x59, 0x9f, 0x7d,
+ 0x8a, 0x63, 0xd7, 0x27, 0x66, 0xe0, 0x52, 0x05, 0x3d, 0x4e, 0x14, 0xad, 0xf5, 0xaa, 0xc5, 0x79,
+ 0x1a, 0x02, 0x78, 0x03, 0x2c, 0xe4, 0x86, 0x14, 0x51, 0xbc, 0xc7, 0x31, 0x58, 0x04, 0x39, 0xe9,
+ 0xac, 0xae, 0xaf, 0x74, 0x97, 0xef, 0x9a, 0x5a, 0x97, 0x7c, 0xf5, 0xcd, 0xa1, 0x19, 0xd6, 0x31,
+ 0xc2, 0x0b, 0x5e, 0x66, 0x9a, 0x7f, 0x96, 0x09, 0x59, 0xc5, 0x17, 0x5c, 0x39, 0x66, 0xa7, 0x29,
+ 0x31, 0xb9, 0x6d, 0xad, 0x4e, 0xc1, 0x90, 0xb9, 0x94, 0x02, 0xc3, 0xe0, 0x69, 0xb8, 0x44, 0x6b,
+ 0xa3, 0xa6, 0xab, 0x7e, 0xfe, 0xfa, 0x8f, 0x89, 0x60, 0xf5, 0x7e, 0x68, 0x62, 0xcf, 0x58, 0xa2,
+ 0x96, 0xca, 0xe5, 0x36, 0x23, 0xd9, 0x88, 0x6e, 0x8b, 0x17, 0x7e, 0xf3, 0xe5, 0xd7, 0x63, 0xb0,
+ 0x96, 0x82, 0x18, 0xf3, 0x10, 0x13, 0x09, 0xce, 0x7b, 0xe3, 0xd8, 0xb6, 0x5b, 0x6f, 0x0e, 0x13,
+ 0x1b, 0xd3, 0x49, 0x57, 0x8b, 0xa1, 0xf8, 0xbd, 0xda, 0xed, 0x0d, 0x9c, 0x6c, 0x32, 0x61, 0x03,
+ 0xdd, 0x39, 0x63, 0x9c, 0x6f, 0xe3, 0xe5, 0xc1, 0xd6, 0xdb, 0x26, 0x1d, 0xa2, 0x60, 0x7e, 0x7b,
+ 0xb2, 0x51, 0x80, 0x8f, 0x78, 0x89, 0x43, 0xaa, 0x9d, 0x76, 0xef, 0x1e, 0xdb, 0xd0, 0x51, 0xb4,
+ 0x8e, 0xed, 0x14, 0x42, 0xfb, 0x63, 0x5d, 0x21, 0x99, 0x30, 0x99, 0x05, 0x53, 0x25, 0xe8, 0xec,
+ 0xe7, 0xf1, 0x40, 0x8c, 0xba, 0xb6, 0x6a, 0xe0, 0xc7, 0x73, 0x68, 0x6c, 0x15, 0x4b, 0x42, 0xe3,
+ 0xda, 0x97, 0x0e, 0x40, 0xc5, 0xff, 0x98, 0x2b, 0xf2, 0x19, 0xca, 0x3d, 0x49, 0x72, 0x7a, 0x96,
+ 0xd5, 0x16, 0xd4, 0x2a, 0xf4, 0x5d, 0x1d, 0xd2, 0x1d, 0x22, 0x60, 0xe0, 0x18, 0xf7, 0x38, 0x04,
+ 0x01, 0x94, 0x45, 0xb2, 0x5f, 0xc0, 0x10, 0xce, 0x65, 0x62, 0x33, 0x61, 0x6d, 0x65, 0x15, 0x7d,
+ 0x39, 0xc0, 0xcf, 0xcb, 0x4c, 0xa2, 0x23, 0x1c, 0xa8, 0x42, 0x46, 0x99, 0x81, 0xdc, 0x28, 0xad,
+ 0xd6, 0xcc, 0x92, 0xdd, 0x06, 0x58, 0x02, 0x0c, 0xe1, 0x67, 0xf2, 0x4f, 0x7a, 0xe3, 0xde, 0xb9,
+ 0x65, 0x81, 0xb4, 0x59, 0x13, 0xfc, 0xa4, 0x12, 0x13, 0x41, 0x9f, 0xd2, 0xe2, 0x9e, 0xea, 0x87,
+ 0x6a, 0x95, 0xba, 0xae, 0x27, 0x4d, 0x12, 0xc4, 0x58, 0x2a, 0x4c, 0x18, 0x68, 0x6b, 0x3b, 0xd6,
+ 0xfa, 0xc5, 0x47, 0x0c, 0xfe, 0x40, 0x66, 0x5b, 0x0e, 0xe9, 0xe9, 0x01, 0x4f, 0x1c, 0x48, 0x52,
+ 0x19, 0xc8, 0x9d, 0xa3, 0xbe, 0x81, 0x04, 0xa1, 0xd8, 0x4e, 0x6f, 0x6e, 0x80, 0xcd, 0xf7, 0x38,
+ 0x63, 0x16, 0x1f, 0x27, 0x4e, 0x5e, 0x4a, 0xcb, 0xc8, 0x15, 0x62, 0x15, 0x9e, 0x4e, 0xbc, 0xfc,
+ 0xa3, 0x26, 0x85, 0x54, 0xe0, 0x56, 0xb9, 0xef, 0xc0, 0x6c, 0x42, 0x87, 0x35, 0x9a, 0x28, 0xc1,
+ 0x90, 0x2c, 0xa2, 0xc6, 0xbe, 0x9e, 0xbb, 0x11, 0x1b, 0x88, 0xa7, 0xea, 0x03, 0x82, 0x8b, 0xf5,
+ 0xb5, 0x72, 0x76, 0xb8, 0x30, 0x2d, 0x07, 0xb3, 0x2f, 0x35, 0x48, 0xf5, 0xc5, 0x6c, 0xd3, 0x30,
+ 0x98, 0x55, 0xe1, 0x68, 0x0d, 0x47, 0xcf, 0xbe, 0x29, 0x8f, 0xcf, 0x48, 0x7b, 0x79, 0x2d, 0xd8,
+ 0xbf, 0x52, 0xce, 0x1d, 0xdc, 0xb2, 0x22, 0xe6, 0x86, 0x30, 0x98, 0x50, 0xf4, 0x56, 0x53, 0x49,
+ 0x38, 0x5f, 0x6d, 0xce, 0xe9, 0x35, 0x2f, 0xcf, 0x44, 0x8a, 0x96, 0xe5, 0x0a, 0xd8, 0x62, 0x64,
+ 0x1b, 0xfe, 0x38, 0x83, 0x36, 0x60, 0xd4, 0x31, 0xa4, 0x63, 0x4a, 0xd7, 0xa0, 0x9b, 0x1a, 0xca,
+ 0x84, 0xaa, 0x30, 0xba, 0xea, 0xcc, 0x48, 0xb2, 0xb0, 0x51, 0xc5, 0x0e, 0xd6, 0x3b, 0x1b, 0xab,
+ 0x20, 0x4a, 0xd0, 0xd9, 0xc8, 0xf3, 0x19, 0x63, 0x07, 0x10, 0x7c, 0xcd, 0xa6, 0x5a, 0xa5, 0xcd,
+ 0x3b, 0x8e, 0x09, 0x7f, 0xf0, 0x54, 0xba, 0xc8, 0x2a, 0xbb, 0x1d, 0x0d, 0x76, 0xdd, 0xb1, 0x47,
+ 0xed, 0xb9, 0x41, 0x25, 0x43, 0x97, 0x2d, 0x27, 0xc0, 0x89, 0x81, 0x69, 0xfb, 0x02, 0x21, 0xd3,
+ 0xc6, 0x59, 0x65, 0x11, 0x42, 0xbc, 0x88, 0x98, 0xa0, 0x0a, 0xa1, 0xdc, 0xb1, 0xb7, 0x03, 0xc1,
+ 0x64, 0x8f, 0x95, 0xb3, 0x37, 0x67, 0x87, 0x5f, 0xe5, 0xf1, 0x93, 0x27, 0xe7, 0x12, 0x62, 0x5e,
+ 0x87, 0x52, 0x4b, 0x44, 0x5f, 0xe5, 0x45, 0x58, 0xc0, 0xfb, 0x06, 0xbc, 0x8a, 0xe0, 0xd4, 0xe5,
+ 0x9f, 0xf3, 0x2c, 0x20, 0x30, 0x64, 0xfe, 0x46, 0xf5, 0xf3, 0xda, 0x53, 0x42, 0x8f, 0x99, 0x7d,
+ 0xfb, 0x47, 0xb7, 0x4a, 0xbe, 0x66, 0xf6, 0xe1, 0x2e, 0x62, 0x87, 0x26, 0xce, 0x02, 0x9a, 0xe2,
+ 0xeb, 0xca, 0x64, 0xc4, 0xaa, 0x0d, 0xbc, 0x9b, 0x1e, 0x32, 0xc3, 0xf8, 0xec, 0xaf, 0x1b, 0xdb,
+ 0xff, 0x0c, 0x71, 0x69, 0xc6, 0xb2, 0xc0, 0x3a, 0x66, 0xee, 0xd2, 0xc9, 0x16, 0x4d, 0xaf, 0x24,
+ 0xfa, 0x65, 0x18, 0x75, 0xfb, 0x45, 0x25, 0xa6, 0x26, 0xfb, 0x66, 0x2a, 0x15, 0x9c, 0x85, 0xf4,
+ 0xda, 0x1d, 0x4f, 0x3b, 0xe2, 0x4d, 0x23, 0xeb, 0x8c, 0x57, 0xb1, 0xb5, 0x4c, 0x90, 0x23, 0x7f,
+ 0x01, 0xfa, 0x06, 0x9d, 0x35, 0x4c, 0x6a, 0xb5, 0x79, 0xb9, 0x00, 0x17, 0x46, 0x46, 0x54, 0x45,
+ 0x60, 0xed, 0xe8, 0x86, 0xc3, 0xde, 0x65, 0xdf, 0x5b, 0x40, 0x97, 0xcd, 0x77, 0x25, 0x41, 0xcd,
+ 0xf2, 0x89, 0xbf, 0xfe, 0x55, 0xa1, 0xf9, 0xf5, 0x7a, 0x18, 0x2d, 0x6c, 0xec, 0x28, 0xed, 0xd1,
+ 0x44, 0xa1, 0x98, 0x77, 0x73, 0x6f, 0xc0, 0x4c, 0x7f, 0x05, 0xc0, 0x9c, 0x19, 0xed, 0x90, 0x3c,
+ 0x56, 0xb6, 0xf4, 0x86, 0x2f, 0x60, 0xb3, 0x1b, 0x95, 0x58, 0x26, 0x40, 0xc2, 0xc0, 0xda, 0x24,
+ 0x26, 0xcb, 0x06, 0x26, 0x53, 0x30, 0x12, 0x35, 0x0b, 0xe5, 0x39, 0x80, 0x3a, 0xf7, 0xd5, 0xae,
+ 0xb8, 0xcb, 0xea, 0xf6, 0x4c, 0x3d, 0x81, 0xb4, 0x1f, 0x97, 0x88, 0x2c, 0x9f, 0x9c, 0x70, 0x70,
+ 0xd5, 0x34, 0xe8, 0x65, 0xb7, 0xdb, 0xb3, 0x33, 0x26, 0xcf, 0x95, 0xa3, 0x31, 0x6a, 0x90, 0x9f,
+ 0xde, 0xd3, 0x17, 0x8a, 0x24, 0xdc, 0xe1, 0x57, 0xb8, 0x28, 0x70, 0x79, 0x52, 0xd7, 0x9d, 0x6b,
+ 0x99, 0xbb, 0xf7, 0x14, 0x5e, 0xc0, 0x05, 0xff, 0xbc, 0x82, 0xc2, 0x20, 0x57, 0x6c, 0xbe, 0xbe,
+ 0x71, 0xf7, 0xdb, 0x24, 0xc3, 0x33, 0xe6, 0x26, 0x50, 0x9a, 0xfc, 0xd6, 0x35, 0xb7, 0x42, 0xc4,
+ 0x63, 0x22, 0x3d, 0x4c, 0x52, 0x1b, 0xf3, 0x6a, 0x38, 0x5c, 0x9b, 0xf5, 0x9b, 0xfb, 0x5f, 0x0b,
+ 0x37, 0x9a, 0xf2, 0x25, 0xd3, 0xd9, 0xa7, 0xc5, 0x02, 0x0f, 0x86, 0xaa, 0xee, 0x71, 0x49, 0xa2,
+ 0x22, 0xc2, 0x9d, 0x92, 0xc2, 0x3e, 0x8f, 0x26, 0x7f, 0x5c, 0x23, 0x62, 0xe4, 0xb5, 0xf5, 0x9e,
+ 0xea, 0x2f, 0xbc, 0xe8, 0x4b, 0x4d, 0xd1, 0xbd, 0x2e, 0x39, 0x04, 0x56, 0xfc, 0x0f, 0xd3, 0xd6,
+ 0x10, 0x16, 0xe5, 0x02, 0x11, 0x5c, 0xbc, 0x66, 0x90, 0xf1, 0xb7, 0xf6, 0x4f, 0x56, 0x0f, 0x87,
+ 0x2c, 0xa8, 0xb6, 0xa9, 0x30, 0xf6, 0x17, 0x1b, 0xda, 0x2c, 0x2a, 0x75, 0x09, 0xcc, 0x32, 0xe2,
+ 0x77, 0xc8, 0xd8, 0x98, 0x7b, 0xd4, 0x8a, 0x73, 0xda, 0xe2, 0x76, 0x78, 0x04, 0x82, 0xab, 0x11,
+ 0x71, 0xe3, 0x73, 0x79, 0x5e, 0xdb, 0x86, 0x79, 0x52, 0x1d, 0x28, 0xc1, 0x87, 0xa8, 0x2f, 0xca,
+ 0xbc, 0xb9, 0xba, 0x58, 0x4e, 0xb3, 0x89, 0x4d, 0x74, 0x88, 0x37, 0x36, 0xbb, 0x1d, 0x1d, 0xe8,
+ 0xc9, 0xd4, 0xe8, 0xa4, 0x31, 0x17, 0x56, 0xf4, 0x72, 0xc0, 0x00, 0x58, 0x1c, 0x76, 0xab, 0x2d,
+ 0x75, 0xe6, 0x90, 0x85, 0xbf, 0xdc, 0x57, 0x2f, 0xbe, 0xb1, 0xa9, 0x3c, 0xd1, 0xf6, 0x58, 0x80,
+ 0xcf, 0x43, 0x60, 0xb4, 0x1b, 0x82, 0x02, 0x90, 0x3c, 0xad, 0xfc, 0xef, 0xc4, 0xce, 0x9a, 0xec,
+ 0xea, 0x26, 0x57, 0xb9, 0x7e, 0xf7, 0x69, 0xa3, 0x06, 0x52, 0xc2, 0x51, 0x83, 0x8f, 0xf4, 0x0d,
+ 0xb7, 0xa3, 0xfc, 0xae, 0x29, 0x81, 0xcc, 0xdc, 0xbb, 0x2d, 0xed, 0x38, 0xf4, 0x40, 0x7a, 0x16,
+ 0x56, 0x11, 0x7f, 0x33, 0x50, 0x44, 0xc0, 0xb9, 0x77, 0x66, 0x6b, 0xce, 0x18, 0xd6, 0xdf, 0x39,
+ 0x9e, 0xa6, 0xa1, 0xbd, 0xed, 0x0e, 0xd7, 0x14, 0xe1, 0xb9, 0x6a, 0x51, 0x4b, 0x5c, 0x00, 0xdc,
+ 0xd7, 0xdb, 0x76, 0x69, 0xef, 0xfa, 0x2e, 0xcf, 0x4f, 0xa8, 0x2e, 0x59, 0x26, 0xa0, 0x55, 0x7e,
+ 0x9b, 0x55, 0xfc, 0x7c, 0x32, 0xff, 0xbf, 0x08, 0x90, 0xb5, 0x7a, 0x4f, 0xf2, 0x26, 0x05, 0x85,
+ 0xf6, 0x56, 0x7b, 0x56, 0x41, 0xdc, 0x95, 0xcf, 0x03, 0x45, 0xef, 0x78, 0x34, 0x30, 0x61, 0x9a,
+ 0x44, 0x8f, 0xbc, 0xb5, 0x5c, 0xf4, 0x64, 0x2c, 0x13, 0x21, 0x3c, 0xa5, 0x1b, 0xe7, 0x9c, 0x60,
+ 0x9b, 0x49, 0xe1, 0x34, 0x8a, 0xef, 0x72, 0xa7, 0xa9, 0x71, 0x6f, 0x32, 0x52, 0x64, 0x0a, 0xa0,
+ 0x4a, 0xf3, 0xa2, 0xee, 0x16, 0x1a, 0xbe, 0x93, 0x0a, 0xa2, 0xd8, 0xb0, 0x82, 0x3b, 0x4d, 0x7d,
+ 0x24, 0xe2, 0x09, 0xef, 0x6b, 0xdd, 0x92, 0x00, 0x6f, 0x76, 0xd1, 0x41, 0xde, 0xdb, 0xab, 0x6c,
+ 0x39, 0x4d, 0x26, 0x54, 0xb4, 0x56, 0xce, 0x4c, 0x19, 0x95, 0x2a, 0x51, 0xa9, 0xf1, 0xad, 0x58,
+ 0xf8, 0x6d, 0xeb, 0x32, 0xc2, 0x30, 0x03, 0x15, 0x0e, 0x9d, 0x76, 0x74, 0x5d, 0xe0, 0x62, 0xd9,
+ 0xc3, 0x83, 0xe4, 0xd5, 0x33, 0x1d, 0x7b, 0xfe, 0x6f, 0x16, 0x5c, 0xaf, 0x34, 0xe9, 0x2c, 0x20,
+ 0xca, 0x99, 0xac, 0x57, 0x47, 0x81, 0x0d, 0x57, 0x65, 0x33, 0x1a, 0x5b, 0x0c, 0xaa, 0x13, 0x00,
+ 0xf9, 0x3d, 0x02, 0x2c, 0xc1, 0x23, 0x7d, 0x55, 0x47, 0xdb, 0x8b, 0xcb, 0x50, 0xc1, 0xd2, 0x95,
+ 0xff, 0x0b, 0x8a, 0xb3, 0x38, 0x43, 0x51, 0xe1, 0x3b, 0x3b, 0xc3, 0x4b, 0x5e, 0xc9, 0xac, 0x0f,
+ 0xb3, 0x81, 0x32, 0xf1, 0x2e, 0xa2, 0x51, 0xea, 0xb2, 0x85, 0x1a, 0x48, 0xee, 0x35, 0xa0, 0x86,
+ 0x05, 0x14, 0x05, 0xc3, 0xf5, 0xe2, 0xa1, 0xdf, 0x47, 0xb0, 0xe2, 0x04, 0x21, 0x85, 0xbd, 0x0b,
+ 0x00, 0x98, 0xe4, 0xdb, 0xe1, 0x7a, 0xf7, 0xfd, 0x7a, 0x92, 0x45, 0x15, 0x57, 0xd7, 0xcf, 0x18,
+ 0xb7, 0xa3, 0xf2, 0xd5, 0xcf, 0x18, 0x7a, 0xe5, 0xa4, 0x4b, 0x0c, 0xe1, 0x66, 0xd9, 0x1b, 0x3f,
+ 0x60, 0x47, 0x90, 0xd1, 0xe9, 0xb8, 0xf5, 0xa8, 0x36, 0x1f, 0xab, 0x7d, 0x85, 0x9a, 0x57, 0xc6,
+ 0xdb, 0x9c, 0xf8, 0x90, 0xbf, 0xc7, 0xb7, 0xf5, 0xa3, 0x1d, 0x69, 0x6d, 0xe8, 0xda, 0x3d, 0xa6,
+ 0xaa, 0x38, 0x55, 0x30, 0x9d, 0x7a, 0xc0, 0x6d, 0x42, 0xeb, 0xc6, 0x97, 0xf3, 0x84, 0xa1, 0x0a,
+ 0x4c, 0x78, 0xc3, 0xdb, 0x9f, 0x29, 0x85, 0x08, 0x4d, 0x8f, 0xbe, 0x8e, 0xba, 0x68, 0x1a, 0x97,
+ 0x74, 0xa7, 0xd2, 0xec, 0xb9, 0x8b, 0xbf, 0x8c, 0xd7, 0xb6, 0x2e, 0x3d, 0x3b, 0x7d, 0xf8, 0x84,
+ 0x2b, 0x30, 0xe6, 0x40, 0x13, 0x53, 0xbe, 0x47, 0xd9, 0x14, 0x16, 0xdf, 0x05, 0xeb, 0xa3, 0x6c,
+ 0x74, 0xd4, 0xba, 0x8d, 0xf5, 0x80, 0xab, 0xc8, 0x40, 0x3c, 0xd5, 0x00, 0x47, 0x86, 0x66, 0x73,
+ 0x6b, 0x36, 0xc5, 0xa2, 0x81, 0x92, 0xd8, 0xfd, 0xde, 0x61, 0x34, 0xc3, 0x34, 0xaa, 0x1a, 0x40,
+ 0x3c, 0x95, 0x8f, 0x75, 0x2f, 0xc6, 0x22, 0xbb, 0x45, 0xfa, 0x68, 0x10, 0xd7, 0x22, 0x09, 0x59,
+ 0x36, 0x25, 0x45, 0x06, 0x9b, 0xa2, 0x33, 0xf9, 0x34, 0x63, 0xe2, 0x2b, 0x18, 0xa7, 0xbe, 0x25,
+ 0xf2, 0xe6, 0x9d, 0x99, 0x97, 0xb1, 0x0d, 0x64, 0x3a, 0x53, 0xcb, 0xe5, 0x73, 0xc6, 0x47, 0x3c,
+ 0x76, 0x87, 0xae, 0x74, 0x1f, 0x4f, 0x84, 0x2e, 0x4f, 0x10, 0xda, 0x4e, 0x32, 0x40, 0x71, 0xc4,
+ 0xd9, 0xac, 0x85, 0x4c, 0x6e, 0x10, 0x37, 0x66, 0xcd, 0x49, 0x83, 0x20, 0xa7, 0xe7, 0x47, 0x70,
+ 0xaf, 0x38, 0x6c, 0x95, 0x32, 0x6e, 0x7f, 0x21, 0x9e, 0x2b, 0xbd, 0x09, 0x6a, 0xe0, 0xd9, 0xdf,
+ 0x27, 0x1e, 0x41, 0x0b, 0x1a, 0xc3, 0x6c, 0x83, 0x9f, 0x1a, 0x57, 0x5e, 0x94, 0x72, 0xc5, 0x8d,
+ 0x9f, 0x61, 0xe4, 0x47, 0x56, 0xb1, 0x80, 0x32, 0x3c, 0x23, 0x4c, 0x21, 0x0d, 0xdd, 0x4e, 0x5f,
+ 0x61, 0x8a, 0xcf, 0xee, 0x59, 0x87, 0x36, 0xe4, 0x0a, 0x24, 0x7c, 0x03, 0xda, 0x64, 0x76, 0x3c,
+ 0x80, 0x04, 0x3c, 0x89, 0x91, 0x9e, 0x56, 0xba, 0x66, 0x98, 0xb2, 0xfc, 0x8d, 0x81, 0xdf, 0xf4,
+ 0x3c, 0x0c, 0x0c, 0x03, 0xee, 0xd9, 0xb4, 0xb0, 0x0a, 0xcf, 0x6d, 0x0b, 0xf6, 0xe7, 0xa6, 0x21,
+ 0x1c, 0xe7, 0x9f, 0xa5, 0x74, 0xea, 0x18, 0x3f, 0xf7, 0x2c, 0x3c, 0x09, 0x53, 0xd6, 0xcc, 0x71,
+ 0xd7, 0x07, 0x9d, 0x3d, 0x59, 0xb4, 0xec, 0x86, 0xe9, 0x8b, 0xa0, 0x14, 0x99, 0xf8, 0xa6, 0x9b,
+ 0x59, 0xe2, 0x6e, 0x73, 0x78, 0xe0, 0xf3, 0xcb, 0xce, 0x06, 0xd0, 0x1b, 0x70, 0xd8, 0x15, 0xc2,
+ 0xbf, 0x04, 0xe8, 0xcb, 0x31, 0x1d, 0x04, 0x9f, 0x9d, 0xf2, 0xa1, 0x60, 0x1f, 0x63, 0x49, 0x64,
+ 0x56, 0x3e, 0xa1, 0x64, 0xf2, 0xb0, 0xaa, 0xdc, 0x5f, 0xa3, 0x3b, 0x8d, 0x16, 0x07, 0xa1, 0xf3,
+ 0xec, 0xc5, 0x7f, 0xe2, 0x1c, 0xeb, 0xb7, 0x81, 0xd3, 0xdf, 0x5f, 0xee, 0xa0, 0xe1, 0x82, 0x25,
+ 0x7a, 0xe2, 0x3f, 0xce, 0x3b, 0x89, 0x1f, 0xbe, 0x73, 0x9e, 0xe4, 0x46, 0x11, 0x39, 0xfc, 0x6b,
+ 0xe6, 0x99, 0xd6, 0x98, 0x9f, 0x8f, 0x19, 0x41, 0x90, 0x5d, 0xf1, 0x85, 0x94, 0xe7, 0x13, 0x91,
+ 0xe3, 0x01, 0xfd, 0x41, 0x29, 0x1d, 0xcb, 0x11, 0x13, 0xcd, 0x4c, 0x92, 0x6c, 0x15, 0x7c, 0xd1,
+ 0xbc, 0x50, 0x68, 0x4c, 0x46, 0xe3, 0x0f, 0x25, 0xd5, 0x6c, 0x3b, 0x53, 0x0b, 0x2f, 0x1d, 0xd2,
+ 0x52, 0xca, 0x97, 0x29, 0x5c, 0xdf, 0x24, 0xa8, 0xc6, 0xbe, 0xd1, 0xc1, 0x14, 0x20, 0x24, 0x4f,
+ 0xfa, 0xd4, 0xe5, 0xb0, 0x93, 0x45, 0xe1, 0xc9, 0xf2, 0xbe, 0x0d, 0xc2, 0xd1, 0x4c, 0xab, 0x2f,
+ 0x85, 0xc1, 0x0b, 0x51, 0x40, 0x7c, 0xdf, 0x7f, 0x74, 0xa1, 0x3d, 0xb8, 0x4d, 0x4f, 0x26, 0x24,
+ 0x11, 0x61, 0x64, 0xd3, 0x0e, 0x5b, 0x29, 0x87, 0x05, 0xfe, 0xb9, 0x78, 0xde, 0xad, 0xf9, 0xe8,
+ 0xc4, 0x47, 0x4d, 0xfb, 0xa8, 0x54, 0x99, 0x50, 0x1d, 0xe7, 0xaf, 0x1a, 0x12, 0x20, 0x8d, 0xcd,
+ 0xde, 0x8e, 0xf8, 0x26, 0x65, 0x8b,
+ };
+ unsigned char commit_0[] = {
+ 0x09, 0x9e, 0x56, 0x8d, 0x5b, 0x9d, 0x2a, 0xd6, 0x1f, 0xe0, 0x81, 0x21, 0xcc, 0x15, 0xb3, 0x66,
+ 0x6d, 0xb4, 0xbb, 0xac, 0xdd, 0x28, 0x08, 0xab, 0x21, 0x6e, 0x35, 0xac, 0xa7, 0xe0, 0x0a, 0xa8,
+ 0xef,
+ };
+
+ CHECK(secp256k1_pedersen_commit(ctx, &pc, vector_blind, value, secp256k1_generator_h));
+ CHECK(secp256k1_rangeproof_sign(ctx, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, secp256k1_generator_h));
+ CHECK(p_len <= secp256k1_rangeproof_max_size(ctx, value, min_bits));
+ CHECK(p_len == sizeof(proof));
+ /* Uncomment the next line to print the test vector */
+ /* print_vector(0, proof, p_len, &pc); */
+ CHECK(p_len == sizeof(vector_0));
+ CHECK(secp256k1_memcmp_var(proof, vector_0, p_len) == 0);
+
+ test_rangeproof_fixed_vectors_reproducible_helper(vector_0, sizeof(vector_0), commit_0, &value_r, &min_value_r, &max_value_r, message_r, &m_len_r);
+ CHECK(value_r == value);
+ CHECK(m_len_r == m_len);
+ CHECK(secp256k1_memcmp_var(message_r, message, m_len_r) == 0);
+ CHECK(min_value_r == min_value);
+ CHECK(max_value_r == UINT64_MAX);
+ memset(message_r, 0, sizeof(message_r));
+ }
+
+ /* Test min_bits = 3 */
+ {
+ uint64_t value = 13;
+ size_t m_len = 128; /* maximum message length with min_bits = 3 */
+
+ uint64_t min_value = 1;
+ int min_bits = 3;
+ int exp = 1;
+ unsigned char proof[267];
+ size_t p_len = sizeof(proof);
+ secp256k1_pedersen_commitment pc;
+
+ unsigned char vector_1[] = {
+ 0x61, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0xcb, 0xdc, 0xbe, 0x42, 0xe6,
+ 0x44, 0x1e, 0xc4, 0x63, 0x9d, 0xb1, 0x93, 0x7b, 0x49, 0xdc, 0xd5, 0x6e, 0x55, 0xdd, 0x3b, 0x1e,
+ 0x41, 0x1c, 0x0e, 0xd7, 0x47, 0xd7, 0xf0, 0x26, 0xf7, 0xe4, 0x36, 0xbd, 0x51, 0xb9, 0x77, 0x90,
+ 0x33, 0xdd, 0x64, 0xe7, 0x47, 0x38, 0x49, 0x29, 0x12, 0xa8, 0x12, 0x79, 0xbc, 0x62, 0xea, 0xf9,
+ 0xb5, 0x51, 0x8f, 0x51, 0xea, 0x28, 0x5d, 0x30, 0x9f, 0x30, 0xd5, 0x93, 0x31, 0x56, 0x61, 0x01,
+ 0xd7, 0x7f, 0xa4, 0xec, 0xfc, 0xe5, 0x83, 0x52, 0x5a, 0xe0, 0x80, 0x76, 0x40, 0xb8, 0x8d, 0x67,
+ 0x23, 0x46, 0x8c, 0xb8, 0x74, 0x2a, 0x20, 0x12, 0x86, 0x4d, 0xd8, 0x8c, 0x23, 0x73, 0x2f, 0xbe,
+ 0x99, 0xa5, 0xd5, 0x8c, 0x11, 0xc7, 0xb2, 0xf9, 0xd3, 0x7c, 0x88, 0x16, 0x4d, 0x21, 0x80, 0x10,
+ 0x70, 0xfc, 0x1f, 0x9b, 0x0b, 0x5e, 0xbe, 0xe3, 0x65, 0xe2, 0x4f, 0xbd, 0x1d, 0xb0, 0x64, 0x0a,
+ 0xc5, 0xe0, 0x94, 0x8b, 0x49, 0xf7, 0xc4, 0x88, 0x5e, 0xc0, 0x2d, 0xbb, 0x98, 0x60, 0x5f, 0xd2,
+ 0x7a, 0x9a, 0xff, 0x9e, 0x1c, 0x1f, 0x45, 0x34, 0x08, 0x96, 0xa9, 0xd3, 0xa5, 0x4d, 0x95, 0x9c,
+ 0x1f, 0xe6, 0xe5, 0xdc, 0x32, 0xbb, 0x18, 0x4a, 0x76, 0x22, 0xe9, 0x75, 0x1f, 0x45, 0x6b, 0x81,
+ 0x70, 0x4a, 0xc8, 0x00, 0x72, 0x7a, 0xc8, 0xee, 0xed, 0xc5, 0x19, 0x8f, 0xec, 0x7b, 0x4b, 0xfd,
+ 0x7f, 0xc8, 0x51, 0xda, 0x28, 0x0e, 0x95, 0xd3, 0xc6, 0xc1, 0x29, 0x28, 0x3f, 0xd8, 0x3d, 0x41,
+ 0xde, 0xdf, 0xfc, 0x2b, 0x71, 0x3a, 0xdb, 0x78, 0xa4, 0x0e, 0x50, 0xb8, 0xf9, 0xae, 0xdb, 0x7b,
+ 0xb1, 0x31, 0x81, 0xc2, 0xf2, 0xb5, 0x01, 0x64, 0x8e, 0x86, 0xe2, 0x8b, 0x67, 0x13, 0xec, 0x7e,
+ 0xf5, 0xad, 0x9d, 0x57, 0x2b, 0x5d, 0x0c, 0x94, 0xa9, 0x89, 0x92,
+ };
+ unsigned char commit_1[] = {
+ 0x09, 0xe5, 0xb3, 0x27, 0x82, 0x88, 0xeb, 0x21, 0xcd, 0xb2, 0x56, 0x37, 0x61, 0x84, 0xce, 0xc1,
+ 0x66, 0x16, 0x2e, 0x44, 0xc8, 0x65, 0x8e, 0xe6, 0x3a, 0x1a, 0x57, 0x2c, 0xb9, 0x6c, 0x07, 0x85,
+ 0xf0,
+ };
+ CHECK(secp256k1_pedersen_commit(ctx, &pc, vector_blind, value, secp256k1_generator_h));
+ CHECK(secp256k1_rangeproof_sign(ctx, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, secp256k1_generator_h));
+ CHECK(p_len <= secp256k1_rangeproof_max_size(ctx, value, min_bits));
+ CHECK(p_len == sizeof(proof));
+ /* Uncomment the next line to print the test vector */
+ /* print_vector(1, proof, p_len, &pc); */
+ CHECK(p_len == sizeof(vector_1));
+ CHECK(secp256k1_memcmp_var(proof, vector_1, p_len) == 0);
+
+ test_rangeproof_fixed_vectors_reproducible_helper(vector_1, sizeof(vector_1), commit_1, &value_r, &min_value_r, &max_value_r, message_r, &m_len_r);
+ CHECK(value_r == value);
+ CHECK(m_len_r == m_len);
+ CHECK(secp256k1_memcmp_var(message_r, message, m_len_r) == 0);
+ CHECK(min_value_r == 3);
+ CHECK(max_value_r == 73);
+ memset(message_r, 0, sizeof(message_r));
+ }
+
+ /* Test large min_value */
+ {
+ uint64_t value = INT64_MAX;
+ size_t m_len = 0; /* maximum message length with min_bits = 3 */
+
+ /* Uncomment this to recreate test vector */
+ uint64_t min_value = INT64_MAX-1;
+ int min_bits = 1;
+ int exp = 0;
+ unsigned char proof[106];
+ size_t p_len = sizeof(proof);
+ secp256k1_pedersen_commitment pc;
+
+ unsigned char vector_2[] = {
+ 0x60, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x81, 0xd8, 0x21, 0x12, 0x4d, 0xa4,
+ 0x84, 0xdd, 0x2c, 0xd1, 0x04, 0xe7, 0x08, 0x9a, 0xd3, 0x6f, 0xa5, 0xd8, 0xfc, 0x52, 0x4c, 0xba,
+ 0xf0, 0x83, 0xeb, 0x76, 0x9f, 0x1c, 0x03, 0xe3, 0xcf, 0x23, 0x1e, 0x40, 0x18, 0xc6, 0x6d, 0xf9,
+ 0x25, 0x56, 0x80, 0x3c, 0x83, 0xdd, 0x58, 0x36, 0x43, 0xe3, 0x56, 0xa0, 0xb7, 0xf0, 0x0e, 0xf9,
+ 0xe2, 0x8b, 0x82, 0x5a, 0x77, 0xa7, 0xbe, 0x36, 0x98, 0x10, 0x99, 0x2e, 0xaa, 0x21, 0x24, 0xe6,
+ 0x78, 0xa8, 0xcc, 0xc7, 0x06, 0x1c, 0x06, 0xb0, 0x03, 0x87, 0x86, 0x89, 0xce, 0x85, 0x88, 0xea,
+ 0xa1, 0x9d, 0x4d, 0xfd, 0x8d, 0x65, 0xbd, 0xa9, 0xd0, 0x0f,
+ };
+ unsigned char commit_2[] = {
+ 0x09, 0x2a, 0x74, 0xa1, 0x9c, 0xee, 0xcb, 0x6a, 0xd1, 0xa7, 0x97, 0xbe, 0x97, 0xe7, 0xb6, 0x37,
+ 0x90, 0x96, 0xc2, 0x5a, 0xe5, 0xfc, 0xed, 0x91, 0xff, 0x4c, 0x67, 0x07, 0x96, 0x1d, 0x2a, 0xb3,
+ 0x70,
+ };
+
+ CHECK(secp256k1_pedersen_commit(ctx, &pc, vector_blind, value, secp256k1_generator_h));
+ CHECK(secp256k1_rangeproof_sign(ctx, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, secp256k1_generator_h));
+ CHECK(p_len <= secp256k1_rangeproof_max_size(ctx, value, min_bits));
+ CHECK(p_len == sizeof(proof));
+ /* Uncomment the next line to print the test vector */
+ /* print_vector(2, proof, p_len, &pc); */
+ CHECK(p_len == sizeof(vector_2));
+ CHECK(secp256k1_memcmp_var(proof, vector_2, p_len) == 0);
+
+ test_rangeproof_fixed_vectors_reproducible_helper(vector_2, sizeof(vector_2), commit_2, &value_r, &min_value_r, &max_value_r, message_r, &m_len_r);
+ CHECK(value_r == value);
+ CHECK(m_len_r == m_len);
+ CHECK(secp256k1_memcmp_var(message_r, message, m_len_r) == 0);
+ CHECK(min_value_r == INT64_MAX-1);
+ CHECK(max_value_r == INT64_MAX);
+ memset(message_r, 0, sizeof(message_r));
+ }
}
void run_rangeproof_tests(void) {
int i;
test_api();
+
+ test_single_value_proof(0);
+ test_single_value_proof(12345678);
+ test_single_value_proof(UINT64_MAX);
+
test_rangeproof_fixed_vectors();
- test_pedersen_commitment_fixed_vector();
- for (i = 0; i < count / 2 + 1; i++) {
- test_pedersen();
- }
+ test_rangeproof_fixed_vectors_reproducible();
for (i = 0; i < count / 2 + 1; i++) {
test_borromean();
}
test_rangeproof();
+ test_rangeproof_null_blinder();
test_multiple_generators();
}
diff --git a/src/modules/recovery/tests_exhaustive_impl.h b/src/modules/recovery/tests_exhaustive_impl.h
index 590a972ed3f..ed9386b6f8a 100644
--- a/src/modules/recovery/tests_exhaustive_impl.h
+++ b/src/modules/recovery/tests_exhaustive_impl.h
@@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
-#include "src/modules/recovery/main_impl.h"
+#include "main_impl.h"
#include "../../../include/secp256k1_recovery.h"
void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {
diff --git a/src/modules/schnorrsig/tests_exhaustive_impl.h b/src/modules/schnorrsig/tests_exhaustive_impl.h
index d8df9dd2df7..55f9028a638 100644
--- a/src/modules/schnorrsig/tests_exhaustive_impl.h
+++ b/src/modules/schnorrsig/tests_exhaustive_impl.h
@@ -8,7 +8,7 @@
#define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H
#include "../../../include/secp256k1_schnorrsig.h"
-#include "src/modules/schnorrsig/main_impl.h"
+#include "main_impl.h"
static const unsigned char invalid_pubkey_bytes[][32] = {
/* 0 */
diff --git a/src/modules/surjection/main_impl.h b/src/modules/surjection/main_impl.h
index b8f145e5f11..c6bdea2e509 100644
--- a/src/modules/surjection/main_impl.h
+++ b/src/modules/surjection/main_impl.h
@@ -3,21 +3,21 @@
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef SECP256K1_MODULE_SURJECTION_MAIN
-#define SECP256K1_MODULE_SURJECTION_MAIN
+#ifndef SECP256K1_MODULE_SURJECTION_MAIN_H
+#define SECP256K1_MODULE_SURJECTION_MAIN_H
#include
#include
#if defined HAVE_CONFIG_H
-#include "libsecp256k1-config.h"
+#include "../../libsecp256k1-config.h"
#endif
-#include "include/secp256k1_rangeproof.h"
-#include "include/secp256k1_surjectionproof.h"
-#include "modules/rangeproof/borromean.h"
-#include "modules/surjection/surjection_impl.h"
-#include "hash.h"
+#include "../../../include/secp256k1_rangeproof.h"
+#include "../../../include/secp256k1_surjectionproof.h"
+#include "../rangeproof/borromean.h"
+#include "surjection_impl.h"
+#include "../../hash.h"
#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE
#undef SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS
@@ -243,7 +243,7 @@ int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1
while (1) {
size_t next_input_index;
next_input_index = secp256k1_surjectionproof_csprng_next(&csprng, n_input_tags);
- if (memcmp(&fixed_input_tags[next_input_index], fixed_output_tag, sizeof(*fixed_output_tag)) == 0) {
+ if (secp256k1_memcmp_var(&fixed_input_tags[next_input_index], fixed_output_tag, sizeof(*fixed_output_tag)) == 0) {
*input_index = next_input_index;
has_output_tag = 1;
}
@@ -298,6 +298,10 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
CHECK(proof->initialized == 1);
#endif
+ n_used_pubkeys = secp256k1_surjectionproof_n_used_inputs(ctx, proof);
+ /* This must be true if the proof was created with surjectionproof_initialize */
+ ARG_CHECK(n_used_pubkeys > 0);
+
/* Compute secret key */
secp256k1_scalar_set_b32(&tmps, input_blinding_key, &overflow);
if (overflow) {
@@ -307,17 +311,21 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
if (overflow) {
return 0;
}
- /* The only time the input may equal the output is if neither one was blinded in the first place,
- * i.e. both blinding keys are zero. Otherwise this is a privacy leak. */
- if (secp256k1_scalar_eq(&tmps, &blinding_key) && !secp256k1_scalar_is_zero(&blinding_key)) {
- return 0;
+ /* If any input tag is equal to an output tag, verification will fail, because our ring
+ * signature logic would receive a zero-key, which is illegal. This is unfortunate but
+ * it is deployed on Liquid and cannot be fixed without a hardfork. We should review
+ * this at the same time that we relax the max-256-inputs rule. */
+ for (i = 0; i < n_ephemeral_input_tags; i++) {
+ if (secp256k1_memcmp_var(ephemeral_input_tags[i].data, ephemeral_output_tag->data, sizeof(ephemeral_output_tag->data)) == 0) {
+ return 0;
+ }
}
secp256k1_scalar_negate(&tmps, &tmps);
secp256k1_scalar_add(&blinding_key, &blinding_key, &tmps);
/* Compute public keys */
n_total_pubkeys = secp256k1_surjectionproof_n_total_inputs(ctx, proof);
- n_used_pubkeys = secp256k1_surjectionproof_n_used_inputs(ctx, proof);
+
if (n_used_pubkeys > n_total_pubkeys || n_total_pubkeys != n_ephemeral_input_tags) {
return 0;
}
diff --git a/src/modules/surjection/surjection.h b/src/modules/surjection/surjection.h
index 20ac4931630..ac7407d7187 100644
--- a/src/modules/surjection/surjection.h
+++ b/src/modules/surjection/surjection.h
@@ -4,11 +4,11 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SURJECTION_H_
-#define _SECP256K1_SURJECTION_H_
+#ifndef SECP256K1_SURJECTION_H
+#define SECP256K1_SURJECTION_H
-#include "group.h"
-#include "scalar.h"
+#include "../../group.h"
+#include "../../scalar.h"
SECP256K1_INLINE static int secp256k1_surjection_genmessage(unsigned char *msg32, secp256k1_ge *ephemeral_input_tags, size_t n_input_tags, secp256k1_ge *ephemeral_output_tag);
diff --git a/src/modules/surjection/surjection_impl.h b/src/modules/surjection/surjection_impl.h
index f3652567fa5..f5adc7ebccc 100644
--- a/src/modules/surjection/surjection_impl.h
+++ b/src/modules/surjection/surjection_impl.h
@@ -4,16 +4,16 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SURJECTION_IMPL_H_
-#define _SECP256K1_SURJECTION_IMPL_H_
+#ifndef SECP256K1_SURJECTION_IMPL_H
+#define SECP256K1_SURJECTION_IMPL_H
#include
#include
-#include "eckey.h"
-#include "group.h"
-#include "scalar.h"
-#include "hash.h"
+#include "../../eckey.h"
+#include "../../group.h"
+#include "../../scalar.h"
+#include "../../hash.h"
SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg32, const secp256k1_generator *ephemeral_input_tags, size_t n_input_tags, const secp256k1_generator *ephemeral_output_tag) {
/* compute message */
diff --git a/src/modules/surjection/tests_impl.h b/src/modules/surjection/tests_impl.h
index 89ba4e1a6ab..cf9e39aeb5f 100644
--- a/src/modules/surjection/tests_impl.h
+++ b/src/modules/surjection/tests_impl.h
@@ -4,14 +4,14 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef SECP256K1_MODULE_SURJECTIONPROOF_TESTS
-#define SECP256K1_MODULE_SURJECTIONPROOF_TESTS
+#ifndef SECP256K1_MODULE_SURJECTIONPROOF_TESTS_H
+#define SECP256K1_MODULE_SURJECTIONPROOF_TESTS_H
-#include "testrand.h"
-#include "group.h"
-#include "include/secp256k1_generator.h"
-#include "include/secp256k1_rangeproof.h"
-#include "include/secp256k1_surjectionproof.h"
+#include "../../testrand.h"
+#include "../../group.h"
+#include "../../../include/secp256k1_generator.h"
+#include "../../../include/secp256k1_rangeproof.h"
+#include "../../../include/secp256k1_surjectionproof.h"
static void test_surjectionproof_api(void) {
unsigned char seed[32];
@@ -173,31 +173,45 @@ static void test_surjectionproof_api(void) {
CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs, NULL) == 0);
CHECK(ecount == 16);
+ /* Test how surjectionproof_generate fails when the proof was not created
+ * with surjectionproof_initialize */
+ ecount = 0;
+ CHECK(secp256k1_surjectionproof_generate(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 1);
+ {
+ secp256k1_surjectionproof tmp_proof = proof;
+ tmp_proof.n_inputs = 0;
+ CHECK(secp256k1_surjectionproof_generate(sign, &tmp_proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
+ }
+ CHECK(ecount == 1);
+
+ CHECK(secp256k1_surjectionproof_generate(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 1);
+
/* Check serialize */
+ ecount = 0;
serialized_len = sizeof(serialized_proof);
CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0);
- CHECK(ecount == 16);
+ CHECK(ecount == 0);
serialized_len = sizeof(serialized_proof);
CHECK(secp256k1_surjectionproof_serialize(none, NULL, &serialized_len, &proof) == 0);
- CHECK(ecount == 17);
+ CHECK(ecount == 1);
serialized_len = sizeof(serialized_proof);
CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, NULL, &proof) == 0);
- CHECK(ecount == 18);
+ CHECK(ecount == 2);
serialized_len = sizeof(serialized_proof);
CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, NULL) == 0);
- CHECK(ecount == 19);
+ CHECK(ecount == 3);
serialized_len = sizeof(serialized_proof);
CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0);
/* Check parse */
CHECK(secp256k1_surjectionproof_parse(none, &proof, serialized_proof, serialized_len) != 0);
- CHECK(ecount == 19);
+ CHECK(ecount == 3);
CHECK(secp256k1_surjectionproof_parse(none, NULL, serialized_proof, serialized_len) == 0);
- CHECK(ecount == 20);
+ CHECK(ecount == 4);
CHECK(secp256k1_surjectionproof_parse(none, &proof, NULL, serialized_len) == 0);
- CHECK(ecount == 21);
+ CHECK(ecount == 5);
CHECK(secp256k1_surjectionproof_parse(none, &proof, serialized_proof, 0) == 0);
- CHECK(ecount == 21);
+ CHECK(ecount == 5);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
@@ -524,6 +538,31 @@ void test_bad_parse(void) {
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof2, sizeof(serialized_proof2)) == 0);
}
+void test_input_eq_output(void) {
+ secp256k1_surjectionproof proof;
+ secp256k1_fixed_asset_tag fixed_tag;
+ secp256k1_generator ephemeral_tag;
+ unsigned char blinding_key[32];
+ unsigned char entropy[32];
+ size_t input_index;
+
+ secp256k1_testrand256(fixed_tag.data);
+ secp256k1_testrand256(blinding_key);
+ secp256k1_testrand256(entropy);
+
+ CHECK(secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, &fixed_tag, 1, 1, &fixed_tag, 100, entropy) == 1);
+ CHECK(input_index == 0);
+
+ /* Generation should fail */
+ CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_tag, fixed_tag.data, blinding_key));
+ CHECK(!secp256k1_surjectionproof_generate(ctx, &proof, &ephemeral_tag, 1, &ephemeral_tag, input_index, blinding_key, blinding_key));
+
+ /* ...even when the blinding key is zero */
+ memset(blinding_key, 0, 32);
+ CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_tag, fixed_tag.data, blinding_key));
+ CHECK(!secp256k1_surjectionproof_generate(ctx, &proof, &ephemeral_tag, 1, &ephemeral_tag, input_index, blinding_key, blinding_key));
+}
+
void test_fixed_vectors(void) {
const unsigned char tag0_ser[] = {
0x0a,
@@ -672,6 +711,7 @@ void test_fixed_vectors(void) {
void run_surjection_tests(void) {
test_surjectionproof_api();
+ test_input_eq_output();
test_fixed_vectors();
test_input_selection(0);
diff --git a/src/modules/whitelist/main_impl.h b/src/modules/whitelist/main_impl.h
index a37e16ffeb4..da631522785 100644
--- a/src/modules/whitelist/main_impl.h
+++ b/src/modules/whitelist/main_impl.h
@@ -4,11 +4,11 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef SECP256K1_MODULE_WHITELIST_MAIN
-#define SECP256K1_MODULE_WHITELIST_MAIN
+#ifndef SECP256K1_MODULE_WHITELIST_MAIN_H
+#define SECP256K1_MODULE_WHITELIST_MAIN_H
-#include "include/secp256k1_whitelist.h"
-#include "modules/whitelist/whitelist_impl.h"
+#include "../../../include/secp256k1_whitelist.h"
+#include "whitelist_impl.h"
#define MAX_KEYS SECP256K1_WHITELIST_MAX_N_KEYS /* shorter alias */
diff --git a/src/modules/whitelist/tests_impl.h b/src/modules/whitelist/tests_impl.h
index 10e8693e69b..19c1d6e07d4 100644
--- a/src/modules/whitelist/tests_impl.h
+++ b/src/modules/whitelist/tests_impl.h
@@ -4,10 +4,10 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef SECP256K1_MODULE_WHITELIST_TESTS
-#define SECP256K1_MODULE_WHITELIST_TESTS
+#ifndef SECP256K1_MODULE_WHITELIST_TESTS_H
+#define SECP256K1_MODULE_WHITELIST_TESTS_H
-#include "include/secp256k1_whitelist.h"
+#include "../../../include/secp256k1_whitelist.h"
void test_whitelist_end_to_end_internal(const unsigned char *summed_seckey, const unsigned char *online_seckey, const secp256k1_pubkey *online_pubkeys, const secp256k1_pubkey *offline_pubkeys, const secp256k1_pubkey *sub_pubkey, const size_t signer_i, const size_t n_keys) {
unsigned char serialized[32 + 4 + 32 * SECP256K1_WHITELIST_MAX_N_KEYS] = {0};
diff --git a/src/modules/whitelist/whitelist_impl.h b/src/modules/whitelist/whitelist_impl.h
index fc1d489c698..8d6911271c5 100644
--- a/src/modules/whitelist/whitelist_impl.h
+++ b/src/modules/whitelist/whitelist_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_WHITELIST_IMPL_H_
-#define _SECP256K1_WHITELIST_IMPL_H_
+#ifndef SECP256K1_WHITELIST_IMPL_H
+#define SECP256K1_WHITELIST_IMPL_H
static int secp256k1_whitelist_hash_pubkey(secp256k1_scalar* output, secp256k1_gej* pubkey) {
unsigned char h[32];
diff --git a/src/scalar.h b/src/scalar.h
index 36eb0db8d38..227913cb5d3 100644
--- a/src/scalar.h
+++ b/src/scalar.h
@@ -65,6 +65,9 @@ static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a,
* the low bits that were shifted off */
static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n);
+/** Compute the square of a scalar (modulo the group order). */
+static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a);
+
/** Compute the inverse of a scalar (modulo the group order). */
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a);
diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h
index 6b0b44ed921..426c41f1aa5 100644
--- a/src/scalar_4x64_impl.h
+++ b/src/scalar_4x64_impl.h
@@ -110,8 +110,9 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
uint128_t t;
+ volatile int vflag = flag;
VERIFY_CHECK(bit < 256);
- bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */
+ bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */
t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F));
@@ -180,7 +181,8 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
/* If we are flag = 0, mask = 00...00 and this is a no-op;
* if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
- uint64_t mask = !flag - 1;
+ volatile int vflag = flag;
+ uint64_t mask = -vflag;
uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1;
uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
r->d[0] = t & nonzero; t >>= 64;
@@ -224,6 +226,28 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
VERIFY_CHECK(c1 >= th); \
}
+/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
+#define muladd2(a,b) { \
+ uint64_t tl, th, th2, tl2; \
+ { \
+ uint128_t t = (uint128_t)a * b; \
+ th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \
+ tl = t; \
+ } \
+ th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \
+ c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \
+ VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
+ tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \
+ th2 += (tl2 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
+ c0 += tl2; /* overflow is handled on the next line */ \
+ th2 += (c0 < tl2); /* second overflow is handled on the next line */ \
+ c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \
+ VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \
+ c1 += th2; /* overflow is handled on the next line */ \
+ c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \
+ VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \
+}
+
/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */
#define sumadd(a) { \
unsigned int over; \
@@ -365,7 +389,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"movq %%r10, %q5\n"
/* extract m6 */
"movq %%r8, %q6\n"
- : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6)
+ : "=&g"(m0), "=&g"(m1), "=&g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6)
: "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc");
@@ -733,10 +757,148 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c
#endif
}
+static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) {
+#ifdef USE_ASM_X86_64
+ __asm__ __volatile__(
+ /* Preload */
+ "movq 0(%%rdi), %%r11\n"
+ "movq 8(%%rdi), %%r12\n"
+ "movq 16(%%rdi), %%r13\n"
+ "movq 24(%%rdi), %%r14\n"
+ /* (rax,rdx) = a0 * a0 */
+ "movq %%r11, %%rax\n"
+ "mulq %%r11\n"
+ /* Extract l0 */
+ "movq %%rax, 0(%%rsi)\n"
+ /* (r8,r9,r10) = (rdx,0) */
+ "movq %%rdx, %%r8\n"
+ "xorq %%r9, %%r9\n"
+ "xorq %%r10, %%r10\n"
+ /* (r8,r9,r10) += 2 * a0 * a1 */
+ "movq %%r11, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* Extract l1 */
+ "movq %%r8, 8(%%rsi)\n"
+ "xorq %%r8, %%r8\n"
+ /* (r9,r10,r8) += 2 * a0 * a2 */
+ "movq %%r11, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* (r9,r10,r8) += a1 * a1 */
+ "movq %%r12, %%rax\n"
+ "mulq %%r12\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* Extract l2 */
+ "movq %%r9, 16(%%rsi)\n"
+ "xorq %%r9, %%r9\n"
+ /* (r10,r8,r9) += 2 * a0 * a3 */
+ "movq %%r11, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* (r10,r8,r9) += 2 * a1 * a2 */
+ "movq %%r12, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ "adcq $0, %%r9\n"
+ /* Extract l3 */
+ "movq %%r10, 24(%%rsi)\n"
+ "xorq %%r10, %%r10\n"
+ /* (r8,r9,r10) += 2 * a1 * a3 */
+ "movq %%r12, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* (r8,r9,r10) += a2 * a2 */
+ "movq %%r13, %%rax\n"
+ "mulq %%r13\n"
+ "addq %%rax, %%r8\n"
+ "adcq %%rdx, %%r9\n"
+ "adcq $0, %%r10\n"
+ /* Extract l4 */
+ "movq %%r8, 32(%%rsi)\n"
+ "xorq %%r8, %%r8\n"
+ /* (r9,r10,r8) += 2 * a2 * a3 */
+ "movq %%r13, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ "addq %%rax, %%r9\n"
+ "adcq %%rdx, %%r10\n"
+ "adcq $0, %%r8\n"
+ /* Extract l5 */
+ "movq %%r9, 40(%%rsi)\n"
+ /* (r10,r8) += a3 * a3 */
+ "movq %%r14, %%rax\n"
+ "mulq %%r14\n"
+ "addq %%rax, %%r10\n"
+ "adcq %%rdx, %%r8\n"
+ /* Extract l6 */
+ "movq %%r10, 48(%%rsi)\n"
+ /* Extract l7 */
+ "movq %%r8, 56(%%rsi)\n"
+ :
+ : "S"(l), "D"(a->d)
+ : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc", "memory");
+#else
+ /* 160 bit accumulator. */
+ uint64_t c0 = 0, c1 = 0;
+ uint32_t c2 = 0;
+
+ /* l[0..7] = a[0..3] * b[0..3]. */
+ muladd_fast(a->d[0], a->d[0]);
+ extract_fast(l[0]);
+ muladd2(a->d[0], a->d[1]);
+ extract(l[1]);
+ muladd2(a->d[0], a->d[2]);
+ muladd(a->d[1], a->d[1]);
+ extract(l[2]);
+ muladd2(a->d[0], a->d[3]);
+ muladd2(a->d[1], a->d[2]);
+ extract(l[3]);
+ muladd2(a->d[1], a->d[3]);
+ muladd(a->d[2], a->d[2]);
+ extract(l[4]);
+ muladd2(a->d[2], a->d[3]);
+ extract(l[5]);
+ muladd_fast(a->d[3], a->d[3]);
+ extract_fast(l[6]);
+ VERIFY_CHECK(c1 == 0);
+ l[7] = c0;
+#endif
+}
+
#undef sumadd
#undef sumadd_fast
#undef muladd
#undef muladd_fast
+#undef muladd2
#undef extract
#undef extract_fast
@@ -758,6 +920,12 @@ static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
return ret;
}
+static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
+ uint64_t l[8];
+ secp256k1_scalar_sqr_512(l, a);
+ secp256k1_scalar_reduce_512(r, l);
+}
+
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) {
r1->d[0] = k->d[0];
r1->d[1] = k->d[1];
@@ -792,8 +960,9 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint64_t mask0, mask1;
+ volatile int vflag = flag;
VG_CHECK_VERIFY(r->d, sizeof(r->d));
- mask0 = flag + ~((uint64_t)0);
+ mask0 = vflag + ~((uint64_t)0);
mask1 = ~mask0;
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);
r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1);
diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h
index acd5ef7de05..b96e0335aba 100644
--- a/src/scalar_8x32_impl.h
+++ b/src/scalar_8x32_impl.h
@@ -153,8 +153,9 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
uint64_t t;
+ volatile int vflag = flag;
VERIFY_CHECK(bit < 256);
- bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */
+ bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */
t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F));
@@ -253,7 +254,8 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
/* If we are flag = 0, mask = 00...00 and this is a no-op;
* if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
- uint32_t mask = !flag - 1;
+ volatile int vflag = flag;
+ uint32_t mask = -vflag;
uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0);
uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
r->d[0] = t & nonzero; t >>= 32;
@@ -306,6 +308,28 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
VERIFY_CHECK(c1 >= th); \
}
+/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */
+#define muladd2(a,b) { \
+ uint32_t tl, th, th2, tl2; \
+ { \
+ uint64_t t = (uint64_t)a * b; \
+ th = t >> 32; /* at most 0xFFFFFFFE */ \
+ tl = t; \
+ } \
+ th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \
+ c2 += (th2 < th); /* never overflows by contract (verified the next line) */ \
+ VERIFY_CHECK((th2 >= th) || (c2 != 0)); \
+ tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \
+ th2 += (tl2 < tl); /* at most 0xFFFFFFFF */ \
+ c0 += tl2; /* overflow is handled on the next line */ \
+ th2 += (c0 < tl2); /* second overflow is handled on the next line */ \
+ c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \
+ VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \
+ c1 += th2; /* overflow is handled on the next line */ \
+ c2 += (c1 < th2); /* never overflows by contract (verified the next line) */ \
+ VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \
+}
+
/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */
#define sumadd(a) { \
unsigned int over; \
@@ -569,10 +593,71 @@ static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, con
l[15] = c0;
}
+static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) {
+ /* 96 bit accumulator. */
+ uint32_t c0 = 0, c1 = 0, c2 = 0;
+
+ /* l[0..15] = a[0..7]^2. */
+ muladd_fast(a->d[0], a->d[0]);
+ extract_fast(l[0]);
+ muladd2(a->d[0], a->d[1]);
+ extract(l[1]);
+ muladd2(a->d[0], a->d[2]);
+ muladd(a->d[1], a->d[1]);
+ extract(l[2]);
+ muladd2(a->d[0], a->d[3]);
+ muladd2(a->d[1], a->d[2]);
+ extract(l[3]);
+ muladd2(a->d[0], a->d[4]);
+ muladd2(a->d[1], a->d[3]);
+ muladd(a->d[2], a->d[2]);
+ extract(l[4]);
+ muladd2(a->d[0], a->d[5]);
+ muladd2(a->d[1], a->d[4]);
+ muladd2(a->d[2], a->d[3]);
+ extract(l[5]);
+ muladd2(a->d[0], a->d[6]);
+ muladd2(a->d[1], a->d[5]);
+ muladd2(a->d[2], a->d[4]);
+ muladd(a->d[3], a->d[3]);
+ extract(l[6]);
+ muladd2(a->d[0], a->d[7]);
+ muladd2(a->d[1], a->d[6]);
+ muladd2(a->d[2], a->d[5]);
+ muladd2(a->d[3], a->d[4]);
+ extract(l[7]);
+ muladd2(a->d[1], a->d[7]);
+ muladd2(a->d[2], a->d[6]);
+ muladd2(a->d[3], a->d[5]);
+ muladd(a->d[4], a->d[4]);
+ extract(l[8]);
+ muladd2(a->d[2], a->d[7]);
+ muladd2(a->d[3], a->d[6]);
+ muladd2(a->d[4], a->d[5]);
+ extract(l[9]);
+ muladd2(a->d[3], a->d[7]);
+ muladd2(a->d[4], a->d[6]);
+ muladd(a->d[5], a->d[5]);
+ extract(l[10]);
+ muladd2(a->d[4], a->d[7]);
+ muladd2(a->d[5], a->d[6]);
+ extract(l[11]);
+ muladd2(a->d[5], a->d[7]);
+ muladd(a->d[6], a->d[6]);
+ extract(l[12]);
+ muladd2(a->d[6], a->d[7]);
+ extract(l[13]);
+ muladd_fast(a->d[7], a->d[7]);
+ extract_fast(l[14]);
+ VERIFY_CHECK(c1 == 0);
+ l[15] = c0;
+}
+
#undef sumadd
#undef sumadd_fast
#undef muladd
#undef muladd_fast
+#undef muladd2
#undef extract
#undef extract_fast
@@ -598,6 +683,12 @@ static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
return ret;
}
+static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
+ uint32_t l[16];
+ secp256k1_scalar_sqr_512(l, a);
+ secp256k1_scalar_reduce_512(r, l);
+}
+
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) {
r1->d[0] = k->d[0];
r1->d[1] = k->d[1];
@@ -644,8 +735,9 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint32_t mask0, mask1;
+ volatile int vflag = flag;
VG_CHECK_VERIFY(r->d, sizeof(r->d));
- mask0 = flag + ~((uint32_t)0);
+ mask0 = vflag + ~((uint32_t)0);
mask1 = ~mask0;
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);
r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1);
diff --git a/src/scalar_low_impl.h b/src/scalar_low_impl.h
index 47001fccb62..4005cc8c8ba 100644
--- a/src/scalar_low_impl.h
+++ b/src/scalar_low_impl.h
@@ -105,6 +105,10 @@ static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
return ret;
}
+static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
+ *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER;
+}
+
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
*r1 = *a;
*r2 = 0;
@@ -116,8 +120,9 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint32_t mask0, mask1;
+ volatile int vflag = flag;
VG_CHECK_VERIFY(r, sizeof(*r));
- mask0 = flag + ~((uint32_t)0);
+ mask0 = vflag + ~((uint32_t)0);
mask1 = ~mask0;
*r = (*r & mask0) | (*a & mask1);
}
diff --git a/src/secp256k1.c b/src/secp256k1.c
index 6c686e0b6df..bc07b290e41 100644
--- a/src/secp256k1.c
+++ b/src/secp256k1.c
@@ -33,17 +33,15 @@
#endif
#ifdef ENABLE_MODULE_GENERATOR
-# include "include/secp256k1_generator.h"
+# include "../include/secp256k1_generator.h"
#endif
#ifdef ENABLE_MODULE_RANGEPROOF
-# include "include/secp256k1_rangeproof.h"
-# include "modules/rangeproof/pedersen.h"
-# include "modules/rangeproof/rangeproof.h"
+# include "../include/secp256k1_rangeproof.h"
#endif
#ifdef ENABLE_MODULE_ECDSA_S2C
-# include "include/secp256k1_ecdsa_s2c.h"
+# include "../include/secp256k1_ecdsa_s2c.h"
static void secp256k1_ecdsa_s2c_opening_save(secp256k1_ecdsa_s2c_opening* opening, secp256k1_ge* ge);
#else
typedef void secp256k1_ecdsa_s2c_opening;
@@ -802,6 +800,36 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32,
return 1;
}
+/* Outputs 33 zero bytes if the given group element is the point at infinity and
+ * otherwise outputs the compressed serialization */
+static void secp256k1_ge_serialize_ext(unsigned char *out33, secp256k1_ge* ge) {
+ if (secp256k1_ge_is_infinity(ge)) {
+ memset(out33, 0, 33);
+ } else {
+ int ret;
+ size_t size = 33;
+ ret = secp256k1_eckey_pubkey_serialize(ge, out33, &size, 1);
+ /* Serialize must succeed because the point is not at infinity */
+ VERIFY_CHECK(ret && size == 33);
+ }
+}
+
+/* Outputs the point at infinity if the given byte array is all zero, otherwise
+ * attempts to parse compressed point serialization. */
+static int secp256k1_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) {
+ unsigned char zeros[33] = { 0 };
+
+ if (memcmp(in33, zeros, sizeof(zeros)) == 0) {
+ secp256k1_ge_set_infinity(ge);
+ return 1;
+ }
+ return secp256k1_eckey_pubkey_parse(ge, in33, 33);
+}
+
+#ifdef ENABLE_MODULE_BPPP
+# include "modules/bppp/main_impl.h"
+#endif
+
#ifdef ENABLE_MODULE_ECDH
# include "modules/ecdh/main_impl.h"
#endif
diff --git a/src/tests.c b/src/tests.c
index ca1ded47b3a..9e7efe3ad2b 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -1898,6 +1898,14 @@ void scalar_test(void) {
CHECK(secp256k1_scalar_eq(&r1, &r2));
}
+ {
+ /* Test square. */
+ secp256k1_scalar r1, r2;
+ secp256k1_scalar_sqr(&r1, &s1);
+ secp256k1_scalar_mul(&r2, &s1, &s1);
+ CHECK(secp256k1_scalar_eq(&r1, &r2));
+ }
+
{
/* Test multiplicative identity. */
secp256k1_scalar r1, v1;
@@ -2653,6 +2661,12 @@ void run_scalar_tests(void) {
CHECK(!secp256k1_scalar_check_overflow(&zz));
CHECK(secp256k1_scalar_eq(&one, &zz));
}
+ secp256k1_scalar_mul(&z, &x, &x);
+ CHECK(!secp256k1_scalar_check_overflow(&z));
+ secp256k1_scalar_sqr(&zz, &x);
+ CHECK(!secp256k1_scalar_check_overflow(&zz));
+ CHECK(secp256k1_scalar_eq(&zz, &z));
+ CHECK(secp256k1_scalar_eq(&r2, &zz));
}
}
}
@@ -7118,6 +7132,10 @@ void run_ecdsa_edge_cases(void) {
test_ecdsa_edge_cases();
}
+#ifdef ENABLE_MODULE_BPPP
+# include "modules/bppp/tests_impl.h"
+#endif
+
#ifdef ENABLE_MODULE_ECDH
# include "modules/ecdh/tests_impl.h"
#endif
@@ -7438,6 +7456,10 @@ int main(int argc, char **argv) {
/* EC key arithmetic test */
run_eckey_negate_test();
+#ifdef ENABLE_MODULE_BPPP
+ run_bppp_tests();
+#endif
+
#ifdef ENABLE_MODULE_ECDH
/* ecdh tests */
run_ecdh_tests();
diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c
index 6a4e2340f28..225bbddffc3 100644
--- a/src/tests_exhaustive.c
+++ b/src/tests_exhaustive.c
@@ -342,15 +342,15 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
}
#ifdef ENABLE_MODULE_RECOVERY
-#include "src/modules/recovery/tests_exhaustive_impl.h"
+#include "modules/recovery/tests_exhaustive_impl.h"
#endif
#ifdef ENABLE_MODULE_EXTRAKEYS
-#include "src/modules/extrakeys/tests_exhaustive_impl.h"
+#include "modules/extrakeys/tests_exhaustive_impl.h"
#endif
#ifdef ENABLE_MODULE_SCHNORRSIG
-#include "src/modules/schnorrsig/tests_exhaustive_impl.h"
+#include "modules/schnorrsig/tests_exhaustive_impl.h"
#endif
int main(int argc, char** argv) {
diff --git a/src/valgrind_ctime_test.c b/src/valgrind_ctime_test.c
index 4fe93ef8f4d..ee1801163fd 100644
--- a/src/valgrind_ctime_test.c
+++ b/src/valgrind_ctime_test.c
@@ -29,15 +29,15 @@
#endif
#ifdef ENABLE_MODULE_ECDSA_S2C
-#include "include/secp256k1_ecdsa_s2c.h"
+#include "../include/secp256k1_ecdsa_s2c.h"
#endif
#ifdef ENABLE_MODULE_ECDSA_ADAPTOR
-#include "include/secp256k1_ecdsa_adaptor.h"
+#include "../include/secp256k1_ecdsa_adaptor.h"
#endif
#ifdef ENABLE_MODULE_MUSIG
-#include "include/secp256k1_musig.h"
+#include "../include/secp256k1_musig.h"
#endif
void run_tests(secp256k1_context *ctx, unsigned char *key);
@@ -249,8 +249,8 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
#ifdef ENABLE_MODULE_MUSIG
{
- secp256k1_xonly_pubkey pk;
- const secp256k1_xonly_pubkey *pk_ptr[1];
+ secp256k1_pubkey pk;
+ const secp256k1_pubkey *pk_ptr[1];
secp256k1_xonly_pubkey agg_pk;
unsigned char session_id[32];
secp256k1_musig_secnonce secnonce;
@@ -279,14 +279,14 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
partial_sig_ptr[0] = &partial_sig;
CHECK(secp256k1_keypair_create(ctx, &keypair, key));
- CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
+ CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair));
CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, &cache, pk_ptr, 1));
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor));
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
VALGRIND_MAKE_MEM_UNDEFINED(session_id, sizeof(session_id));
VALGRIND_MAKE_MEM_UNDEFINED(extra_input, sizeof(extra_input));
VALGRIND_MAKE_MEM_UNDEFINED(sec_adaptor, sizeof(sec_adaptor));
- ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_id, key, msg, &cache, extra_input);
+ ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_id, key, &pk, msg, &cache, extra_input);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
CHECK(ret == 1);
CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1));