Merge pull request #53 from romanz/zkp-trezor

Changes necessary for usage on Trezor
This commit is contained in:
Andrew Poelstra 2019-04-12 16:42:45 +00:00 committed by GitHub
commit 1c830b4c9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 625 additions and 163 deletions

View File

@ -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

View File

@ -85,42 +85,42 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
]) ])
AC_ARG_ENABLE(benchmark, AC_ARG_ENABLE(benchmark,
AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is yes)]), AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]),
[use_benchmark=$enableval], [use_benchmark=$enableval],
[use_benchmark=yes]) [use_benchmark=yes])
AC_ARG_ENABLE(coverage, AC_ARG_ENABLE(coverage,
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]), AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]),
[enable_coverage=$enableval], [enable_coverage=$enableval],
[enable_coverage=no]) [enable_coverage=no])
AC_ARG_ENABLE(tests, AC_ARG_ENABLE(tests,
AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]),
[use_tests=$enableval], [use_tests=$enableval],
[use_tests=yes]) [use_tests=yes])
AC_ARG_ENABLE(openssl_tests, AC_ARG_ENABLE(openssl_tests,
AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]), AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests [default=auto]]),
[enable_openssl_tests=$enableval], [enable_openssl_tests=$enableval],
[enable_openssl_tests=auto]) [enable_openssl_tests=auto])
AC_ARG_ENABLE(experimental, AC_ARG_ENABLE(experimental,
AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]), AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]),
[use_experimental=$enableval], [use_experimental=$enableval],
[use_experimental=no]) [use_experimental=no])
AC_ARG_ENABLE(exhaustive_tests, AC_ARG_ENABLE(exhaustive_tests,
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]), AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]),
[use_exhaustive_tests=$enableval], [use_exhaustive_tests=$enableval],
[use_exhaustive_tests=yes]) [use_exhaustive_tests=yes])
AC_ARG_ENABLE(endomorphism, AC_ARG_ENABLE(endomorphism,
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), AS_HELP_STRING([--enable-endomorphism],[enable endomorphism [default=no]]),
[use_endomorphism=$enableval], [use_endomorphism=$enableval],
[use_endomorphism=no]) [use_endomorphism=no])
AC_ARG_ENABLE(ecmult_static_precomputation, AC_ARG_ENABLE(ecmult_static_precomputation,
AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]), AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing [default=auto]]),
[use_ecmult_static_precomputation=$enableval], [use_ecmult_static_precomputation=$enableval],
[use_ecmult_static_precomputation=auto]) [use_ecmult_static_precomputation=auto])
@ -140,46 +140,61 @@ AC_ARG_ENABLE(module_musig,
[enable_module_musig=no]) [enable_module_musig=no])
AC_ARG_ENABLE(module_recovery, AC_ARG_ENABLE(module_recovery,
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]), AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]),
[enable_module_recovery=$enableval], [enable_module_recovery=$enableval],
[enable_module_recovery=no]) [enable_module_recovery=no])
AC_ARG_ENABLE(module_generator, AC_ARG_ENABLE(module_generator,
AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module (default is no)]), AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module [default=no]]),
[enable_module_generator=$enableval], [enable_module_generator=$enableval],
[enable_module_generator=no]) [enable_module_generator=no])
AC_ARG_ENABLE(module_rangeproof, AC_ARG_ENABLE(module_rangeproof,
AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module (default is no)]), AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module [default=no]]),
[enable_module_rangeproof=$enableval], [enable_module_rangeproof=$enableval],
[enable_module_rangeproof=no]) [enable_module_rangeproof=no])
AC_ARG_ENABLE(module_whitelist, AC_ARG_ENABLE(module_whitelist,
AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module (default is no)]), AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module [default=no]]),
[enable_module_whitelist=$enableval], [enable_module_whitelist=$enableval],
[enable_module_whitelist=no]) [enable_module_whitelist=no])
AC_ARG_ENABLE(external_default_callbacks,
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]),
[use_external_default_callbacks=$enableval],
[use_external_default_callbacks=no])
AC_ARG_ENABLE(jni, AC_ARG_ENABLE(jni,
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is no)]), AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni [default=no]]),
[use_jni=$enableval], [use_jni=$enableval],
[use_jni=no]) [use_jni=no])
AC_ARG_ENABLE(module_surjectionproof, AC_ARG_ENABLE(module_surjectionproof,
AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module (default is no)]), AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module [default=no]]),
[enable_module_surjectionproof=$enableval], [enable_module_surjectionproof=$enableval],
[enable_module_surjectionproof=no]) [enable_module_surjectionproof=no])
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) [finite field implementation to use [default=auto]])],[req_field=$withval], [req_field=auto])
AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto]) [bignum implementation to use [default=auto]])],[req_bignum=$withval], [req_bignum=auto])
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) [scalar implementation to use [default=auto]])],[req_scalar=$withval], [req_scalar=auto])
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto] AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto]) [assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto])
# Default is window size 16 (or window size 15 with endomorphism) which needs 1.375 MiB. */
AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto],
[window size for ecmult precomputation for verification, specified as integer in range [3..24].]
[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.]
[The table will store 2^(SIZE-2) * 64 bytes of data but can be larger in memory due]
[to platform-specific padding and alignment. "auto" is a reasonable setting for desktop machines]
[(currently 15 if the endomorphism optimization is disabled and 16 if it is enabled). [default=auto]]
)],
[req_ecmult_window=$withval], [req_ecmult_window=auto])
AC_CHECK_TYPES([__int128]) AC_CHECK_TYPES([__int128])
@ -408,6 +423,32 @@ case $set_scalar in
;; ;;
esac esac
#set ecmult window size
if test x"$req_ecmult_window" = x"auto"; then
if test x"$use_endomorphism" = x"yes"; then
set_ecmult_window=16
else
set_ecmult_window=15
fi
else
set_ecmult_window=$req_ecmult_window
fi
error_window_size=['window size for ecmult precomputation not an integer in range [3..24] or "auto"']
case $set_ecmult_window in
''|*[[!0-9]]*)
# no valid integer
AC_MSG_ERROR($error_window_size)
;;
*)
if test "$set_ecmult_window" -lt 3 -o "$set_ecmult_window" -gt 24 ; then
# not in range
AC_MSG_ERROR($error_window_size)
fi
AC_DEFINE_UNQUOTED(ECMULT_WINDOW_SIZE, $set_ecmult_window, [Set window size for ecmult precomputation])
;;
esac
if test x"$use_tests" = x"yes"; then if test x"$use_tests" = x"yes"; then
SECP_OPENSSL_CHECK SECP_OPENSSL_CHECK
if test x"$has_openssl_ec" = x"yes"; then if test x"$has_openssl_ec" = x"yes"; then
@ -507,17 +548,9 @@ if test x"$use_external_asm" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
fi fi
AC_MSG_NOTICE([Using static precomputation: $set_precomp]) if test x"$use_external_default_callbacks" = x"yes"; then
AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
AC_MSG_NOTICE([Using field implementation: $set_field]) fi
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
AC_MSG_NOTICE([Building benchmarks: $use_benchmark])
AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage])
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
AC_MSG_NOTICE([Using jni: $use_jni])
if test x"$enable_experimental" = x"yes"; then if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([******]) AC_MSG_NOTICE([******])
@ -610,3 +643,26 @@ unset PKG_CONFIG_PATH
PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP" PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
AC_OUTPUT AC_OUTPUT
echo
echo "Build Options:"
echo " with endomorphism = $use_endomorphism"
echo " with ecmult precomp = $set_precomp"
echo " with external callbacks = $use_external_default_callbacks"
echo " with jni = $use_jni"
echo " with benchmarks = $use_benchmark"
echo " with coverage = $enable_coverage"
echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo
echo " asm = $set_asm"
echo " bignum = $set_bignum"
echo " field = $set_field"
echo " scalar = $set_scalar"
echo " ecmult window size = $set_ecmult_window"
echo
echo " CC = $CC"
echo " CFLAGS = $CFLAGS"
echo " CPPFLAGS = $CPPFLAGS"
echo " LDFLAGS = $LDFLAGS"
echo

View File

@ -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
@ -229,11 +247,28 @@ SECP256K1_API void secp256k1_context_destroy(
* to cause a crash, though its return value and output arguments are * to cause a crash, though its return value and output arguments are
* undefined. * undefined.
* *
* When this function has not been called (or called with fn=NULL), then the
* default handler will be used. The library provides a default handler which
* writes the message to stderr and calls abort. This default handler can be
* replaced at link time if the preprocessor macro
* USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build
* has been configured with --enable-external-default-callbacks. Then the
* following two symbols must be provided to link against:
* - void secp256k1_default_illegal_callback_fn(const char* message, void* data);
* - void secp256k1_default_error_callback_fn(const char* message, void* data);
* The library can call these default handlers even before a proper callback data
* pointer could have been using secp256k1_context_set_illegal_callback or
* secp256k1_context_set_illegal_callback, e.g., when the creation of a context
* fails. In this case, the corresponding default handler will be called with
* the data pointer argument set to NULL.
*
* Args: ctx: an existing context object (cannot be NULL) * Args: ctx: an existing context object (cannot be NULL)
* In: fun: a pointer to a function to call when an illegal argument is * In: fun: a pointer to a function to call when an illegal argument is
* passed to the API, taking a message and an opaque pointer * passed to the API, taking a message and an opaque pointer.
* (NULL restores a default handler that calls abort). * (NULL restores the default handler.)
* data: the opaque pointer to pass to fun above. * data: the opaque pointer to pass to fun above.
*
* See also secp256k1_context_set_error_callback.
*/ */
SECP256K1_API void secp256k1_context_set_illegal_callback( SECP256K1_API void secp256k1_context_set_illegal_callback(
secp256k1_context* ctx, secp256k1_context* ctx,
@ -253,9 +288,12 @@ SECP256K1_API void secp256k1_context_set_illegal_callback(
* *
* Args: ctx: an existing context object (cannot be NULL) * Args: ctx: an existing context object (cannot be NULL)
* In: fun: a pointer to a function to call when an internal error occurs, * In: fun: a pointer to a function to call when an internal error occurs,
* taking a message and an opaque pointer (NULL restores a default * taking a message and an opaque pointer (NULL restores the
* handler that calls abort). * default handler, see secp256k1_context_set_illegal_callback
* for details).
* data: the opaque pointer to pass to fun above. * data: the opaque pointer to pass to fun above.
*
* See also secp256k1_context_set_illegal_callback.
*/ */
SECP256K1_API void secp256k1_context_set_error_callback( SECP256K1_API void secp256k1_context_set_error_callback(
secp256k1_context* ctx, secp256k1_context* ctx,
@ -615,7 +653,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Updates the context randomization to protect against side-channel leakage. /** Updates the context randomization to protect against side-channel leakage.
* Returns: 1: randomization successfully updated * Returns: 1: randomization successfully updated or nothing to randomize
* 0: error * 0: error
* Args: ctx: pointer to a context object (cannot be NULL) * Args: ctx: pointer to a context object (cannot be NULL)
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
@ -630,8 +668,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
* that it does not affect function results, but shields against attacks which * that it does not affect function results, but shields against attacks which
* rely on any input-dependent behaviour. * rely on any input-dependent behaviour.
* *
* This function has currently an effect only on contexts initialized for signing
* because randomization is currently used only for signing. However, this is not
* guaranteed and may change in the future. It is safe to call this function on
* 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,

View 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 */

View File

@ -10,7 +10,10 @@
#ifdef USE_BASIC_CONFIG #ifdef USE_BASIC_CONFIG
#undef USE_ASM_X86_64 #undef USE_ASM_X86_64
#undef USE_ECMULT_STATIC_PRECOMPUTATION
#undef USE_ENDOMORPHISM #undef USE_ENDOMORPHISM
#undef USE_EXTERNAL_ASM
#undef USE_EXTERNAL_DEFAULT_CALLBACKS
#undef USE_FIELD_10X26 #undef USE_FIELD_10X26
#undef USE_FIELD_5X52 #undef USE_FIELD_5X52
#undef USE_FIELD_INV_BUILTIN #undef USE_FIELD_INV_BUILTIN

View File

@ -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);

View File

@ -61,6 +61,10 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size)
int bit; int bit;
secp256k1_scalar neg_s; secp256k1_scalar neg_s;
int not_neg_one; int not_neg_one;
VERIFY_CHECK(w > 0);
VERIFY_CHECK(size > 0);
/* Note that we cannot handle even numbers by negating them to be odd, as is /* Note that we cannot handle even numbers by negating them to be odd, as is
* done in other implementations, since if our scalars were specified to have * done in other implementations, since if our scalars were specified to have
* width < 256 for performance reasons, their negations would have width 256 * width < 256 for performance reasons, their negations would have width 256
@ -93,7 +97,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size)
/* 4 */ /* 4 */
u_last = secp256k1_scalar_shr_int(&s, w); u_last = secp256k1_scalar_shr_int(&s, w);
while (word * w < size) { do {
int sign; int sign;
int even; int even;
@ -109,7 +113,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size)
wnaf[word++] = u_last * global_sign; wnaf[word++] = u_last * global_sign;
u_last = u; u_last = u;
} } while (word * w < size);
wnaf[word] = u * global_sign; wnaf[word] = u * global_sign;
VERIFY_CHECK(secp256k1_scalar_is_zero(&s)); VERIFY_CHECK(secp256k1_scalar_is_zero(&s));

View File

@ -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);

View File

@ -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 in clang. */
#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;

View File

@ -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"
@ -30,16 +31,34 @@
# endif # endif
#else #else
/* optimal for 128-bit and 256-bit exponents. */ /* optimal for 128-bit and 256-bit exponents. */
#define WINDOW_A 5 # define WINDOW_A 5
/** larger numbers may result in slightly better performance, at the cost of /** Larger values for ECMULT_WINDOW_SIZE result in possibly better
exponentially larger precomputed tables. */ * performance at the cost of an exponentially larger precomputed
#ifdef USE_ENDOMORPHISM * table. The exact table size is
/** Two tables for window size 15: 1.375 MiB. */ * (1 << (WINDOW_G - 2)) * sizeof(secp256k1_ge_storage) bytes,
#define WINDOW_G 15 * where sizeof(secp256k1_ge_storage) is typically 64 bytes but can
#else * be larger due to platform-specific padding and alignment.
/** One table for window size 16: 1.375 MiB. */ */
#define WINDOW_G 16 # ifdef USE_ENDOMORPHISM
# define WINDOW_G ((ECMULT_WINDOW_SIZE)-1)
# else
# define WINDOW_G (ECMULT_WINDOW_SIZE)
# endif
#endif #endif
/* Noone will ever need more than a window size of 24. The code might
* be correct for larger values of ECMULT_WINDOW_SIZE but this is not
* not tested.
*
* The following limitations are known, and there are probably more:
* If WINDOW_G > 27 and size_t has 32 bits, then the code is incorrect
* because the size of the memory object that we allocate (in bytes)
* will not fit in a size_t.
* If WINDOW_G > 31 and int has 32 bits, then the code is incorrect
* because certain expressions will overflow.
* */
#if ECMULT_WINDOW_SIZE < 3 || ECMULT_WINDOW_SIZE > 24
# error Set ECMULT_WINDOW_SIZE to an integer in range [3..24].
#endif #endif
#ifdef USE_ENDOMORPHISM #ifdef USE_ENDOMORPHISM
@ -293,6 +312,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
@ -300,8 +326,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;
@ -310,7 +338,12 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
/* get the generator */ /* get the generator */
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); {
size_t size = sizeof((*ctx->pre_g)[0]) * ((size_t)ECMULT_TABLE_SIZE(WINDOW_G));
/* check for overflow */
VERIFY_CHECK(size / sizeof((*ctx->pre_g)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)));
ctx->pre_g = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, size, base, prealloc_size);
}
/* precompute the tables with odd multiples */ /* precompute the tables with odd multiples */
secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj); secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj);
@ -320,7 +353,10 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
secp256k1_gej g_128j; secp256k1_gej g_128j;
int i; int i;
ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); size_t size = sizeof((*ctx->pre_g_128)[0]) * ((size_t) ECMULT_TABLE_SIZE(WINDOW_G));
/* check for overflow */
VERIFY_CHECK(size / sizeof((*ctx->pre_g_128)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)));
ctx->pre_g_128 = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, size, base, prealloc_size);
/* calculate 2^128*generator */ /* calculate 2^128*generator */
g_128j = gj; g_128j = gj;
@ -332,22 +368,13 @@ 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) { dst->pre_g = (secp256k1_ge_storage (*)[])((unsigned char*)dst + ((unsigned char*)(src->pre_g) - (unsigned char*)src));
dst->pre_g = NULL;
} else {
size_t size = sizeof((*dst->pre_g)[0]) * 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 (*)[])((unsigned char*)dst + ((unsigned char*)(src->pre_g_128) - (unsigned char*)src));
} else {
size_t size = sizeof((*dst->pre_g_128)[0]) * 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
} }
@ -357,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);
} }

View File

@ -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;
@ -45,8 +47,10 @@ int main(int argc, char **argv) {
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,6 +69,7 @@ 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");

View File

@ -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;

View File

@ -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"
@ -36,28 +37,39 @@
} \ } \
} while(0) } while(0)
static void default_illegal_callback_fn(const char* str, void* data) { #define ARG_CHECK_NO_RETURN(cond) do { \
if (EXPECT(!(cond), 0)) { \
secp256k1_callback_call(&ctx->illegal_callback, #cond); \
} \
} while(0)
#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS
#include <stdlib.h>
#include <stdio.h>
static void secp256k1_default_illegal_callback_fn(const char* str, void* data) {
(void)data; (void)data;
fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str);
abort(); abort();
} }
static void secp256k1_default_error_callback_fn(const char* str, void* data) {
static const secp256k1_callback default_illegal_callback = {
default_illegal_callback_fn,
NULL
};
static void default_error_callback_fn(const char* str, void* data) {
(void)data; (void)data;
fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str);
abort(); abort();
} }
#else
void secp256k1_default_illegal_callback_fn(const char* str, void* data);
void secp256k1_default_error_callback_fn(const char* str, void* data);
#endif
static const secp256k1_callback default_error_callback = { static const secp256k1_callback default_illegal_callback = {
default_error_callback_fn, secp256k1_default_illegal_callback_fn,
NULL NULL
}; };
static const secp256k1_callback default_error_callback = {
secp256k1_default_error_callback_fn,
NULL
};
struct secp256k1_context_struct { struct secp256k1_context_struct {
secp256k1_ecmult_context ecmult_ctx; secp256k1_ecmult_context ecmult_ctx;
@ -69,20 +81,55 @@ struct secp256k1_context_struct {
static const secp256k1_context secp256k1_context_no_precomp_ = { static const secp256k1_context secp256k1_context_no_precomp_ = {
{ 0 }, { 0 },
{ 0 }, { 0 },
{ default_illegal_callback_fn, 0 }, { secp256k1_default_illegal_callback_fn, 0 },
{ default_error_callback_fn, 0 } { secp256k1_default_error_callback_fn, 0 }
}; };
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;
} }
@ -90,47 +137,79 @@ 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); ARG_CHECK_NO_RETURN(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);
} }
} }
void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
CHECK(ctx != secp256k1_context_no_precomp); ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
if (fun == NULL) { if (fun == NULL) {
fun = default_illegal_callback_fn; fun = secp256k1_default_illegal_callback_fn;
} }
ctx->illegal_callback.fn = fun; ctx->illegal_callback.fn = fun;
ctx->illegal_callback.data = data; ctx->illegal_callback.data = data;
} }
void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
CHECK(ctx != secp256k1_context_no_precomp); ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
if (fun == NULL) { if (fun == NULL) {
fun = default_error_callback_fn; fun = secp256k1_default_error_callback_fn;
} }
ctx->error_callback.fn = fun; ctx->error_callback.fn = fun;
ctx->error_callback.data = data; ctx->error_callback.data = data;
@ -601,9 +680,9 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey
int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {
VERIFY_CHECK(ctx != NULL); VERIFY_CHECK(ctx != NULL);
CHECK(ctx != secp256k1_context_no_precomp); if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) {
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); }
return 1; return 1;
} }

View File

@ -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
@ -183,23 +184,47 @@ void run_util_tests(void) {
} }
} }
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;
@ -209,14 +234,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. */
@ -264,17 +332,17 @@ void run_context_tests(void) {
CHECK(ecount == 3); CHECK(ecount == 3);
CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1); CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
CHECK(ecount == 3); CHECK(ecount == 3);
CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0); CHECK(secp256k1_context_randomize(vrfy, ctmp) == 1);
CHECK(ecount == 4); CHECK(ecount == 3);
CHECK(secp256k1_context_randomize(vrfy, NULL) == 1);
CHECK(ecount == 3);
CHECK(secp256k1_context_randomize(sign, ctmp) == 1);
CHECK(ecount2 == 14);
CHECK(secp256k1_context_randomize(sign, NULL) == 1); CHECK(secp256k1_context_randomize(sign, NULL) == 1);
CHECK(ecount2 == 14); CHECK(ecount2 == 14);
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);
@ -289,12 +357,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) {
@ -5192,7 +5273,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)) {

View File

@ -110,6 +110,47 @@ SECP256K1_INLINE static int secp256k1_clz64_var(uint64_t x) {
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