diff --git a/.gitignore b/.gitignore index 3a7539f..03eb4d0 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ Cargo.lock #fuzz fuzz/hfuzz_target fuzz/hfuzz_workspace + +*~ diff --git a/.travis.yml b/.travis.yml index 76f9f0b..6757df4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,5 +14,6 @@ script: - cargo test --verbose - cargo test --verbose --features "serde" - cargo build --verbose --features "fuzztarget" + - cargo build --verbose --no-default-features - if [ "$(rustup show | grep default | grep beta)" != "" ]; then cargo install --force cargo-web && cargo web build --target=asmjs-unknown-emscripten && cargo web test --target=asmjs-unknown-emscripten --nodejs; fi - if [ "$(rustup show | grep default | grep stable)" != "" ]; then cd fuzz && cargo test --verbose && ./travis-fuzz.sh; fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 538a0af..367320d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.6.0 - 2019-07-10 + +* Add `no_std` support, rearrange traits to not depend on `io::Write` + # 0.5.0 - 2019-06-28 * Fix panic when parsing hashes that contain multibyte characters diff --git a/Cargo.toml b/Cargo.toml index d236799..98ac2de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bitcoin_hashes" -version = "0.5.0" +version = "0.6.0" authors = ["Andrew Poelstra "] license = "CC0-1.0" description = "Hash functions used by rust-bitcoin which support rustc 1.14.0" @@ -13,7 +13,8 @@ name = "bitcoin_hashes" path = "src/lib.rs" [features] -default = [] +default = [ "std" ] +std = ["byteorder/std", "serde/std"] unstable = [] # for benchmarking fuzztarget = [] # used by other rust-bitcoin projects to make hashes almost-noops, DON'T USE THIS @@ -21,9 +22,9 @@ fuzztarget = [] # used by other rust-bitcoin projects to make hashes almost-noop serde_test = "1.0" [dependencies] -byteorder = "1.2" +byteorder = { version = "1.2", default-features = false } [dependencies.serde] version = "1.0" optional = true - +default-features = false diff --git a/src/cmp.rs b/src/cmp.rs index be5abe1..6a37119 100644 --- a/src/cmp.rs +++ b/src/cmp.rs @@ -20,26 +20,26 @@ pub fn fixed_time_eq(a: &[u8], b: &[u8]) -> bool { let mut r: u8 = 0; for i in 0..count { - let mut rs = unsafe { ::std::ptr::read_volatile(&r) }; + let mut rs = unsafe { ::core::ptr::read_volatile(&r) }; rs |= lhs[i] ^ rhs[i]; - unsafe { ::std::ptr::write_volatile(&mut r, rs); } + unsafe { ::core::ptr::write_volatile(&mut r, rs); } } { - let mut t = unsafe { ::std::ptr::read_volatile(&r) }; + let mut t = unsafe { ::core::ptr::read_volatile(&r) }; t |= t >> 4; - unsafe { ::std::ptr::write_volatile(&mut r, t); } + unsafe { ::core::ptr::write_volatile(&mut r, t); } } { - let mut t = unsafe { ::std::ptr::read_volatile(&r) }; + let mut t = unsafe { ::core::ptr::read_volatile(&r) }; t |= t >> 2; - unsafe { ::std::ptr::write_volatile(&mut r, t); } + unsafe { ::core::ptr::write_volatile(&mut r, t); } } { - let mut t = unsafe { ::std::ptr::read_volatile(&r) }; + let mut t = unsafe { ::core::ptr::read_volatile(&r) }; t |= t >> 1; - unsafe { ::std::ptr::write_volatile(&mut r, t); } + unsafe { ::core::ptr::write_volatile(&mut r, t); } } - unsafe { (::std::ptr::read_volatile(&r) & 1) == 0 } + unsafe { (::core::ptr::read_volatile(&r) & 1) == 0 } } #[test] diff --git a/src/error.rs b/src/error.rs index 1609c56..da8d587 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,7 +15,7 @@ //! # Error Type //! -use std::{error, fmt}; +use core::fmt; /// Hex decoding error #[derive(Copy, Clone, PartialEq, Eq)] @@ -44,17 +44,3 @@ impl fmt::Display for Error { } } -impl error::Error for Error { - fn cause(&self) -> Option<&error::Error> { - None - } - - fn description(&self) -> &str { - match *self { - Error::InvalidChar(_) => "invalid hex character", - Error::OddLengthString(_) => "odd hex string length", - Error::InvalidLength(_, _) => "bad hex string length", - } - } -} - diff --git a/src/hash160.rs b/src/hash160.rs index 8ad16f6..95c2b7b 100644 --- a/src/hash160.rs +++ b/src/hash160.rs @@ -19,7 +19,7 @@ //! # HASH160 (SHA256 then RIPEMD160) -use std::str; +use core::str; use sha256; use ripemd160; @@ -84,11 +84,10 @@ impl HashTrait for Hash { #[cfg(test)] mod tests { - use std::io::Write; - use hash160; use hex::{FromHex, ToHex}; use Hash; + use HashEngine; #[derive(Clone)] struct Test { @@ -110,12 +109,12 @@ mod tests { 0xb8, 0x5d, 0xf1, 0x69, 0xc1, 0x8a, 0x3c, 0x69, 0x7f, 0xbb, 0x2d, 0xc4, 0xec, 0xef, 0x94, 0xac, 0x55, 0xfe, 0x81, 0x64, 0xcc, 0xf9, 0x82, 0xa1, 0x38, 0x69, 0x1a, - 0x55, 0x19, + 0x55, 0x19, ], output: vec![ 0xda, 0x0b, 0x34, 0x52, 0xb0, 0x6f, 0xe3, 0x41, 0x62, 0x6a, 0xd0, 0x94, 0x9c, 0x18, 0x3f, 0xbd, - 0xa5, 0x67, 0x68, 0x26, + 0xa5, 0x67, 0x68, 0x26, ], output_str: "da0b3452b06fe341626ad0949c183fbda5676826", }, @@ -131,7 +130,7 @@ mod tests { // Hash through engine, checking that we can input byte by byte let mut engine = hash160::Hash::engine(); for ch in test.input { - engine.write_all(&[ch]).expect("write to engine"); + engine.input(&[ch]); } let manual_hash = Hash::from_engine(engine); assert_eq!(hash, manual_hash); @@ -160,18 +159,18 @@ mod tests { #[cfg(all(test, feature="unstable"))] mod benches { - use std::io::Write; use test::Bencher; use hash160; use Hash; + use HashEngine; #[bench] pub fn hash160_10(bh: & mut Bencher) { let mut engine = hash160::Hash::engine(); let bytes = [1u8; 10]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -181,7 +180,7 @@ mod benches { let mut engine = hash160::Hash::engine(); let bytes = [1u8; 1024]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -191,7 +190,7 @@ mod benches { let mut engine = hash160::Hash::engine(); let bytes = [1u8; 65536]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } diff --git a/src/hex.rs b/src/hex.rs index ff9f126..e325a89 100644 --- a/src/hex.rs +++ b/src/hex.rs @@ -15,11 +15,11 @@ //! # Hex encoding and decoding //! -use std::fmt; -use std::str; +use core::{fmt, str}; use {Error, Hash}; /// Trait for objects that can be serialized as hex strings +#[cfg(any(test, feature = "std"))] pub trait ToHex { /// Hex representation of the object fn to_hex(&self) -> String; @@ -39,6 +39,7 @@ pub trait FromHex: Sized { } } +#[cfg(any(test, feature = "std"))] impl ToHex for T { /// Outputs the hash in hexadecimal form fn to_hex(&self) -> String { @@ -152,9 +153,10 @@ pub fn format_hex_reverse(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result { Ok(()) } +#[cfg(any(test, feature = "std"))] impl ToHex for [u8] { fn to_hex(&self) -> String { - use std::fmt::Write; + use core::fmt::Write; let mut ret = String::with_capacity(2 * self.len()); for ch in self { write!(ret, "{:02x}", ch).expect("writing to string"); @@ -163,6 +165,7 @@ impl ToHex for [u8] { } } +#[cfg(any(test, feature = "std"))] impl FromHex for Vec { fn from_byte_iter(iter: I) -> Result where I: Iterator> + @@ -217,9 +220,9 @@ impl_fromhex_array!(512); #[cfg(test)] mod tests { - use std::fmt; + use core::fmt; - use super::{format_hex, format_hex_reverse, ToHex, FromHex}; + use super::{format_hex, format_hex_reverse, FromHex, ToHex}; use Error; #[test] diff --git a/src/hmac.rs b/src/hmac.rs index 6ea8a7c..09a846b 100644 --- a/src/hmac.rs +++ b/src/hmac.rs @@ -19,7 +19,7 @@ //! # HMAC support -use std::{borrow, fmt, io, ops, str}; +use core::{borrow, fmt, ops, str}; #[cfg(feature="serde")] use serde::{Serialize, Serializer, Deserialize, Deserializer}; @@ -99,15 +99,9 @@ impl HashEngine for HmacEngine { } const BLOCK_SIZE: usize = T::Engine::BLOCK_SIZE; -} - -impl io::Write for HmacEngine { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.iengine.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.iengine.flush() + + fn input(&mut self, buf: &[u8]) { + self.iengine.input(buf) } } diff --git a/src/lib.rs b/src/lib.rs index 46a9409..9d215c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,15 +27,18 @@ #![deny(unused_mut)] #![deny(missing_docs)] +#![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="std"))] extern crate core; #[cfg(feature="serde")] extern crate serde; #[cfg(all(test,feature="serde"))] extern crate serde_test; extern crate byteorder; #[macro_use] mod util; #[macro_use] mod serde_macros; +#[cfg(any(test, feature = "std"))] mod std_impls; pub mod error; pub mod hex; pub mod hash160; @@ -48,7 +51,7 @@ pub mod sha256d; pub mod siphash24; pub mod cmp; -use std::{borrow, fmt, hash, io, ops}; +use core::{borrow, fmt, hash, ops}; pub use hmac::{Hmac, HmacEngine}; pub use error::Error; @@ -56,7 +59,7 @@ pub use error::Error; /// A hashing engine which bytes can be serialized into. It is expected /// to implement the `io::Write` trait, but to never return errors under /// any conditions. -pub trait HashEngine: Clone + io::Write { +pub trait HashEngine: Clone { /// Byte array representing the internal state of the hash engine type MidState; @@ -67,11 +70,8 @@ pub trait HashEngine: Clone + io::Write { /// Length of the hash's internal block size, in bytes const BLOCK_SIZE: usize; - /// Add data to the hash engine without any error return type to deal with - #[inline(always)] - fn input(&mut self, data: &[u8]) { - self.write_all(data).expect("hash returned error"); - } + /// Add data to the hash engine + fn input(&mut self, data: &[u8]); } /// Trait which applies to hashes of all types @@ -82,7 +82,7 @@ pub trait Hash: Copy + Clone + PartialEq + Eq + Default + PartialOrd + Ord + ops::Index, Output = [u8]> + ops::Index, Output = [u8]> + ops::Index + - hex::ToHex + borrow::Borrow<[u8]> + borrow::Borrow<[u8]> { /// A hashing engine which bytes can be serialized into. It is expected /// to implement the `io::Write` trait, and to never return errors under @@ -106,10 +106,8 @@ pub trait Hash: Copy + Clone + PartialEq + Eq + Default + PartialOrd + Ord + /// Hashes some bytes fn hash(data: &[u8]) -> Self { - use std::io::Write; - let mut engine = Self::engine(); - engine.write_all(data).unwrap(); + engine.input(data); Self::from_engine(engine) } diff --git a/src/ripemd160.rs b/src/ripemd160.rs index 36bc493..a398250 100644 --- a/src/ripemd160.rs +++ b/src/ripemd160.rs @@ -20,7 +20,7 @@ //! # RIPEMD160 use byteorder::{ByteOrder, LittleEndian}; -use std::str; +use core::{cmp, str}; use HashEngine as EngineTrait; use Hash as HashTrait; @@ -35,8 +35,6 @@ pub struct HashEngine { length: usize, } -write_impl!(HashEngine); - impl Clone for HashEngine { fn clone(&self) -> HashEngine { HashEngine { @@ -65,6 +63,8 @@ impl EngineTrait for HashEngine { } const BLOCK_SIZE: usize = 64; + + engine_input_impl!(); } /// Output of the RIPEMD160 hash function @@ -99,22 +99,21 @@ impl HashTrait for Hash { #[cfg(not(feature = "fuzztarget"))] fn from_engine(mut e: HashEngine) -> Hash { - use std::io::Write; - use byteorder::WriteBytesExt; - // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining let data_len = e.length as u64; let zeroes = [0; BLOCK_SIZE - 8]; - e.write_all(&[0x80]).unwrap(); + e.input(&[0x80]); if e.length % BLOCK_SIZE > zeroes.len() { - e.write_all(&zeroes).unwrap(); + e.input(&zeroes); } let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); - e.write_all(&zeroes[..pad_length]).unwrap(); + e.input(&zeroes[..pad_length]); debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); - e.write_u64::(8 * data_len).unwrap(); + let mut len_buf = [0; 8]; + LittleEndian::write_u64(&mut len_buf, 8 * data_len); + e.input(&len_buf); debug_assert_eq!(e.length % BLOCK_SIZE, 0); Hash(e.midstate()) @@ -440,11 +439,10 @@ impl HashEngine { #[cfg(test)] mod tests { - use std::io::Write; - use ripemd160; use hex::{FromHex, ToHex}; use Hash; + use HashEngine; #[derive(Clone)] struct Test { @@ -515,7 +513,7 @@ mod tests { // Hash through engine, checking that we can input byte by byte let mut engine = ripemd160::Hash::engine(); for ch in test.input.as_bytes() { - engine.write_all(&[*ch]).expect("write to engine"); + engine.input(&[*ch]); } let manual_hash = ripemd160::Hash::from_engine(engine); assert_eq!(hash, manual_hash); @@ -544,18 +542,18 @@ mod tests { #[cfg(all(test, feature="unstable"))] mod benches { - use std::io::Write; use test::Bencher; use ripemd160; use Hash; + use HashEngine; #[bench] pub fn ripemd160_10(bh: & mut Bencher) { let mut engine = ripemd160::Hash::engine(); let bytes = [1u8; 10]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -565,7 +563,7 @@ mod benches { let mut engine = ripemd160::Hash::engine(); let bytes = [1u8; 1024]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -575,7 +573,7 @@ mod benches { let mut engine = ripemd160::Hash::engine(); let bytes = [1u8; 65536]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } diff --git a/src/sha1.rs b/src/sha1.rs index 1c578a1..a2ed6a1 100644 --- a/src/sha1.rs +++ b/src/sha1.rs @@ -15,7 +15,7 @@ //! # SHA1 use byteorder::{ByteOrder, BigEndian}; -use std::str; +use core::{cmp, str}; use HashEngine as EngineTrait; use Hash as HashTrait; @@ -30,8 +30,6 @@ pub struct HashEngine { length: usize, } -write_impl!(HashEngine); - impl Clone for HashEngine { fn clone(&self) -> HashEngine { HashEngine { @@ -51,7 +49,10 @@ impl EngineTrait for HashEngine { ret } + const BLOCK_SIZE: usize = 64; + + engine_input_impl!(); } /// Output of the SHA1 hash function @@ -85,22 +86,21 @@ impl HashTrait for Hash { } fn from_engine(mut e: HashEngine) -> Hash { - use std::io::Write; - use byteorder::WriteBytesExt; - // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining let data_len = e.length as u64; let zeroes = [0; BLOCK_SIZE - 8]; - e.write_all(&[0x80]).unwrap(); + e.input(&[0x80]); if e.length % BLOCK_SIZE > zeroes.len() { - e.write_all(&zeroes).unwrap(); + e.input(&zeroes); } let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); - e.write_all(&zeroes[..pad_length]).unwrap(); + e.input(&zeroes[..pad_length]); debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); - - e.write_u64::(8 * data_len).unwrap(); + + let mut len_buf = [0; 8]; + BigEndian::write_u64(&mut len_buf, 8 * data_len); + e.input(&len_buf); debug_assert_eq!(e.length % BLOCK_SIZE, 0); Hash(e.midstate()) @@ -171,11 +171,10 @@ impl HashEngine { #[cfg(test)] mod tests { - use std::io::Write; - use sha1; use hex::{FromHex, ToHex}; use Hash; + use HashEngine; #[derive(Clone)] struct Test { @@ -233,7 +232,7 @@ mod tests { // Hash through engine, checking that we can input byte by byte let mut engine = sha1::Hash::engine(); for ch in test.input.as_bytes() { - engine.write_all(&[*ch]).expect("write to engine"); + engine.input(&[*ch]); } let manual_hash = sha1::Hash::from_engine(engine); assert_eq!(hash, manual_hash); @@ -262,18 +261,18 @@ mod tests { #[cfg(all(test, feature="unstable"))] mod benches { - use std::io::Write; use test::Bencher; use sha1; use Hash; + use HashEngine; #[bench] pub fn sha1_10(bh: & mut Bencher) { let mut engine = sha1::Hash::engine(); let bytes = [1u8; 10]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -283,7 +282,7 @@ mod benches { let mut engine = sha1::Hash::engine(); let bytes = [1u8; 1024]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -293,7 +292,7 @@ mod benches { let mut engine = sha1::Hash::engine(); let bytes = [1u8; 65536]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } diff --git a/src/sha256.rs b/src/sha256.rs index 98f7bfb..c1205db 100644 --- a/src/sha256.rs +++ b/src/sha256.rs @@ -15,7 +15,7 @@ //! # SHA256 use byteorder::{ByteOrder, BigEndian}; -use std::str; +use core::{cmp, str}; use hex; use HashEngine as EngineTrait; @@ -31,8 +31,6 @@ pub struct HashEngine { length: usize, } -write_impl!(HashEngine); - impl Clone for HashEngine { fn clone(&self) -> HashEngine { HashEngine { @@ -61,6 +59,8 @@ impl EngineTrait for HashEngine { } const BLOCK_SIZE: usize = 64; + + engine_input_impl!(); } /// Output of the SHA256 hash function @@ -95,22 +95,21 @@ impl HashTrait for Hash { #[cfg(not(feature = "fuzztarget"))] fn from_engine(mut e: HashEngine) -> Hash { - use std::io::Write; - use byteorder::WriteBytesExt; - // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining let data_len = e.length as u64; let zeroes = [0; BLOCK_SIZE - 8]; - e.write_all(&[0x80]).unwrap(); + e.input(&[0x80]); if e.length % BLOCK_SIZE > zeroes.len() { - e.write_all(&zeroes).unwrap(); + e.input(&zeroes); } let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); - e.write_all(&zeroes[..pad_length]).unwrap(); + e.input(&zeroes[..pad_length]); debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); - e.write_u64::(8 * data_len).unwrap(); + let mut len_buf = [0; 8]; + BigEndian::write_u64(&mut len_buf, 8 * data_len); + e.input(&len_buf); debug_assert_eq!(e.length % BLOCK_SIZE, 0); Hash(e.midstate().into_inner()) @@ -331,8 +330,6 @@ impl HashEngine { #[cfg(test)] mod tests { - use std::io::Write; - use sha256; use hex::{FromHex, ToHex}; use {Hash, HashEngine}; @@ -390,7 +387,7 @@ mod tests { // Hash through engine, checking that we can input byte by byte let mut engine = sha256::Hash::engine(); for ch in test.input.as_bytes() { - engine.write_all(&[*ch]).expect("write to engine"); + engine.input(&[*ch]); } let manual_hash = sha256::Hash::from_engine(engine); assert_eq!(hash, manual_hash); @@ -419,7 +416,7 @@ mod tests { 0x0b, 0xcf, 0xe0, 0xe5, 0x4e, 0x6c, 0xc7, 0xd3, 0x4f, 0x4f, 0x7c, 0x1d, 0xf0, 0xb0, 0xf5, 0x03, 0xf2, 0xf7, 0x12, 0x91, 0x2a, 0x06, 0x05, 0xb4, - 0x14, 0xed, 0x33, 0x7f, 0x7f, 0x03, 0x2e, 0x03, + 0x14, 0xed, 0x33, 0x7f, 0x7f, 0x03, 0x2e, 0x03, ]) ); } @@ -493,18 +490,18 @@ mod tests { #[cfg(all(test, feature="unstable"))] mod benches { - use std::io::Write; use test::Bencher; use sha256; use Hash; + use HashEngine; #[bench] pub fn sha256_10(bh: & mut Bencher) { let mut engine = sha256::Hash::engine(); let bytes = [1u8; 10]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -514,7 +511,7 @@ mod benches { let mut engine = sha256::Hash::engine(); let bytes = [1u8; 1024]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -524,7 +521,7 @@ mod benches { let mut engine = sha256::Hash::engine(); let bytes = [1u8; 65536]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } diff --git a/src/sha256d.rs b/src/sha256d.rs index 645064b..66e2f94 100644 --- a/src/sha256d.rs +++ b/src/sha256d.rs @@ -14,7 +14,7 @@ //! # SHA256d -use std::str; +use core::str; use sha256; use Hash as HashTrait; @@ -80,11 +80,10 @@ impl HashTrait for Hash { #[cfg(test)] mod tests { - use std::io::Write; - use sha256d; use hex::{FromHex, ToHex}; use Hash; + use HashEngine; #[derive(Clone)] struct Test { @@ -119,7 +118,7 @@ input: &'static str, // Hash through engine, checking that we can input byte by byte let mut engine = sha256d::Hash::engine(); for ch in test.input.as_bytes() { - engine.write_all(&[*ch]).expect("write to engine"); + engine.input(&[*ch]); } let manual_hash = sha256d::Hash::from_engine(engine); assert_eq!(hash, manual_hash); @@ -147,18 +146,18 @@ input: &'static str, #[cfg(all(test, feature="unstable"))] mod benches { - use std::io::Write; use test::Bencher; use sha256d; use Hash; + use HashEngine; #[bench] pub fn sha256d_10(bh: & mut Bencher) { let mut engine = sha256d::Hash::engine(); let bytes = [1u8; 10]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -168,7 +167,7 @@ mod benches { let mut engine = sha256d::Hash::engine(); let bytes = [1u8; 1024]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -178,9 +177,8 @@ mod benches { let mut engine = sha256d::Hash::engine(); let bytes = [1u8; 65536]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } - } diff --git a/src/sha512.rs b/src/sha512.rs index 1c32d68..22b2fc1 100644 --- a/src/sha512.rs +++ b/src/sha512.rs @@ -19,7 +19,7 @@ //! # SHA512 -use std::{hash, str}; +use core::{cmp, hash, str}; use byteorder::{ByteOrder, BigEndian}; @@ -36,8 +36,6 @@ pub struct HashEngine { buffer: [u8; BLOCK_SIZE], } -write_impl!(HashEngine); - impl Clone for HashEngine { fn clone(&self) -> HashEngine { HashEngine { @@ -66,6 +64,8 @@ impl EngineTrait for HashEngine { } const BLOCK_SIZE: usize = 128; + + engine_input_impl!(); } /// Output of the SHA256 hash function @@ -95,16 +95,14 @@ impl Default for Hash { } } -use std::cmp::Ordering; - impl PartialOrd for Hash { - fn partial_cmp(&self, other: &Hash) -> Option { + fn partial_cmp(&self, other: &Hash) -> Option { (&self.0).partial_cmp(&other.0) } } impl Ord for Hash { - fn cmp(&self, other: &Hash) -> Ordering { + fn cmp(&self, other: &Hash) -> cmp::Ordering { (&self.0).cmp(&other.0) } } @@ -146,23 +144,22 @@ impl HashTrait for Hash { #[cfg(not(feature = "fuzztarget"))] fn from_engine(mut e: HashEngine) -> Hash { - use std::io::Write; - use byteorder::WriteBytesExt; - // pad buffer with a single 1-bit then all 0s, until there are exactly 16 bytes remaining let data_len = e.length as u64; let zeroes = [0; BLOCK_SIZE - 16]; - e.write_all(&[0x80]).unwrap(); + e.input(&[0x80]); if e.length % BLOCK_SIZE > zeroes.len() { - e.write_all(&zeroes).unwrap(); + e.input(&zeroes); } let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); - e.write_all(&zeroes[..pad_length]).unwrap(); + e.input(&zeroes[..pad_length]); debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); - e.write_u64::(0).unwrap(); - e.write_u64::(8 * data_len).unwrap(); + let mut len_buf = [0; 8]; + e.input(&len_buf); + BigEndian::write_u64(&mut len_buf, 8 * data_len); + e.input(&len_buf); debug_assert_eq!(e.length % BLOCK_SIZE, 0); Hash(e.midstate()) @@ -333,11 +330,10 @@ impl HashEngine { #[cfg(test)] mod tests { - use std::io::Write; - use sha512; use hex::{FromHex, ToHex}; use Hash; + use HashEngine; #[derive(Clone)] struct Test { @@ -404,7 +400,7 @@ mod tests { // Hash through engine, checking that we can input byte by byte let mut engine = sha512::Hash::engine(); for ch in test.input.as_bytes() { - engine.write_all(&[*ch]).expect("write to engine"); + engine.input(&[*ch]); } let manual_hash = sha512::Hash::from_engine(engine); assert_eq!(hash, manual_hash); @@ -442,18 +438,18 @@ mod tests { #[cfg(all(test, feature="unstable"))] mod benches { - use std::io::Write; use test::Bencher; use sha512; use Hash; + use HashEngine; #[bench] pub fn sha512_10(bh: & mut Bencher) { let mut engine = sha512::Hash::engine(); let bytes = [1u8; 10]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -463,7 +459,7 @@ mod benches { let mut engine = sha512::Hash::engine(); let bytes = [1u8; 1024]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -473,7 +469,7 @@ mod benches { let mut engine = sha512::Hash::engine(); let bytes = [1u8; 65536]; bh.iter( || { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } diff --git a/src/siphash24.rs b/src/siphash24.rs index 7bd3915..83bb81b 100644 --- a/src/siphash24.rs +++ b/src/siphash24.rs @@ -19,8 +19,7 @@ //! # SipHash 2-4 -use std::io::Write; -use std::{cmp, mem, ptr, str}; +use core::{cmp, mem, ptr, str}; use byteorder::{ByteOrder, LittleEndian}; @@ -135,14 +134,17 @@ impl HashEngine { } } -impl Write for HashEngine { - #[inline] - fn flush(&mut self) -> ::std::io::Result<()> { - Ok(()) +impl EngineTrait for HashEngine { + type MidState = State; + + fn midstate(&self) -> State { + self.state.clone() } + const BLOCK_SIZE: usize = 8; + #[inline] - fn write(&mut self, msg: &[u8]) -> ::std::io::Result { + fn input(&mut self, msg: &[u8]) { let length = msg.len(); self.length += length; @@ -153,7 +155,7 @@ impl Write for HashEngine { self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail); if length < needed { self.ntail += length; - return Ok(length); + return; } else { self.state.v3 ^= self.tail; HashEngine::c_rounds(&mut self.state); @@ -179,27 +181,9 @@ impl Write for HashEngine { self.tail = unsafe { u8to64_le(msg, i, left) }; self.ntail = left; - - Ok(length) } } -impl EngineTrait for HashEngine { - type MidState = State; - - #[cfg(not(feature = "fuzztarget"))] - fn midstate(&self) -> State { - self.state.clone() - } - - #[cfg(feature = "fuzztarget")] - fn midstate(&self) -> State { - self.state.clone() - } - - const BLOCK_SIZE: usize = 8; -} - /// Output of the SipHash24 hash function. #[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] pub struct Hash([u8; 8]); @@ -222,14 +206,14 @@ impl Hash { /// Hash the given data with an engine with the provided keys. pub fn hash_with_keys(k0: u64, k1: u64, data: &[u8]) -> Hash { let mut engine = HashEngine::with_keys(k0, k1); - engine.write_all(data).unwrap(); + engine.input(data); Hash::from_engine(engine) } /// Hash the given data directly to u64 with an engine with the provided keys. pub fn hash_to_u64_with_keys(k0: u64, k1: u64, data: &[u8]) -> u64 { let mut engine = HashEngine::with_keys(k0, k1); - engine.write_all(data).unwrap(); + engine.input(data); Hash::from_engine_to_u64(engine) } @@ -421,18 +405,18 @@ mod tests { #[cfg(all(test, feature = "unstable"))] mod benches { - use std::io::Write; use test::Bencher; use siphash24; use Hash; + use HashEngine; #[bench] pub fn siphash24_1ki(bh: &mut Bencher) { let mut engine = siphash24::Hash::engine(); let bytes = [1u8; 1024]; bh.iter(|| { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } @@ -442,7 +426,7 @@ mod benches { let mut engine = siphash24::Hash::engine(); let bytes = [1u8; 65536]; bh.iter(|| { - engine.write_all(&bytes).expect("write"); + engine.input(&bytes); }); bh.bytes = bytes.len() as u64; } diff --git a/src/std_impls.rs b/src/std_impls.rs new file mode 100644 index 0000000..c03f8fb --- /dev/null +++ b/src/std_impls.rs @@ -0,0 +1,161 @@ +// Bitcoin Hashes Library +// Written in 2019 by +// Andrew Poelstra +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! `std` Impls +//! +//! impls of traits defined in `std` and not `core` + +use std::{error, io}; + +use {sha1, sha256, sha512, ripemd160, siphash24}; +use HashEngine; +use Error; + +impl error::Error for Error { + fn cause(&self) -> Option<&error::Error> { None } + fn description(&self) -> &str { "`std::error::description` is deprecated" } +} + +impl io::Write for sha1::HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { + self.input(buf); + Ok(buf.len()) + } +} + +impl io::Write for sha256::HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { + self.input(buf); + Ok(buf.len()) + } +} + +impl io::Write for sha512::HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { + self.input(buf); + Ok(buf.len()) + } +} + +impl io::Write for ripemd160::HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { + self.input(buf); + Ok(buf.len()) + } +} + +impl io::Write for siphash24::HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { + self.input(buf); + Ok(buf.len()) + } +} + +#[cfg(test)] +mod tests { + use std::io::Write; + + use {sha1, sha256, sha256d, sha512, ripemd160, hash160, siphash24}; + use Hash; + + macro_rules! write_test { + ($mod:ident, $exp_empty:expr, $exp_256:expr, $exp_64k:expr,) => { + #[test] + fn $mod() { + let mut engine = $mod::Hash::engine(); + engine.write_all(&[]).unwrap(); + assert_eq!( + format!("{}", $mod::Hash::from_engine(engine)), + $exp_empty + ); + + let mut engine = $mod::Hash::engine(); + engine.write_all(&[1; 256]).unwrap(); + assert_eq!( + format!("{}", $mod::Hash::from_engine(engine)), + $exp_256 + ); + + let mut engine = $mod::Hash::engine(); + engine.write_all(&[99; 64000]).unwrap(); + assert_eq!( + format!("{}", $mod::Hash::from_engine(engine)), + $exp_64k + ); + } + } + } + + write_test!( + sha1, + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "ac458b067c6b021c7e9358229b636e9d1e4cb154", + "e4b66838f9f7b6f91e5be32a02ae78094df402e7", + ); + + write_test!( + sha256, + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "2661920f2409dd6c8adeb0c44972959f232b6429afa913845d0fd95e7e768234", + "5c5e904f5d4fd587c7a906bf846e08a927286f388c54c39213a4884695271bbc", + ); + + write_test!( + sha256d, + "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d", + "374000d830c75d10d9417e493a7652920f30efbd300e3fb092f24c28c20baf64", + "0050d4148ad7a0437ca0643fad5bf4614cd95d9ba21fde52370b37dcc3f03307", + ); + + write_test!( + sha512, + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce\ + 47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", + "57ecf739d3a7ca647639adae80a05f4f361304bfcbfa1ceba93296b096e74287\ + 45fc10c142cecdd3bb587a3dba598c072f6f78b31cc0a06a3da0105ee51f75d6", + "dd28f78c53f3bc9bd0c2dca9642a1ad402a70412f985c1f6e54fadb98ce9c458\ + 4761df8d04ed04bb734ba48dd2106bb9ea54524f1394cdd18e6da3166e71c3ee", + ); + + write_test!( + ripemd160, + "9c1185a5c5e9fc54612808977ee8f548b2258d31", + "e571a1ca5b780aa52bafdb9ec852544ffca418ba", + "ddd2ecce739e823629c7d46ab18918e9c4a51c75", + ); + + write_test!( + hash160, + "b472a266d0bd89c13706a4132ccfb16f7c3b9fcb", + "671356a1a874695ad3bc20cae440f4360835bd5a", + "a9608c952c8dbcc20c53803d2ca5ad31d64d9313", + ); + + write_test!( + siphash24, + "d70077739d4b921e", + "3a3ccefde9b5b1e3", + "ce456e4e4ecbc5bf", + ); +} diff --git a/src/util.rs b/src/util.rs index fcc3cea..47022a3 100644 --- a/src/util.rs +++ b/src/util.rs @@ -23,8 +23,8 @@ macro_rules! circular_lshift64 ( macro_rules! hex_fmt_impl( ($imp:ident, $ty:ident) => ( - impl ::std::fmt::$imp for $ty { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl ::core::fmt::$imp for $ty { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use hex::{format_hex, format_hex_reverse}; if $ty::DISPLAY_BACKWARD { format_hex_reverse(&self.0, f) @@ -38,37 +38,37 @@ macro_rules! hex_fmt_impl( macro_rules! index_impl( ($ty:ty) => ( - impl ::std::ops::Index for $ty { + impl ::core::ops::Index for $ty { type Output = u8; fn index(&self, index: usize) -> &u8 { &self.0[index] } } - impl ::std::ops::Index<::std::ops::Range> for $ty { + impl ::core::ops::Index<::core::ops::Range> for $ty { type Output = [u8]; - fn index(&self, index: ::std::ops::Range) -> &[u8] { + fn index(&self, index: ::core::ops::Range) -> &[u8] { &self.0[index] } } - impl ::std::ops::Index<::std::ops::RangeFrom> for $ty { + impl ::core::ops::Index<::core::ops::RangeFrom> for $ty { type Output = [u8]; - fn index(&self, index: ::std::ops::RangeFrom) -> &[u8] { + fn index(&self, index: ::core::ops::RangeFrom) -> &[u8] { &self.0[index] } } - impl ::std::ops::Index<::std::ops::RangeTo> for $ty { + impl ::core::ops::Index<::core::ops::RangeTo> for $ty { type Output = [u8]; - fn index(&self, index: ::std::ops::RangeTo) -> &[u8] { + fn index(&self, index: ::core::ops::RangeTo) -> &[u8] { &self.0[index] } } - impl ::std::ops::Index<::std::ops::RangeFull> for $ty { + impl ::core::ops::Index<::core::ops::RangeFull> for $ty { type Output = [u8]; - fn index(&self, index: ::std::ops::RangeFull) -> &[u8] { + fn index(&self, index: ::core::ops::RangeFull) -> &[u8] { &self.0[index] } } @@ -77,19 +77,19 @@ macro_rules! index_impl( macro_rules! borrow_slice_impl( ($ty:ty) => ( - impl ::std::borrow::Borrow<[u8]> for $ty { + impl ::core::borrow::Borrow<[u8]> for $ty { fn borrow(&self) -> &[u8] { &self[..] } } - impl ::std::convert::AsRef<[u8]> for $ty { + impl ::core::convert::AsRef<[u8]> for $ty { fn as_ref(&self) -> &[u8] { &self[..] } } - impl ::std::ops::Deref for $ty { + impl ::core::ops::Deref for $ty { type Target = [u8]; fn deref(&self) -> &Self::Target { @@ -99,36 +99,31 @@ macro_rules! borrow_slice_impl( ) ); -macro_rules! write_impl( - ($ty:ty) => ( - impl ::std::io::Write for $ty { - fn flush(&mut self) -> ::std::io::Result<()> { - Ok(()) - } - - #[cfg(not(feature = "fuzztarget"))] - fn write(&mut self, inp: &[u8]) -> ::std::io::Result { - let buf_idx = self.length % ::BLOCK_SIZE; - let rem_len = ::BLOCK_SIZE - buf_idx; - let write_len = ::std::cmp::min(rem_len, inp.len()); - - self.buffer[buf_idx..buf_idx + write_len].copy_from_slice(&inp[..write_len]); +macro_rules! engine_input_impl( + () => ( + #[cfg(not(feature = "fuzztarget"))] + fn input(&mut self, mut inp: &[u8]) { + while !inp.is_empty() { + let buf_idx = self.length % ::BLOCK_SIZE; + let rem_len = ::BLOCK_SIZE - buf_idx; + let write_len = cmp::min(rem_len, inp.len()); + + self.buffer[buf_idx..buf_idx + write_len] + .copy_from_slice(&inp[..write_len]); self.length += write_len; - if self.length % ::BLOCK_SIZE == 0 { + if self.length % ::BLOCK_SIZE == 0 { self.process_block(); } - - Ok(write_len) + inp = &inp[write_len..]; } + } - #[cfg(feature = "fuzztarget")] - fn write(&mut self, inp: &[u8]) -> ::std::io::Result { - for c in inp { - self.buffer[0] ^= *c; - } - self.length += inp.len(); - Ok(inp.len()) + #[cfg(feature = "fuzztarget")] + fn input(&mut self, inp: &[u8]) { + for c in inp { + self.buffer[0] ^= *c; } + self.length += inp.len(); } ) );