Browse Source
We want the ecdh stuff for onion routing. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
Rusty Russell
9 years ago
67 changed files with 4320 additions and 1966 deletions
@ -0,0 +1,30 @@ |
|||
#ifndef _SECP256K1_ECDH_ |
|||
# define _SECP256K1_ECDH_ |
|||
|
|||
# include "secp256k1.h" |
|||
|
|||
# ifdef __cplusplus |
|||
extern "C" { |
|||
# endif |
|||
|
|||
/** Compute an EC Diffie-Hellman secret in constant time
|
|||
* Returns: 1: exponentiation was successful |
|||
* 0: scalar was invalid (zero or overflow) |
|||
* Args: ctx: pointer to a context object (cannot be NULL) |
|||
* Out: result: a 32-byte array which will be populated by an ECDH |
|||
* secret computed from the point and scalar |
|||
* In: point: pointer to a public point |
|||
* scalar: a 32-byte scalar with which to multiply the point |
|||
*/ |
|||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( |
|||
const secp256k1_context* ctx, |
|||
unsigned char *result, |
|||
const secp256k1_pubkey *point, |
|||
const unsigned char *scalar |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); |
|||
|
|||
# ifdef __cplusplus |
|||
} |
|||
# endif |
|||
|
|||
#endif |
@ -0,0 +1,110 @@ |
|||
#ifndef _SECP256K1_RECOVERY_ |
|||
# define _SECP256K1_RECOVERY_ |
|||
|
|||
# include "secp256k1.h" |
|||
|
|||
# ifdef __cplusplus |
|||
extern "C" { |
|||
# endif |
|||
|
|||
/** Opaque data structured that holds a parsed ECDSA signature,
|
|||
* supporting pubkey recovery. |
|||
* |
|||
* The exact representation of data inside is implementation defined and not |
|||
* guaranteed to be portable between different platforms or versions. It is |
|||
* however guaranteed to be 65 bytes in size, and can be safely copied/moved. |
|||
* If you need to convert to a format suitable for storage or transmission, use |
|||
* the secp256k1_ecdsa_signature_serialize_* and |
|||
* secp256k1_ecdsa_signature_serialize_* functions. |
|||
* |
|||
* Furthermore, it is guaranteed to identical signatures (including their |
|||
* recoverability) will have identical representation, so they can be |
|||
* memcmp'ed. |
|||
*/ |
|||
typedef struct { |
|||
unsigned char data[65]; |
|||
} secp256k1_ecdsa_recoverable_signature; |
|||
|
|||
/** Parse a compact ECDSA signature (64 bytes + recovery id).
|
|||
* |
|||
* Returns: 1 when the signature could be parsed, 0 otherwise |
|||
* Args: ctx: a secp256k1 context object |
|||
* Out: sig: a pointer to a signature object |
|||
* In: input64: a pointer to a 64-byte compact signature |
|||
* recid: the recovery id (0, 1, 2 or 3) |
|||
*/ |
|||
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_ecdsa_recoverable_signature* sig, |
|||
const unsigned char *input64, |
|||
int recid |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
/** Convert a recoverable signature into a normal signature.
|
|||
* |
|||
* Returns: 1 |
|||
* Out: sig: a pointer to a normal signature (cannot be NULL). |
|||
* In: sigin: a pointer to a recoverable signature (cannot be NULL). |
|||
*/ |
|||
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_ecdsa_signature* sig, |
|||
const secp256k1_ecdsa_recoverable_signature* sigin |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
|
|||
* |
|||
* Returns: 1 |
|||
* Args: ctx: a secp256k1 context object |
|||
* Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL) |
|||
* recid: a pointer to an integer to hold the recovery id (can be NULL). |
|||
* In: sig: a pointer to an initialized signature object (cannot be NULL) |
|||
*/ |
|||
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( |
|||
const secp256k1_context* ctx, |
|||
unsigned char *output64, |
|||
int *recid, |
|||
const secp256k1_ecdsa_recoverable_signature* sig |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); |
|||
|
|||
/** Create a recoverable ECDSA signature.
|
|||
* |
|||
* 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: sig: pointer to an 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_ecdsa_sign_recoverable( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_ecdsa_recoverable_signature *sig, |
|||
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); |
|||
|
|||
/** Recover an ECDSA public key from a signature.
|
|||
* |
|||
* 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 the recoved public key (cannot be NULL) |
|||
* In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL) |
|||
* msg32: the 32-byte message hash assumed to be signed (cannot be NULL) |
|||
*/ |
|||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_pubkey *pubkey, |
|||
const secp256k1_ecdsa_recoverable_signature *sig, |
|||
const unsigned char *msg32 |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); |
|||
|
|||
# ifdef __cplusplus |
|||
} |
|||
# endif |
|||
|
|||
#endif |
@ -0,0 +1,173 @@ |
|||
#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 succesfully. |
|||
* 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 succesfully 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, |
|||
int n |
|||
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
# ifdef __cplusplus |
|||
} |
|||
# endif |
|||
|
|||
#endif |
@ -0,0 +1,32 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2013, 2014 Pieter Wuille * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#ifndef _SECP256K1_BASIC_CONFIG_ |
|||
#define _SECP256K1_BASIC_CONFIG_ |
|||
|
|||
#ifdef USE_BASIC_CONFIG |
|||
|
|||
#undef USE_ASM_X86_64 |
|||
#undef USE_ENDOMORPHISM |
|||
#undef USE_FIELD_10X26 |
|||
#undef USE_FIELD_5X52 |
|||
#undef USE_FIELD_INV_BUILTIN |
|||
#undef USE_FIELD_INV_NUM |
|||
#undef USE_NUM_GMP |
|||
#undef USE_NUM_NONE |
|||
#undef USE_SCALAR_4X64 |
|||
#undef USE_SCALAR_8X32 |
|||
#undef USE_SCALAR_INV_BUILTIN |
|||
#undef USE_SCALAR_INV_NUM |
|||
|
|||
#define USE_NUM_NONE 1 |
|||
#define USE_FIELD_INV_BUILTIN 1 |
|||
#define USE_SCALAR_INV_BUILTIN 1 |
|||
#define USE_FIELD_10X26 1 |
|||
#define USE_SCALAR_8X32 1 |
|||
|
|||
#endif // USE_BASIC_CONFIG
|
|||
#endif // _SECP256K1_BASIC_CONFIG_
|
@ -0,0 +1,53 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#include <string.h> |
|||
|
|||
#include "include/secp256k1.h" |
|||
#include "include/secp256k1_ecdh.h" |
|||
#include "util.h" |
|||
#include "bench.h" |
|||
|
|||
typedef struct { |
|||
secp256k1_context *ctx; |
|||
secp256k1_pubkey point; |
|||
unsigned char scalar[32]; |
|||
} bench_ecdh_t; |
|||
|
|||
static void bench_ecdh_setup(void* arg) { |
|||
int i; |
|||
bench_ecdh_t *data = (bench_ecdh_t*)arg; |
|||
const unsigned char point[] = { |
|||
0x03, |
|||
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, |
|||
0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, |
|||
0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, |
|||
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f |
|||
}; |
|||
|
|||
data->ctx = secp256k1_context_create(0); |
|||
for (i = 0; i < 32; i++) { |
|||
data->scalar[i] = i + 1; |
|||
} |
|||
CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); |
|||
} |
|||
|
|||
static void bench_ecdh(void* arg) { |
|||
int i; |
|||
unsigned char res[32]; |
|||
bench_ecdh_t *data = (bench_ecdh_t*)arg; |
|||
|
|||
for (i = 0; i < 20000; i++) { |
|||
CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1); |
|||
} |
|||
} |
|||
|
|||
int main(void) { |
|||
bench_ecdh_t data; |
|||
|
|||
run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); |
|||
return 0; |
|||
} |
@ -0,0 +1,15 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2015 Andrew Poelstra * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#ifndef _SECP256K1_ECMULT_CONST_ |
|||
#define _SECP256K1_ECMULT_CONST_ |
|||
|
|||
#include "scalar.h" |
|||
#include "group.h" |
|||
|
|||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); |
|||
|
|||
#endif |
@ -0,0 +1,260 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#ifndef _SECP256K1_ECMULT_CONST_IMPL_ |
|||
#define _SECP256K1_ECMULT_CONST_IMPL_ |
|||
|
|||
#include "scalar.h" |
|||
#include "group.h" |
|||
#include "ecmult_const.h" |
|||
#include "ecmult_impl.h" |
|||
|
|||
#ifdef USE_ENDOMORPHISM |
|||
#define WNAF_BITS 128 |
|||
#else |
|||
#define WNAF_BITS 256 |
|||
#endif |
|||
#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w)) |
|||
|
|||
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */ |
|||
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ |
|||
int m; \ |
|||
int abs_n = (n) * (((n) > 0) * 2 - 1); \ |
|||
int idx_n = abs_n / 2; \ |
|||
secp256k1_fe neg_y; \ |
|||
VERIFY_CHECK(((n) & 1) == 1); \ |
|||
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ |
|||
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ |
|||
VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \ |
|||
VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \ |
|||
for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \ |
|||
/* This loop is used to avoid secret data in array indices. See
|
|||
* the comment in ecmult_gen_impl.h for rationale. */ \ |
|||
secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \ |
|||
secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \ |
|||
} \ |
|||
(r)->infinity = 0; \ |
|||
secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ |
|||
secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \ |
|||
} while(0) |
|||
|
|||
|
|||
/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val)
|
|||
* with the following guarantees: |
|||
* - each wnaf[i] an odd integer between -(1 << w) and (1 << w) |
|||
* - each wnaf[i] is nonzero |
|||
* - the number of words set is returned; this is always (WNAF_BITS + w - 1) / w |
|||
* |
|||
* Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar |
|||
* Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) |
|||
* CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003 |
|||
* |
|||
* Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 |
|||
*/ |
|||
static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) { |
|||
int global_sign; |
|||
int skew = 0; |
|||
int word = 0; |
|||
/* 1 2 3 */ |
|||
int u_last; |
|||
int u; |
|||
|
|||
#ifdef USE_ENDOMORPHISM |
|||
int flip; |
|||
int bit; |
|||
secp256k1_scalar neg_s; |
|||
int not_neg_one; |
|||
/* If we are using the endomorphism, we cannot handle even numbers by negating
|
|||
* them, since we are working with 128-bit numbers whose negations would be 256 |
|||
* bits, eliminating the performance advantage. Instead we use a technique from |
|||
* Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even) |
|||
* or 2 (for odd) to the number we are encoding, then compensating after the |
|||
* multiplication. */ |
|||
/* Negative 128-bit numbers will be negated, since otherwise they are 256-bit */ |
|||
flip = secp256k1_scalar_is_high(&s); |
|||
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ |
|||
bit = flip ^ (s.d[0] & 1); |
|||
/* We check for negative one, since adding 2 to it will cause an overflow */ |
|||
secp256k1_scalar_negate(&neg_s, &s); |
|||
not_neg_one = !secp256k1_scalar_is_one(&neg_s); |
|||
secp256k1_scalar_cadd_bit(&s, bit, not_neg_one); |
|||
/* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects
|
|||
* that we added two to it and flipped it. In fact for -1 these operations are |
|||
* identical. We only flipped, but since skewing is required (in the sense that |
|||
* the skew must be 1 or 2, never zero) and flipping is not, we need to change |
|||
* our flags to claim that we only skewed. */ |
|||
global_sign = secp256k1_scalar_cond_negate(&s, flip); |
|||
global_sign *= not_neg_one * 2 - 1; |
|||
skew = 1 << bit; |
|||
#else |
|||
/* Otherwise, we just negate to force oddness */ |
|||
int is_even = secp256k1_scalar_is_even(&s); |
|||
global_sign = secp256k1_scalar_cond_negate(&s, is_even); |
|||
#endif |
|||
|
|||
/* 4 */ |
|||
u_last = secp256k1_scalar_shr_int(&s, w); |
|||
while (word * w < WNAF_BITS) { |
|||
int sign; |
|||
int even; |
|||
|
|||
/* 4.1 4.4 */ |
|||
u = secp256k1_scalar_shr_int(&s, w); |
|||
/* 4.2 */ |
|||
even = ((u & 1) == 0); |
|||
sign = 2 * (u_last > 0) - 1; |
|||
u += sign * even; |
|||
u_last -= sign * even * (1 << w); |
|||
|
|||
/* 4.3, adapted for global sign change */ |
|||
wnaf[word++] = u_last * global_sign; |
|||
|
|||
u_last = u; |
|||
} |
|||
wnaf[word] = u * global_sign; |
|||
|
|||
VERIFY_CHECK(secp256k1_scalar_is_zero(&s)); |
|||
VERIFY_CHECK(word == WNAF_SIZE(w)); |
|||
return skew; |
|||
} |
|||
|
|||
|
|||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) { |
|||
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; |
|||
secp256k1_ge tmpa; |
|||
secp256k1_fe Z; |
|||
|
|||
#ifdef USE_ENDOMORPHISM |
|||
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; |
|||
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; |
|||
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; |
|||
int skew_1; |
|||
int skew_lam; |
|||
secp256k1_scalar q_1, q_lam; |
|||
#else |
|||
int wnaf[1 + WNAF_SIZE(WINDOW_A - 1)]; |
|||
#endif |
|||
|
|||
int i; |
|||
secp256k1_scalar sc = *scalar; |
|||
|
|||
/* build wnaf representation for q. */ |
|||
#ifdef USE_ENDOMORPHISM |
|||
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ |
|||
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc); |
|||
/* no need for zero correction when using endomorphism since even
|
|||
* numbers have one added to them anyway */ |
|||
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1); |
|||
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1); |
|||
#else |
|||
int is_zero = secp256k1_scalar_is_zero(scalar); |
|||
/* the wNAF ladder cannot handle zero, so bump this to one .. we will
|
|||
* correct the result after the fact */ |
|||
sc.d[0] += is_zero; |
|||
VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc)); |
|||
|
|||
secp256k1_wnaf_const(wnaf, sc, WINDOW_A - 1); |
|||
#endif |
|||
|
|||
/* Calculate odd multiples of a.
|
|||
* All multiples are brought to the same Z 'denominator', which is stored |
|||
* in Z. Due to secp256k1' isomorphism we can do all operations pretending |
|||
* that the Z coordinate was 1, use affine addition formulae, and correct |
|||
* the Z coordinate of the result once at the end. |
|||
*/ |
|||
secp256k1_gej_set_ge(r, a); |
|||
secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); |
|||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { |
|||
secp256k1_fe_normalize_weak(&pre_a[i].y); |
|||
} |
|||
#ifdef USE_ENDOMORPHISM |
|||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { |
|||
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); |
|||
} |
|||
#endif |
|||
|
|||
/* first loop iteration (separated out so we can directly set r, rather
|
|||
* than having it start at infinity, get doubled several times, then have |
|||
* its new value added to it) */ |
|||
#ifdef USE_ENDOMORPHISM |
|||
i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)]; |
|||
VERIFY_CHECK(i != 0); |
|||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); |
|||
secp256k1_gej_set_ge(r, &tmpa); |
|||
|
|||
i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)]; |
|||
VERIFY_CHECK(i != 0); |
|||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); |
|||
secp256k1_gej_add_ge(r, r, &tmpa); |
|||
#else |
|||
i = wnaf[WNAF_SIZE(WINDOW_A - 1)]; |
|||
VERIFY_CHECK(i != 0); |
|||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); |
|||
secp256k1_gej_set_ge(r, &tmpa); |
|||
#endif |
|||
/* remaining loop iterations */ |
|||
for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) { |
|||
int n; |
|||
int j; |
|||
for (j = 0; j < WINDOW_A - 1; ++j) { |
|||
secp256k1_gej_double_nonzero(r, r, NULL); |
|||
} |
|||
#ifdef USE_ENDOMORPHISM |
|||
n = wnaf_1[i]; |
|||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); |
|||
VERIFY_CHECK(n != 0); |
|||
secp256k1_gej_add_ge(r, r, &tmpa); |
|||
|
|||
n = wnaf_lam[i]; |
|||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); |
|||
VERIFY_CHECK(n != 0); |
|||
secp256k1_gej_add_ge(r, r, &tmpa); |
|||
#else |
|||
n = wnaf[i]; |
|||
VERIFY_CHECK(n != 0); |
|||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); |
|||
secp256k1_gej_add_ge(r, r, &tmpa); |
|||
#endif |
|||
} |
|||
|
|||
secp256k1_fe_mul(&r->z, &r->z, &Z); |
|||
|
|||
#ifdef USE_ENDOMORPHISM |
|||
{ |
|||
/* Correct for wNAF skew */ |
|||
secp256k1_ge correction = *a; |
|||
secp256k1_ge_storage correction_1_stor; |
|||
secp256k1_ge_storage correction_lam_stor; |
|||
secp256k1_ge_storage a2_stor; |
|||
secp256k1_gej tmpj; |
|||
secp256k1_gej_set_ge(&tmpj, &correction); |
|||
secp256k1_gej_double_var(&tmpj, &tmpj, NULL); |
|||
secp256k1_ge_set_gej(&correction, &tmpj); |
|||
secp256k1_ge_to_storage(&correction_1_stor, a); |
|||
secp256k1_ge_to_storage(&correction_lam_stor, a); |
|||
secp256k1_ge_to_storage(&a2_stor, &correction); |
|||
|
|||
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */ |
|||
secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2); |
|||
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2); |
|||
|
|||
/* Apply the correction */ |
|||
secp256k1_ge_from_storage(&correction, &correction_1_stor); |
|||
secp256k1_ge_neg(&correction, &correction); |
|||
secp256k1_gej_add_ge(r, r, &correction); |
|||
|
|||
secp256k1_ge_from_storage(&correction, &correction_lam_stor); |
|||
secp256k1_ge_neg(&correction, &correction); |
|||
secp256k1_ge_mul_lambda(&correction, &correction); |
|||
secp256k1_gej_add_ge(r, r, &correction); |
|||
} |
|||
#else |
|||
/* correct for zero */ |
|||
r->infinity |= is_zero; |
|||
#endif |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,9 @@ |
|||
include_HEADERS += include/secp256k1_ecdh.h |
|||
noinst_HEADERS += src/modules/ecdh/main_impl.h |
|||
noinst_HEADERS += src/modules/ecdh/tests_impl.h |
|||
if USE_BENCHMARK |
|||
noinst_PROGRAMS += bench_ecdh |
|||
bench_ecdh_SOURCES = src/bench_ecdh.c |
|||
bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) |
|||
bench_ecdh_LDFLAGS = -static |
|||
endif |
@ -0,0 +1,54 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2015 Andrew Poelstra * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#ifndef _SECP256K1_MODULE_ECDH_MAIN_ |
|||
#define _SECP256K1_MODULE_ECDH_MAIN_ |
|||
|
|||
#include "include/secp256k1_ecdh.h" |
|||
#include "ecmult_const_impl.h" |
|||
|
|||
int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) { |
|||
int ret = 0; |
|||
int overflow = 0; |
|||
secp256k1_gej res; |
|||
secp256k1_ge pt; |
|||
secp256k1_scalar s; |
|||
ARG_CHECK(result != NULL); |
|||
ARG_CHECK(point != NULL); |
|||
ARG_CHECK(scalar != NULL); |
|||
(void)ctx; |
|||
|
|||
secp256k1_pubkey_load(ctx, &pt, point); |
|||
secp256k1_scalar_set_b32(&s, scalar, &overflow); |
|||
if (overflow || secp256k1_scalar_is_zero(&s)) { |
|||
ret = 0; |
|||
} else { |
|||
unsigned char x[32]; |
|||
unsigned char y[1]; |
|||
secp256k1_sha256_t sha; |
|||
|
|||
secp256k1_ecmult_const(&res, &pt, &s); |
|||
secp256k1_ge_set_gej(&pt, &res); |
|||
/* Compute a hash of the point in compressed form
|
|||
* Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not |
|||
* expect its output to be secret and has a timing sidechannel. */ |
|||
secp256k1_fe_normalize(&pt.x); |
|||
secp256k1_fe_normalize(&pt.y); |
|||
secp256k1_fe_get_b32(x, &pt.x); |
|||
y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y); |
|||
|
|||
secp256k1_sha256_initialize(&sha); |
|||
secp256k1_sha256_write(&sha, y, sizeof(y)); |
|||
secp256k1_sha256_write(&sha, x, sizeof(x)); |
|||
secp256k1_sha256_finalize(&sha, result); |
|||
ret = 1; |
|||
} |
|||
|
|||
secp256k1_scalar_clear(&s); |
|||
return ret; |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,75 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2015 Andrew Poelstra * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#ifndef _SECP256K1_MODULE_ECDH_TESTS_ |
|||
#define _SECP256K1_MODULE_ECDH_TESTS_ |
|||
|
|||
void test_ecdh_generator_basepoint(void) { |
|||
unsigned char s_one[32] = { 0 }; |
|||
secp256k1_pubkey point[2]; |
|||
int i; |
|||
|
|||
s_one[31] = 1; |
|||
/* Check against pubkey creation when the basepoint is the generator */ |
|||
for (i = 0; i < 100; ++i) { |
|||
secp256k1_sha256_t sha; |
|||
unsigned char s_b32[32]; |
|||
unsigned char output_ecdh[32]; |
|||
unsigned char output_ser[32]; |
|||
unsigned char point_ser[33]; |
|||
size_t point_ser_len = sizeof(point_ser); |
|||
secp256k1_scalar s; |
|||
|
|||
random_scalar_order(&s); |
|||
secp256k1_scalar_get_b32(s_b32, &s); |
|||
|
|||
/* compute using ECDH function */ |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); |
|||
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1); |
|||
/* compute "explicitly" */ |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); |
|||
CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); |
|||
CHECK(point_ser_len == sizeof(point_ser)); |
|||
secp256k1_sha256_initialize(&sha); |
|||
secp256k1_sha256_write(&sha, point_ser, point_ser_len); |
|||
secp256k1_sha256_finalize(&sha, output_ser); |
|||
/* compare */ |
|||
CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0); |
|||
} |
|||
} |
|||
|
|||
void test_bad_scalar(void) { |
|||
unsigned char s_zero[32] = { 0 }; |
|||
unsigned char s_overflow[32] = { |
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, |
|||
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, |
|||
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 |
|||
}; |
|||
unsigned char s_rand[32] = { 0 }; |
|||
unsigned char output[32]; |
|||
secp256k1_scalar rand; |
|||
secp256k1_pubkey point; |
|||
|
|||
/* Create random point */ |
|||
random_scalar_order(&rand); |
|||
secp256k1_scalar_get_b32(s_rand, &rand); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1); |
|||
|
|||
/* Try to multiply it by bad values */ |
|||
CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0); |
|||
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0); |
|||
/* ...and a good one */ |
|||
s_overflow[31] -= 1; |
|||
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1); |
|||
} |
|||
|
|||
void run_ecdh_tests(void) { |
|||
test_ecdh_generator_basepoint(); |
|||
test_bad_scalar(); |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,9 @@ |
|||
include_HEADERS += include/secp256k1_recovery.h |
|||
noinst_HEADERS += src/modules/recovery/main_impl.h |
|||
noinst_HEADERS += src/modules/recovery/tests_impl.h |
|||
if USE_BENCHMARK |
|||
noinst_PROGRAMS += bench_recover |
|||
bench_recover_SOURCES = src/bench_recover.c |
|||
bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) |
|||
bench_recover_LDFLAGS = -static |
|||
endif |
@ -0,0 +1,156 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2013-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_RECOVERY_MAIN_ |
|||
#define _SECP256K1_MODULE_RECOVERY_MAIN_ |
|||
|
|||
#include "include/secp256k1_recovery.h" |
|||
|
|||
static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) { |
|||
(void)ctx; |
|||
if (sizeof(secp256k1_scalar) == 32) { |
|||
/* When the secp256k1_scalar type is exactly 32 byte, use its
|
|||
* representation inside secp256k1_ecdsa_signature, as conversion is very fast. |
|||
* Note that secp256k1_ecdsa_signature_save must use the same representation. */ |
|||
memcpy(r, &sig->data[0], 32); |
|||
memcpy(s, &sig->data[32], 32); |
|||
} else { |
|||
secp256k1_scalar_set_b32(r, &sig->data[0], NULL); |
|||
secp256k1_scalar_set_b32(s, &sig->data[32], NULL); |
|||
} |
|||
*recid = sig->data[64]; |
|||
} |
|||
|
|||
static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) { |
|||
if (sizeof(secp256k1_scalar) == 32) { |
|||
memcpy(&sig->data[0], r, 32); |
|||
memcpy(&sig->data[32], s, 32); |
|||
} else { |
|||
secp256k1_scalar_get_b32(&sig->data[0], r); |
|||
secp256k1_scalar_get_b32(&sig->data[32], s); |
|||
} |
|||
sig->data[64] = recid; |
|||
} |
|||
|
|||
int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) { |
|||
secp256k1_scalar r, s; |
|||
int ret = 1; |
|||
int overflow = 0; |
|||
|
|||
(void)ctx; |
|||
ARG_CHECK(sig != NULL); |
|||
ARG_CHECK(input64 != NULL); |
|||
ARG_CHECK(recid >= 0 && recid <= 3); |
|||
|
|||
secp256k1_scalar_set_b32(&r, &input64[0], &overflow); |
|||
ret &= !overflow; |
|||
secp256k1_scalar_set_b32(&s, &input64[32], &overflow); |
|||
ret &= !overflow; |
|||
if (ret) { |
|||
secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid); |
|||
} else { |
|||
memset(sig, 0, sizeof(*sig)); |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) { |
|||
secp256k1_scalar r, s; |
|||
|
|||
(void)ctx; |
|||
ARG_CHECK(output64 != NULL); |
|||
ARG_CHECK(sig != NULL); |
|||
|
|||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); |
|||
secp256k1_scalar_get_b32(&output64[0], &r); |
|||
secp256k1_scalar_get_b32(&output64[32], &s); |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) { |
|||
secp256k1_scalar r, s; |
|||
int recid; |
|||
|
|||
(void)ctx; |
|||
ARG_CHECK(sig != NULL); |
|||
ARG_CHECK(sigin != NULL); |
|||
|
|||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); |
|||
secp256k1_ecdsa_signature_save(sig, &r, &s); |
|||
return 1; |
|||
} |
|||
|
|||
int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { |
|||
secp256k1_scalar r, s; |
|||
secp256k1_scalar sec, non, msg; |
|||
int recid; |
|||
int ret = 0; |
|||
int overflow = 0; |
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); |
|||
ARG_CHECK(msg32 != NULL); |
|||
ARG_CHECK(signature != NULL); |
|||
ARG_CHECK(seckey != NULL); |
|||
if (noncefp == NULL) { |
|||
noncefp = secp256k1_nonce_function_default; |
|||
} |
|||
|
|||
secp256k1_scalar_set_b32(&sec, seckey, &overflow); |
|||
/* Fail if the secret key is invalid. */ |
|||
if (!overflow && !secp256k1_scalar_is_zero(&sec)) { |
|||
unsigned int count = 0; |
|||
secp256k1_scalar_set_b32(&msg, msg32, NULL); |
|||
while (1) { |
|||
unsigned char nonce32[32]; |
|||
ret = noncefp(nonce32, seckey, msg32, NULL, (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_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { |
|||
break; |
|||
} |
|||
} |
|||
count++; |
|||
} |
|||
secp256k1_scalar_clear(&msg); |
|||
secp256k1_scalar_clear(&non); |
|||
secp256k1_scalar_clear(&sec); |
|||
} |
|||
if (ret) { |
|||
secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid); |
|||
} else { |
|||
memset(signature, 0, sizeof(*signature)); |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32) { |
|||
secp256k1_ge q; |
|||
secp256k1_scalar r, s; |
|||
secp256k1_scalar m; |
|||
int recid; |
|||
VERIFY_CHECK(ctx != NULL); |
|||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); |
|||
ARG_CHECK(msg32 != NULL); |
|||
ARG_CHECK(signature != NULL); |
|||
ARG_CHECK(pubkey != NULL); |
|||
|
|||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); |
|||
ARG_CHECK(recid >= 0 && recid < 4); |
|||
secp256k1_scalar_set_b32(&m, msg32, NULL); |
|||
if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) { |
|||
secp256k1_pubkey_save(pubkey, &q); |
|||
return 1; |
|||
} else { |
|||
memset(pubkey, 0, sizeof(*pubkey)); |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,249 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2013-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_RECOVERY_TESTS_ |
|||
#define _SECP256K1_MODULE_RECOVERY_TESTS_ |
|||
|
|||
void test_ecdsa_recovery_end_to_end(void) { |
|||
unsigned char extra[32] = {0x00}; |
|||
unsigned char privkey[32]; |
|||
unsigned char message[32]; |
|||
secp256k1_ecdsa_signature signature[5]; |
|||
secp256k1_ecdsa_recoverable_signature rsignature[5]; |
|||
unsigned char sig[74]; |
|||
secp256k1_pubkey pubkey; |
|||
secp256k1_pubkey recpubkey; |
|||
int recid = 0; |
|||
|
|||
/* Generate a random key and message. */ |
|||
{ |
|||
secp256k1_scalar msg, key; |
|||
random_scalar_order_test(&msg); |
|||
random_scalar_order_test(&key); |
|||
secp256k1_scalar_get_b32(privkey, &key); |
|||
secp256k1_scalar_get_b32(message, &msg); |
|||
} |
|||
|
|||
/* Construct and verify corresponding public key. */ |
|||
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); |
|||
|
|||
/* Serialize/parse compact and verify/recover. */ |
|||
extra[0] = 0; |
|||
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1); |
|||
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1); |
|||
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1); |
|||
extra[31] = 1; |
|||
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1); |
|||
extra[31] = 0; |
|||
extra[0] = 1; |
|||
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); |
|||
memset(&rsignature[4], 0, sizeof(rsignature[4])); |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); |
|||
/* Parse compact (with recovery id) and recover. */ |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); |
|||
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1); |
|||
CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); |
|||
/* Serialize/destroy/parse signature and verify again. */ |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); |
|||
sig[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); |
|||
/* Recover again */ |
|||
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 || |
|||
memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); |
|||
} |
|||
|
|||
/* Tests several edge cases. */ |
|||
void test_ecdsa_recovery_edge_cases(void) { |
|||
const unsigned char msg32[32] = { |
|||
'T', 'h', 'i', 's', ' ', 'i', 's', ' ', |
|||
'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', |
|||
'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', |
|||
's', 's', 'a', 'g', 'e', '.', '.', '.' |
|||
}; |
|||
const unsigned char sig64[64] = { |
|||
/* Generated by signing the above message with nonce 'This is the nonce we will use...'
|
|||
* and secret key 0 (which is not valid), resulting in recid 0. */ |
|||
0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, |
|||
0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, |
|||
0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, |
|||
0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, |
|||
0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, |
|||
0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, |
|||
0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, |
|||
0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 |
|||
}; |
|||
secp256k1_pubkey pubkey; |
|||
/* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ |
|||
const unsigned char sigb64[64] = { |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, |
|||
}; |
|||
secp256k1_pubkey pubkeyb; |
|||
secp256k1_ecdsa_recoverable_signature rsig; |
|||
secp256k1_ecdsa_signature sig; |
|||
int recid; |
|||
|
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0)); |
|||
CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); |
|||
CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); |
|||
CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); |
|||
CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); |
|||
|
|||
for (recid = 0; recid < 4; recid++) { |
|||
int i; |
|||
int recid2; |
|||
/* (4,4) encoded in DER. */ |
|||
unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; |
|||
unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; |
|||
unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; |
|||
unsigned char sigbderalt1[39] = { |
|||
0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, |
|||
}; |
|||
unsigned char sigbderalt2[39] = { |
|||
0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, |
|||
}; |
|||
unsigned char sigbderalt3[40] = { |
|||
0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, |
|||
}; |
|||
unsigned char sigbderalt4[40] = { |
|||
0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, |
|||
}; |
|||
/* (order + r,4) encoded in DER. */ |
|||
unsigned char sigbderlong[40] = { |
|||
0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, |
|||
0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, |
|||
0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 |
|||
}; |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); |
|||
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1); |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); |
|||
for (recid2 = 0; recid2 < 4; recid2++) { |
|||
secp256k1_pubkey pubkey2b; |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); |
|||
CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1); |
|||
/* Verifying with (order + r,4) should always fail. */ |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 0); |
|||
} |
|||
/* DER parsing tests. */ |
|||
/* Zero length r/s. */ |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); |
|||
/* Leading zeros. */ |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); |
|||
sigbderalt3[4] = 1; |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); |
|||
sigbderalt4[7] = 1; |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); |
|||
/* Damage signature. */ |
|||
sigbder[7]++; |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); |
|||
sigbder[7]--; |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0); |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0); |
|||
for(i = 0; i < 8; i++) { |
|||
int c; |
|||
unsigned char orig = sigbder[i]; |
|||
/*Try every single-byte change.*/ |
|||
for (c = 0; c < 256; c++) { |
|||
if (c == orig ) { |
|||
continue; |
|||
} |
|||
sigbder[i] = c; |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); |
|||
} |
|||
sigbder[i] = orig; |
|||
} |
|||
} |
|||
|
|||
/* Test r/s equal to zero */ |
|||
{ |
|||
/* (1,1) encoded in DER. */ |
|||
unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; |
|||
unsigned char sigc64[64] = { |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, |
|||
}; |
|||
secp256k1_pubkey pubkeyc; |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); |
|||
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1); |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1); |
|||
sigcder[4] = 0; |
|||
sigc64[31] = 0; |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); |
|||
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); |
|||
sigcder[4] = 1; |
|||
sigcder[7] = 0; |
|||
sigc64[31] = 1; |
|||
sigc64[63] = 0; |
|||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); |
|||
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); |
|||
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); |
|||
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); |
|||
} |
|||
} |
|||
|
|||
void run_recovery_tests(void) { |
|||
int i; |
|||
for (i = 0; i < 64*count; i++) { |
|||
test_ecdsa_recovery_end_to_end(); |
|||
} |
|||
test_ecdsa_recovery_edge_cases(); |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,11 @@ |
|||
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) |
|||
bench_schnorr_verify_LDFLAGS = -static |
|||
endif |
@ -0,0 +1,164 @@ |
|||
/**********************************************************************
|
|||
* 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, int n) { |
|||
ARG_CHECK(sig64 != NULL); |
|||
ARG_CHECK(n >= 1); |
|||
ARG_CHECK(sig64sin != NULL); |
|||
return secp256k1_schnorr_sig_combine(sig64, n, sig64sin); |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,20 @@ |
|||
/***********************************************************************
|
|||
* 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, int n, const unsigned char * const *sig64ins); |
|||
|
|||
#endif |
@ -0,0 +1,207 @@ |
|||
/***********************************************************************
|
|||
* 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); |
|||
if (overflow || secp256k1_scalar_is_zero(&h)) { |
|||
return 0; |
|||
} |
|||
overflow = 0; |
|||
secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); |
|||
if (overflow) { |
|||
return 0; |
|||
} |
|||
if (!secp256k1_fe_set_b32(&Rx, sig64)) { |
|||
return 0; |
|||
} |
|||
secp256k1_gej_set_ge(&Qj, pubkey); |
|||
secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s); |
|||
if (secp256k1_gej_is_infinity(&Rj)) { |
|||
return 0; |
|||
} |
|||
secp256k1_ge_set_gej_var(&Ra, &Rj); |
|||
secp256k1_fe_normalize_var(&Ra.y); |
|||
if (secp256k1_fe_is_odd(&Ra.y)) { |
|||
return 0; |
|||
} |
|||
return secp256k1_fe_equal_var(&Rx, &Ra.x); |
|||
} |
|||
|
|||
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) { |
|||
secp256k1_gej Qj, Rj; |
|||
secp256k1_ge Ra; |
|||
secp256k1_fe Rx; |
|||
secp256k1_scalar h, s; |
|||
unsigned char hh[32]; |
|||
int overflow; |
|||
|
|||
hash(hh, sig64, msg32); |
|||
overflow = 0; |
|||
secp256k1_scalar_set_b32(&h, hh, &overflow); |
|||
if (overflow || secp256k1_scalar_is_zero(&h)) { |
|||
return 0; |
|||
} |
|||
overflow = 0; |
|||
secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); |
|||
if (overflow) { |
|||
return 0; |
|||
} |
|||
if (!secp256k1_fe_set_b32(&Rx, sig64)) { |
|||
return 0; |
|||
} |
|||
if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) { |
|||
return 0; |
|||
} |
|||
secp256k1_gej_set_ge(&Rj, &Ra); |
|||
secp256k1_scalar_inverse_var(&h, &h); |
|||
secp256k1_scalar_negate(&s, &s); |
|||
secp256k1_scalar_mul(&s, &s, &h); |
|||
secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s); |
|||
if (secp256k1_gej_is_infinity(&Qj)) { |
|||
return 0; |
|||
} |
|||
secp256k1_ge_set_gej(pubkey, &Qj); |
|||
return 1; |
|||
} |
|||
|
|||
static int secp256k1_schnorr_sig_combine(unsigned char *sig64, int n, const unsigned char * const *sig64ins) { |
|||
secp256k1_scalar s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); |
|||
int i; |
|||
for (i = 0; i < n; i++) { |
|||
secp256k1_scalar si; |
|||
int overflow; |
|||
secp256k1_scalar_set_b32(&si, sig64ins[i] + 32, &overflow); |
|||
if (overflow) { |
|||
return -1; |
|||
} |
|||
if (i) { |
|||
if (memcmp(sig64ins[i - 1], sig64ins[i], 32) != 0) { |
|||
return -1; |
|||
} |
|||
} |
|||
secp256k1_scalar_add(&s, &s, &si); |
|||
} |
|||
if (secp256k1_scalar_is_zero(&s)) { |
|||
return 0; |
|||
} |
|||
memcpy(sig64, sig64ins[0], 32); |
|||
secp256k1_scalar_get_b32(sig64 + 32, &s); |
|||
secp256k1_scalar_clear(&s); |
|||
return 1; |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,175 @@ |
|||
/**********************************************************************
|
|||
* 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_TESTS |
|||
#define SECP256K1_MODULE_SCHNORR_TESTS |
|||
|
|||
#include "include/secp256k1_schnorr.h" |
|||
|
|||
void test_schnorr_end_to_end(void) { |
|||
unsigned char privkey[32]; |
|||
unsigned char message[32]; |
|||
unsigned char schnorr_signature[64]; |
|||
secp256k1_pubkey pubkey, recpubkey; |
|||
|
|||
/* Generate a random key and message. */ |
|||
{ |
|||
secp256k1_scalar key; |
|||
random_scalar_order_test(&key); |
|||
secp256k1_scalar_get_b32(privkey, &key); |
|||
secp256k1_rand256_test(message); |
|||
} |
|||
|
|||
/* Construct and verify corresponding public key. */ |
|||
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); |
|||
|
|||
/* Schnorr sign. */ |
|||
CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1); |
|||
CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1); |
|||
CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1); |
|||
CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); |
|||
/* Destroy signature and verify again. */ |
|||
schnorr_signature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); |
|||
CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0); |
|||
CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 || |
|||
memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); |
|||
} |
|||
|
|||
/** Horribly broken hash function. Do not use for anything but tests. */ |
|||
void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { |
|||
int i; |
|||
for (i = 0; i < 32; i++) { |
|||
h32[i] = r32[i] ^ msg32[i]; |
|||
} |
|||
} |
|||
|
|||
void test_schnorr_sign_verify(void) { |
|||
unsigned char msg32[32]; |
|||
unsigned char sig64[3][64]; |
|||
secp256k1_gej pubkeyj[3]; |
|||
secp256k1_ge pubkey[3]; |
|||
secp256k1_scalar nonce[3], key[3]; |
|||
int i = 0; |
|||
int k; |
|||
|
|||
secp256k1_rand256_test(msg32); |
|||
|
|||
for (k = 0; k < 3; k++) { |
|||
random_scalar_order_test(&key[k]); |
|||
|
|||
do { |
|||
random_scalar_order_test(&nonce[k]); |
|||
if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) { |
|||
break; |
|||
} |
|||
} while(1); |
|||
|
|||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]); |
|||
secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]); |
|||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32)); |
|||
|
|||
for (i = 0; i < 4; i++) { |
|||
int pos = secp256k1_rand32() % 64; |
|||
int mod = 1 + (secp256k1_rand32() % 255); |
|||
sig64[k][pos] ^= mod; |
|||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0); |
|||
sig64[k][pos] ^= mod; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void test_schnorr_threshold(void) { |
|||
unsigned char msg[32]; |
|||
unsigned char sec[5][32]; |
|||
secp256k1_pubkey pub[5]; |
|||
unsigned char nonce[5][32]; |
|||
secp256k1_pubkey pubnonce[5]; |
|||
unsigned char sig[5][64]; |
|||
const unsigned char* sigs[5]; |
|||
unsigned char allsig[64]; |
|||
const secp256k1_pubkey* pubs[5]; |
|||
secp256k1_pubkey allpub; |
|||
int n, i; |
|||
int damage; |
|||
int ret = 0; |
|||
|
|||
damage = (secp256k1_rand32() % 2) ? (1 + (secp256k1_rand32() % 4)) : 0; |
|||
secp256k1_rand256_test(msg); |
|||
n = 2 + (secp256k1_rand32() % 4); |
|||
for (i = 0; i < n; i++) { |
|||
do { |
|||
secp256k1_rand256_test(sec[i]); |
|||
} while (!secp256k1_ec_seckey_verify(ctx, sec[i])); |
|||
CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i])); |
|||
CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL)); |
|||
pubs[i] = &pub[i]; |
|||
} |
|||
if (damage == 1) { |
|||
nonce[secp256k1_rand32() % n][secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); |
|||
} else if (damage == 2) { |
|||
sec[secp256k1_rand32() % n][secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); |
|||
} |
|||
for (i = 0; i < n; i++) { |
|||
secp256k1_pubkey allpubnonce; |
|||
const secp256k1_pubkey *pubnonces[4]; |
|||
int j; |
|||
for (j = 0; j < i; j++) { |
|||
pubnonces[j] = &pubnonce[j]; |
|||
} |
|||
for (j = i + 1; j < n; j++) { |
|||
pubnonces[j - 1] = &pubnonce[j]; |
|||
} |
|||
CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1)); |
|||
ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1; |
|||
sigs[i] = sig[i]; |
|||
} |
|||
if (damage == 3) { |
|||
sig[secp256k1_rand32() % n][secp256k1_rand32() % 64] ^= 1 + (secp256k1_rand32() % 255); |
|||
} |
|||
ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2; |
|||
if ((ret & 1) == 0) { |
|||
ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4; |
|||
} |
|||
if (damage == 4) { |
|||
allsig[secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); |
|||
} |
|||
if ((ret & 7) == 0) { |
|||
ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8; |
|||
} |
|||
CHECK((ret == 0) == (damage == 0)); |
|||
} |
|||
|
|||
void test_schnorr_recovery(void) { |
|||
unsigned char msg32[32]; |
|||
unsigned char sig64[64]; |
|||
secp256k1_ge Q; |
|||
|
|||
secp256k1_rand256_test(msg32); |
|||
secp256k1_rand256_test(sig64); |
|||
secp256k1_rand256_test(sig64 + 32); |
|||
if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) { |
|||
CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1); |
|||
} |
|||
} |
|||
|
|||
void run_schnorr_tests(void) { |
|||
int i; |
|||
for (i = 0; i < 32*count; i++) { |
|||
test_schnorr_end_to_end(); |
|||
} |
|||
for (i = 0; i < 32 * count; i++) { |
|||
test_schnorr_sign_verify(); |
|||
} |
|||
for (i = 0; i < 16 * count; i++) { |
|||
test_schnorr_recovery(); |
|||
} |
|||
for (i = 0; i < 10 * count; i++) { |
|||
test_schnorr_threshold(); |
|||
} |
|||
} |
|||
|
|||
#endif |
@ -1,18 +0,0 @@ |
|||
/***********************************************************************
|
|||
* Copyright (c) 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_ |
|||
#define _SECP256K1_SCHNORR_ |
|||
|
|||
#include "scalar.h" |
|||
#include "group.h" |
|||
|
|||
typedef void (*secp256k1_schnorr_msghash_t)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32); |
|||
|
|||
static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context_t* ctx, unsigned char *sig64, const secp256k1_scalar_t *key, secp256k1_scalar_t *nonce, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32); |
|||
static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context_t* ctx, const unsigned char *sig64, const secp256k1_ge_t *pubkey, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32); |
|||
|
|||
#endif |
@ -1,116 +0,0 @@ |
|||
/***********************************************************************
|
|||
* Copyright (c) 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: |
|||
* |
|||
* 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_t* ctx, unsigned char *sig64, const secp256k1_scalar_t *key, secp256k1_scalar_t *nonce, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32) { |
|||
secp256k1_gej_t Rj; |
|||
secp256k1_ge_t Ra; |
|||
unsigned char h32[32]; |
|||
secp256k1_scalar_t h, s; |
|||
int overflow; |
|||
|
|||
if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) { |
|||
return 0; |
|||
} |
|||
|
|||
secp256k1_ecmult_gen(ctx, &Rj, nonce); |
|||
secp256k1_ge_set_gej(&Ra, &Rj); |
|||
secp256k1_fe_normalize(&Ra.y); |
|||
if (secp256k1_fe_is_odd(&Ra.y)) { |
|||
secp256k1_scalar_negate(nonce, nonce); |
|||
} |
|||
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)) { |
|||
return 0; |
|||
} |
|||
secp256k1_scalar_mul(&s, &h, key); |
|||
secp256k1_scalar_negate(&s, &s); |
|||
secp256k1_scalar_add(&s, &s, nonce); |
|||
secp256k1_scalar_get_b32(sig64 + 32, &s); |
|||
return 1; |
|||
} |
|||
|
|||
static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context_t* ctx, const unsigned char *sig64, const secp256k1_ge_t *pubkey, secp256k1_schnorr_msghash_t hash, const unsigned char *msg32) { |
|||
secp256k1_gej_t Qj, Rj; |
|||
secp256k1_ge_t Ra; |
|||
secp256k1_fe_t Rx; |
|||
secp256k1_scalar_t 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); |
|||
if (overflow || secp256k1_scalar_is_zero(&h)) { |
|||
return 0; |
|||
} |
|||
overflow = 0; |
|||
secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); |
|||
if (overflow) { |
|||
return 0; |
|||
} |
|||
if (!secp256k1_fe_set_b32(&Rx, sig64)) { |
|||
return 0; |
|||
} |
|||
secp256k1_gej_set_ge(&Qj, pubkey); |
|||
secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s); |
|||
if (secp256k1_gej_is_infinity(&Rj)) { |
|||
return 0; |
|||
} |
|||
secp256k1_ge_set_gej_var(&Ra, &Rj); |
|||
secp256k1_fe_normalize_var(&Ra.y); |
|||
if (secp256k1_fe_is_odd(&Ra.y)) { |
|||
return 0; |
|||
} |
|||
return secp256k1_fe_equal_var(&Rx, &Ra.x); |
|||
} |
|||
|
|||
#endif |
File diff suppressed because it is too large
Loading…
Reference in new issue