diff --git a/CHANGELOG.md b/CHANGELOG.md index e351f35..d568be8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.14.1 - 2019-07-14 + +* Implemented FFI functions: `secp256k1_context_create` and `secp256k1_context_destroy` in rust. + # 0.14.0 - 2019-07-08 * [Feature-gate endormorphism optimization](https://github.com/rust-bitcoin/rust-secp256k1/pull/120) diff --git a/Cargo.toml b/Cargo.toml index 380f73b..5227bce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "secp256k1" -version = "0.14.0" +version = "0.14.1" authors = [ "Dawid Ciężarkiewicz ", "Andrew Poelstra " ] license = "CC0-1.0" diff --git a/src/ffi.rs b/src/ffi.rs index 42062f7..f5a4a98 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -16,7 +16,7 @@ //! # FFI bindings //! Direct bindings to the underlying C library functions. These should //! not be needed for most users. -use core::{mem, hash}; +use core::{mem, hash, slice}; use types::*; /// Flag for context to enable no precomputation @@ -260,6 +260,50 @@ extern "C" { } +#[cfg(feature = "std")] +#[no_mangle] +/// A reimplementation of the C function `secp256k1_context_create` in rust. +/// +/// This function allocates memory, the pointer should be deallocated using `secp256k1_context_destroy` +/// A failure to do so will result in a memory leak. +/// +/// This will create a secp256k1 raw context. +// 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::() >= mem::align_of::()); + assert_eq!(mem::size_of::(), mem::size_of::<&usize>()); + + 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); + + secp256k1_context_preallocated_create(ptr as *mut c_void, flags) +} + +#[cfg(feature = "std")] +#[no_mangle] +/// A reimplementation of the C function `secp256k1_context_destroy` in rust. +/// +/// This function destroys and deallcates the context created by `secp256k1_context_create`. +/// +/// The pointer shouldn't be used after passing to this function, consider it as passing it to `free()`. +/// +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 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]); +} + + #[no_mangle] /// **This function is an override for the C function, this is the an edited version of the original description:** /// @@ -280,7 +324,7 @@ extern "C" { /// See also secp256k1_default_error_callback_fn. /// pub unsafe extern "C" fn secp256k1_default_illegal_callback_fn(message: *const c_char, _data: *mut c_void) { - use core::{str, slice}; + use core::str; let msg_slice = slice::from_raw_parts(message as *const u8, strlen(message)); let msg = str::from_utf8_unchecked(msg_slice); panic!("[libsecp256k1] illegal argument. {}", msg); @@ -302,7 +346,7 @@ pub unsafe extern "C" fn secp256k1_default_illegal_callback_fn(message: *const c /// See also secp256k1_default_illegal_callback_fn. /// pub unsafe extern "C" fn secp256k1_default_error_callback_fn(message: *const c_char, _data: *mut c_void) { - use core::{str, slice}; + use core::str; let msg_slice = slice::from_raw_parts(message as *const u8, strlen(message)); let msg = str::from_utf8_unchecked(msg_slice); panic!("[libsecp256k1] internal consistency check failed {}", msg); diff --git a/src/lib.rs b/src/lib.rs index 6651bc2..a05dd2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -681,12 +681,15 @@ fn from_hex(hex: &str, target: &mut [u8]) -> Result { mod tests { use rand::{RngCore, thread_rng}; use std::str::FromStr; + 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 context::*; macro_rules! hex { ($hex:expr) => ({ @@ -696,6 +699,35 @@ mod tests { }); } + + #[test] + fn test_manual_create_destroy() { + let ctx_full = unsafe { ffi::secp256k1_context_create(AllPreallocated::FLAGS) }; + 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 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}; + + 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()); + + drop(full);drop(sign);drop(vrfy); + + unsafe { ffi::secp256k1_context_destroy(ctx_vrfy) }; + unsafe { ffi::secp256k1_context_destroy(ctx_sign) }; + unsafe { ffi::secp256k1_context_destroy(ctx_full) }; + } + #[test] fn test_preallocation() { let mut buf_ful = vec![0u8; Secp256k1::preallocate_size()];