From 84ebaa0bd6d94c07a283b36aaa3f55c93eea40a1 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Thu, 8 Aug 2019 13:58:48 -0400 Subject: [PATCH 1/2] Add AlignType and use it for buffer allocations --- secp256k1-sys/src/lib.rs | 30 ++++++++++++++++++++---------- src/context.rs | 36 ++++++++++++++++++------------------ src/lib.rs | 16 +++++++++++++--- 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/secp256k1-sys/src/lib.rs b/secp256k1-sys/src/lib.rs index a7792351e..de99d921d 100644 --- a/secp256k1-sys/src/lib.rs +++ b/secp256k1-sys/src/lib.rs @@ -39,6 +39,12 @@ pub mod recovery; use core::{hash, slice, ptr}; use types::*; +#[cfg(any(target_pointer_width = "32", target_pointer_width = "16", target_pointer_width = "8"))] +pub type AlignType = u64; + +#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "16", target_pointer_width = "8")))] +pub type AlignType = usize; + /// Flag for context to enable no precomputation pub const SECP256K1_START_NONE: c_uint = 1; /// Flag for context to enable verification precomputation @@ -300,14 +306,18 @@ pub unsafe extern "C" fn rustsecp256k1_v0_1_1_context_create(flags: c_uint) -> * use std::mem; assert!(mem::align_of::() >= mem::align_of::()); assert_eq!(mem::size_of::(), mem::size_of::<&usize>()); + assert!(mem::align_of::() >= mem::align_of::()); + assert!(mem::align_of::() >= mem::align_of::()); + assert!(mem::size_of::() >= mem::size_of::()); + assert!(mem::align_of::() >= mem::align_of::<&AlignType>()); - let word_size = mem::size_of::(); + let word_size = mem::size_of::(); 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: *mut AlignType = 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) } @@ -327,12 +337,12 @@ pub unsafe fn secp256k1_context_create(flags: c_uint) -> *mut Context { #[cfg(all(feature = "std", not(feature = "external-symbols")))] pub unsafe extern "C" fn rustsecp256k1_v0_1_1_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]); } #[cfg(all(feature = "std", not(feature = "external-symbols")))] diff --git a/src/context.rs b/src/context.rs index 3ddf9a77a..c08df4e0f 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use core::mem::ManuallyDrop; use ptr; -use ffi::{self, CPtr}; +use ffi::{self, CPtr, AlignType}; use ffi::types::{c_uint, c_void}; use Error; use Secp256k1; @@ -17,7 +17,7 @@ pub unsafe trait Context : private::Sealed { /// A constant description of the context. const DESCRIPTION: &'static str; /// A function to deallocate the memory when the context is dropped. - unsafe fn deallocate(ptr: *mut [u8]); + unsafe fn deallocate(ptr: *mut [AlignType]); } /// Marker trait for indicating that an instance of `Secp256k1` can be used for signing. @@ -80,7 +80,7 @@ mod std_only { const FLAGS: c_uint = ffi::SECP256K1_START_SIGN; const DESCRIPTION: &'static str = "signing only"; - unsafe fn deallocate(ptr: *mut [u8]) { + unsafe fn deallocate(ptr: *mut [AlignType]) { let _ = Box::from_raw(ptr); } } @@ -89,7 +89,7 @@ mod std_only { const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY; const DESCRIPTION: &'static str = "verification only"; - unsafe fn deallocate(ptr: *mut [u8]) { + unsafe fn deallocate(ptr: *mut [AlignType]) { let _ = Box::from_raw(ptr); } } @@ -98,7 +98,7 @@ mod std_only { const FLAGS: c_uint = VerifyOnly::FLAGS | SignOnly::FLAGS; const DESCRIPTION: &'static str = "all capabilities"; - unsafe fn deallocate(ptr: *mut [u8]) { + unsafe fn deallocate(ptr: *mut [AlignType]) { let _ = Box::from_raw(ptr); } } @@ -109,7 +109,7 @@ mod std_only { #[cfg(target_arch = "wasm32")] ffi::types::sanity_checks_for_wasm(); - 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) }, @@ -149,7 +149,7 @@ mod std_only { impl Clone for Secp256k1 { fn clone(&self) -> Secp256k1 { 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, @@ -169,7 +169,7 @@ unsafe impl<'buf> Context for SignOnlyPreallocated<'buf> { const FLAGS: c_uint = ffi::SECP256K1_START_SIGN; const DESCRIPTION: &'static str = "signing only"; - unsafe fn deallocate(_ptr: *mut [u8]) { + unsafe fn deallocate(_ptr: *mut [AlignType]) { // Allocated by the user } } @@ -178,7 +178,7 @@ unsafe impl<'buf> Context for VerifyOnlyPreallocated<'buf> { const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY; const DESCRIPTION: &'static str = "verification only"; - unsafe fn deallocate(_ptr: *mut [u8]) { + unsafe fn deallocate(_ptr: *mut [AlignType]) { // Allocated by the user } } @@ -187,14 +187,14 @@ unsafe impl<'buf> Context for AllPreallocated<'buf> { const FLAGS: c_uint = SignOnlyPreallocated::FLAGS | VerifyOnlyPreallocated::FLAGS; const DESCRIPTION: &'static str = "all capabilities"; - unsafe fn deallocate(_ptr: *mut [u8]) { + unsafe fn deallocate(_ptr: *mut [AlignType]) { // Allocated by the user } } impl<'buf, C: Context + 'buf> Secp256k1 { /// 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, Error> { + pub fn preallocated_gen_new(buf: &'buf mut [AlignType]) -> Result, Error> { #[cfg(target_arch = "wasm32")] ffi::types::sanity_checks_for_wasm(); @@ -208,14 +208,14 @@ impl<'buf, C: Context + 'buf> Secp256k1 { C::FLAGS) }, phantom: PhantomData, - buf: buf as *mut [u8], + buf: buf as *mut [AlignType], }) } } impl<'buf> Secp256k1> { /// Creates a new Secp256k1 context with all capabilities - pub fn preallocated_new(buf: &'buf mut [u8]) -> Result>, Error> { + pub fn preallocated_new(buf: &'buf mut [AlignType]) -> Result>, Error> { Secp256k1::preallocated_gen_new(buf) } /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for a context @@ -238,14 +238,14 @@ impl<'buf> Secp256k1> { ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData, - buf: ptr::null_mut::<[u8;0]>() as *mut [u8] , + buf: ptr::null_mut::<[AlignType;0]>() as *mut [AlignType] , }) } } impl<'buf> Secp256k1> { /// Creates a new Secp256k1 context that can only be used for signing - pub fn preallocated_signing_only(buf: &'buf mut [u8]) -> Result>, Error> { + pub fn preallocated_signing_only(buf: &'buf mut [AlignType]) -> Result>, Error> { Secp256k1::preallocated_gen_new(buf) } @@ -270,14 +270,14 @@ impl<'buf> Secp256k1> { ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData, - buf: ptr::null_mut::<[u8;0]>() as *mut [u8] , + buf: ptr::null_mut::<[AlignType;0]>() as *mut [AlignType] , }) } } impl<'buf> Secp256k1> { /// Creates a new Secp256k1 context that can only be used for verification - pub fn preallocated_verification_only(buf: &'buf mut [u8]) -> Result>, Error> { + pub fn preallocated_verification_only(buf: &'buf mut [AlignType]) -> Result>, Error> { Secp256k1::preallocated_gen_new(buf) } @@ -302,7 +302,7 @@ impl<'buf> Secp256k1> { ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData, - buf: ptr::null_mut::<[u8;0]>() as *mut [u8] , + buf: ptr::null_mut::<[AlignType;0]>() as *mut [AlignType] , }) } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index a60a2b5ca..941eefc0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -155,7 +155,9 @@ pub use secp256k1_sys as ffi; #[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 ffi::AlignType; #[macro_use] mod macros; @@ -530,7 +532,7 @@ impl std::error::Error for Error { pub struct Secp256k1 { ctx: *mut ffi::Context, phantom: PhantomData, - buf: *mut [u8], + buf: *mut [AlignType], } // The underlying secp context does not contain any references to memory it does not own @@ -602,7 +604,15 @@ impl Secp256k1 { /// 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::() >= mem::align_of::()); + assert!(mem::align_of::() >= mem::align_of::()); + assert!(mem::size_of::() >= mem::size_of::()); + assert!(mem::align_of::() >= mem::align_of::<&AlignType>()); + + let bytes_size = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) }; + let word_size = mem::size_of::(); + let n_words = (bytes_size + word_size - 1) / word_size; + n_words } /// (Re)randomizes the Secp256k1 context for cheap sidechannel resistance; From 12be8fadc851e77aa1c4c79889eb8187822a2802 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Thu, 8 Aug 2019 13:54:03 -0400 Subject: [PATCH 2/2] Add docs for AlignType and preallocation, and update preallocate tests --- no_std_test/src/main.rs | 4 ++-- secp256k1-sys/src/lib.rs | 6 ++++++ src/context.rs | 39 ++++++++++++++++++++++++++++++++++++--- src/lib.rs | 15 +++++++++------ 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/no_std_test/src/main.rs b/no_std_test/src/main.rs index fbf87a53f..6fc33fc13 100644 --- a/no_std_test/src/main.rs +++ b/no_std_test/src/main.rs @@ -82,9 +82,9 @@ impl RngCore for FakeRng { #[start] fn start(_argc: isize, _argv: *const *const u8) -> isize { - let mut buf = [0u8; 600_000]; + let mut buf = [0; 75_000]; let size = Secp256k1::preallocate_size(); - unsafe { libc::printf("needed size: %d\n\0".as_ptr() as _, size) }; + unsafe { libc::printf("needed size: %zu\n\0".as_ptr() as _, size) }; let mut secp = Secp256k1::preallocated_new(&mut buf).unwrap(); secp.randomize(&mut FakeRng); diff --git a/secp256k1-sys/src/lib.rs b/secp256k1-sys/src/lib.rs index de99d921d..3cb8fe659 100644 --- a/secp256k1-sys/src/lib.rs +++ b/secp256k1-sys/src/lib.rs @@ -39,9 +39,15 @@ pub mod recovery; use core::{hash, slice, ptr}; use types::*; +/// 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_width = "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_width = "8")))] pub type AlignType = usize; diff --git a/src/context.rs b/src/context.rs index c08df4e0f..a8729b5e0 100644 --- a/src/context.rs +++ b/src/context.rs @@ -218,7 +218,18 @@ impl<'buf> Secp256k1> { pub fn preallocated_new(buf: &'buf mut [AlignType]) -> Result>, Error> { Secp256k1::preallocated_gen_new(buf) } - /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for a context + /// Returns the required memory for a preallocated context buffer in a generic manner(sign/verify/all) + /// + /// Notice that the memory returned is in [AlignType](type.AlignType.html) + /// + /// ## Examples + /// ```rust + /// # use secp256k1::*; + /// let buf_size = Secp256k1::preallocate_size(); + /// let mut buf = vec![0; buf_size]; + /// let secp = Secp256k1::preallocated_new(&mut buf).unwrap(); + /// + /// ``` pub fn preallocate_size() -> usize { Self::preallocate_size_gen() } @@ -249,7 +260,18 @@ impl<'buf> Secp256k1> { Secp256k1::preallocated_gen_new(buf) } - /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for the context + /// Returns the required memory for a preallocated context buffer in a generic manner(sign/verify/all) + /// + /// Notice that the memory returned is in [AlignType](type.AlignType.html) + /// + /// ## Examples + /// ```rust + /// # use secp256k1::*; + /// let buf_size = Secp256k1::preallocate_signing_size(); + /// let mut buf = vec![0; buf_size]; + /// let secp = Secp256k1::preallocated_signing_only(&mut buf).unwrap(); + /// + /// ``` #[inline] pub fn preallocate_signing_size() -> usize { Self::preallocate_size_gen() @@ -281,7 +303,18 @@ impl<'buf> Secp256k1> { Secp256k1::preallocated_gen_new(buf) } - /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for the context + /// Returns the required memory for a preallocated context buffer in a generic manner(sign/verify/all) + /// + /// Notice that the memory returned is in [AlignType](type.AlignType.html) + /// + /// ## Examples + /// ```rust + /// # use secp256k1::*; + /// let buf_size = Secp256k1::preallocate_verification_size(); + /// let mut buf = vec![0; buf_size]; + /// let secp = Secp256k1::preallocated_verification_only(&mut buf).unwrap(); + /// + /// ``` #[inline] pub fn preallocate_verification_size() -> usize { Self::preallocate_size_gen() diff --git a/src/lib.rs b/src/lib.rs index 941eefc0c..21fda2f99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -603,6 +603,9 @@ impl Secp256k1 { } /// Returns the required memory for a preallocated context buffer in a generic manner(sign/verify/all) + /// + /// Notice that the memory returned is in [AlignType](type.AlignType.html) + /// pub fn preallocate_size_gen() -> usize { assert!(mem::align_of::() >= mem::align_of::()); assert!(mem::align_of::() >= mem::align_of::()); @@ -728,7 +731,7 @@ mod tests { use super::constants; use super::{Secp256k1, Signature, Message}; use super::Error::{InvalidMessage, IncorrectSignature, InvalidSignature}; - use ffi; + use ffi::{self, AlignType}; use context::*; macro_rules! hex { @@ -746,7 +749,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 = Secp256k1{ctx: ctx_full, phantom: PhantomData, buf}; let sign: Secp256k1 = Secp256k1{ctx: ctx_sign, phantom: PhantomData, buf}; let vrfy: Secp256k1 = Secp256k1{ctx: ctx_vrfy, phantom: PhantomData, buf}; @@ -805,10 +808,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();