From 66ab70f99178f816262584755cd3a0eadbcc7457 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Fri, 16 Aug 2019 14:48:03 -0400 Subject: [PATCH] Added a C Ptr trait that returns a null pointer for ZSTs --- src/ffi.rs | 34 +++++++++++++++++++++++++++++++++- src/key.rs | 14 +++++++++++++- src/lib.rs | 12 ++++++++++++ src/macros.rs | 18 ++++++++++++++++++ src/recovery/mod.rs | 19 +++++++++++++++++++ 5 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 3f28490..fab655d 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, slice}; +use core::{mem, hash, slice, ptr}; use types::*; /// Flag for context to enable no precomputation @@ -366,6 +366,38 @@ unsafe fn strlen(mut str_ptr: *const c_char) -> usize { } +/// A trait for producing pointers that will always be valid in C. (assuming NULL pointer is a valid no-op) +/// Rust doesn't promise what pointers does it give to ZST (https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts) +/// In case the type is empty this trait will give a NULL pointer, which should be handled in C. +/// +pub(crate) trait CPtr { + type Target; + fn as_c_ptr(&self) -> *const Self::Target; + fn as_mut_c_ptr(&mut self) -> *mut Self::Target; +} + +impl CPtr for [T] { + type Target = T; + fn as_c_ptr(&self) -> *const Self::Target { + if self.is_empty() { + ptr::null() + } else { + self.as_ptr() + } + } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + if self.is_empty() { + ptr::null::() as *mut _ + } else { + self.as_mut_ptr() + } + } +} + + + + #[cfg(feature = "fuzztarget")] mod fuzz_dummy { extern crate std; diff --git a/src/key.rs b/src/key.rs index 85eb92e..e4464ff 100644 --- a/src/key.rs +++ b/src/key.rs @@ -24,7 +24,7 @@ use super::Error::{self, InvalidPublicKey, InvalidSecretKey}; use Signing; use Verification; use constants; -use ffi; +use ffi::{self, CPtr}; /// Secret 256-bit key used as `x` in an ECDSA signature pub struct SecretKey([u8; constants::SECRET_KEY_SIZE]); @@ -355,6 +355,18 @@ impl PublicKey { } } +impl CPtr for PublicKey { + type Target = ffi::PublicKey; + fn as_c_ptr(&self) -> *const Self::Target { + self.as_ptr() + } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + self.as_mut_ptr() + } +} + + /// Creates a new public key from a FFI public key impl From for PublicKey { #[inline] diff --git a/src/lib.rs b/src/lib.rs index fd24ab6..450e193 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,6 +161,7 @@ pub use key::PublicKey; pub use context::*; use core::marker::PhantomData; use core::ops::Deref; +use ffi::CPtr; /// An ECDSA signature #[derive(Copy, Clone, PartialEq, Eq)] @@ -380,6 +381,17 @@ impl Signature { } } +impl CPtr for Signature { + type Target = ffi::Signature; + fn as_c_ptr(&self) -> *const Self::Target { + self.as_ptr() + } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + self.as_mut_ptr() + } +} + /// Creates a new signature from a FFI signature impl From for Signature { #[inline] diff --git a/src/macros.rs b/src/macros.rs index 3b41467..6a8354f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -122,6 +122,24 @@ macro_rules! impl_array_newtype { &dat[..] } } + impl ::ffi::CPtr for $thing { + type Target = $ty; + fn as_c_ptr(&self) -> *const Self::Target { + if self.is_empty() { + ::core::ptr::null() + } else { + self.as_ptr() + } + } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + if self.is_empty() { + ::core::ptr::null::() as *mut _ + } else { + self.as_mut_ptr() + } + } + } } } diff --git a/src/recovery/mod.rs b/src/recovery/mod.rs index aecefb1..bf0c9f6 100644 --- a/src/recovery/mod.rs +++ b/src/recovery/mod.rs @@ -23,6 +23,7 @@ use super::{Secp256k1, Message, Error, Signature, Verification, Signing}; use super::ffi as super_ffi; pub use key::SecretKey; pub use key::PublicKey; +use self::super_ffi::CPtr; mod ffi; @@ -82,6 +83,12 @@ impl RecoverableSignature { &self.0 as *const _ } + /// Obtains a raw mutable pointer suitable for use with FFI functions + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut ffi::RecoverableSignature { + &mut self.0 as *mut _ + } + #[inline] /// Serializes the recoverable signature in compact format pub fn serialize_compact(&self) -> (RecoveryId, [u8; 64]) { @@ -116,6 +123,18 @@ impl RecoverableSignature { } } + +impl CPtr for RecoverableSignature { + type Target = ffi::RecoverableSignature; + fn as_c_ptr(&self) -> *const Self::Target { + self.as_ptr() + } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + self.as_mut_ptr() + } +} + /// Creates a new recoverable signature from a FFI one impl From for RecoverableSignature { #[inline]