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

Add no-std support #100

Merged
merged 6 commits into from
May 10, 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 .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ path = "src/lib.rs"

[features]
unstable = []
default = []
default = ["std"]
fuzztarget = []
std = []

[dev-dependencies]
rand = "0.6"
Expand All @@ -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
2 changes: 1 addition & 1 deletion src/ecdh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
//! Support for shared secret computations
//!

use std::{ops, ptr};
use core::{ops, ptr};

use key::{SecretKey, PublicKey};
use ffi;
Expand Down
7 changes: 4 additions & 3 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
116 changes: 97 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,26 +133,30 @@
#![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;
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)]
Expand All @@ -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,
}
apoelstra marked this conversation as resolved.
Show resolved Hide resolved

impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
Expand Down Expand Up @@ -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()
}
real-or-random marked this conversation as resolved.
Show resolved Hide resolved

/// 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) {
apoelstra marked this conversation as resolved.
Show resolved Hide resolved
self.len = len;
}

/// Convert the serialized signature into the Signature struct.
/// (This DER deserializes it)
pub fn to_signature(&self) -> Result<Signature, Error> {
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
Expand Down Expand Up @@ -334,18 +379,18 @@ impl Signature {

#[inline]
/// Serializes the signature in DER format
pub fn serialize_der(&self) -> Vec<u8> {
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
}
Expand Down Expand Up @@ -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?)",
Expand All @@ -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())
}
}

real-or-random marked this conversation as resolved.
Show resolved Hide resolved
#[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 {}

Expand Down Expand Up @@ -584,6 +632,36 @@ impl<C> PartialEq for Secp256k1<C> {
fn eq(&self, _other: &Secp256k1<C>) -> 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]
}
}
real-or-random marked this conversation as resolved.
Show resolved Hide resolved

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<C> Eq for Secp256k1<C> { }

impl<C> Drop for Secp256k1<C> {
Expand Down
34 changes: 17 additions & 17 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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[..])
}
}
Expand All @@ -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(),
Expand All @@ -80,7 +80,7 @@ macro_rules! impl_array_newtype {
}
}

impl ::std::ops::Index<usize> for $thing {
impl ::core::ops::Index<usize> for $thing {
type Output = $ty;

#[inline]
Expand All @@ -90,41 +90,41 @@ macro_rules! impl_array_newtype {
}
}

impl ::std::ops::Index<::std::ops::Range<usize>> for $thing {
impl ::core::ops::Index<::core::ops::Range<usize>> for $thing {
type Output = [$ty];

#[inline]
fn index(&self, index: ::std::ops::Range<usize>) -> &[$ty] {
fn index(&self, index: ::core::ops::Range<usize>) -> &[$ty] {
let &$thing(ref dat) = self;
&dat[index]
}
}

impl ::std::ops::Index<::std::ops::RangeTo<usize>> for $thing {
impl ::core::ops::Index<::core::ops::RangeTo<usize>> for $thing {
type Output = [$ty];

#[inline]
fn index(&self, index: ::std::ops::RangeTo<usize>) -> &[$ty] {
fn index(&self, index: ::core::ops::RangeTo<usize>) -> &[$ty] {
let &$thing(ref dat) = self;
&dat[index]
}
}

impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for $thing {
impl ::core::ops::Index<::core::ops::RangeFrom<usize>> for $thing {
type Output = [$ty];

#[inline]
fn index(&self, index: ::std::ops::RangeFrom<usize>) -> &[$ty] {
fn index(&self, index: ::core::ops::RangeFrom<usize>) -> &[$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[..]
}
Expand All @@ -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));
Expand All @@ -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));
}
Expand Down
22 changes: 22 additions & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
@@ -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")
}
}