Merge #117: Add ECDSA adaptor signatures module
b0ffa923199c45f717adf3fb003bcef796259032 ecdsa_adaptor: add tests (Jesse Posner) 6955af5ca8930aa674e5fdbc4343e722b25e0ca8 ecdsa_adaptor: add ECDSA adaptor signature APIs (Jesse Posner) b508e5dd9b1f6f4f9e552056a1fe898fffc0a450 ecdsa_adaptor: add support for proof of discrete logarithm equality (Jesse Posner) d8f336564fe1255752c7e454d998beaa25f945c1 ecdsa_adaptor: add nonce function and tags (Jesse Posner) 654cd633f509db3100ce99acd84f47db594ff9a6 ecdsa_adaptor: initialize project (Jesse Posner) Pull request description: ACKs for top commit: LLFourn: ACK b0ffa923199c45f717adf3fb003bcef796259032 I've added a small warning to the spec too. jonasnick: ACK b0ffa923199c45f717adf3fb003bcef796259032 Tree-SHA512: f14e6f32265518d435d4da00a73423615ba900de68c28039ae26ac7ee7b4088db44358741411d96c42bd497db79483ff0766fc2d076d95a9116bcc168b80802d
This commit is contained in:
commit
f3708a1ecb
11
.cirrus.yml
11
.cirrus.yml
@ -17,6 +17,7 @@ env:
|
||||
RANGEPROOF: no
|
||||
WHITELIST: no
|
||||
MUSIG: no
|
||||
ECDSAADAPTOR: no
|
||||
EXPERIMENTAL: no
|
||||
CTIMETEST: yes
|
||||
BENCH: yes
|
||||
@ -59,13 +60,13 @@ task:
|
||||
memory: 1G
|
||||
matrix: &ENV_MATRIX
|
||||
- env: {WIDEMUL: int64, RECOVERY: yes}
|
||||
- env: {WIDEMUL: int64, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes}
|
||||
- env: {WIDEMUL: int64, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
|
||||
- env: {WIDEMUL: int128}
|
||||
- env: {WIDEMUL: int128, RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes}
|
||||
- env: {WIDEMUL: int128, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes}
|
||||
- env: {WIDEMUL: int128, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
|
||||
- env: {WIDEMUL: int128, ASM: x86_64}
|
||||
- env: {BIGNUM: no}
|
||||
- env: {BIGNUM: no, RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes}
|
||||
- env: {BIGNUM: no, RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
|
||||
- env: {BIGNUM: no, STATICPRECOMPUTATION: no}
|
||||
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
|
||||
- env: {CPPFLAGS: -DDETERMINISTIC}
|
||||
@ -85,6 +86,7 @@ task:
|
||||
WHITELIST: yes
|
||||
GENERATOR: yes
|
||||
MUSIG: yes
|
||||
ECDSAADAPTOR: yes
|
||||
CTIMETEST: no
|
||||
- env: { ECMULTGENPRECISION: 2 }
|
||||
- env: { ECMULTGENPRECISION: 8 }
|
||||
@ -101,6 +103,7 @@ task:
|
||||
WHITELIST: yes
|
||||
GENERATOR: yes
|
||||
MUSIG: yes
|
||||
ECDSAADAPTOR: yes
|
||||
EXTRAFLAGS: "--disable-openssl-tests"
|
||||
BUILD:
|
||||
matrix:
|
||||
@ -130,6 +133,7 @@ task:
|
||||
WHITELIST: yes
|
||||
GENERATOR: yes
|
||||
MUSIG: yes
|
||||
ECDSAADAPTOR: yes
|
||||
matrix:
|
||||
- env:
|
||||
CC: i686-linux-gnu-gcc
|
||||
@ -227,6 +231,7 @@ task:
|
||||
WHITELIST: yes
|
||||
GENERATOR: yes
|
||||
MUSIG: yes
|
||||
ECDSAADAPTOR: yes
|
||||
CTIMETEST: no
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
|
@ -189,3 +189,6 @@ if ENABLE_MODULE_ECDSA_S2C
|
||||
include src/modules/ecdsa_s2c/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_ECDSA_ADAPTOR
|
||||
include src/modules/ecdsa_adaptor/Makefile.am.include
|
||||
endif
|
||||
|
@ -17,6 +17,7 @@ Features:
|
||||
* Suitable for embedded systems.
|
||||
* Optional module for public key recovery.
|
||||
* Optional module for ECDH key exchange.
|
||||
* Optional module for ECDSA adaptor signatures (experimental).
|
||||
|
||||
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.
|
||||
|
||||
|
@ -19,7 +19,7 @@ valgrind --version || true
|
||||
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
|
||||
--enable-module-ecdsa-s2c="$ECDSA_S2C" \
|
||||
--enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
|
||||
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG"\
|
||||
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
|
||||
--with-valgrind="$WITH_VALGRIND" \
|
||||
--host="$HOST" $EXTRAFLAGS
|
||||
|
||||
|
15
configure.ac
15
configure.ac
@ -180,6 +180,11 @@ AC_ARG_ENABLE(module_ecdsa_s2c,
|
||||
[enable_module_ecdsa_s2c=$enableval],
|
||||
[enable_module_ecdsa_s2c=no])
|
||||
|
||||
AC_ARG_ENABLE(module_ecdsa-adaptor,
|
||||
AS_HELP_STRING([--enable-module-ecdsa-adaptor],[enable ECDSA adaptor module [default=no]]),
|
||||
[enable_module_ecdsa_adaptor=$enableval],
|
||||
[enable_module_ecdsa_adaptor=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],
|
||||
@ -580,6 +585,10 @@ if test x"$use_reduced_surjection_proof_size" = x"yes"; then
|
||||
AC_DEFINE(USE_REDUCED_SURJECTION_PROOF_SIZE, 1, [Define this symbol to reduce SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS to 16, disabling parsing and verification])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_ecdsa_adaptor" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_ECDSA_ADAPTOR, 1, [Define this symbol to enable the ECDSA adaptor module])
|
||||
fi
|
||||
|
||||
###
|
||||
### Check for --enable-experimental if necessary
|
||||
###
|
||||
@ -596,6 +605,7 @@ if test x"$enable_experimental" = x"yes"; then
|
||||
AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys])
|
||||
AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig])
|
||||
AC_MSG_NOTICE([Building ECDSA sign-to-contract module: $enable_module_ecdsa_s2c])
|
||||
AC_MSG_NOTICE([Building ECDSA adaptor signatures module: $enable_module_ecdsa_adaptor])
|
||||
AC_MSG_NOTICE([******])
|
||||
|
||||
|
||||
@ -632,6 +642,9 @@ else
|
||||
if test x"$enable_module_ecdsa_s2c" = x"yes"; then
|
||||
AC_MSG_ERROR([ECDSA sign-to-contract module module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_ecdsa_adaptor" = x"yes"; then
|
||||
AC_MSG_ERROR([ecdsa adaptor signatures 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
|
||||
@ -673,6 +686,7 @@ AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"
|
||||
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([ENABLE_MODULE_ECDSA_S2C], [test x"$enable_module_ecdsa_s2c" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_ADAPTOR], [test x"$enable_module_ecdsa_adaptor" = 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"])
|
||||
@ -698,6 +712,7 @@ echo " module recovery = $enable_module_recovery"
|
||||
echo " module extrakeys = $enable_module_extrakeys"
|
||||
echo " module schnorrsig = $enable_module_schnorrsig"
|
||||
echo " module ecdsa-s2c = $enable_module_ecdsa_s2c"
|
||||
echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor"
|
||||
echo
|
||||
echo " asm = $set_asm"
|
||||
echo " bignum = $set_bignum"
|
||||
|
162
include/secp256k1_ecdsa_adaptor.h
Normal file
162
include/secp256k1_ecdsa_adaptor.h
Normal file
@ -0,0 +1,162 @@
|
||||
#ifndef SECP256K1_ECDSA_ADAPTOR_H
|
||||
#define SECP256K1_ECDSA_ADAPTOR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** This module implements single signer ECDSA adaptor signatures following
|
||||
* "One-Time Verifiably Encrypted Signatures A.K.A. Adaptor Signatures" by
|
||||
* Lloyd Fournier
|
||||
* (https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-November/002316.html
|
||||
* and https://github.com/LLFourn/one-time-VES/blob/master/main.pdf).
|
||||
*
|
||||
* WARNING! DANGER AHEAD!
|
||||
* As mentioned in Lloyd Fournier's paper, the adaptor signature leaks the
|
||||
* Elliptic-curve Diffie–Hellman (ECDH) key between the signing key and the
|
||||
* encryption key. This is not a problem for ECDSA adaptor signatures
|
||||
* themselves, but may result in a complete loss of security when they are
|
||||
* composed with other schemes. More specifically, let us refer to the
|
||||
* signer's public key as X = x*G, and to the encryption key as Y = y*G.
|
||||
* Given X, Y and the adaptor signature, it is trivial to compute Y^x = X^y.
|
||||
*
|
||||
* A defense is to not reuse the signing key of ECDSA adaptor signatures in
|
||||
* protocols that rely on the hardness of the CDH problem, e.g., Diffie-Hellman
|
||||
* key exchange and ElGamal encryption. In general, it is a well-established
|
||||
* cryptographic practice to seperate keys for different purposes whenever
|
||||
* possible.
|
||||
*/
|
||||
|
||||
/** A pointer to a function to deterministically generate a nonce.
|
||||
*
|
||||
* Same as secp256k1_nonce_function_hardened with the exception of using the
|
||||
* compressed 33-byte encoding for the pubkey argument.
|
||||
*
|
||||
* 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
|
||||
* key32: pointer to a 32-byte secret key
|
||||
* pk33: the 33-byte serialized pubkey corresponding to key32
|
||||
* algo: pointer to an array describing the signature algorithm
|
||||
* algolen: the length of the algo array
|
||||
* 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 int (*secp256k1_nonce_function_hardened_ecdsa_adaptor)(
|
||||
unsigned char *nonce32,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *key32,
|
||||
const unsigned char *pk33,
|
||||
const unsigned char *algo,
|
||||
size_t algolen,
|
||||
void *data
|
||||
);
|
||||
|
||||
/** A modified BIP-340 nonce generation function. 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.
|
||||
* The hash will be tagged with algo after removing all terminating null bytes.
|
||||
*/
|
||||
SECP256K1_API extern const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor;
|
||||
|
||||
/** Encrypted Signing
|
||||
*
|
||||
* Creates an adaptor signature, which includes a proof to verify the adaptor
|
||||
* signature.
|
||||
* WARNING: Make sure you have read and understood the WARNING at the top of
|
||||
* this file and applied the suggested countermeasures.
|
||||
*
|
||||
* Returns: 1 on success, 0 on failure
|
||||
* Args: ctx: a secp256k1 context object, initialized for signing
|
||||
* Out: adaptor_sig162: pointer to 162 byte to store the returned signature
|
||||
* In: seckey32: pointer to 32 byte secret key that will be used for
|
||||
* signing
|
||||
* enckey: pointer to the encryption public key
|
||||
* msg32: pointer to the 32-byte message hash to sign
|
||||
* noncefp: pointer to a nonce generation function. If NULL,
|
||||
* secp256k1_nonce_function_ecdsa_adaptor 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_ecdsa_adaptor is used, then
|
||||
* ndata must be a pointer to 32-byte auxiliary randomness
|
||||
* as per BIP-340.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_adaptor_encrypt(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *adaptor_sig162,
|
||||
unsigned char *seckey32,
|
||||
const secp256k1_pubkey *enckey,
|
||||
const unsigned char *msg32,
|
||||
secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp,
|
||||
void *ndata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Encryption Verification
|
||||
*
|
||||
* Verifies that the adaptor decryption key can be extracted from the adaptor signature
|
||||
* and the completed ECDSA signature.
|
||||
*
|
||||
* Returns: 1 on success, 0 on failure
|
||||
* Args: ctx: a secp256k1 context object, initialized for verification
|
||||
* In: adaptor_sig162: pointer to 162-byte signature to verify
|
||||
* pubkey: pointer to the public key corresponding to the secret key
|
||||
* used for signing
|
||||
* msg32: pointer to the 32-byte message hash being verified
|
||||
* enckey: pointer to the adaptor encryption public key
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_adaptor_verify(
|
||||
const secp256k1_context* ctx,
|
||||
const unsigned char *adaptor_sig162,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_pubkey *enckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Signature Decryption
|
||||
*
|
||||
* Derives an ECDSA signature from an adaptor signature and an adaptor decryption key.
|
||||
*
|
||||
* Returns: 1 on success, 0 on failure
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: sig: pointer to the ECDSA signature to create
|
||||
* In: deckey32: pointer to 32-byte decryption secret key for the adaptor
|
||||
* encryption public key
|
||||
* adaptor_sig162: pointer to 162-byte adaptor sig
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_adaptor_decrypt(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_ecdsa_signature *sig,
|
||||
const unsigned char *deckey32,
|
||||
const unsigned char *adaptor_sig162
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Decryption Key Recovery
|
||||
*
|
||||
* Extracts the adaptor decryption key from the complete signature and the adaptor
|
||||
* signature.
|
||||
*
|
||||
* Returns: 1 on success, 0 on failure
|
||||
* Args: ctx: a secp256k1 context object, initialized for signing
|
||||
* Out: deckey32: pointer to 32-byte adaptor decryption key for the adaptor
|
||||
* encryption public key
|
||||
* In: sig: pointer to ECDSA signature to recover the adaptor decryption
|
||||
* key from
|
||||
* adaptor_sig162: pointer to adaptor signature to recover the adaptor
|
||||
* decryption key from
|
||||
* enckey: pointer to the adaptor encryption public key
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_adaptor_recover(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *deckey32,
|
||||
const secp256k1_ecdsa_signature *sig,
|
||||
const unsigned char *adaptor_sig162,
|
||||
const secp256k1_pubkey *enckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_ECDSA_ADAPTOR_H */
|
4
src/modules/ecdsa_adaptor/Makefile.am.include
Normal file
4
src/modules/ecdsa_adaptor/Makefile.am.include
Normal file
@ -0,0 +1,4 @@
|
||||
include_HEADERS += include/secp256k1_ecdsa_adaptor.h
|
||||
noinst_HEADERS += src/modules/ecdsa_adaptor/main_impl.h
|
||||
noinst_HEADERS += src/modules/ecdsa_adaptor/dleq_impl.h
|
||||
noinst_HEADERS += src/modules/ecdsa_adaptor/tests_impl.h
|
158
src/modules/ecdsa_adaptor/dleq_impl.h
Normal file
158
src/modules/ecdsa_adaptor/dleq_impl.h
Normal file
@ -0,0 +1,158 @@
|
||||
#ifndef SECP256K1_DLEQ_IMPL_H
|
||||
#define SECP256K1_DLEQ_IMPL_H
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("DLEQ")||SHA256("DLEQ"). */
|
||||
static void secp256k1_nonce_function_dleq_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x8cc4beacul;
|
||||
sha->s[1] = 0x2e011f3ful;
|
||||
sha->s[2] = 0x355c75fbul;
|
||||
sha->s[3] = 0x3ba6a2c5ul;
|
||||
sha->s[4] = 0xe96f3aeful;
|
||||
sha->s[5] = 0x180530fdul;
|
||||
sha->s[6] = 0x94582499ul;
|
||||
sha->s[7] = 0x577fd564ul;
|
||||
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* algo argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */
|
||||
static const unsigned char dleq_algo[4] = "DLEQ";
|
||||
|
||||
static int secp256k1_dleq_hash_point(secp256k1_sha256 *sha, secp256k1_ge *p) {
|
||||
unsigned char buf[33];
|
||||
size_t size = 33;
|
||||
|
||||
if (!secp256k1_eckey_pubkey_serialize(p, buf, &size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_sha256_write(sha, buf, size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_dleq_nonce(secp256k1_scalar *k, const unsigned char *sk32, const unsigned char *gen2_33, const unsigned char *p1_33, const unsigned char *p2_33, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char buf[32];
|
||||
unsigned char nonce[32];
|
||||
size_t size = 33;
|
||||
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_ecdsa_adaptor;
|
||||
}
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, p1_33, size);
|
||||
secp256k1_sha256_write(&sha, p2_33, size);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
|
||||
if (!noncefp(nonce, buf, sk32, gen2_33, dleq_algo, sizeof(dleq_algo), ndata)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(k, nonce, NULL);
|
||||
if (secp256k1_scalar_is_zero(k)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generates a challenge as defined in the DLC Specification at
|
||||
* https://github.com/discreetlogcontracts/dlcspecs */
|
||||
static void secp256k1_dleq_challenge(secp256k1_scalar *e, secp256k1_ge *gen2, secp256k1_ge *r1, secp256k1_ge *r2, secp256k1_ge *p1, secp256k1_ge *p2) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
secp256k1_nonce_function_dleq_sha256_tagged(&sha);
|
||||
secp256k1_dleq_hash_point(&sha, p1);
|
||||
secp256k1_dleq_hash_point(&sha, gen2);
|
||||
secp256k1_dleq_hash_point(&sha, p2);
|
||||
secp256k1_dleq_hash_point(&sha, r1);
|
||||
secp256k1_dleq_hash_point(&sha, r2);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
|
||||
secp256k1_scalar_set_b32(e, buf, NULL);
|
||||
}
|
||||
|
||||
/* P1 = x*G, P2 = x*Y */
|
||||
static void secp256k1_dleq_pair(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_ge *p1, secp256k1_ge *p2, const secp256k1_scalar *sk, const secp256k1_ge *gen2) {
|
||||
secp256k1_gej p1j, p2j;
|
||||
|
||||
secp256k1_ecmult_gen(ecmult_gen_ctx, &p1j, sk);
|
||||
secp256k1_ge_set_gej(p1, &p1j);
|
||||
secp256k1_ecmult_const(&p2j, gen2, sk, 256);
|
||||
secp256k1_ge_set_gej(p2, &p2j);
|
||||
}
|
||||
|
||||
/* Generates a proof that the discrete logarithm of P1 to the secp256k1 base G is the
|
||||
* same as the discrete logarithm of P2 to the base Y */
|
||||
static int secp256k1_dleq_prove(const secp256k1_context* ctx, secp256k1_scalar *s, secp256k1_scalar *e, const secp256k1_scalar *sk, secp256k1_ge *gen2, secp256k1_ge *p1, secp256k1_ge *p2, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
|
||||
secp256k1_ge r1, r2;
|
||||
secp256k1_scalar k = { 0 };
|
||||
unsigned char sk32[32];
|
||||
unsigned char gen2_33[33];
|
||||
unsigned char p1_33[33];
|
||||
unsigned char p2_33[33];
|
||||
int ret = 1;
|
||||
size_t pubkey_size = 33;
|
||||
|
||||
secp256k1_scalar_get_b32(sk32, sk);
|
||||
if (!secp256k1_eckey_pubkey_serialize(gen2, gen2_33, &pubkey_size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_eckey_pubkey_serialize(p1, p1_33, &pubkey_size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_eckey_pubkey_serialize(p2, p2_33, &pubkey_size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret &= secp256k1_dleq_nonce(&k, sk32, gen2_33, p1_33, p2_33, noncefp, ndata);
|
||||
/* R1 = k*G, R2 = k*Y */
|
||||
secp256k1_dleq_pair(&ctx->ecmult_gen_ctx, &r1, &r2, &k, gen2);
|
||||
/* We declassify the non-secret values r1 and r2 to allow using them as
|
||||
* branch points. */
|
||||
secp256k1_declassify(ctx, &r1, sizeof(r1));
|
||||
secp256k1_declassify(ctx, &r2, sizeof(r2));
|
||||
|
||||
/* e = tagged hash(p1, gen2, p2, r1, r2) */
|
||||
/* s = k + e * sk */
|
||||
secp256k1_dleq_challenge(e, gen2, &r1, &r2, p1, p2);
|
||||
secp256k1_scalar_mul(s, e, sk);
|
||||
secp256k1_scalar_add(s, s, &k);
|
||||
|
||||
secp256k1_scalar_clear(&k);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int secp256k1_dleq_verify(const secp256k1_ecmult_context *ecmult_ctx, const secp256k1_scalar *s, const secp256k1_scalar *e, secp256k1_ge *p1, secp256k1_ge *gen2, secp256k1_ge *p2) {
|
||||
secp256k1_scalar e_neg;
|
||||
secp256k1_scalar e_expected;
|
||||
secp256k1_gej gen2j;
|
||||
secp256k1_gej p1j, p2j;
|
||||
secp256k1_gej r1j, r2j;
|
||||
secp256k1_ge r1, r2;
|
||||
secp256k1_gej tmpj;
|
||||
|
||||
secp256k1_gej_set_ge(&p1j, p1);
|
||||
secp256k1_gej_set_ge(&p2j, p2);
|
||||
|
||||
secp256k1_scalar_negate(&e_neg, e);
|
||||
/* R1 = s*G - e*P1 */
|
||||
secp256k1_ecmult(ecmult_ctx, &r1j, &p1j, &e_neg, s);
|
||||
/* R2 = s*gen2 - e*P2 */
|
||||
secp256k1_ecmult(ecmult_ctx, &tmpj, &p2j, &e_neg, &secp256k1_scalar_zero);
|
||||
secp256k1_gej_set_ge(&gen2j, gen2);
|
||||
secp256k1_ecmult(ecmult_ctx, &r2j, &gen2j, s, &secp256k1_scalar_zero);
|
||||
secp256k1_gej_add_var(&r2j, &r2j, &tmpj, NULL);
|
||||
|
||||
secp256k1_ge_set_gej(&r1, &r1j);
|
||||
secp256k1_ge_set_gej(&r2, &r2j);
|
||||
secp256k1_dleq_challenge(&e_expected, gen2, &r1, &r2, p1, p2);
|
||||
|
||||
secp256k1_scalar_add(&e_expected, &e_expected, &e_neg);
|
||||
return secp256k1_scalar_is_zero(&e_expected);
|
||||
}
|
||||
|
||||
#endif
|
365
src/modules/ecdsa_adaptor/main_impl.h
Normal file
365
src/modules/ecdsa_adaptor/main_impl.h
Normal file
@ -0,0 +1,365 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020-2021 Jonas Nick, Jesse Posner *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ECDSA_ADAPTOR_MAIN_H
|
||||
#define SECP256K1_MODULE_ECDSA_ADAPTOR_MAIN_H
|
||||
|
||||
#include "include/secp256k1_ecdsa_adaptor.h"
|
||||
#include "modules/ecdsa_adaptor/dleq_impl.h"
|
||||
|
||||
/* (R, R', s', dleq_proof) */
|
||||
static int secp256k1_ecdsa_adaptor_sig_serialize(unsigned char *adaptor_sig162, secp256k1_ge *r, secp256k1_ge *rp, const secp256k1_scalar *sp, const secp256k1_scalar *dleq_proof_e, const secp256k1_scalar *dleq_proof_s) {
|
||||
size_t size = 33;
|
||||
|
||||
if (!secp256k1_eckey_pubkey_serialize(r, adaptor_sig162, &size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_eckey_pubkey_serialize(rp, &adaptor_sig162[33], &size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_get_b32(&adaptor_sig162[66], sp);
|
||||
secp256k1_scalar_get_b32(&adaptor_sig162[98], dleq_proof_e);
|
||||
secp256k1_scalar_get_b32(&adaptor_sig162[130], dleq_proof_s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_adaptor_sig_deserialize(secp256k1_ge *r, secp256k1_scalar *sigr, secp256k1_ge *rp, secp256k1_scalar *sp, secp256k1_scalar *dleq_proof_e, secp256k1_scalar *dleq_proof_s, const unsigned char *adaptor_sig162) {
|
||||
/* If r is deserialized, require that a sigr is provided to receive
|
||||
* the X-coordinate */
|
||||
VERIFY_CHECK((r == NULL) || (r != NULL && sigr != NULL));
|
||||
if (r != NULL) {
|
||||
if (!secp256k1_eckey_pubkey_parse(r, &adaptor_sig162[0], 33)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (sigr != NULL) {
|
||||
secp256k1_scalar_set_b32(sigr, &adaptor_sig162[1], NULL);
|
||||
if (secp256k1_scalar_is_zero(sigr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (rp != NULL) {
|
||||
if (!secp256k1_eckey_pubkey_parse(rp, &adaptor_sig162[33], 33)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (sp != NULL) {
|
||||
if (!secp256k1_scalar_set_b32_seckey(sp, &adaptor_sig162[66])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (dleq_proof_e != NULL) {
|
||||
secp256k1_scalar_set_b32(dleq_proof_e, &adaptor_sig162[98], NULL);
|
||||
}
|
||||
if (dleq_proof_s != NULL) {
|
||||
int overflow;
|
||||
secp256k1_scalar_set_b32(dleq_proof_s, &adaptor_sig162[130], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("ECDSAadaptor/non")||SHA256("ECDSAadaptor/non"). */
|
||||
static void secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x791dae43ul;
|
||||
sha->s[1] = 0xe52d3b44ul;
|
||||
sha->s[2] = 0x37f9edeaul;
|
||||
sha->s[3] = 0x9bfd2ab1ul;
|
||||
sha->s[4] = 0xcfb0f44dul;
|
||||
sha->s[5] = 0xccf1d880ul;
|
||||
sha->s[6] = 0xd18f2c13ul;
|
||||
sha->s[7] = 0xa37b9024ul;
|
||||
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("ECDSAadaptor/aux")||SHA256("ECDSAadaptor/aux"). */
|
||||
static void secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0xd14c7bd9ul;
|
||||
sha->s[1] = 0x095d35e6ul;
|
||||
sha->s[2] = 0xb8490a88ul;
|
||||
sha->s[3] = 0xfb00ef74ul;
|
||||
sha->s[4] = 0x0baa488ful;
|
||||
sha->s[5] = 0x69366693ul;
|
||||
sha->s[6] = 0x1c81c5baul;
|
||||
sha->s[7] = 0xc33b296aul;
|
||||
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* algo argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */
|
||||
static const unsigned char ecdsa_adaptor_algo[16] = "ECDSAadaptor/non";
|
||||
|
||||
/* Modified BIP-340 nonce function */
|
||||
static int nonce_function_ecdsa_adaptor(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *pk33, const unsigned char *algo, size_t algolen, void *data) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char masked_key[32];
|
||||
int i;
|
||||
|
||||
if (algo == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
secp256k1_nonce_function_ecdsa_adaptor_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 algo which is important to avoid nonce reuse across
|
||||
* algorithims. An optimized tagging implementation is used if the default
|
||||
* tag is provided. */
|
||||
if (algolen == sizeof(ecdsa_adaptor_algo)
|
||||
&& secp256k1_memcmp_var(algo, ecdsa_adaptor_algo, algolen) == 0) {
|
||||
secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(&sha);
|
||||
} else if (algolen == sizeof(dleq_algo)
|
||||
&& secp256k1_memcmp_var(algo, dleq_algo, algolen) == 0) {
|
||||
secp256k1_nonce_function_dleq_sha256_tagged(&sha);
|
||||
} else {
|
||||
secp256k1_sha256_initialize_tagged(&sha, algo, algolen);
|
||||
}
|
||||
|
||||
/* Hash (masked-)key||pk||msg using the tagged hash as per BIP-340 */
|
||||
if (data != NULL) {
|
||||
secp256k1_sha256_write(&sha, masked_key, 32);
|
||||
} else {
|
||||
secp256k1_sha256_write(&sha, key32, 32);
|
||||
}
|
||||
secp256k1_sha256_write(&sha, pk33, 33);
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
secp256k1_sha256_finalize(&sha, nonce32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor = nonce_function_ecdsa_adaptor;
|
||||
|
||||
int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char *adaptor_sig162, unsigned char *seckey32, const secp256k1_pubkey *enckey, const unsigned char *msg32, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
|
||||
secp256k1_scalar k;
|
||||
secp256k1_gej rj, rpj;
|
||||
secp256k1_ge r, rp;
|
||||
secp256k1_ge enckey_ge;
|
||||
secp256k1_scalar dleq_proof_s;
|
||||
secp256k1_scalar dleq_proof_e;
|
||||
secp256k1_scalar sk;
|
||||
secp256k1_scalar msg;
|
||||
secp256k1_scalar sp;
|
||||
secp256k1_scalar sigr;
|
||||
secp256k1_scalar n;
|
||||
unsigned char nonce32[32] = { 0 };
|
||||
unsigned char buf33[33];
|
||||
size_t size = 33;
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(adaptor_sig162 != NULL);
|
||||
ARG_CHECK(seckey32 != NULL);
|
||||
ARG_CHECK(enckey != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
|
||||
secp256k1_scalar_clear(&dleq_proof_e);
|
||||
secp256k1_scalar_clear(&dleq_proof_s);
|
||||
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_ecdsa_adaptor;
|
||||
}
|
||||
|
||||
ret &= secp256k1_pubkey_load(ctx, &enckey_ge, enckey);
|
||||
ret &= secp256k1_eckey_pubkey_serialize(&enckey_ge, buf33, &size, 1);
|
||||
ret &= !!noncefp(nonce32, msg32, seckey32, buf33, ecdsa_adaptor_algo, sizeof(ecdsa_adaptor_algo), ndata);
|
||||
secp256k1_scalar_set_b32(&k, nonce32, NULL);
|
||||
ret &= !secp256k1_scalar_is_zero(&k);
|
||||
secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
|
||||
|
||||
/* R' := k*G */
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rpj, &k);
|
||||
secp256k1_ge_set_gej(&rp, &rpj);
|
||||
/* R = k*Y; */
|
||||
secp256k1_ecmult_const(&rj, &enckey_ge, &k, 256);
|
||||
secp256k1_ge_set_gej(&r, &rj);
|
||||
/* We declassify the non-secret values rp and r to allow using them
|
||||
* as branch points. */
|
||||
secp256k1_declassify(ctx, &rp, sizeof(rp));
|
||||
secp256k1_declassify(ctx, &r, sizeof(r));
|
||||
|
||||
/* dleq_proof = DLEQ_prove(k, (R', Y, R)) */
|
||||
ret &= secp256k1_dleq_prove(ctx, &dleq_proof_s, &dleq_proof_e, &k, &enckey_ge, &rp, &r, noncefp, ndata);
|
||||
|
||||
ret &= secp256k1_scalar_set_b32_seckey(&sk, seckey32);
|
||||
secp256k1_scalar_cmov(&sk, &secp256k1_scalar_one, !ret);
|
||||
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
||||
secp256k1_fe_normalize(&r.x);
|
||||
secp256k1_fe_get_b32(buf33, &r.x);
|
||||
secp256k1_scalar_set_b32(&sigr, buf33, NULL);
|
||||
ret &= !secp256k1_scalar_is_zero(&sigr);
|
||||
/* s' = k⁻¹(m + R.x * x) */
|
||||
secp256k1_scalar_mul(&n, &sigr, &sk);
|
||||
secp256k1_scalar_add(&n, &n, &msg);
|
||||
secp256k1_scalar_inverse(&sp, &k);
|
||||
secp256k1_scalar_mul(&sp, &sp, &n);
|
||||
ret &= !secp256k1_scalar_is_zero(&sp);
|
||||
|
||||
/* return (R, R', s', dleq_proof) */
|
||||
ret &= secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig162, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s);
|
||||
|
||||
secp256k1_memczero(adaptor_sig162, 162, !ret);
|
||||
secp256k1_scalar_clear(&n);
|
||||
secp256k1_scalar_clear(&k);
|
||||
secp256k1_scalar_clear(&sk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_adaptor_verify(const secp256k1_context* ctx, const unsigned char *adaptor_sig162, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_pubkey *enckey) {
|
||||
secp256k1_scalar dleq_proof_s, dleq_proof_e;
|
||||
secp256k1_scalar msg;
|
||||
secp256k1_ge pubkey_ge;
|
||||
secp256k1_ge r, rp;
|
||||
secp256k1_scalar sp;
|
||||
secp256k1_scalar sigr;
|
||||
secp256k1_ge enckey_ge;
|
||||
secp256k1_gej derived_rp;
|
||||
secp256k1_scalar sn, u1, u2;
|
||||
secp256k1_gej pubkeyj;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(adaptor_sig162 != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(enckey != NULL);
|
||||
|
||||
if (!secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig162)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_pubkey_load(ctx, &enckey_ge, enckey)) {
|
||||
return 0;
|
||||
}
|
||||
/* DLEQ_verify((R', Y, R), dleq_proof) */
|
||||
if(!secp256k1_dleq_verify(&ctx->ecmult_ctx, &dleq_proof_s, &dleq_proof_e, &rp, &enckey_ge, &r)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
||||
if (!secp256k1_pubkey_load(ctx, &pubkey_ge, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return R' == s'⁻¹(m * G + R.x * X) */
|
||||
secp256k1_scalar_inverse_var(&sn, &sp);
|
||||
secp256k1_scalar_mul(&u1, &sn, &msg);
|
||||
secp256k1_scalar_mul(&u2, &sn, &sigr);
|
||||
secp256k1_gej_set_ge(&pubkeyj, &pubkey_ge);
|
||||
secp256k1_ecmult(&ctx->ecmult_ctx, &derived_rp, &pubkeyj, &u2, &u1);
|
||||
if (secp256k1_gej_is_infinity(&derived_rp)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_neg(&derived_rp, &derived_rp);
|
||||
secp256k1_gej_add_ge_var(&derived_rp, &derived_rp, &rp, NULL);
|
||||
return secp256k1_gej_is_infinity(&derived_rp);
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_adaptor_decrypt(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sig, const unsigned char *deckey32, const unsigned char *adaptor_sig162) {
|
||||
secp256k1_scalar deckey;
|
||||
secp256k1_scalar sp;
|
||||
secp256k1_scalar s;
|
||||
secp256k1_scalar sigr;
|
||||
int overflow;
|
||||
int high;
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(deckey32 != NULL);
|
||||
ARG_CHECK(adaptor_sig162 != NULL);
|
||||
|
||||
secp256k1_scalar_clear(&sp);
|
||||
secp256k1_scalar_set_b32(&deckey, deckey32, &overflow);
|
||||
ret &= !overflow;
|
||||
ret &= secp256k1_ecdsa_adaptor_sig_deserialize(NULL, &sigr, NULL, &sp, NULL, NULL, adaptor_sig162);
|
||||
ret &= !secp256k1_scalar_is_zero(&deckey);
|
||||
secp256k1_scalar_inverse(&s, &deckey);
|
||||
/* s = s' * y⁻¹ */
|
||||
secp256k1_scalar_mul(&s, &s, &sp);
|
||||
high = secp256k1_scalar_is_high(&s);
|
||||
secp256k1_scalar_cond_negate(&s, high);
|
||||
secp256k1_ecdsa_signature_save(sig, &sigr, &s);
|
||||
|
||||
secp256k1_memczero(&sig->data[0], 64, !ret);
|
||||
secp256k1_scalar_clear(&deckey);
|
||||
secp256k1_scalar_clear(&sp);
|
||||
secp256k1_scalar_clear(&s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_adaptor_recover(const secp256k1_context* ctx, unsigned char *deckey32, const secp256k1_ecdsa_signature *sig, const unsigned char *adaptor_sig162, const secp256k1_pubkey *enckey) {
|
||||
secp256k1_scalar sp, adaptor_sigr;
|
||||
secp256k1_scalar s, r;
|
||||
secp256k1_scalar deckey;
|
||||
secp256k1_ge enckey_expected_ge;
|
||||
secp256k1_gej enckey_expected_gej;
|
||||
unsigned char enckey33[33];
|
||||
unsigned char enckey_expected33[33];
|
||||
size_t size = 33;
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(deckey32 != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(adaptor_sig162 != NULL);
|
||||
ARG_CHECK(enckey != NULL);
|
||||
|
||||
if (!secp256k1_ecdsa_adaptor_sig_deserialize(NULL, &adaptor_sigr, NULL, &sp, NULL, NULL, adaptor_sig162)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
|
||||
/* Check that we're not looking at some unrelated signature */
|
||||
ret &= secp256k1_scalar_eq(&adaptor_sigr, &r);
|
||||
/* y = s⁻¹ * s' */
|
||||
ret &= !secp256k1_scalar_is_zero(&s);
|
||||
secp256k1_scalar_inverse(&deckey, &s);
|
||||
secp256k1_scalar_mul(&deckey, &deckey, &sp);
|
||||
|
||||
/* Deal with ECDSA malleability */
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &enckey_expected_gej, &deckey);
|
||||
secp256k1_ge_set_gej(&enckey_expected_ge, &enckey_expected_gej);
|
||||
/* We declassify non-secret enckey_expected_ge to allow using it as a
|
||||
* branch point. */
|
||||
secp256k1_declassify(ctx, &enckey_expected_ge, sizeof(enckey_expected_ge));
|
||||
if (!secp256k1_eckey_pubkey_serialize(&enckey_expected_ge, enckey_expected33, &size, SECP256K1_EC_COMPRESSED)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ec_pubkey_serialize(ctx, enckey33, &size, enckey, SECP256K1_EC_COMPRESSED)) {
|
||||
return 0;
|
||||
}
|
||||
if (secp256k1_memcmp_var(&enckey_expected33[1], &enckey33[1], 32) != 0) {
|
||||
return 0;
|
||||
}
|
||||
if (enckey_expected33[0] != enckey33[0]) {
|
||||
/* try Y_implied == -Y */
|
||||
secp256k1_scalar_negate(&deckey, &deckey);
|
||||
}
|
||||
secp256k1_scalar_get_b32(deckey32, &deckey);
|
||||
|
||||
secp256k1_scalar_clear(&deckey);
|
||||
secp256k1_scalar_clear(&sp);
|
||||
secp256k1_scalar_clear(&s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
1221
src/modules/ecdsa_adaptor/tests_impl.h
Normal file
1221
src/modules/ecdsa_adaptor/tests_impl.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -831,6 +831,10 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
|
||||
# include "modules/ecdsa_s2c/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDSA_ADAPTOR
|
||||
# include "modules/ecdsa_adaptor/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
# include "modules/musig/main_impl.h"
|
||||
#endif
|
||||
|
@ -5652,6 +5652,10 @@ void run_ecdsa_openssl(void) {
|
||||
# include "modules/ecdsa_s2c/tests_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDSA_ADAPTOR
|
||||
# include "modules/ecdsa_adaptor/tests_impl.h"
|
||||
#endif
|
||||
|
||||
void run_secp256k1_memczero_test(void) {
|
||||
unsigned char buf1[6] = {1, 2, 3, 4, 5, 6};
|
||||
unsigned char buf2[sizeof(buf1)];
|
||||
@ -5966,6 +5970,10 @@ int main(int argc, char **argv) {
|
||||
run_ecdsa_s2c_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDSA_ADAPTOR
|
||||
run_ecdsa_adaptor_tests();
|
||||
#endif
|
||||
|
||||
/* util tests */
|
||||
run_secp256k1_memczero_test();
|
||||
|
||||
|
@ -31,6 +31,10 @@
|
||||
#include "include/secp256k1_ecdsa_s2c.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDSA_ADAPTOR
|
||||
#include "include/secp256k1_ecdsa_adaptor.h"
|
||||
#endif
|
||||
|
||||
void run_tests(secp256k1_context *ctx, unsigned char *key);
|
||||
|
||||
int main(void) {
|
||||
@ -199,4 +203,42 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
||||
CHECK(ret == 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDSA_ADAPTOR
|
||||
{
|
||||
unsigned char adaptor_sig[162];
|
||||
unsigned char deckey[32];
|
||||
unsigned char expected_deckey[32];
|
||||
secp256k1_pubkey enckey;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
deckey[i] = i + 2;
|
||||
}
|
||||
|
||||
ret = secp256k1_ec_pubkey_create(ctx, &enckey, deckey);
|
||||
CHECK(ret == 1);
|
||||
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
|
||||
ret = secp256k1_ecdsa_adaptor_encrypt(ctx, adaptor_sig, key, &enckey, msg, NULL, NULL);
|
||||
VALGRIND_MAKE_MEM_DEFINED(adaptor_sig, sizeof(adaptor_sig));
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(deckey, 32);
|
||||
ret = secp256k1_ecdsa_adaptor_decrypt(ctx, &signature, deckey, adaptor_sig);
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(&signature, 32);
|
||||
ret = secp256k1_ecdsa_adaptor_recover(ctx, expected_deckey, &signature, adaptor_sig, &enckey);
|
||||
VALGRIND_MAKE_MEM_DEFINED(expected_deckey, sizeof(expected_deckey));
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
VALGRIND_MAKE_MEM_DEFINED(deckey, sizeof(deckey));
|
||||
ret = secp256k1_memcmp_var(deckey, expected_deckey, sizeof(expected_deckey));
|
||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||
CHECK(ret == 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user