Skip to content

Commit 5408a2f

Browse files
committed
[experiment/wip] module ecdsa_sign_to_contract, anti nonce sidechan
General sign to contract, with special util functions to perform the anti nonce covert channel protection. This is based on the description of the fix by Stepan: https://medium.com/cryptoadvance/hardware-wallets-can-be-hacked-but-this-is-fine-a6156bbd199 The protocol wording and some functions are copied/adapted from Jonas Nick's PRs which do the same for BIP-Schnorr. Add test_ecdsa_s2c_anti_nonce_covert_channel_client_commit to return the curve point committing to the signing client nonce. This is a convenience function and can technically be emulated by calling secp256k1_ecdsa_s2c_sign() and reconstructing the curve point from the signature r/s values.
1 parent 4c0c66d commit 5408a2f

File tree

9 files changed

+623
-22
lines changed

9 files changed

+623
-22
lines changed

.travis.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@ cache:
1111
- src/java/guava/
1212
env:
1313
global:
14-
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no JNI=no
14+
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no$ECDSA_SIGN_TO_CONTRACT=no EXPERIMENTAL=no JNI=no
1515
- GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
1616
matrix:
1717
- SCALAR=32bit RECOVERY=yes
18-
- SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
18+
- SCALAR=32bit FIELD=32bit ECDH=yes ECDSA_SIGN_TO_CONTRACT=yes EXPERIMENTAL=yes
19+
- SCALAR=32bit FIELD=32bit EXPERIMENTAL=yes
1920
- SCALAR=64bit
2021
- FIELD=64bit RECOVERY=yes
2122
- FIELD=64bit ENDOMORPHISM=yes
22-
- FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
23+
- FIELD=64bit ENDOMORPHISM=yes ECDH=yes ECDSA_SIGN_TO_CONTRACT=yes EXPERIMENTAL=yes
2324
- FIELD=64bit ASM=x86_64
2425
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
2526
- FIELD=32bit ENDOMORPHISM=yes
@@ -65,4 +66,4 @@ before_script: ./autogen.sh
6566
script:
6667
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
6768
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
68-
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
69+
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-ecdsa-sign-to-contract=$ECDSA_SIGN_TO_CONTRACT --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD

Makefile.am

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,7 @@ endif
181181
if ENABLE_MODULE_RECOVERY
182182
include src/modules/recovery/Makefile.am.include
183183
endif
184+
185+
if ENABLE_MODULE_ECDSA_SIGN_TO_CONTRACT
186+
include src/modules/ecdsa_sign_to_contract/Makefile.am.include
187+
endif

configure.ac

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ AC_ARG_ENABLE(module_recovery,
134134
[enable_module_recovery=$enableval],
135135
[enable_module_recovery=no])
136136

137+
AC_ARG_ENABLE(module_ecdsa_sign_to_contract,
138+
AS_HELP_STRING([--enable-module-ecdsa-sign-to-contract],[enable ECDSA sign-to-contract module [default=no]]),
139+
[enable_module_ecdsa_sign_to_contract=$enableval],
140+
[enable_module_ecdsa_sign_to_contract=no])
141+
137142
AC_ARG_ENABLE(external_default_callbacks,
138143
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions (default is no)]),
139144
[use_external_default_callbacks=$enableval],
@@ -492,6 +497,10 @@ if test x"$enable_module_recovery" = x"yes"; then
492497
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
493498
fi
494499

500+
if test x"$enable_module_ecdsa_sign_to_contract" = x"yes"; then
501+
AC_DEFINE(ENABLE_MODULE_ECDSA_SIGN_TO_CONTRACT, 1, [Define this symbol to enable the ECDSA sign-to-contract module])
502+
fi
503+
495504
AC_C_BIGENDIAN()
496505

497506
if test x"$use_external_asm" = x"yes"; then
@@ -507,11 +516,15 @@ if test x"$enable_experimental" = x"yes"; then
507516
AC_MSG_NOTICE([WARNING: experimental build])
508517
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
509518
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
519+
AC_MSG_NOTICE([Building ECDSA sign-to-contract module: $enable_module_ecdsa_sign_to_contract])
510520
AC_MSG_NOTICE([******])
511521
else
512522
if test x"$enable_module_ecdh" = x"yes"; then
513523
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
514524
fi
525+
if test x"$enable_module_ecdsa_sign_to_contract" = x"yes"; then
526+
AC_MSG_ERROR([ECDA sign-to-contract module module is experimental. Use --enable-experimental to allow.])
527+
fi
515528
if test x"$set_asm" = x"arm"; then
516529
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
517530
fi
@@ -531,6 +544,7 @@ AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
531544
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
532545
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
533546
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
547+
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_SIGN_TO_CONTRACT], [test x"$enable_module_ecdsa_sign_to_contract" = x"yes"])
534548
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" = x"yes"])
535549
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
536550
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
@@ -544,23 +558,24 @@ AC_OUTPUT
544558

545559
echo
546560
echo "Build Options:"
547-
echo " with endomorphism = $use_endomorphism"
548-
echo " with ecmult precomp = $set_precomp"
549-
echo " with external callbacks = $use_external_default_callbacks"
550-
echo " with jni = $use_jni"
551-
echo " with benchmarks = $use_benchmark"
552-
echo " with coverage = $enable_coverage"
553-
echo " module ecdh = $enable_module_ecdh"
554-
echo " module recovery = $enable_module_recovery"
561+
echo " with endomorphism = $use_endomorphism"
562+
echo " with ecmult precomp = $set_precomp"
563+
echo " with external callbacks = $use_external_default_callbacks"
564+
echo " with jni = $use_jni"
565+
echo " with benchmarks = $use_benchmark"
566+
echo " with coverage = $enable_coverage"
567+
echo " module ecdh = $enable_module_ecdh"
568+
echo " module recovery = $enable_module_recovery"
569+
echo " module ecdsa sign-to-contract = $enable_module_ecdsa_sign_to_contract"
555570
echo
556-
echo " asm = $set_asm"
557-
echo " bignum = $set_bignum"
558-
echo " field = $set_field"
559-
echo " scalar = $set_scalar"
560-
echo " ecmult window size = $set_ecmult_window"
571+
echo " asm = $set_asm"
572+
echo " bignum = $set_bignum"
573+
echo " field = $set_field"
574+
echo " scalar = $set_scalar"
575+
echo " ecmult window size = $set_ecmult_window"
561576
echo
562-
echo " CC = $CC"
563-
echo " CFLAGS = $CFLAGS"
564-
echo " CPPFLAGS = $CPPFLAGS"
565-
echo " LDFLAGS = $LDFLAGS"
577+
echo " CC = $CC"
578+
echo " CFLAGS = $CFLAGS"
579+
echo " CPPFLAGS = $CPPFLAGS"
580+
echo " LDFLAGS = $LDFLAGS"
566581
echo
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#ifndef SECP256K1_ECDSA_ANTI_COVERT_CHANNEL_H
2+
#define SECP256K1_ECDSA_ANTI_COVERT_CHANNEL_H
3+
4+
#include "secp256k1.h"
5+
6+
#ifdef __cplusplus
7+
extern "C" {
8+
#endif
9+
10+
/** Same as secp256k1_ecdsa_sign, but s2c_data32 is committed to by adding `hash(R1, s2c_data32)` to
11+
* the nonce generated by noncefp, with `ndata=hash(s2c_data32, ndata)`.
12+
* Returns: 1: signature created
13+
* 0: the nonce generation function failed, or the private key was invalid.
14+
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
15+
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
16+
* s2c_opening: pointer to an secp256k1_s2c_opening structure which can be
17+
* NULL but is required to be not NULL if this signature creates
18+
* a sign-to-contract commitment (i.e. the `s2c_data` argument
19+
* is not NULL). nonce_is_negated is always 0 for ecdsa.
20+
* In:
21+
* msg32: the 32-byte message hash being signed (cannot be NULL)
22+
* seckey: pointer to a 32-byte secret key (cannot be NULL)
23+
* s2c_data32: pointer to a 32-byte data to create an optional
24+
* sign-to-contract commitment to if not NULL (can be NULL).
25+
* noncefp: pointer to a nonce generation function.
26+
* If NULL, secp256k1_nonce_function_default is used.
27+
* Must be the default if s2c_data32 is not NULL.
28+
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
29+
*/
30+
SECP256K1_API int secp256k1_ecdsa_s2c_sign(
31+
const secp256k1_context* ctx,
32+
secp256k1_ecdsa_signature *sig,
33+
secp256k1_s2c_opening *s2c_opening,
34+
const unsigned char *msg32,
35+
const unsigned char *seckey,
36+
const unsigned char* s2c_data32,
37+
secp256k1_nonce_function noncefp,
38+
const void *ndata
39+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
40+
41+
/** Verify a sign-to-contract commitment.
42+
*
43+
* Returns: 1: the signature contains a commitment to data32
44+
* 0: incorrect opening
45+
* Args: ctx: a secp256k1 context object, initialized for verification.
46+
* In: sig: the signature containing the sign-to-contract commitment (cannot be NULL)
47+
* data32: the 32-byte data that was committed to (cannot be NULL)
48+
* opening: pointer to the opening created during signing (cannot be NULL)
49+
*/
50+
SECP256K1_API int secp256k1_ecdsa_s2c_verify_commit(
51+
const secp256k1_context* ctx,
52+
const secp256k1_ecdsa_signature *sig,
53+
const unsigned char *data32,
54+
const secp256k1_s2c_opening *opening
55+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
56+
57+
/** Compute commitment on the client as part of the ECDSA Anti Nonce Covert Channel Protocol.
58+
*
59+
* ECDSA Anti Nonce Covert Channel Protocol:
60+
* 1. The host draws randomness `k2`, commits to it with sha256 and sends the commitment to the client.
61+
* 2. The client commits to its original nonce `k1` using the host commitment by calling
62+
* `secp256k1_ecdsa_anti_covert_channel_client_commit`. The client sends the resulting commitment
63+
* `R1` to the host.
64+
* 3. The host replies with `k2` generated in step 1.
65+
* 4. The client signs with `secp256k1_ecdsa_s2c_sign`, using the `k2` as `s2c_data` and
66+
* sends the signature and opening to the host.
67+
* 5. The host verifies that `R_x = (R1 + H(R1, k2)*G)_x`, where R_x is the `r` part of the signature by using
68+
* `secp256k1_ecdsa_s2c_anti_nonce_covert_channel_host_verify` with the client's
69+
* commitment from step 2 and the signature and opening received in step 4. If verification does
70+
* not succeed, the protocol failed and can be restarted.
71+
*
72+
* Returns 1 on success, 0 on failure.
73+
* Args: ctx: pointer to a context object (cannot be NULL)
74+
* Out: client_commit: pointer to a pubkey where the clients public nonce will be
75+
* placed. (cannot be NULL)
76+
* In: msg32: the 32-byte message hash to be signed (cannot be NULL)
77+
* seckey32: the 32-byte secret key used for signing (cannot be NULL)
78+
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
79+
* rand_commitment32: the 32-byte randomness commitment from the host (cannot be NULL)
80+
*/
81+
SECP256K1_API int secp256k1_ecdsa_s2c_anti_nonce_covert_channel_client_commit(
82+
const secp256k1_context* ctx,
83+
secp256k1_pubkey *client_commit,
84+
const unsigned char *msg32,
85+
const unsigned char *seckey32,
86+
unsigned char *rand_commitment32
87+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
88+
89+
/** Create a randomness commitment on the host as part of the ECDSA Anti Nonce Covert Channel Protocol.
90+
*
91+
* Returns 1 on success, 0 on failure.
92+
* Args: ctx: pointer to a context object (cannot be NULL)
93+
* Out: rand_commitment32: pointer to 32-byte array to store the returned commitment (cannot be NULL)
94+
* In: rand32: the 32-byte randomness to commit to (cannot be NULL)
95+
*/
96+
SECP256K1_API int secp256k1_ecdsa_s2c_anti_nonce_covert_channel_host_commit(
97+
secp256k1_context *ctx,
98+
unsigned char *rand_commitment32,
99+
const unsigned char *rand32
100+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
101+
102+
/** Verify that a clients signature contains the hosts randomness as part of the Anti
103+
* Nonce Covert Channel Protocol. Does not verify the signature itself.
104+
*
105+
* Returns 1 on success, 0 on failure.
106+
* Args: ctx: pointer to a context object (cannot be NULL)
107+
* In: sig: pointer to the signature whose randomness should be verified
108+
* (cannot be NULL)
109+
* rand32: pointer to the 32-byte randomness from the host which should
110+
* be included by the signature (cannot be NULL)
111+
* opening: pointer to the opening produced by the client when signing
112+
* with `rand32` as `s2c_data` (cannot be NULL)
113+
* client_commit: pointer to the client's commitment created in
114+
* `secp256k1_ecdsa_s2c_anti_nonce_covert_channel_client_commit`
115+
* (cannot be NULL)
116+
*/
117+
SECP256K1_API int secp256k1_ecdsa_s2c_anti_nonce_covert_channel_host_verify(
118+
secp256k1_context *ctx,
119+
const secp256k1_ecdsa_signature *sig,
120+
const unsigned char *rand32,
121+
const secp256k1_s2c_opening *opening,
122+
const secp256k1_pubkey *client_commit
123+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
124+
125+
#ifdef __cplusplus
126+
}
127+
#endif
128+
129+
#endif /* SECP256K1_RECOVERY_H */
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
include_HEADERS += include/secp256k1_ecdsa_sign_to_contract.h
2+
noinst_HEADERS += src/modules/ecdsa_sign_to_contract/main_impl.h
3+
noinst_HEADERS += src/modules/ecdsa_sign_to_contract/tests_impl.h

0 commit comments

Comments
 (0)