From 11ce86681f9901439d03ac723d494a955e78d939 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 18 Feb 2019 14:30:39 +0200 Subject: [PATCH 1/6] Replaced std with core, and made std::error::Error optional through feature --- Cargo.toml | 5 ++++- src/ecdh.rs | 2 +- src/key.rs | 2 +- src/lib.rs | 24 +++++++++++------------- src/macros.rs | 34 +++++++++++++++++----------------- 5 files changed, 34 insertions(+), 33 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f114fef9b..8ada2dec6 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 aec2dbcda..35de210eb 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/key.rs b/src/key.rs index 2d90c2e84..ff1d9a1e8 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 5cb3d9bba..89c61f888 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,15 +133,17 @@ #![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; @@ -152,7 +154,7 @@ pub mod key; pub use key::SecretKey; pub use key::PublicKey; -use std::marker::PhantomData; +use core::marker::PhantomData; /// A tag used for recovering the public key from a compact signature #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -519,15 +521,7 @@ pub enum 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(error::Error::description(self)) - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&error::Error> { None } - - fn description(&self) -> &str { - match *self { + let res = match *self { Error::IncorrectSignature => "secp: signature failed verification", Error::InvalidMessage => "secp: message was not 32 bytes (do you need to hash?)", Error::InvalidPublicKey => "secp: malformed public key", @@ -535,10 +529,14 @@ impl error::Error for Error { Error::InvalidSecretKey => "secp: malformed or out-of-range secret key", Error::InvalidRecoveryId => "secp: bad recovery id", Error::InvalidTweak => "secp: bad tweak", - } + }; + f.write_str(res) } } +#[cfg(feature = "std")] +impl std::error::Error for Error {} + /// Marker trait for indicating that an instance of `Secp256k1` can be used for signing. pub trait Signing {} diff --git a/src/macros.rs b/src/macros.rs index 4d51403d7..90f9ee31b 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)); } From ab8066eb1a265c9dbf636da0f4be8993aff407b1 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 18 Feb 2019 14:31:30 +0200 Subject: [PATCH 2/6] Replaced the std::os::raw c types with types.rs --- src/ffi.rs | 8 +++++--- src/lib.rs | 1 + src/types.rs | 5 +++++ 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/types.rs diff --git a/src/ffi.rs b/src/ffi.rs index a7633b5d4..3cdffa3fe 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -16,9 +16,11 @@ //! # 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 core::ffi::c_void; +use crate::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/lib.rs b/src/lib.rs index 89c61f888..52a4e1372 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -147,6 +147,7 @@ use core::{fmt, ptr, str}; #[macro_use] mod macros; +mod types; pub mod constants; pub mod ecdh; pub mod ffi; diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 000000000..9bcb3b91b --- /dev/null +++ b/src/types.rs @@ -0,0 +1,5 @@ +#![allow(non_camel_case_types)] +pub type c_int = i32; +pub type c_uchar = u8; +pub type c_uint = u32; +pub use core::ffi::c_void; \ No newline at end of file From 6871567a1c698a1ad72adc6753d2ef2f375283cc Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 18 Feb 2019 14:42:06 +0200 Subject: [PATCH 3/6] Updated travis.yml to test no-std too --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index c74203995..3cc8800d0 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 From e98975a1c00a6de979a6abf9a5eb3b5d28ff981c Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 18 Feb 2019 15:24:48 +0200 Subject: [PATCH 4/6] Added backwards support without the crate keyword --- src/ffi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ffi.rs b/src/ffi.rs index 3cdffa3fe..2bba67086 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -18,7 +18,7 @@ //! not be needed for most users. use core::{mem, hash}; use core::ffi::c_void; -use crate::types::*; +use types::*; // use std::os::raw::{c_int, c_uchar, c_uint, c_void}; From 312b9a55fc2599696dc3be147d466ea23201382c Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 18 Feb 2019 16:47:11 +0200 Subject: [PATCH 5/6] Added Error::description copied c_void impl from core::ffi::c_void --- src/ffi.rs | 1 - src/lib.rs | 21 ++++++++++++++------- src/types.rs | 19 ++++++++++++++++++- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 2bba67086..f173300c7 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -17,7 +17,6 @@ //! Direct bindings to the underlying C library functions. These should //! not be needed for most users. use core::{mem, hash}; -use core::ffi::c_void; use types::*; // use std::os::raw::{c_int, c_uchar, c_uint, c_void}; diff --git a/src/lib.rs b/src/lib.rs index 52a4e1372..c65d168b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -519,10 +519,9 @@ 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> { - let res = match *self { +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?)", Error::InvalidPublicKey => "secp: malformed public key", @@ -530,13 +529,21 @@ impl fmt::Display for Error { Error::InvalidSecretKey => "secp: malformed or out-of-range secret key", Error::InvalidRecoveryId => "secp: bad recovery id", Error::InvalidTweak => "secp: bad tweak", - }; - f.write_str(res) + } + } +} + +// 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 {} +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 {} diff --git a/src/types.rs b/src/types.rs index 9bcb3b91b..4e12c90a1 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +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; -pub use core::ffi::c_void; \ No newline at end of file + +/// 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 From dfcf74f9d01c2d796d219af94362d8c65dda229e Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Thu, 11 Apr 2019 21:47:20 +0300 Subject: [PATCH 6/6] Added a new struct for the DER serialized signature --- src/lib.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c65d168b3..1a25c9e93 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -156,6 +156,7 @@ pub mod key; pub use key::SecretKey; pub use key::PublicKey; 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)] @@ -165,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) @@ -231,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 @@ -337,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 } @@ -590,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 {