Skip to content

Commit 8ab24e8

Browse files
Merge #558: Add schnorrsig module which implements BIP-340 compliant signatures
f431b3f valgrind_ctime_test: Add schnorrsig_sign (Jonas Nick) 16ffa9d schnorrsig: Add taproot test case (Jonas Nick) 8dfd53e schnorrsig: Add benchmark for sign and verify (Jonas Nick) 4e43520 schnorrsig: Add BIP-340 compatible signing and verification (Jonas Nick) 7332d2d schnorrsig: Add BIP-340 nonce function (Jonas Nick) 7a703fd schnorrsig: Init empty experimental module (Jonas Nick) eabd9bc Allow initializing tagged sha256 (Jonas Nick) 6fcb5b8 extrakeys: Add keypair_xonly_tweak_add (Jonas Nick) 5825446 extrakeys: Add keypair struct with create, pub and pub_xonly (Jonas Nick) f001034 Separate helper functions for pubkey_create and seckey_tweak_add (Jonas Nick) 910d9c2 extrakeys: Add xonly_pubkey_tweak_add & xonly_pubkey_tweak_add_test (Jonas Nick) 176bfb1 Separate helper function for ec_pubkey_tweak_add (Jonas Nick) 4cd2ee4 extrakeys: Add xonly_pubkey with serialize, parse and from_pubkey (Jonas Nick) 47e6618 extrakeys: Init empty experimental module (Jonas Nick) 3e08b02 Make the secp256k1_declassify argument constant (Jonas Nick) Pull request description: This PR implements signing, verification and batch verification as described in [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) in an experimental module named `schnorrsig`. It includes the test vectors and a benchmarking tool. This PR also adds a module `extrakeys` that allows [BIP-341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki)-style key tweaking. (Adding ChaCha20 as a CSPRNG and batch verification was moved to PR #760). In order to enable the module run `./configure` with `--enable-experimental --enable-module-schnorrsig`. Based on apoelstra's work. ACKs for top commit: gmaxwell: ACK f431b3f (exactly matches the previous post-fixup version which I have already reviewed and tested) sipa: ACK f431b3f real-or-random: ACK f431b3f careful code review Tree-SHA512: e15e849c7bb65cdc5d7b1d6874678e275a71e4514de9d5432ec1700de3ba92aa9f381915813f4729057af152d90eea26aabb976ed297019c5767e59cf0bbc693
2 parents f3733c5 + f431b3f commit 8ab24e8

20 files changed

+2445
-31
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
bench_inv
22
bench_ecdh
33
bench_ecmult
4+
bench_schnorrsig
45
bench_sign
56
bench_verify
6-
bench_schnorr_verify
77
bench_recover
88
bench_internal
99
tests

.travis.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,19 @@ compiler:
1717
- gcc
1818
env:
1919
global:
20-
- WIDEMUL=auto BIGNUM=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2
20+
- WIDEMUL=auto BIGNUM=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no SCHNORRSIG=no EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2
2121
matrix:
2222
- WIDEMUL=int64 RECOVERY=yes
23-
- WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes
23+
- WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes
2424
- WIDEMUL=int64 ENDOMORPHISM=yes
2525
- WIDEMUL=int128
26-
- WIDEMUL=int128 RECOVERY=yes
26+
- WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes
2727
- WIDEMUL=int128 ENDOMORPHISM=yes
28-
- WIDEMUL=int128 ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
28+
- WIDEMUL=int128 ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes
2929
- WIDEMUL=int128 ASM=x86_64
3030
- WIDEMUL=int128 ENDOMORPHISM=yes ASM=x86_64
3131
- BIGNUM=no
32-
- BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes
32+
- BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes
3333
- BIGNUM=no STATICPRECOMPUTATION=no
3434
- BUILD=distcheck CTIMETEST= BENCH=
3535
- CPPFLAGS=-DDETERMINISTIC

Makefile.am

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,11 @@ endif
154154
if ENABLE_MODULE_RECOVERY
155155
include src/modules/recovery/Makefile.am.include
156156
endif
157+
158+
if ENABLE_MODULE_EXTRAKEYS
159+
include src/modules/extrakeys/Makefile.am.include
160+
endif
161+
162+
if ENABLE_MODULE_SCHNORRSIG
163+
include src/modules/schnorrsig/Makefile.am.include
164+
endif

configure.ac

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ AC_ARG_ENABLE(module_recovery,
136136
[enable_module_recovery=$enableval],
137137
[enable_module_recovery=no])
138138

139+
AC_ARG_ENABLE(module_extrakeys,
140+
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module (experimental)]),
141+
[enable_module_extrakeys=$enableval],
142+
[enable_module_extrakeys=no])
143+
144+
AC_ARG_ENABLE(module_schnorrsig,
145+
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]),
146+
[enable_module_schnorrsig=$enableval],
147+
[enable_module_schnorrsig=no])
148+
139149
AC_ARG_ENABLE(external_default_callbacks,
140150
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]),
141151
[use_external_default_callbacks=$enableval],
@@ -421,6 +431,17 @@ if test x"$enable_module_recovery" = x"yes"; then
421431
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
422432
fi
423433

434+
if test x"$enable_module_schnorrsig" = x"yes"; then
435+
AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module])
436+
enable_module_extrakeys=yes
437+
fi
438+
439+
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
440+
# module to set enable_module_extrakeys=yes
441+
if test x"$enable_module_extrakeys" = x"yes"; then
442+
AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module])
443+
fi
444+
424445
if test x"$use_external_asm" = x"yes"; then
425446
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
426447
fi
@@ -434,11 +455,19 @@ if test x"$enable_experimental" = x"yes"; then
434455
AC_MSG_NOTICE([WARNING: experimental build])
435456
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
436457
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
458+
AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys])
459+
AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig])
437460
AC_MSG_NOTICE([******])
438461
else
439462
if test x"$enable_module_ecdh" = x"yes"; then
440463
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
441464
fi
465+
if test x"$enable_module_extrakeys" = x"yes"; then
466+
AC_MSG_ERROR([extrakeys module is experimental. Use --enable-experimental to allow.])
467+
fi
468+
if test x"$enable_module_schnorrsig" = x"yes"; then
469+
AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.])
470+
fi
442471
if test x"$set_asm" = x"arm"; then
443472
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
444473
fi
@@ -457,6 +486,8 @@ AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
457486
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
458487
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
459488
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
489+
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
490+
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
460491
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
461492
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
462493

@@ -476,6 +507,8 @@ echo " with benchmarks = $use_benchmark"
476507
echo " with coverage = $enable_coverage"
477508
echo " module ecdh = $enable_module_ecdh"
478509
echo " module recovery = $enable_module_recovery"
510+
echo " module extrakeys = $enable_module_extrakeys"
511+
echo " module schnorrsig = $enable_module_schnorrsig"
479512
echo
480513
echo " asm = $set_asm"
481514
echo " bignum = $set_bignum"

contrib/travis.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ fi
1717
--with-test-override-wide-multiply="$WIDEMUL" --with-bignum="$BIGNUM" --with-asm="$ASM" \
1818
--enable-ecmult-static-precomputation="$STATICPRECOMPUTATION" --with-ecmult-gen-precision="$ECMULTGENPRECISION" \
1919
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
20+
--enable-module-schnorrsig="$SCHNORRSIG" \
2021
--host="$HOST" $EXTRAFLAGS
2122

2223
if [ -n "$BUILD" ]

include/secp256k1_extrakeys.h

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
#ifndef SECP256K1_EXTRAKEYS_H
2+
#define SECP256K1_EXTRAKEYS_H
3+
4+
#include "secp256k1.h"
5+
6+
#ifdef __cplusplus
7+
extern "C" {
8+
#endif
9+
10+
/** Opaque data structure that holds a parsed and valid "x-only" public key.
11+
* An x-only pubkey encodes a point whose Y coordinate is even. It is
12+
* serialized using only its X coordinate (32 bytes). See BIP-340 for more
13+
* information about x-only pubkeys.
14+
*
15+
* The exact representation of data inside is implementation defined and not
16+
* guaranteed to be portable between different platforms or versions. It is
17+
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
18+
* If you need to convert to a format suitable for storage, transmission, or
19+
* comparison, use secp256k1_xonly_pubkey_serialize and
20+
* secp256k1_xonly_pubkey_parse.
21+
*/
22+
typedef struct {
23+
unsigned char data[64];
24+
} secp256k1_xonly_pubkey;
25+
26+
/** Opaque data structure that holds a keypair consisting of a secret and a
27+
* public key.
28+
*
29+
* The exact representation of data inside is implementation defined and not
30+
* guaranteed to be portable between different platforms or versions. It is
31+
* however guaranteed to be 96 bytes in size, and can be safely copied/moved.
32+
*/
33+
typedef struct {
34+
unsigned char data[96];
35+
} secp256k1_keypair;
36+
37+
/** Parse a 32-byte sequence into a xonly_pubkey object.
38+
*
39+
* Returns: 1 if the public key was fully valid.
40+
* 0 if the public key could not be parsed or is invalid.
41+
*
42+
* Args: ctx: a secp256k1 context object (cannot be NULL).
43+
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
44+
* parsed version of input. If not, it's set to an invalid value.
45+
* (cannot be NULL).
46+
* In: input32: pointer to a serialized xonly_pubkey (cannot be NULL)
47+
*/
48+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
49+
const secp256k1_context* ctx,
50+
secp256k1_xonly_pubkey* pubkey,
51+
const unsigned char *input32
52+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
53+
54+
/** Serialize an xonly_pubkey object into a 32-byte sequence.
55+
*
56+
* Returns: 1 always.
57+
*
58+
* Args: ctx: a secp256k1 context object (cannot be NULL).
59+
* Out: output32: a pointer to a 32-byte array to place the serialized key in
60+
* (cannot be NULL).
61+
* In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an
62+
* initialized public key (cannot be NULL).
63+
*/
64+
SECP256K1_API int secp256k1_xonly_pubkey_serialize(
65+
const secp256k1_context* ctx,
66+
unsigned char *output32,
67+
const secp256k1_xonly_pubkey* pubkey
68+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
69+
70+
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
71+
*
72+
* Returns: 1 if the public key was successfully converted
73+
* 0 otherwise
74+
*
75+
* Args: ctx: pointer to a context object (cannot be NULL)
76+
* Out: xonly_pubkey: pointer to an x-only public key object for placing the
77+
* converted public key (cannot be NULL)
78+
* pk_parity: pointer to an integer that will be set to 1 if the point
79+
* encoded by xonly_pubkey is the negation of the pubkey and
80+
* set to 0 otherwise. (can be NULL)
81+
* In: pubkey: pointer to a public key that is converted (cannot be NULL)
82+
*/
83+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey(
84+
const secp256k1_context* ctx,
85+
secp256k1_xonly_pubkey *xonly_pubkey,
86+
int *pk_parity,
87+
const secp256k1_pubkey *pubkey
88+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
89+
90+
/** Tweak an x-only public key by adding the generator multiplied with tweak32
91+
* to it.
92+
*
93+
* Note that the resulting point can not in general be represented by an x-only
94+
* pubkey because it may have an odd Y coordinate. Instead, the output_pubkey
95+
* is a normal secp256k1_pubkey.
96+
*
97+
* Returns: 0 if the arguments are invalid or the resulting public key would be
98+
* invalid (only when the tweak is the negation of the corresponding
99+
* secret key). 1 otherwise.
100+
*
101+
* Args: ctx: pointer to a context object initialized for verification
102+
* (cannot be NULL)
103+
* Out: output_pubkey: pointer to a public key to store the result. Will be set
104+
* to an invalid value if this function returns 0 (cannot
105+
* be NULL)
106+
* In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to.
107+
* (cannot be NULL).
108+
* tweak32: pointer to a 32-byte tweak. If the tweak is invalid
109+
* according to secp256k1_ec_seckey_verify, this function
110+
* returns 0. For uniformly random 32-byte arrays the
111+
* chance of being invalid is negligible (around 1 in
112+
* 2^128) (cannot be NULL).
113+
*/
114+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
115+
const secp256k1_context* ctx,
116+
secp256k1_pubkey *output_pubkey,
117+
const secp256k1_xonly_pubkey *internal_pubkey,
118+
const unsigned char *tweak32
119+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
120+
121+
/** Checks that a tweaked pubkey is the result of calling
122+
* secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32.
123+
*
124+
* The tweaked pubkey is represented by its 32-byte x-only serialization and
125+
* its pk_parity, which can both be obtained by converting the result of
126+
* tweak_add to a secp256k1_xonly_pubkey.
127+
*
128+
* Note that this alone does _not_ verify that the tweaked pubkey is a
129+
* commitment. If the tweak is not chosen in a specific way, the tweaked pubkey
130+
* can easily be the result of a different internal_pubkey and tweak.
131+
*
132+
* Returns: 0 if the arguments are invalid or the tweaked pubkey is not the
133+
* result of tweaking the internal_pubkey with tweak32. 1 otherwise.
134+
* Args: ctx: pointer to a context object initialized for verification
135+
* (cannot be NULL)
136+
* In: tweaked_pubkey32: pointer to a serialized xonly_pubkey (cannot be NULL)
137+
* tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization
138+
* is passed in as tweaked_pubkey32). This must match the
139+
* pk_parity value that is returned when calling
140+
* secp256k1_xonly_pubkey with the tweaked pubkey, or
141+
* this function will fail.
142+
* internal_pubkey: pointer to an x-only public key object to apply the
143+
* tweak to (cannot be NULL)
144+
* tweak32: pointer to a 32-byte tweak (cannot be NULL)
145+
*/
146+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check(
147+
const secp256k1_context* ctx,
148+
const unsigned char *tweaked_pubkey32,
149+
int tweaked_pk_parity,
150+
const secp256k1_xonly_pubkey *internal_pubkey,
151+
const unsigned char *tweak32
152+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
153+
154+
/** Compute the keypair for a secret key.
155+
*
156+
* Returns: 1: secret was valid, keypair is ready to use
157+
* 0: secret was invalid, try again with a different secret
158+
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
159+
* Out: keypair: pointer to the created keypair (cannot be NULL)
160+
* In: seckey: pointer to a 32-byte secret key (cannot be NULL)
161+
*/
162+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
163+
const secp256k1_context* ctx,
164+
secp256k1_keypair *keypair,
165+
const unsigned char *seckey
166+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
167+
168+
/** Get the public key from a keypair.
169+
*
170+
* Returns: 0 if the arguments are invalid. 1 otherwise.
171+
* Args: ctx: pointer to a context object (cannot be NULL)
172+
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to
173+
* the keypair public key. If not, it's set to an invalid value.
174+
* (cannot be NULL)
175+
* In: keypair: pointer to a keypair (cannot be NULL)
176+
*/
177+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
178+
const secp256k1_context* ctx,
179+
secp256k1_pubkey *pubkey,
180+
const secp256k1_keypair *keypair
181+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
182+
183+
/** Get the x-only public key from a keypair.
184+
*
185+
* This is the same as calling secp256k1_keypair_pub and then
186+
* secp256k1_xonly_pubkey_from_pubkey.
187+
*
188+
* Returns: 0 if the arguments are invalid. 1 otherwise.
189+
* Args: ctx: pointer to a context object (cannot be NULL)
190+
* Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set
191+
* to the keypair public key after converting it to an
192+
* xonly_pubkey. If not, it's set to an invalid value (cannot be
193+
* NULL).
194+
* pk_parity: pointer to an integer that will be set to the pk_parity
195+
* argument of secp256k1_xonly_pubkey_from_pubkey (can be NULL).
196+
* In: keypair: pointer to a keypair (cannot be NULL)
197+
*/
198+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
199+
const secp256k1_context* ctx,
200+
secp256k1_xonly_pubkey *pubkey,
201+
int *pk_parity,
202+
const secp256k1_keypair *keypair
203+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
204+
205+
/** Tweak a keypair by adding tweak32 to the secret key and updating the public
206+
* key accordingly.
207+
*
208+
* Calling this function and then secp256k1_keypair_pub results in the same
209+
* public key as calling secp256k1_keypair_xonly_pub and then
210+
* secp256k1_xonly_pubkey_tweak_add.
211+
*
212+
* Returns: 0 if the arguments are invalid or the resulting keypair would be
213+
* invalid (only when the tweak is the negation of the keypair's
214+
* secret key). 1 otherwise.
215+
*
216+
* Args: ctx: pointer to a context object initialized for verification
217+
* (cannot be NULL)
218+
* In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to
219+
* an invalid value if this function returns 0 (cannot be
220+
* NULL).
221+
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according
222+
* to secp256k1_ec_seckey_verify, this function returns 0. For
223+
* uniformly random 32-byte arrays the chance of being invalid
224+
* is negligible (around 1 in 2^128) (cannot be NULL).
225+
*/
226+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add(
227+
const secp256k1_context* ctx,
228+
secp256k1_keypair *keypair,
229+
const unsigned char *tweak32
230+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
231+
232+
#ifdef __cplusplus
233+
}
234+
#endif
235+
236+
#endif /* SECP256K1_EXTRAKEYS_H */

0 commit comments

Comments
 (0)