From ec648ebb1c9ea5dfce363eeb487bb335c2d233e9 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Fri, 5 Jul 2019 16:53:05 +0000 Subject: [PATCH 1/9] add std_impls module, for now with only unit tests --- .gitignore | 2 + src/lib.rs | 1 + src/std_impls.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 src/std_impls.rs 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/src/lib.rs b/src/lib.rs index 46a9409..06bdd54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,7 @@ extern crate byteorder; #[macro_use] mod util; #[macro_use] mod serde_macros; +mod std_impls; pub mod error; pub mod hex; pub mod hash160; diff --git a/src/std_impls.rs b/src/std_impls.rs new file mode 100644 index 0000000..0221c4c --- /dev/null +++ b/src/std_impls.rs @@ -0,0 +1,105 @@ +// 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` + +#[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", + ); +} From f629a0d7ef6d726336c8e3ec1b78cbed10fd653a Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Fri, 5 Jul 2019 15:30:58 +0000 Subject: [PATCH 2/9] eliminate `write_impl` macro This was saving a very small amount of code and will make it difficult to refactor the `write` function into the `input` function in the next commit. --- src/ripemd160.rs | 30 ++++++++++++++++++++++++++++-- src/sha1.rs | 30 ++++++++++++++++++++++++++++-- src/sha256.rs | 30 ++++++++++++++++++++++++++++-- src/sha512.rs | 30 ++++++++++++++++++++++++++++-- src/util.rs | 34 ---------------------------------- 5 files changed, 112 insertions(+), 42 deletions(-) diff --git a/src/ripemd160.rs b/src/ripemd160.rs index 36bc493..ae64416 100644 --- a/src/ripemd160.rs +++ b/src/ripemd160.rs @@ -20,7 +20,7 @@ //! # RIPEMD160 use byteorder::{ByteOrder, LittleEndian}; -use std::str; +use std::{cmp, io, str}; use HashEngine as EngineTrait; use Hash as HashTrait; @@ -35,7 +35,33 @@ pub struct HashEngine { length: usize, } -write_impl!(HashEngine); +impl io::Write for HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + #[cfg(not(feature = "fuzztarget"))] + fn write(&mut self, inp: &[u8]) -> io::Result { + 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 { + self.process_block(); + } + + Ok(write_len) + } + + #[cfg(feature = "fuzztarget")] + fn write(&mut self, inp: &[u8]) -> io::Result { + for c in inp { + self.buffer[0] ^= *c; + } + self.length += inp.len(); + Ok(inp.len()) + } +} impl Clone for HashEngine { fn clone(&self) -> HashEngine { diff --git a/src/sha1.rs b/src/sha1.rs index 1c578a1..200df7a 100644 --- a/src/sha1.rs +++ b/src/sha1.rs @@ -15,7 +15,7 @@ //! # SHA1 use byteorder::{ByteOrder, BigEndian}; -use std::str; +use std::{io, cmp, str}; use HashEngine as EngineTrait; use Hash as HashTrait; @@ -30,7 +30,33 @@ pub struct HashEngine { length: usize, } -write_impl!(HashEngine); +impl io::Write for HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + #[cfg(not(feature = "fuzztarget"))] + fn write(&mut self, inp: &[u8]) -> io::Result { + 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 { + self.process_block(); + } + + Ok(write_len) + } + + #[cfg(feature = "fuzztarget")] + fn write(&mut self, inp: &[u8]) -> io::Result { + for c in inp { + self.buffer[0] ^= *c; + } + self.length += inp.len(); + Ok(inp.len()) + } +} impl Clone for HashEngine { fn clone(&self) -> HashEngine { diff --git a/src/sha256.rs b/src/sha256.rs index 98f7bfb..48b16cd 100644 --- a/src/sha256.rs +++ b/src/sha256.rs @@ -15,7 +15,7 @@ //! # SHA256 use byteorder::{ByteOrder, BigEndian}; -use std::str; +use std::{io, cmp, str}; use hex; use HashEngine as EngineTrait; @@ -31,7 +31,33 @@ pub struct HashEngine { length: usize, } -write_impl!(HashEngine); +impl io::Write for HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + #[cfg(not(feature = "fuzztarget"))] + fn write(&mut self, inp: &[u8]) -> io::Result { + 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 { + self.process_block(); + } + + Ok(write_len) + } + + #[cfg(feature = "fuzztarget")] + fn write(&mut self, inp: &[u8]) -> io::Result { + for c in inp { + self.buffer[0] ^= *c; + } + self.length += inp.len(); + Ok(inp.len()) + } +} impl Clone for HashEngine { fn clone(&self) -> HashEngine { diff --git a/src/sha512.rs b/src/sha512.rs index 1c32d68..dd6cb60 100644 --- a/src/sha512.rs +++ b/src/sha512.rs @@ -19,7 +19,7 @@ //! # SHA512 -use std::{hash, str}; +use std::{cmp, hash, io, str}; use byteorder::{ByteOrder, BigEndian}; @@ -36,7 +36,33 @@ pub struct HashEngine { buffer: [u8; BLOCK_SIZE], } -write_impl!(HashEngine); +impl io::Write for HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + #[cfg(not(feature = "fuzztarget"))] + fn write(&mut self, inp: &[u8]) -> io::Result { + 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 { + self.process_block(); + } + + Ok(write_len) + } + + #[cfg(feature = "fuzztarget")] + fn write(&mut self, inp: &[u8]) -> io::Result { + for c in inp { + self.buffer[0] ^= *c; + } + self.length += inp.len(); + Ok(inp.len()) + } +} impl Clone for HashEngine { fn clone(&self) -> HashEngine { diff --git a/src/util.rs b/src/util.rs index fcc3cea..6d4a82b 100644 --- a/src/util.rs +++ b/src/util.rs @@ -99,40 +99,6 @@ 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]); - self.length += write_len; - if self.length % ::BLOCK_SIZE == 0 { - self.process_block(); - } - - Ok(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(test)] mod test { use Hash; From c26a6045c044155fdf3b81e3f596de137991694b Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Fri, 5 Jul 2019 16:02:59 +0000 Subject: [PATCH 3/9] remove io::Write impls (will restore them in next commit) --- src/hash160.rs | 13 ++++---- src/hmac.rs | 14 +++------ src/lib.rs | 17 ++++------ src/ripemd160.rs | 80 ++++++++++++++++++++++------------------------ src/sha1.rs | 82 ++++++++++++++++++++++-------------------------- src/sha256.rs | 82 ++++++++++++++++++++++-------------------------- src/sha256d.rs | 14 ++++----- src/sha512.rs | 82 ++++++++++++++++++++++-------------------------- src/siphash24.rs | 44 +++++++++----------------- 9 files changed, 187 insertions(+), 241 deletions(-) diff --git a/src/hash160.rs b/src/hash160.rs index 8ad16f6..471790f 100644 --- a/src/hash160.rs +++ b/src/hash160.rs @@ -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 { @@ -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/hmac.rs b/src/hmac.rs index 6ea8a7c..5d9d150 100644 --- a/src/hmac.rs +++ b/src/hmac.rs @@ -19,7 +19,7 @@ //! # HMAC support -use std::{borrow, fmt, io, ops, str}; +use std::{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 06bdd54..3936a00 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,7 @@ extern crate byteorder; #[macro_use] mod util; #[macro_use] mod serde_macros; -mod std_impls; +//mod std_impls; // will return in next commit pub mod error; pub mod hex; pub mod hash160; @@ -49,7 +49,7 @@ pub mod sha256d; pub mod siphash24; pub mod cmp; -use std::{borrow, fmt, hash, io, ops}; +use std::{borrow, fmt, hash, ops}; pub use hmac::{Hmac, HmacEngine}; pub use error::Error; @@ -57,7 +57,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; @@ -68,11 +68,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 @@ -107,10 +104,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 ae64416..1763fcf 100644 --- a/src/ripemd160.rs +++ b/src/ripemd160.rs @@ -20,7 +20,7 @@ //! # RIPEMD160 use byteorder::{ByteOrder, LittleEndian}; -use std::{cmp, io, str}; +use std::{cmp, str}; use HashEngine as EngineTrait; use Hash as HashTrait; @@ -35,34 +35,6 @@ pub struct HashEngine { length: usize, } -impl io::Write for HashEngine { - fn flush(&mut self) -> io::Result<()> { Ok(()) } - - #[cfg(not(feature = "fuzztarget"))] - fn write(&mut self, inp: &[u8]) -> io::Result { - 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 { - self.process_block(); - } - - Ok(write_len) - } - - #[cfg(feature = "fuzztarget")] - fn write(&mut self, inp: &[u8]) -> io::Result { - for c in inp { - self.buffer[0] ^= *c; - } - self.length += inp.len(); - Ok(inp.len()) - } -} - impl Clone for HashEngine { fn clone(&self) -> HashEngine { HashEngine { @@ -91,6 +63,30 @@ impl EngineTrait for HashEngine { } const BLOCK_SIZE: usize = 64; + + #[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 { + self.process_block(); + } + inp = &inp[write_len..]; + } + } + + #[cfg(feature = "fuzztarget")] + fn input(&mut self, inp: &[u8]) { + for c in inp { + self.buffer[0] ^= *c; + } + self.length += inp.len(); + } } /// Output of the RIPEMD160 hash function @@ -125,22 +121,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()) @@ -466,11 +461,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 { @@ -541,7 +535,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); @@ -570,18 +564,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; } @@ -591,7 +585,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; } @@ -601,7 +595,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 200df7a..22c5861 100644 --- a/src/sha1.rs +++ b/src/sha1.rs @@ -15,7 +15,7 @@ //! # SHA1 use byteorder::{ByteOrder, BigEndian}; -use std::{io, cmp, str}; +use std::{cmp, str}; use HashEngine as EngineTrait; use Hash as HashTrait; @@ -30,34 +30,6 @@ pub struct HashEngine { length: usize, } -impl io::Write for HashEngine { - fn flush(&mut self) -> io::Result<()> { Ok(()) } - - #[cfg(not(feature = "fuzztarget"))] - fn write(&mut self, inp: &[u8]) -> io::Result { - 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 { - self.process_block(); - } - - Ok(write_len) - } - - #[cfg(feature = "fuzztarget")] - fn write(&mut self, inp: &[u8]) -> io::Result { - for c in inp { - self.buffer[0] ^= *c; - } - self.length += inp.len(); - Ok(inp.len()) - } -} - impl Clone for HashEngine { fn clone(&self) -> HashEngine { HashEngine { @@ -77,7 +49,31 @@ impl EngineTrait for HashEngine { ret } + const BLOCK_SIZE: usize = 64; + #[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 { + self.process_block(); + } + inp = &inp[write_len..]; + } + } + + #[cfg(feature = "fuzztarget")] + fn input(&mut self, inp: &[u8]) { + for c in inp { + self.buffer[0] ^= *c; + } + self.length += inp.len(); + } } /// Output of the SHA1 hash function @@ -111,22 +107,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()) @@ -197,11 +192,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 { @@ -259,7 +253,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); @@ -288,18 +282,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; } @@ -309,7 +303,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; } @@ -319,7 +313,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 48b16cd..4266b9d 100644 --- a/src/sha256.rs +++ b/src/sha256.rs @@ -15,7 +15,7 @@ //! # SHA256 use byteorder::{ByteOrder, BigEndian}; -use std::{io, cmp, str}; +use std::{cmp, str}; use hex; use HashEngine as EngineTrait; @@ -31,34 +31,6 @@ pub struct HashEngine { length: usize, } -impl io::Write for HashEngine { - fn flush(&mut self) -> io::Result<()> { Ok(()) } - - #[cfg(not(feature = "fuzztarget"))] - fn write(&mut self, inp: &[u8]) -> io::Result { - 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 { - self.process_block(); - } - - Ok(write_len) - } - - #[cfg(feature = "fuzztarget")] - fn write(&mut self, inp: &[u8]) -> io::Result { - for c in inp { - self.buffer[0] ^= *c; - } - self.length += inp.len(); - Ok(inp.len()) - } -} - impl Clone for HashEngine { fn clone(&self) -> HashEngine { HashEngine { @@ -87,6 +59,31 @@ impl EngineTrait for HashEngine { } const BLOCK_SIZE: usize = 64; + + #[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 { + self.process_block(); + } + inp = &inp[write_len..]; + } + } + + #[cfg(feature = "fuzztarget")] + fn input(&mut self, inp: &[u8]) { + for c in inp { + self.buffer[0] ^= *c; + } + self.length += inp.len(); + } } /// Output of the SHA256 hash function @@ -121,22 +118,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()) @@ -357,8 +353,6 @@ impl HashEngine { #[cfg(test)] mod tests { - use std::io::Write; - use sha256; use hex::{FromHex, ToHex}; use {Hash, HashEngine}; @@ -416,7 +410,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); @@ -445,7 +439,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, ]) ); } @@ -519,18 +513,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; } @@ -540,7 +534,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; } @@ -550,7 +544,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..df85d30 100644 --- a/src/sha256d.rs +++ b/src/sha256d.rs @@ -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 dd6cb60..10ec15a 100644 --- a/src/sha512.rs +++ b/src/sha512.rs @@ -19,7 +19,7 @@ //! # SHA512 -use std::{cmp, hash, io, str}; +use std::{cmp, hash, str}; use byteorder::{ByteOrder, BigEndian}; @@ -36,34 +36,6 @@ pub struct HashEngine { buffer: [u8; BLOCK_SIZE], } -impl io::Write for HashEngine { - fn flush(&mut self) -> io::Result<()> { Ok(()) } - - #[cfg(not(feature = "fuzztarget"))] - fn write(&mut self, inp: &[u8]) -> io::Result { - 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 { - self.process_block(); - } - - Ok(write_len) - } - - #[cfg(feature = "fuzztarget")] - fn write(&mut self, inp: &[u8]) -> io::Result { - for c in inp { - self.buffer[0] ^= *c; - } - self.length += inp.len(); - Ok(inp.len()) - } -} - impl Clone for HashEngine { fn clone(&self) -> HashEngine { HashEngine { @@ -92,6 +64,30 @@ impl EngineTrait for HashEngine { } const BLOCK_SIZE: usize = 128; + + #[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 { + self.process_block(); + } + inp = &inp[write_len..]; + } + } + + #[cfg(feature = "fuzztarget")] + fn input(&mut self, inp: &[u8]) { + for c in inp { + self.buffer[0] ^= *c; + } + self.length += inp.len(); + } } /// Output of the SHA256 hash function @@ -172,23 +168,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()) @@ -359,11 +354,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 { @@ -430,7 +424,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); @@ -468,18 +462,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; } @@ -489,7 +483,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; } @@ -499,7 +493,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..7c5e037 100644 --- a/src/siphash24.rs +++ b/src/siphash24.rs @@ -19,7 +19,6 @@ //! # SipHash 2-4 -use std::io::Write; use std::{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; } From fc981dfba2f0909d6849144c7a61312999f8ca15 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Fri, 5 Jul 2019 17:00:12 +0000 Subject: [PATCH 4/9] move all std-specific stuff into the `std_impls` module --- src/error.rs | 16 +------------- src/lib.rs | 2 +- src/std_impls.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/error.rs b/src/error.rs index 1609c56..713f4bc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,7 +15,7 @@ //! # Error Type //! -use std::{error, fmt}; +use std::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/lib.rs b/src/lib.rs index 3936a00..79e2527 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,7 @@ extern crate byteorder; #[macro_use] mod util; #[macro_use] mod serde_macros; -//mod std_impls; // will return in next commit +mod std_impls; pub mod error; pub mod hex; pub mod hash160; diff --git a/src/std_impls.rs b/src/std_impls.rs index 0221c4c..c03f8fb 100644 --- a/src/std_impls.rs +++ b/src/std_impls.rs @@ -16,6 +16,62 @@ //! //! 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; From 55da5ec4a2760fcdc1ffa3b2f908fbea52963279 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Fri, 5 Jul 2019 17:26:23 +0000 Subject: [PATCH 5/9] add no_std support --- Cargo.toml | 3 ++- src/cmp.rs | 18 +++++++++--------- src/error.rs | 2 +- src/hash160.rs | 6 +++--- src/hex.rs | 13 ++++++++----- src/hmac.rs | 2 +- src/lib.rs | 8 +++++--- src/ripemd160.rs | 2 +- src/sha1.rs | 2 +- src/sha256.rs | 2 +- src/sha256d.rs | 2 +- src/sha512.rs | 8 +++----- src/siphash24.rs | 2 +- src/util.rs | 28 ++++++++++++++-------------- 14 files changed, 51 insertions(+), 47 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d236799..76db9a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,8 @@ name = "bitcoin_hashes" path = "src/lib.rs" [features] -default = [] +default = [ "std" ] +std = [] unstable = [] # for benchmarking fuzztarget = [] # used by other rust-bitcoin projects to make hashes almost-noops, DON'T USE THIS 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 713f4bc..da8d587 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,7 +15,7 @@ //! # Error Type //! -use std::fmt; +use core::fmt; /// Hex decoding error #[derive(Copy, Clone, PartialEq, Eq)] diff --git a/src/hash160.rs b/src/hash160.rs index 471790f..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; @@ -109,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", }, 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 5d9d150..09a846b 100644 --- a/src/hmac.rs +++ b/src/hmac.rs @@ -19,7 +19,7 @@ //! # HMAC support -use std::{borrow, fmt, ops, str}; +use core::{borrow, fmt, ops, str}; #[cfg(feature="serde")] use serde::{Serialize, Serializer, Deserialize, Deserializer}; diff --git a/src/lib.rs b/src/lib.rs index 79e2527..9d215c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,16 +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; -mod std_impls; +#[cfg(any(test, feature = "std"))] mod std_impls; pub mod error; pub mod hex; pub mod hash160; @@ -49,7 +51,7 @@ pub mod sha256d; pub mod siphash24; pub mod cmp; -use std::{borrow, fmt, hash, ops}; +use core::{borrow, fmt, hash, ops}; pub use hmac::{Hmac, HmacEngine}; pub use error::Error; @@ -80,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 diff --git a/src/ripemd160.rs b/src/ripemd160.rs index 1763fcf..e268e75 100644 --- a/src/ripemd160.rs +++ b/src/ripemd160.rs @@ -20,7 +20,7 @@ //! # RIPEMD160 use byteorder::{ByteOrder, LittleEndian}; -use std::{cmp, str}; +use core::{cmp, str}; use HashEngine as EngineTrait; use Hash as HashTrait; diff --git a/src/sha1.rs b/src/sha1.rs index 22c5861..fe76b59 100644 --- a/src/sha1.rs +++ b/src/sha1.rs @@ -15,7 +15,7 @@ //! # SHA1 use byteorder::{ByteOrder, BigEndian}; -use std::{cmp, str}; +use core::{cmp, str}; use HashEngine as EngineTrait; use Hash as HashTrait; diff --git a/src/sha256.rs b/src/sha256.rs index 4266b9d..9923ffc 100644 --- a/src/sha256.rs +++ b/src/sha256.rs @@ -15,7 +15,7 @@ //! # SHA256 use byteorder::{ByteOrder, BigEndian}; -use std::{cmp, str}; +use core::{cmp, str}; use hex; use HashEngine as EngineTrait; diff --git a/src/sha256d.rs b/src/sha256d.rs index df85d30..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; diff --git a/src/sha512.rs b/src/sha512.rs index 10ec15a..50f4e64 100644 --- a/src/sha512.rs +++ b/src/sha512.rs @@ -19,7 +19,7 @@ //! # SHA512 -use std::{cmp, hash, str}; +use core::{cmp, hash, str}; use byteorder::{ByteOrder, BigEndian}; @@ -117,16 +117,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) } } diff --git a/src/siphash24.rs b/src/siphash24.rs index 7c5e037..83bb81b 100644 --- a/src/siphash24.rs +++ b/src/siphash24.rs @@ -19,7 +19,7 @@ //! # SipHash 2-4 -use std::{cmp, mem, ptr, str}; +use core::{cmp, mem, ptr, str}; use byteorder::{ByteOrder, LittleEndian}; diff --git a/src/util.rs b/src/util.rs index 6d4a82b..8eca293 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 { From c26dfb416c81e61775a1dfde6d5ad4edf320ad38 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sun, 7 Jul 2019 15:46:13 +0000 Subject: [PATCH 6/9] add no_std build test to travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) 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 From 052c29bbf0a8ef14ac4e185467c9e56d2121dbd5 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Wed, 10 Jul 2019 15:28:58 +0000 Subject: [PATCH 7/9] bump version to 0.6.0 --- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) 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 76db9a8..12485c5 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" From 761af286332f802900e5f09601d120776fe4c9c6 Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Wed, 10 Jul 2019 13:48:13 -0400 Subject: [PATCH 8/9] Pass down no_std to dependencies. --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 12485c5..98ac2de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ path = "src/lib.rs" [features] default = [ "std" ] -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 @@ -22,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 From eac6cde4e0ad9957fc4a2745b4668a9880339d8c Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Wed, 10 Jul 2019 13:27:02 -0400 Subject: [PATCH 9/9] Add engine_input_impl! macro. This was previously removed to aid restructuring, but should be added back so we don't have to remember to modify every HashEngine every time we modify the input function. --- src/ripemd160.rs | 24 +----------------------- src/sha1.rs | 25 ++----------------------- src/sha256.rs | 25 +------------------------ src/sha512.rs | 24 +----------------------- src/util.rs | 29 +++++++++++++++++++++++++++++ 5 files changed, 34 insertions(+), 93 deletions(-) diff --git a/src/ripemd160.rs b/src/ripemd160.rs index e268e75..a398250 100644 --- a/src/ripemd160.rs +++ b/src/ripemd160.rs @@ -64,29 +64,7 @@ impl EngineTrait for HashEngine { const BLOCK_SIZE: usize = 64; - #[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 { - self.process_block(); - } - inp = &inp[write_len..]; - } - } - - #[cfg(feature = "fuzztarget")] - fn input(&mut self, inp: &[u8]) { - for c in inp { - self.buffer[0] ^= *c; - } - self.length += inp.len(); - } + engine_input_impl!(); } /// Output of the RIPEMD160 hash function diff --git a/src/sha1.rs b/src/sha1.rs index fe76b59..a2ed6a1 100644 --- a/src/sha1.rs +++ b/src/sha1.rs @@ -51,29 +51,8 @@ impl EngineTrait for HashEngine { const BLOCK_SIZE: usize = 64; - #[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 { - self.process_block(); - } - inp = &inp[write_len..]; - } - } - - #[cfg(feature = "fuzztarget")] - fn input(&mut self, inp: &[u8]) { - for c in inp { - self.buffer[0] ^= *c; - } - self.length += inp.len(); - } + + engine_input_impl!(); } /// Output of the SHA1 hash function diff --git a/src/sha256.rs b/src/sha256.rs index 9923ffc..c1205db 100644 --- a/src/sha256.rs +++ b/src/sha256.rs @@ -60,30 +60,7 @@ impl EngineTrait for HashEngine { const BLOCK_SIZE: usize = 64; - #[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 { - self.process_block(); - } - inp = &inp[write_len..]; - } - } - - #[cfg(feature = "fuzztarget")] - fn input(&mut self, inp: &[u8]) { - for c in inp { - self.buffer[0] ^= *c; - } - self.length += inp.len(); - } + engine_input_impl!(); } /// Output of the SHA256 hash function diff --git a/src/sha512.rs b/src/sha512.rs index 50f4e64..22b2fc1 100644 --- a/src/sha512.rs +++ b/src/sha512.rs @@ -65,29 +65,7 @@ impl EngineTrait for HashEngine { const BLOCK_SIZE: usize = 128; - #[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 { - self.process_block(); - } - inp = &inp[write_len..]; - } - } - - #[cfg(feature = "fuzztarget")] - fn input(&mut self, inp: &[u8]) { - for c in inp { - self.buffer[0] ^= *c; - } - self.length += inp.len(); - } + engine_input_impl!(); } /// Output of the SHA256 hash function diff --git a/src/util.rs b/src/util.rs index 8eca293..47022a3 100644 --- a/src/util.rs +++ b/src/util.rs @@ -99,6 +99,35 @@ macro_rules! borrow_slice_impl( ) ); +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 { + self.process_block(); + } + inp = &inp[write_len..]; + } + } + + #[cfg(feature = "fuzztarget")] + fn input(&mut self, inp: &[u8]) { + for c in inp { + self.buffer[0] ^= *c; + } + self.length += inp.len(); + } + ) +); + #[cfg(test)] mod test { use Hash;