Skip to content

Commit f3708a1

Browse files
committed
Merge #117: Add ECDSA adaptor signatures module
b0ffa92 ecdsa_adaptor: add tests (Jesse Posner) 6955af5 ecdsa_adaptor: add ECDSA adaptor signature APIs (Jesse Posner) b508e5d ecdsa_adaptor: add support for proof of discrete logarithm equality (Jesse Posner) d8f3365 ecdsa_adaptor: add nonce function and tags (Jesse Posner) 654cd63 ecdsa_adaptor: initialize project (Jesse Posner) Pull request description: ACKs for top commit: LLFourn: ACK b0ffa92 I've added a small warning to the spec too. jonasnick: ACK b0ffa92 Tree-SHA512: f14e6f32265518d435d4da00a73423615ba900de68c28039ae26ac7ee7b4088db44358741411d96c42bd497db79483ff0766fc2d076d95a9116bcc168b80802d
2 parents 5710eba + b0ffa92 commit f3708a1

13 files changed

+1992
-4
lines changed

.cirrus.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ env:
1717
RANGEPROOF: no
1818
WHITELIST: no
1919
MUSIG: no
20+
ECDSAADAPTOR: no
2021
EXPERIMENTAL: no
2122
CTIMETEST: yes
2223
BENCH: yes
@@ -59,13 +60,13 @@ task:
5960
memory: 1G
6061
matrix: &ENV_MATRIX
6162
- env: {WIDEMUL: int64, RECOVERY: yes}
62-
- env: {WIDEMUL: int64, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes}
63+
- env: {WIDEMUL: int64, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
6364
- env: {WIDEMUL: int128}
6465
- env: {WIDEMUL: int128, RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes}
65-
- env: {WIDEMUL: int128, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes}
66+
- env: {WIDEMUL: int128, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
6667
- env: {WIDEMUL: int128, ASM: x86_64}
6768
- env: {BIGNUM: no}
68-
- env: {BIGNUM: no, RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes}
69+
- env: {BIGNUM: no, RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
6970
- env: {BIGNUM: no, STATICPRECOMPUTATION: no}
7071
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
7172
- env: {CPPFLAGS: -DDETERMINISTIC}
@@ -85,6 +86,7 @@ task:
8586
WHITELIST: yes
8687
GENERATOR: yes
8788
MUSIG: yes
89+
ECDSAADAPTOR: yes
8890
CTIMETEST: no
8991
- env: { ECMULTGENPRECISION: 2 }
9092
- env: { ECMULTGENPRECISION: 8 }
@@ -101,6 +103,7 @@ task:
101103
WHITELIST: yes
102104
GENERATOR: yes
103105
MUSIG: yes
106+
ECDSAADAPTOR: yes
104107
EXTRAFLAGS: "--disable-openssl-tests"
105108
BUILD:
106109
matrix:
@@ -130,6 +133,7 @@ task:
130133
WHITELIST: yes
131134
GENERATOR: yes
132135
MUSIG: yes
136+
ECDSAADAPTOR: yes
133137
matrix:
134138
- env:
135139
CC: i686-linux-gnu-gcc
@@ -227,6 +231,7 @@ task:
227231
WHITELIST: yes
228232
GENERATOR: yes
229233
MUSIG: yes
234+
ECDSAADAPTOR: yes
230235
CTIMETEST: no
231236
<< : *MERGE_BASE
232237
test_script:

Makefile.am

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,6 @@ if ENABLE_MODULE_ECDSA_S2C
189189
include src/modules/ecdsa_s2c/Makefile.am.include
190190
endif
191191

192+
if ENABLE_MODULE_ECDSA_ADAPTOR
193+
include src/modules/ecdsa_adaptor/Makefile.am.include
194+
endif

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Features:
1717
* Suitable for embedded systems.
1818
* Optional module for public key recovery.
1919
* Optional module for ECDH key exchange.
20+
* Optional module for ECDSA adaptor signatures (experimental).
2021

2122
Experimental features have not received enough scrutiny to satisfy the standard of quality of this library but are made available for testing and review by the community. The APIs of these features should not be considered stable.
2223

ci/cirrus.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ valgrind --version || true
1919
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
2020
--enable-module-ecdsa-s2c="$ECDSA_S2C" \
2121
--enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
22-
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG"\
22+
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
2323
--with-valgrind="$WITH_VALGRIND" \
2424
--host="$HOST" $EXTRAFLAGS
2525

configure.ac

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ AC_ARG_ENABLE(module_ecdsa_s2c,
180180
[enable_module_ecdsa_s2c=$enableval],
181181
[enable_module_ecdsa_s2c=no])
182182

183+
AC_ARG_ENABLE(module_ecdsa-adaptor,
184+
AS_HELP_STRING([--enable-module-ecdsa-adaptor],[enable ECDSA adaptor module [default=no]]),
185+
[enable_module_ecdsa_adaptor=$enableval],
186+
[enable_module_ecdsa_adaptor=no])
187+
183188
AC_ARG_ENABLE(external_default_callbacks,
184189
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]),
185190
[use_external_default_callbacks=$enableval],
@@ -580,6 +585,10 @@ if test x"$use_reduced_surjection_proof_size" = x"yes"; then
580585
AC_DEFINE(USE_REDUCED_SURJECTION_PROOF_SIZE, 1, [Define this symbol to reduce SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS to 16, disabling parsing and verification])
581586
fi
582587

588+
if test x"$enable_module_ecdsa_adaptor" = x"yes"; then
589+
AC_DEFINE(ENABLE_MODULE_ECDSA_ADAPTOR, 1, [Define this symbol to enable the ECDSA adaptor module])
590+
fi
591+
583592
###
584593
### Check for --enable-experimental if necessary
585594
###
@@ -596,6 +605,7 @@ if test x"$enable_experimental" = x"yes"; then
596605
AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys])
597606
AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig])
598607
AC_MSG_NOTICE([Building ECDSA sign-to-contract module: $enable_module_ecdsa_s2c])
608+
AC_MSG_NOTICE([Building ECDSA adaptor signatures module: $enable_module_ecdsa_adaptor])
599609
AC_MSG_NOTICE([******])
600610

601611

@@ -632,6 +642,9 @@ else
632642
if test x"$enable_module_ecdsa_s2c" = x"yes"; then
633643
AC_MSG_ERROR([ECDSA sign-to-contract module module is experimental. Use --enable-experimental to allow.])
634644
fi
645+
if test x"$enable_module_ecdsa_adaptor" = x"yes"; then
646+
AC_MSG_ERROR([ecdsa adaptor signatures module is experimental. Use --enable-experimental to allow.])
647+
fi
635648
if test x"$set_asm" = x"arm"; then
636649
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
637650
fi
@@ -673,6 +686,7 @@ AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"
673686
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
674687
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
675688
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_S2C], [test x"$enable_module_ecdsa_s2c" = x"yes"])
689+
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_ADAPTOR], [test x"$enable_module_ecdsa_adaptor" = x"yes"])
676690
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
677691
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
678692
AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"])
@@ -698,6 +712,7 @@ echo " module recovery = $enable_module_recovery"
698712
echo " module extrakeys = $enable_module_extrakeys"
699713
echo " module schnorrsig = $enable_module_schnorrsig"
700714
echo " module ecdsa-s2c = $enable_module_ecdsa_s2c"
715+
echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor"
701716
echo
702717
echo " asm = $set_asm"
703718
echo " bignum = $set_bignum"

include/secp256k1_ecdsa_adaptor.h

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
#ifndef SECP256K1_ECDSA_ADAPTOR_H
2+
#define SECP256K1_ECDSA_ADAPTOR_H
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
8+
/** This module implements single signer ECDSA adaptor signatures following
9+
* "One-Time Verifiably Encrypted Signatures A.K.A. Adaptor Signatures" by
10+
* Lloyd Fournier
11+
* (https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-November/002316.html
12+
* and https://github.com/LLFourn/one-time-VES/blob/master/main.pdf).
13+
*
14+
* WARNING! DANGER AHEAD!
15+
* As mentioned in Lloyd Fournier's paper, the adaptor signature leaks the
16+
* Elliptic-curve Diffie–Hellman (ECDH) key between the signing key and the
17+
* encryption key. This is not a problem for ECDSA adaptor signatures
18+
* themselves, but may result in a complete loss of security when they are
19+
* composed with other schemes. More specifically, let us refer to the
20+
* signer's public key as X = x*G, and to the encryption key as Y = y*G.
21+
* Given X, Y and the adaptor signature, it is trivial to compute Y^x = X^y.
22+
*
23+
* A defense is to not reuse the signing key of ECDSA adaptor signatures in
24+
* protocols that rely on the hardness of the CDH problem, e.g., Diffie-Hellman
25+
* key exchange and ElGamal encryption. In general, it is a well-established
26+
* cryptographic practice to seperate keys for different purposes whenever
27+
* possible.
28+
*/
29+
30+
/** A pointer to a function to deterministically generate a nonce.
31+
*
32+
* Same as secp256k1_nonce_function_hardened with the exception of using the
33+
* compressed 33-byte encoding for the pubkey argument.
34+
*
35+
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to
36+
* return an error.
37+
* Out: nonce32: pointer to a 32-byte array to be filled by the function
38+
* In: msg32: the 32-byte message hash being verified
39+
* key32: pointer to a 32-byte secret key
40+
* pk33: the 33-byte serialized pubkey corresponding to key32
41+
* algo: pointer to an array describing the signature algorithm
42+
* algolen: the length of the algo array
43+
* data: arbitrary data pointer that is passed through
44+
*
45+
* Except for test cases, this function should compute some cryptographic hash of
46+
* the message, the key, the pubkey, the algorithm description, and data.
47+
*/
48+
typedef int (*secp256k1_nonce_function_hardened_ecdsa_adaptor)(
49+
unsigned char *nonce32,
50+
const unsigned char *msg32,
51+
const unsigned char *key32,
52+
const unsigned char *pk33,
53+
const unsigned char *algo,
54+
size_t algolen,
55+
void *data
56+
);
57+
58+
/** A modified BIP-340 nonce generation function. If a data pointer is passed, it is
59+
* assumed to be a pointer to 32 bytes of auxiliary random data as defined in BIP-340.
60+
* The hash will be tagged with algo after removing all terminating null bytes.
61+
*/
62+
SECP256K1_API extern const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor;
63+
64+
/** Encrypted Signing
65+
*
66+
* Creates an adaptor signature, which includes a proof to verify the adaptor
67+
* signature.
68+
* WARNING: Make sure you have read and understood the WARNING at the top of
69+
* this file and applied the suggested countermeasures.
70+
*
71+
* Returns: 1 on success, 0 on failure
72+
* Args: ctx: a secp256k1 context object, initialized for signing
73+
* Out: adaptor_sig162: pointer to 162 byte to store the returned signature
74+
* In: seckey32: pointer to 32 byte secret key that will be used for
75+
* signing
76+
* enckey: pointer to the encryption public key
77+
* msg32: pointer to the 32-byte message hash to sign
78+
* noncefp: pointer to a nonce generation function. If NULL,
79+
* secp256k1_nonce_function_ecdsa_adaptor is used
80+
* ndata: pointer to arbitrary data used by the nonce generation
81+
* function (can be NULL). If it is non-NULL and
82+
* secp256k1_nonce_function_ecdsa_adaptor is used, then
83+
* ndata must be a pointer to 32-byte auxiliary randomness
84+
* as per BIP-340.
85+
*/
86+
SECP256K1_API int secp256k1_ecdsa_adaptor_encrypt(
87+
const secp256k1_context* ctx,
88+
unsigned char *adaptor_sig162,
89+
unsigned char *seckey32,
90+
const secp256k1_pubkey *enckey,
91+
const unsigned char *msg32,
92+
secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp,
93+
void *ndata
94+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
95+
96+
/** Encryption Verification
97+
*
98+
* Verifies that the adaptor decryption key can be extracted from the adaptor signature
99+
* and the completed ECDSA signature.
100+
*
101+
* Returns: 1 on success, 0 on failure
102+
* Args: ctx: a secp256k1 context object, initialized for verification
103+
* In: adaptor_sig162: pointer to 162-byte signature to verify
104+
* pubkey: pointer to the public key corresponding to the secret key
105+
* used for signing
106+
* msg32: pointer to the 32-byte message hash being verified
107+
* enckey: pointer to the adaptor encryption public key
108+
*/
109+
SECP256K1_API int secp256k1_ecdsa_adaptor_verify(
110+
const secp256k1_context* ctx,
111+
const unsigned char *adaptor_sig162,
112+
const secp256k1_pubkey *pubkey,
113+
const unsigned char *msg32,
114+
const secp256k1_pubkey *enckey
115+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
116+
117+
/** Signature Decryption
118+
*
119+
* Derives an ECDSA signature from an adaptor signature and an adaptor decryption key.
120+
*
121+
* Returns: 1 on success, 0 on failure
122+
* Args: ctx: a secp256k1 context object
123+
* Out: sig: pointer to the ECDSA signature to create
124+
* In: deckey32: pointer to 32-byte decryption secret key for the adaptor
125+
* encryption public key
126+
* adaptor_sig162: pointer to 162-byte adaptor sig
127+
*/
128+
SECP256K1_API int secp256k1_ecdsa_adaptor_decrypt(
129+
const secp256k1_context* ctx,
130+
secp256k1_ecdsa_signature *sig,
131+
const unsigned char *deckey32,
132+
const unsigned char *adaptor_sig162
133+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
134+
135+
/** Decryption Key Recovery
136+
*
137+
* Extracts the adaptor decryption key from the complete signature and the adaptor
138+
* signature.
139+
*
140+
* Returns: 1 on success, 0 on failure
141+
* Args: ctx: a secp256k1 context object, initialized for signing
142+
* Out: deckey32: pointer to 32-byte adaptor decryption key for the adaptor
143+
* encryption public key
144+
* In: sig: pointer to ECDSA signature to recover the adaptor decryption
145+
* key from
146+
* adaptor_sig162: pointer to adaptor signature to recover the adaptor
147+
* decryption key from
148+
* enckey: pointer to the adaptor encryption public key
149+
*/
150+
SECP256K1_API int secp256k1_ecdsa_adaptor_recover(
151+
const secp256k1_context* ctx,
152+
unsigned char *deckey32,
153+
const secp256k1_ecdsa_signature *sig,
154+
const unsigned char *adaptor_sig162,
155+
const secp256k1_pubkey *enckey
156+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
157+
158+
#ifdef __cplusplus
159+
}
160+
#endif
161+
162+
#endif /* SECP256K1_ECDSA_ADAPTOR_H */
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include_HEADERS += include/secp256k1_ecdsa_adaptor.h
2+
noinst_HEADERS += src/modules/ecdsa_adaptor/main_impl.h
3+
noinst_HEADERS += src/modules/ecdsa_adaptor/dleq_impl.h
4+
noinst_HEADERS += src/modules/ecdsa_adaptor/tests_impl.h

0 commit comments

Comments
 (0)