ecdsa_adaptor: add support for proof of discrete logarithm equality
This commit adds proving and verification functions for discrete logarithm equality. From the spec (https://github.com/discreetlogcontracts/dlcspecs/pull/114): "As part of the ECDSA adaptor signature a proof of discrete logarithm equality must be provided. This is a proof that the discrete logarithm of some X to the standard base G is the same as the discrete logarithm of some Z to the base Y. This proof can be constructed by using equality composition on two Sigma protocols proving knowledge of the discrete logarithm between both pairs of points. In other words the prover proves knowledge of a such that X = a * G and b such that Z = b * Y and that a = b. We make the resulting Sigma protocol non-interactive by applying the Fiat-Shamir transformation with SHA256 as the challenge hash."
This commit is contained in:
parent
d8f336564f
commit
b508e5dd9b
@ -1,2 +1,3 @@
|
||||
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
|
||||
|
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
|
@ -8,6 +8,7 @@
|
||||
#define SECP256K1_MODULE_ECDSA_ADAPTOR_MAIN_H
|
||||
|
||||
#include "include/secp256k1_ecdsa_adaptor.h"
|
||||
#include "modules/ecdsa_adaptor/dleq_impl.h"
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("ECDSAadaptor/non")||SHA256("ECDSAadaptor/non"). */
|
||||
@ -69,6 +70,9 @@ static int nonce_function_ecdsa_adaptor(unsigned char *nonce32, const unsigned c
|
||||
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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user