ECDSA signing has a retry loop for the exceptionally unlikely case that S==0. S is not a secret at this point and this case is so rare that it will never be observed but branching on it will trip up tools analysing if the code is constant time with respect to secrets. Derandomized ECDSA can also loop on k being zero or overflowing, and while k is a secret these cases are too rare (1:2^255) to ever observe and are also of no concern. This adds a function for marking memory as no-longer-secret and sets it up for use with the valgrind memcheck constant-time test.
715 lines
24 KiB
C
715 lines
24 KiB
C
/**********************************************************************
|
|
* 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.*
|
|
**********************************************************************/
|
|
|
|
#include "include/secp256k1.h"
|
|
#include "include/secp256k1_preallocated.h"
|
|
|
|
#include "util.h"
|
|
#include "num_impl.h"
|
|
#include "field_impl.h"
|
|
#include "scalar_impl.h"
|
|
#include "group_impl.h"
|
|
#include "ecmult_impl.h"
|
|
#include "ecmult_const_impl.h"
|
|
#include "ecmult_gen_impl.h"
|
|
#include "ecdsa_impl.h"
|
|
#include "eckey_impl.h"
|
|
#include "hash_impl.h"
|
|
#include "scratch_impl.h"
|
|
|
|
#if defined(VALGRIND)
|
|
# include <valgrind/memcheck.h>
|
|
#endif
|
|
|
|
#define ARG_CHECK(cond) do { \
|
|
if (EXPECT(!(cond), 0)) { \
|
|
secp256k1_callback_call(&ctx->illegal_callback, #cond); \
|
|
return 0; \
|
|
} \
|
|
} while(0)
|
|
|
|
#define ARG_CHECK_NO_RETURN(cond) do { \
|
|
if (EXPECT(!(cond), 0)) { \
|
|
secp256k1_callback_call(&ctx->illegal_callback, #cond); \
|
|
} \
|
|
} while(0)
|
|
|
|
#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
static void secp256k1_default_illegal_callback_fn(const char* str, void* data) {
|
|
(void)data;
|
|
fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str);
|
|
abort();
|
|
}
|
|
static void secp256k1_default_error_callback_fn(const char* str, void* data) {
|
|
(void)data;
|
|
fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str);
|
|
abort();
|
|
}
|
|
#else
|
|
void secp256k1_default_illegal_callback_fn(const char* str, void* data);
|
|
void secp256k1_default_error_callback_fn(const char* str, void* data);
|
|
#endif
|
|
|
|
static const secp256k1_callback default_illegal_callback = {
|
|
secp256k1_default_illegal_callback_fn,
|
|
NULL
|
|
};
|
|
|
|
static const secp256k1_callback default_error_callback = {
|
|
secp256k1_default_error_callback_fn,
|
|
NULL
|
|
};
|
|
|
|
struct secp256k1_context_struct {
|
|
secp256k1_ecmult_context ecmult_ctx;
|
|
secp256k1_ecmult_gen_context ecmult_gen_ctx;
|
|
secp256k1_callback illegal_callback;
|
|
secp256k1_callback error_callback;
|
|
int declassify;
|
|
};
|
|
|
|
static const secp256k1_context secp256k1_context_no_precomp_ = {
|
|
{ 0 },
|
|
{ 0 },
|
|
{ secp256k1_default_illegal_callback_fn, 0 },
|
|
{ secp256k1_default_error_callback_fn, 0 },
|
|
0
|
|
};
|
|
const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_;
|
|
|
|
size_t secp256k1_context_preallocated_size(unsigned int flags) {
|
|
size_t ret = ROUND_TO_ALIGN(sizeof(secp256k1_context));
|
|
|
|
if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) {
|
|
secp256k1_callback_call(&default_illegal_callback,
|
|
"Invalid flags");
|
|
return 0;
|
|
}
|
|
|
|
if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) {
|
|
ret += SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
|
|
}
|
|
if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) {
|
|
ret += SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
size_t secp256k1_context_preallocated_clone_size(const secp256k1_context* ctx) {
|
|
size_t ret = ROUND_TO_ALIGN(sizeof(secp256k1_context));
|
|
VERIFY_CHECK(ctx != NULL);
|
|
if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) {
|
|
ret += SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
|
|
}
|
|
if (secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)) {
|
|
ret += SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) {
|
|
void* const base = prealloc;
|
|
size_t prealloc_size;
|
|
secp256k1_context* ret;
|
|
|
|
VERIFY_CHECK(prealloc != NULL);
|
|
prealloc_size = secp256k1_context_preallocated_size(flags);
|
|
ret = (secp256k1_context*)manual_alloc(&prealloc, sizeof(secp256k1_context), base, prealloc_size);
|
|
ret->illegal_callback = default_illegal_callback;
|
|
ret->error_callback = default_error_callback;
|
|
|
|
if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) {
|
|
secp256k1_callback_call(&ret->illegal_callback,
|
|
"Invalid flags");
|
|
return NULL;
|
|
}
|
|
|
|
secp256k1_ecmult_context_init(&ret->ecmult_ctx);
|
|
secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx);
|
|
|
|
if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) {
|
|
secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &prealloc);
|
|
}
|
|
if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) {
|
|
secp256k1_ecmult_context_build(&ret->ecmult_ctx, &prealloc);
|
|
}
|
|
ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY);
|
|
|
|
return (secp256k1_context*) ret;
|
|
}
|
|
|
|
secp256k1_context* secp256k1_context_create(unsigned int flags) {
|
|
size_t const prealloc_size = secp256k1_context_preallocated_size(flags);
|
|
secp256k1_context* ctx = (secp256k1_context*)checked_malloc(&default_error_callback, prealloc_size);
|
|
if (EXPECT(secp256k1_context_preallocated_create(ctx, flags) == NULL, 0)) {
|
|
free(ctx);
|
|
return NULL;
|
|
}
|
|
|
|
return ctx;
|
|
}
|
|
|
|
secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context* ctx, void* prealloc) {
|
|
size_t prealloc_size;
|
|
secp256k1_context* ret;
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(prealloc != NULL);
|
|
|
|
prealloc_size = secp256k1_context_preallocated_clone_size(ctx);
|
|
ret = (secp256k1_context*)prealloc;
|
|
memcpy(ret, ctx, prealloc_size);
|
|
secp256k1_ecmult_gen_context_finalize_memcpy(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx);
|
|
secp256k1_ecmult_context_finalize_memcpy(&ret->ecmult_ctx, &ctx->ecmult_ctx);
|
|
return ret;
|
|
}
|
|
|
|
secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
|
|
secp256k1_context* ret;
|
|
size_t prealloc_size;
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
prealloc_size = secp256k1_context_preallocated_clone_size(ctx);
|
|
ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size);
|
|
ret = secp256k1_context_preallocated_clone(ctx, ret);
|
|
return ret;
|
|
}
|
|
|
|
void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
|
|
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
|
|
if (ctx != NULL) {
|
|
secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
|
|
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
|
|
}
|
|
}
|
|
|
|
void secp256k1_context_destroy(secp256k1_context* ctx) {
|
|
if (ctx != NULL) {
|
|
secp256k1_context_preallocated_destroy(ctx);
|
|
free(ctx);
|
|
}
|
|
}
|
|
|
|
void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
|
|
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
|
|
if (fun == NULL) {
|
|
fun = secp256k1_default_illegal_callback_fn;
|
|
}
|
|
ctx->illegal_callback.fn = fun;
|
|
ctx->illegal_callback.data = data;
|
|
}
|
|
|
|
void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
|
|
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
|
|
if (fun == NULL) {
|
|
fun = secp256k1_default_error_callback_fn;
|
|
}
|
|
ctx->error_callback.fn = fun;
|
|
ctx->error_callback.data = data;
|
|
}
|
|
|
|
secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) {
|
|
VERIFY_CHECK(ctx != NULL);
|
|
return secp256k1_scratch_create(&ctx->error_callback, max_size);
|
|
}
|
|
|
|
void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) {
|
|
VERIFY_CHECK(ctx != NULL);
|
|
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
|
|
}
|
|
|
|
/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour
|
|
* of the software. This is setup for use with valgrind but could be substituted with
|
|
* the appropriate instrumentation for other analysis tools.
|
|
*/
|
|
static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, void *p, size_t len) {
|
|
#if defined(VALGRIND)
|
|
if (EXPECT(ctx->declassify,0)) VALGRIND_MAKE_MEM_DEFINED(p, len);
|
|
#else
|
|
(void)ctx;
|
|
(void)p;
|
|
(void)len;
|
|
#endif
|
|
}
|
|
|
|
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
|
|
if (sizeof(secp256k1_ge_storage) == 64) {
|
|
/* When the secp256k1_ge_storage type is exactly 64 byte, use its
|
|
* representation inside secp256k1_pubkey, as conversion is very fast.
|
|
* Note that secp256k1_pubkey_save must use the same representation. */
|
|
secp256k1_ge_storage s;
|
|
memcpy(&s, &pubkey->data[0], sizeof(s));
|
|
secp256k1_ge_from_storage(ge, &s);
|
|
} else {
|
|
/* Otherwise, fall back to 32-byte big endian for X and Y. */
|
|
secp256k1_fe x, y;
|
|
secp256k1_fe_set_b32(&x, pubkey->data);
|
|
secp256k1_fe_set_b32(&y, pubkey->data + 32);
|
|
secp256k1_ge_set_xy(ge, &x, &y);
|
|
}
|
|
ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));
|
|
return 1;
|
|
}
|
|
|
|
static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
|
|
if (sizeof(secp256k1_ge_storage) == 64) {
|
|
secp256k1_ge_storage s;
|
|
secp256k1_ge_to_storage(&s, ge);
|
|
memcpy(&pubkey->data[0], &s, sizeof(s));
|
|
} else {
|
|
VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
|
|
secp256k1_fe_normalize_var(&ge->x);
|
|
secp256k1_fe_normalize_var(&ge->y);
|
|
secp256k1_fe_get_b32(pubkey->data, &ge->x);
|
|
secp256k1_fe_get_b32(pubkey->data + 32, &ge->y);
|
|
}
|
|
}
|
|
|
|
int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {
|
|
secp256k1_ge Q;
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(pubkey != NULL);
|
|
memset(pubkey, 0, sizeof(*pubkey));
|
|
ARG_CHECK(input != NULL);
|
|
if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) {
|
|
return 0;
|
|
}
|
|
secp256k1_pubkey_save(pubkey, &Q);
|
|
secp256k1_ge_clear(&Q);
|
|
return 1;
|
|
}
|
|
|
|
int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) {
|
|
secp256k1_ge Q;
|
|
size_t len;
|
|
int ret = 0;
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(outputlen != NULL);
|
|
ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65));
|
|
len = *outputlen;
|
|
*outputlen = 0;
|
|
ARG_CHECK(output != NULL);
|
|
memset(output, 0, len);
|
|
ARG_CHECK(pubkey != NULL);
|
|
ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION);
|
|
if (secp256k1_pubkey_load(ctx, &Q, pubkey)) {
|
|
ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION);
|
|
if (ret) {
|
|
*outputlen = len;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_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);
|
|
}
|
|
}
|
|
|
|
static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s) {
|
|
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);
|
|
}
|
|
}
|
|
|
|
int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
|
|
secp256k1_scalar r, s;
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(sig != NULL);
|
|
ARG_CHECK(input != NULL);
|
|
|
|
if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) {
|
|
secp256k1_ecdsa_signature_save(sig, &r, &s);
|
|
return 1;
|
|
} else {
|
|
memset(sig, 0, sizeof(*sig));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) {
|
|
secp256k1_scalar r, s;
|
|
int ret = 1;
|
|
int overflow = 0;
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(sig != NULL);
|
|
ARG_CHECK(input64 != NULL);
|
|
|
|
secp256k1_scalar_set_b32(&r, &input64[0], &overflow);
|
|
ret &= !overflow;
|
|
secp256k1_scalar_set_b32(&s, &input64[32], &overflow);
|
|
ret &= !overflow;
|
|
if (ret) {
|
|
secp256k1_ecdsa_signature_save(sig, &r, &s);
|
|
} else {
|
|
memset(sig, 0, sizeof(*sig));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) {
|
|
secp256k1_scalar r, s;
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(output != NULL);
|
|
ARG_CHECK(outputlen != NULL);
|
|
ARG_CHECK(sig != NULL);
|
|
|
|
secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
|
|
return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s);
|
|
}
|
|
|
|
int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) {
|
|
secp256k1_scalar r, s;
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(output64 != NULL);
|
|
ARG_CHECK(sig != NULL);
|
|
|
|
secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
|
|
secp256k1_scalar_get_b32(&output64[0], &r);
|
|
secp256k1_scalar_get_b32(&output64[32], &s);
|
|
return 1;
|
|
}
|
|
|
|
int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) {
|
|
secp256k1_scalar r, s;
|
|
int ret = 0;
|
|
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(sigin != NULL);
|
|
|
|
secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin);
|
|
ret = secp256k1_scalar_is_high(&s);
|
|
if (sigout != NULL) {
|
|
if (ret) {
|
|
secp256k1_scalar_negate(&s, &s);
|
|
}
|
|
secp256k1_ecdsa_signature_save(sigout, &r, &s);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) {
|
|
secp256k1_ge q;
|
|
secp256k1_scalar r, s;
|
|
secp256k1_scalar m;
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
|
ARG_CHECK(msg32 != NULL);
|
|
ARG_CHECK(sig != NULL);
|
|
ARG_CHECK(pubkey != NULL);
|
|
|
|
secp256k1_scalar_set_b32(&m, msg32, NULL);
|
|
secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
|
|
return (!secp256k1_scalar_is_high(&s) &&
|
|
secp256k1_pubkey_load(ctx, &q, pubkey) &&
|
|
secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m));
|
|
}
|
|
|
|
static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) {
|
|
memcpy(buf + *offset, data, len);
|
|
*offset += len;
|
|
}
|
|
|
|
static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
|
|
unsigned char keydata[112];
|
|
unsigned int offset = 0;
|
|
secp256k1_rfc6979_hmac_sha256 rng;
|
|
unsigned int i;
|
|
/* We feed a byte array to the PRNG as input, consisting of:
|
|
* - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d.
|
|
* - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data.
|
|
* - optionally 16 extra bytes with the algorithm name.
|
|
* Because the arguments have distinct fixed lengths it is not possible for
|
|
* different argument mixtures to emulate each other and result in the same
|
|
* nonces.
|
|
*/
|
|
buffer_append(keydata, &offset, key32, 32);
|
|
buffer_append(keydata, &offset, msg32, 32);
|
|
if (data != NULL) {
|
|
buffer_append(keydata, &offset, data, 32);
|
|
}
|
|
if (algo16 != NULL) {
|
|
buffer_append(keydata, &offset, algo16, 16);
|
|
}
|
|
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, offset);
|
|
memset(keydata, 0, sizeof(keydata));
|
|
for (i = 0; i <= counter; i++) {
|
|
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
|
}
|
|
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
|
return 1;
|
|
}
|
|
|
|
const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
|
|
const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;
|
|
|
|
int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_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 ret = 0;
|
|
int overflow = 0;
|
|
unsigned char nonce32[32];
|
|
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(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. */
|
|
overflow |= secp256k1_scalar_is_zero(&sec);
|
|
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_one, overflow);
|
|
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
|
while (1) {
|
|
int koverflow;
|
|
ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
secp256k1_scalar_set_b32(&non, nonce32, &koverflow);
|
|
koverflow |= secp256k1_scalar_is_zero(&non);
|
|
/* The nonce is still secret here, but it overflowing or being zero is is less likely than 1:2^255. */
|
|
secp256k1_declassify(ctx, &koverflow, sizeof(koverflow));
|
|
if (!koverflow) {
|
|
ret = secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL);
|
|
/* The final signature is no longer a secret, nor is the fact that we were successful or not. */
|
|
secp256k1_declassify(ctx, &ret, sizeof(ret));
|
|
if (ret) {
|
|
break;
|
|
}
|
|
}
|
|
count++;
|
|
}
|
|
memset(nonce32, 0, 32);
|
|
secp256k1_scalar_clear(&msg);
|
|
secp256k1_scalar_clear(&non);
|
|
secp256k1_scalar_clear(&sec);
|
|
secp256k1_scalar_cmov(&r, &secp256k1_scalar_zero, (!ret) | overflow);
|
|
secp256k1_scalar_cmov(&s, &secp256k1_scalar_zero, (!ret) | overflow);
|
|
secp256k1_ecdsa_signature_save(signature, &r, &s);
|
|
return !!ret & !overflow;
|
|
}
|
|
|
|
int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) {
|
|
secp256k1_scalar sec;
|
|
int ret;
|
|
int overflow;
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(seckey != NULL);
|
|
|
|
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
|
|
ret = !overflow & !secp256k1_scalar_is_zero(&sec);
|
|
secp256k1_scalar_clear(&sec);
|
|
return ret;
|
|
}
|
|
|
|
int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) {
|
|
secp256k1_gej pj;
|
|
secp256k1_ge p;
|
|
secp256k1_scalar sec;
|
|
int overflow;
|
|
int ret = 0;
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(pubkey != NULL);
|
|
memset(pubkey, 0, sizeof(*pubkey));
|
|
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
|
ARG_CHECK(seckey != NULL);
|
|
|
|
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
|
|
ret = !overflow & !secp256k1_scalar_is_zero(&sec);
|
|
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_one, !ret);
|
|
|
|
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
|
|
secp256k1_ge_set_gej(&p, &pj);
|
|
secp256k1_pubkey_save(pubkey, &p);
|
|
memczero(pubkey, sizeof(*pubkey), !ret);
|
|
|
|
secp256k1_scalar_clear(&sec);
|
|
return ret;
|
|
}
|
|
|
|
int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) {
|
|
secp256k1_scalar sec;
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(seckey != NULL);
|
|
|
|
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
|
secp256k1_scalar_negate(&sec, &sec);
|
|
secp256k1_scalar_get_b32(seckey, &sec);
|
|
|
|
secp256k1_scalar_clear(&sec);
|
|
return 1;
|
|
}
|
|
|
|
int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) {
|
|
int ret = 0;
|
|
secp256k1_ge p;
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(pubkey != NULL);
|
|
|
|
ret = secp256k1_pubkey_load(ctx, &p, pubkey);
|
|
memset(pubkey, 0, sizeof(*pubkey));
|
|
if (ret) {
|
|
secp256k1_ge_neg(&p, &p);
|
|
secp256k1_pubkey_save(pubkey, &p);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
|
|
secp256k1_scalar term;
|
|
secp256k1_scalar sec;
|
|
int ret = 0;
|
|
int overflow = 0;
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(seckey != NULL);
|
|
ARG_CHECK(tweak != NULL);
|
|
|
|
secp256k1_scalar_set_b32(&term, tweak, &overflow);
|
|
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
|
|
|
ret = (!overflow) & secp256k1_eckey_privkey_tweak_add(&sec, &term);
|
|
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
|
|
secp256k1_scalar_get_b32(seckey, &sec);
|
|
|
|
secp256k1_scalar_clear(&sec);
|
|
secp256k1_scalar_clear(&term);
|
|
return ret;
|
|
}
|
|
|
|
int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) {
|
|
secp256k1_ge p;
|
|
secp256k1_scalar term;
|
|
int ret = 0;
|
|
int overflow = 0;
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
|
ARG_CHECK(pubkey != NULL);
|
|
ARG_CHECK(tweak != NULL);
|
|
|
|
secp256k1_scalar_set_b32(&term, tweak, &overflow);
|
|
ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey);
|
|
memset(pubkey, 0, sizeof(*pubkey));
|
|
if (ret) {
|
|
if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) {
|
|
secp256k1_pubkey_save(pubkey, &p);
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
|
|
secp256k1_scalar factor;
|
|
secp256k1_scalar sec;
|
|
int ret = 0;
|
|
int overflow = 0;
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(seckey != NULL);
|
|
ARG_CHECK(tweak != NULL);
|
|
|
|
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
|
|
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
|
ret = (!overflow) & secp256k1_eckey_privkey_tweak_mul(&sec, &factor);
|
|
secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret);
|
|
secp256k1_scalar_get_b32(seckey, &sec);
|
|
|
|
secp256k1_scalar_clear(&sec);
|
|
secp256k1_scalar_clear(&factor);
|
|
return ret;
|
|
}
|
|
|
|
int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) {
|
|
secp256k1_ge p;
|
|
secp256k1_scalar factor;
|
|
int ret = 0;
|
|
int overflow = 0;
|
|
VERIFY_CHECK(ctx != NULL);
|
|
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
|
ARG_CHECK(pubkey != NULL);
|
|
ARG_CHECK(tweak != NULL);
|
|
|
|
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
|
|
ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey);
|
|
memset(pubkey, 0, sizeof(*pubkey));
|
|
if (ret) {
|
|
if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) {
|
|
secp256k1_pubkey_save(pubkey, &p);
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {
|
|
VERIFY_CHECK(ctx != NULL);
|
|
if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) {
|
|
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) {
|
|
size_t i;
|
|
secp256k1_gej Qj;
|
|
secp256k1_ge Q;
|
|
|
|
ARG_CHECK(pubnonce != NULL);
|
|
memset(pubnonce, 0, sizeof(*pubnonce));
|
|
ARG_CHECK(n >= 1);
|
|
ARG_CHECK(pubnonces != NULL);
|
|
|
|
secp256k1_gej_set_infinity(&Qj);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
secp256k1_pubkey_load(ctx, &Q, pubnonces[i]);
|
|
secp256k1_gej_add_ge(&Qj, &Qj, &Q);
|
|
}
|
|
if (secp256k1_gej_is_infinity(&Qj)) {
|
|
return 0;
|
|
}
|
|
secp256k1_ge_set_gej(&Q, &Qj);
|
|
secp256k1_pubkey_save(pubnonce, &Q);
|
|
return 1;
|
|
}
|
|
|
|
#ifdef ENABLE_MODULE_ECDH
|
|
# include "modules/ecdh/main_impl.h"
|
|
#endif
|
|
|
|
#ifdef ENABLE_MODULE_RECOVERY
|
|
# include "modules/recovery/main_impl.h"
|
|
#endif
|