Skip to content

Commit

Permalink
Add AlignType and use it for buffer allocations
Browse files Browse the repository at this point in the history
  • Loading branch information
elichai committed Aug 8, 2019
1 parent de21642 commit 93b3a49
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 34 deletions.
43 changes: 29 additions & 14 deletions src/context.rs
Expand Up @@ -7,6 +7,21 @@ use Secp256k1;
#[cfg(feature = "std")]
pub use self::std_only::*;



/// A type that represents the type with the biggest alignment we can get in rust.
/// Trying to match what `malloc` does in C, this should be aligned enough to contain pointers too.
/// This type can have different size/alignment depending on the architecture.
#[cfg(any(target_pointer_width = "32", target_pointer_width = "16", target_pointer_wid = "8"))]
pub type AlignType = u64;

/// A type that represents the type with the biggest alignment we can get in rust.
/// Trying to match what `malloc` does in C, this should be aligned enough to contain pointers too.
/// This type can have different size/alignment depending on the architecture.
#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "16", target_pointer_wid = "8")))]
pub type AlignType = usize;


/// 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 {
Expand All @@ -15,7 +30,7 @@ pub unsafe trait Context {
/// 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]);
fn deallocate(ptr: *mut [AlignType]);
}

/// Marker trait for indicating that an instance of `Secp256k1` can be used for signing.
Expand Down Expand Up @@ -62,7 +77,7 @@ mod std_only {
const FLAGS: c_uint = ffi::SECP256K1_START_SIGN;
const DESCRIPTION: &'static str = "signing only";

fn deallocate(ptr: *mut [u8]) {
fn deallocate(ptr: *mut [AlignType]) {
let _ = unsafe { Box::from_raw(ptr) };
}
}
Expand All @@ -71,7 +86,7 @@ mod std_only {
const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY;
const DESCRIPTION: &'static str = "verification only";

fn deallocate(ptr: *mut [u8]) {
fn deallocate(ptr: *mut [AlignType]) {
let _ = unsafe { Box::from_raw(ptr) };
}
}
Expand All @@ -80,15 +95,15 @@ mod std_only {
const FLAGS: c_uint = VerifyOnly::FLAGS | SignOnly::FLAGS;
const DESCRIPTION: &'static str = "all capabilities";

fn deallocate(ptr: *mut [u8]) {
fn deallocate(ptr: *mut [AlignType]) {
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 buf = vec![0 as AlignType; 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) },
Expand Down Expand Up @@ -128,7 +143,7 @@ mod std_only {
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());
let ptr_buf = Box::into_raw(vec![0 as AlignType; clone_size].into_boxed_slice());
Secp256k1 {
ctx: unsafe { ffi::secp256k1_context_preallocated_clone(self.ctx, ptr_buf as *mut c_void) },
phantom: PhantomData,
Expand All @@ -149,7 +164,7 @@ 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]) {
fn deallocate(_ptr: *mut [AlignType]) {
// Allocated by the user
}
}
Expand All @@ -158,7 +173,7 @@ 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]) {
fn deallocate(_ptr: *mut [AlignType]) {
// Allocated by the user
}
}
Expand All @@ -167,14 +182,14 @@ 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]) {
fn deallocate(_ptr: *mut [AlignType]) {
// 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> {
pub fn preallocated_gen_new(buf: &'buf mut [AlignType]) -> Result<Secp256k1<C>, Error> {
if buf.len() < Self::preallocate_size_gen() {
return Err(Error::NotEnoughMemory);
}
Expand All @@ -185,14 +200,14 @@ impl<'buf, C: Context + 'buf> Secp256k1<C> {
C::FLAGS)
},
phantom: PhantomData,
buf: buf as *mut [u8],
buf: buf as *mut [AlignType],
})
}
}

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> {
pub fn preallocated_new(buf: &'buf mut [AlignType]) -> 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
Expand All @@ -203,7 +218,7 @@ impl<'buf> Secp256k1<AllPreallocated<'buf>> {

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> {
pub fn preallocated_signing_only(buf: &'buf mut [AlignType]) -> Result<Secp256k1<SignOnlyPreallocated<'buf>>, Error> {
Secp256k1::preallocated_gen_new(buf)
}

Expand All @@ -216,7 +231,7 @@ impl<'buf> Secp256k1<SignOnlyPreallocated<'buf>> {

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> {
pub fn preallocated_verification_only(buf: &'buf mut [AlignType]) -> Result<Secp256k1<VerifyOnlyPreallocated<'buf>>, Error> {
Secp256k1::preallocated_gen_new(buf)
}

Expand Down
27 changes: 15 additions & 12 deletions src/ffi.rs
Expand Up @@ -18,6 +18,7 @@
//! not be needed for most users.
use core::{mem, hash, slice};
use types::*;
use context::AlignType;

/// Flag for context to enable no precomputation
pub const SECP256K1_START_NONE: c_uint = 1;
Expand Down Expand Up @@ -271,16 +272,18 @@ extern "C" {
// Returns: a newly created context object.
// In: flags: which parts of the context to initialize.
pub unsafe extern "C" fn secp256k1_context_create(flags: c_uint) -> *mut Context {
assert!(mem::align_of::<usize>() >= mem::align_of::<u8>());
assert_eq!(mem::size_of::<usize>(), mem::size_of::<&usize>());
assert!(mem::align_of::<AlignType>() >= mem::align_of::<u8>());
assert!(mem::align_of::<AlignType>() >= mem::align_of::<usize>());
assert!(mem::size_of::<AlignType>() >= mem::size_of::<usize>());
assert_eq!(mem::size_of::<AlignType>(), mem::size_of::<&AlignType>());

let word_size = mem::size_of::<usize>();
let word_size = mem::size_of::<AlignType>();
let n_words = (secp256k1_context_preallocated_size(flags) + word_size - 1) / word_size;

let buf = vec![0usize; n_words + 1].into_boxed_slice();
let ptr = Box::into_raw(buf) as *mut usize;
::core::ptr::write(ptr, n_words);
let ptr: *mut usize = ptr.offset(1);
let buf = vec![0 as AlignType; n_words + 1].into_boxed_slice();
let ptr = Box::into_raw(buf) as *mut AlignType;
::core::ptr::write(ptr, n_words as AlignType);
let ptr: *mut AlignType = ptr.offset(1);

secp256k1_context_preallocated_create(ptr as *mut c_void, flags)
}
Expand All @@ -295,12 +298,12 @@ pub unsafe extern "C" fn secp256k1_context_create(flags: c_uint) -> *mut Context
///
pub unsafe extern "C" fn secp256k1_context_destroy(ctx: *mut Context) {
secp256k1_context_preallocated_destroy(ctx);
let ctx: *mut usize = ctx as *mut usize;
let ctx: *mut AlignType = ctx as *mut AlignType;

let n_words_ptr: *mut usize = ctx.offset(-1);
let n_words: usize = ::core::ptr::read(n_words_ptr);
let slice: &mut [usize] = slice::from_raw_parts_mut(n_words_ptr , n_words+1);
let _ = Box::from_raw(slice as *mut [usize]);
let n_words_ptr: *mut AlignType = ctx.offset(-1);
let n_words: AlignType = ::core::ptr::read(n_words_ptr);
let slice: &mut [AlignType] = slice::from_raw_parts_mut(n_words_ptr , (n_words+1) as usize);
let _ = Box::from_raw(slice as *mut [AlignType]);
}


Expand Down
26 changes: 18 additions & 8 deletions src/lib.rs
Expand Up @@ -143,7 +143,9 @@
#[cfg(any(test, feature = "rand"))] use rand::Rng;
#[cfg(any(test, feature = "std"))] extern crate core;

use core::{fmt, ptr, str};
use core::{fmt, mem, ptr, str};

pub use context::AlignType;

#[macro_use]
mod macros;
Expand Down Expand Up @@ -502,7 +504,7 @@ impl std::error::Error for Error {
pub struct Secp256k1<C: Context> {
ctx: *mut ffi::Context,
phantom: PhantomData<C>,
buf: *mut [u8],
buf: *mut [AlignType],
}

// The underlying secp context does not contain any references to memory it does not own
Expand Down Expand Up @@ -572,7 +574,15 @@ impl<C: Context> Secp256k1<C> {

/// 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) }
assert!(mem::align_of::<AlignType>() >= mem::align_of::<u8>());
assert!(mem::align_of::<AlignType>() >= mem::align_of::<usize>());
assert!(mem::size_of::<AlignType>() >= mem::size_of::<usize>());
assert_eq!(mem::size_of::<AlignType>(), mem::size_of::<&AlignType>());

let bytes_size = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) };
let word_size = mem::size_of::<AlignType>();
let n_words = (bytes_size + word_size - 1) / word_size;
n_words
}

/// (Re)randomizes the Secp256k1 context for cheap sidechannel resistance;
Expand Down Expand Up @@ -706,7 +716,7 @@ mod tests {
let ctx_sign = unsafe { ffi::secp256k1_context_create(SignOnlyPreallocated::FLAGS) };
let ctx_vrfy = unsafe { ffi::secp256k1_context_create(VerifyOnlyPreallocated::FLAGS) };

let buf: *mut [u8] = &mut [0u8;0] as _;
let buf: *mut [AlignType] = &mut [0 as AlignType;0] as _;
let full: Secp256k1<AllPreallocated> = Secp256k1{ctx: ctx_full, phantom: PhantomData, buf};
let sign: Secp256k1<SignOnlyPreallocated> = Secp256k1{ctx: ctx_sign, phantom: PhantomData, buf};
let vrfy: Secp256k1<VerifyOnlyPreallocated> = Secp256k1{ctx: ctx_vrfy, phantom: PhantomData, buf};
Expand All @@ -730,10 +740,10 @@ 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 mut buf_ful = vec![0; Secp256k1::preallocate_size()];
let mut buf_sign = vec![0; Secp256k1::preallocate_signing_size()];
let mut buf_vfy = vec![0; 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();
Expand Down

0 comments on commit 93b3a49

Please sign in to comment.