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 Jul 2, 2024
1 parent a526937 commit 747a01a
Show file tree
Hide file tree
Showing 10 changed files with 733 additions and 31 deletions.
39 changes: 30 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ env:
RECOVERY: 'no'
SCHNORRSIG: 'no'
ELLSWIFT: 'no'
SCHNORRSIG_HALFAGG: 'no'
### test options
SECP256K1_TEST_ITERS:
BENCH: 'yes'
Expand Down Expand Up @@ -71,14 +72,14 @@ jobs:
matrix:
configuration:
- env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' }
- env_vars: { WIDEMUL: 'int64', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- env_vars: { WIDEMUL: 'int64', ECDH: 'yes', SCHNORRSIG: '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', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- env_vars: { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes' }
- env_vars: { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' }
- env_vars: { RECOVERY: 'yes', SCHNORRSIG: 'yes' }
- env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', CPPFLAGS: '-DVERIFY' }
- env_vars: { RECOVERY: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: '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 @@ -140,6 +141,8 @@ jobs:
ECDH: 'yes'
RECOVERY: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
ELLSWIFT: 'yes'
CC: ${{ matrix.cc }}

Expand Down Expand Up @@ -184,6 +187,8 @@ jobs:
ECDH: 'yes'
RECOVERY: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'

Expand Down Expand Up @@ -235,6 +240,8 @@ jobs:
ECDH: 'yes'
RECOVERY: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'

Expand Down Expand Up @@ -280,6 +287,8 @@ jobs:
ECDH: 'yes'
RECOVERY: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'

Expand Down Expand Up @@ -335,6 +344,8 @@ jobs:
ECDH: 'yes'
RECOVERY: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'

Expand Down Expand Up @@ -387,6 +398,8 @@ jobs:
ECDH: 'yes'
RECOVERY: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'
SECP256K1_TEST_ITERS: 2
Expand Down Expand Up @@ -438,6 +451,8 @@ jobs:
ECDH: 'yes'
RECOVERY: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'
CFLAGS: '-fsanitize=undefined,address -g'
Expand Down Expand Up @@ -502,6 +517,8 @@ jobs:
ECDH: 'yes'
RECOVERY: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
ELLSWIFT: 'yes'
CC: 'clang'
SECP256K1_TEST_ITERS: 32
Expand Down Expand Up @@ -548,6 +565,8 @@ jobs:
ECDH: 'yes'
RECOVERY: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
ELLSWIFT: 'yes'
CTIMETESTS: 'no'

Expand Down Expand Up @@ -666,13 +685,13 @@ jobs:
fail-fast: false
matrix:
env_vars:
- { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 }
- { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY', EXPERIMENTAL: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- BUILD: 'distcheck'

steps:
Expand Down Expand Up @@ -779,6 +798,8 @@ jobs:
ECDH: 'yes'
RECOVERY: 'yes'
SCHNORRSIG: 'yes'
EXPERIMENTAL: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
ELLSWIFT: 'yes'

steps:
Expand Down
4 changes: 4 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,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 SCHNORRSIG ELLSWIFT \
EXPERIMENTAL ECDH RECOVERY SCHNORRSIG SCHNORRSIG_HALFAGG ELLSWIFT \
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
EXAMPLES \
HOST WRAPPER_CMD \
Expand Down Expand Up @@ -78,6 +78,7 @@ esac
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
--enable-module-ellswift="$ELLSWIFT" \
--enable-module-schnorrsig="$SCHNORRSIG" \
--enable-module-schnorrsig-halfagg="$SCHNORRSIG_HALFAGG" \
--enable-examples="$EXAMPLES" \
--enable-ctime-tests="$CTIMETESTS" \
--with-valgrind="$WITH_VALGRIND" \
Expand Down
56 changes: 35 additions & 21 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ AC_ARG_ENABLE(module_schnorrsig,
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig], [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 @@ -394,6 +398,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 @@ -430,6 +439,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 @@ -449,6 +461,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_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"])
Expand All @@ -461,32 +474,33 @@ 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 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 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 747a01a

Please sign in to comment.