diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ad905af52..fd7105e4c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,10 +80,10 @@ jobs: - env_vars: { RECOVERY: 'yes', SCHNORRSIG: 'yes' } - env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', CPPFLAGS: '-DVERIFY' } - env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' } - - env_vars: { CPPFLAGS: '-DDETERMINISTIC' } + - env_vars: { RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DDETERMINISTIC -DSECP256K1_HAVE_STDIO_H=0' } - env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' } - - env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } - - env_vars: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } + - env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes'} + - env_vars: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2, CPPFLAGS: '-DSECP256K1_HAVE_STDLIB_H=0', EXTRAFLAGS='--enable-external-default-callbacks'} - env_vars: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 } cc: - 'gcc' diff --git a/include/secp256k1.h b/include/secp256k1.h index 936f0b42b7..5faa98670c 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -122,6 +122,46 @@ typedef int (*secp256k1_nonce_function)( # endif # endif +/* SECP_HAVE_X is 1 iff standard library header X is available. + * + * We guess the values of HAVE_X here for various X. You can always override our + * guess by providing a definition of the respective macro. + * + * Note to developers of the library: All SECP256K1_HAVE_X macros will always be + * defined after this section, so use #if instead #ifdef to check them. */ +#if !defined(SECP256K1_HAVE_STDIO_H) +# if defined(__has_include) +# define SECP256K1_HAVE_STDIO_H (__has_include()) +# elif defined(__STDC_HOSTED__) +# define SECP256K1_HAVE_STDIO_H __STDC_HOSTED__ +# else + /* Unreachable with a confirming compiler. Guess "yes" as a last resort. */ +# define SECP256K1_HAVE_STDIO_H 1 +# endif +# if !SECP256K1_HAVE_STDIO_H && defined(SECP256K1_BUILD) && !defined(USE_EXTERNAL_DEFAULT_CALLBACKS) +# pragma message( \ + " appears unavailable, " \ + "disabling debugging output for fatal errors in libsecp256k1. " \ + "(#define SECP256K1_HAVE_STDIO_H 0 to suppress this message.)") +# endif +#endif +#if !defined(SECP256K1_HAVE_STDLIB_H) +# if defined(__has_include) +# define SECP256K1_HAVE_STDLIB_H (__has_include()) +# elif defined(__STDC_HOSTED__) +# define SECP256K1_HAVE_STDLIB_H __STDC_HOSTED__ +# else + /* Unreachable with a confirming compiler. Guess "yes" as a last resort. */ +# define SECP256K1_HAVE_STDLIB_H 1 +# endif +# if !SECP256K1_HAVE_STDLIB_H && defined(SECP256K1_BUILD) +# pragma message( \ + " appears unavailable, " \ + "disabling dynamic memory allocation in libsecp256k1. " \ + "(#define SECP256K1_HAVE_STDLIB_H 0 to suppress this message.)") +# endif +#endif + /* When this header is used at build-time the SECP256K1_BUILD define needs to be set * to correctly setup export attributes and nullness checks. This is normally done * by secp256k1.c but to guard against this header being included before secp256k1.c @@ -190,6 +230,17 @@ typedef int (*secp256k1_nonce_function)( # define SECP256K1_DEPRECATED(_msg) #endif +/* Attribute for marking functions, types, and variables as unavailable */ +#if !defined(SECP256K1_BUILD) && defined(__has_attribute) +# if __has_attribute(__unavailable__) +# define SECP256K1_UNAVAILABLE(_msg) __attribute__ ((__unavailable__(_msg))) +# else +# define SECP256K1_UNAVAILABLE(_msg) +# endif +#else +# define SECP256K1_UNAVAILABLE(_msg) +#endif + /* All flags' lower 8 bits indicate what they're for. Do not use directly. */ #define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) #define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) @@ -285,7 +336,15 @@ SECP256K1_API void secp256k1_selftest(void); */ SECP256K1_API secp256k1_context *secp256k1_context_create( unsigned int flags -) SECP256K1_WARN_UNUSED_RESULT; +) SECP256K1_WARN_UNUSED_RESULT +#if !SECP256K1_HAVE_STDLIB_H +SECP256K1_UNAVAILABLE( + "Needs malloc/free but seems unavailable on this platform, " + "see secp256k1_prealloc.h for alternatives. " + "(#define SECP256K1_HAVE_STDLIB_H 1 to override.)" +) +#endif +; /** Copy a secp256k1 context object (into dynamically allocated memory). * @@ -301,7 +360,15 @@ SECP256K1_API secp256k1_context *secp256k1_context_create( */ SECP256K1_API secp256k1_context *secp256k1_context_clone( const secp256k1_context *ctx -) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT +#if !SECP256K1_HAVE_STDLIB_H +SECP256K1_UNAVAILABLE( + "Needs malloc/free but seems unavailable on this platform, " + "see secp256k1_prealloc.h for alternatives. " + "(#define SECP256K1_HAVE_STDLIB_H 1 to override.)" +) +#endif +; /** Destroy a secp256k1 context object (created in dynamically allocated memory). * @@ -319,7 +386,15 @@ SECP256K1_API secp256k1_context *secp256k1_context_clone( */ SECP256K1_API void secp256k1_context_destroy( secp256k1_context *ctx -) SECP256K1_ARG_NONNULL(1); +) SECP256K1_ARG_NONNULL(1) +#if !SECP256K1_HAVE_STDLIB_H +SECP256K1_UNAVAILABLE( + "Needs malloc/free but seems unavailable on this platform, " + "see secp256k1_prealloc.h for alternatives. " + "(#define SECP256K1_HAVE_STDLIB_H 1 to override.)" +) +#endif +; /** Set a callback function to be called when an illegal argument is passed to * an API call. It will only trigger for violations that are mentioned @@ -402,7 +477,14 @@ SECP256K1_API void secp256k1_context_set_error_callback( SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space *secp256k1_scratch_space_create( const secp256k1_context *ctx, size_t size -) SECP256K1_ARG_NONNULL(1); +) SECP256K1_ARG_NONNULL(1) +#if !SECP256K1_HAVE_STDLIB_H +SECP256K1_UNAVAILABLE( + "Needs malloc/free but seems unavailable on this platform. " + "(#define SECP256K1_HAVE_STDLIB_H 1 to override.)" +) +#endif +; /** Destroy a secp256k1 scratch space. * @@ -413,7 +495,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space *secp256k1_sc SECP256K1_API void secp256k1_scratch_space_destroy( const secp256k1_context *ctx, secp256k1_scratch_space *scratch -) SECP256K1_ARG_NONNULL(1); +) SECP256K1_ARG_NONNULL(1) +#if !SECP256K1_HAVE_STDLIB_H +SECP256K1_UNAVAILABLE( + "Needs malloc/free but seems unavailable on this platform. " + "(#define SECP256K1_HAVE_STDLIB_H 1 to override.)" +) +#endif +; /** Parse a variable-length public key into the pubkey object. * diff --git a/src/hash.h b/src/hash.h index 4e0384cfbf..0960c42a81 100644 --- a/src/hash.h +++ b/src/hash.h @@ -7,7 +7,7 @@ #ifndef SECP256K1_HASH_H #define SECP256K1_HASH_H -#include +#include #include typedef struct { diff --git a/src/hash_impl.h b/src/hash_impl.h index 89f75ace74..e7808e37dc 100644 --- a/src/hash_impl.h +++ b/src/hash_impl.h @@ -10,7 +10,7 @@ #include "hash.h" #include "util.h" -#include +#include #include #include diff --git a/src/modinv32.h b/src/modinv32.h index 846c642f8c..cfdac60377 100644 --- a/src/modinv32.h +++ b/src/modinv32.h @@ -7,6 +7,8 @@ #ifndef SECP256K1_MODINV32_H #define SECP256K1_MODINV32_H +#include + #include "util.h" /* A signed 30-bit limb representation of integers. diff --git a/src/modinv32_impl.h b/src/modinv32_impl.h index 75eb354ff0..ed883069de 100644 --- a/src/modinv32_impl.h +++ b/src/modinv32_impl.h @@ -8,11 +8,8 @@ #define SECP256K1_MODINV32_IMPL_H #include "modinv32.h" - #include "util.h" -#include - /* This file implements modular inversion based on the paper "Fast constant-time gcd computation and * modular inversion" by Daniel J. Bernstein and Bo-Yin Yang. * @@ -21,6 +18,14 @@ */ #ifdef VERIFY +/* Helper function to compute the absolute value of an int32_t. + * (We don't use abs/labs/llabs as they depend on the int sizes and require stdlib.h.) */ +static int64_t secp256k1_modinv32_abs(int32_t v) { + VERIFY_CHECK(v > INT32_MIN); + if (v < 0) return -v; + return v; +} + static const secp256k1_modinv32_signed30 SECP256K1_SIGNED30_ONE = {{1}}; /* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^30). */ @@ -415,8 +420,8 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ - VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */ - VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */ + VERIFY_CHECK(secp256k1_modinv32_abs(u) <= (M30 + 1 - secp256k1_modinv32_abs(v))); /* |u|+|v| <= 2^30 */ + VERIFY_CHECK(secp256k1_modinv32_abs(q) <= (M30 + 1 - secp256k1_modinv32_abs(r))); /* |q|+|r| <= 2^30 */ /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ sd = d->v[8] >> 31; diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h index 0dc1e80696..498ebbe934 100644 --- a/src/modinv64_impl.h +++ b/src/modinv64_impl.h @@ -28,7 +28,7 @@ typedef struct { #ifdef VERIFY /* Helper function to compute the absolute value of an int64_t. - * (we don't use abs/labs/llabs as it depends on the int sizes). */ + * (We don't use abs/labs/llabs as they depend on the int sizes and require stdlib.h.) */ static int64_t secp256k1_modinv64_abs(int64_t v) { VERIFY_CHECK(v > INT64_MIN); if (v < 0) return -v; diff --git a/src/scratch_impl.h b/src/scratch_impl.h index f71a20b963..5795653604 100644 --- a/src/scratch_impl.h +++ b/src/scratch_impl.h @@ -7,9 +7,12 @@ #ifndef SECP256K1_SCRATCH_IMPL_H #define SECP256K1_SCRATCH_IMPL_H +#include + #include "util.h" #include "scratch.h" +#if SECP256K1_HAVE_STDLIB_H static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) { const size_t base_alloc = ROUND_TO_ALIGN(sizeof(secp256k1_scratch)); void *alloc = checked_malloc(error_callback, base_alloc + size); @@ -34,6 +37,7 @@ static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, free(scratch); } } +#endif static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch) { if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { diff --git a/src/secp256k1.c b/src/secp256k1.c index 4c11e7f0b8..5aa8b1ac58 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -137,6 +137,7 @@ secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigne return ret; } +#if SECP256K1_HAVE_STDLIB_H 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); @@ -147,6 +148,7 @@ secp256k1_context* secp256k1_context_create(unsigned int flags) { return ctx; } +#endif secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context* ctx, void* prealloc) { secp256k1_context* ret; @@ -159,6 +161,7 @@ secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context* return ret; } +#if SECP256K1_HAVE_STDLIB_H secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { secp256k1_context* ret; size_t prealloc_size; @@ -171,6 +174,7 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { ret = secp256k1_context_preallocated_clone(ctx, ret); return ret; } +#endif void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) { ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx)); @@ -183,6 +187,7 @@ void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) { secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); } +#if SECP256K1_HAVE_STDLIB_H void secp256k1_context_destroy(secp256k1_context* ctx) { ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx)); @@ -194,6 +199,7 @@ void secp256k1_context_destroy(secp256k1_context* ctx) { secp256k1_context_preallocated_destroy(ctx); free(ctx); } +#endif void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { /* We compare pointers instead of checking secp256k1_context_is_proper() here @@ -219,6 +225,7 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co ctx->error_callback.data = data; } +#if SECP256K1_HAVE_STDLIB_H 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); @@ -228,6 +235,7 @@ void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scr VERIFY_CHECK(ctx != NULL); secp256k1_scratch_destroy(&ctx->error_callback, scratch); } +#endif /* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour * of the software. diff --git a/src/util.h b/src/util.h index 187bf1c5e0..de71e7456c 100644 --- a/src/util.h +++ b/src/util.h @@ -9,16 +9,22 @@ #include "../include/secp256k1.h" -#include -#include -#include #include +#include +#include +#if SECP256K1_HAVE_STDIO_H +# include +#endif +#if SECP256K1_HAVE_STDLIB_H +# include +#endif #define STR_(x) #x #define STR(x) STR_(x) #define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x #define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x)) +#if SECP256K1_HAVE_STDIO_H /* Debug helper for printing arrays of unsigned char. */ #define PRINT_BUF(buf, len) do { \ printf("%s[%lu] = ", #buf, (unsigned long)len); \ @@ -38,6 +44,7 @@ static void print_buf_plain(const unsigned char *buf, size_t len) { } printf("\n}\n"); } +#endif # if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) # if SECP256K1_GNUC_PREREQ(2,7) @@ -73,15 +80,27 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * cb->fn(text, (void*)cb->data); } -#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS +#if !SECP256K1_HAVE_STDLIB_H && !defined(USE_EXTERNAL_DEFAULT_CALLBACKS) +# error " is not available. You need to use external default callbacks, see the documentation of secp256k1_context_set_illegal_callback." +#endif + +#if SECP256K1_HAVE_STDLIB_H static void secp256k1_default_illegal_callback_fn(const char* str, void* data) { (void)data; +#if SECP256K1_HAVE_STDIO_H fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); +#else + (void)str; +#endif abort(); } static void secp256k1_default_error_callback_fn(const char* str, void* data) { (void)data; +#if SECP256K1_HAVE_STDIO_H fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); +#else + (void)str; +#endif abort(); } #else @@ -139,6 +158,7 @@ static const secp256k1_callback default_error_callback = { #define VERIFY_CHECK(cond) #endif +#if SECP256K1_HAVE_STDLIB_H static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { void *ret = malloc(size); if (ret == NULL) { @@ -146,6 +166,7 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_ } return ret; } +#endif #if defined(__BIGGEST_ALIGNMENT__) #define ALIGNMENT __BIGGEST_ALIGNMENT__