ecdsa_adaptor: add ECDSA adaptor signature APIs
This commit adds the ECDSA adaptor signature APIs: - Encrypted Signing Creates an adaptor signature, which includes a proof to verify the adaptor signature. - Encryption Verification Verifies that the adaptor decryption key can be extracted from the adaptor signature and the completed ECDSA signature. - Signature Decryption Derives an ECDSA signature from an adaptor signature and an adaptor decryption key. - Key Recovery Extracts the adaptor decryption key from the complete signature and the adaptor signature.
This commit is contained in:
parent
b508e5dd9b
commit
6955af5ca8
@ -10,7 +10,22 @@ extern "C" {
|
|||||||
* Lloyd Fournier
|
* Lloyd Fournier
|
||||||
* (https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-November/002316.html
|
* (https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-November/002316.html
|
||||||
* and https://github.com/LLFourn/one-time-VES/blob/master/main.pdf).
|
* 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.
|
/** A pointer to a function to deterministically generate a nonce.
|
||||||
*
|
*
|
||||||
@ -46,6 +61,100 @@ typedef int (*secp256k1_nonce_function_hardened_ecdsa_adaptor)(
|
|||||||
*/
|
*/
|
||||||
SECP256K1_API extern const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor;
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,6 +10,61 @@
|
|||||||
#include "include/secp256k1_ecdsa_adaptor.h"
|
#include "include/secp256k1_ecdsa_adaptor.h"
|
||||||
#include "modules/ecdsa_adaptor/dleq_impl.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
|
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||||
* SHA256 to SHA256("ECDSAadaptor/non")||SHA256("ECDSAadaptor/non"). */
|
* SHA256 to SHA256("ECDSAadaptor/non")||SHA256("ECDSAadaptor/non"). */
|
||||||
static void secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(secp256k1_sha256 *sha) {
|
static void secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(secp256k1_sha256 *sha) {
|
||||||
@ -91,4 +146,220 @@ static int nonce_function_ecdsa_adaptor(unsigned char *nonce32, const unsigned c
|
|||||||
|
|
||||||
const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor = nonce_function_ecdsa_adaptor;
|
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
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user