Merge #103: Merge upstream schnorrsig PR
96b9236c425125f348c15b6629b3a73c8a3062f5 re-enable musig module (Andrew Poelstra) 23900a0d86730f719c52aebba41a1c1cdb9288bd Fix the MuSig module after integrating bip-schnorr updates (Jonas Nick) f431b3f28ac95a3645ad5a6dc96b878fa30a1de3 valgrind_ctime_test: Add schnorrsig_sign (Jonas Nick) 16ffa9d97cef93f49544b016339c107882f9a1c3 schnorrsig: Add taproot test case (Jonas Nick) 8dfd53ee3fa059562483d1867815f78b9e00d947 schnorrsig: Add benchmark for sign and verify (Jonas Nick) 4e43520026f5bcd182d21f0759bac159ef47bb62 schnorrsig: Add BIP-340 compatible signing and verification (Jonas Nick) 7332d2db6b62fda851f9ed8adbfda187a875b84e schnorrsig: Add BIP-340 nonce function (Jonas Nick) 7a703fd97db0161bae07ef84513ddde6e0d27353 schnorrsig: Init empty experimental module (Jonas Nick) eabd9bc46a31c0da6db6d88840eadbe9006447b1 Allow initializing tagged sha256 (Jonas Nick) 6fcb5b845d2832ce019d60507033f74426290768 extrakeys: Add keypair_xonly_tweak_add (Jonas Nick) 58254463f9a2e96d893157a341c9953c440fdf60 extrakeys: Add keypair struct with create, pub and pub_xonly (Jonas Nick) f0010349b876bc6b3f0a6ec6c8bad0b12ca17b51 Separate helper functions for pubkey_create and seckey_tweak_add (Jonas Nick) 910d9c284c33b77774a9316d4524f313357d441c extrakeys: Add xonly_pubkey_tweak_add & xonly_pubkey_tweak_add_test (Jonas Nick) 176bfb1110147b5dca1834ea071acc846fb1cab3 Separate helper function for ec_pubkey_tweak_add (Jonas Nick) 4cd2ee474d178bd1b5602486104db346a7562c67 extrakeys: Add xonly_pubkey with serialize, parse and from_pubkey (Jonas Nick) 47e6618e11813cfabe91f0909ca031f960cb7dd4 extrakeys: Init empty experimental module (Jonas Nick) 3e08b02e2a78f2a1fc457efab665db8ab8085373 Make the secp256k1_declassify argument constant (Jonas Nick) a11250330b24b3dffdf11d2de5d496397b4e4410 (actually) remove schnorrsig module (Andrew Poelstra) bac746c55e72abc1cc1ba1e8e6fabb2fea503cfe (temporarily) disable musig module (Andrew Poelstra) Pull request description: ACKs for top commit: jonasnick: ACK 96b9236c425125f348c15b6629b3a73c8a3062f5 Tree-SHA512: 6801f3b64a0f9b7ac39dec25c2f35793d66483b1e07678521ca82df1b978303d4b3c4693b8d34b2148840b551a4bc530a4e0e726848a6f8fb87bec3eca03d5e6
This commit is contained in:
commit
81052ca411
@ -22,10 +22,10 @@ env:
|
||||
- WIDEMUL=int64 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
|
||||
- WIDEMUL=int128 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
|
||||
- WIDEMUL=int64 RECOVERY=yes
|
||||
- WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes
|
||||
- WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes
|
||||
- WIDEMUL=int64 ENDOMORPHISM=yes
|
||||
- WIDEMUL=int128
|
||||
- WIDEMUL=int128 RECOVERY=yes
|
||||
- WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes
|
||||
- WIDEMUL=int128 ENDOMORPHISM=yes
|
||||
- WIDEMUL=int128 ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
|
||||
- WIDEMUL=int128 ASM=x86_64
|
||||
|
12
Makefile.am
12
Makefile.am
@ -151,10 +151,6 @@ if ENABLE_MODULE_ECDH
|
||||
include src/modules/ecdh/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_SCHNORRSIG
|
||||
include src/modules/schnorrsig/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_MUSIG
|
||||
include src/modules/musig/Makefile.am.include
|
||||
endif
|
||||
@ -178,3 +174,11 @@ endif
|
||||
if ENABLE_MODULE_SURJECTIONPROOF
|
||||
include src/modules/surjection/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_EXTRAKEYS
|
||||
include src/modules/extrakeys/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_SCHNORRSIG
|
||||
include src/modules/schnorrsig/Makefile.am.include
|
||||
endif
|
||||
|
46
configure.ac
46
configure.ac
@ -131,11 +131,6 @@ AC_ARG_ENABLE(module_ecdh,
|
||||
[enable_module_ecdh=$enableval],
|
||||
[enable_module_ecdh=no])
|
||||
|
||||
AC_ARG_ENABLE(module_schnorrsig,
|
||||
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]),
|
||||
[enable_module_schnorrsig=$enableval],
|
||||
[enable_module_schnorrsig=no])
|
||||
|
||||
AC_ARG_ENABLE(module_musig,
|
||||
AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]),
|
||||
[enable_module_musig=$enableval],
|
||||
@ -161,6 +156,16 @@ AC_ARG_ENABLE(module_whitelist,
|
||||
[enable_module_whitelist=$enableval],
|
||||
[enable_module_whitelist=no])
|
||||
|
||||
AC_ARG_ENABLE(module_extrakeys,
|
||||
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module (experimental)]),
|
||||
[enable_module_extrakeys=$enableval],
|
||||
[enable_module_extrakeys=no])
|
||||
|
||||
AC_ARG_ENABLE(module_schnorrsig,
|
||||
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]),
|
||||
[enable_module_schnorrsig=$enableval],
|
||||
[enable_module_schnorrsig=no])
|
||||
|
||||
AC_ARG_ENABLE(external_default_callbacks,
|
||||
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]),
|
||||
[use_external_default_callbacks=$enableval],
|
||||
@ -464,10 +469,6 @@ if test x"$enable_module_ecdh" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_schnorrsig" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_musig" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_MUSIG, 1, [Define this symbol to enable the MuSig module])
|
||||
fi
|
||||
@ -492,6 +493,17 @@ if test x"$enable_module_surjectionproof" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_SURJECTIONPROOF, 1, [Define this symbol to enable the surjection proof module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_schnorrsig" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module])
|
||||
enable_module_extrakeys=yes
|
||||
fi
|
||||
|
||||
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
|
||||
# module to set enable_module_extrakeys=yes
|
||||
if test x"$enable_module_extrakeys" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module])
|
||||
fi
|
||||
|
||||
if test x"$use_external_asm" = x"yes"; then
|
||||
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
|
||||
fi
|
||||
@ -513,8 +525,9 @@ if test x"$enable_experimental" = x"yes"; then
|
||||
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 schnorrsig module: $enable_module_schnorrsig])
|
||||
AC_MSG_NOTICE([Building MuSig module: $enable_module_musig])
|
||||
AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys])
|
||||
AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig])
|
||||
AC_MSG_NOTICE([******])
|
||||
|
||||
|
||||
@ -542,12 +555,15 @@ else
|
||||
if test x"$enable_module_ecdh" = x"yes"; then
|
||||
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_schnorrsig" = x"yes"; then
|
||||
AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_musig" = x"yes"; then
|
||||
AC_MSG_ERROR([MuSig module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_extrakeys" = x"yes"; then
|
||||
AC_MSG_ERROR([extrakeys module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_schnorrsig" = x"yes"; then
|
||||
AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$set_asm" = x"arm"; then
|
||||
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
@ -577,12 +593,13 @@ AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
|
||||
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
|
||||
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_GENERATOR], [test x"$enable_module_generator" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
|
||||
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
|
||||
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"])
|
||||
@ -604,6 +621,7 @@ echo " with benchmarks = $use_benchmark"
|
||||
echo " with coverage = $enable_coverage"
|
||||
echo " module ecdh = $enable_module_ecdh"
|
||||
echo " module recovery = $enable_module_recovery"
|
||||
echo " module extrakeys = $enable_module_extrakeys"
|
||||
echo " module schnorrsig = $enable_module_schnorrsig"
|
||||
echo
|
||||
echo " asm = $set_asm"
|
||||
|
@ -525,12 +525,6 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize(
|
||||
*/
|
||||
SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
|
||||
|
||||
/** An implementation of the nonce generation function as defined in BIP-schnorr.
|
||||
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
|
||||
* extra entropy.
|
||||
*/
|
||||
SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_bipschnorr;
|
||||
|
||||
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
|
||||
SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default;
|
||||
|
||||
|
236
include/secp256k1_extrakeys.h
Normal file
236
include/secp256k1_extrakeys.h
Normal file
@ -0,0 +1,236 @@
|
||||
#ifndef SECP256K1_EXTRAKEYS_H
|
||||
#define SECP256K1_EXTRAKEYS_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Opaque data structure that holds a parsed and valid "x-only" public key.
|
||||
* An x-only pubkey encodes a point whose Y coordinate is even. It is
|
||||
* serialized using only its X coordinate (32 bytes). See BIP-340 for more
|
||||
* information about x-only pubkeys.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage, transmission, or
|
||||
* comparison, use secp256k1_xonly_pubkey_serialize and
|
||||
* secp256k1_xonly_pubkey_parse.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} secp256k1_xonly_pubkey;
|
||||
|
||||
/** Opaque data structure that holds a keypair consisting of a secret and a
|
||||
* public key.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 96 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[96];
|
||||
} secp256k1_keypair;
|
||||
|
||||
/** Parse a 32-byte sequence into a xonly_pubkey object.
|
||||
*
|
||||
* Returns: 1 if the public key was fully valid.
|
||||
* 0 if the public key could not be parsed or is invalid.
|
||||
*
|
||||
* Args: ctx: a secp256k1 context object (cannot be NULL).
|
||||
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
|
||||
* parsed version of input. If not, it's set to an invalid value.
|
||||
* (cannot be NULL).
|
||||
* In: input32: pointer to a serialized xonly_pubkey (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_xonly_pubkey* pubkey,
|
||||
const unsigned char *input32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize an xonly_pubkey object into a 32-byte sequence.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
*
|
||||
* Args: ctx: a secp256k1 context object (cannot be NULL).
|
||||
* Out: output32: a pointer to a 32-byte array to place the serialized key in
|
||||
* (cannot be NULL).
|
||||
* In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an
|
||||
* initialized public key (cannot be NULL).
|
||||
*/
|
||||
SECP256K1_API int secp256k1_xonly_pubkey_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output32,
|
||||
const secp256k1_xonly_pubkey* pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
|
||||
*
|
||||
* Returns: 1 if the public key was successfully converted
|
||||
* 0 otherwise
|
||||
*
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* Out: xonly_pubkey: pointer to an x-only public key object for placing the
|
||||
* converted public key (cannot be NULL)
|
||||
* pk_parity: pointer to an integer that will be set to 1 if the point
|
||||
* encoded by xonly_pubkey is the negation of the pubkey and
|
||||
* set to 0 otherwise. (can be NULL)
|
||||
* In: pubkey: pointer to a public key that is converted (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_xonly_pubkey *xonly_pubkey,
|
||||
int *pk_parity,
|
||||
const secp256k1_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Tweak an x-only public key by adding the generator multiplied with tweak32
|
||||
* to it.
|
||||
*
|
||||
* Note that the resulting point can not in general be represented by an x-only
|
||||
* pubkey because it may have an odd Y coordinate. Instead, the output_pubkey
|
||||
* is a normal secp256k1_pubkey.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting public key would be
|
||||
* invalid (only when the tweak is the negation of the corresponding
|
||||
* secret key). 1 otherwise.
|
||||
*
|
||||
* Args: ctx: pointer to a context object initialized for verification
|
||||
* (cannot be NULL)
|
||||
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
||||
* to an invalid value if this function returns 0 (cannot
|
||||
* be NULL)
|
||||
* In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to.
|
||||
* (cannot be NULL).
|
||||
* tweak32: pointer to a 32-byte tweak. If the tweak is invalid
|
||||
* according to secp256k1_ec_seckey_verify, this function
|
||||
* returns 0. For uniformly random 32-byte arrays the
|
||||
* chance of being invalid is negligible (around 1 in
|
||||
* 2^128) (cannot be NULL).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *output_pubkey,
|
||||
const secp256k1_xonly_pubkey *internal_pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Checks that a tweaked pubkey is the result of calling
|
||||
* secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32.
|
||||
*
|
||||
* The tweaked pubkey is represented by its 32-byte x-only serialization and
|
||||
* its pk_parity, which can both be obtained by converting the result of
|
||||
* tweak_add to a secp256k1_xonly_pubkey.
|
||||
*
|
||||
* Note that this alone does _not_ verify that the tweaked pubkey is a
|
||||
* commitment. If the tweak is not chosen in a specific way, the tweaked pubkey
|
||||
* can easily be the result of a different internal_pubkey and tweak.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the tweaked pubkey is not the
|
||||
* result of tweaking the internal_pubkey with tweak32. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object initialized for verification
|
||||
* (cannot be NULL)
|
||||
* In: tweaked_pubkey32: pointer to a serialized xonly_pubkey (cannot be NULL)
|
||||
* tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization
|
||||
* is passed in as tweaked_pubkey32). This must match the
|
||||
* pk_parity value that is returned when calling
|
||||
* secp256k1_xonly_pubkey with the tweaked pubkey, or
|
||||
* this function will fail.
|
||||
* internal_pubkey: pointer to an x-only public key object to apply the
|
||||
* tweak to (cannot be NULL)
|
||||
* tweak32: pointer to a 32-byte tweak (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check(
|
||||
const secp256k1_context* ctx,
|
||||
const unsigned char *tweaked_pubkey32,
|
||||
int tweaked_pk_parity,
|
||||
const secp256k1_xonly_pubkey *internal_pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Compute the keypair for a secret key.
|
||||
*
|
||||
* Returns: 1: secret was valid, keypair is ready to use
|
||||
* 0: secret was invalid, try again with a different secret
|
||||
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||
* Out: keypair: pointer to the created keypair (cannot be NULL)
|
||||
* In: seckey: pointer to a 32-byte secret key (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_keypair *keypair,
|
||||
const unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Get the public key from a keypair.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to
|
||||
* the keypair public key. If not, it's set to an invalid value.
|
||||
* (cannot be NULL)
|
||||
* In: keypair: pointer to a keypair (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const secp256k1_keypair *keypair
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Get the x-only public key from a keypair.
|
||||
*
|
||||
* This is the same as calling secp256k1_keypair_pub and then
|
||||
* secp256k1_xonly_pubkey_from_pubkey.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set
|
||||
* to the keypair public key after converting it to an
|
||||
* xonly_pubkey. If not, it's set to an invalid value (cannot be
|
||||
* NULL).
|
||||
* pk_parity: pointer to an integer that will be set to the pk_parity
|
||||
* argument of secp256k1_xonly_pubkey_from_pubkey (can be NULL).
|
||||
* In: keypair: pointer to a keypair (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_xonly_pubkey *pubkey,
|
||||
int *pk_parity,
|
||||
const secp256k1_keypair *keypair
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Tweak a keypair by adding tweak32 to the secret key and updating the public
|
||||
* key accordingly.
|
||||
*
|
||||
* Calling this function and then secp256k1_keypair_pub results in the same
|
||||
* public key as calling secp256k1_keypair_xonly_pub and then
|
||||
* secp256k1_xonly_pubkey_tweak_add.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting keypair would be
|
||||
* invalid (only when the tweak is the negation of the keypair's
|
||||
* secret key). 1 otherwise.
|
||||
*
|
||||
* Args: ctx: pointer to a context object initialized for verification
|
||||
* (cannot be NULL)
|
||||
* In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to
|
||||
* an invalid value if this function returns 0 (cannot be
|
||||
* NULL).
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according
|
||||
* to secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128) (cannot be NULL).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_keypair *keypair,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_EXTRAKEYS_H */
|
@ -1,6 +1,8 @@
|
||||
#ifndef SECP256K1_MUSIG_H
|
||||
#define SECP256K1_MUSIG_H
|
||||
|
||||
#include "secp256k1_extrakeys.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -8,15 +10,30 @@ extern "C" {
|
||||
#include <stdint.h>
|
||||
|
||||
/** This module implements a Schnorr-based multi-signature scheme called MuSig
|
||||
* (https://eprint.iacr.org/2018/068.pdf). There's an example C source file in the
|
||||
* module's directory (src/modules/musig/example.c) that demonstrates how it can be
|
||||
* used.
|
||||
* (https://eprint.iacr.org/2018/068.pdf). It is compatible with bip-schnorr.
|
||||
* There's an example C source file in the module's directory
|
||||
* (src/modules/musig/example.c) that demonstrates how it can be used.
|
||||
*
|
||||
* The documentation in this include file is for reference and may not be sufficient
|
||||
* for users to begin using the library. A full description of API usage can be found
|
||||
* in src/modules/musig/musig.md
|
||||
*/
|
||||
|
||||
/** Data structure containing auxiliary data generated in `pubkey_combine` and
|
||||
* required for `session_*_initialize`.
|
||||
* Fields:
|
||||
* magic: Set during initialization in `pubkey_combine` in order to allow
|
||||
* detecting an uninitialized object.
|
||||
* pk_hash: The 32-byte hash of the original public keys
|
||||
* is_negated: Whether the MuSig-aggregated point was negated when
|
||||
* converting it to the combined xonly pubkey.
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t magic;
|
||||
unsigned char pk_hash[32];
|
||||
int is_negated;
|
||||
} secp256k1_musig_pre_session;
|
||||
|
||||
/** Data structure containing data related to a signing session resulting in a single
|
||||
* signature.
|
||||
*
|
||||
@ -28,14 +45,14 @@ extern "C" {
|
||||
* structure.
|
||||
*
|
||||
* Fields:
|
||||
* combined_pk: MuSig-computed combined public key
|
||||
* combined_pk: MuSig-computed combined xonly public key
|
||||
* pre_session: Auxiliary data created in `pubkey_combine`
|
||||
* n_signers: Number of signers
|
||||
* pk_hash: The 32-byte hash of the original public keys
|
||||
* combined_nonce: Summed combined public nonce (undefined if `nonce_is_set` is false)
|
||||
* nonce_is_set: Whether the above nonce has been set
|
||||
* nonce_is_negated: If `nonce_is_set`, whether the above nonce was negated after
|
||||
* summing the participants' nonces. Needed to ensure the nonce's y
|
||||
* coordinate has a quadratic-residue y coordinate
|
||||
* coordinate is even.
|
||||
* msg: The 32-byte message (hash) to be signed
|
||||
* msg_is_set: Whether the above message has been set
|
||||
* has_secret_data: Whether this session object has a signers' secret data; if this
|
||||
@ -49,9 +66,9 @@ extern "C" {
|
||||
* nonce_commitments_hash has been set
|
||||
*/
|
||||
typedef struct {
|
||||
secp256k1_pubkey combined_pk;
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
secp256k1_musig_pre_session pre_session;
|
||||
uint32_t n_signers;
|
||||
unsigned char pk_hash[32];
|
||||
secp256k1_pubkey combined_nonce;
|
||||
int nonce_is_set;
|
||||
int nonce_is_negated;
|
||||
@ -119,9 +136,9 @@ typedef struct {
|
||||
* (cannot be NULL)
|
||||
* scratch: scratch space used to compute the combined pubkey by
|
||||
* multiexponentiation. If NULL, an inefficient algorithm is used.
|
||||
* Out: combined_pk: the MuSig-combined public key (cannot be NULL)
|
||||
* pk_hash32: if non-NULL, filled with the 32-byte hash of all input public
|
||||
* keys in order to be used in `musig_session_initialize`.
|
||||
* Out: combined_pk: the MuSig-combined xonly public key (cannot be NULL)
|
||||
* pre_session: if non-NULL, pointer to a musig_pre_session struct to be used in
|
||||
* `musig_session_initialize`.
|
||||
* In: pubkeys: input array of public keys to combine. The order is important;
|
||||
* a different order will result in a different combined public
|
||||
* key (cannot be NULL)
|
||||
@ -130,9 +147,9 @@ typedef struct {
|
||||
SECP256K1_API int secp256k1_musig_pubkey_combine(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_scratch_space *scratch,
|
||||
secp256k1_pubkey *combined_pk,
|
||||
unsigned char *pk_hash32,
|
||||
const secp256k1_pubkey *pubkeys,
|
||||
secp256k1_xonly_pubkey *combined_pk,
|
||||
secp256k1_musig_pre_session *pre_session,
|
||||
const secp256k1_xonly_pubkey *pubkeys,
|
||||
size_t n_pubkeys
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
@ -154,9 +171,9 @@ SECP256K1_API int secp256k1_musig_pubkey_combine(
|
||||
* require sharing nonce commitments before the message is known
|
||||
* because it reduces nonce misuse resistance. If NULL, must be
|
||||
* set with `musig_session_get_public_nonce`.
|
||||
* combined_pk: the combined public key of all signers (cannot be NULL)
|
||||
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be
|
||||
* NULL)
|
||||
* combined_pk: the combined xonly public key of all signers (cannot be NULL)
|
||||
* pre_session: pointer to a musig_pre_session struct from
|
||||
* `musig_pubkey_combine` (cannot be NULL)
|
||||
* n_signers: length of signers array. Number of signers participating in
|
||||
* the MuSig. Must be greater than 0 and at most 2^32 - 1.
|
||||
* my_index: index of this signer in the signers array
|
||||
@ -169,8 +186,8 @@ SECP256K1_API int secp256k1_musig_session_initialize(
|
||||
unsigned char *nonce_commitment32,
|
||||
const unsigned char *session_id32,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_pubkey *combined_pk,
|
||||
const unsigned char *pk_hash32,
|
||||
const secp256k1_xonly_pubkey *combined_pk,
|
||||
const secp256k1_musig_pre_session *pre_session,
|
||||
size_t n_signers,
|
||||
size_t my_index,
|
||||
const unsigned char *seckey
|
||||
@ -213,7 +230,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_publi
|
||||
* signers: an array of signers' data to be initialized. Array length must
|
||||
* equal to `n_signers`(cannot be NULL)
|
||||
* In: msg32: the 32-byte message to be signed (cannot be NULL)
|
||||
* combined_pk: the combined public key of all signers (cannot be NULL)
|
||||
* combined_pk: the combined xonly public key of all signers (cannot be NULL)
|
||||
* pre_session: pointer to a musig_pre_session struct from
|
||||
* `musig_pubkey_combine` (cannot be NULL)
|
||||
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be NULL)
|
||||
* commitments: array of 32-byte nonce commitments. Array length must equal to
|
||||
* `n_signers` (cannot be NULL)
|
||||
@ -226,8 +245,8 @@ SECP256K1_API int secp256k1_musig_session_initialize_verifier(
|
||||
secp256k1_musig_session *session,
|
||||
secp256k1_musig_session_signer_data *signers,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_pubkey *combined_pk,
|
||||
const unsigned char *pk_hash32,
|
||||
const secp256k1_xonly_pubkey *combined_pk,
|
||||
const secp256k1_musig_pre_session *pre_session,
|
||||
const unsigned char *const *commitments,
|
||||
size_t n_signers
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
|
||||
@ -343,7 +362,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif
|
||||
const secp256k1_musig_session *session,
|
||||
const secp256k1_musig_session_signer_data *signer,
|
||||
const secp256k1_musig_partial_signature *partial_sig,
|
||||
const secp256k1_pubkey *pubkey
|
||||
const secp256k1_xonly_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Combines partial signatures
|
||||
@ -354,23 +373,16 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* session: initialized session for which the combined nonce has been
|
||||
* computed (cannot be NULL)
|
||||
* Out: sig: complete signature (cannot be NULL)
|
||||
* Out: sig64: complete signature (cannot be NULL)
|
||||
* In: partial_sigs: array of partial signatures to combine (cannot be NULL)
|
||||
* n_sigs: number of signatures in the partial_sigs array
|
||||
* tweak32: if `combined_pk` was tweaked with `ec_pubkey_tweak_add` after
|
||||
* `musig_pubkey_combine` and before `musig_session_initialize` then
|
||||
* the same tweak must be provided here in order to get a valid
|
||||
* signature for the tweaked key. Otherwise `tweak` should be NULL.
|
||||
* If the tweak is larger than the group order or 0 this function will
|
||||
* return 0. (can be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combine(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_musig_session *session,
|
||||
secp256k1_schnorrsig *sig,
|
||||
unsigned char *sig64,
|
||||
const secp256k1_musig_partial_signature *partial_sigs,
|
||||
size_t n_sigs,
|
||||
const unsigned char *tweak32
|
||||
size_t n_sigs
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Converts a partial signature to an adaptor signature by adding a given secret
|
||||
@ -403,7 +415,7 @@ SECP256K1_API int secp256k1_musig_partial_sig_adapt(
|
||||
* 0: otherwise
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* Out:sec_adaptor32: 32-byte secret adaptor (cannot be NULL)
|
||||
* In: sig: complete 2-of-2 signature (cannot be NULL)
|
||||
* In: sig64: complete 2-of-2 signature (cannot be NULL)
|
||||
* partial_sigs: array of partial signatures (cannot be NULL)
|
||||
* n_partial_sigs: number of elements in partial_sigs array
|
||||
* nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces`
|
||||
@ -411,7 +423,7 @@ SECP256K1_API int secp256k1_musig_partial_sig_adapt(
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_adaptor(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *sec_adaptor32,
|
||||
const secp256k1_schnorrsig *sig,
|
||||
const unsigned char *sig64,
|
||||
const secp256k1_musig_partial_signature *partial_sigs,
|
||||
size_t n_partial_sigs,
|
||||
int nonce_is_negated
|
||||
|
@ -2,126 +2,108 @@
|
||||
#define SECP256K1_SCHNORRSIG_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
#include "secp256k1_extrakeys.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** This module implements a variant of Schnorr signatures compliant with
|
||||
* BIP-schnorr
|
||||
* (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki).
|
||||
* Bitcoin Improvement Proposal 340 "Schnorr Signatures for secp256k1"
|
||||
* (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||
*/
|
||||
|
||||
/** Opaque data structure that holds a parsed Schnorr signature.
|
||||
/** A pointer to a function to deterministically generate a nonce.
|
||||
*
|
||||
* 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 the `secp256k1_schnorrsig_serialize` and
|
||||
* `secp256k1_schnorrsig_parse` functions.
|
||||
* Same as secp256k1_nonce function with the exception of accepting an
|
||||
* additional pubkey argument and not requiring an attempt argument. The pubkey
|
||||
* argument can protect signature schemes with key-prefixed challenge hash
|
||||
* inputs against reusing the nonce when signing with the wrong precomputed
|
||||
* pubkey.
|
||||
*
|
||||
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to
|
||||
* return an error.
|
||||
* Out: nonce32: pointer to a 32-byte array to be filled by the function.
|
||||
* In: msg32: the 32-byte message hash being verified (will not be NULL)
|
||||
* key32: pointer to a 32-byte secret key (will not be NULL)
|
||||
* xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32
|
||||
* (will not be NULL)
|
||||
* algo16: pointer to a 16-byte array describing the signature
|
||||
* algorithm (will not be NULL).
|
||||
* data: Arbitrary data pointer that is passed through.
|
||||
*
|
||||
* Except for test cases, this function should compute some cryptographic hash of
|
||||
* the message, the key, the pubkey, the algorithm description, and data.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} secp256k1_schnorrsig;
|
||||
typedef int (*secp256k1_nonce_function_hardened)(
|
||||
unsigned char *nonce32,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *key32,
|
||||
const unsigned char *xonly_pk32,
|
||||
const unsigned char *algo16,
|
||||
void *data
|
||||
);
|
||||
|
||||
/** Serialize a Schnorr signature.
|
||||
/** An implementation of the nonce generation function as defined in Bitcoin
|
||||
* Improvement Proposal 340 "Schnorr Signatures for secp256k1"
|
||||
* (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||
*
|
||||
* Returns: 1
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: out64: pointer to a 64-byte array to store the serialized signature
|
||||
* In: sig: pointer to the signature
|
||||
*
|
||||
* See secp256k1_schnorrsig_parse for details about the encoding.
|
||||
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
|
||||
* auxiliary random data as defined in BIP-340. If the data pointer is NULL,
|
||||
* schnorrsig_sign does not produce BIP-340 compliant signatures. The algo16
|
||||
* argument must be non-NULL, otherwise the function will fail and return 0.
|
||||
* The hash will be tagged with algo16 after removing all terminating null
|
||||
* bytes. Therefore, to create BIP-340 compliant signatures, algo16 must be set
|
||||
* to "BIP0340/nonce\0\0\0"
|
||||
*/
|
||||
SECP256K1_API int secp256k1_schnorrsig_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *out64,
|
||||
const secp256k1_schnorrsig* sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Parse a Schnorr signature.
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: sig: pointer to a signature object
|
||||
* In: in64: pointer to the 64-byte signature to be parsed
|
||||
*
|
||||
* The signature is serialized in the form R||s, where R is a 32-byte public
|
||||
* key (x-coordinate only; the y-coordinate is considered to be the unique
|
||||
* y-coordinate satisfying the curve equation that is a quadratic residue)
|
||||
* and s is a 32-byte big-endian scalar.
|
||||
*
|
||||
* After the call, sig will always be initialized. If parsing failed or the
|
||||
* encoded numbers are out of range, signature validation with it is
|
||||
* guaranteed to fail for every message and public key.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_schnorrsig_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_schnorrsig* sig,
|
||||
const unsigned char *in64
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
|
||||
|
||||
/** Create a Schnorr signature.
|
||||
*
|
||||
* Does _not_ strictly follow BIP-340 because it does not verify the resulting
|
||||
* signature. Instead, you can manually use secp256k1_schnorrsig_verify and
|
||||
* abort if it fails.
|
||||
*
|
||||
* Otherwise BIP-340 compliant if the noncefp argument is NULL or
|
||||
* secp256k1_nonce_function_bip340 and the ndata argument is 32-byte auxiliary
|
||||
* randomness.
|
||||
*
|
||||
* Returns 1 on success, 0 on failure.
|
||||
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||
* Out: sig: pointer to the returned signature (cannot be NULL)
|
||||
* nonce_is_negated: a pointer to an integer indicates if signing algorithm negated the
|
||||
* nonce (can be NULL)
|
||||
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
|
||||
* seckey: pointer to a 32-byte secret key (cannot be NULL)
|
||||
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bipschnorr is used
|
||||
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
|
||||
* Out: sig64: pointer to a 64-byte array to store the serialized signature (cannot be NULL)
|
||||
* In: msg32: the 32-byte message being signed (cannot be NULL)
|
||||
* keypair: pointer to an initialized keypair (cannot be NULL)
|
||||
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bip340 is used
|
||||
* ndata: pointer to arbitrary data used by the nonce generation
|
||||
* function (can be NULL). If it is non-NULL and
|
||||
* secp256k1_nonce_function_bip340 is used, then ndata must be a
|
||||
* pointer to 32-byte auxiliary randomness as per BIP-340.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_schnorrsig_sign(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_schnorrsig *sig,
|
||||
int *nonce_is_negated,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *seckey,
|
||||
secp256k1_nonce_function noncefp,
|
||||
const secp256k1_keypair *keypair,
|
||||
secp256k1_nonce_function_hardened noncefp,
|
||||
void *ndata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Verify a Schnorr signature.
|
||||
*
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect or unparseable signature
|
||||
* 0: incorrect signature
|
||||
* Args: ctx: a secp256k1 context object, initialized for verification.
|
||||
* In: sig: the signature being verified (cannot be NULL)
|
||||
* msg32: the 32-byte message hash being verified (cannot be NULL)
|
||||
* pubkey: pointer to a public key to verify with (cannot be NULL)
|
||||
* In: sig64: pointer to the 64-byte signature to verify (cannot be NULL)
|
||||
* msg32: the 32-byte message being verified (cannot be NULL)
|
||||
* pubkey: pointer to an x-only public key to verify with (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_schnorrsig *sig,
|
||||
const unsigned char *sig64,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_pubkey *pubkey
|
||||
const secp256k1_xonly_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Verifies a set of Schnorr signatures.
|
||||
*
|
||||
* Returns 1 if all succeeded, 0 otherwise. In particular, returns 1 if n_sigs is 0.
|
||||
*
|
||||
* Args: ctx: a secp256k1 context object, initialized for verification.
|
||||
* scratch: scratch space used for the multiexponentiation
|
||||
* In: sig: array of signatures, or NULL if there are no signatures
|
||||
* msg32: array of messages, or NULL if there are no signatures
|
||||
* pk: array of public keys, or NULL if there are no signatures
|
||||
* n_sigs: number of signatures in above arrays. Must be smaller than
|
||||
* 2^31 and smaller than half the maximum size_t value. Must be 0
|
||||
* if above arrays are NULL.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify_batch(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_scratch_space *scratch,
|
||||
const secp256k1_schnorrsig *const *sig,
|
||||
const unsigned char *const *msg32,
|
||||
const secp256k1_pubkey *const *pk,
|
||||
size_t n_sigs
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2018 Andrew Poelstra *
|
||||
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
@ -7,6 +7,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_schnorrsig.h"
|
||||
#include "util.h"
|
||||
@ -14,26 +15,24 @@
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
secp256k1_scratch_space *scratch;
|
||||
int n;
|
||||
|
||||
const secp256k1_keypair **keypairs;
|
||||
const unsigned char **pk;
|
||||
const secp256k1_schnorrsig **sigs;
|
||||
const unsigned char **sigs;
|
||||
const unsigned char **msgs;
|
||||
} bench_schnorrsig_data;
|
||||
|
||||
void bench_schnorrsig_sign(void* arg, int iters) {
|
||||
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
|
||||
int i;
|
||||
unsigned char sk[32] = "benchmarkexample secrettemplate";
|
||||
unsigned char msg[32] = "benchmarkexamplemessagetemplate";
|
||||
secp256k1_schnorrsig sig;
|
||||
unsigned char sig[64];
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
msg[0] = i;
|
||||
msg[1] = i >> 8;
|
||||
sk[0] = i;
|
||||
sk[1] = i >> 8;
|
||||
CHECK(secp256k1_schnorrsig_sign(data->ctx, &sig, NULL, msg, sk, NULL, NULL));
|
||||
CHECK(secp256k1_schnorrsig_sign(data->ctx, sig, msg, data->keypairs[i], NULL, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,50 +41,30 @@ void bench_schnorrsig_verify(void* arg, int iters) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_pubkey pk;
|
||||
CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pk, data->pk[i], 33) == 1);
|
||||
secp256k1_xonly_pubkey pk;
|
||||
CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], &pk));
|
||||
}
|
||||
}
|
||||
|
||||
void bench_schnorrsig_verify_n(void* arg, int iters) {
|
||||
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
|
||||
int i, j;
|
||||
const secp256k1_pubkey **pk = (const secp256k1_pubkey **)malloc(data->n * sizeof(*pk));
|
||||
|
||||
CHECK(pk != NULL);
|
||||
for (j = 0; j < iters/data->n; j++) {
|
||||
for (i = 0; i < data->n; i++) {
|
||||
secp256k1_pubkey *pk_nonconst = (secp256k1_pubkey *)malloc(sizeof(*pk_nonconst));
|
||||
CHECK(secp256k1_ec_pubkey_parse(data->ctx, pk_nonconst, data->pk[i], 33) == 1);
|
||||
pk[i] = pk_nonconst;
|
||||
}
|
||||
CHECK(secp256k1_schnorrsig_verify_batch(data->ctx, data->scratch, data->sigs, data->msgs, pk, data->n));
|
||||
for (i = 0; i < data->n; i++) {
|
||||
free((void *)pk[i]);
|
||||
}
|
||||
}
|
||||
free(pk);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int i;
|
||||
bench_schnorrsig_data data;
|
||||
int iters = get_iters(1000);
|
||||
int iters = get_iters(10000);
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
|
||||
data.scratch = secp256k1_scratch_space_create(data.ctx, 1024 * 1024 * 1024);
|
||||
data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *));
|
||||
data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
|
||||
data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
|
||||
data.sigs = (const secp256k1_schnorrsig **)malloc(iters * sizeof(secp256k1_schnorrsig *));
|
||||
data.sigs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
unsigned char sk[32];
|
||||
unsigned char *msg = (unsigned char *)malloc(32);
|
||||
secp256k1_schnorrsig *sig = (secp256k1_schnorrsig *)malloc(sizeof(*sig));
|
||||
unsigned char *pk_char = (unsigned char *)malloc(33);
|
||||
secp256k1_pubkey pk;
|
||||
size_t pk_len = 33;
|
||||
unsigned char *sig = (unsigned char *)malloc(64);
|
||||
secp256k1_keypair *keypair = (secp256k1_keypair *)malloc(sizeof(*keypair));
|
||||
unsigned char *pk_char = (unsigned char *)malloc(32);
|
||||
secp256k1_xonly_pubkey pk;
|
||||
msg[0] = sk[0] = i;
|
||||
msg[1] = sk[1] = i >> 8;
|
||||
msg[2] = sk[2] = i >> 16;
|
||||
@ -93,37 +72,31 @@ int main(void) {
|
||||
memset(&msg[4], 'm', 28);
|
||||
memset(&sk[4], 's', 28);
|
||||
|
||||
data.keypairs[i] = keypair;
|
||||
data.pk[i] = pk_char;
|
||||
data.msgs[i] = msg;
|
||||
data.sigs[i] = sig;
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(data.ctx, &pk, sk));
|
||||
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, pk_char, &pk_len, &pk, SECP256K1_EC_COMPRESSED) == 1);
|
||||
CHECK(secp256k1_schnorrsig_sign(data.ctx, sig, NULL, msg, sk, NULL, NULL));
|
||||
CHECK(secp256k1_keypair_create(data.ctx, keypair, sk));
|
||||
CHECK(secp256k1_schnorrsig_sign(data.ctx, sig, msg, keypair, NULL, NULL));
|
||||
CHECK(secp256k1_keypair_xonly_pub(data.ctx, &pk, NULL, keypair));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1);
|
||||
}
|
||||
|
||||
run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, iters);
|
||||
run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, iters);
|
||||
for (i = 1; i <= iters; i *= 2) {
|
||||
char name[64];
|
||||
int divisible_iters;
|
||||
sprintf(name, "schnorrsig_batch_verify_%d", (int) i);
|
||||
|
||||
data.n = i;
|
||||
divisible_iters = iters - (iters % data.n);
|
||||
run_benchmark(name, bench_schnorrsig_verify_n, NULL, NULL, (void *) &data, 3, divisible_iters);
|
||||
}
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
free((void *)data.keypairs[i]);
|
||||
free((void *)data.pk[i]);
|
||||
free((void *)data.msgs[i]);
|
||||
free((void *)data.sigs[i]);
|
||||
}
|
||||
free(data.keypairs);
|
||||
free(data.pk);
|
||||
free(data.msgs);
|
||||
free(data.sigs);
|
||||
|
||||
secp256k1_scratch_space_destroy(data.ctx, data.scratch);
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
}
|
||||
|
@ -164,6 +164,19 @@ static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out
|
||||
memcpy(out32, (const unsigned char*)out, 32);
|
||||
}
|
||||
|
||||
/* Initializes a sha256 struct and writes the 64 byte string
|
||||
* SHA256(tag)||SHA256(tag) into it. */
|
||||
static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256_initialize(hash);
|
||||
secp256k1_sha256_write(hash, tag, taglen);
|
||||
secp256k1_sha256_finalize(hash, buf);
|
||||
|
||||
secp256k1_sha256_initialize(hash);
|
||||
secp256k1_sha256_write(hash, buf, 32);
|
||||
secp256k1_sha256_write(hash, buf, 32);
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
|
||||
size_t n;
|
||||
unsigned char rkey[64];
|
||||
|
3
src/modules/extrakeys/Makefile.am.include
Normal file
3
src/modules/extrakeys/Makefile.am.include
Normal file
@ -0,0 +1,3 @@
|
||||
include_HEADERS += include/secp256k1_extrakeys.h
|
||||
noinst_HEADERS += src/modules/extrakeys/tests_impl.h
|
||||
noinst_HEADERS += src/modules/extrakeys/main_impl.h
|
248
src/modules/extrakeys/main_impl.h
Normal file
248
src/modules/extrakeys/main_impl.h
Normal file
@ -0,0 +1,248 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_EXTRAKEYS_MAIN_
|
||||
#define _SECP256K1_MODULE_EXTRAKEYS_MAIN_
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_extrakeys.h"
|
||||
|
||||
static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) {
|
||||
return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_xonly_pubkey_save(secp256k1_xonly_pubkey *pubkey, secp256k1_ge *ge) {
|
||||
secp256k1_pubkey_save((secp256k1_pubkey *) pubkey, ge);
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, const unsigned char *input32) {
|
||||
secp256k1_ge pk;
|
||||
secp256k1_fe x;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
ARG_CHECK(input32 != NULL);
|
||||
|
||||
if (!secp256k1_fe_set_b32(&x, input32)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_xonly_pubkey_save(pubkey, &pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output32, const secp256k1_xonly_pubkey *pubkey) {
|
||||
secp256k1_ge pk;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output32 != NULL);
|
||||
memset(output32, 0, 32);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_get_b32(output32, &pk.x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Keeps a group element as is if it has an even Y and otherwise negates it.
|
||||
* y_parity is set to 0 in the former case and to 1 in the latter case.
|
||||
* Requires that the coordinates of r are normalized. */
|
||||
static int secp256k1_extrakeys_ge_even_y(secp256k1_ge *r) {
|
||||
int y_parity = 0;
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(r));
|
||||
|
||||
if (secp256k1_fe_is_odd(&r->y)) {
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
y_parity = 1;
|
||||
}
|
||||
return y_parity;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, const secp256k1_pubkey *pubkey) {
|
||||
secp256k1_ge pk;
|
||||
int tmp;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(xonly_pubkey != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
tmp = secp256k1_extrakeys_ge_even_y(&pk);
|
||||
if (pk_parity != NULL) {
|
||||
*pk_parity = tmp;
|
||||
}
|
||||
secp256k1_xonly_pubkey_save(xonly_pubkey, &pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
|
||||
secp256k1_ge pk;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output_pubkey != NULL);
|
||||
memset(output_pubkey, 0, sizeof(*output_pubkey));
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(internal_pubkey != NULL);
|
||||
ARG_CHECK(tweak32 != NULL);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey)
|
||||
|| !secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_pubkey_save(output_pubkey, &pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
|
||||
secp256k1_ge pk;
|
||||
unsigned char pk_expected32[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(internal_pubkey != NULL);
|
||||
ARG_CHECK(tweaked_pubkey32 != NULL);
|
||||
ARG_CHECK(tweak32 != NULL);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey)
|
||||
|| !secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_normalize_var(&pk.x);
|
||||
secp256k1_fe_normalize_var(&pk.y);
|
||||
secp256k1_fe_get_b32(pk_expected32, &pk.x);
|
||||
|
||||
return memcmp(&pk_expected32, tweaked_pubkey32, 32) == 0
|
||||
&& secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity;
|
||||
}
|
||||
|
||||
static void secp256k1_keypair_save(secp256k1_keypair *keypair, const secp256k1_scalar *sk, secp256k1_ge *pk) {
|
||||
secp256k1_scalar_get_b32(&keypair->data[0], sk);
|
||||
secp256k1_pubkey_save((secp256k1_pubkey *)&keypair->data[32], pk);
|
||||
}
|
||||
|
||||
|
||||
static int secp256k1_keypair_seckey_load(const secp256k1_context* ctx, secp256k1_scalar *sk, const secp256k1_keypair *keypair) {
|
||||
int ret;
|
||||
|
||||
ret = secp256k1_scalar_set_b32_seckey(sk, &keypair->data[0]);
|
||||
/* We can declassify ret here because sk is only zero if a keypair function
|
||||
* failed (which zeroes the keypair) and its return value is ignored. */
|
||||
secp256k1_declassify(ctx, &ret, sizeof(ret));
|
||||
ARG_CHECK(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Load a keypair into pk and sk (if non-NULL). This function declassifies pk
|
||||
* and ARG_CHECKs that the keypair is not invalid. It always initializes sk and
|
||||
* pk with dummy values. */
|
||||
static int secp256k1_keypair_load(const secp256k1_context* ctx, secp256k1_scalar *sk, secp256k1_ge *pk, const secp256k1_keypair *keypair) {
|
||||
int ret;
|
||||
const secp256k1_pubkey *pubkey = (const secp256k1_pubkey *)&keypair->data[32];
|
||||
|
||||
/* Need to declassify the pubkey because pubkey_load ARG_CHECKs if it's
|
||||
* invalid. */
|
||||
secp256k1_declassify(ctx, pubkey, sizeof(*pubkey));
|
||||
ret = secp256k1_pubkey_load(ctx, pk, pubkey);
|
||||
if (sk != NULL) {
|
||||
ret = ret && secp256k1_keypair_seckey_load(ctx, sk, keypair);
|
||||
}
|
||||
if (!ret) {
|
||||
*pk = secp256k1_ge_const_g;
|
||||
if (sk != NULL) {
|
||||
*sk = secp256k1_scalar_one;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_create(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *seckey32) {
|
||||
secp256k1_scalar sk;
|
||||
secp256k1_ge pk;
|
||||
int ret = 0;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(keypair != NULL);
|
||||
memset(keypair, 0, sizeof(*keypair));
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(seckey32 != NULL);
|
||||
|
||||
ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &sk, &pk, seckey32);
|
||||
secp256k1_keypair_save(keypair, &sk, &pk);
|
||||
memczero(keypair, sizeof(*keypair), !ret);
|
||||
|
||||
secp256k1_scalar_clear(&sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_pub(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
ARG_CHECK(keypair != NULL);
|
||||
|
||||
memcpy(pubkey->data, &keypair->data[32], sizeof(*pubkey));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_xonly_pub(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, const secp256k1_keypair *keypair) {
|
||||
secp256k1_ge pk;
|
||||
int tmp;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
ARG_CHECK(keypair != NULL);
|
||||
|
||||
if (!secp256k1_keypair_load(ctx, NULL, &pk, keypair)) {
|
||||
return 0;
|
||||
}
|
||||
tmp = secp256k1_extrakeys_ge_even_y(&pk);
|
||||
if (pk_parity != NULL) {
|
||||
*pk_parity = tmp;
|
||||
}
|
||||
secp256k1_xonly_pubkey_save(pubkey, &pk);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *tweak32) {
|
||||
secp256k1_ge pk;
|
||||
secp256k1_scalar sk;
|
||||
int y_parity;
|
||||
int ret;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(keypair != NULL);
|
||||
ARG_CHECK(tweak32 != NULL);
|
||||
|
||||
ret = secp256k1_keypair_load(ctx, &sk, &pk, keypair);
|
||||
memset(keypair, 0, sizeof(*keypair));
|
||||
|
||||
y_parity = secp256k1_extrakeys_ge_even_y(&pk);
|
||||
if (y_parity == 1) {
|
||||
secp256k1_scalar_negate(&sk, &sk);
|
||||
}
|
||||
|
||||
ret &= secp256k1_ec_seckey_tweak_add_helper(&sk, tweak32);
|
||||
ret &= secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32);
|
||||
|
||||
secp256k1_declassify(ctx, &ret, sizeof(ret));
|
||||
if (ret) {
|
||||
secp256k1_keypair_save(keypair, &sk, &pk);
|
||||
}
|
||||
|
||||
secp256k1_scalar_clear(&sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
524
src/modules/extrakeys/tests_impl.h
Normal file
524
src/modules/extrakeys/tests_impl.h
Normal file
@ -0,0 +1,524 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_EXTRAKEYS_TESTS_
|
||||
#define _SECP256K1_MODULE_EXTRAKEYS_TESTS_
|
||||
|
||||
#include "secp256k1_extrakeys.h"
|
||||
|
||||
static secp256k1_context* api_test_context(int flags, int *ecount) {
|
||||
secp256k1_context *ctx0 = secp256k1_context_create(flags);
|
||||
secp256k1_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount);
|
||||
secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount);
|
||||
return ctx0;
|
||||
}
|
||||
|
||||
void test_xonly_pubkey(void) {
|
||||
secp256k1_pubkey pk;
|
||||
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
|
||||
secp256k1_ge pk1;
|
||||
secp256k1_ge pk2;
|
||||
secp256k1_fe y;
|
||||
unsigned char sk[32];
|
||||
unsigned char xy_sk[32];
|
||||
unsigned char buf32[32];
|
||||
unsigned char ones32[32];
|
||||
unsigned char zeros64[64] = { 0 };
|
||||
int pk_parity;
|
||||
int i;
|
||||
|
||||
int ecount;
|
||||
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
|
||||
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
|
||||
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
|
||||
|
||||
secp256k1_rand256(sk);
|
||||
memset(ones32, 0xFF, 32);
|
||||
secp256k1_rand256(xy_sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
|
||||
/* Test xonly_pubkey_from_pubkey */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_parity, &pk) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
memset(&pk, 0, sizeof(pk));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 0);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */
|
||||
memset(sk, 0, sizeof(sk));
|
||||
sk[0] = 1;
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(memcmp(&pk, &xonly_pk, sizeof(pk)) == 0);
|
||||
CHECK(pk_parity == 0);
|
||||
|
||||
/* Choose a secret key such that pubkey and xonly_pubkey are each others
|
||||
* negation. */
|
||||
sk[0] = 2;
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(memcmp(&xonly_pk, &pk, sizeof(xonly_pk)) != 0);
|
||||
CHECK(pk_parity == 1);
|
||||
secp256k1_pubkey_load(ctx, &pk1, &pk);
|
||||
secp256k1_pubkey_load(ctx, &pk2, (secp256k1_pubkey *) &xonly_pk);
|
||||
CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1);
|
||||
secp256k1_fe_negate(&y, &pk2.y, 1);
|
||||
CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1);
|
||||
|
||||
/* Test xonly_pubkey_serialize and xonly_pubkey_parse */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(none, NULL, &xonly_pk) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, NULL) == 0);
|
||||
CHECK(memcmp(buf32, zeros64, 32) == 0);
|
||||
CHECK(ecount == 2);
|
||||
{
|
||||
/* A pubkey filled with 0s will fail to serialize due to pubkey_load
|
||||
* special casing. */
|
||||
secp256k1_xonly_pubkey pk_tmp;
|
||||
memset(&pk_tmp, 0, sizeof(pk_tmp));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &pk_tmp) == 0);
|
||||
}
|
||||
/* pubkey_load called illegal callback */
|
||||
CHECK(ecount == 3);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &xonly_pk) == 1);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_parse(none, NULL, buf32) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
|
||||
/* Serialization and parse roundtrip */
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1);
|
||||
CHECK(memcmp(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0);
|
||||
|
||||
/* Test parsing invalid field elements */
|
||||
memset(&xonly_pk, 1, sizeof(xonly_pk));
|
||||
/* Overflowing field element */
|
||||
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, ones32) == 0);
|
||||
CHECK(memcmp(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
|
||||
memset(&xonly_pk, 1, sizeof(xonly_pk));
|
||||
/* There's no point with x-coordinate 0 on secp256k1 */
|
||||
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, zeros64) == 0);
|
||||
CHECK(memcmp(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
|
||||
/* If a random 32-byte string can not be parsed with ec_pubkey_parse
|
||||
* (because interpreted as X coordinate it does not correspond to a point on
|
||||
* the curve) then xonly_pubkey_parse should fail as well. */
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned char rand33[33];
|
||||
secp256k1_rand256(&rand33[1]);
|
||||
rand33[0] = SECP256K1_TAG_PUBKEY_EVEN;
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &pk, rand33, 33)) {
|
||||
memset(&xonly_pk, 1, sizeof(xonly_pk));
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 0);
|
||||
CHECK(memcmp(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
|
||||
} else {
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 1);
|
||||
}
|
||||
}
|
||||
CHECK(ecount == 2);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(verify);
|
||||
}
|
||||
|
||||
void test_xonly_pubkey_tweak(void) {
|
||||
unsigned char zeros64[64] = { 0 };
|
||||
unsigned char overflows[32];
|
||||
unsigned char sk[32];
|
||||
secp256k1_pubkey internal_pk;
|
||||
secp256k1_xonly_pubkey internal_xonly_pk;
|
||||
secp256k1_pubkey output_pk;
|
||||
int pk_parity;
|
||||
unsigned char tweak[32];
|
||||
int i;
|
||||
|
||||
int ecount;
|
||||
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
|
||||
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
|
||||
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
|
||||
|
||||
memset(overflows, 0xff, sizeof(overflows));
|
||||
secp256k1_rand256(tweak);
|
||||
secp256k1_rand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(none, &output_pk, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &output_pk, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, NULL, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, NULL, tweak) == 0);
|
||||
CHECK(ecount == 4);
|
||||
/* NULL internal_xonly_pk zeroes the output_pk */
|
||||
CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
/* NULL tweak zeroes the output_pk */
|
||||
CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
|
||||
/* Invalid tweak zeroes the output_pk */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, overflows) == 0);
|
||||
CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
|
||||
/* A zero tweak is fine */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, zeros64) == 1);
|
||||
|
||||
/* Fails if the resulting key was infinity */
|
||||
for (i = 0; i < count; i++) {
|
||||
secp256k1_scalar scalar_tweak;
|
||||
/* Because sk may be negated before adding, we need to try with tweak =
|
||||
* sk as well as tweak = -sk. */
|
||||
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
|
||||
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
|
||||
secp256k1_scalar_get_b32(tweak, &scalar_tweak);
|
||||
CHECK((secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, sk) == 0)
|
||||
|| (secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0));
|
||||
CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
}
|
||||
|
||||
/* Invalid pk with a valid tweak */
|
||||
memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk));
|
||||
secp256k1_rand256(tweak);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(verify);
|
||||
}
|
||||
|
||||
void test_xonly_pubkey_tweak_check(void) {
|
||||
unsigned char zeros64[64] = { 0 };
|
||||
unsigned char overflows[32];
|
||||
unsigned char sk[32];
|
||||
secp256k1_pubkey internal_pk;
|
||||
secp256k1_xonly_pubkey internal_xonly_pk;
|
||||
secp256k1_pubkey output_pk;
|
||||
secp256k1_xonly_pubkey output_xonly_pk;
|
||||
unsigned char output_pk32[32];
|
||||
unsigned char buf32[32];
|
||||
int pk_parity;
|
||||
unsigned char tweak[32];
|
||||
|
||||
int ecount;
|
||||
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
|
||||
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
|
||||
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
|
||||
|
||||
memset(overflows, 0xff, sizeof(overflows));
|
||||
secp256k1_rand256(tweak);
|
||||
secp256k1_rand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &output_xonly_pk, &pk_parity, &output_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &output_xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(none, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(sign, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, NULL, pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
/* invalid pk_parity value */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, 2, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, NULL, tweak) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
|
||||
memset(tweak, 1, sizeof(tweak));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, NULL, &internal_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &pk_parity, &output_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk32, &output_xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1);
|
||||
|
||||
/* Wrong pk_parity */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
/* Wrong public key */
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &internal_xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
|
||||
/* Overflowing tweak not allowed */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0);
|
||||
CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
CHECK(ecount == 5);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(verify);
|
||||
}
|
||||
|
||||
/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1
|
||||
* additional pubkeys by calling tweak_add. Then verifies every tweak starting
|
||||
* from the last pubkey. */
|
||||
#define N_PUBKEYS 32
|
||||
void test_xonly_pubkey_tweak_recursive(void) {
|
||||
unsigned char sk[32];
|
||||
secp256k1_pubkey pk[N_PUBKEYS];
|
||||
unsigned char pk_serialized[32];
|
||||
unsigned char tweak[N_PUBKEYS - 1][32];
|
||||
int i;
|
||||
|
||||
secp256k1_rand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk) == 1);
|
||||
/* Add tweaks */
|
||||
for (i = 0; i < N_PUBKEYS - 1; i++) {
|
||||
secp256k1_xonly_pubkey xonly_pk;
|
||||
memset(tweak[i], i + 1, sizeof(tweak[i]));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &pk[i + 1], &xonly_pk, tweak[i]) == 1);
|
||||
}
|
||||
|
||||
/* Verify tweaks */
|
||||
for (i = N_PUBKEYS - 1; i > 0; i--) {
|
||||
secp256k1_xonly_pubkey xonly_pk;
|
||||
int pk_parity;
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk[i]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk_serialized, &xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i - 1]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1);
|
||||
}
|
||||
}
|
||||
#undef N_PUBKEYS
|
||||
|
||||
void test_keypair(void) {
|
||||
unsigned char sk[32];
|
||||
unsigned char zeros96[96] = { 0 };
|
||||
unsigned char overflows[32];
|
||||
secp256k1_keypair keypair;
|
||||
secp256k1_pubkey pk, pk_tmp;
|
||||
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
|
||||
int pk_parity, pk_parity_tmp;
|
||||
int ecount;
|
||||
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
|
||||
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
|
||||
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
|
||||
|
||||
CHECK(sizeof(zeros96) == sizeof(keypair));
|
||||
memset(overflows, 0xFF, sizeof(overflows));
|
||||
|
||||
/* Test keypair_create */
|
||||
ecount = 0;
|
||||
secp256k1_rand256(sk);
|
||||
CHECK(secp256k1_keypair_create(none, &keypair, sk) == 0);
|
||||
CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_create(verify, &keypair, sk) == 0);
|
||||
CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_create(sign, NULL, sk) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, NULL) == 0);
|
||||
CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(ecount == 4);
|
||||
|
||||
/* Invalid secret key */
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, zeros96) == 0);
|
||||
CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, overflows) == 0);
|
||||
CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
|
||||
/* Test keypair_pub */
|
||||
ecount = 0;
|
||||
secp256k1_rand256(sk);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_pub(none, NULL, &keypair) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_pub(none, &pk, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(memcmp(zeros96, &pk, sizeof(pk)) == 0);
|
||||
|
||||
/* Using an invalid keypair is fine for keypair_pub */
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1);
|
||||
CHECK(memcmp(zeros96, &pk, sizeof(pk)) == 0);
|
||||
|
||||
/* keypair holds the same pubkey as pubkey_create */
|
||||
CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_pub(none, &pk_tmp, &keypair) == 1);
|
||||
CHECK(memcmp(&pk, &pk_tmp, sizeof(pk)) == 0);
|
||||
|
||||
/** Test keypair_xonly_pub **/
|
||||
ecount = 0;
|
||||
secp256k1_rand256(sk);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, NULL, &pk_parity, &keypair) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, NULL, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(memcmp(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
|
||||
/* Using an invalid keypair will set the xonly_pk to 0 (first reset
|
||||
* xonly_pk). */
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1);
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 0);
|
||||
CHECK(memcmp(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/** keypair holds the same xonly pubkey as pubkey_create **/
|
||||
CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1);
|
||||
CHECK(memcmp(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0);
|
||||
CHECK(pk_parity == pk_parity_tmp);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(verify);
|
||||
}
|
||||
|
||||
void test_keypair_add(void) {
|
||||
unsigned char sk[32];
|
||||
secp256k1_keypair keypair;
|
||||
unsigned char overflows[32];
|
||||
unsigned char zeros96[96] = { 0 };
|
||||
unsigned char tweak[32];
|
||||
int i;
|
||||
int ecount = 0;
|
||||
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
|
||||
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
|
||||
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
|
||||
|
||||
CHECK(sizeof(zeros96) == sizeof(keypair));
|
||||
secp256k1_rand256(sk);
|
||||
secp256k1_rand256(tweak);
|
||||
memset(overflows, 0xFF, 32);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(none, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(sign, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(verify, NULL, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, NULL) == 0);
|
||||
CHECK(ecount == 4);
|
||||
/* This does not set the keypair to zeroes */
|
||||
CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) != 0);
|
||||
|
||||
/* Invalid tweak zeroes the keypair */
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, overflows) == 0);
|
||||
CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) == 0);
|
||||
|
||||
/* A zero tweak is fine */
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, zeros96) == 1);
|
||||
|
||||
/* Fails if the resulting keypair was (sk=0, pk=infinity) */
|
||||
for (i = 0; i < count; i++) {
|
||||
secp256k1_scalar scalar_tweak;
|
||||
secp256k1_keypair keypair_tmp;
|
||||
secp256k1_rand256(sk);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
memcpy(&keypair_tmp, &keypair, sizeof(keypair));
|
||||
/* Because sk may be negated before adding, we need to try with tweak =
|
||||
* sk as well as tweak = -sk. */
|
||||
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
|
||||
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
|
||||
secp256k1_scalar_get_b32(tweak, &scalar_tweak);
|
||||
CHECK((secp256k1_keypair_xonly_tweak_add(ctx, &keypair, sk) == 0)
|
||||
|| (secp256k1_keypair_xonly_tweak_add(ctx, &keypair_tmp, tweak) == 0));
|
||||
CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) == 0
|
||||
|| memcmp(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0);
|
||||
}
|
||||
|
||||
/* Invalid keypair with a valid tweak */
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
secp256k1_rand256(tweak);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) == 0);
|
||||
/* Only seckey part of keypair invalid */
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
memset(&keypair, 0, 32);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
/* Only pubkey part of keypair invalid */
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
memset(&keypair.data[32], 0, 64);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/* Check that the keypair_tweak_add implementation is correct */
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
for (i = 0; i < count; i++) {
|
||||
secp256k1_xonly_pubkey internal_pk;
|
||||
secp256k1_xonly_pubkey output_pk;
|
||||
secp256k1_pubkey output_pk_xy;
|
||||
secp256k1_pubkey output_pk_expected;
|
||||
unsigned char pk32[32];
|
||||
int pk_parity;
|
||||
|
||||
secp256k1_rand256(tweak);
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1);
|
||||
|
||||
/* Check that it passes xonly_pubkey_tweak_add_check */
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk32, &output_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk32, pk_parity, &internal_pk, tweak) == 1);
|
||||
|
||||
/* Check that the resulting pubkey matches xonly_pubkey_tweak_add */
|
||||
CHECK(secp256k1_keypair_pub(ctx, &output_pk_xy, &keypair) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk_expected, &internal_pk, tweak) == 1);
|
||||
CHECK(memcmp(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
|
||||
|
||||
/* Check that the secret key in the keypair is tweaked correctly */
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, &keypair.data[0]) == 1);
|
||||
CHECK(memcmp(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
|
||||
}
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(verify);
|
||||
}
|
||||
|
||||
void run_extrakeys_tests(void) {
|
||||
/* xonly key test cases */
|
||||
test_xonly_pubkey();
|
||||
test_xonly_pubkey_tweak();
|
||||
test_xonly_pubkey_tweak_check();
|
||||
test_xonly_pubkey_tweak_recursive();
|
||||
|
||||
/* keypair tests */
|
||||
test_keypair();
|
||||
test_keypair_add();
|
||||
}
|
||||
|
||||
#endif
|
@ -18,8 +18,9 @@
|
||||
/* Number of public keys involved in creating the aggregate signature */
|
||||
#define N_SIGNERS 3
|
||||
/* Create a key pair and store it in seckey and pubkey */
|
||||
int create_key(const secp256k1_context* ctx, unsigned char* seckey, secp256k1_pubkey* pubkey) {
|
||||
int create_keypair(const secp256k1_context* ctx, unsigned char *seckey, secp256k1_xonly_pubkey *pubkey) {
|
||||
int ret;
|
||||
secp256k1_keypair keypair;
|
||||
FILE *frand = fopen("/dev/urandom", "r");
|
||||
if (frand == NULL) {
|
||||
return 0;
|
||||
@ -32,12 +33,14 @@ int create_key(const secp256k1_context* ctx, unsigned char* seckey, secp256k1_pu
|
||||
/* The probability that this not a valid secret key is approximately 2^-128 */
|
||||
} while (!secp256k1_ec_seckey_verify(ctx, seckey));
|
||||
fclose(frand);
|
||||
ret = secp256k1_ec_pubkey_create(ctx, pubkey, seckey);
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, seckey);
|
||||
ret &= secp256k1_keypair_xonly_pub(ctx, pubkey, NULL, &keypair);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Sign a message hash with the given key pairs and store the result in sig */
|
||||
int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_pubkey* pubkeys, const unsigned char* msg32, secp256k1_schnorrsig *sig) {
|
||||
int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_xonly_pubkey* pubkeys, const unsigned char* msg32, unsigned char *sig64) {
|
||||
secp256k1_musig_session musig_session[N_SIGNERS];
|
||||
unsigned char nonce_commitment[N_SIGNERS][32];
|
||||
const unsigned char *nonce_commitment_ptr[N_SIGNERS];
|
||||
@ -49,11 +52,11 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
FILE *frand;
|
||||
unsigned char session_id32[32];
|
||||
unsigned char pk_hash[32];
|
||||
secp256k1_pubkey combined_pk;
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
secp256k1_musig_pre_session pre_session;
|
||||
|
||||
/* Create combined pubkey and initialize signer data */
|
||||
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, pk_hash, pubkeys, N_SIGNERS)) {
|
||||
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, &pre_session, pubkeys, N_SIGNERS)) {
|
||||
return 0;
|
||||
}
|
||||
/* Create random session ID. It is absolutely necessary that the session ID
|
||||
@ -69,7 +72,7 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25
|
||||
}
|
||||
fclose(frand);
|
||||
/* Initialize session */
|
||||
if (!secp256k1_musig_session_initialize(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, pk_hash, N_SIGNERS, i, seckeys[i])) {
|
||||
if (!secp256k1_musig_session_initialize(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, &pre_session, N_SIGNERS, i, seckeys[i])) {
|
||||
return 0;
|
||||
}
|
||||
nonce_commitment_ptr[i] = &nonce_commitment[i][0];
|
||||
@ -119,23 +122,23 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25
|
||||
}
|
||||
}
|
||||
}
|
||||
return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig, partial_sig, N_SIGNERS, NULL);
|
||||
return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig64, partial_sig, N_SIGNERS);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
secp256k1_context* ctx;
|
||||
int i;
|
||||
unsigned char seckeys[N_SIGNERS][32];
|
||||
secp256k1_pubkey pubkeys[N_SIGNERS];
|
||||
secp256k1_pubkey combined_pk;
|
||||
secp256k1_xonly_pubkey pubkeys[N_SIGNERS];
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!";
|
||||
secp256k1_schnorrsig sig;
|
||||
unsigned char sig[64];
|
||||
|
||||
/* Create a context for signing and verification */
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
printf("Creating key pairs......");
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
if (!create_key(ctx, seckeys[i], &pubkeys[i])) {
|
||||
if (!create_keypair(ctx, seckeys[i], &pubkeys[i])) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
@ -148,13 +151,13 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Signing message.........");
|
||||
if (!sign(ctx, seckeys, pubkeys, msg, &sig)) {
|
||||
if (!sign(ctx, seckeys, pubkeys, msg, sig)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Verifying signature.....");
|
||||
if (!secp256k1_schnorrsig_verify(ctx, &sig, msg, &combined_pk)) {
|
||||
if (!secp256k1_schnorrsig_verify(ctx, sig, msg, &combined_pk)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -7,23 +7,23 @@
|
||||
#ifndef _SECP256K1_MODULE_MUSIG_MAIN_
|
||||
#define _SECP256K1_MODULE_MUSIG_MAIN_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_musig.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* Computes ell = SHA256(pk[0], ..., pk[np-1]) */
|
||||
static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_pubkey *pk, size_t np) {
|
||||
static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_xonly_pubkey *pk, size_t np) {
|
||||
secp256k1_sha256 sha;
|
||||
size_t i;
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
for (i = 0; i < np; i++) {
|
||||
unsigned char ser[33];
|
||||
size_t serlen = sizeof(ser);
|
||||
if (!secp256k1_ec_pubkey_serialize(ctx, ser, &serlen, &pk[i], SECP256K1_EC_COMPRESSED)) {
|
||||
unsigned char ser[32];
|
||||
if (!secp256k1_xonly_pubkey_serialize(ctx, ser, &pk[i])) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(&sha, ser, serlen);
|
||||
secp256k1_sha256_write(&sha, ser, 32);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, ell);
|
||||
return 1;
|
||||
@ -77,14 +77,14 @@ static void secp256k1_musig_coefficient(secp256k1_scalar *r, const unsigned char
|
||||
typedef struct {
|
||||
const secp256k1_context *ctx;
|
||||
unsigned char ell[32];
|
||||
const secp256k1_pubkey *pks;
|
||||
const secp256k1_xonly_pubkey *pks;
|
||||
} secp256k1_musig_pubkey_combine_ecmult_data;
|
||||
|
||||
/* Callback for batch EC multiplication to compute ell_0*P0 + ell_1*P1 + ... */
|
||||
static int secp256k1_musig_pubkey_combine_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
||||
secp256k1_musig_pubkey_combine_ecmult_data *ctx = (secp256k1_musig_pubkey_combine_ecmult_data *) data;
|
||||
secp256k1_musig_coefficient(sc, ctx->ell, idx);
|
||||
return secp256k1_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]);
|
||||
return secp256k1_xonly_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]);
|
||||
}
|
||||
|
||||
|
||||
@ -97,10 +97,13 @@ static void secp256k1_musig_signers_init(secp256k1_musig_session_signer_data *si
|
||||
}
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_pubkey *combined_pk, unsigned char *pk_hash32, const secp256k1_pubkey *pubkeys, size_t n_pubkeys) {
|
||||
static const uint64_t pre_session_magic = 0xf4adbbdf7c7dd304UL;
|
||||
|
||||
int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const secp256k1_xonly_pubkey *pubkeys, size_t n_pubkeys) {
|
||||
secp256k1_musig_pubkey_combine_ecmult_data ecmult_data;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_ge pkp;
|
||||
int is_negated;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(combined_pk != NULL);
|
||||
@ -117,23 +120,26 @@ int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scrat
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej(&pkp, &pkj);
|
||||
secp256k1_pubkey_save(combined_pk, &pkp);
|
||||
secp256k1_fe_normalize(&pkp.y);
|
||||
is_negated = secp256k1_extrakeys_ge_even_y(&pkp);
|
||||
secp256k1_xonly_pubkey_save(combined_pk, &pkp);
|
||||
|
||||
if (pk_hash32 != NULL) {
|
||||
memcpy(pk_hash32, ecmult_data.ell, 32);
|
||||
if (pre_session != NULL) {
|
||||
pre_session->magic = pre_session_magic;
|
||||
memcpy(pre_session->pk_hash, ecmult_data.ell, 32);
|
||||
pre_session->is_negated = is_negated;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, size_t n_signers, size_t my_index, const unsigned char *seckey) {
|
||||
unsigned char combined_ser[33];
|
||||
size_t combined_ser_size = sizeof(combined_ser);
|
||||
int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, size_t n_signers, size_t my_index, const unsigned char *seckey) {
|
||||
unsigned char combined_ser[32];
|
||||
int overflow;
|
||||
secp256k1_scalar secret;
|
||||
secp256k1_scalar mu;
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge rp;
|
||||
secp256k1_gej pj;
|
||||
secp256k1_ge p;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
@ -142,7 +148,8 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m
|
||||
ARG_CHECK(nonce_commitment32 != NULL);
|
||||
ARG_CHECK(session_id32 != NULL);
|
||||
ARG_CHECK(combined_pk != NULL);
|
||||
ARG_CHECK(pk_hash32 != NULL);
|
||||
ARG_CHECK(pre_session != NULL);
|
||||
ARG_CHECK(pre_session->magic == pre_session_magic);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
|
||||
memset(session, 0, sizeof(*session));
|
||||
@ -154,7 +161,7 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m
|
||||
session->msg_is_set = 0;
|
||||
}
|
||||
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
|
||||
memcpy(session->pk_hash, pk_hash32, 32);
|
||||
session->pre_session = *pre_session;
|
||||
session->nonce_is_set = 0;
|
||||
session->has_secret_data = 1;
|
||||
if (n_signers == 0 || my_index >= n_signers) {
|
||||
@ -173,7 +180,25 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m
|
||||
secp256k1_scalar_clear(&secret);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_musig_coefficient(&mu, pk_hash32, (uint32_t) my_index);
|
||||
secp256k1_musig_coefficient(&mu, session->pre_session.pk_hash, (uint32_t) my_index);
|
||||
/* Compute the signers public key point and determine if the secret needs to
|
||||
* be negated before signing. If the signer's pubkey is negated XOR the
|
||||
* MuSig-combined pubkey is negated the secret has to be negated. This can
|
||||
* be seen by looking at the secret key belonging to `combined_pk`. Let's
|
||||
* define
|
||||
* P' := mu_0*|P_0| + ... + mu_n*|P_n| where P_i is the i-th public key
|
||||
* point x_i*G, mu_i is the i-th musig coefficient and |.| is a function
|
||||
* that normalizes a point to an even Y by negating if necessary similar to
|
||||
* secp256k1_extrakeys_ge_even_y. Then we have
|
||||
* P := |P'| the combined xonly public key. Also, P = x*G where x =
|
||||
* sum_i(b_i*mu_i*x_i) and b_i = -1 if (P != |P'| XOR P_i != |P_i|) and 1
|
||||
* otherwise. */
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret);
|
||||
secp256k1_ge_set_gej(&p, &pj);
|
||||
secp256k1_fe_normalize(&p.y);
|
||||
if (secp256k1_fe_is_odd(&p.y) != session->pre_session.is_negated) {
|
||||
secp256k1_scalar_negate(&secret, &secret);
|
||||
}
|
||||
secp256k1_scalar_mul(&secret, &secret, &mu);
|
||||
secp256k1_scalar_get_b32(session->seckey, &secret);
|
||||
|
||||
@ -183,8 +208,8 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m
|
||||
if (session->msg_is_set) {
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
}
|
||||
secp256k1_ec_pubkey_serialize(ctx, combined_ser, &combined_ser_size, combined_pk, SECP256K1_EC_COMPRESSED);
|
||||
secp256k1_sha256_write(&sha, combined_ser, combined_ser_size);
|
||||
secp256k1_xonly_pubkey_serialize(ctx, combined_ser, combined_pk);
|
||||
secp256k1_sha256_write(&sha, combined_ser, 32);
|
||||
secp256k1_sha256_write(&sha, seckey, 32);
|
||||
secp256k1_sha256_finalize(&sha, session->secnonce);
|
||||
secp256k1_scalar_set_b32(&secret, session->secnonce, &overflow);
|
||||
@ -194,9 +219,9 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m
|
||||
}
|
||||
|
||||
/* Compute public nonce and commitment */
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &secret);
|
||||
secp256k1_ge_set_gej(&rp, &rj);
|
||||
secp256k1_pubkey_save(&session->nonce, &rp);
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret);
|
||||
secp256k1_ge_set_gej(&p, &pj);
|
||||
secp256k1_pubkey_save(&session->nonce, &p);
|
||||
|
||||
if (nonce_commitment32 != NULL) {
|
||||
unsigned char commit[33];
|
||||
@ -256,7 +281,7 @@ int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp2
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, const unsigned char *const *commitments, size_t n_signers) {
|
||||
int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, const unsigned char *const *commitments, size_t n_signers) {
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
@ -264,7 +289,8 @@ int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, se
|
||||
ARG_CHECK(signers != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(combined_pk != NULL);
|
||||
ARG_CHECK(pk_hash32 != NULL);
|
||||
ARG_CHECK(pre_session != NULL);
|
||||
ARG_CHECK(pre_session->magic == pre_session_magic);
|
||||
ARG_CHECK(commitments != NULL);
|
||||
/* Check n_signers before checking commitments to allow testing the case where
|
||||
* n_signers is big without allocating the space. */
|
||||
@ -279,13 +305,14 @@ int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, se
|
||||
memset(session, 0, sizeof(*session));
|
||||
|
||||
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
|
||||
session->pre_session = *pre_session;
|
||||
if (n_signers == 0) {
|
||||
return 0;
|
||||
}
|
||||
session->n_signers = (uint32_t) n_signers;
|
||||
secp256k1_musig_signers_init(signers, session->n_signers);
|
||||
|
||||
memcpy(session->pk_hash, pk_hash32, 32);
|
||||
session->pre_session = *pre_session;
|
||||
session->nonce_is_set = 0;
|
||||
session->msg_is_set = 1;
|
||||
memcpy(session->msg, msg32, 32);
|
||||
@ -365,7 +392,8 @@ int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256
|
||||
secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL);
|
||||
}
|
||||
secp256k1_ge_set_gej(&combined_noncep, &combined_noncej);
|
||||
if (secp256k1_fe_is_quad_var(&combined_noncep.y)) {
|
||||
secp256k1_fe_normalize(&combined_noncep.y);
|
||||
if (!secp256k1_fe_is_odd(&combined_noncep.y)) {
|
||||
session->nonce_is_negated = 0;
|
||||
} else {
|
||||
session->nonce_is_negated = 1;
|
||||
@ -397,21 +425,20 @@ int secp256k1_musig_partial_signature_parse(const secp256k1_context* ctx, secp25
|
||||
|
||||
/* Compute msghash = SHA256(combined_nonce, combined_pk, msg) */
|
||||
static int secp256k1_musig_compute_messagehash(const secp256k1_context *ctx, unsigned char *msghash, const secp256k1_musig_session *session) {
|
||||
unsigned char buf[33];
|
||||
size_t bufsize = 33;
|
||||
unsigned char buf[32];
|
||||
secp256k1_ge rp;
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_schnorrsig_sha256_tagged(&sha);
|
||||
if (!session->nonce_is_set) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_pubkey_load(ctx, &rp, &session->combined_nonce);
|
||||
secp256k1_fe_get_b32(buf, &rp.x);
|
||||
secp256k1_sha256_write(&sha, buf, 32);
|
||||
secp256k1_ec_pubkey_serialize(ctx, buf, &bufsize, &session->combined_pk, SECP256K1_EC_COMPRESSED);
|
||||
VERIFY_CHECK(bufsize == 33);
|
||||
secp256k1_sha256_write(&sha, buf, bufsize);
|
||||
|
||||
secp256k1_xonly_pubkey_serialize(ctx, buf, &session->combined_pk);
|
||||
secp256k1_sha256_write(&sha, buf, 32);
|
||||
if (!session->msg_is_set) {
|
||||
return 0;
|
||||
}
|
||||
@ -466,14 +493,14 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_m
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_schnorrsig *sig, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs, const unsigned char *tweak32) {
|
||||
int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs) {
|
||||
size_t i;
|
||||
secp256k1_scalar s;
|
||||
secp256k1_ge noncep;
|
||||
(void) ctx;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(partial_sigs != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
|
||||
@ -495,40 +522,23 @@ int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp
|
||||
secp256k1_scalar_add(&s, &s, &term);
|
||||
}
|
||||
|
||||
/* If there is a tweak then add `msghash` times `tweak` to `s`.*/
|
||||
if (tweak32 != NULL) {
|
||||
unsigned char msghash[32];
|
||||
secp256k1_scalar e, scalar_tweak;
|
||||
int overflow = 0;
|
||||
|
||||
if (!secp256k1_musig_compute_messagehash(ctx, msghash, session)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&e, msghash, NULL);
|
||||
secp256k1_scalar_set_b32(&scalar_tweak, tweak32, &overflow);
|
||||
if (overflow || !secp256k1_eckey_privkey_tweak_mul(&e, &scalar_tweak)) {
|
||||
/* This mimics the behavior of secp256k1_ec_privkey_tweak_mul regarding
|
||||
* overflow and tweak32 being 0. */
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&s, &s, &e);
|
||||
}
|
||||
|
||||
secp256k1_pubkey_load(ctx, &noncep, &session->combined_nonce);
|
||||
VERIFY_CHECK(secp256k1_fe_is_quad_var(&noncep.y));
|
||||
VERIFY_CHECK(!secp256k1_fe_is_odd(&noncep.y));
|
||||
secp256k1_fe_normalize(&noncep.x);
|
||||
secp256k1_fe_get_b32(&sig->data[0], &noncep.x);
|
||||
secp256k1_scalar_get_b32(&sig->data[32], &s);
|
||||
secp256k1_fe_get_b32(&sig64[0], &noncep.x);
|
||||
secp256k1_scalar_get_b32(&sig64[32], &s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, const secp256k1_musig_partial_signature *partial_sig, const secp256k1_pubkey *pubkey) {
|
||||
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, const secp256k1_musig_partial_signature *partial_sig, const secp256k1_xonly_pubkey *pubkey) {
|
||||
unsigned char msghash[32];
|
||||
secp256k1_scalar s;
|
||||
secp256k1_scalar e;
|
||||
secp256k1_scalar mu;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge pkp;
|
||||
secp256k1_ge rp;
|
||||
int overflow;
|
||||
|
||||
@ -554,16 +564,27 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2
|
||||
/* Multiplying the messagehash by the musig coefficient is equivalent
|
||||
* to multiplying the signer's public key by the coefficient, except
|
||||
* much easier to do. */
|
||||
secp256k1_musig_coefficient(&mu, session->pk_hash, signer->index);
|
||||
secp256k1_musig_coefficient(&mu, session->pre_session.pk_hash, signer->index);
|
||||
secp256k1_scalar_mul(&e, &e, &mu);
|
||||
|
||||
if (!secp256k1_pubkey_load(ctx, &rp, &signer->nonce)) {
|
||||
return 0;
|
||||
}
|
||||
/* If the MuSig-combined point is negated, the signers will sign for the
|
||||
* negation of their individual xonly public key such that the combined
|
||||
* signature is valid for the MuSig aggregated xonly key. */
|
||||
if (session->pre_session.is_negated) {
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
}
|
||||
|
||||
if (!secp256k1_schnorrsig_real_verify(ctx, &rj, &s, &e, pubkey)) {
|
||||
/* Compute rj = s*G + (-e)*pkj */
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&pkj, &pkp);
|
||||
secp256k1_ecmult(&ctx->ecmult_ctx, &rj, &pkj, &e, &s);
|
||||
|
||||
if (!session->nonce_is_negated) {
|
||||
secp256k1_ge_neg(&rp, &rp);
|
||||
}
|
||||
@ -603,7 +624,7 @@ int secp256k1_musig_partial_sig_adapt(const secp256k1_context* ctx, secp256k1_mu
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigned char *sec_adaptor32, const secp256k1_schnorrsig *sig, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_is_negated) {
|
||||
int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigned char *sec_adaptor32, const unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_is_negated) {
|
||||
secp256k1_scalar t;
|
||||
secp256k1_scalar s;
|
||||
int overflow;
|
||||
@ -612,10 +633,10 @@ int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigne
|
||||
(void) ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sec_adaptor32 != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(partial_sigs != NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&t, &sig->data[32], &overflow);
|
||||
secp256k1_scalar_set_b32(&t, &sig64[32], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -9,6 +9,69 @@
|
||||
|
||||
#include "secp256k1_musig.h"
|
||||
|
||||
int secp256k1_xonly_pubkey_create(secp256k1_xonly_pubkey *pk, const unsigned char *seckey) {
|
||||
int ret;
|
||||
secp256k1_keypair keypair;
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, seckey);
|
||||
ret &= secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Just a simple (non-adaptor, non-tweaked) 2-of-2 MuSig combine, sign, verify
|
||||
* test. */
|
||||
void musig_simple_test(secp256k1_scratch_space *scratch) {
|
||||
unsigned char sk[2][32];
|
||||
secp256k1_musig_session session[2];
|
||||
secp256k1_musig_session_signer_data signer0[2];
|
||||
secp256k1_musig_session_signer_data signer1[2];
|
||||
unsigned char nonce_commitment[2][32];
|
||||
unsigned char msg[32];
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
secp256k1_musig_pre_session pre_session;
|
||||
unsigned char session_id[2][32];
|
||||
secp256k1_xonly_pubkey pk[2];
|
||||
const unsigned char *ncs[2];
|
||||
secp256k1_pubkey public_nonce[3];
|
||||
secp256k1_musig_partial_signature partial_sig[2];
|
||||
unsigned char final_sig[64];
|
||||
|
||||
secp256k1_rand256(session_id[0]);
|
||||
secp256k1_rand256(session_id[1]);
|
||||
secp256k1_rand256(sk[0]);
|
||||
secp256k1_rand256(sk[1]);
|
||||
secp256k1_rand256(msg);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
|
||||
|
||||
ncs[0] = nonce_commitment[0];
|
||||
ncs[1] = nonce_commitment[1];
|
||||
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signer0, &public_nonce[0], ncs, 2, NULL) == 1);
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signer1, &public_nonce[1], ncs, 2, NULL) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signer0[0], &public_nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signer0[1], &public_nonce[1]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signer1[0], &public_nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signer1[1], &public_nonce[1]) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signer0, 2, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signer1, 2, NULL, NULL) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signer0[1], &partial_sig[1], &pk[1]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], final_sig, partial_sig, 2) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, &combined_pk) == 1);
|
||||
}
|
||||
|
||||
void musig_api_tests(secp256k1_scratch_space *scratch) {
|
||||
secp256k1_scratch_space *scratch_small;
|
||||
secp256k1_musig_session session[2];
|
||||
@ -19,8 +82,8 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
|
||||
secp256k1_musig_partial_signature partial_sig[2];
|
||||
secp256k1_musig_partial_signature partial_sig_adapted[2];
|
||||
secp256k1_musig_partial_signature partial_sig_overflow;
|
||||
secp256k1_schnorrsig final_sig;
|
||||
secp256k1_schnorrsig final_sig_cmp;
|
||||
unsigned char final_sig[64];
|
||||
unsigned char final_sig_cmp[64];
|
||||
|
||||
unsigned char buf[32];
|
||||
unsigned char sk[2][32];
|
||||
@ -31,9 +94,10 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
|
||||
const unsigned char *ncs[2];
|
||||
unsigned char msg[32];
|
||||
unsigned char msghash[32];
|
||||
secp256k1_pubkey combined_pk;
|
||||
unsigned char pk_hash[32];
|
||||
secp256k1_pubkey pk[2];
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
secp256k1_musig_pre_session pre_session;
|
||||
secp256k1_musig_pre_session pre_session_uninitialized;
|
||||
secp256k1_xonly_pubkey pk[2];
|
||||
unsigned char tweak[32];
|
||||
|
||||
unsigned char sec_adaptor[32];
|
||||
@ -54,6 +118,10 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
|
||||
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
|
||||
memset(ones, 0xff, 32);
|
||||
/* Simulate pre_session being uninitialized by setting it to 0s. Actually providing
|
||||
* an unitialized pre_session object to a initialize_*_session would be undefined
|
||||
* behavior */
|
||||
memset(&pre_session_uninitialized, 0, sizeof(pre_session_uninitialized));
|
||||
|
||||
secp256k1_rand256(session_id[0]);
|
||||
secp256k1_rand256(session_id[1]);
|
||||
@ -63,104 +131,108 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
|
||||
secp256k1_rand256(sec_adaptor);
|
||||
secp256k1_rand256(tweak);
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor) == 1);
|
||||
|
||||
|
||||
/** main test body **/
|
||||
|
||||
/* Key combination */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_pubkey_combine(none, scratch, &combined_pk, pk_hash, pk, 2) == 0);
|
||||
CHECK(secp256k1_musig_pubkey_combine(none, scratch, &combined_pk, &pre_session, pk, 2) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(sign, scratch, &combined_pk, pk_hash, pk, 2) == 0);
|
||||
CHECK(secp256k1_musig_pubkey_combine(sign, scratch, &combined_pk, &pre_session, pk, 2) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(ecount == 2);
|
||||
/* pubkey_combine does not require a scratch space */
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, pk_hash, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(ecount == 2);
|
||||
/* A small scratch space works too, but will result in using an ineffecient algorithm */
|
||||
scratch_small = secp256k1_scratch_space_create(ctx, 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, pk_hash, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
secp256k1_scratch_space_destroy(ctx, scratch_small);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, pk_hash, pk, 2) == 0);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, &pre_session, pk, 2) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, NULL, pk, 2) == 1);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, NULL, 2) == 0);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 2) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 0) == 0);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 0) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, NULL, 0) == 0);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 0) == 0);
|
||||
CHECK(ecount == 6);
|
||||
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
|
||||
/** Session creation **/
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_session_initialize(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, pk_hash, 2, 0, sk[0]) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, pk_hash, 2, 0, sk[0]) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 7);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, NULL, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 8);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 0, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 8);
|
||||
/* Uninitialized pre_session */
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session_uninitialized, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 9);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 0, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 9);
|
||||
/* If more than UINT32_MAX fits in a size_t, test that session_initialize
|
||||
* rejects n_signers that high. */
|
||||
if (SIZE_MAX > UINT32_MAX) {
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, ((size_t) UINT32_MAX) + 2, 0, sk[0]) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, ((size_t) UINT32_MAX) + 2, 0, sk[0]) == 0);
|
||||
}
|
||||
CHECK(ecount == 8);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, NULL) == 0);
|
||||
CHECK(ecount == 9);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, NULL) == 0);
|
||||
CHECK(ecount == 10);
|
||||
/* secret key overflows */
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, ones) == 0);
|
||||
CHECK(ecount == 9);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, ones) == 0);
|
||||
CHECK(ecount == 10);
|
||||
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, pk_hash, 2, 1, sk[1]) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
|
||||
ncs[0] = nonce_commitment[0];
|
||||
ncs[1] = nonce_commitment[1];
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, NULL, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, NULL, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, pk_hash, ncs, 2) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, &pre_session, ncs, 2) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, pk_hash, ncs, 2) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, &pre_session, ncs, 2) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, NULL, ncs, 2) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, NULL, 2) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, NULL, 2) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 0) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 0) == 0);
|
||||
CHECK(ecount == 5);
|
||||
if (SIZE_MAX > UINT32_MAX) {
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, ((size_t) UINT32_MAX) + 2) == 0);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, ((size_t) UINT32_MAX) + 2) == 0);
|
||||
}
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_compute_messagehash(none, msghash, &verifier_session) == 0);
|
||||
CHECK(secp256k1_musig_compute_messagehash(none, msghash, &session[0]) == 0);
|
||||
@ -306,65 +378,59 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
|
||||
|
||||
/** Signing combining and verification */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2, NULL) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2, NULL) == 1);
|
||||
CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2, NULL) == 1);
|
||||
CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig_cmp, partial_sig_adapted, 2) == 1);
|
||||
CHECK(memcmp(final_sig, final_sig_cmp, sizeof(final_sig)) == 0);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig_cmp, partial_sig_adapted, 2) == 1);
|
||||
CHECK(memcmp(final_sig, final_sig_cmp, sizeof(final_sig)) == 0);
|
||||
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, NULL, &final_sig, partial_sig_adapted, 2, tweak) == 0);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, NULL, final_sig, partial_sig_adapted, 2) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2, tweak) == 0);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, NULL, 2, tweak) == 0);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, NULL, 2) == 0);
|
||||
CHECK(ecount == 3);
|
||||
{
|
||||
secp256k1_musig_partial_signature partial_sig_tmp[2];
|
||||
partial_sig_tmp[0] = partial_sig_adapted[0];
|
||||
partial_sig_tmp[1] = partial_sig_overflow;
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_tmp, 2, tweak) == 0);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_tmp, 2) == 0);
|
||||
}
|
||||
CHECK(ecount == 3);
|
||||
/* Wrong number of partial sigs */
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 1, tweak) == 0);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 1) == 0);
|
||||
CHECK(ecount == 3);
|
||||
{
|
||||
/* Overflowing tweak */
|
||||
unsigned char overflowing_tweak[32];
|
||||
memset(overflowing_tweak, 0xff, sizeof(overflowing_tweak));
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2, overflowing_tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
}
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2, NULL) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
CHECK(secp256k1_schnorrsig_verify(vrfy, &final_sig, msg, &combined_pk) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(vrfy, final_sig, msg, &combined_pk) == 1);
|
||||
|
||||
/** Secret adaptor can be extracted from signature */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 2, nonce_is_negated) == 1);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 2, nonce_is_negated) == 1);
|
||||
CHECK(memcmp(sec_adaptor, sec_adaptor1, 32) == 0);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, NULL, &final_sig, partial_sig, 2, 0) == 0);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, NULL, final_sig, partial_sig, 2, 0) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, NULL, partial_sig, 2, 0) == 0);
|
||||
CHECK(ecount == 2);
|
||||
{
|
||||
secp256k1_schnorrsig final_sig_tmp = final_sig;
|
||||
memcpy(&final_sig_tmp.data[32], ones, 32);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig_tmp, partial_sig, 2, nonce_is_negated) == 0);
|
||||
unsigned char final_sig_tmp[64];
|
||||
memcpy(final_sig_tmp, final_sig, sizeof(final_sig_tmp));
|
||||
memcpy(&final_sig_tmp[32], ones, 32);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig_tmp, partial_sig, 2, nonce_is_negated) == 0);
|
||||
}
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, NULL, 2, 0) == 0);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, NULL, 2, 0) == 0);
|
||||
CHECK(ecount == 3);
|
||||
{
|
||||
secp256k1_musig_partial_signature partial_sig_tmp[2];
|
||||
partial_sig_tmp[0] = partial_sig[0];
|
||||
partial_sig_tmp[1] = partial_sig_overflow;
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig_tmp, 2, nonce_is_negated) == 0);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig_tmp, 2, nonce_is_negated) == 0);
|
||||
}
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 0, 0) == 1);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 2, 1) == 1);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 0, 0) == 1);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 2, 1) == 1);
|
||||
|
||||
/** cleanup **/
|
||||
memset(&session, 0, sizeof(session));
|
||||
@ -380,26 +446,26 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
|
||||
* ones and return the resulting messagehash. This should not result in a different
|
||||
* messagehash because the public keys of the signers are only used during session
|
||||
* initialization. */
|
||||
int musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, const unsigned char * const *nonce_commitments, unsigned char *msg, secp256k1_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id) {
|
||||
int musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256k1_xonly_pubkey *pks, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const unsigned char * const *nonce_commitments, unsigned char *msg, secp256k1_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id) {
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_session session_tmp;
|
||||
unsigned char nonce_commitment[32];
|
||||
secp256k1_musig_session_signer_data signers[2];
|
||||
secp256k1_musig_session_signer_data signers_tmp[2];
|
||||
unsigned char sk_dummy[32];
|
||||
secp256k1_pubkey pks_tmp[2];
|
||||
secp256k1_pubkey combined_pk_tmp;
|
||||
unsigned char pk_hash_tmp[32];
|
||||
secp256k1_xonly_pubkey pks_tmp[2];
|
||||
secp256k1_xonly_pubkey combined_pk_tmp;
|
||||
secp256k1_musig_pre_session pre_session_tmp;
|
||||
secp256k1_pubkey nonce;
|
||||
|
||||
/* Set up signers with different public keys */
|
||||
secp256k1_rand256(sk_dummy);
|
||||
pks_tmp[0] = pks[0];
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pks_tmp[1], sk_dummy) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, pk_hash_tmp, pks_tmp, 2) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, pk_hash_tmp, 2, 1, sk_dummy) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pks_tmp[1], sk_dummy) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, &pre_session_tmp, pks_tmp, 2) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, &pre_session_tmp, 2, 1, sk_dummy) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 0, sk) == 1);
|
||||
CHECK(memcmp(nonce_commitment, nonce_commitments[1], 32) == 0);
|
||||
/* Call get_public_nonce with different signers than the signers the session was
|
||||
* initialized with. */
|
||||
@ -417,7 +483,7 @@ int musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256
|
||||
* commitments of signers_other do not match the nonce commitments the new session
|
||||
* was initialized with. If do_test is 0, the correct signers are being used and
|
||||
* therefore the function should return 1. */
|
||||
int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, unsigned char *msg, unsigned char *sk, secp256k1_musig_session_signer_data *signers_other, int do_test) {
|
||||
int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, unsigned char *msg, unsigned char *sk, secp256k1_musig_session_signer_data *signers_other, int do_test) {
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_session_signer_data signers[2];
|
||||
secp256k1_musig_session_signer_data *signers_to_use;
|
||||
@ -428,7 +494,7 @@ int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_pubkey *combin
|
||||
|
||||
/* Initialize new signers */
|
||||
secp256k1_rand256(session_id);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 1, sk) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 1, sk) == 1);
|
||||
ncs[0] = nonce_commitment_other;
|
||||
ncs[1] = nonce_commitment;
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2, NULL) == 1);
|
||||
@ -448,7 +514,7 @@ int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_pubkey *combin
|
||||
* parameters but without a message. Will test that the message must be
|
||||
* provided with `get_public_nonce`.
|
||||
*/
|
||||
void musig_state_machine_late_msg_test(secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id, unsigned char *msg) {
|
||||
void musig_state_machine_late_msg_test(secp256k1_xonly_pubkey *pks, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id, unsigned char *msg) {
|
||||
/* Create context for testing ARG_CHECKs by setting an illegal_callback. */
|
||||
secp256k1_context *ctx_tmp = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
int ecount = 0;
|
||||
@ -460,7 +526,7 @@ void musig_state_machine_late_msg_test(secp256k1_pubkey *pks, secp256k1_pubkey *
|
||||
secp256k1_musig_partial_signature partial_sig;
|
||||
|
||||
secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, NULL, combined_pk, pk_hash, 2, 1, sk) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, NULL, combined_pk, pre_session, 2, 1, sk) == 1);
|
||||
ncs[0] = nonce_commitment_other;
|
||||
ncs[1] = nonce_commitment;
|
||||
|
||||
@ -488,17 +554,17 @@ void musig_state_machine_late_msg_test(secp256k1_pubkey *pks, secp256k1_pubkey *
|
||||
* and tries to verify and combine partial sigs. If do_combine is 0, the
|
||||
* combine_nonces step is left out. In that case verify and combine should fail and
|
||||
* this function should return 0. */
|
||||
int musig_state_machine_missing_combine_test(secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, secp256k1_musig_partial_signature *partial_sig_other, unsigned char *msg, unsigned char *sk, unsigned char *session_id, secp256k1_musig_partial_signature *partial_sig, int do_combine) {
|
||||
int musig_state_machine_missing_combine_test(secp256k1_xonly_pubkey *pks, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, secp256k1_musig_partial_signature *partial_sig_other, unsigned char *msg, unsigned char *sk, unsigned char *session_id, secp256k1_musig_partial_signature *partial_sig, int do_combine) {
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_session_signer_data signers[2];
|
||||
unsigned char nonce_commitment[32];
|
||||
const unsigned char *ncs[2];
|
||||
secp256k1_pubkey nonce;
|
||||
secp256k1_musig_partial_signature partial_sigs[2];
|
||||
secp256k1_schnorrsig sig;
|
||||
unsigned char sig[64];
|
||||
int partial_verify, sig_combine;
|
||||
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 1, sk) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 1, sk) == 1);
|
||||
ncs[0] = nonce_commitment_other;
|
||||
ncs[1] = nonce_commitment;
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2, NULL) == 1);
|
||||
@ -511,7 +577,7 @@ int musig_state_machine_missing_combine_test(secp256k1_pubkey *pks, secp256k1_pu
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1);
|
||||
}
|
||||
partial_verify = secp256k1_musig_partial_sig_verify(ctx, &session, signers, partial_sig_other, &pks[0]);
|
||||
sig_combine = secp256k1_musig_partial_sig_combine(ctx, &session, &sig, partial_sigs, 2, NULL);
|
||||
sig_combine = secp256k1_musig_partial_sig_combine(ctx, &session, sig, partial_sigs, 2);
|
||||
if (do_combine != 0) {
|
||||
/* Return 1 if both succeeded */
|
||||
return partial_verify && sig_combine;
|
||||
@ -529,9 +595,9 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
|
||||
unsigned char session_id[2][32];
|
||||
unsigned char msg[32];
|
||||
unsigned char sk[2][32];
|
||||
secp256k1_pubkey pk[2];
|
||||
secp256k1_pubkey combined_pk;
|
||||
unsigned char pk_hash[32];
|
||||
secp256k1_xonly_pubkey pk[2];
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
secp256k1_musig_pre_session pre_session;
|
||||
secp256k1_pubkey nonce[2];
|
||||
const unsigned char *ncs[2];
|
||||
secp256k1_musig_partial_signature partial_sig[2];
|
||||
@ -547,11 +613,11 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
|
||||
secp256k1_rand256(sk[0]);
|
||||
secp256k1_rand256(sk[1]);
|
||||
secp256k1_rand256(msg);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, pk_hash, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, pk_hash, 2, 1, sk[1]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
|
||||
|
||||
/* Set nonce commitments */
|
||||
ncs[0] = nonce_commitment[0];
|
||||
@ -583,8 +649,8 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[1], &nonce[1]) == 1);
|
||||
|
||||
/* Can't combine nonces from signers of a different session */
|
||||
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, pk_hash, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 1) == 0);
|
||||
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, pk_hash, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 0) == 1);
|
||||
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, &pre_session, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 1) == 0);
|
||||
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, &pre_session, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 0) == 1);
|
||||
|
||||
/* Partially sign */
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1);
|
||||
@ -597,7 +663,7 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
|
||||
* with different signers (i.e. they diff in public keys). This is because the
|
||||
* public keys of the signers is set in stone when initializing the session. */
|
||||
CHECK(secp256k1_musig_compute_messagehash(ctx, msghash1, &session[1]) == 1);
|
||||
CHECK(musig_state_machine_diff_signer_msghash_test(msghash2, pk, &combined_pk, pk_hash, ncs, msg, &nonce[0], sk[1], session_id[1]) == 1);
|
||||
CHECK(musig_state_machine_diff_signer_msghash_test(msghash2, pk, &combined_pk, &pre_session, ncs, msg, &nonce[0], sk[1], session_id[1]) == 1);
|
||||
CHECK(memcmp(msghash1, msghash2, 32) == 0);
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
|
||||
|
||||
@ -605,11 +671,11 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
|
||||
/* Wrong signature */
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[0], &pk[1]) == 0);
|
||||
/* Can't get the public nonce until msg is set */
|
||||
musig_state_machine_late_msg_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], sk[1], session_id[1], msg);
|
||||
musig_state_machine_late_msg_test(pk, &combined_pk, &pre_session, nonce_commitment[0], &nonce[0], sk[1], session_id[1], msg);
|
||||
|
||||
/* Can't verify and combine partial sigs until nonces are combined */
|
||||
CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 0) == 0);
|
||||
CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 1) == 1);
|
||||
CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, &pre_session, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 0) == 0);
|
||||
CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, &pre_session, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 1) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -618,8 +684,8 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
|
||||
* while the indices 0 and 1 refer to the two signers. Here signer 0 is
|
||||
* sending a-coins to signer 1, while signer 1 is sending b-coins to signer
|
||||
* 0. Signer 0 produces the adaptor signatures. */
|
||||
secp256k1_schnorrsig final_sig_a;
|
||||
secp256k1_schnorrsig final_sig_b;
|
||||
unsigned char final_sig_a[64];
|
||||
unsigned char final_sig_b[64];
|
||||
secp256k1_musig_partial_signature partial_sig_a[2];
|
||||
secp256k1_musig_partial_signature partial_sig_b_adapted[2];
|
||||
secp256k1_musig_partial_signature partial_sig_b[2];
|
||||
@ -629,12 +695,12 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
|
||||
|
||||
unsigned char seckey_a[2][32];
|
||||
unsigned char seckey_b[2][32];
|
||||
secp256k1_pubkey pk_a[2];
|
||||
secp256k1_pubkey pk_b[2];
|
||||
unsigned char pk_hash_a[32];
|
||||
unsigned char pk_hash_b[32];
|
||||
secp256k1_pubkey combined_pk_a;
|
||||
secp256k1_pubkey combined_pk_b;
|
||||
secp256k1_xonly_pubkey pk_a[2];
|
||||
secp256k1_xonly_pubkey pk_b[2];
|
||||
secp256k1_musig_pre_session pre_session_a;
|
||||
secp256k1_musig_pre_session pre_session_b;
|
||||
secp256k1_xonly_pubkey combined_pk_a;
|
||||
secp256k1_xonly_pubkey combined_pk_b;
|
||||
secp256k1_musig_session musig_session_a[2];
|
||||
secp256k1_musig_session musig_session_b[2];
|
||||
unsigned char noncommit_a[2][32];
|
||||
@ -659,22 +725,22 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
|
||||
secp256k1_rand256(seckey_b[1]);
|
||||
secp256k1_rand256(sec_adaptor);
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_a[0], seckey_a[0]));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_a[1], seckey_a[1]));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_b[0], seckey_b[0]));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk_b[1], seckey_b[1]));
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk_a[0], seckey_a[0]));
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk_a[1], seckey_a[1]));
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk_b[0], seckey_b[0]));
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk_b[1], seckey_b[1]));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor));
|
||||
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_a, pk_hash_a, pk_a, 2));
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_b, pk_hash_b, pk_b, 2));
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_a, &pre_session_a, pk_a, 2));
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_b, &pre_session_b, pk_b, 2));
|
||||
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[0], data_a, noncommit_a[0], seed, msg32_a, &combined_pk_a, pk_hash_a, 2, 0, seckey_a[0]));
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[1], data_a, noncommit_a[1], seed, msg32_a, &combined_pk_a, pk_hash_a, 2, 1, seckey_a[1]));
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[0], data_a, noncommit_a[0], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, 0, seckey_a[0]));
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_a[1], data_a, noncommit_a[1], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, 1, seckey_a[1]));
|
||||
noncommit_a_ptr[0] = noncommit_a[0];
|
||||
noncommit_a_ptr[1] = noncommit_a[1];
|
||||
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[0], data_b, noncommit_b[0], seed, msg32_b, &combined_pk_b, pk_hash_b, 2, 0, seckey_b[0]));
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[1], data_b, noncommit_b[1], seed, msg32_b, &combined_pk_b, pk_hash_b, 2, 1, seckey_b[1]));
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[0], data_b, noncommit_b[0], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, 0, seckey_b[0]));
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &musig_session_b[1], data_b, noncommit_b[1], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, 1, seckey_b[1]));
|
||||
noncommit_b_ptr[0] = noncommit_b[0];
|
||||
noncommit_b_ptr[1] = noncommit_b[1];
|
||||
|
||||
@ -707,17 +773,17 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
|
||||
* is broadcasted by signer 0 to take B-coins. */
|
||||
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_b_adapted[0], &partial_sig_b[0], sec_adaptor, nonce_is_negated_b));
|
||||
memcpy(&partial_sig_b_adapted[1], &partial_sig_b[1], sizeof(partial_sig_b_adapted[1]));
|
||||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_b[0], &final_sig_b, partial_sig_b_adapted, 2, NULL) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig_b, msg32_b, &combined_pk_b) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_b[0], final_sig_b, partial_sig_b_adapted, 2) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_b, msg32_b, &combined_pk_b) == 1);
|
||||
|
||||
/* Step 6: Signer 1 extracts adaptor from the published signature, applies it to
|
||||
* other partial signature, and takes A-coins. */
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(ctx, sec_adaptor_extracted, &final_sig_b, partial_sig_b, 2, nonce_is_negated_b) == 1);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(ctx, sec_adaptor_extracted, final_sig_b, partial_sig_b, 2, nonce_is_negated_b) == 1);
|
||||
CHECK(memcmp(sec_adaptor_extracted, sec_adaptor, sizeof(sec_adaptor)) == 0); /* in real life we couldn't check this, of course */
|
||||
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_a[0], &partial_sig_a[0], sec_adaptor_extracted, nonce_is_negated_a));
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[1], &partial_sig_a[1]));
|
||||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_a[1], &final_sig_a, partial_sig_a, 2, NULL) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig_a, msg32_a, &combined_pk_a) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_a[1], final_sig_a, partial_sig_a, 2) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_a, msg32_a, &combined_pk_a) == 1);
|
||||
}
|
||||
|
||||
/* Checks that hash initialized by secp256k1_musig_sha256_init_tagged has the
|
||||
@ -753,93 +819,13 @@ void sha256_tag_test(void) {
|
||||
CHECK(memcmp(buf, buf2, 32) == 0);
|
||||
}
|
||||
|
||||
|
||||
void musig_tweak_test_helper(const secp256k1_pubkey* combined_pubkey, const unsigned char *ec_commit_tweak, const unsigned char *sk0, const unsigned char *sk1, const unsigned char *pk_hash) {
|
||||
secp256k1_musig_session session[2];
|
||||
secp256k1_musig_session_signer_data signers0[2];
|
||||
secp256k1_musig_session_signer_data signers1[2];
|
||||
secp256k1_pubkey pk[2];
|
||||
unsigned char session_id[2][32];
|
||||
unsigned char msg[32];
|
||||
unsigned char nonce_commitment[2][32];
|
||||
secp256k1_pubkey nonce[2];
|
||||
const unsigned char *ncs[2];
|
||||
secp256k1_musig_partial_signature partial_sig[2];
|
||||
secp256k1_schnorrsig final_sig;
|
||||
|
||||
secp256k1_rand256(session_id[0]);
|
||||
secp256k1_rand256(session_id[1]);
|
||||
secp256k1_rand256(msg);
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk0) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk1) == 1);
|
||||
|
||||
/* want to show that can both sign for Q and P */
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, combined_pubkey, pk_hash, 2, 0, sk0) == 1);
|
||||
CHECK(secp256k1_musig_session_initialize(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, combined_pubkey, pk_hash, 2, 1, sk1) == 1);
|
||||
/* Set nonce commitments */
|
||||
ncs[0] = nonce_commitment[0];
|
||||
ncs[1] = nonce_commitment[1];
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2, NULL) == 1);
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, &nonce[1], ncs, 2, NULL) == 1);
|
||||
/* Set nonces */
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[0], &nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], &nonce[1]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[0], &nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[1], &nonce[1]) == 1);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signers0, 2, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signers0[1], &partial_sig[1], &pk[1]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], &final_sig, partial_sig, 2, ec_commit_tweak));
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig, msg, combined_pubkey) == 1);
|
||||
}
|
||||
|
||||
/* In this test we create a combined public key P and a commitment Q = P +
|
||||
* hash(P, contract)*G. Then we test that we can sign for both public keys. In
|
||||
* order to sign for Q we use the tweak32 argument of partial_sig_combine. */
|
||||
void musig_tweak_test(secp256k1_scratch_space *scratch) {
|
||||
unsigned char sk[2][32];
|
||||
secp256k1_pubkey pk[2];
|
||||
unsigned char pk_hash[32];
|
||||
secp256k1_pubkey P;
|
||||
unsigned char P_serialized[33];
|
||||
size_t compressed_size = 33;
|
||||
secp256k1_pubkey Q;
|
||||
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char contract[32];
|
||||
unsigned char ec_commit_tweak[32];
|
||||
|
||||
/* Setup */
|
||||
secp256k1_rand256(sk[0]);
|
||||
secp256k1_rand256(sk[1]);
|
||||
secp256k1_rand256(contract);
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &P, pk_hash, pk, 2) == 1);
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_serialize(ctx, P_serialized, &compressed_size, &P, SECP256K1_EC_COMPRESSED) == 1);
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, P_serialized, 33);
|
||||
secp256k1_sha256_write(&sha, contract, 32);
|
||||
secp256k1_sha256_finalize(&sha, ec_commit_tweak);
|
||||
memcpy(&Q, &P, sizeof(secp256k1_pubkey));
|
||||
CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &Q, ec_commit_tweak));
|
||||
|
||||
/* Test signing for P */
|
||||
musig_tweak_test_helper(&P, NULL, sk[0], sk[1], pk_hash);
|
||||
/* Test signing for Q */
|
||||
musig_tweak_test_helper(&Q, ec_commit_tweak, sk[0], sk[1], pk_hash);
|
||||
}
|
||||
|
||||
void run_musig_tests(void) {
|
||||
int i;
|
||||
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
musig_simple_test(scratch);
|
||||
}
|
||||
musig_api_tests(scratch);
|
||||
musig_state_machine_tests(scratch);
|
||||
for (i = 0; i < count; i++) {
|
||||
@ -847,7 +833,6 @@ void run_musig_tests(void) {
|
||||
scriptless_atomic_swap(scratch);
|
||||
}
|
||||
sha256_tag_test();
|
||||
musig_tweak_test(scratch);
|
||||
|
||||
secp256k1_scratch_space_destroy(ctx, scratch);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2018 Andrew Poelstra *
|
||||
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
@ -11,328 +11,228 @@
|
||||
#include "include/secp256k1_schnorrsig.h"
|
||||
#include "hash.h"
|
||||
|
||||
int secp256k1_schnorrsig_serialize(const secp256k1_context* ctx, unsigned char *out64, const secp256k1_schnorrsig* sig) {
|
||||
(void) ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(out64 != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
memcpy(out64, sig->data, 64);
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("BIP0340/nonce")||SHA256("BIP0340/nonce"). */
|
||||
static void secp256k1_nonce_function_bip340_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x46615b35ul;
|
||||
sha->s[1] = 0xf4bfbff7ul;
|
||||
sha->s[2] = 0x9f8dc671ul;
|
||||
sha->s[3] = 0x83627ab3ul;
|
||||
sha->s[4] = 0x60217180ul;
|
||||
sha->s[5] = 0x57358661ul;
|
||||
sha->s[6] = 0x21a29e54ul;
|
||||
sha->s[7] = 0x68b07b4cul;
|
||||
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("BIP0340/aux")||SHA256("BIP0340/aux"). */
|
||||
static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x24dd3219ul;
|
||||
sha->s[1] = 0x4eba7e70ul;
|
||||
sha->s[2] = 0xca0fabb9ul;
|
||||
sha->s[3] = 0x0fa3166dul;
|
||||
sha->s[4] = 0x3afbe4b1ul;
|
||||
sha->s[5] = 0x4c44df97ul;
|
||||
sha->s[6] = 0x4aac2739ul;
|
||||
sha->s[7] = 0x249e850aul;
|
||||
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* algo16 argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340
|
||||
* by using the correct tagged hash function. */
|
||||
static const unsigned char bip340_algo16[16] = "BIP0340/nonce\0\0\0";
|
||||
|
||||
static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char masked_key[32];
|
||||
int i;
|
||||
|
||||
if (algo16 == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha);
|
||||
secp256k1_sha256_write(&sha, data, 32);
|
||||
secp256k1_sha256_finalize(&sha, masked_key);
|
||||
for (i = 0; i < 32; i++) {
|
||||
masked_key[i] ^= key32[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Tag the hash with algo16 which is important to avoid nonce reuse across
|
||||
* algorithms. If this nonce function is used in BIP-340 signing as defined
|
||||
* in the spec, an optimized tagging implementation is used. */
|
||||
if (memcmp(algo16, bip340_algo16, 16) == 0) {
|
||||
secp256k1_nonce_function_bip340_sha256_tagged(&sha);
|
||||
} else {
|
||||
int algo16_len = 16;
|
||||
/* Remove terminating null bytes */
|
||||
while (algo16_len > 0 && !algo16[algo16_len - 1]) {
|
||||
algo16_len--;
|
||||
}
|
||||
secp256k1_sha256_initialize_tagged(&sha, algo16, algo16_len);
|
||||
}
|
||||
|
||||
/* Hash (masked-)key||pk||msg using the tagged hash as per the spec */
|
||||
if (data != NULL) {
|
||||
secp256k1_sha256_write(&sha, masked_key, 32);
|
||||
} else {
|
||||
secp256k1_sha256_write(&sha, key32, 32);
|
||||
}
|
||||
secp256k1_sha256_write(&sha, xonly_pk32, 32);
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
secp256k1_sha256_finalize(&sha, nonce32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64) {
|
||||
(void) ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(in64 != NULL);
|
||||
memcpy(sig->data, in64, 64);
|
||||
return 1;
|
||||
const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340 = nonce_function_bip340;
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("BIP0340/challenge")||SHA256("BIP0340/challenge"). */
|
||||
static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x9cecba11ul;
|
||||
sha->s[1] = 0x23925381ul;
|
||||
sha->s[2] = 0x11679112ul;
|
||||
sha->s[3] = 0xd1627e0ful;
|
||||
sha->s[4] = 0x97c87550ul;
|
||||
sha->s[5] = 0x003cc765ul;
|
||||
sha->s[6] = 0x90f61164ul;
|
||||
sha->s[7] = 0x33e9b66aul;
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, secp256k1_schnorrsig *sig, int *nonce_is_negated, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, void *ndata) {
|
||||
secp256k1_scalar x;
|
||||
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) {
|
||||
secp256k1_scalar sk;
|
||||
secp256k1_scalar e;
|
||||
secp256k1_scalar k;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge pk;
|
||||
secp256k1_ge r;
|
||||
secp256k1_sha256 sha;
|
||||
int overflow;
|
||||
unsigned char buf[33];
|
||||
size_t buflen = sizeof(buf);
|
||||
unsigned char buf[32] = { 0 };
|
||||
unsigned char pk_buf[32];
|
||||
unsigned char seckey[32];
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
ARG_CHECK(keypair != NULL);
|
||||
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_bipschnorr;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&x, seckey, &overflow);
|
||||
/* Fail if the secret key is invalid. */
|
||||
if (overflow || secp256k1_scalar_is_zero(&x)) {
|
||||
memset(sig, 0, sizeof(*sig));
|
||||
return 0;
|
||||
noncefp = secp256k1_nonce_function_bip340;
|
||||
}
|
||||
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pkj, &x);
|
||||
secp256k1_ge_set_gej(&pk, &pkj);
|
||||
|
||||
if (!noncefp(buf, msg32, seckey, NULL, (void*)ndata, 0)) {
|
||||
return 0;
|
||||
ret &= secp256k1_keypair_load(ctx, &sk, &pk, keypair);
|
||||
/* Because we are signing for a x-only pubkey, the secret key is negated
|
||||
* before signing if the point corresponding to the secret key does not
|
||||
* have an even Y. */
|
||||
if (secp256k1_fe_is_odd(&pk.y)) {
|
||||
secp256k1_scalar_negate(&sk, &sk);
|
||||
}
|
||||
|
||||
secp256k1_scalar_get_b32(seckey, &sk);
|
||||
secp256k1_fe_get_b32(pk_buf, &pk.x);
|
||||
ret &= !!noncefp(buf, msg32, seckey, pk_buf, bip340_algo16, ndata);
|
||||
secp256k1_scalar_set_b32(&k, buf, NULL);
|
||||
if (secp256k1_scalar_is_zero(&k)) {
|
||||
return 0;
|
||||
}
|
||||
ret &= !secp256k1_scalar_is_zero(&k);
|
||||
secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
|
||||
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k);
|
||||
secp256k1_ge_set_gej(&r, &rj);
|
||||
|
||||
if (nonce_is_negated != NULL) {
|
||||
*nonce_is_negated = 0;
|
||||
}
|
||||
if (!secp256k1_fe_is_quad_var(&r.y)) {
|
||||
/* We declassify r to allow using it as a branch point. This is fine
|
||||
* because r is not a secret. */
|
||||
secp256k1_declassify(ctx, &r, sizeof(r));
|
||||
secp256k1_fe_normalize_var(&r.y);
|
||||
if (secp256k1_fe_is_odd(&r.y)) {
|
||||
secp256k1_scalar_negate(&k, &k);
|
||||
if (nonce_is_negated != NULL) {
|
||||
*nonce_is_negated = 1;
|
||||
}
|
||||
}
|
||||
secp256k1_fe_normalize(&r.x);
|
||||
secp256k1_fe_get_b32(&sig->data[0], &r.x);
|
||||
secp256k1_fe_normalize_var(&r.x);
|
||||
secp256k1_fe_get_b32(&sig64[0], &r.x);
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, &sig->data[0], 32);
|
||||
secp256k1_eckey_pubkey_serialize(&pk, buf, &buflen, 1);
|
||||
secp256k1_sha256_write(&sha, buf, buflen);
|
||||
/* tagged hash(r.x, pk.x, msg32) */
|
||||
secp256k1_schnorrsig_sha256_tagged(&sha);
|
||||
secp256k1_sha256_write(&sha, &sig64[0], 32);
|
||||
secp256k1_sha256_write(&sha, pk_buf, sizeof(pk_buf));
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
|
||||
/* Set scalar e to the challenge hash modulo the curve order as per
|
||||
* BIP340. */
|
||||
secp256k1_scalar_set_b32(&e, buf, NULL);
|
||||
secp256k1_scalar_mul(&e, &e, &x);
|
||||
secp256k1_scalar_mul(&e, &e, &sk);
|
||||
secp256k1_scalar_add(&e, &e, &k);
|
||||
secp256k1_scalar_get_b32(&sig64[32], &e);
|
||||
|
||||
secp256k1_scalar_get_b32(&sig->data[32], &e);
|
||||
memczero(sig64, 64, !ret);
|
||||
secp256k1_scalar_clear(&k);
|
||||
secp256k1_scalar_clear(&x);
|
||||
secp256k1_scalar_clear(&sk);
|
||||
memset(seckey, 0, sizeof(seckey));
|
||||
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Helper function for verification and batch verification.
|
||||
* Computes R = sG - eP. */
|
||||
static int secp256k1_schnorrsig_real_verify(const secp256k1_context* ctx, secp256k1_gej *rj, const secp256k1_scalar *s, const secp256k1_scalar *e, const secp256k1_pubkey *pk) {
|
||||
secp256k1_scalar nege;
|
||||
secp256k1_ge pkp;
|
||||
secp256k1_gej pkj;
|
||||
|
||||
secp256k1_scalar_negate(&nege, e);
|
||||
|
||||
if (!secp256k1_pubkey_load(ctx, &pkp, pk)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&pkj, &pkp);
|
||||
|
||||
/* rj = s*G + (-e)*pkj */
|
||||
secp256k1_ecmult(&ctx->ecmult_ctx, rj, &pkj, &nege, s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk) {
|
||||
int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_xonly_pubkey *pubkey) {
|
||||
secp256k1_scalar s;
|
||||
secp256k1_scalar e;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge pk;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_fe rx;
|
||||
secp256k1_ge r;
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char buf[33];
|
||||
size_t buflen = sizeof(buf);
|
||||
unsigned char buf[32];
|
||||
int overflow;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(pk != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
if (!secp256k1_fe_set_b32(&rx, &sig->data[0])) {
|
||||
if (!secp256k1_fe_set_b32(&rx, &sig64[0])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_b32(&s, &sig->data[32], &overflow);
|
||||
secp256k1_scalar_set_b32(&s, &sig64[32], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, &sig->data[0], 32);
|
||||
secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk, SECP256K1_EC_COMPRESSED);
|
||||
secp256k1_sha256_write(&sha, buf, buflen);
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_schnorrsig_sha256_tagged(&sha);
|
||||
secp256k1_sha256_write(&sha, &sig64[0], 32);
|
||||
secp256k1_fe_get_b32(buf, &pk.x);
|
||||
secp256k1_sha256_write(&sha, buf, sizeof(buf));
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
secp256k1_scalar_set_b32(&e, buf, NULL);
|
||||
|
||||
if (!secp256k1_schnorrsig_real_verify(ctx, &rj, &s, &e, pk)
|
||||
|| !secp256k1_gej_has_quad_y_var(&rj) /* fails if rj is infinity */
|
||||
|| !secp256k1_gej_eq_x_var(&rx, &rj)) {
|
||||
/* Compute rj = s*G + (-e)*pkj */
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
secp256k1_gej_set_ge(&pkj, &pk);
|
||||
secp256k1_ecmult(&ctx->ecmult_ctx, &rj, &pkj, &e, &s);
|
||||
|
||||
secp256k1_ge_set_gej_var(&r, &rj);
|
||||
if (secp256k1_ge_is_infinity(&r)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Data that is used by the batch verification ecmult callback */
|
||||
typedef struct {
|
||||
const secp256k1_context *ctx;
|
||||
/* Seed for the random number generator */
|
||||
unsigned char chacha_seed[32];
|
||||
/* Caches randomizers generated by the PRNG which returns two randomizers per call. Caching
|
||||
* avoids having to call the PRNG twice as often. The very first randomizer will be set to 1 and
|
||||
* the PRNG is called at every odd indexed schnorrsig to fill the cache. */
|
||||
secp256k1_scalar randomizer_cache[2];
|
||||
/* Signature, message, public key tuples to verify */
|
||||
const secp256k1_schnorrsig *const *sig;
|
||||
const unsigned char *const *msg32;
|
||||
const secp256k1_pubkey *const *pk;
|
||||
size_t n_sigs;
|
||||
} secp256k1_schnorrsig_verify_ecmult_context;
|
||||
|
||||
/* Callback function which is called by ecmult_multi in order to convert the ecmult_context
|
||||
* consisting of signature, message and public key tuples into scalars and points. */
|
||||
static int secp256k1_schnorrsig_verify_batch_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
||||
secp256k1_schnorrsig_verify_ecmult_context *ecmult_context = (secp256k1_schnorrsig_verify_ecmult_context *) data;
|
||||
|
||||
if (idx % 4 == 2) {
|
||||
/* Every idx corresponds to a (scalar,point)-tuple. So this callback is called with 4
|
||||
* consecutive tuples before we need to call the RNG for new randomizers:
|
||||
* (-randomizer_cache[0], R1)
|
||||
* (-randomizer_cache[0]*e1, P1)
|
||||
* (-randomizer_cache[1], R2)
|
||||
* (-randomizer_cache[1]*e2, P2) */
|
||||
secp256k1_scalar_chacha20(&ecmult_context->randomizer_cache[0], &ecmult_context->randomizer_cache[1], ecmult_context->chacha_seed, idx / 4);
|
||||
}
|
||||
|
||||
/* R */
|
||||
if (idx % 2 == 0) {
|
||||
secp256k1_fe rx;
|
||||
*sc = ecmult_context->randomizer_cache[(idx / 2) % 2];
|
||||
if (!secp256k1_fe_set_b32(&rx, &ecmult_context->sig[idx / 2]->data[0])) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ge_set_xquad(pt, &rx)) {
|
||||
return 0;
|
||||
}
|
||||
/* eP */
|
||||
} else {
|
||||
unsigned char buf[33];
|
||||
size_t buflen = sizeof(buf);
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, &ecmult_context->sig[idx / 2]->data[0], 32);
|
||||
secp256k1_ec_pubkey_serialize(ecmult_context->ctx, buf, &buflen, ecmult_context->pk[idx / 2], SECP256K1_EC_COMPRESSED);
|
||||
secp256k1_sha256_write(&sha, buf, buflen);
|
||||
secp256k1_sha256_write(&sha, ecmult_context->msg32[idx / 2], 32);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
|
||||
secp256k1_scalar_set_b32(sc, buf, NULL);
|
||||
secp256k1_scalar_mul(sc, sc, &ecmult_context->randomizer_cache[(idx / 2) % 2]);
|
||||
|
||||
if (!secp256k1_pubkey_load(ecmult_context->ctx, pt, ecmult_context->pk[idx / 2])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Helper function for batch verification. Hashes signature verification data into the
|
||||
* randomization seed and initializes ecmult_context.
|
||||
*
|
||||
* Returns 1 if the randomizer was successfully initialized.
|
||||
*
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: ecmult_context: context for batch_ecmult_callback
|
||||
* In/Out sha: an initialized sha256 object which hashes the schnorrsig input in order to get a
|
||||
* seed for the randomizer PRNG
|
||||
* In: sig: array of signatures, or NULL if there are no signatures
|
||||
* msg32: array of messages, or NULL if there are no signatures
|
||||
* pk: array of public keys, or NULL if there are no signatures
|
||||
* n_sigs: number of signatures in above arrays (must be 0 if they are NULL)
|
||||
*/
|
||||
static int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_context *ctx, secp256k1_schnorrsig_verify_ecmult_context *ecmult_context, secp256k1_sha256 *sha, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) {
|
||||
size_t i;
|
||||
|
||||
if (n_sigs > 0) {
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(pk != NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_sigs; i++) {
|
||||
unsigned char buf[33];
|
||||
size_t buflen = sizeof(buf);
|
||||
secp256k1_sha256_write(sha, sig[i]->data, 64);
|
||||
secp256k1_sha256_write(sha, msg32[i], 32);
|
||||
secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk[i], SECP256K1_EC_COMPRESSED);
|
||||
secp256k1_sha256_write(sha, buf, buflen);
|
||||
}
|
||||
ecmult_context->ctx = ctx;
|
||||
ecmult_context->sig = sig;
|
||||
ecmult_context->msg32 = msg32;
|
||||
ecmult_context->pk = pk;
|
||||
ecmult_context->n_sigs = n_sigs;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Helper function for batch verification. Sums the s part of all signatures multiplied by their
|
||||
* randomizer.
|
||||
*
|
||||
* Returns 1 if s is successfully summed.
|
||||
*
|
||||
* In/Out: s: the s part of the input sigs is added to this s argument
|
||||
* In: chacha_seed: PRNG seed for computing randomizers
|
||||
* sig: array of signatures, or NULL if there are no signatures
|
||||
* n_sigs: number of signatures in above array (must be 0 if they are NULL)
|
||||
*/
|
||||
static int secp256k1_schnorrsig_verify_batch_sum_s(secp256k1_scalar *s, unsigned char *chacha_seed, const secp256k1_schnorrsig *const *sig, size_t n_sigs) {
|
||||
secp256k1_scalar randomizer_cache[2];
|
||||
size_t i;
|
||||
|
||||
secp256k1_scalar_set_int(&randomizer_cache[0], 1);
|
||||
for (i = 0; i < n_sigs; i++) {
|
||||
int overflow;
|
||||
secp256k1_scalar term;
|
||||
if (i % 2 == 1) {
|
||||
secp256k1_scalar_chacha20(&randomizer_cache[0], &randomizer_cache[1], chacha_seed, i / 2);
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_b32(&term, &sig[i]->data[32], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_mul(&term, &term, &randomizer_cache[i % 2]);
|
||||
secp256k1_scalar_add(s, s, &term);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* schnorrsig batch verification.
|
||||
* Seeds a random number generator with the inputs and derives a random number ai for every
|
||||
* signature i. Fails if y-coordinate of any R is not a quadratic residue or if
|
||||
* 0 != -(s1 + a2*s2 + ... + au*su)G + R1 + a2*R2 + ... + au*Ru + e1*P1 + (a2*e2)P2 + ... + (au*eu)Pu. */
|
||||
int secp256k1_schnorrsig_verify_batch(const secp256k1_context *ctx, secp256k1_scratch *scratch, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) {
|
||||
secp256k1_schnorrsig_verify_ecmult_context ecmult_context;
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_scalar s;
|
||||
secp256k1_gej rj;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(scratch != NULL);
|
||||
/* Check that n_sigs is less than half of the maximum size_t value. This is necessary because
|
||||
* the number of points given to ecmult_multi is 2*n_sigs. */
|
||||
ARG_CHECK(n_sigs <= SIZE_MAX / 2);
|
||||
/* Check that n_sigs is less than 2^31 to ensure the same behavior of this function on 32-bit
|
||||
* and 64-bit platforms. */
|
||||
ARG_CHECK(n_sigs < ((uint32_t)1 << 31));
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
if (!secp256k1_schnorrsig_verify_batch_init_randomizer(ctx, &ecmult_context, &sha, sig, msg32, pk, n_sigs)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, ecmult_context.chacha_seed);
|
||||
secp256k1_scalar_set_int(&ecmult_context.randomizer_cache[0], 1);
|
||||
|
||||
secp256k1_scalar_clear(&s);
|
||||
if (!secp256k1_schnorrsig_verify_batch_sum_s(&s, ecmult_context.chacha_seed, sig, n_sigs)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_negate(&s, &s);
|
||||
|
||||
return secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &rj, &s, secp256k1_schnorrsig_verify_batch_ecmult_callback, (void *) &ecmult_context, 2 * n_sigs)
|
||||
&& secp256k1_gej_is_infinity(&rj);
|
||||
secp256k1_fe_normalize_var(&r.y);
|
||||
return !secp256k1_fe_is_odd(&r.y) &&
|
||||
secp256k1_fe_equal_var(&rx, &r.x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -241,7 +241,7 @@ void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scr
|
||||
* of the software. This is setup for use with valgrind but could be substituted with
|
||||
* the appropriate instrumentation for other analysis tools.
|
||||
*/
|
||||
static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, void *p, size_t len) {
|
||||
static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, const void *p, size_t len) {
|
||||
#if defined(VALGRIND)
|
||||
if (EXPECT(ctx->declassify,0)) VALGRIND_MAKE_MEM_DEFINED(p, len);
|
||||
#else
|
||||
@ -449,29 +449,6 @@ static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *off
|
||||
*offset += len;
|
||||
}
|
||||
|
||||
/* This nonce function is described in BIP-schnorr
|
||||
* (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki) */
|
||||
static int nonce_function_bipschnorr(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
|
||||
secp256k1_sha256 sha;
|
||||
(void) counter;
|
||||
VERIFY_CHECK(counter == 0);
|
||||
|
||||
/* Hash x||msg as per the spec */
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, key32, 32);
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
/* Hash in algorithm, which is not in the spec, but may be critical to
|
||||
* users depending on it to avoid nonce reuse across algorithms. */
|
||||
if (algo16 != NULL) {
|
||||
secp256k1_sha256_write(&sha, algo16, 16);
|
||||
}
|
||||
if (data != NULL) {
|
||||
secp256k1_sha256_write(&sha, data, 32);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, nonce32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
|
||||
unsigned char keydata[112];
|
||||
unsigned int offset = 0;
|
||||
@ -502,7 +479,6 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
|
||||
return 1;
|
||||
}
|
||||
|
||||
const secp256k1_nonce_function secp256k1_nonce_function_bipschnorr = nonce_function_bipschnorr;
|
||||
const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
|
||||
const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;
|
||||
|
||||
@ -587,10 +563,21 @@ int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) {
|
||||
static int secp256k1_ec_pubkey_create_helper(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_scalar *seckey_scalar, secp256k1_ge *p, const unsigned char *seckey) {
|
||||
secp256k1_gej pj;
|
||||
int ret;
|
||||
|
||||
ret = secp256k1_scalar_set_b32_seckey(seckey_scalar, seckey);
|
||||
secp256k1_scalar_cmov(seckey_scalar, &secp256k1_scalar_one, !ret);
|
||||
|
||||
secp256k1_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar);
|
||||
secp256k1_ge_set_gej(p, &pj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) {
|
||||
secp256k1_ge p;
|
||||
secp256k1_scalar sec;
|
||||
secp256k1_scalar seckey_scalar;
|
||||
int ret = 0;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
@ -598,15 +585,11 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(seckey != NULL);
|
||||
|
||||
ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
|
||||
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_one, !ret);
|
||||
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
|
||||
secp256k1_ge_set_gej(&p, &pj);
|
||||
ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey);
|
||||
secp256k1_pubkey_save(pubkey, &p);
|
||||
memczero(pubkey, sizeof(*pubkey), !ret);
|
||||
|
||||
secp256k1_scalar_clear(&sec);
|
||||
secp256k1_scalar_clear(&seckey_scalar);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -644,24 +627,31 @@ int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *p
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ec_seckey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
|
||||
|
||||
static int secp256k1_ec_seckey_tweak_add_helper(secp256k1_scalar *sec, const unsigned char *tweak) {
|
||||
secp256k1_scalar term;
|
||||
int overflow = 0;
|
||||
int ret = 0;
|
||||
|
||||
secp256k1_scalar_set_b32(&term, tweak, &overflow);
|
||||
ret = (!overflow) & secp256k1_eckey_privkey_tweak_add(sec, &term);
|
||||
secp256k1_scalar_clear(&term);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ec_seckey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
|
||||
secp256k1_scalar sec;
|
||||
int ret = 0;
|
||||
int overflow = 0;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
ARG_CHECK(tweak != NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&term, tweak, &overflow);
|
||||
ret = secp256k1_scalar_set_b32_seckey(&sec, seckey);
|
||||
|
||||
ret &= (!overflow) & secp256k1_eckey_privkey_tweak_add(&sec, &term);
|
||||
ret &= secp256k1_ec_seckey_tweak_add_helper(&sec, tweak);
|
||||
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
|
||||
secp256k1_scalar_get_b32(seckey, &sec);
|
||||
|
||||
secp256k1_scalar_clear(&sec);
|
||||
secp256k1_scalar_clear(&term);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -669,25 +659,26 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *
|
||||
return secp256k1_ec_seckey_tweak_add(ctx, seckey, tweak);
|
||||
}
|
||||
|
||||
static int secp256k1_ec_pubkey_tweak_add_helper(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_ge *p, const unsigned char *tweak) {
|
||||
secp256k1_scalar term;
|
||||
int overflow = 0;
|
||||
secp256k1_scalar_set_b32(&term, tweak, &overflow);
|
||||
return !overflow && secp256k1_eckey_pubkey_tweak_add(ecmult_ctx, p, &term);
|
||||
}
|
||||
|
||||
int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) {
|
||||
secp256k1_ge p;
|
||||
secp256k1_scalar term;
|
||||
int ret = 0;
|
||||
int overflow = 0;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
ARG_CHECK(tweak != NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&term, tweak, &overflow);
|
||||
ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey);
|
||||
ret = secp256k1_pubkey_load(ctx, &p, pubkey);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
ret = ret && secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &p, tweak);
|
||||
if (ret) {
|
||||
if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) {
|
||||
secp256k1_pubkey_save(pubkey, &p);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -777,6 +768,14 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
|
||||
# include "modules/ecdh/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_RECOVERY
|
||||
# include "modules/recovery/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_EXTRAKEYS
|
||||
# include "modules/extrakeys/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_SCHNORRSIG
|
||||
# include "modules/schnorrsig/main_impl.h"
|
||||
#endif
|
||||
@ -785,10 +784,6 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
|
||||
# include "modules/musig/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_RECOVERY
|
||||
# include "modules/recovery/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_GENERATOR
|
||||
# include "modules/generator/main_impl.h"
|
||||
#endif
|
||||
@ -804,3 +799,4 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
|
||||
#ifdef ENABLE_MODULE_SURJECTIONPROOF
|
||||
# include "modules/surjection/main_impl.h"
|
||||
#endif
|
||||
|
||||
|
@ -38,4 +38,7 @@ static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len);
|
||||
/** Generate a pseudorandom 64-bit integer in the range min..max, inclusive. */
|
||||
static int64_t secp256k1_rands64(uint64_t min, uint64_t max);
|
||||
|
||||
/** Flip a single random bit in a byte array */
|
||||
static void secp256k1_rand_flip(unsigned char *b, size_t len);
|
||||
|
||||
#endif /* SECP256K1_TESTRAND_H */
|
||||
|
@ -124,4 +124,8 @@ SECP256K1_INLINE static int64_t secp256k1_rands64(uint64_t min, uint64_t max) {
|
||||
return min + (int64_t)r;
|
||||
}
|
||||
|
||||
static void secp256k1_rand_flip(unsigned char *b, size_t len) {
|
||||
b[secp256k1_rand_int(len)] ^= (1 << secp256k1_rand_int(8));
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_TESTRAND_IMPL_H */
|
||||
|
25
src/tests.c
25
src/tests.c
@ -5504,10 +5504,6 @@ void run_ecdsa_openssl(void) {
|
||||
# include "modules/ecdh/tests_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_SCHNORRSIG
|
||||
# include "modules/schnorrsig/tests_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
# include "modules/musig/tests_impl.h"
|
||||
#endif
|
||||
@ -5532,6 +5528,14 @@ void run_ecdsa_openssl(void) {
|
||||
# include "modules/surjection/tests_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_EXTRAKEYS
|
||||
# include "modules/extrakeys/tests_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_SCHNORRSIG
|
||||
# include "modules/schnorrsig/tests_impl.h"
|
||||
#endif
|
||||
|
||||
void run_memczero_test(void) {
|
||||
unsigned char buf1[6] = {1, 2, 3, 4, 5, 6};
|
||||
unsigned char buf2[sizeof(buf1)];
|
||||
@ -5824,11 +5828,6 @@ int main(int argc, char **argv) {
|
||||
run_ecdh_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_SCHNORRSIG
|
||||
/* Schnorrsig tests */
|
||||
run_schnorrsig_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
run_musig_tests();
|
||||
#endif
|
||||
@ -5865,6 +5864,14 @@ int main(int argc, char **argv) {
|
||||
run_surjection_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_EXTRAKEYS
|
||||
run_extrakeys_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_SCHNORRSIG
|
||||
run_schnorrsig_tests();
|
||||
#endif
|
||||
|
||||
/* util tests */
|
||||
run_memczero_test();
|
||||
|
||||
|
@ -17,6 +17,14 @@
|
||||
# include "include/secp256k1_recovery.h"
|
||||
#endif
|
||||
|
||||
#if ENABLE_MODULE_EXTRAKEYS
|
||||
# include "include/secp256k1_extrakeys.h"
|
||||
#endif
|
||||
|
||||
#if ENABLE_MODULE_SCHNORRSIG
|
||||
#include "include/secp256k1_schnorrsig.h"
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
secp256k1_context* ctx;
|
||||
secp256k1_ecdsa_signature signature;
|
||||
@ -33,6 +41,9 @@ int main(void) {
|
||||
secp256k1_ecdsa_recoverable_signature recoverable_signature;
|
||||
int recid;
|
||||
#endif
|
||||
#if ENABLE_MODULE_EXTRAKEYS
|
||||
secp256k1_keypair keypair;
|
||||
#endif
|
||||
|
||||
if (!RUNNING_ON_VALGRIND) {
|
||||
fprintf(stderr, "This test can only usefully be run inside valgrind.\n");
|
||||
@ -50,7 +61,9 @@ int main(void) {
|
||||
msg[i] = i + 1;
|
||||
}
|
||||
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_DECLASSIFY);
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN
|
||||
| SECP256K1_CONTEXT_VERIFY
|
||||
| SECP256K1_CONTEXT_DECLASSIFY);
|
||||
|
||||
/* Test keygen. */
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
|
||||
@ -115,6 +128,30 @@ int main(void) {
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret);
|
||||
|
||||
/* Test keypair_create and keypair_xonly_tweak_add. */
|
||||
#if ENABLE_MODULE_EXTRAKEYS
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, key);
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
/* The tweak is not treated as a secret in keypair_tweak_add */
|
||||
VALGRIND_MAKE_MEM_DEFINED(msg, 32);
|
||||
ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg);
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
#endif
|
||||
|
||||
#if ENABLE_MODULE_SCHNORRSIG
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, key);
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
ret = secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, NULL);
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
#endif
|
||||
|
||||
secp256k1_context_destroy(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user