Skip to content

Commit

Permalink
Make preallocated_* unsafe and pass raw pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
elichai committed Aug 28, 2020
1 parent b09494f commit bbf8996
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 27 deletions.
44 changes: 28 additions & 16 deletions src/context.rs
@@ -1,8 +1,7 @@
use core::marker::PhantomData;
use core::mem::{self, ManuallyDrop};
use ffi::{self, CPtr, types::AlignedType};
use ffi::{self, types::AlignedType};
use ffi::types::{c_uint, c_void};
use Error;
use Secp256k1;

#[cfg(feature = "std")]
Expand Down Expand Up @@ -232,28 +231,31 @@ unsafe impl<'buf> Context for AllPreallocated<'buf> {

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> {
///
/// # Safety
/// * The pointer must be valid for [`preallocate_size_gen()`](#method.preallocated_gen_new) bytes
/// * The pointer must be as aligned as [`ffi::types::AlignedType`](../secp256k1-sys/src/types.html#AlignedType)
/// * The pointer must be writeable.
pub unsafe fn preallocated_gen_new(buf: *mut c_void) -> Secp256k1<C> {
#[cfg(target_arch = "wasm32")]
ffi::types::sanity_checks_for_wasm();

if buf.len() < Self::preallocate_size_gen() {
return Err(Error::NotEnoughMemory);
}
Ok(Secp256k1 {
ctx: unsafe {
ffi::secp256k1_context_preallocated_create(
buf.as_mut_c_ptr() as *mut c_void,
C::FLAGS)
},
Secp256k1 {
ctx: ffi::secp256k1_context_preallocated_create(buf, C::FLAGS),
phantom: PhantomData,
size: 0, // We don't care about the size because it's the caller responsibility to deallocate.
})
}
}
}

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> {
///
/// # Safety
/// * The pointer must be valid for [`preallocate_size()`](#method.preallocate_size) bytes
/// * The pointer must be as aligned as [`ffi::types::AlignedType`](../secp256k1-sys/src/types.html#AlignedType)
/// * The pointer must be writeable.
pub unsafe fn preallocated_new(buf: *mut c_void) -> Secp256k1<AllPreallocated<'buf>> {
Secp256k1::preallocated_gen_new(buf)
}
/// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for a context
Expand Down Expand Up @@ -283,7 +285,12 @@ 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> {
///
/// # Safety
/// * The pointer must be valid for [`preallocate_size_gen()`](#method.preallocate_size_gen) bytes
/// * The pointer must be as aligned as [`ffi::types::AlignedType`](../secp256k1-sys/src/types.html#AlignedType)
/// * The pointer must be writeable.
pub unsafe fn preallocated_signing_only(buf: *mut c_void) -> Secp256k1<SignOnlyPreallocated<'buf>> {
Secp256k1::preallocated_gen_new(buf)
}

Expand Down Expand Up @@ -315,7 +322,12 @@ 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> {
///
/// # Safety
/// * The pointer must be valid for [`preallocate_verification_size()`](#method.preallocate_verification_size) bytes
/// * The pointer must be as aligned as [`ffi::types::AlignedType`](../secp256k1-sys/src/types.html#AlignedType)
/// * The pointer must be writeable.
pub unsafe fn preallocated_verification_only(buf: *mut c_void) -> Secp256k1<VerifyOnlyPreallocated<'buf>> {
Secp256k1::preallocated_gen_new(buf)
}

Expand Down
29 changes: 18 additions & 11 deletions src/lib.rs
Expand Up @@ -548,8 +548,6 @@ pub enum Error {
InvalidRecoveryId,
/// Invalid tweak for add_*_assign or mul_*_assign
InvalidTweak,
/// Didn't pass enough memory to context creation with preallocated memory
NotEnoughMemory,
}

impl Error {
Expand All @@ -562,7 +560,6 @@ impl Error {
Error::InvalidSecretKey => "secp: malformed or out-of-range secret key",
Error::InvalidRecoveryId => "secp: bad recovery id",
Error::InvalidTweak => "secp: bad tweak",
Error::NotEnoughMemory => "secp: not enough memory allocated",
}
}
}
Expand Down Expand Up @@ -788,14 +785,15 @@ fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, ()> {
mod tests {
use rand::{RngCore, thread_rng};
use std::str::FromStr;
use std::alloc::{alloc, dealloc, Layout};
use std::marker::PhantomData;

use key::{SecretKey, PublicKey};
use super::from_hex;
use super::constants;
use super::{Secp256k1, Signature, Message};
use super::Error::{InvalidMessage, IncorrectSignature, InvalidSignature};
use ffi;
use ffi::{self, types::AlignedType};
use context::*;

macro_rules! hex {
Expand Down Expand Up @@ -872,13 +870,17 @@ 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();
const ALIGN_TO: usize = std::mem::align_of::<AlignedType>();
let ful_layout = Layout::from_size_align(Secp256k1::preallocate_size(), ALIGN_TO).unwrap();
let sign_layout = Layout::from_size_align(Secp256k1::preallocate_signing_size(), ALIGN_TO).unwrap();
let vrf_layout = Layout::from_size_align(Secp256k1::preallocate_verification_size(), ALIGN_TO).unwrap();
let buf_ful = unsafe { alloc(ful_layout) };
let buf_sign = unsafe { alloc(sign_layout) };
let buf_vfy = unsafe { alloc(vrf_layout)} ;

let full = unsafe { Secp256k1::preallocated_new(buf_ful as _) };
let sign = unsafe { Secp256k1::preallocated_signing_only(buf_sign as _) };
let vrfy = unsafe { Secp256k1::preallocated_verification_only(buf_vfy as _) };

// 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.
Expand All @@ -892,6 +894,11 @@ mod tests {
// Try verifying
assert!(vrfy.verify(&msg, &sig, &pk).is_ok());
assert!(full.verify(&msg, &sig, &pk).is_ok());
unsafe {
dealloc(buf_ful, ful_layout);
dealloc(buf_sign, sign_layout);
dealloc(buf_vfy, vrf_layout);
}
}

#[test]
Expand Down

0 comments on commit bbf8996

Please sign in to comment.