Skip to content

Commit c4fd5da

Browse files
Switch to a single malloc call
1 parent ef020de commit c4fd5da

File tree

8 files changed

+78
-65
lines changed

8 files changed

+78
-65
lines changed

include/secp256k1.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ typedef int (*secp256k1_nonce_function)(
187187
SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp;
188188

189189
/** Create a secp256k1 context object.
190+
*
191+
* This function uses malloc to allocate memory. It is guaranteed that malloc is
192+
* called at most once for every call of this function.
190193
*
191194
* Returns: a newly created context object.
192195
* In: flags: which parts of the context to initialize.
@@ -198,6 +201,9 @@ SECP256K1_API secp256k1_context* secp256k1_context_create(
198201
) SECP256K1_WARN_UNUSED_RESULT;
199202

200203
/** Copies a secp256k1 context object.
204+
*
205+
* This function uses malloc to allocate memory. It is guaranteed that malloc is
206+
* called at most once for every call of this function.
201207
*
202208
* Returns: a newly created context object.
203209
* Args: ctx: an existing context to copy (cannot be NULL)

src/ecmult.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ typedef struct {
2222

2323
static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE;
2424
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx);
25-
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb);
26-
static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,
27-
const secp256k1_ecmult_context *src, const secp256k1_callback *cb);
25+
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void **prealloc);
26+
static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *dst, const secp256k1_ecmult_context *src);
2827
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx);
2928
static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx);
3029

src/ecmult_gen.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,8 @@ typedef struct {
3030

3131
static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
3232
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx);
33-
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb);
34-
static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
35-
const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb);
33+
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, void **prealloc);
34+
static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context* src);
3635
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);
3736
static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx);
3837

src/ecmult_gen_impl.h

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,21 @@ static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx)
2626
ctx->prec = NULL;
2727
}
2828

29-
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) {
29+
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, void **prealloc) {
3030
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
3131
secp256k1_ge prec[1024];
3232
secp256k1_gej gj;
3333
secp256k1_gej nums_gej;
3434
int i, j;
35+
size_t const prealloc_size = SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
36+
void* const base = *prealloc;
3537
#endif
3638

3739
if (ctx->prec != NULL) {
3840
return;
3941
}
4042
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
41-
ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec));
43+
ctx->prec = (secp256k1_ge_storage (*)[64][16])manual_alloc(prealloc, prealloc_size, base, prealloc_size);
4244

4345
/* get the generator */
4446
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
@@ -93,7 +95,7 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx
9395
}
9496
}
9597
#else
96-
(void)cb;
98+
(void)prealloc;
9799
ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context;
98100
#endif
99101
secp256k1_ecmult_gen_blind(ctx, NULL);
@@ -103,27 +105,18 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont
103105
return ctx->prec != NULL;
104106
}
105107

106-
static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
107-
const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) {
108-
if (src->prec == NULL) {
109-
dst->prec = NULL;
110-
} else {
108+
static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context *src) {
111109
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
112-
dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec));
113-
memcpy(dst->prec, src->prec, sizeof(*dst->prec));
110+
if (src->prec != NULL) {
111+
/* We cast to void* first to suppress a -Wcast-align warning. */
112+
dst->prec = (secp256k1_ge_storage (*)[64][16])(void*)((unsigned char*)dst + ((unsigned char*)src->prec - (unsigned char*)src));
113+
}
114114
#else
115-
(void)cb;
116-
dst->prec = src->prec;
115+
(void)dst, (void)src;
117116
#endif
118-
dst->initial = src->initial;
119-
dst->blind = src->blind;
120-
}
121117
}
122118

123119
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
124-
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
125-
free(ctx->prec);
126-
#endif
127120
secp256k1_scalar_clear(&ctx->blind);
128121
secp256k1_gej_clear(&ctx->initial);
129122
ctx->prec = NULL;

src/ecmult_impl.h

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,10 @@ static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) {
325325
#endif
326326
}
327327

328-
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) {
328+
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void **prealloc) {
329329
secp256k1_gej gj;
330+
void* const base = *prealloc;
331+
size_t const prealloc_size = SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE;
330332

331333
if (ctx->pre_g != NULL) {
332334
return;
@@ -339,7 +341,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
339341
size_t size = sizeof((*ctx->pre_g)[0]) * ((size_t)ECMULT_TABLE_SIZE(WINDOW_G));
340342
/* check for overflow */
341343
VERIFY_CHECK(size / sizeof((*ctx->pre_g)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)));
342-
ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
344+
ctx->pre_g = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G), base, prealloc_size);
343345
}
344346

345347
/* precompute the tables with odd multiples */
@@ -353,7 +355,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
353355
size_t size = sizeof((*ctx->pre_g_128)[0]) * ((size_t) ECMULT_TABLE_SIZE(WINDOW_G));
354356
/* check for overflow */
355357
VERIFY_CHECK(size / sizeof((*ctx->pre_g_128)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)));
356-
ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
358+
ctx->pre_g_128 = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G), base, prealloc_size);
357359

358360
/* calculate 2^128*generator */
359361
g_128j = gj;
@@ -365,22 +367,14 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
365367
#endif
366368
}
367369

368-
static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,
369-
const secp256k1_ecmult_context *src, const secp256k1_callback *cb) {
370-
if (src->pre_g == NULL) {
371-
dst->pre_g = NULL;
372-
} else {
373-
size_t size = sizeof((*dst->pre_g)[0]) * ((size_t)ECMULT_TABLE_SIZE(WINDOW_G));
374-
dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
375-
memcpy(dst->pre_g, src->pre_g, size);
370+
static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *dst, const secp256k1_ecmult_context *src) {
371+
if (src->pre_g != NULL) {
372+
/* We cast to void* first to suppress a -Wcast-align warning. */
373+
dst->pre_g = (secp256k1_ge_storage (*)[])(void*)((unsigned char*)dst + ((unsigned char*)(src->pre_g) - (unsigned char*)src));
376374
}
377375
#ifdef USE_ENDOMORPHISM
378-
if (src->pre_g_128 == NULL) {
379-
dst->pre_g_128 = NULL;
380-
} else {
381-
size_t size = sizeof((*dst->pre_g_128)[0]) * ((size_t)ECMULT_TABLE_SIZE(WINDOW_G));
382-
dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
383-
memcpy(dst->pre_g_128, src->pre_g_128, size);
376+
if (src->pre_g_128 != NULL) {
377+
dst->pre_g_128 = (secp256k1_ge_storage (*)[])(void*)((unsigned char*)dst + ((unsigned char*)(src->pre_g_128) - (unsigned char*)src));
384378
}
385379
#endif
386380
}
@@ -390,10 +384,6 @@ static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx
390384
}
391385

392386
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) {
393-
free(ctx->pre_g);
394-
#ifdef USE_ENDOMORPHISM
395-
free(ctx->pre_g_128);
396-
#endif
397387
secp256k1_ecmult_context_init(ctx);
398388
}
399389

src/gen_context.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "basic-config.h"
1010
#include "include/secp256k1.h"
11+
#include "util.h"
1112
#include "field_impl.h"
1213
#include "scalar_impl.h"
1314
#include "group_impl.h"
@@ -26,6 +27,7 @@ static const secp256k1_callback default_error_callback = {
2627

2728
int main(int argc, char **argv) {
2829
secp256k1_ecmult_gen_context ctx;
30+
void *prealloc, *base;
2931
int inner;
3032
int outer;
3133
FILE* fp;
@@ -38,15 +40,17 @@ int main(int argc, char **argv) {
3840
fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n");
3941
return -1;
4042
}
41-
43+
4244
fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
4345
fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
4446
fprintf(fp, "#include \"src/group.h\"\n");
4547
fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n");
4648
fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n");
4749

50+
base = checked_malloc(&default_error_callback, SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE);
51+
prealloc = base;
4852
secp256k1_ecmult_gen_context_init(&ctx);
49-
secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback);
53+
secp256k1_ecmult_gen_context_build(&ctx, &prealloc);
5054
for(outer = 0; outer != 64; outer++) {
5155
fprintf(fp,"{\n");
5256
for(inner = 0; inner != 16; inner++) {
@@ -65,10 +69,11 @@ int main(int argc, char **argv) {
6569
}
6670
fprintf(fp,"};\n");
6771
secp256k1_ecmult_gen_context_clear(&ctx);
68-
72+
free(base);
73+
6974
fprintf(fp, "#undef SC\n");
7075
fprintf(fp, "#endif\n");
7176
fclose(fp);
72-
77+
7378
return 0;
7479
}

src/secp256k1.c

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -82,46 +82,71 @@ size_t secp256k1_context_preallocated_size(unsigned int flags) {
8282
return ret;
8383
}
8484

85-
secp256k1_context* secp256k1_context_create(unsigned int flags) {
86-
secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context));
85+
secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) {
86+
void* const base = prealloc;
87+
size_t prealloc_size = secp256k1_context_preallocated_size(flags);
88+
secp256k1_context* ret = (secp256k1_context*)manual_alloc(&prealloc, sizeof(secp256k1_context), base, prealloc_size);
89+
8790
ret->illegal_callback = default_illegal_callback;
8891
ret->error_callback = default_error_callback;
8992

9093
if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) {
9194
secp256k1_callback_call(&ret->illegal_callback,
9295
"Invalid flags");
93-
free(ret);
9496
return NULL;
9597
}
9698

9799
secp256k1_ecmult_context_init(&ret->ecmult_ctx);
98100
secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx);
99101

100102
if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) {
101-
secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback);
103+
secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &prealloc);
102104
}
103105
if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) {
104-
secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback);
106+
secp256k1_ecmult_context_build(&ret->ecmult_ctx, &prealloc);
105107
}
106108

107-
return ret;
109+
return (secp256k1_context*) ret;
110+
}
111+
112+
secp256k1_context* secp256k1_context_create(unsigned int flags) {
113+
size_t const prealloc_size = secp256k1_context_preallocated_size(flags);
114+
secp256k1_context* ctx = (secp256k1_context*)checked_malloc(&default_error_callback, prealloc_size);
115+
if (EXPECT(secp256k1_context_preallocated_create(ctx, flags) == NULL, 0)) {
116+
free(ctx);
117+
return NULL;
118+
}
119+
120+
return ctx;
108121
}
109122

110123
secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
111-
secp256k1_context* ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context));
112-
ret->illegal_callback = ctx->illegal_callback;
113-
ret->error_callback = ctx->error_callback;
114-
secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback);
115-
secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback);
124+
secp256k1_context* ret;
125+
size_t prealloc_size = ROUND_TO_ALIGN(sizeof(secp256k1_context));
126+
if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) {
127+
prealloc_size += SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
128+
}
129+
if (secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)) {
130+
prealloc_size += SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE;
131+
}
132+
ret = checked_malloc(&ctx->error_callback, prealloc_size);
133+
memcpy(ret, ctx, prealloc_size);
134+
secp256k1_ecmult_gen_context_finalize_memcpy(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx);
135+
secp256k1_ecmult_context_finalize_memcpy(&ret->ecmult_ctx, &ctx->ecmult_ctx);
116136
return ret;
117137
}
118138

119-
void secp256k1_context_destroy(secp256k1_context* ctx) {
139+
void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
120140
CHECK(ctx != secp256k1_context_no_precomp);
121141
if (ctx != NULL) {
122142
secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
123143
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
144+
}
145+
}
124146

147+
void secp256k1_context_destroy(secp256k1_context* ctx) {
148+
if (ctx != NULL) {
149+
secp256k1_context_preallocated_destroy(ctx);
125150
free(ctx);
126151
}
127152
}

src/tests.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,6 @@ void run_context_tests(void) {
229229
secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);
230230
secp256k1_context_set_illegal_callback(sign, NULL, NULL);
231231

232-
/* This shouldn't leak memory, due to already-set tests. */
233-
secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL);
234-
secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL);
235-
236232
/* obtain a working nonce */
237233
do {
238234
random_scalar_order_test(&nonce);

0 commit comments

Comments
 (0)