Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented context create/destroy in rust #130

Merged
merged 3 commits into from
Jul 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "secp256k1"
version = "0.14.0"
version = "0.14.1"
authors = [ "Dawid Ciężarkiewicz <dpc@ucore.info>",
"Andrew Poelstra <apoelstra@wpsoftware.net>" ]
license = "CC0-1.0"
Expand Down
50 changes: 47 additions & 3 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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::<usize>() >= mem::align_of::<u8>());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh, in light of our recent alignment discussion I don't think this assertion provides any value. It's better to add a comment saying that https://rust-lang.github.io/unsafe-code-guidelines/layout/pointers.html guarantees our pointers will be aligned to size_of::<usize> so we can offset by that amount without fear.

assert_eq!(mem::size_of::<usize>(), mem::size_of::<&usize>());

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

let buf = vec![0usize; n_words + 1].into_boxed_slice();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need this +1.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, derp, the +1 is the extra word for the length.

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:**
///
Expand All @@ -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);
Expand All @@ -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);
Expand Down
32 changes: 32 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,12 +681,15 @@ fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, ()> {
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) => ({
Expand All @@ -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<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};

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()];
Expand Down