**********************************************************************/
#include "include/secp256k1.h"
+#include "include/secp256k1_preallocated.h"
#include "util.h"
#include "num_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); \
} \
} while(0)
-static void default_illegal_callback_fn(const char* str, void* data) {
+#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 const secp256k1_callback default_illegal_callback = {
- default_illegal_callback_fn,
- NULL
-};
-
-static void default_error_callback_fn(const char* str, void* data) {
+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_error_callback = {
- default_error_callback_fn,
+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 },
- { default_illegal_callback_fn, 0 },
- { default_error_callback_fn, 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_;
-secp256k1_context* secp256k1_context_create(unsigned int flags) {
- secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context));
+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");
- free(ret);
return NULL;
}
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, &ret->error_callback);
+ secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &prealloc);
}
if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) {
- secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback);
+ 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 = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context));
- ret->illegal_callback = ctx->illegal_callback;
- ret->error_callback = ctx->error_callback;
- secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback);
- secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback);
+ 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_destroy(secp256k1_context* ctx) {
- CHECK(ctx != secp256k1_context_no_precomp);
+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) {
- CHECK(ctx != secp256k1_context_no_precomp);
+ ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
if (fun == NULL) {
- fun = default_illegal_callback_fn;
+ 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) {
- CHECK(ctx != secp256k1_context_no_precomp);
+ ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
if (fun == NULL) {
- fun = default_error_callback_fn;
+ fun = secp256k1_default_error_callback_fn;
}
ctx->error_callback.fn = fun;
ctx->error_callback.data = data;
return secp256k1_scratch_create(&ctx->error_callback, max_size);
}
-void secp256k1_scratch_space_destroy(secp256k1_scratch_space* scratch) {
- secp256k1_scratch_destroy(scratch);
+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) {
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);
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
/* Fail if the secret key is invalid. */
- if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
- unsigned char nonce32[32];
- unsigned int count = 0;
- secp256k1_scalar_set_b32(&msg, msg32, NULL);
- while (1) {
- ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
- if (!ret) {
+ 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;
}
- secp256k1_scalar_set_b32(&non, nonce32, &overflow);
- if (!overflow && !secp256k1_scalar_is_zero(&non)) {
- if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) {
- break;
- }
- }
- count++;
}
- memset(nonce32, 0, 32);
- secp256k1_scalar_clear(&msg);
- secp256k1_scalar_clear(&non);
- secp256k1_scalar_clear(&sec);
- }
- if (ret) {
- secp256k1_ecdsa_signature_save(signature, &r, &s);
- } else {
- memset(signature, 0, sizeof(*signature));
+ count++;
}
- return ret;
+ 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) {
ARG_CHECK(seckey != NULL);
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
- ret = !overflow && !secp256k1_scalar_is_zero(&sec);
+ ret = !overflow & !secp256k1_scalar_is_zero(&sec);
secp256k1_scalar_clear(&sec);
return ret;
}
ARG_CHECK(seckey != NULL);
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
- ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec));
- if (ret) {
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
- secp256k1_ge_set_gej(&p, &pj);
- secp256k1_pubkey_save(pubkey, &p);
- }
+ 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;
}
secp256k1_scalar_negate(&sec, &sec);
secp256k1_scalar_get_b32(seckey, &sec);
+ secp256k1_scalar_clear(&sec);
return 1;
}
secp256k1_scalar_set_b32(&term, tweak, &overflow);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
- ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term);
- memset(seckey, 0, 32);
- if (ret) {
- secp256k1_scalar_get_b32(seckey, &sec);
- }
+ 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);
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
- ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor);
- memset(seckey, 0, 32);
- if (ret) {
- secp256k1_scalar_get_b32(seckey, &sec);
- }
+ 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);