diff --git a/.travis.yml b/.travis.yml index c742039..3cc8800 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,10 @@ script: - cargo build --verbose --features=rand - cargo test --verbose --features=rand - cargo test --verbose --features="rand serde" + - cargo build --verbose --no-default-features + - cargo build --verbose --no-default-features --features="serde" + - cargo build --verbose --no-default-features --features="rand" + - cargo build --verbose --no-default-features --features="rand serde" - cargo build --verbose - cargo test --verbose - cargo build --release diff --git a/Cargo.toml b/Cargo.toml index 47db1b0..31a8c6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,8 +27,9 @@ path = "src/lib.rs" [features] unstable = [] -default = [] +default = ["std"] fuzztarget = [] +std = [] [dev-dependencies] rand = "0.6" @@ -38,7 +39,9 @@ serde_test = "1.0" [dependencies.rand] version = "0.6" optional = true +default-features = false [dependencies.serde] version = "1.0" optional = true +default-features = false diff --git a/src/ecdh.rs b/src/ecdh.rs index aec2dbc..35de210 100644 --- a/src/ecdh.rs +++ b/src/ecdh.rs @@ -16,7 +16,7 @@ //! Support for shared secret computations //! -use std::{ops, ptr}; +use core::{ops, ptr}; use key::{SecretKey, PublicKey}; use ffi; diff --git a/src/ffi.rs b/src/ffi.rs index a7633b5..f173300 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -16,9 +16,10 @@ //! # FFI bindings //! Direct bindings to the underlying C library functions. These should //! not be needed for most users. -use std::mem; -use std::hash; -use std::os::raw::{c_int, c_uchar, c_uint, c_void}; +use core::{mem, hash}; +use types::*; +// use std::os::raw::{c_int, c_uchar, c_uint, c_void}; + /// Flag for context to enable no precomputation pub const SECP256K1_START_NONE: c_uint = 1; diff --git a/src/key.rs b/src/key.rs index 1f302f4..8dab98f 100644 --- a/src/key.rs +++ b/src/key.rs @@ -17,7 +17,7 @@ #[cfg(any(test, feature = "rand"))] use rand::Rng; -use std::{fmt, mem, str}; +use core::{fmt, mem, str}; use super::{from_hex, Secp256k1}; use super::Error::{self, InvalidPublicKey, InvalidSecretKey}; diff --git a/src/lib.rs b/src/lib.rs index 8ec5e58..69dee83 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,18 +133,21 @@ #![cfg_attr(feature = "dev", feature(plugin))] #![cfg_attr(feature = "dev", plugin(clippy))] +#![cfg_attr(all(not(test), not(feature = "std")), no_std)] #![cfg_attr(all(test, feature = "unstable"), feature(test))] #[cfg(all(test, feature = "unstable"))] extern crate test; #[cfg(any(test, feature = "rand"))] pub extern crate rand; #[cfg(any(test))] extern crate rand_core; #[cfg(feature = "serde")] pub extern crate serde; #[cfg(all(test, feature = "serde"))] extern crate serde_test; - -use std::{error, fmt, ptr, str}; #[cfg(any(test, feature = "rand"))] use rand::Rng; +#[cfg(any(test, feature = "std"))] extern crate core; + +use core::{fmt, ptr, str}; #[macro_use] mod macros; +mod types; pub mod constants; pub mod ecdh; pub mod ffi; @@ -152,7 +155,8 @@ pub mod key; pub use key::SecretKey; pub use key::PublicKey; -use std::marker::PhantomData; +use core::marker::PhantomData; +use core::ops::Deref; /// A tag used for recovering the public key from a compact signature #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -162,6 +166,13 @@ pub struct RecoveryId(i32); #[derive(Copy, Clone, PartialEq, Eq)] pub struct Signature(ffi::Signature); +/// A DER serialized Signature +#[derive(Copy, Clone)] +pub struct SerializedSignature { + data: [u8; 72], + len: usize, +} + impl fmt::Debug for Signature { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) @@ -228,6 +239,40 @@ pub fn to_i32(self) -> i32 { } } +impl SerializedSignature { + /// Get a pointer to the underlying data with the specified capacity. + pub(crate) fn get_data_mut_ptr(&mut self) -> *mut u8 { + self.data.as_mut_ptr() + } + + /// Get the capacity of the underlying data buffer. + pub fn capacity(&self) -> usize { + self.data.len() + } + + /// Get the len of the used data. + pub fn len(&self) -> usize { + self.len + } + + /// Set the length of the object. + pub(crate) fn set_len(&mut self, len: usize) { + self.len = len; + } + + /// Convert the serialized signature into the Signature struct. + /// (This DER deserializes it) + pub fn to_signature(&self) -> Result { + Signature::from_der(&self) + } + + /// Create a SerializedSignature from a Signature. + /// (this DER serializes it) + pub fn from_signature(sig: &Signature) -> SerializedSignature { + sig.serialize_der() + } +} + impl Signature { #[inline] /// Converts a DER-encoded byte slice to a signature @@ -334,18 +379,18 @@ impl Signature { #[inline] /// Serializes the signature in DER format - pub fn serialize_der(&self) -> Vec { - let mut ret = Vec::with_capacity(72); - let mut len: usize = ret.capacity() as usize; + pub fn serialize_der(&self) -> SerializedSignature { + let mut ret = SerializedSignature::default(); + let mut len: usize = ret.capacity(); unsafe { let err = ffi::secp256k1_ecdsa_signature_serialize_der( ffi::secp256k1_context_no_precomp, - ret.as_mut_ptr(), + ret.get_data_mut_ptr(), &mut len, self.as_ptr(), ); debug_assert!(err == 1); - ret.set_len(len as usize); + ret.set_len(len); } ret } @@ -516,17 +561,8 @@ pub enum Error { InvalidTweak, } -// Passthrough Debug to Display, since errors should be user-visible -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - f.write_str(error::Error::description(self)) - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&error::Error> { None } - - fn description(&self) -> &str { +impl Error { + fn as_str(&self) -> &str { match *self { Error::IncorrectSignature => "secp: signature failed verification", Error::InvalidMessage => "secp: message was not 32 bytes (do you need to hash?)", @@ -539,6 +575,18 @@ impl error::Error for Error { } } +// Passthrough Debug to Display, since errors should be user-visible +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + f.write_str(self.as_str()) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error { + fn description(&self) -> &str { self.as_str() } +} + /// Marker trait for indicating that an instance of `Secp256k1` can be used for signing. pub trait Signing {} @@ -584,6 +632,36 @@ impl PartialEq for Secp256k1 { fn eq(&self, _other: &Secp256k1) -> bool { true } } +impl Default for SerializedSignature { + fn default() -> SerializedSignature { + SerializedSignature { + data: [0u8; 72], + len: 0, + } + } +} + +impl PartialEq for SerializedSignature { + fn eq(&self, other: &SerializedSignature) -> bool { + &self.data[..self.len] == &other.data[..other.len] + } +} + +impl AsRef<[u8]> for SerializedSignature { + fn as_ref(&self) -> &[u8] { + &self.data[..self.len] + } +} + +impl Deref for SerializedSignature { + type Target = [u8]; + fn deref(&self) -> &[u8] { + &self.data[..self.len] + } +} + +impl Eq for SerializedSignature {} + impl Eq for Secp256k1 { } impl Drop for Secp256k1 { diff --git a/src/macros.rs b/src/macros.rs index 4d51403..90f9ee3 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -53,14 +53,14 @@ macro_rules! impl_array_newtype { impl PartialOrd for $thing { #[inline] - fn partial_cmp(&self, other: &$thing) -> Option<::std::cmp::Ordering> { + fn partial_cmp(&self, other: &$thing) -> Option<::core::cmp::Ordering> { self[..].partial_cmp(&other[..]) } } impl Ord for $thing { #[inline] - fn cmp(&self, other: &$thing) -> ::std::cmp::Ordering { + fn cmp(&self, other: &$thing) -> ::core::cmp::Ordering { self[..].cmp(&other[..]) } } @@ -69,8 +69,8 @@ macro_rules! impl_array_newtype { #[inline] fn clone(&self) -> $thing { unsafe { - use std::intrinsics::copy_nonoverlapping; - use std::mem; + use core::intrinsics::copy_nonoverlapping; + use core::mem; let mut ret: $thing = mem::uninitialized(); copy_nonoverlapping(self.as_ptr(), ret.as_mut_ptr(), @@ -80,7 +80,7 @@ macro_rules! impl_array_newtype { } } - impl ::std::ops::Index for $thing { + impl ::core::ops::Index for $thing { type Output = $ty; #[inline] @@ -90,41 +90,41 @@ macro_rules! impl_array_newtype { } } - impl ::std::ops::Index<::std::ops::Range> for $thing { + impl ::core::ops::Index<::core::ops::Range> for $thing { type Output = [$ty]; #[inline] - fn index(&self, index: ::std::ops::Range) -> &[$ty] { + fn index(&self, index: ::core::ops::Range) -> &[$ty] { let &$thing(ref dat) = self; &dat[index] } } - impl ::std::ops::Index<::std::ops::RangeTo> for $thing { + impl ::core::ops::Index<::core::ops::RangeTo> for $thing { type Output = [$ty]; #[inline] - fn index(&self, index: ::std::ops::RangeTo) -> &[$ty] { + fn index(&self, index: ::core::ops::RangeTo) -> &[$ty] { let &$thing(ref dat) = self; &dat[index] } } - impl ::std::ops::Index<::std::ops::RangeFrom> for $thing { + impl ::core::ops::Index<::core::ops::RangeFrom> for $thing { type Output = [$ty]; #[inline] - fn index(&self, index: ::std::ops::RangeFrom) -> &[$ty] { + fn index(&self, index: ::core::ops::RangeFrom) -> &[$ty] { let &$thing(ref dat) = self; &dat[index] } } - impl ::std::ops::Index<::std::ops::RangeFull> for $thing { + impl ::core::ops::Index<::core::ops::RangeFull> for $thing { type Output = [$ty]; #[inline] - fn index(&self, _: ::std::ops::RangeFull) -> &[$ty] { + fn index(&self, _: ::core::ops::RangeFull) -> &[$ty] { let &$thing(ref dat) = self; &dat[..] } @@ -134,8 +134,8 @@ macro_rules! impl_array_newtype { macro_rules! impl_pretty_debug { ($thing:ident) => { - impl ::std::fmt::Debug for $thing { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl ::core::fmt::Debug for $thing { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { try!(write!(f, "{}(", stringify!($thing))); for i in self[..].iter().cloned() { try!(write!(f, "{:02x}", i)); @@ -148,8 +148,8 @@ macro_rules! impl_pretty_debug { macro_rules! impl_raw_debug { ($thing:ident) => { - impl ::std::fmt::Debug for $thing { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl ::core::fmt::Debug for $thing { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { for i in self[..].iter().cloned() { try!(write!(f, "{:02x}", i)); } diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..4e12c90 --- /dev/null +++ b/src/types.rs @@ -0,0 +1,22 @@ +#![allow(non_camel_case_types)] +use core::fmt; + +pub type c_int = i32; +pub type c_uchar = u8; +pub type c_uint = u32; + +/// This is an exact copy of https://doc.rust-lang.org/core/ffi/enum.c_void.html +/// It should be Equivalent to C's void type when used as a pointer. +/// +/// We can replace this with `core::ffi::c_void` once we update the rustc version to >=1.30.0. +#[repr(u8)] +pub enum c_void { + #[doc(hidden)] __variant1, + #[doc(hidden)] __variant2, +} + +impl fmt::Debug for c_void { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("c_void") + } +} \ No newline at end of file