#ifndef _SECP256K1_SCRATCH_IMPL_H_
#define _SECP256K1_SCRATCH_IMPL_H_
+#include "util.h"
#include "scratch.h"
-/* Using 16 bytes alignment because common architectures never have alignment
- * requirements above 8 for any of the types we care about. In addition we
- * leave some room because currently we don't care about a few bytes.
- * TODO: Determine this at configure time. */
-#define ALIGNMENT 16
-
-static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t init_size, size_t max_size) {
- secp256k1_scratch* ret = (secp256k1_scratch*)checked_malloc(error_callback, sizeof(*ret));
+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);
+ secp256k1_scratch* ret = (secp256k1_scratch *)alloc;
if (ret != NULL) {
- ret->data = checked_malloc(error_callback, init_size);
- if (ret->data == NULL) {
- free (ret);
- return NULL;
- }
- ret->offset = 0;
- ret->init_size = init_size;
- ret->max_size = max_size;
- ret->error_callback = error_callback;
+ memset(ret, 0, sizeof(*ret));
+ memcpy(ret->magic, "scratch", 8);
+ ret->data = (void *) ((char *) alloc + base_alloc);
+ ret->max_size = size;
}
return ret;
}
-static void secp256k1_scratch_destroy(secp256k1_scratch* scratch) {
+static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) {
if (scratch != NULL) {
- free(scratch->data);
+ VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */
+ if (memcmp(scratch->magic, "scratch", 8) != 0) {
+ secp256k1_callback_call(error_callback, "invalid scratch space");
+ return;
+ }
+ memset(scratch->magic, 0, sizeof(scratch->magic));
free(scratch);
}
}
-static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t objects) {
- if (scratch->max_size <= objects * ALIGNMENT) {
+static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch) {
+ if (memcmp(scratch->magic, "scratch", 8) != 0) {
+ secp256k1_callback_call(error_callback, "invalid scratch space");
return 0;
}
- return scratch->max_size - objects * ALIGNMENT;
+ return scratch->alloc_size;
}
-static int secp256k1_scratch_resize(secp256k1_scratch* scratch, size_t n, size_t objects) {
- n += objects * ALIGNMENT;
- if (n > scratch->init_size && n <= scratch->max_size) {
- void *tmp = checked_realloc(scratch->error_callback, scratch->data, n);
- if (tmp == NULL) {
- return 0;
- }
- scratch->init_size = n;
- scratch->data = tmp;
+static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint) {
+ if (memcmp(scratch->magic, "scratch", 8) != 0) {
+ secp256k1_callback_call(error_callback, "invalid scratch space");
+ return;
+ }
+ if (checkpoint > scratch->alloc_size) {
+ secp256k1_callback_call(error_callback, "invalid checkpoint");
+ return;
}
- return n <= scratch->max_size;
+ scratch->alloc_size = checkpoint;
}
-static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t size) {
+static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t objects) {
+ if (memcmp(scratch->magic, "scratch", 8) != 0) {
+ secp256k1_callback_call(error_callback, "invalid scratch space");
+ return 0;
+ }
+ /* Ensure that multiplication will not wrap around */
+ if (ALIGNMENT > 1 && objects > SIZE_MAX/(ALIGNMENT - 1)) {
+ return 0;
+ }
+ if (scratch->max_size - scratch->alloc_size <= objects * (ALIGNMENT - 1)) {
+ return 0;
+ }
+ return scratch->max_size - scratch->alloc_size - objects * (ALIGNMENT - 1);
+}
+
+static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t size) {
void *ret;
- size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
- if (size + scratch->offset > scratch->init_size) {
+ size_t rounded_size;
+
+ rounded_size = ROUND_TO_ALIGN(size);
+ /* Check that rounding did not wrap around */
+ if (rounded_size < size) {
+ return NULL;
+ }
+ size = rounded_size;
+
+ if (memcmp(scratch->magic, "scratch", 8) != 0) {
+ secp256k1_callback_call(error_callback, "invalid scratch space");
return NULL;
}
- ret = (void *) ((unsigned char *) scratch->data + scratch->offset);
+
+ if (size > scratch->max_size - scratch->alloc_size) {
+ return NULL;
+ }
+ ret = (void *) ((char *) scratch->data + scratch->alloc_size);
memset(ret, 0, size);
- scratch->offset += size;
- return ret;
-}
+ scratch->alloc_size += size;
-static void secp256k1_scratch_reset(secp256k1_scratch* scratch) {
- scratch->offset = 0;
+ return ret;
}
#endif