Merge pull request #125 from elichai/manual-memory
Implement pre allocation context creation
This commit is contained in:
commit
e1aac5e008
|
@ -188,51 +188,6 @@ 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 (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.
|
|
||||||
* In: flags: which parts of the context to initialize.
|
|
||||||
*
|
|
||||||
* See also secp256k1_context_randomize.
|
|
||||||
*/
|
|
||||||
SECP256K1_API secp256k1_context* secp256k1_context_create(
|
|
||||||
unsigned int flags
|
|
||||||
) SECP256K1_WARN_UNUSED_RESULT;
|
|
||||||
|
|
||||||
/** 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.
|
|
||||||
* Args: ctx: an existing context to copy (cannot be NULL)
|
|
||||||
*/
|
|
||||||
SECP256K1_API secp256k1_context* secp256k1_context_clone(
|
|
||||||
const secp256k1_context* ctx
|
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
|
||||||
|
|
||||||
/** Destroy a secp256k1 context object (created in dynamically allocated memory).
|
|
||||||
*
|
|
||||||
* The context pointer may not be used afterwards.
|
|
||||||
*
|
|
||||||
* 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_context* ctx
|
|
||||||
);
|
|
||||||
|
|
||||||
/** Set a callback function to be called when an illegal argument is passed to
|
/** Set a callback function to be called when an illegal argument is passed to
|
||||||
* an API call. It will only trigger for violations that are mentioned
|
* an API call. It will only trigger for violations that are mentioned
|
||||||
* explicitly in the header.
|
* explicitly in the header.
|
||||||
|
@ -301,28 +256,6 @@ SECP256K1_API void secp256k1_context_set_error_callback(
|
||||||
const void* data
|
const void* data
|
||||||
) SECP256K1_ARG_NONNULL(1);
|
) SECP256K1_ARG_NONNULL(1);
|
||||||
|
|
||||||
/** Create a secp256k1 scratch space object.
|
|
||||||
*
|
|
||||||
* Returns: a newly created scratch space.
|
|
||||||
* Args: ctx: an existing context object (cannot be NULL)
|
|
||||||
* In: size: amount of memory to be available as scratch space. Some extra
|
|
||||||
* (<100 bytes) will be allocated for extra accounting.
|
|
||||||
*/
|
|
||||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_scratch_space_create(
|
|
||||||
const secp256k1_context* ctx,
|
|
||||||
size_t size
|
|
||||||
) SECP256K1_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
/** Destroy a secp256k1 scratch space.
|
|
||||||
*
|
|
||||||
* The pointer may not be used afterwards.
|
|
||||||
* Args: ctx: a secp256k1 context object.
|
|
||||||
* scratch: space to destroy
|
|
||||||
*/
|
|
||||||
SECP256K1_API void secp256k1_scratch_space_destroy(
|
|
||||||
const secp256k1_context* ctx,
|
|
||||||
secp256k1_scratch_space* scratch
|
|
||||||
) SECP256K1_ARG_NONNULL(1);
|
|
||||||
|
|
||||||
/** Parse a variable-length public key into the pubkey object.
|
/** Parse a variable-length public key into the pubkey object.
|
||||||
*
|
*
|
||||||
|
|
|
@ -21,9 +21,7 @@ typedef struct secp256k1_scratch_space_struct {
|
||||||
size_t max_size;
|
size_t max_size;
|
||||||
} secp256k1_scratch;
|
} secp256k1_scratch;
|
||||||
|
|
||||||
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size);
|
|
||||||
|
|
||||||
static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch);
|
|
||||||
|
|
||||||
/** Returns an opaque object used to "checkpoint" a scratch space. Used
|
/** Returns an opaque object used to "checkpoint" a scratch space. Used
|
||||||
* with `secp256k1_scratch_apply_checkpoint` to undo allocations. */
|
* with `secp256k1_scratch_apply_checkpoint` to undo allocations. */
|
||||||
|
|
|
@ -10,31 +10,6 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "scratch.h"
|
#include "scratch.h"
|
||||||
|
|
||||||
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) {
|
|
||||||
const size_t base_alloc = ((sizeof(secp256k1_scratch) + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
|
|
||||||
void *alloc = checked_malloc(error_callback, base_alloc + size);
|
|
||||||
secp256k1_scratch* ret = (secp256k1_scratch *)alloc;
|
|
||||||
if (ret != NULL) {
|
|
||||||
memset(ret, 0, sizeof(*ret));
|
|
||||||
memcpy(ret->magic, "scratch", 8);
|
|
||||||
ret->data = (void *) ((char *) alloc + base_alloc);
|
|
||||||
ret->max_size = size;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) {
|
|
||||||
if (scratch != NULL) {
|
|
||||||
VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */
|
|
||||||
if (memcmp(scratch->magic, "scratch", 8) != 0) {
|
|
||||||
secp256k1_callback_call(error_callback, "invalid scratch space");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memset(scratch->magic, 0, sizeof(scratch->magic));
|
|
||||||
free(scratch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch) {
|
static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch) {
|
||||||
if (memcmp(scratch->magic, "scratch", 8) != 0) {
|
if (memcmp(scratch->magic, "scratch", 8) != 0) {
|
||||||
secp256k1_callback_call(error_callback, "invalid scratch space");
|
secp256k1_callback_call(error_callback, "invalid scratch space");
|
||||||
|
|
|
@ -136,17 +136,6 @@ secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigne
|
||||||
return (secp256k1_context*) ret;
|
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) {
|
secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context* ctx, void* prealloc) {
|
||||||
size_t prealloc_size;
|
size_t prealloc_size;
|
||||||
secp256k1_context* ret;
|
secp256k1_context* ret;
|
||||||
|
@ -161,17 +150,6 @@ secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context*
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
|
|
||||||
secp256k1_context* ret;
|
|
||||||
size_t prealloc_size;
|
|
||||||
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
|
void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
|
||||||
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
|
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
|
||||||
if (ctx != NULL) {
|
if (ctx != NULL) {
|
||||||
|
@ -180,13 +158,6 @@ void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void secp256k1_context_destroy(secp256k1_context* ctx) {
|
|
||||||
if (ctx != NULL) {
|
|
||||||
secp256k1_context_preallocated_destroy(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) {
|
||||||
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
|
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
|
||||||
if (fun == NULL) {
|
if (fun == NULL) {
|
||||||
|
@ -205,16 +176,6 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co
|
||||||
ctx->error_callback.data = data;
|
ctx->error_callback.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) {
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
|
||||||
return secp256k1_scratch_create(&ctx->error_callback, max_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) {
|
|
||||||
VERIFY_CHECK(ctx != NULL);
|
|
||||||
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
|
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
|
||||||
if (sizeof(secp256k1_ge_storage) == 64) {
|
if (sizeof(secp256k1_ge_storage) == 64) {
|
||||||
/* When the secp256k1_ge_storage type is exactly 64 byte, use its
|
/* When the secp256k1_ge_storage type is exactly 64 byte, use its
|
||||||
|
|
|
@ -68,22 +68,6 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback *
|
||||||
#define VERIFY_SETUP(stmt)
|
#define VERIFY_SETUP(stmt)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) {
|
|
||||||
void *ret = malloc(size);
|
|
||||||
if (ret == NULL) {
|
|
||||||
secp256k1_callback_call(cb, "Out of memory");
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SECP256K1_INLINE void *checked_realloc(const secp256k1_callback* cb, void *ptr, size_t size) {
|
|
||||||
void *ret = realloc(ptr, size);
|
|
||||||
if (ret == NULL) {
|
|
||||||
secp256k1_callback_call(cb, "Out of memory");
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__BIGGEST_ALIGNMENT__)
|
#if defined(__BIGGEST_ALIGNMENT__)
|
||||||
#define ALIGNMENT __BIGGEST_ALIGNMENT__
|
#define ALIGNMENT __BIGGEST_ALIGNMENT__
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use ffi;
|
||||||
|
use types::{c_uint, c_void};
|
||||||
|
use Error;
|
||||||
|
use Secp256k1;
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub use self::std_only::*;
|
||||||
|
|
||||||
|
/// A trait for all kinds of Context's that Lets you define the exact flags and a function to deallocate memory.
|
||||||
|
/// * DO NOT * implement it for your own types.
|
||||||
|
pub unsafe trait Context {
|
||||||
|
/// Flags for the ffi.
|
||||||
|
const FLAGS: c_uint;
|
||||||
|
/// A constant description of the context.
|
||||||
|
const DESCRIPTION: &'static str;
|
||||||
|
/// A function to deallocate the memory when the context is dropped.
|
||||||
|
fn deallocate(ptr: *mut [u8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marker trait for indicating that an instance of `Secp256k1` can be used for signing.
|
||||||
|
pub trait Signing: Context {}
|
||||||
|
|
||||||
|
/// Marker trait for indicating that an instance of `Secp256k1` can be used for verification.
|
||||||
|
pub trait Verification: Context {}
|
||||||
|
|
||||||
|
/// Represents the set of capabilities needed for signing with a user preallocated memory.
|
||||||
|
pub struct SignOnlyPreallocated<'buf> {
|
||||||
|
phantom: PhantomData<&'buf ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the set of capabilities needed for verification with a user preallocated memory.
|
||||||
|
pub struct VerifyOnlyPreallocated<'buf> {
|
||||||
|
phantom: PhantomData<&'buf ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the set of all capabilities with a user preallocated memory.
|
||||||
|
pub struct AllPreallocated<'buf> {
|
||||||
|
phantom: PhantomData<&'buf ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
mod std_only {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Represents the set of capabilities needed for signing.
|
||||||
|
pub enum SignOnly {}
|
||||||
|
|
||||||
|
/// Represents the set of capabilities needed for verification.
|
||||||
|
pub enum VerifyOnly {}
|
||||||
|
|
||||||
|
/// Represents the set of all capabilities.
|
||||||
|
pub enum All {}
|
||||||
|
|
||||||
|
impl Signing for SignOnly {}
|
||||||
|
impl Signing for All {}
|
||||||
|
|
||||||
|
impl Verification for VerifyOnly {}
|
||||||
|
impl Verification for All {}
|
||||||
|
|
||||||
|
unsafe impl Context for SignOnly {
|
||||||
|
const FLAGS: c_uint = ffi::SECP256K1_START_SIGN;
|
||||||
|
const DESCRIPTION: &'static str = "signing only";
|
||||||
|
|
||||||
|
fn deallocate(ptr: *mut [u8]) {
|
||||||
|
let _ = unsafe { Box::from_raw(ptr) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Context for VerifyOnly {
|
||||||
|
const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY;
|
||||||
|
const DESCRIPTION: &'static str = "verification only";
|
||||||
|
|
||||||
|
fn deallocate(ptr: *mut [u8]) {
|
||||||
|
let _ = unsafe { Box::from_raw(ptr) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Context for All {
|
||||||
|
const FLAGS: c_uint = VerifyOnly::FLAGS | SignOnly::FLAGS;
|
||||||
|
const DESCRIPTION: &'static str = "all capabilities";
|
||||||
|
|
||||||
|
fn deallocate(ptr: *mut [u8]) {
|
||||||
|
let _ = unsafe { Box::from_raw(ptr) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: Context> Secp256k1<C> {
|
||||||
|
/// Lets you create a context in a generic manner(sign/verify/all)
|
||||||
|
pub fn gen_new() -> Secp256k1<C> {
|
||||||
|
let buf = vec![0u8; Self::preallocate_size_gen()].into_boxed_slice();
|
||||||
|
let ptr = Box::into_raw(buf);
|
||||||
|
Secp256k1 {
|
||||||
|
ctx: unsafe { ffi::secp256k1_context_preallocated_create(ptr as *mut c_void, C::FLAGS) },
|
||||||
|
phantom: PhantomData,
|
||||||
|
buf: ptr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Secp256k1<All> {
|
||||||
|
/// Creates a new Secp256k1 context with all capabilities
|
||||||
|
pub fn new() -> Secp256k1<All> {
|
||||||
|
Secp256k1::gen_new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Secp256k1<SignOnly> {
|
||||||
|
/// Creates a new Secp256k1 context that can only be used for signing
|
||||||
|
pub fn signing_only() -> Secp256k1<SignOnly> {
|
||||||
|
Secp256k1::gen_new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Secp256k1<VerifyOnly> {
|
||||||
|
/// Creates a new Secp256k1 context that can only be used for verification
|
||||||
|
pub fn verification_only() -> Secp256k1<VerifyOnly> {
|
||||||
|
Secp256k1::gen_new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Secp256k1<All> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: Context> Clone for Secp256k1<C> {
|
||||||
|
fn clone(&self) -> Secp256k1<C> {
|
||||||
|
let clone_size = unsafe {ffi::secp256k1_context_preallocated_clone_size(self.ctx)};
|
||||||
|
let ptr_buf = Box::into_raw(vec![0u8; clone_size].into_boxed_slice());
|
||||||
|
Secp256k1 {
|
||||||
|
ctx: unsafe { ffi::secp256k1_context_preallocated_clone(self.ctx, ptr_buf as *mut c_void) },
|
||||||
|
phantom: PhantomData,
|
||||||
|
buf: ptr_buf,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'buf> Signing for SignOnlyPreallocated<'buf> {}
|
||||||
|
impl<'buf> Signing for AllPreallocated<'buf> {}
|
||||||
|
|
||||||
|
impl<'buf> Verification for VerifyOnlyPreallocated<'buf> {}
|
||||||
|
impl<'buf> Verification for AllPreallocated<'buf> {}
|
||||||
|
|
||||||
|
unsafe impl<'buf> Context for SignOnlyPreallocated<'buf> {
|
||||||
|
const FLAGS: c_uint = ffi::SECP256K1_START_SIGN;
|
||||||
|
const DESCRIPTION: &'static str = "signing only";
|
||||||
|
|
||||||
|
fn deallocate(_ptr: *mut [u8]) {
|
||||||
|
// Allocated by the user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<'buf> Context for VerifyOnlyPreallocated<'buf> {
|
||||||
|
const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY;
|
||||||
|
const DESCRIPTION: &'static str = "verification only";
|
||||||
|
|
||||||
|
fn deallocate(_ptr: *mut [u8]) {
|
||||||
|
// Allocated by the user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<'buf> Context for AllPreallocated<'buf> {
|
||||||
|
const FLAGS: c_uint = SignOnlyPreallocated::FLAGS | VerifyOnlyPreallocated::FLAGS;
|
||||||
|
const DESCRIPTION: &'static str = "all capabilities";
|
||||||
|
|
||||||
|
fn deallocate(_ptr: *mut [u8]) {
|
||||||
|
// Allocated by the user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'buf, C: Context + 'buf> Secp256k1<C> {
|
||||||
|
/// Lets you create a context with preallocated buffer in a generic manner(sign/verify/all)
|
||||||
|
pub fn preallocated_gen_new(buf: &'buf mut [u8]) -> Result<Secp256k1<C>, Error> {
|
||||||
|
if buf.len() < Self::preallocate_size_gen() {
|
||||||
|
return Err(Error::NotEnoughMemory);
|
||||||
|
}
|
||||||
|
Ok(Secp256k1 {
|
||||||
|
ctx: unsafe {
|
||||||
|
ffi::secp256k1_context_preallocated_create(
|
||||||
|
buf.as_mut_ptr() as *mut c_void,
|
||||||
|
C::FLAGS)
|
||||||
|
},
|
||||||
|
phantom: PhantomData,
|
||||||
|
buf: buf as *mut [u8],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'buf> Secp256k1<AllPreallocated<'buf>> {
|
||||||
|
/// Creates a new Secp256k1 context with all capabilities
|
||||||
|
pub fn preallocated_new(buf: &'buf mut [u8]) -> Result<Secp256k1<AllPreallocated<'buf>>, Error> {
|
||||||
|
Secp256k1::preallocated_gen_new(buf)
|
||||||
|
}
|
||||||
|
/// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for a context
|
||||||
|
pub fn preallocate_size() -> usize {
|
||||||
|
Self::preallocate_size_gen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'buf> Secp256k1<SignOnlyPreallocated<'buf>> {
|
||||||
|
/// Creates a new Secp256k1 context that can only be used for signing
|
||||||
|
pub fn preallocated_signing_only(buf: &'buf mut [u8]) -> Result<Secp256k1<SignOnlyPreallocated<'buf>>, Error> {
|
||||||
|
Secp256k1::preallocated_gen_new(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for the context
|
||||||
|
#[inline]
|
||||||
|
pub fn preallocate_signing_size() -> usize {
|
||||||
|
Self::preallocate_size_gen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'buf> Secp256k1<VerifyOnlyPreallocated<'buf>> {
|
||||||
|
/// Creates a new Secp256k1 context that can only be used for verification
|
||||||
|
pub fn preallocated_verification_only(buf: &'buf mut [u8]) -> Result<Secp256k1<VerifyOnlyPreallocated<'buf>>, Error> {
|
||||||
|
Secp256k1::preallocated_gen_new(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for the context
|
||||||
|
#[inline]
|
||||||
|
pub fn preallocate_verification_size() -> usize {
|
||||||
|
Self::preallocate_size_gen()
|
||||||
|
}
|
||||||
|
}
|
39
src/ffi.rs
39
src/ffi.rs
|
@ -142,11 +142,15 @@ extern "C" {
|
||||||
pub static secp256k1_context_no_precomp: *const Context;
|
pub static secp256k1_context_no_precomp: *const Context;
|
||||||
|
|
||||||
// Contexts
|
// Contexts
|
||||||
pub fn secp256k1_context_create(flags: c_uint) -> *mut Context;
|
pub fn secp256k1_context_preallocated_size(flags: c_uint) -> usize;
|
||||||
|
|
||||||
pub fn secp256k1_context_clone(cx: *mut Context) -> *mut Context;
|
pub fn secp256k1_context_preallocated_create(prealloc: *mut c_void, flags: c_uint) -> *mut Context;
|
||||||
|
|
||||||
pub fn secp256k1_context_destroy(cx: *mut Context);
|
pub fn secp256k1_context_preallocated_destroy(cx: *mut Context);
|
||||||
|
|
||||||
|
pub fn secp256k1_context_preallocated_clone_size(cx: *const Context) -> usize;
|
||||||
|
|
||||||
|
pub fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: *mut c_void) -> *mut Context;
|
||||||
|
|
||||||
pub fn secp256k1_context_randomize(cx: *mut Context,
|
pub fn secp256k1_context_randomize(cx: *mut Context,
|
||||||
seed32: *const c_uchar)
|
seed32: *const c_uchar)
|
||||||
|
@ -320,7 +324,7 @@ mod fuzz_dummy {
|
||||||
extern crate std;
|
extern crate std;
|
||||||
use types::*;
|
use types::*;
|
||||||
use ffi::*;
|
use ffi::*;
|
||||||
use self::std::ptr;
|
use self::std::{ptr, mem};
|
||||||
use self::std::boxed::Box;
|
use self::std::boxed::Box;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -331,20 +335,31 @@ mod fuzz_dummy {
|
||||||
|
|
||||||
// Contexts
|
// Contexts
|
||||||
/// Creates a dummy context, tracking flags to ensure proper calling semantics
|
/// Creates a dummy context, tracking flags to ensure proper calling semantics
|
||||||
pub unsafe fn secp256k1_context_create(flags: c_uint) -> *mut Context {
|
pub unsafe fn secp256k1_context_preallocated_create(_ptr: *mut c_void, flags: c_uint) -> *mut Context {
|
||||||
let b = Box::new(Context(flags as i32));
|
let b = Box::new(Context(flags as i32));
|
||||||
Box::into_raw(b)
|
Box::into_raw(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copies a dummy context
|
/// Return dummy size of context struct.
|
||||||
pub unsafe fn secp256k1_context_clone(cx: *mut Context) -> *mut Context {
|
pub unsafe fn secp256k1_context_preallocated_size(_flags: c_uint) -> usize {
|
||||||
let b = Box::new(Context((*cx).0));
|
mem::size_of::<Context>()
|
||||||
Box::into_raw(b)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Frees a dummy context
|
/// Return dummy size of context struct.
|
||||||
pub unsafe fn secp256k1_context_destroy(cx: *mut Context) {
|
pub unsafe fn secp256k1_context_preallocated_clone_size(cx: *mut Context) -> usize {
|
||||||
Box::from_raw(cx);
|
mem::size_of::<Context>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copies a dummy context
|
||||||
|
pub unsafe fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: *mut c_void) -> *mut Context {
|
||||||
|
let ret = prealloc as *mut Context;
|
||||||
|
*ret = (*cx).clone();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// "Destroys" a dummy context
|
||||||
|
pub unsafe fn secp256k1_context_preallocated_destroy(cx: *mut Context) {
|
||||||
|
(*cx).0 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asserts that cx is properly initialized
|
/// Asserts that cx is properly initialized
|
||||||
|
|
126
src/lib.rs
126
src/lib.rs
|
@ -148,6 +148,7 @@ use core::{fmt, ptr, str};
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
mod types;
|
mod types;
|
||||||
|
mod context;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod ecdh;
|
pub mod ecdh;
|
||||||
pub mod ffi;
|
pub mod ffi;
|
||||||
|
@ -157,6 +158,7 @@ pub mod recovery;
|
||||||
|
|
||||||
pub use key::SecretKey;
|
pub use key::SecretKey;
|
||||||
pub use key::PublicKey;
|
pub use key::PublicKey;
|
||||||
|
pub use context::*;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
|
||||||
|
@ -463,6 +465,9 @@ pub enum Error {
|
||||||
InvalidRecoveryId,
|
InvalidRecoveryId,
|
||||||
/// Invalid tweak for add_*_assign or mul_*_assign
|
/// Invalid tweak for add_*_assign or mul_*_assign
|
||||||
InvalidTweak,
|
InvalidTweak,
|
||||||
|
/// Didn't pass enough memory to context creation with preallocated memory
|
||||||
|
NotEnoughMemory,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
|
@ -475,6 +480,7 @@ impl Error {
|
||||||
Error::InvalidSecretKey => "secp: malformed or out-of-range secret key",
|
Error::InvalidSecretKey => "secp: malformed or out-of-range secret key",
|
||||||
Error::InvalidRecoveryId => "secp: bad recovery id",
|
Error::InvalidRecoveryId => "secp: bad recovery id",
|
||||||
Error::InvalidTweak => "secp: bad tweak",
|
Error::InvalidTweak => "secp: bad tweak",
|
||||||
|
Error::NotEnoughMemory => "secp: not enough memory allocated",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -491,48 +497,21 @@ impl std::error::Error for Error {
|
||||||
fn description(&self) -> &str { self.as_str() }
|
fn description(&self) -> &str { self.as_str() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marker trait for indicating that an instance of `Secp256k1` can be used for signing.
|
|
||||||
pub trait Signing {}
|
|
||||||
|
|
||||||
/// Marker trait for indicating that an instance of `Secp256k1` can be used for verification.
|
|
||||||
pub trait Verification {}
|
|
||||||
|
|
||||||
/// Represents the set of capabilities needed for signing.
|
|
||||||
pub struct SignOnly {}
|
|
||||||
|
|
||||||
/// Represents the set of capabilities needed for verification.
|
|
||||||
pub struct VerifyOnly {}
|
|
||||||
|
|
||||||
/// Represents the set of all capabilities.
|
|
||||||
pub struct All {}
|
|
||||||
|
|
||||||
impl Signing for SignOnly {}
|
|
||||||
impl Signing for All {}
|
|
||||||
|
|
||||||
impl Verification for VerifyOnly {}
|
|
||||||
impl Verification for All {}
|
|
||||||
|
|
||||||
/// The secp256k1 engine, used to execute all signature operations
|
/// The secp256k1 engine, used to execute all signature operations
|
||||||
pub struct Secp256k1<C> {
|
pub struct Secp256k1<C: Context> {
|
||||||
ctx: *mut ffi::Context,
|
ctx: *mut ffi::Context,
|
||||||
phantom: PhantomData<C>
|
phantom: PhantomData<C>,
|
||||||
|
buf: *mut [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
// The underlying secp context does not contain any references to memory it does not own
|
// The underlying secp context does not contain any references to memory it does not own
|
||||||
unsafe impl<C> Send for Secp256k1<C> {}
|
unsafe impl<C: Context> Send for Secp256k1<C> {}
|
||||||
// The API does not permit any mutation of `Secp256k1` objects except through `&mut` references
|
// The API does not permit any mutation of `Secp256k1` objects except through `&mut` references
|
||||||
unsafe impl<C> Sync for Secp256k1<C> {}
|
unsafe impl<C: Context> Sync for Secp256k1<C> {}
|
||||||
|
|
||||||
impl<C> Clone for Secp256k1<C> {
|
|
||||||
fn clone(&self) -> Secp256k1<C> {
|
|
||||||
Secp256k1 {
|
|
||||||
ctx: unsafe { ffi::secp256k1_context_clone(self.ctx) },
|
|
||||||
phantom: self.phantom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C> PartialEq for Secp256k1<C> {
|
impl<C: Context> PartialEq for Secp256k1<C> {
|
||||||
fn eq(&self, _other: &Secp256k1<C>) -> bool { true }
|
fn eq(&self, _other: &Secp256k1<C>) -> bool { true }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,60 +545,22 @@ impl Deref for SerializedSignature {
|
||||||
|
|
||||||
impl Eq for SerializedSignature {}
|
impl Eq for SerializedSignature {}
|
||||||
|
|
||||||
impl<C> Eq for Secp256k1<C> { }
|
impl<C: Context> Eq for Secp256k1<C> { }
|
||||||
|
|
||||||
impl<C> Drop for Secp256k1<C> {
|
impl<C: Context> Drop for Secp256k1<C> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { ffi::secp256k1_context_destroy(self.ctx); }
|
unsafe { ffi::secp256k1_context_preallocated_destroy(self.ctx) };
|
||||||
|
C::deallocate(self.buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Secp256k1<SignOnly> {
|
impl<C: Context> fmt::Debug for Secp256k1<C> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "<secp256k1 context {:?}, signing only>", self.ctx)
|
write!(f, "<secp256k1 context {:?}, {}>", self.ctx, C::DESCRIPTION)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Secp256k1<VerifyOnly> {
|
impl<C: Context> Secp256k1<C> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "<secp256k1 context {:?}, verification only>", self.ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Secp256k1<All> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "<secp256k1 context {:?}, all capabilities>", self.ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Secp256k1<All> {
|
|
||||||
/// Creates a new Secp256k1 context with all capabilities
|
|
||||||
pub fn new() -> Secp256k1<All> {
|
|
||||||
Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(ffi::SECP256K1_START_SIGN | ffi::SECP256K1_START_VERIFY) }, phantom: PhantomData }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Secp256k1<All> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Secp256k1<SignOnly> {
|
|
||||||
/// Creates a new Secp256k1 context that can only be used for signing
|
|
||||||
pub fn signing_only() -> Secp256k1<SignOnly> {
|
|
||||||
Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(ffi::SECP256K1_START_SIGN) }, phantom: PhantomData }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Secp256k1<VerifyOnly> {
|
|
||||||
/// Creates a new Secp256k1 context that can only be used for verification
|
|
||||||
pub fn verification_only() -> Secp256k1<VerifyOnly> {
|
|
||||||
Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(ffi::SECP256K1_START_VERIFY) }, phantom: PhantomData }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C> Secp256k1<C> {
|
|
||||||
|
|
||||||
/// Getter for the raw pointer to the underlying secp256k1 context. This
|
/// Getter for the raw pointer to the underlying secp256k1 context. This
|
||||||
/// shouldn't be needed with normal usage of the library. It enables
|
/// shouldn't be needed with normal usage of the library. It enables
|
||||||
|
@ -629,6 +570,11 @@ impl<C> Secp256k1<C> {
|
||||||
&self.ctx
|
&self.ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the required memory for a preallocated context buffer in a generic manner(sign/verify/all)
|
||||||
|
pub fn preallocate_size_gen() -> usize {
|
||||||
|
unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) }
|
||||||
|
}
|
||||||
|
|
||||||
/// (Re)randomizes the Secp256k1 context for cheap sidechannel resistance;
|
/// (Re)randomizes the Secp256k1 context for cheap sidechannel resistance;
|
||||||
/// see comment in libsecp256k1 commit d2275795f by Gregory Maxwell. Requires
|
/// see comment in libsecp256k1 commit d2275795f by Gregory Maxwell. Requires
|
||||||
/// compilation with "rand" feature.
|
/// compilation with "rand" feature.
|
||||||
|
@ -750,6 +696,30 @@ mod tests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_preallocation() {
|
||||||
|
let mut buf_ful = vec![0u8; Secp256k1::preallocate_size()];
|
||||||
|
let mut buf_sign = vec![0u8; Secp256k1::preallocate_signing_size()];
|
||||||
|
let mut buf_vfy = vec![0u8; Secp256k1::preallocate_verification_size()];
|
||||||
|
//
|
||||||
|
let full = Secp256k1::preallocated_new(&mut buf_ful).unwrap();
|
||||||
|
let sign = Secp256k1::preallocated_signing_only(&mut buf_sign).unwrap();
|
||||||
|
let vrfy = Secp256k1::preallocated_verification_only(&mut buf_vfy).unwrap();
|
||||||
|
|
||||||
|
// drop(buf_vfy); // The buffer can't get dropped before the context.
|
||||||
|
// println!("{:?}", buf_ful[5]); // Can't even read the data thanks to the borrow checker.
|
||||||
|
|
||||||
|
let (sk, pk) = full.generate_keypair(&mut thread_rng());
|
||||||
|
let msg = Message::from_slice(&[2u8; 32]).unwrap();
|
||||||
|
// Try signing
|
||||||
|
assert_eq!(sign.sign(&msg, &sk), full.sign(&msg, &sk));
|
||||||
|
let sig = full.sign(&msg, &sk);
|
||||||
|
|
||||||
|
// Try verifying
|
||||||
|
assert!(vrfy.verify(&msg, &sig, &pk).is_ok());
|
||||||
|
assert!(full.verify(&msg, &sig, &pk).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn capabilities() {
|
fn capabilities() {
|
||||||
let sign = Secp256k1::signing_only();
|
let sign = Secp256k1::signing_only();
|
||||||
|
|
Loading…
Reference in New Issue