Skip to content

Commit

Permalink
Experimental: Add incremental half-aggregation for Schnorr signatures
Browse files Browse the repository at this point in the history
Co-authored-by: Benedikt <[email protected]>
  • Loading branch information
fjahr and b-wagn committed Nov 18, 2024
1 parent 8deef00 commit a32870b
Show file tree
Hide file tree
Showing 11 changed files with 741 additions and 32 deletions.
6 changes: 6 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ env:
RECOVERY: no
EXTRAKEYS: no
SCHNORRSIG: no
EXPERIMENTAL: no
SCHNORRSIG_HALFAGG: no
MUSIG: no
ELLSWIFT: no
### test options
Expand Down Expand Up @@ -70,6 +72,8 @@ task:
RECOVERY: yes
EXTRAKEYS: yes
SCHNORRSIG: yes
EXPERIMENTAL: yes
SCHNORRSIG_HALFAGG: yes
MUSIG: yes
ELLSWIFT: yes
matrix:
Expand All @@ -88,6 +92,8 @@ task:
RECOVERY: yes
EXTRAKEYS: yes
SCHNORRSIG: yes
EXPERIMENTAL: yes
SCHNORRSIG_HALFAGG: yes
MUSIG: yes
ELLSWIFT: yes
WRAPPER_CMD: 'valgrind --error-exitcode=42'
Expand Down
40 changes: 31 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ env:
SCHNORRSIG: 'no'
MUSIG: 'no'
ELLSWIFT: 'no'
SCHNORRSIG_HALFAGG: 'no'
### test options
SECP256K1_TEST_ITERS: 64
BENCH: 'yes'
Expand Down Expand Up @@ -73,14 +74,15 @@ jobs:
matrix:
configuration:
- env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' }
- env_vars: { WIDEMUL: 'int64', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
- env_vars: { WIDEMUL: 'int64', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- env_vars: { WIDEMUL: 'int128' }
- env_vars: { WIDEMUL: 'int128_struct', ELLSWIFT: 'yes' }
- env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
- env_vars: { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes' }
- env_vars: { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' }
- env_vars: { RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes' }
- env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', CPPFLAGS: '-DVERIFY' }

- env_vars: { RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes', CPPFLAGS: '-DVERIFY' }
- env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' }
- env_vars: { CPPFLAGS: '-DDETERMINISTIC' }
- env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' }
Expand Down Expand Up @@ -143,6 +145,8 @@ jobs:
RECOVERY: 'yes'
EXTRAKEYS: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
MUSIG: 'yes'
ELLSWIFT: 'yes'
CC: ${{ matrix.cc }}
Expand Down Expand Up @@ -189,6 +193,8 @@ jobs:
RECOVERY: 'yes'
EXTRAKEYS: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
MUSIG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'
Expand Down Expand Up @@ -242,6 +248,8 @@ jobs:
RECOVERY: 'yes'
EXTRAKEYS: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
MUSIG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'
Expand Down Expand Up @@ -289,6 +297,8 @@ jobs:
RECOVERY: 'yes'
EXTRAKEYS: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
MUSIG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'
Expand Down Expand Up @@ -346,6 +356,8 @@ jobs:
RECOVERY: 'yes'
EXTRAKEYS: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
MUSIG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'
Expand Down Expand Up @@ -400,6 +412,8 @@ jobs:
RECOVERY: 'yes'
EXTRAKEYS: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
MUSIG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'
Expand Down Expand Up @@ -453,6 +467,8 @@ jobs:
RECOVERY: 'yes'
EXTRAKEYS: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
MUSIG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'
Expand Down Expand Up @@ -519,6 +535,8 @@ jobs:
RECOVERY: 'yes'
EXTRAKEYS: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
MUSIG: 'yes'
ELLSWIFT: 'yes'
CC: 'clang'
Expand Down Expand Up @@ -567,6 +585,8 @@ jobs:
RECOVERY: 'yes'
EXTRAKEYS: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
MUSIG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'
Expand Down Expand Up @@ -686,13 +706,13 @@ jobs:
fail-fast: false
matrix:
env_vars:
- { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 }
- { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- BUILD: 'distcheck'

steps:
Expand Down Expand Up @@ -800,6 +820,8 @@ jobs:
RECOVERY: 'yes'
EXTRAKEYS: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
MUSIG: 'yes'
ELLSWIFT: 'yes'

Expand Down
4 changes: 4 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,7 @@ endif
if ENABLE_MODULE_ELLSWIFT
include src/modules/ellswift/Makefile.am.include
endif

if ENABLE_MODULE_SCHNORRSIG_HALFAGG
include src/modules/schnorrsig_halfagg/Makefile.am.include
endif
3 changes: 2 additions & 1 deletion ci/ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ print_environment() {
# does not rely on bash.
for var in WERROR_CFLAGS MAKEFLAGS BUILD \
ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
EXPERIMENTAL ECDH RECOVERY EXTRAKEYS MUSIG SCHNORRSIG ELLSWIFT \
EXPERIMENTAL ECDH RECOVERY SCHNORRSIG SCHNORRSIG_HALFAGG MUSIG ELLSWIFT \
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
EXAMPLES \
HOST WRAPPER_CMD \
Expand Down Expand Up @@ -79,6 +79,7 @@ esac
--enable-module-ellswift="$ELLSWIFT" \
--enable-module-extrakeys="$EXTRAKEYS" \
--enable-module-schnorrsig="$SCHNORRSIG" \
--enable-module-schnorrsig-halfagg="$SCHNORRSIG_HALFAGG" \
--enable-module-musig="$MUSIG" \
--enable-examples="$EXAMPLES" \
--enable-ctime-tests="$CTIMETESTS" \
Expand Down
58 changes: 36 additions & 22 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ AC_ARG_ENABLE(module_musig,
AS_HELP_STRING([--enable-module-musig],[enable MuSig2 module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_musig], [yes], [yes])])

AC_ARG_ENABLE(module_schnorrsig_halfagg,
AS_HELP_STRING([--enable-module-schnorrsig-halfagg],[enable schnorrsig half-aggregation module (experimental) [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig_halfagg], [no], [yes])])

AC_ARG_ENABLE(module_ellswift,
AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])])
Expand Down Expand Up @@ -398,6 +402,11 @@ SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"

# Processing must be done in a reverse topological sorting of the dependency graph
# (dependent module first).
if test x"$enable_module_schnorrsig_halfagg" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG_HALFAGG=1"
enable_module_schnorrsig=yes
fi

if test x"$enable_module_ellswift" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1"
fi
Expand Down Expand Up @@ -442,6 +451,9 @@ if test x"$enable_experimental" = x"no"; then
if test x"$set_asm" = x"arm32"; then
AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.])
fi
if test x"$enable_module_schnorrsig_halfagg" = x"yes"; then
AC_MSG_ERROR([Schnorrsig Half-Aggregation module is experimental. Use --enable-experimental to allow.])
fi
fi

###
Expand All @@ -461,6 +473,7 @@ AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG_HALFAGG], [test x"$enable_module_schnorrsig_halfagg" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
Expand All @@ -474,33 +487,34 @@ AC_OUTPUT

echo
echo "Build Options:"
echo " with external callbacks = $enable_external_default_callbacks"
echo " with benchmarks = $enable_benchmark"
echo " with tests = $enable_tests"
echo " with ctime tests = $enable_ctime_tests"
echo " with coverage = $enable_coverage"
echo " with examples = $enable_examples"
echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo " module extrakeys = $enable_module_extrakeys"
echo " module schnorrsig = $enable_module_schnorrsig"
echo " module musig = $enable_module_musig"
echo " module ellswift = $enable_module_ellswift"
echo " with external callbacks = $enable_external_default_callbacks"
echo " with benchmarks = $enable_benchmark"
echo " with tests = $enable_tests"
echo " with ctime tests = $enable_ctime_tests"
echo " with coverage = $enable_coverage"
echo " with examples = $enable_examples"
echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo " module extrakeys = $enable_module_extrakeys"
echo " module schnorrsig = $enable_module_schnorrsig"
echo " module schnorrsig-halfagg = $enable_module_schnorrsig_halfagg"
echo " module musig = $enable_module_musig"
echo " module ellswift = $enable_module_ellswift"
echo
echo " asm = $set_asm"
echo " ecmult window size = $set_ecmult_window"
echo " ecmult gen table size = $set_ecmult_gen_kb KiB"
echo " asm = $set_asm"
echo " ecmult window size = $set_ecmult_window"
echo " ecmult gen table size = $set_ecmult_gen_kb KiB"
# Hide test-only options unless they're used.
if test x"$set_widemul" != xauto; then
echo " wide multiplication = $set_widemul"
echo " wide multiplication = $set_widemul"
fi
echo
echo " valgrind = $enable_valgrind"
echo " CC = $CC"
echo " CPPFLAGS = $CPPFLAGS"
echo " SECP_CFLAGS = $SECP_CFLAGS"
echo " CFLAGS = $CFLAGS"
echo " LDFLAGS = $LDFLAGS"
echo " valgrind = $enable_valgrind"
echo " CC = $CC"
echo " CPPFLAGS = $CPPFLAGS"
echo " SECP_CFLAGS = $SECP_CFLAGS"
echo " CFLAGS = $CFLAGS"
echo " LDFLAGS = $LDFLAGS"

if test x"$print_msan_notice" = x"yes"; then
echo
Expand Down
107 changes: 107 additions & 0 deletions include/secp256k1_schnorrsig_halfagg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#ifndef SECP256K1_SCHNORRSIG_HALFAGG_H
#define SECP256K1_SCHNORRSIG_HALFAGG_H

#include "secp256k1.h"
#include "secp256k1_extrakeys.h"

#ifdef __cplusplus
extern "C" {
#endif


/** Incrementally (Half-)Aggregate a sequence of Schnorr
* signatures to an existing half-aggregate signature.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: a secp256k1 context object.
* In/Out: aggsig: pointer to the serialized aggregate signature
* that is input. The first 32*(n_before+1) of this
* array should hold the input aggsig. It will be
* overwritten by the new serialized aggregate signature.
* It should be large enough for that, see aggsig_len.
* aggsig_len: size of aggsig array in bytes.
* Should be large enough to hold the new
* serialized aggregate signature, i.e.,
* should satisfy aggsig_size >= 32*(n_before+n_new+1).
* It will be overwritten to be the exact size of the
* resulting aggsig.
* In: all_pubkeys: Array of (n_before + n_new) many x-only public keys,
* including both the ones for the already aggregated signature
* and the ones for the signatures that should be added.
* Can only be NULL if n_before + n_new is 0.
* all_msgs32: Array of (n_before + n_new) many 32-byte messages,
* including both the ones for the already aggregated signature
* and the ones for the signatures that should be added.
* Can only be NULL if n_before + n_new is 0.
* new_sigs64: Array of n_new many 64-byte signatures, containing the new
* signatures that should be added. Can only be NULL if n_new is 0.
* n_before: Number of signatures that have already been aggregated
* in the input aggregate signature.
* n_new: Number of signatures that should now be added
* to the aggregate signature.
*/
SECP256K1_API int secp256k1_schnorrsig_inc_aggregate(
const secp256k1_context *ctx,
unsigned char *aggsig,
size_t *aggsig_len,
const secp256k1_xonly_pubkey* all_pubkeys,
const unsigned char *all_msgs32,
const unsigned char *new_sigs64,
size_t n_before,
size_t n_new
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

/** (Half-)Aggregate a sequence of Schnorr signatures.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: a secp256k1 context object.
* Out: aggsig: pointer to an array of aggsig_len many bytes to
* store the serialized aggregate signature.
* In/Out: aggsig_len: size of the aggsig array that is passed in bytes;
* will be overwritten to be the exact size of aggsig.
* In: pubkeys: Array of n many x-only public keys.
* Can only be NULL if n is 0.
* msgs32: Array of n many 32-byte messages.
* Can only be NULL if n is 0.
* sigs64: Array of n many 64-byte signatures.
* Can only be NULL if n is 0.
* n: number of signatures to be aggregated.
*/
SECP256K1_API int secp256k1_schnorrsig_aggregate(
const secp256k1_context *ctx,
unsigned char *aggsig,
size_t *aggsig_len,
const secp256k1_xonly_pubkey *pubkeys,
const unsigned char *msgs32,
const unsigned char *sigs64,
size_t n
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

/** Verify a (Half-)aggregate Schnorr signature.
*
* Returns: 1: correct signature.
* 0: incorrect signature.
* Args: ctx: a secp256k1 context object.
* In: pubkeys: Array of n many x-only public keys. Can only be NULL if n is 0.
* msgs32: Array of n many 32-byte messages. Can only be NULL if n is 0.
* n: number of signatures to that have been aggregated.
* aggsig: Pointer to an array of aggsig_size many bytes
* containing the serialized aggregate
* signature to be verified.
* aggsig_len: Size of the aggregate signature in bytes.
* Should be aggsig_len = 32*(n+1)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_aggverify(
const secp256k1_context *ctx,
const secp256k1_xonly_pubkey *pubkeys,
const unsigned char *msgs32,
size_t n,
const unsigned char *aggsig,
size_t aggsig_len
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5);

#ifdef __cplusplus
}
#endif

#endif /* SECP256K1_SCHNORRSIG_HALFAGG_H */
3 changes: 3 additions & 0 deletions src/modules/schnorrsig_halfagg/Makefile.am.include
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_HEADERS += include/secp256k1_schnorrsig_halfagg.h
noinst_HEADERS += src/modules/schnorrsig_halfagg/main_impl.h
noinst_HEADERS += src/modules/schnorrsig_halfagg/tests_impl.h
Loading

0 comments on commit a32870b

Please sign in to comment.