Skip to content

Commit 4895cf9

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 4895cf9

9 files changed

+603
-22
lines changed

.travis.yml

+5-4
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

+4
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

+32-17
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
+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
* In:
13+
* s2c_opening: pointer to an secp256k1_s2c_opening structure which can be
14+
* NULL but is required to be not NULL if this signature creates
15+
* a sign-to-contract commitment (i.e. the `s2c_data` argument
16+
* is not NULL). nonce_is_negated is always 0 for ecdsa.
17+
*/
18+
SECP256K1_API int secp256k1_ecdsa_s2c_sign(
19+
const secp256k1_context* ctx,
20+
secp256k1_ecdsa_signature *sig,
21+
secp256k1_s2c_opening *s2c_opening,
22+
const unsigned char *msg32,
23+
const unsigned char *seckey,
24+
secp256k1_nonce_function noncefp,
25+
const void *ndata,
26+
const unsigned char* s2c_data32
27+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
28+
29+
/** Verify a sign-to-contract commitment.
30+
*
31+
* Returns: 1: the signature contains a commitment to data32
32+
* 0: incorrect opening
33+
* Args: ctx: a secp256k1 context object, initialized for verification.
34+
* In: sig: the signature containing the sign-to-contract commitment (cannot be NULL)
35+
* data32: the 32-byte data that was committed to (cannot be NULL)
36+
* opening: pointer to the opening created during signing (cannot be NULL)
37+
*/
38+
SECP256K1_API int secp256k1_ecdsa_s2c_verify_commit(
39+
const secp256k1_context* ctx,
40+
const secp256k1_ecdsa_signature *sig,
41+
const unsigned char *data32,
42+
const secp256k1_s2c_opening *opening
43+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
44+
45+
/** Compute commitment on the client as part of the ECDSA Anti Nonce Covert Channel Protocol.
46+
*
47+
* ECDSA Anti Nonce Covert Channel Protocol:
48+
* 1. The host draws randomness `k2`, commits to it with sha256 and sends the commitment to the client.
49+
* 2. The client commits to its original nonce `k1` using the host commitment by calling
50+
* `secp256k1_ecdsa_anti_covert_channel_client_commit`. The client sends the resulting commitment
51+
* `R1` to the host.
52+
* 3. The host replies with `k2` generated in step 1.
53+
* 4. The client signs with `secp256k1_ecdsa_s2c_sign`, using the `k2` as `s2c_data` and
54+
* sends the signature and opening to the host.
55+
* 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
56+
* `secp256k1_ecdsa_s2c_anti_nonce_covert_channel_host_verify` with the client's
57+
* commitment from step 2 and the signature and opening received in step 4. If verification does
58+
* not succeed, the protocol failed and can be restarted.
59+
*
60+
* Returns 1 on success, 0 on failure.
61+
* Args: ctx: pointer to a context object (cannot be NULL)
62+
* Out: client_commit: pointer to a pubkey where the clients public nonce will be
63+
* placed. (cannot be NULL)
64+
* In: msg32: the 32-byte message hash to be signed (cannot be NULL)
65+
* seckey32: the 32-byte secret key used for signing (cannot be NULL)
66+
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
67+
* rand_commitment32: the 32-byte randomness commitment from the host (cannot be NULL)
68+
*/
69+
SECP256K1_API int secp256k1_ecdsa_s2c_anti_nonce_covert_channel_client_commit(
70+
const secp256k1_context* ctx,
71+
secp256k1_pubkey *client_commit,
72+
const unsigned char *msg32,
73+
const unsigned char *seckey32,
74+
unsigned char *rand_commitment32
75+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
76+
77+
/** Create a randomness commitment on the host as part of the ECDSA Anti Nonce Covert Channel Protocol.
78+
*
79+
* Returns 1 on success, 0 on failure.
80+
* Args: ctx: pointer to a context object (cannot be NULL)
81+
* Out: rand_commitment32: pointer to 32-byte array to store the returned commitment (cannot be NULL)
82+
* In: rand32: the 32-byte randomness to commit to (cannot be NULL)
83+
*/
84+
SECP256K1_API int secp256k1_ecdsa_s2c_anti_nonce_covert_channel_host_commit(
85+
secp256k1_context *ctx,
86+
unsigned char *rand_commitment32,
87+
const unsigned char *rand32
88+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
89+
90+
/** Verify that a clients signature contains the hosts randomness as part of the Anti
91+
* Nonce Covert Channel Protocol. Does not verify the signature itself.
92+
*
93+
* Returns 1 on success, 0 on failure.
94+
* Args: ctx: pointer to a context object (cannot be NULL)
95+
* In: sig: pointer to the signature whose randomness should be verified
96+
* (cannot be NULL)
97+
* rand32: pointer to the 32-byte randomness from the host which should
98+
* be included by the signature (cannot be NULL)
99+
* opening: pointer to the opening produced by the client when signing
100+
* with `rand32` as `s2c_data` (cannot be NULL)
101+
* client_commit: pointer to the client's commitment created in
102+
* `secp256k1_ecdsa_s2c_anti_nonce_covert_channel_client_commit`
103+
* (cannot be NULL)
104+
*/
105+
SECP256K1_API int secp256k1_ecdsa_s2c_anti_nonce_covert_channel_host_verify(
106+
secp256k1_context *ctx,
107+
const secp256k1_ecdsa_signature *sig,
108+
const unsigned char *rand32,
109+
const secp256k1_s2c_opening *opening,
110+
const secp256k1_pubkey *client_commit
111+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
112+
113+
#ifdef __cplusplus
114+
}
115+
#endif
116+
117+
#endif /* SECP256K1_RECOVERY_H */
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)