Skip to content

Commit 143dc6e

Browse files
committed
Merge dashpay#595: Allow to use external default callbacks
e49f799 Add missing #(un)defines to base-config.h (Tim Ruffing) 77defd2 Add secp256k1_ prefix to default callback functions (Tim Ruffing) 908bdce Include stdio.h and stdlib.h explicitly in secp256k1.c (Tim Ruffing) 5db782e Allow usage of external default callbacks (Tim Ruffing) 6095a86 Replace CHECKs for no_precomp ctx by ARG_CHECKs without a return (Tim Ruffing) Pull request description: This is intended for environments without implementations for `abort()`, `fprintf()`, and `stderr`. e.g., embedded systems. Those can provide their own implementations of `default_illegal_callback_fn` and `default_error_callback_fn` at compile time. If you want to use your own default callback, things will be somewhat inconsistent unfortunately: We cannot make the callback data `extern` too, because then the initialization lists for `default_illegal_callback` won't contain only constants. (`const` variables are not compile-time constants). So you cannot take callback data in your own default callback function. As a more drastic/breaking alternative I suggest to remove the callback data entirely. I don't think it's a big loss and I would be surprised if anyone uses it. Additionally, we could even remove the possibility to set the callback function at runtime after this PR. This will simplify things a lot, and again I don't think it's a big loss. Note that `abort()`, `fprintf()`, and `stderr` are also used in `CHECK`, which is still used in production code if we rely on gmp for scalar and field inversions (e.g., https://github.com/bitcoin-core/secp256k1/blob/master/src/scalar_impl.h#L240). This is not an issue for embedded system which probably don't want to use gmp anyway, but it is probably an issue for the reasons explained in bitcoin-core/secp256k1#566 (comment). (related downstream: rust-bitcoin/rust-secp256k1#100 @elichai) ACKs for commit e49f79: Tree-SHA512: 4dec0821eef4156cbe162bd8cdf0531c1fae8c98cd9db8438170ff1aa0e59b199739eeab293695bb582246812bea5309959f02f1fb74bb57872da54ebc52313f
2 parents 6c36de7 + e49f799 commit 143dc6e

File tree

4 files changed

+80
-37
lines changed

4 files changed

+80
-37
lines changed

configure.ac

+26-16
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ AC_ARG_ENABLE(module_recovery,
134134
[enable_module_recovery=$enableval],
135135
[enable_module_recovery=no])
136136

137+
AC_ARG_ENABLE(external_default_callbacks,
138+
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions (default is no)]),
139+
[use_external_default_callbacks=$enableval],
140+
[use_external_default_callbacks=no])
141+
137142
AC_ARG_ENABLE(jni,
138143
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni [default=no]]),
139144
[use_jni=$enableval],
@@ -493,6 +498,10 @@ if test x"$use_external_asm" = x"yes"; then
493498
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
494499
fi
495500

501+
if test x"$use_external_default_callbacks" = x"yes"; then
502+
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
503+
fi
504+
496505
if test x"$enable_experimental" = x"yes"; then
497506
AC_MSG_NOTICE([******])
498507
AC_MSG_NOTICE([WARNING: experimental build])
@@ -535,22 +544,23 @@ AC_OUTPUT
535544

536545
echo
537546
echo "Build Options:"
538-
echo " with endomorphism = $use_endomorphism"
539-
echo " with ecmult precomp = $set_precomp"
540-
echo " with jni = $use_jni"
541-
echo " with benchmarks = $use_benchmark"
542-
echo " with coverage = $enable_coverage"
543-
echo " module ecdh = $enable_module_ecdh"
544-
echo " module recovery = $enable_module_recovery"
547+
echo " with endomorphism = $use_endomorphism"
548+
echo " with ecmult precomp = $set_precomp"
549+
echo " with external callbacks = $use_external_default_callbacks"
550+
echo " with jni = $use_jni"
551+
echo " with benchmarks = $use_benchmark"
552+
echo " with coverage = $enable_coverage"
553+
echo " module ecdh = $enable_module_ecdh"
554+
echo " module recovery = $enable_module_recovery"
545555
echo
546-
echo " asm = $set_asm"
547-
echo " bignum = $set_bignum"
548-
echo " field = $set_field"
549-
echo " scalar = $set_scalar"
550-
echo " ecmult window size = $set_ecmult_window"
556+
echo " asm = $set_asm"
557+
echo " bignum = $set_bignum"
558+
echo " field = $set_field"
559+
echo " scalar = $set_scalar"
560+
echo " ecmult window size = $set_ecmult_window"
551561
echo
552-
echo " CC = $CC"
553-
echo " CFLAGS = $CFLAGS"
554-
echo " CPPFLAGS = $CPPFLAGS"
555-
echo " LDFLAGS = $LDFLAGS"
562+
echo " CC = $CC"
563+
echo " CFLAGS = $CFLAGS"
564+
echo " CPPFLAGS = $CPPFLAGS"
565+
echo " LDFLAGS = $LDFLAGS"
556566
echo

include/secp256k1.h

+24-4
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,28 @@ SECP256K1_API void secp256k1_context_destroy(
247247
* to cause a crash, though its return value and output arguments are
248248
* undefined.
249249
*
250+
* When this function has not been called (or called with fn==NULL), then the
251+
* default handler will be used. The library provides a default handler which
252+
* writes the message to stderr and calls abort. This default handler can be
253+
* replaced at link time if the preprocessor macro
254+
* USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build
255+
* has been configured with --enable-external-default-callbacks. Then the
256+
* following two symbols must be provided to link against:
257+
* - void secp256k1_default_illegal_callback_fn(const char* message, void* data);
258+
* - void secp256k1_default_error_callback_fn(const char* message, void* data);
259+
* The library can call these default handlers even before a proper callback data
260+
* pointer could have been set using secp256k1_context_set_illegal_callback or
261+
* secp256k1_context_set_illegal_callback, e.g., when the creation of a context
262+
* fails. In this case, the corresponding default handler will be called with
263+
* the data pointer argument set to NULL.
264+
*
250265
* Args: ctx: an existing context object (cannot be NULL)
251266
* In: fun: a pointer to a function to call when an illegal argument is
252-
* passed to the API, taking a message and an opaque pointer
253-
* (NULL restores a default handler that calls abort).
267+
* passed to the API, taking a message and an opaque pointer.
268+
* (NULL restores the default handler.)
254269
* data: the opaque pointer to pass to fun above.
270+
*
271+
* See also secp256k1_context_set_error_callback.
255272
*/
256273
SECP256K1_API void secp256k1_context_set_illegal_callback(
257274
secp256k1_context* ctx,
@@ -271,9 +288,12 @@ SECP256K1_API void secp256k1_context_set_illegal_callback(
271288
*
272289
* Args: ctx: an existing context object (cannot be NULL)
273290
* In: fun: a pointer to a function to call when an internal error occurs,
274-
* taking a message and an opaque pointer (NULL restores a default
275-
* handler that calls abort).
291+
* taking a message and an opaque pointer (NULL restores the
292+
* default handler, see secp256k1_context_set_illegal_callback
293+
* for details).
276294
* data: the opaque pointer to pass to fun above.
295+
*
296+
* See also secp256k1_context_set_illegal_callback.
277297
*/
278298
SECP256K1_API void secp256k1_context_set_error_callback(
279299
secp256k1_context* ctx,

src/basic-config.h

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#undef USE_ASM_X86_64
1313
#undef USE_ECMULT_STATIC_PRECOMPUTATION
1414
#undef USE_ENDOMORPHISM
15+
#undef USE_EXTERNAL_ASM
16+
#undef USE_EXTERNAL_DEFAULT_CALLBACKS
1517
#undef USE_FIELD_10X26
1618
#undef USE_FIELD_5X52
1719
#undef USE_FIELD_INV_BUILTIN

src/secp256k1.c

+28-17
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,39 @@
2727
} \
2828
} while(0)
2929

30-
static void default_illegal_callback_fn(const char* str, void* data) {
30+
#define ARG_CHECK_NO_RETURN(cond) do { \
31+
if (EXPECT(!(cond), 0)) { \
32+
secp256k1_callback_call(&ctx->illegal_callback, #cond); \
33+
} \
34+
} while(0)
35+
36+
#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS
37+
#include <stdlib.h>
38+
#include <stdio.h>
39+
static void secp256k1_default_illegal_callback_fn(const char* str, void* data) {
3140
(void)data;
3241
fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str);
3342
abort();
3443
}
35-
36-
static const secp256k1_callback default_illegal_callback = {
37-
default_illegal_callback_fn,
38-
NULL
39-
};
40-
41-
static void default_error_callback_fn(const char* str, void* data) {
44+
static void secp256k1_default_error_callback_fn(const char* str, void* data) {
4245
(void)data;
4346
fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str);
4447
abort();
4548
}
49+
#else
50+
void secp256k1_default_illegal_callback_fn(const char* str, void* data);
51+
void secp256k1_default_error_callback_fn(const char* str, void* data);
52+
#endif
4653

47-
static const secp256k1_callback default_error_callback = {
48-
default_error_callback_fn,
54+
static const secp256k1_callback default_illegal_callback = {
55+
secp256k1_default_illegal_callback_fn,
4956
NULL
5057
};
5158

59+
static const secp256k1_callback default_error_callback = {
60+
secp256k1_default_error_callback_fn,
61+
NULL
62+
};
5263

5364
struct secp256k1_context_struct {
5465
secp256k1_ecmult_context ecmult_ctx;
@@ -60,8 +71,8 @@ struct secp256k1_context_struct {
6071
static const secp256k1_context secp256k1_context_no_precomp_ = {
6172
{ 0 },
6273
{ 0 },
63-
{ default_illegal_callback_fn, 0 },
64-
{ default_error_callback_fn, 0 }
74+
{ secp256k1_default_illegal_callback_fn, 0 },
75+
{ secp256k1_default_error_callback_fn, 0 }
6576
};
6677
const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_;
6778

@@ -162,7 +173,7 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
162173
}
163174

164175
void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
165-
CHECK(ctx != secp256k1_context_no_precomp);
176+
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
166177
if (ctx != NULL) {
167178
secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
168179
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
@@ -177,18 +188,18 @@ void secp256k1_context_destroy(secp256k1_context* ctx) {
177188
}
178189

179190
void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
180-
CHECK(ctx != secp256k1_context_no_precomp);
191+
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
181192
if (fun == NULL) {
182-
fun = default_illegal_callback_fn;
193+
fun = secp256k1_default_illegal_callback_fn;
183194
}
184195
ctx->illegal_callback.fn = fun;
185196
ctx->illegal_callback.data = data;
186197
}
187198

188199
void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
189-
CHECK(ctx != secp256k1_context_no_precomp);
200+
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
190201
if (fun == NULL) {
191-
fun = default_error_callback_fn;
202+
fun = secp256k1_default_error_callback_fn;
192203
}
193204
ctx->error_callback.fn = fun;
194205
ctx->error_callback.data = data;

0 commit comments

Comments
 (0)