Merge #566: Enable context creation in preallocated memory
0522caa Explain caller's obligations for preallocated memory (Tim Ruffing) 238305f Move _preallocated functions to separate header (Tim Ruffing) 695feb6 Export _preallocated functions (Tim Ruffing) 814cc78 Add tests for contexts in preallocated memory (Tim Ruffing) ba12dd0 Check arguments of _preallocated functions (Tim Ruffing) 5feadde Support cloning a context into preallocated memory (Tim Ruffing) c4fd5da Switch to a single malloc call (Tim Ruffing) ef020de Add size constants for preallocated memory (Tim Ruffing) 1bf7c05 Prepare for manual memory management in preallocated memory (Tim Ruffing) Pull request description: @apoelstra This builds on #557. Manually managing memory is always a pain in the ass in some way. I tried to keep the pain manageable. I'm open to suggestions to make this less ugly or error-prone. to do: * tests * export functions ACKs for commit 0522ca: Tree-SHA512: 8ddb5b70219b6f095e780a9812d2387ab2a7f399803ce4101e27da504b479a61ebe08b6380568c7ba6f1e73d7d0b1f58a3c0a66fa0fdec7a64cd0740e156ce38
This commit is contained in:
commit
a484e0008b
@ -8,6 +8,7 @@ else
|
|||||||
JNI_LIB =
|
JNI_LIB =
|
||||||
endif
|
endif
|
||||||
include_HEADERS = include/secp256k1.h
|
include_HEADERS = include/secp256k1.h
|
||||||
|
include_HEADERS += include/secp256k1_preallocated.h
|
||||||
noinst_HEADERS =
|
noinst_HEADERS =
|
||||||
noinst_HEADERS += src/scalar.h
|
noinst_HEADERS += src/scalar.h
|
||||||
noinst_HEADERS += src/scalar_4x64.h
|
noinst_HEADERS += src/scalar_4x64.h
|
||||||
|
@ -33,9 +33,10 @@ extern "C" {
|
|||||||
* verification).
|
* verification).
|
||||||
*
|
*
|
||||||
* A constructed context can safely be used from multiple threads
|
* A constructed context can safely be used from multiple threads
|
||||||
* simultaneously, but API call that take a non-const pointer to a context
|
* simultaneously, but API calls that take a non-const pointer to a context
|
||||||
* need exclusive access to it. In particular this is the case for
|
* need exclusive access to it. In particular this is the case for
|
||||||
* secp256k1_context_destroy and secp256k1_context_randomize.
|
* secp256k1_context_destroy, secp256k1_context_preallocated_destroy,
|
||||||
|
* and secp256k1_context_randomize.
|
||||||
*
|
*
|
||||||
* Regarding randomization, either do it once at creation time (in which case
|
* Regarding randomization, either do it once at creation time (in which case
|
||||||
* you do not need any locking for the other calls), or use a read-write lock.
|
* you do not need any locking for the other calls), or use a read-write lock.
|
||||||
@ -163,7 +164,8 @@ typedef int (*secp256k1_nonce_function)(
|
|||||||
#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
|
#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
|
||||||
#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
|
#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
|
||||||
|
|
||||||
/** Flags to pass to secp256k1_context_create. */
|
/** Flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and
|
||||||
|
* secp256k1_context_preallocated_create. */
|
||||||
#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
|
#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
|
||||||
#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
|
#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
|
||||||
#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
|
#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
|
||||||
@ -186,7 +188,11 @@ typedef int (*secp256k1_nonce_function)(
|
|||||||
*/
|
*/
|
||||||
SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp;
|
SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp;
|
||||||
|
|
||||||
/** Create a secp256k1 context object.
|
/** Create a secp256k1 context object (in dynamically allocated memory).
|
||||||
|
*
|
||||||
|
* This function uses malloc to allocate memory. It is guaranteed that malloc is
|
||||||
|
* called at most once for every call of this function. If you need to avoid dynamic
|
||||||
|
* memory allocation entirely, see the functions in secp256k1_preallocated.h.
|
||||||
*
|
*
|
||||||
* Returns: a newly created context object.
|
* Returns: a newly created context object.
|
||||||
* In: flags: which parts of the context to initialize.
|
* In: flags: which parts of the context to initialize.
|
||||||
@ -197,7 +203,11 @@ SECP256K1_API secp256k1_context* secp256k1_context_create(
|
|||||||
unsigned int flags
|
unsigned int flags
|
||||||
) SECP256K1_WARN_UNUSED_RESULT;
|
) SECP256K1_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
/** Copies a secp256k1 context object.
|
/** Copy a secp256k1 context object (into dynamically allocated memory).
|
||||||
|
*
|
||||||
|
* This function uses malloc to allocate memory. It is guaranteed that malloc is
|
||||||
|
* called at most once for every call of this function. If you need to avoid dynamic
|
||||||
|
* memory allocation entirely, see the functions in secp256k1_preallocated.h.
|
||||||
*
|
*
|
||||||
* Returns: a newly created context object.
|
* Returns: a newly created context object.
|
||||||
* Args: ctx: an existing context to copy (cannot be NULL)
|
* Args: ctx: an existing context to copy (cannot be NULL)
|
||||||
@ -206,10 +216,18 @@ SECP256K1_API secp256k1_context* secp256k1_context_clone(
|
|||||||
const secp256k1_context* ctx
|
const secp256k1_context* ctx
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
/** Destroy a secp256k1 context object.
|
/** Destroy a secp256k1 context object (created in dynamically allocated memory).
|
||||||
*
|
*
|
||||||
* The context pointer may not be used afterwards.
|
* The context pointer may not be used afterwards.
|
||||||
* Args: ctx: an existing context to destroy (cannot be NULL)
|
*
|
||||||
|
* The context to destroy must have been created using secp256k1_context_create
|
||||||
|
* or secp256k1_context_clone. If the context has instead been created using
|
||||||
|
* secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone, the
|
||||||
|
* behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must
|
||||||
|
* be used instead.
|
||||||
|
*
|
||||||
|
* Args: ctx: an existing context to destroy, constructed using
|
||||||
|
* secp256k1_context_create or secp256k1_context_clone
|
||||||
*/
|
*/
|
||||||
SECP256K1_API void secp256k1_context_destroy(
|
SECP256K1_API void secp256k1_context_destroy(
|
||||||
secp256k1_context* ctx
|
secp256k1_context* ctx
|
||||||
@ -636,7 +654,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
|
|||||||
* contexts not initialized for signing; then it will have no effect and return 1.
|
* contexts not initialized for signing; then it will have no effect and return 1.
|
||||||
*
|
*
|
||||||
* You should call this after secp256k1_context_create or
|
* You should call this after secp256k1_context_create or
|
||||||
* secp256k1_context_clone, and may call this repeatedly afterwards.
|
* secp256k1_context_clone (and secp256k1_context_preallocated_create or
|
||||||
|
* secp256k1_context_clone, resp.), and you may call this repeatedly afterwards.
|
||||||
*/
|
*/
|
||||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
|
||||||
secp256k1_context* ctx,
|
secp256k1_context* ctx,
|
||||||
|
128
include/secp256k1_preallocated.h
Normal file
128
include/secp256k1_preallocated.h
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#ifndef SECP256K1_PREALLOCATED_H
|
||||||
|
#define SECP256K1_PREALLOCATED_H
|
||||||
|
|
||||||
|
#include "secp256k1.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The module provided by this header file is intended for settings in which it
|
||||||
|
* is not possible or desirable to rely on dynamic memory allocation. It provides
|
||||||
|
* functions for creating, cloning, and destroying secp256k1 context objects in a
|
||||||
|
* contiguous fixed-size block of memory provided by the caller.
|
||||||
|
*
|
||||||
|
* Context objects created by functions in this module can be used like contexts
|
||||||
|
* objects created by functions in secp256k1.h, i.e., they can be passed to any
|
||||||
|
* API function that excepts a context object (see secp256k1.h for details). The
|
||||||
|
* only exception is that context objects created by functions in this module
|
||||||
|
* must be destroyed using secp256k1_context_preallocated_destroy (in this
|
||||||
|
* module) instead of secp256k1_context_destroy (in secp256k1.h).
|
||||||
|
*
|
||||||
|
* It is guaranteed that functions in by this module will not call malloc or its
|
||||||
|
* friends realloc, calloc, and free.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Determine the memory size of a secp256k1 context object to be created in
|
||||||
|
* caller-provided memory.
|
||||||
|
*
|
||||||
|
* The purpose of this function is to determine how much memory must be provided
|
||||||
|
* to secp256k1_context_preallocated_create.
|
||||||
|
*
|
||||||
|
* Returns: the required size of the caller-provided memory block
|
||||||
|
* In: flags: which parts of the context to initialize.
|
||||||
|
*/
|
||||||
|
SECP256K1_API size_t secp256k1_context_preallocated_size(
|
||||||
|
unsigned int flags
|
||||||
|
) SECP256K1_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
/** Create a secp256k1 context object in caller-provided memory.
|
||||||
|
*
|
||||||
|
* The caller must provide a pointer to a rewritable contiguous block of memory
|
||||||
|
* of size at least secp256k1_context_preallocated_size(flags) bytes, suitably
|
||||||
|
* aligned to hold an object of any type.
|
||||||
|
*
|
||||||
|
* The block of memory is exclusively owned by the created context object during
|
||||||
|
* the lifetime of this context object, which begins with the call to this
|
||||||
|
* function and ends when a call to secp256k1_context_preallocated_destroy
|
||||||
|
* (which destroys the context object again) returns. During the lifetime of the
|
||||||
|
* context object, the caller is obligated not to access this block of memory,
|
||||||
|
* i.e., the caller may not read or write the memory, e.g., by copying the memory
|
||||||
|
* contents to a different location or trying to create a second context object
|
||||||
|
* in the memory. In simpler words, the prealloc pointer (or any pointer derived
|
||||||
|
* from it) should not be used during the lifetime of the context object.
|
||||||
|
*
|
||||||
|
* Returns: a newly created context object.
|
||||||
|
* In: prealloc: a pointer to a rewritable contiguous block of memory of
|
||||||
|
* size at least secp256k1_context_preallocated_size(flags)
|
||||||
|
* bytes, as detailed above (cannot be NULL)
|
||||||
|
* flags: which parts of the context to initialize.
|
||||||
|
*
|
||||||
|
* See also secp256k1_context_randomize (in secp256k1.h)
|
||||||
|
* and secp256k1_context_preallocated_destroy.
|
||||||
|
*/
|
||||||
|
SECP256K1_API secp256k1_context* secp256k1_context_preallocated_create(
|
||||||
|
void* prealloc,
|
||||||
|
unsigned int flags
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
/** Determine the memory size of a secp256k1 context object to be copied into
|
||||||
|
* caller-provided memory.
|
||||||
|
*
|
||||||
|
* Returns: the required size of the caller-provided memory block.
|
||||||
|
* In: ctx: an existing context to copy (cannot be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
|
||||||
|
const secp256k1_context* ctx
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
/** Copy a secp256k1 context object into caller-provided memory.
|
||||||
|
*
|
||||||
|
* The caller must provide a pointer to a rewritable contiguous block of memory
|
||||||
|
* of size at least secp256k1_context_preallocated_size(flags) bytes, suitably
|
||||||
|
* aligned to hold an object of any type.
|
||||||
|
*
|
||||||
|
* The block of memory is exclusively owned by the created context object during
|
||||||
|
* the lifetime of this context object, see the description of
|
||||||
|
* secp256k1_context_preallocated_create for details.
|
||||||
|
*
|
||||||
|
* Returns: a newly created context object.
|
||||||
|
* Args: ctx: an existing context to copy (cannot be NULL)
|
||||||
|
* In: prealloc: a pointer to a rewritable contiguous block of memory of
|
||||||
|
* size at least secp256k1_context_preallocated_size(flags)
|
||||||
|
* bytes, as detailed above (cannot be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
void* prealloc
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
/** Destroy a secp256k1 context object that has been created in
|
||||||
|
* caller-provided memory.
|
||||||
|
*
|
||||||
|
* The context pointer may not be used afterwards.
|
||||||
|
*
|
||||||
|
* The context to destroy must have been created using
|
||||||
|
* secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone.
|
||||||
|
* If the context has instead been created using secp256k1_context_create or
|
||||||
|
* secp256k1_context_clone, the behaviour is undefined. In that case,
|
||||||
|
* secp256k1_context_destroy must be used instead.
|
||||||
|
*
|
||||||
|
* If required, it is the responsibility of the caller to deallocate the block
|
||||||
|
* of memory properly after this function returns, e.g., by calling free on the
|
||||||
|
* preallocated pointer given to secp256k1_context_preallocated_create or
|
||||||
|
* secp256k1_context_preallocated_clone.
|
||||||
|
*
|
||||||
|
* Args: ctx: an existing context to destroy, constructed using
|
||||||
|
* secp256k1_context_preallocated_create or
|
||||||
|
* secp256k1_context_preallocated_clone (cannot be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API void secp256k1_context_preallocated_destroy(
|
||||||
|
secp256k1_context* ctx
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SECP256K1_PREALLOCATED_H */
|
@ -20,10 +20,10 @@ typedef struct {
|
|||||||
#endif
|
#endif
|
||||||
} secp256k1_ecmult_context;
|
} secp256k1_ecmult_context;
|
||||||
|
|
||||||
|
static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE;
|
||||||
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx);
|
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx);
|
||||||
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb);
|
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void **prealloc);
|
||||||
static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,
|
static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *dst, const secp256k1_ecmult_context *src);
|
||||||
const secp256k1_ecmult_context *src, const secp256k1_callback *cb);
|
|
||||||
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx);
|
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx);
|
||||||
static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx);
|
static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx);
|
||||||
|
|
||||||
|
@ -28,10 +28,10 @@ typedef struct {
|
|||||||
secp256k1_gej initial;
|
secp256k1_gej initial;
|
||||||
} secp256k1_ecmult_gen_context;
|
} secp256k1_ecmult_gen_context;
|
||||||
|
|
||||||
|
static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
|
||||||
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx);
|
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx);
|
||||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb);
|
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, void **prealloc);
|
||||||
static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
|
static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context* src);
|
||||||
const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb);
|
|
||||||
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);
|
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);
|
||||||
static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx);
|
static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx);
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#ifndef SECP256K1_ECMULT_GEN_IMPL_H
|
#ifndef SECP256K1_ECMULT_GEN_IMPL_H
|
||||||
#define SECP256K1_ECMULT_GEN_IMPL_H
|
#define SECP256K1_ECMULT_GEN_IMPL_H
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
#include "scalar.h"
|
#include "scalar.h"
|
||||||
#include "group.h"
|
#include "group.h"
|
||||||
#include "ecmult_gen.h"
|
#include "ecmult_gen.h"
|
||||||
@ -14,23 +15,32 @@
|
|||||||
#ifdef USE_ECMULT_STATIC_PRECOMPUTATION
|
#ifdef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
#include "ecmult_static_context.h"
|
#include "ecmult_static_context.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
|
static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = ROUND_TO_ALIGN(sizeof(*((secp256k1_ecmult_gen_context*) NULL)->prec));
|
||||||
|
#else
|
||||||
|
static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) {
|
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) {
|
||||||
ctx->prec = NULL;
|
ctx->prec = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) {
|
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, void **prealloc) {
|
||||||
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
secp256k1_ge prec[1024];
|
secp256k1_ge prec[1024];
|
||||||
secp256k1_gej gj;
|
secp256k1_gej gj;
|
||||||
secp256k1_gej nums_gej;
|
secp256k1_gej nums_gej;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
size_t const prealloc_size = SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
|
||||||
|
void* const base = *prealloc;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ctx->prec != NULL) {
|
if (ctx->prec != NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec));
|
ctx->prec = (secp256k1_ge_storage (*)[64][16])manual_alloc(prealloc, prealloc_size, base, prealloc_size);
|
||||||
|
|
||||||
/* get the generator */
|
/* get the generator */
|
||||||
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
|
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
|
||||||
@ -85,7 +95,7 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void)cb;
|
(void)prealloc;
|
||||||
ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context;
|
ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context;
|
||||||
#endif
|
#endif
|
||||||
secp256k1_ecmult_gen_blind(ctx, NULL);
|
secp256k1_ecmult_gen_blind(ctx, NULL);
|
||||||
@ -95,27 +105,18 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont
|
|||||||
return ctx->prec != NULL;
|
return ctx->prec != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
|
static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context *src) {
|
||||||
const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) {
|
|
||||||
if (src->prec == NULL) {
|
|
||||||
dst->prec = NULL;
|
|
||||||
} else {
|
|
||||||
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||||
dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec));
|
if (src->prec != NULL) {
|
||||||
memcpy(dst->prec, src->prec, sizeof(*dst->prec));
|
/* We cast to void* first to suppress a -Wcast-align warning. */
|
||||||
#else
|
dst->prec = (secp256k1_ge_storage (*)[64][16])(void*)((unsigned char*)dst + ((unsigned char*)src->prec - (unsigned char*)src));
|
||||||
(void)cb;
|
|
||||||
dst->prec = src->prec;
|
|
||||||
#endif
|
|
||||||
dst->initial = src->initial;
|
|
||||||
dst->blind = src->blind;
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
(void)dst, (void)src;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
|
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
|
||||||
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
|
||||||
free(ctx->prec);
|
|
||||||
#endif
|
|
||||||
secp256k1_scalar_clear(&ctx->blind);
|
secp256k1_scalar_clear(&ctx->blind);
|
||||||
secp256k1_gej_clear(&ctx->initial);
|
secp256k1_gej_clear(&ctx->initial);
|
||||||
ctx->prec = NULL;
|
ctx->prec = NULL;
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
#include "group.h"
|
#include "group.h"
|
||||||
#include "scalar.h"
|
#include "scalar.h"
|
||||||
#include "ecmult.h"
|
#include "ecmult.h"
|
||||||
@ -310,6 +311,13 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
|
|||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE =
|
||||||
|
ROUND_TO_ALIGN(sizeof((*((secp256k1_ecmult_context*) NULL)->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G))
|
||||||
|
#ifdef USE_ENDOMORPHISM
|
||||||
|
+ ROUND_TO_ALIGN(sizeof((*((secp256k1_ecmult_context*) NULL)->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G))
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) {
|
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) {
|
||||||
ctx->pre_g = NULL;
|
ctx->pre_g = NULL;
|
||||||
#ifdef USE_ENDOMORPHISM
|
#ifdef USE_ENDOMORPHISM
|
||||||
@ -317,8 +325,10 @@ static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) {
|
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void **prealloc) {
|
||||||
secp256k1_gej gj;
|
secp256k1_gej gj;
|
||||||
|
void* const base = *prealloc;
|
||||||
|
size_t const prealloc_size = SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE;
|
||||||
|
|
||||||
if (ctx->pre_g != NULL) {
|
if (ctx->pre_g != NULL) {
|
||||||
return;
|
return;
|
||||||
@ -331,7 +341,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
|
|||||||
size_t size = sizeof((*ctx->pre_g)[0]) * ((size_t)ECMULT_TABLE_SIZE(WINDOW_G));
|
size_t size = sizeof((*ctx->pre_g)[0]) * ((size_t)ECMULT_TABLE_SIZE(WINDOW_G));
|
||||||
/* check for overflow */
|
/* check for overflow */
|
||||||
VERIFY_CHECK(size / sizeof((*ctx->pre_g)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)));
|
VERIFY_CHECK(size / sizeof((*ctx->pre_g)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)));
|
||||||
ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
|
ctx->pre_g = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G), base, prealloc_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* precompute the tables with odd multiples */
|
/* precompute the tables with odd multiples */
|
||||||
@ -345,7 +355,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
|
|||||||
size_t size = sizeof((*ctx->pre_g_128)[0]) * ((size_t) ECMULT_TABLE_SIZE(WINDOW_G));
|
size_t size = sizeof((*ctx->pre_g_128)[0]) * ((size_t) ECMULT_TABLE_SIZE(WINDOW_G));
|
||||||
/* check for overflow */
|
/* check for overflow */
|
||||||
VERIFY_CHECK(size / sizeof((*ctx->pre_g_128)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)));
|
VERIFY_CHECK(size / sizeof((*ctx->pre_g_128)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)));
|
||||||
ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
|
ctx->pre_g_128 = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G), base, prealloc_size);
|
||||||
|
|
||||||
/* calculate 2^128*generator */
|
/* calculate 2^128*generator */
|
||||||
g_128j = gj;
|
g_128j = gj;
|
||||||
@ -357,22 +367,14 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,
|
static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *dst, const secp256k1_ecmult_context *src) {
|
||||||
const secp256k1_ecmult_context *src, const secp256k1_callback *cb) {
|
if (src->pre_g != NULL) {
|
||||||
if (src->pre_g == NULL) {
|
/* We cast to void* first to suppress a -Wcast-align warning. */
|
||||||
dst->pre_g = NULL;
|
dst->pre_g = (secp256k1_ge_storage (*)[])(void*)((unsigned char*)dst + ((unsigned char*)(src->pre_g) - (unsigned char*)src));
|
||||||
} else {
|
|
||||||
size_t size = sizeof((*dst->pre_g)[0]) * ((size_t)ECMULT_TABLE_SIZE(WINDOW_G));
|
|
||||||
dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
|
|
||||||
memcpy(dst->pre_g, src->pre_g, size);
|
|
||||||
}
|
}
|
||||||
#ifdef USE_ENDOMORPHISM
|
#ifdef USE_ENDOMORPHISM
|
||||||
if (src->pre_g_128 == NULL) {
|
if (src->pre_g_128 != NULL) {
|
||||||
dst->pre_g_128 = NULL;
|
dst->pre_g_128 = (secp256k1_ge_storage (*)[])(void*)((unsigned char*)dst + ((unsigned char*)(src->pre_g_128) - (unsigned char*)src));
|
||||||
} else {
|
|
||||||
size_t size = sizeof((*dst->pre_g_128)[0]) * ((size_t)ECMULT_TABLE_SIZE(WINDOW_G));
|
|
||||||
dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
|
|
||||||
memcpy(dst->pre_g_128, src->pre_g_128, size);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -382,10 +384,6 @@ static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) {
|
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) {
|
||||||
free(ctx->pre_g);
|
|
||||||
#ifdef USE_ENDOMORPHISM
|
|
||||||
free(ctx->pre_g_128);
|
|
||||||
#endif
|
|
||||||
secp256k1_ecmult_context_init(ctx);
|
secp256k1_ecmult_context_init(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,7 +440,7 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
|||||||
CHECK(carry == 0);
|
CHECK(carry == 0);
|
||||||
while (bit < 256) {
|
while (bit < 256) {
|
||||||
CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0);
|
CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return last_set_bit + 1;
|
return last_set_bit + 1;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "basic-config.h"
|
#include "basic-config.h"
|
||||||
#include "include/secp256k1.h"
|
#include "include/secp256k1.h"
|
||||||
|
#include "util.h"
|
||||||
#include "field_impl.h"
|
#include "field_impl.h"
|
||||||
#include "scalar_impl.h"
|
#include "scalar_impl.h"
|
||||||
#include "group_impl.h"
|
#include "group_impl.h"
|
||||||
@ -26,6 +27,7 @@ static const secp256k1_callback default_error_callback = {
|
|||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
secp256k1_ecmult_gen_context ctx;
|
secp256k1_ecmult_gen_context ctx;
|
||||||
|
void *prealloc, *base;
|
||||||
int inner;
|
int inner;
|
||||||
int outer;
|
int outer;
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
@ -38,15 +40,17 @@ int main(int argc, char **argv) {
|
|||||||
fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n");
|
fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
|
fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
|
||||||
fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
|
fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
|
||||||
fprintf(fp, "#include \"src/group.h\"\n");
|
fprintf(fp, "#include \"src/group.h\"\n");
|
||||||
fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n");
|
fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n");
|
||||||
fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n");
|
fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n");
|
||||||
|
|
||||||
|
base = checked_malloc(&default_error_callback, SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE);
|
||||||
|
prealloc = base;
|
||||||
secp256k1_ecmult_gen_context_init(&ctx);
|
secp256k1_ecmult_gen_context_init(&ctx);
|
||||||
secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback);
|
secp256k1_ecmult_gen_context_build(&ctx, &prealloc);
|
||||||
for(outer = 0; outer != 64; outer++) {
|
for(outer = 0; outer != 64; outer++) {
|
||||||
fprintf(fp,"{\n");
|
fprintf(fp,"{\n");
|
||||||
for(inner = 0; inner != 16; inner++) {
|
for(inner = 0; inner != 16; inner++) {
|
||||||
@ -65,10 +69,11 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
fprintf(fp,"};\n");
|
fprintf(fp,"};\n");
|
||||||
secp256k1_ecmult_gen_context_clear(&ctx);
|
secp256k1_ecmult_gen_context_clear(&ctx);
|
||||||
|
free(base);
|
||||||
|
|
||||||
fprintf(fp, "#undef SC\n");
|
fprintf(fp, "#undef SC\n");
|
||||||
fprintf(fp, "#endif\n");
|
fprintf(fp, "#endif\n");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,9 @@
|
|||||||
#ifndef _SECP256K1_SCRATCH_IMPL_H_
|
#ifndef _SECP256K1_SCRATCH_IMPL_H_
|
||||||
#define _SECP256K1_SCRATCH_IMPL_H_
|
#define _SECP256K1_SCRATCH_IMPL_H_
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
#include "scratch.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 max_size) {
|
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size) {
|
||||||
secp256k1_scratch* ret = (secp256k1_scratch*)checked_malloc(error_callback, sizeof(*ret));
|
secp256k1_scratch* ret = (secp256k1_scratch*)checked_malloc(error_callback, sizeof(*ret));
|
||||||
if (ret != NULL) {
|
if (ret != NULL) {
|
||||||
@ -71,7 +66,7 @@ static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch) {
|
|||||||
static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t size) {
|
static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t size) {
|
||||||
void *ret;
|
void *ret;
|
||||||
size_t frame = scratch->frame - 1;
|
size_t frame = scratch->frame - 1;
|
||||||
size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
|
size = ROUND_TO_ALIGN(size);
|
||||||
|
|
||||||
if (scratch->frame == 0 || size + scratch->offset[frame] > scratch->frame_size[frame]) {
|
if (scratch->frame == 0 || size + scratch->offset[frame] > scratch->frame_size[frame]) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
#include "include/secp256k1.h"
|
#include "include/secp256k1.h"
|
||||||
|
#include "include/secp256k1_preallocated.h"
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "num_impl.h"
|
#include "num_impl.h"
|
||||||
@ -64,15 +65,50 @@ static const secp256k1_context secp256k1_context_no_precomp_ = {
|
|||||||
};
|
};
|
||||||
const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_;
|
const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_;
|
||||||
|
|
||||||
secp256k1_context* secp256k1_context_create(unsigned int flags) {
|
size_t secp256k1_context_preallocated_size(unsigned int flags) {
|
||||||
secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context));
|
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->illegal_callback = default_illegal_callback;
|
||||||
ret->error_callback = default_error_callback;
|
ret->error_callback = default_error_callback;
|
||||||
|
|
||||||
if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) {
|
if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) {
|
||||||
secp256k1_callback_call(&ret->illegal_callback,
|
secp256k1_callback_call(&ret->illegal_callback,
|
||||||
"Invalid flags");
|
"Invalid flags");
|
||||||
free(ret);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,30 +116,62 @@ secp256k1_context* secp256k1_context_create(unsigned int flags) {
|
|||||||
secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx);
|
secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx);
|
||||||
|
|
||||||
if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) {
|
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) {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
|
secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
|
||||||
secp256k1_context* ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context));
|
secp256k1_context* ret;
|
||||||
ret->illegal_callback = ctx->illegal_callback;
|
size_t prealloc_size;
|
||||||
ret->error_callback = ctx->error_callback;
|
|
||||||
secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback);
|
VERIFY_CHECK(ctx != NULL);
|
||||||
secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void secp256k1_context_destroy(secp256k1_context* ctx) {
|
void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
|
||||||
CHECK(ctx != secp256k1_context_no_precomp);
|
CHECK(ctx != secp256k1_context_no_precomp);
|
||||||
if (ctx != NULL) {
|
if (ctx != NULL) {
|
||||||
secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
|
secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
|
||||||
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_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);
|
free(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
114
src/tests.c
114
src/tests.c
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "secp256k1.c"
|
#include "secp256k1.c"
|
||||||
#include "include/secp256k1.h"
|
#include "include/secp256k1.h"
|
||||||
|
#include "include/secp256k1_preallocated.h"
|
||||||
#include "testrand_impl.h"
|
#include "testrand_impl.h"
|
||||||
|
|
||||||
#ifdef ENABLE_OPENSSL_TESTS
|
#ifdef ENABLE_OPENSSL_TESTS
|
||||||
@ -137,23 +138,47 @@ void random_scalar_order(secp256k1_scalar *num) {
|
|||||||
} while(1);
|
} while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_context_tests(void) {
|
void run_context_tests(int use_prealloc) {
|
||||||
secp256k1_pubkey pubkey;
|
secp256k1_pubkey pubkey;
|
||||||
secp256k1_pubkey zero_pubkey;
|
secp256k1_pubkey zero_pubkey;
|
||||||
secp256k1_ecdsa_signature sig;
|
secp256k1_ecdsa_signature sig;
|
||||||
unsigned char ctmp[32];
|
unsigned char ctmp[32];
|
||||||
int32_t ecount;
|
int32_t ecount;
|
||||||
int32_t ecount2;
|
int32_t ecount2;
|
||||||
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
secp256k1_context *none;
|
||||||
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
secp256k1_context *sign;
|
||||||
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
secp256k1_context *vrfy;
|
||||||
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
secp256k1_context *both;
|
||||||
|
void *none_prealloc = NULL;
|
||||||
|
void *sign_prealloc = NULL;
|
||||||
|
void *vrfy_prealloc = NULL;
|
||||||
|
void *both_prealloc = NULL;
|
||||||
|
|
||||||
secp256k1_gej pubj;
|
secp256k1_gej pubj;
|
||||||
secp256k1_ge pub;
|
secp256k1_ge pub;
|
||||||
secp256k1_scalar msg, key, nonce;
|
secp256k1_scalar msg, key, nonce;
|
||||||
secp256k1_scalar sigr, sigs;
|
secp256k1_scalar sigr, sigs;
|
||||||
|
|
||||||
|
if (use_prealloc) {
|
||||||
|
none_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
|
||||||
|
sign_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN));
|
||||||
|
vrfy_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY));
|
||||||
|
both_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY));
|
||||||
|
CHECK(none_prealloc != NULL);
|
||||||
|
CHECK(sign_prealloc != NULL);
|
||||||
|
CHECK(vrfy_prealloc != NULL);
|
||||||
|
CHECK(both_prealloc != NULL);
|
||||||
|
none = secp256k1_context_preallocated_create(none_prealloc, SECP256K1_CONTEXT_NONE);
|
||||||
|
sign = secp256k1_context_preallocated_create(sign_prealloc, SECP256K1_CONTEXT_SIGN);
|
||||||
|
vrfy = secp256k1_context_preallocated_create(vrfy_prealloc, SECP256K1_CONTEXT_VERIFY);
|
||||||
|
both = secp256k1_context_preallocated_create(both_prealloc, SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||||
|
} else {
|
||||||
|
none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||||
|
sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||||
|
vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||||
|
both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&zero_pubkey, 0, sizeof(zero_pubkey));
|
memset(&zero_pubkey, 0, sizeof(zero_pubkey));
|
||||||
|
|
||||||
ecount = 0;
|
ecount = 0;
|
||||||
@ -163,14 +188,57 @@ void run_context_tests(void) {
|
|||||||
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL);
|
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL);
|
||||||
CHECK(vrfy->error_callback.fn != sign->error_callback.fn);
|
CHECK(vrfy->error_callback.fn != sign->error_callback.fn);
|
||||||
|
|
||||||
|
/* check if sizes for cloning are consistent */
|
||||||
|
CHECK(secp256k1_context_preallocated_clone_size(none) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
|
||||||
|
CHECK(secp256k1_context_preallocated_clone_size(sign) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN));
|
||||||
|
CHECK(secp256k1_context_preallocated_clone_size(vrfy) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY));
|
||||||
|
CHECK(secp256k1_context_preallocated_clone_size(both) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY));
|
||||||
|
|
||||||
/*** clone and destroy all of them to make sure cloning was complete ***/
|
/*** clone and destroy all of them to make sure cloning was complete ***/
|
||||||
{
|
{
|
||||||
secp256k1_context *ctx_tmp;
|
secp256k1_context *ctx_tmp;
|
||||||
|
|
||||||
ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp);
|
if (use_prealloc) {
|
||||||
ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp);
|
/* clone into a non-preallocated context and then again into a new preallocated one. */
|
||||||
ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_destroy(ctx_tmp);
|
ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_preallocated_destroy(ctx_tmp);
|
||||||
ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp);
|
free(none_prealloc); none_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(none_prealloc != NULL);
|
||||||
|
ctx_tmp = none; none = secp256k1_context_preallocated_clone(none, none_prealloc); secp256k1_context_destroy(ctx_tmp);
|
||||||
|
|
||||||
|
ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_preallocated_destroy(ctx_tmp);
|
||||||
|
free(sign_prealloc); sign_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(sign_prealloc != NULL);
|
||||||
|
ctx_tmp = sign; sign = secp256k1_context_preallocated_clone(sign, sign_prealloc); secp256k1_context_destroy(ctx_tmp);
|
||||||
|
|
||||||
|
ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_preallocated_destroy(ctx_tmp);
|
||||||
|
free(vrfy_prealloc); vrfy_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(vrfy_prealloc != NULL);
|
||||||
|
ctx_tmp = vrfy; vrfy = secp256k1_context_preallocated_clone(vrfy, vrfy_prealloc); secp256k1_context_destroy(ctx_tmp);
|
||||||
|
|
||||||
|
ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_preallocated_destroy(ctx_tmp);
|
||||||
|
free(both_prealloc); both_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(both_prealloc != NULL);
|
||||||
|
ctx_tmp = both; both = secp256k1_context_preallocated_clone(both, both_prealloc); secp256k1_context_destroy(ctx_tmp);
|
||||||
|
} else {
|
||||||
|
/* clone into a preallocated context and then again into a new non-preallocated one. */
|
||||||
|
void *prealloc_tmp;
|
||||||
|
|
||||||
|
prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(prealloc_tmp != NULL);
|
||||||
|
ctx_tmp = none; none = secp256k1_context_preallocated_clone(none, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
|
||||||
|
ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_preallocated_destroy(ctx_tmp);
|
||||||
|
free(prealloc_tmp);
|
||||||
|
|
||||||
|
prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(prealloc_tmp != NULL);
|
||||||
|
ctx_tmp = sign; sign = secp256k1_context_preallocated_clone(sign, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
|
||||||
|
ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_preallocated_destroy(ctx_tmp);
|
||||||
|
free(prealloc_tmp);
|
||||||
|
|
||||||
|
prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL);
|
||||||
|
ctx_tmp = vrfy; vrfy = secp256k1_context_preallocated_clone(vrfy, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
|
||||||
|
ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_preallocated_destroy(ctx_tmp);
|
||||||
|
free(prealloc_tmp);
|
||||||
|
|
||||||
|
prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL);
|
||||||
|
ctx_tmp = both; both = secp256k1_context_preallocated_clone(both, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
|
||||||
|
ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_preallocated_destroy(ctx_tmp);
|
||||||
|
free(prealloc_tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify that the error callback makes it across the clone. */
|
/* Verify that the error callback makes it across the clone. */
|
||||||
@ -229,10 +297,6 @@ void run_context_tests(void) {
|
|||||||
secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);
|
secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);
|
||||||
secp256k1_context_set_illegal_callback(sign, NULL, NULL);
|
secp256k1_context_set_illegal_callback(sign, NULL, NULL);
|
||||||
|
|
||||||
/* This shouldn't leak memory, due to already-set tests. */
|
|
||||||
secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL);
|
|
||||||
secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL);
|
|
||||||
|
|
||||||
/* obtain a working nonce */
|
/* obtain a working nonce */
|
||||||
do {
|
do {
|
||||||
random_scalar_order_test(&nonce);
|
random_scalar_order_test(&nonce);
|
||||||
@ -247,12 +311,25 @@ void run_context_tests(void) {
|
|||||||
CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg));
|
CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg));
|
||||||
|
|
||||||
/* cleanup */
|
/* cleanup */
|
||||||
secp256k1_context_destroy(none);
|
if (use_prealloc) {
|
||||||
secp256k1_context_destroy(sign);
|
secp256k1_context_preallocated_destroy(none);
|
||||||
secp256k1_context_destroy(vrfy);
|
secp256k1_context_preallocated_destroy(sign);
|
||||||
secp256k1_context_destroy(both);
|
secp256k1_context_preallocated_destroy(vrfy);
|
||||||
|
secp256k1_context_preallocated_destroy(both);
|
||||||
|
free(none_prealloc);
|
||||||
|
free(sign_prealloc);
|
||||||
|
free(vrfy_prealloc);
|
||||||
|
free(both_prealloc);
|
||||||
|
} else {
|
||||||
|
secp256k1_context_destroy(none);
|
||||||
|
secp256k1_context_destroy(sign);
|
||||||
|
secp256k1_context_destroy(vrfy);
|
||||||
|
secp256k1_context_destroy(both);
|
||||||
|
}
|
||||||
/* Defined as no-op. */
|
/* Defined as no-op. */
|
||||||
secp256k1_context_destroy(NULL);
|
secp256k1_context_destroy(NULL);
|
||||||
|
secp256k1_context_preallocated_destroy(NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_scratch_tests(void) {
|
void run_scratch_tests(void) {
|
||||||
@ -5062,7 +5139,8 @@ int main(int argc, char **argv) {
|
|||||||
printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]);
|
printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]);
|
||||||
|
|
||||||
/* initialize */
|
/* initialize */
|
||||||
run_context_tests();
|
run_context_tests(0);
|
||||||
|
run_context_tests(1);
|
||||||
run_scratch_tests();
|
run_scratch_tests();
|
||||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||||
if (secp256k1_rand_bits(1)) {
|
if (secp256k1_rand_bits(1)) {
|
||||||
|
41
src/util.h
41
src/util.h
@ -84,6 +84,47 @@ static SECP256K1_INLINE void *checked_realloc(const secp256k1_callback* cb, void
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__BIGGEST_ALIGNMENT__)
|
||||||
|
#define ALIGNMENT __BIGGEST_ALIGNMENT__
|
||||||
|
#else
|
||||||
|
/* 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. */
|
||||||
|
#define ALIGNMENT 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ROUND_TO_ALIGN(size) (((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT)
|
||||||
|
|
||||||
|
/* Assume there is a contiguous memory object with bounds [base, base + max_size)
|
||||||
|
* of which the memory range [base, *prealloc_ptr) is already allocated for usage,
|
||||||
|
* where *prealloc_ptr is an aligned pointer. In that setting, this functions
|
||||||
|
* reserves the subobject [*prealloc_ptr, *prealloc_ptr + alloc_size) of
|
||||||
|
* alloc_size bytes by increasing *prealloc_ptr accordingly, taking into account
|
||||||
|
* alignment requirements.
|
||||||
|
*
|
||||||
|
* The function returns an aligned pointer to the newly allocated subobject.
|
||||||
|
*
|
||||||
|
* This is useful for manual memory management: if we're simply given a block
|
||||||
|
* [base, base + max_size), the caller can use this function to allocate memory
|
||||||
|
* in this block and keep track of the current allocation state with *prealloc_ptr.
|
||||||
|
*
|
||||||
|
* It is VERIFY_CHECKed that there is enough space left in the memory object and
|
||||||
|
* *prealloc_ptr is aligned relative to base.
|
||||||
|
*/
|
||||||
|
static SECP256K1_INLINE void *manual_alloc(void** prealloc_ptr, size_t alloc_size, void* base, size_t max_size) {
|
||||||
|
size_t aligned_alloc_size = ROUND_TO_ALIGN(alloc_size);
|
||||||
|
void* ret;
|
||||||
|
VERIFY_CHECK(prealloc_ptr != NULL);
|
||||||
|
VERIFY_CHECK(*prealloc_ptr != NULL);
|
||||||
|
VERIFY_CHECK(base != NULL);
|
||||||
|
VERIFY_CHECK((unsigned char*)*prealloc_ptr >= (unsigned char*)base);
|
||||||
|
VERIFY_CHECK(((unsigned char*)*prealloc_ptr - (unsigned char*)base) % ALIGNMENT == 0);
|
||||||
|
VERIFY_CHECK((unsigned char*)*prealloc_ptr - (unsigned char*)base + aligned_alloc_size <= max_size);
|
||||||
|
ret = *prealloc_ptr;
|
||||||
|
*((unsigned char**)prealloc_ptr) += aligned_alloc_size;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Macro for restrict, when available and not in a VERIFY build. */
|
/* Macro for restrict, when available and not in a VERIFY build. */
|
||||||
#if defined(SECP256K1_BUILD) && defined(VERIFY)
|
#if defined(SECP256K1_BUILD) && defined(VERIFY)
|
||||||
# define SECP256K1_RESTRICT
|
# define SECP256K1_RESTRICT
|
||||||
|
Loading…
x
Reference in New Issue
Block a user