33 changed files with 676 additions and 937 deletions
@ -1,173 +0,0 @@
@@ -1,173 +0,0 @@
|
||||
#ifndef _SECP256K1_SCHNORR_ |
||||
# define _SECP256K1_SCHNORR_ |
||||
|
||||
# include "secp256k1.h" |
||||
|
||||
# ifdef __cplusplus |
||||
extern "C" { |
||||
# endif |
||||
|
||||
/** Create a signature using a custom EC-Schnorr-SHA256 construction. It
|
||||
* produces non-malleable 64-byte signatures which support public key recovery |
||||
* batch validation, and multiparty signing. |
||||
* Returns: 1: signature created |
||||
* 0: the nonce generation function failed, or the private key was |
||||
* invalid. |
||||
* Args: ctx: pointer to a context object, initialized for signing |
||||
* (cannot be NULL) |
||||
* Out: sig64: pointer to a 64-byte array where the signature will be |
||||
* placed (cannot be NULL) |
||||
* In: msg32: the 32-byte message hash being signed (cannot be NULL) |
||||
* seckey: pointer to a 32-byte secret key (cannot be NULL) |
||||
* noncefp:pointer to a nonce generation function. If NULL, |
||||
* secp256k1_nonce_function_default is used |
||||
* ndata: pointer to arbitrary data used by the nonce generation |
||||
* function (can be NULL) |
||||
*/ |
||||
SECP256K1_API int secp256k1_schnorr_sign( |
||||
const secp256k1_context* ctx, |
||||
unsigned char *sig64, |
||||
const unsigned char *msg32, |
||||
const unsigned char *seckey, |
||||
secp256k1_nonce_function noncefp, |
||||
const void *ndata |
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); |
||||
|
||||
/** Verify a signature created by secp256k1_schnorr_sign.
|
||||
* Returns: 1: correct signature |
||||
* 0: incorrect signature |
||||
* Args: ctx: a secp256k1 context object, initialized for verification. |
||||
* In: sig64: the 64-byte signature being verified (cannot be NULL) |
||||
* msg32: the 32-byte message hash being verified (cannot be NULL) |
||||
* pubkey: the public key to verify with (cannot be NULL) |
||||
*/ |
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify( |
||||
const secp256k1_context* ctx, |
||||
const unsigned char *sig64, |
||||
const unsigned char *msg32, |
||||
const secp256k1_pubkey *pubkey |
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); |
||||
|
||||
/** Recover an EC public key from a Schnorr signature created using
|
||||
* secp256k1_schnorr_sign. |
||||
* Returns: 1: public key successfully recovered (which guarantees a correct |
||||
* signature). |
||||
* 0: otherwise. |
||||
* Args: ctx: pointer to a context object, initialized for |
||||
* verification (cannot be NULL) |
||||
* Out: pubkey: pointer to a pubkey to set to the recovered public key |
||||
* (cannot be NULL). |
||||
* In: sig64: signature as 64 byte array (cannot be NULL) |
||||
* msg32: the 32-byte message hash assumed to be signed (cannot |
||||
* be NULL) |
||||
*/ |
||||
SECP256K1_API int secp256k1_schnorr_recover( |
||||
const secp256k1_context* ctx, |
||||
secp256k1_pubkey *pubkey, |
||||
const unsigned char *sig64, |
||||
const unsigned char *msg32 |
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); |
||||
|
||||
/** Generate a nonce pair deterministically for use with
|
||||
* secp256k1_schnorr_partial_sign. |
||||
* Returns: 1: valid nonce pair was generated. |
||||
* 0: otherwise (nonce generation function failed) |
||||
* Args: ctx: pointer to a context object, initialized for signing |
||||
* (cannot be NULL) |
||||
* Out: pubnonce: public side of the nonce (cannot be NULL) |
||||
* privnonce32: private side of the nonce (32 byte) (cannot be NULL) |
||||
* In: msg32: the 32-byte message hash assumed to be signed (cannot |
||||
* be NULL) |
||||
* sec32: the 32-byte private key (cannot be NULL) |
||||
* noncefp: pointer to a nonce generation function. If NULL, |
||||
* secp256k1_nonce_function_default is used |
||||
* noncedata: pointer to arbitrary data used by the nonce generation |
||||
* function (can be NULL) |
||||
* |
||||
* Do not use the output as a private/public key pair for signing/validation. |
||||
*/ |
||||
SECP256K1_API int secp256k1_schnorr_generate_nonce_pair( |
||||
const secp256k1_context* ctx, |
||||
secp256k1_pubkey *pubnonce, |
||||
unsigned char *privnonce32, |
||||
const unsigned char *msg32, |
||||
const unsigned char *sec32, |
||||
secp256k1_nonce_function noncefp, |
||||
const void* noncedata |
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
||||
|
||||
/** Produce a partial Schnorr signature, which can be combined using
|
||||
* secp256k1_schnorr_partial_combine, to end up with a full signature that is |
||||
* verifiable using secp256k1_schnorr_verify. |
||||
* Returns: 1: signature created successfully. |
||||
* 0: no valid signature exists with this combination of keys, nonces |
||||
* and message (chance around 1 in 2^128) |
||||
* -1: invalid private key, nonce, or public nonces. |
||||
* Args: ctx: pointer to context object, initialized for signing (cannot |
||||
* be NULL) |
||||
* Out: sig64: pointer to 64-byte array to put partial signature in |
||||
* In: msg32: pointer to 32-byte message to sign |
||||
* sec32: pointer to 32-byte private key |
||||
* pubnonce_others: pointer to pubkey containing the sum of the other's |
||||
* nonces (see secp256k1_ec_pubkey_combine) |
||||
* secnonce32: pointer to 32-byte array containing our nonce |
||||
* |
||||
* The intended procedure for creating a multiparty signature is: |
||||
* - Each signer S[i] with private key x[i] and public key Q[i] runs |
||||
* secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of |
||||
* private/public nonces. |
||||
* - All signers communicate their public nonces to each other (revealing your |
||||
* private nonce can lead to discovery of your private key, so it should be |
||||
* considered secret). |
||||
* - All signers combine all the public nonces they received (excluding their |
||||
* own) using secp256k1_ec_pubkey_combine to obtain an |
||||
* Rall[i] = sum(R[0..i-1,i+1..n]). |
||||
* - All signers produce a partial signature using |
||||
* secp256k1_schnorr_partial_sign, passing in their own private key x[i], |
||||
* their own private nonce k[i], and the sum of the others' public nonces |
||||
* Rall[i]. |
||||
* - All signers communicate their partial signatures to each other. |
||||
* - Someone combines all partial signatures using |
||||
* secp256k1_schnorr_partial_combine, to obtain a full signature. |
||||
* - The resulting signature is validatable using secp256k1_schnorr_verify, with |
||||
* public key equal to the result of secp256k1_ec_pubkey_combine of the |
||||
* signers' public keys (sum(Q[0..n])). |
||||
* |
||||
* Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine |
||||
* function take their arguments in any order, and it is possible to |
||||
* pre-combine several inputs already with one call, and add more inputs later |
||||
* by calling the function again (they are commutative and associative). |
||||
*/ |
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign( |
||||
const secp256k1_context* ctx, |
||||
unsigned char *sig64, |
||||
const unsigned char *msg32, |
||||
const unsigned char *sec32, |
||||
const secp256k1_pubkey *pubnonce_others, |
||||
const unsigned char *secnonce32 |
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); |
||||
|
||||
/** Combine multiple Schnorr partial signatures.
|
||||
* Returns: 1: the passed signatures were successfully combined. |
||||
* 0: the resulting signature is not valid (chance of 1 in 2^256) |
||||
* -1: some inputs were invalid, or the signatures were not created |
||||
* using the same set of nonces |
||||
* Args: ctx: pointer to a context object |
||||
* Out: sig64: pointer to a 64-byte array to place the combined signature |
||||
* (cannot be NULL) |
||||
* In: sig64sin: pointer to an array of n pointers to 64-byte input |
||||
* signatures |
||||
* n: the number of signatures to combine (at least 1) |
||||
*/ |
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine( |
||||
const secp256k1_context* ctx, |
||||
unsigned char *sig64, |
||||
const unsigned char * const * sig64sin, |
||||
size_t n |
||||
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
||||
|
||||
# ifdef __cplusplus |
||||
} |
||||
# endif |
||||
|
||||
#endif |
@ -1,10 +0,0 @@
@@ -1,10 +0,0 @@
|
||||
include_HEADERS += include/secp256k1_schnorr.h |
||||
noinst_HEADERS += src/modules/schnorr/main_impl.h |
||||
noinst_HEADERS += src/modules/schnorr/schnorr.h |
||||
noinst_HEADERS += src/modules/schnorr/schnorr_impl.h |
||||
noinst_HEADERS += src/modules/schnorr/tests_impl.h |
||||
if USE_BENCHMARK |
||||
noinst_PROGRAMS += bench_schnorr_verify |
||||
bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c |
||||
bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) |
||||
endif |
@ -1,164 +0,0 @@
@@ -1,164 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille * |
||||
* Distributed under the MIT software license, see the accompanying * |
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/ |
||||
|
||||
#ifndef SECP256K1_MODULE_SCHNORR_MAIN |
||||
#define SECP256K1_MODULE_SCHNORR_MAIN |
||||
|
||||
#include "include/secp256k1_schnorr.h" |
||||
#include "modules/schnorr/schnorr_impl.h" |
||||
|
||||
static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { |
||||
secp256k1_sha256_t sha; |
||||
secp256k1_sha256_initialize(&sha); |
||||
secp256k1_sha256_write(&sha, r32, 32); |
||||
secp256k1_sha256_write(&sha, msg32, 32); |
||||
secp256k1_sha256_finalize(&sha, h32); |
||||
} |
||||
|
||||
static const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 "; |
||||
|
||||
int secp256k1_schnorr_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { |
||||
secp256k1_scalar sec, non; |
||||
int ret = 0; |
||||
int overflow = 0; |
||||
unsigned int count = 0; |
||||
VERIFY_CHECK(ctx != NULL); |
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); |
||||
ARG_CHECK(msg32 != NULL); |
||||
ARG_CHECK(sig64 != NULL); |
||||
ARG_CHECK(seckey != NULL); |
||||
if (noncefp == NULL) { |
||||
noncefp = secp256k1_nonce_function_default; |
||||
} |
||||
|
||||
secp256k1_scalar_set_b32(&sec, seckey, NULL); |
||||
while (1) { |
||||
unsigned char nonce32[32]; |
||||
ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)noncedata, count); |
||||
if (!ret) { |
||||
break; |
||||
} |
||||
secp256k1_scalar_set_b32(&non, nonce32, &overflow); |
||||
memset(nonce32, 0, 32); |
||||
if (!secp256k1_scalar_is_zero(&non) && !overflow) { |
||||
if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, NULL, secp256k1_schnorr_msghash_sha256, msg32)) { |
||||
break; |
||||
} |
||||
} |
||||
count++; |
||||
} |
||||
if (!ret) { |
||||
memset(sig64, 0, 64); |
||||
} |
||||
secp256k1_scalar_clear(&non); |
||||
secp256k1_scalar_clear(&sec); |
||||
return ret; |
||||
} |
||||
|
||||
int secp256k1_schnorr_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { |
||||
secp256k1_ge q; |
||||
VERIFY_CHECK(ctx != NULL); |
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); |
||||
ARG_CHECK(msg32 != NULL); |
||||
ARG_CHECK(sig64 != NULL); |
||||
ARG_CHECK(pubkey != NULL); |
||||
|
||||
secp256k1_pubkey_load(ctx, &q, pubkey); |
||||
return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32); |
||||
} |
||||
|
||||
int secp256k1_schnorr_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *sig64, const unsigned char *msg32) { |
||||
secp256k1_ge q; |
||||
|
||||
VERIFY_CHECK(ctx != NULL); |
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); |
||||
ARG_CHECK(msg32 != NULL); |
||||
ARG_CHECK(sig64 != NULL); |
||||
ARG_CHECK(pubkey != NULL); |
||||
|
||||
if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32)) { |
||||
secp256k1_pubkey_save(pubkey, &q); |
||||
return 1; |
||||
} else { |
||||
memset(pubkey, 0, sizeof(*pubkey)); |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function noncefp, const void* noncedata) { |
||||
int count = 0; |
||||
int ret = 1; |
||||
secp256k1_gej Qj; |
||||
secp256k1_ge Q; |
||||
secp256k1_scalar sec; |
||||
|
||||
VERIFY_CHECK(ctx != NULL); |
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); |
||||
ARG_CHECK(msg32 != NULL); |
||||
ARG_CHECK(sec32 != NULL); |
||||
ARG_CHECK(pubnonce != NULL); |
||||
ARG_CHECK(privnonce32 != NULL); |
||||
|
||||
if (noncefp == NULL) { |
||||
noncefp = secp256k1_nonce_function_default; |
||||
} |
||||
|
||||
do { |
||||
int overflow; |
||||
ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, (void*)noncedata, count++); |
||||
if (!ret) { |
||||
break; |
||||
} |
||||
secp256k1_scalar_set_b32(&sec, privnonce32, &overflow); |
||||
if (overflow || secp256k1_scalar_is_zero(&sec)) { |
||||
continue; |
||||
} |
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sec); |
||||
secp256k1_ge_set_gej(&Q, &Qj); |
||||
|
||||
secp256k1_pubkey_save(pubnonce, &Q); |
||||
break; |
||||
} while(1); |
||||
|
||||
secp256k1_scalar_clear(&sec); |
||||
if (!ret) { |
||||
memset(pubnonce, 0, sizeof(*pubnonce)); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
int secp256k1_schnorr_partial_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey *pubnonce_others, const unsigned char *secnonce32) { |
||||
int overflow = 0; |
||||
secp256k1_scalar sec, non; |
||||
secp256k1_ge pubnon; |
||||
VERIFY_CHECK(ctx != NULL); |
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); |
||||
ARG_CHECK(msg32 != NULL); |
||||
ARG_CHECK(sig64 != NULL); |
||||
ARG_CHECK(sec32 != NULL); |
||||
ARG_CHECK(secnonce32 != NULL); |
||||
ARG_CHECK(pubnonce_others != NULL); |
||||
|
||||
secp256k1_scalar_set_b32(&sec, sec32, &overflow); |
||||
if (overflow || secp256k1_scalar_is_zero(&sec)) { |
||||
return -1; |
||||
} |
||||
secp256k1_scalar_set_b32(&non, secnonce32, &overflow); |
||||
if (overflow || secp256k1_scalar_is_zero(&non)) { |
||||
return -1; |
||||
} |
||||
secp256k1_pubkey_load(ctx, &pubnon, pubnonce_others); |
||||
return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32); |
||||
} |
||||
|
||||
int secp256k1_schnorr_partial_combine(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, size_t n) { |
||||
ARG_CHECK(sig64 != NULL); |
||||
ARG_CHECK(n >= 1); |
||||
ARG_CHECK(sig64sin != NULL); |
||||
return secp256k1_schnorr_sig_combine(sig64, n, sig64sin); |
||||
} |
||||
|
||||
#endif |
@ -1,20 +0,0 @@
@@ -1,20 +0,0 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille * |
||||
* Distributed under the MIT software license, see the accompanying * |
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
|
||||
***********************************************************************/ |
||||
|
||||
#ifndef _SECP256K1_MODULE_SCHNORR_H_ |
||||
#define _SECP256K1_MODULE_SCHNORR_H_ |
||||
|
||||
#include "scalar.h" |
||||
#include "group.h" |
||||
|
||||
typedef void (*secp256k1_schnorr_msghash)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32); |
||||
|
||||
static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32); |
||||
static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); |
||||
static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); |
||||
static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins); |
||||
|
||||
#endif |
@ -1,207 +0,0 @@
@@ -1,207 +0,0 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille * |
||||
* Distributed under the MIT software license, see the accompanying * |
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
|
||||
***********************************************************************/ |
||||
|
||||
#ifndef _SECP256K1_SCHNORR_IMPL_H_ |
||||
#define _SECP256K1_SCHNORR_IMPL_H_ |
||||
|
||||
#include <string.h> |
||||
|
||||
#include "schnorr.h" |
||||
#include "num.h" |
||||
#include "field.h" |
||||
#include "group.h" |
||||
#include "ecmult.h" |
||||
#include "ecmult_gen.h" |
||||
|
||||
/**
|
||||
* Custom Schnorr-based signature scheme. They support multiparty signing, public key |
||||
* recovery and batch validation. |
||||
* |
||||
* Rationale for verifying R's y coordinate: |
||||
* In order to support batch validation and public key recovery, the full R point must |
||||
* be known to verifiers, rather than just its x coordinate. In order to not risk |
||||
* being more strict in batch validation than normal validation, validators must be |
||||
* required to reject signatures with incorrect y coordinate. This is only possible |
||||
* by including a (relatively slow) field inverse, or a field square root. However, |
||||
* batch validation offers potentially much higher benefits than this cost. |
||||
* |
||||
* Rationale for having an implicit y coordinate oddness: |
||||
* If we commit to having the full R point known to verifiers, there are two mechanism. |
||||
* Either include its oddness in the signature, or give it an implicit fixed value. |
||||
* As the R y coordinate can be flipped by a simple negation of the nonce, we choose the |
||||
* latter, as it comes with nearly zero impact on signing or validation performance, and |
||||
* saves a byte in the signature. |
||||
* |
||||
* Signing: |
||||
* Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0) |
||||
* |
||||
* Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce). |
||||
* Compute 32-byte r, the serialization of R's x coordinate. |
||||
* Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order. |
||||
* Compute scalar s = k - h * x. |
||||
* The signature is (r, s). |
||||
* |
||||
* |
||||
* Verification: |
||||
* Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s) |
||||
* |
||||
* Signature is invalid if s >= order. |
||||
* Signature is invalid if r >= p. |
||||
* Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order. |
||||
* Option 1 (faster for single verification): |
||||
* Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd. |
||||
* Signature is valid if the serialization of R's x coordinate equals r. |
||||
* Option 2 (allows batch validation and pubkey recovery): |
||||
* Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve. |
||||
* Signature is valid if R + h * Q + s * G == 0. |
||||
*/ |
||||
|
||||
static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { |
||||
secp256k1_gej Rj; |
||||
secp256k1_ge Ra; |
||||
unsigned char h32[32]; |
||||
secp256k1_scalar h, s; |
||||
int overflow; |
||||
secp256k1_scalar n; |
||||
|
||||
if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) { |
||||
return 0; |
||||
} |
||||
n = *nonce; |
||||
|
||||
secp256k1_ecmult_gen(ctx, &Rj, &n); |
||||
if (pubnonce != NULL) { |
||||
secp256k1_gej_add_ge(&Rj, &Rj, pubnonce); |
||||
} |
||||
secp256k1_ge_set_gej(&Ra, &Rj); |
||||
secp256k1_fe_normalize(&Ra.y); |
||||
if (secp256k1_fe_is_odd(&Ra.y)) { |
||||
/* R's y coordinate is odd, which is not allowed (see rationale above).
|
||||
Force it to be even by negating the nonce. Note that this even works |
||||
for multiparty signing, as the R point is known to all participants, |
||||
which can all decide to flip the sign in unison, resulting in the |
||||
overall R point to be negated too. */ |
||||
secp256k1_scalar_negate(&n, &n); |
||||
} |
||||
secp256k1_fe_normalize(&Ra.x); |
||||
secp256k1_fe_get_b32(sig64, &Ra.x); |
||||
hash(h32, sig64, msg32); |
||||
overflow = 0; |
||||
secp256k1_scalar_set_b32(&h, h32, &overflow); |
||||
if (overflow || secp256k1_scalar_is_zero(&h)) { |
||||
secp256k1_scalar_clear(&n); |
||||
return 0; |
||||
} |
||||
secp256k1_scalar_mul(&s, &h, key); |
||||
secp256k1_scalar_negate(&s, &s); |
||||
secp256k1_scalar_add(&s, &s, &n); |
||||
secp256k1_scalar_clear(&n); |
||||
secp256k1_scalar_get_b32(sig64 + 32, &s); |
||||
return 1; |
||||
} |
||||
|
||||
static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { |
||||
secp256k1_gej Qj, Rj; |
||||
secp256k1_ge Ra; |
||||
secp256k1_fe Rx; |
||||
secp256k1_scalar h, s; |
||||
unsigned char hh[32]; |
||||
int overflow; |
||||
|
||||
if (secp256k1_ge_is_infinity(pubkey)) { |
||||
return 0; |
||||
} |
||||
hash(hh, sig64, msg32); |
||||
overflow = 0; |
||||
secp256k1_scalar_set_b32(&h, hh, &overflow); |
||||