From f805963970aa509ab4e0175d296eaf5f4d8dde92 Mon Sep 17 00:00:00 2001 From: Melanie Riise Date: Wed, 10 Aug 2022 12:09:41 -0500 Subject: [PATCH] Add ripemd family of hashes (#226) * add ripemd family of hashes * revert accidental core2 dep change * rustfmt * add ripemd tests - removes it from default features, - adds a simple helper function for writing new tests (generating multihashes out of band) * rustfmt * fix clippy warnings * CI i stg just let me make a PR, rustfmt * move util to examples --- Cargo.lock | 10 +++++++++ Cargo.toml | 2 ++ examples/manual_mh.rs | 24 +++++++++++++++++++++ src/hasher_impl.rs | 34 ++++++++++++++++++----------- src/lib.rs | 2 ++ src/multihash_impl.rs | 12 +++++++++++ tests/lib.rs | 50 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 examples/manual_mh.rs diff --git a/Cargo.lock b/Cargo.lock index b97b9b20..03bdfb63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -488,6 +488,7 @@ dependencies = [ "parity-scale-codec", "quickcheck", "rand", + "ripemd", "serde", "serde-big-array", "serde_json", @@ -769,6 +770,15 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "ripemd" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1facec54cb5e0dc08553501fa740091086d0259ad0067e0d4103448e4cb22ed3" +dependencies = [ + "digest", +] + [[package]] name = "rustc_version" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 28aceac6..5b233bd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ sha1 = ["digest", "sha-1"] sha2 = ["digest", "sha-2"] sha3 = ["digest", "sha-3"] strobe = ["strobe-rs"] +ripemd = ["ripemd-rs"] [dependencies] parity-scale-codec = { version = "3.0.0", default-features = false, features = ["derive"], optional = true } @@ -51,6 +52,7 @@ sha-1 = { version = "0.10.0", default-features = false, optional = true } sha-2 = { version = "0.10.0", default-features = false, optional = true, package = "sha2" } sha-3 = { version = "0.10.0", default-features = false, optional = true, package = "sha3" } strobe-rs = { version = "0.7.0", default-features = false, optional = true } +ripemd-rs = { package = "ripemd", version = "0.1.1", optional = true} core2 = { version = "0.4.0", default-features = false } diff --git a/examples/manual_mh.rs b/examples/manual_mh.rs new file mode 100644 index 00000000..81db713d --- /dev/null +++ b/examples/manual_mh.rs @@ -0,0 +1,24 @@ +use multihash::{Code, MultihashDigest}; + +/// prefix/multihash generating tool to aid when adding new tests +fn prefix_util() { + use unsigned_varint::encode; + // change these as needed + let empty = Code::Sha2_256.wrap(&[]).unwrap().to_bytes(); + let hash = "7c8357577f51d4f0a8d393aa1aaafb28863d9421"; + + // encode things + let len = (hash.len() / 2) as u64; // always hex so len bytes is always half + let mut buf = encode::u64_buffer(); + let len = encode::u64(len, &mut buf); + + let code_hex = hex::encode(&empty[..1]); // change if longer/shorter prefix + let len_hex = hex::encode(len); + println!("prefix hex: code: {}, len: {}", code_hex, len_hex); + + println!("{}{}{}", code_hex, len_hex, hash); +} + +fn main() { + prefix_util() +} diff --git a/src/hasher_impl.rs b/src/hasher_impl.rs index 24a04aa2..4e24439a 100644 --- a/src/hasher_impl.rs +++ b/src/hasher_impl.rs @@ -144,7 +144,7 @@ pub mod blake3 { } #[cfg(feature = "digest")] -macro_rules! derive_hasher_sha { +macro_rules! derive_rustcrypto_hasher { ($module:ty, $name:ident, $size:expr) => { /// Multihash hasher. #[derive(Debug)] @@ -200,30 +200,40 @@ macro_rules! derive_hasher_sha { pub mod sha1 { use super::*; - derive_hasher_sha!(::sha1::Sha1, Sha1, 20); + derive_rustcrypto_hasher!(::sha1::Sha1, Sha1, 20); } #[cfg(feature = "sha2")] pub mod sha2 { use super::*; - derive_hasher_sha!(sha_2::Sha256, Sha2_256, 32); - derive_hasher_sha!(sha_2::Sha512, Sha2_512, 64); + derive_rustcrypto_hasher!(sha_2::Sha256, Sha2_256, 32); + derive_rustcrypto_hasher!(sha_2::Sha512, Sha2_512, 64); } #[cfg(feature = "sha3")] pub mod sha3 { use super::*; - derive_hasher_sha!(sha_3::Sha3_224, Sha3_224, 28); - derive_hasher_sha!(sha_3::Sha3_256, Sha3_256, 32); - derive_hasher_sha!(sha_3::Sha3_384, Sha3_384, 48); - derive_hasher_sha!(sha_3::Sha3_512, Sha3_512, 64); + derive_rustcrypto_hasher!(sha_3::Sha3_224, Sha3_224, 28); + derive_rustcrypto_hasher!(sha_3::Sha3_256, Sha3_256, 32); + derive_rustcrypto_hasher!(sha_3::Sha3_384, Sha3_384, 48); + derive_rustcrypto_hasher!(sha_3::Sha3_512, Sha3_512, 64); - derive_hasher_sha!(sha_3::Keccak224, Keccak224, 28); - derive_hasher_sha!(sha_3::Keccak256, Keccak256, 32); - derive_hasher_sha!(sha_3::Keccak384, Keccak384, 48); - derive_hasher_sha!(sha_3::Keccak512, Keccak512, 64); + derive_rustcrypto_hasher!(sha_3::Keccak224, Keccak224, 28); + derive_rustcrypto_hasher!(sha_3::Keccak256, Keccak256, 32); + derive_rustcrypto_hasher!(sha_3::Keccak384, Keccak384, 48); + derive_rustcrypto_hasher!(sha_3::Keccak512, Keccak512, 64); +} + +#[cfg(feature = "ripemd")] +pub mod ripemd { + + use super::*; + + derive_rustcrypto_hasher!(ripemd_rs::Ripemd160, Ripemd160, 20); + derive_rustcrypto_hasher!(ripemd_rs::Ripemd256, Ripemd256, 32); + derive_rustcrypto_hasher!(ripemd_rs::Ripemd320, Ripemd320, 40); } pub mod identity { diff --git a/src/lib.rs b/src/lib.rs index e1b36366..d561c27b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,6 +80,8 @@ pub use crate::hasher_impl::blake2s::{Blake2s128, Blake2s256, Blake2sHasher}; #[cfg(feature = "blake3")] pub use crate::hasher_impl::blake3::{Blake3Hasher, Blake3_256}; pub use crate::hasher_impl::identity::{Identity256, IdentityHasher}; +#[cfg(feature = "ripemd")] +pub use crate::hasher_impl::ripemd::{Ripemd160, Ripemd256, Ripemd320}; #[cfg(feature = "sha1")] pub use crate::hasher_impl::sha1::Sha1; #[cfg(feature = "sha2")] diff --git a/src/multihash_impl.rs b/src/multihash_impl.rs index ab7d827f..29face0b 100644 --- a/src/multihash_impl.rs +++ b/src/multihash_impl.rs @@ -71,6 +71,18 @@ pub enum Code { #[cfg(feature = "blake3")] #[mh(code = 0x1e, hasher = crate::Blake3_256)] Blake3_256, + /// RIPEMD-160 (20-byte hash size) + #[cfg(feature = "ripemd")] + #[mh(code = 0x1053, hasher = crate::Ripemd160)] + Ripemd160, + /// RIPEMD-256 (32-byte hash size) + #[cfg(feature = "ripemd")] + #[mh(code = 0x1054, hasher = crate::Ripemd256)] + Ripemd256, + /// RIPEMD-320 (40-byte hash size) + #[cfg(feature = "ripemd")] + #[mh(code = 0x1055, hasher = crate::Ripemd320)] + Ripemd320, // The following hashes are not cryptographically secure hashes and are not enabled by default /// Identity hash (max. 64 bytes) diff --git a/tests/lib.rs b/tests/lib.rs index cd475d16..14967ab3 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -6,6 +6,9 @@ use multihash::{ Sha2_512, Sha3_224, Sha3_256, Sha3_384, Sha3_512, Strobe256, Strobe512, }; +#[cfg(feature = "ripemd")] +use multihash::{Ripemd160, Ripemd256, Ripemd320}; + #[derive(Clone, Copy, Debug, Eq, Multihash, PartialEq)] #[mh(alloc_size = 64)] pub enum Code { @@ -47,6 +50,15 @@ pub enum Code { Strobe256, #[mh(code = 0x3312e8, hasher = Strobe512)] Strobe512, + #[cfg(feature = "ripemd")] + #[mh(code = 0x1053, hasher = Ripemd160)] + Ripemd160, + #[cfg(feature = "ripemd")] + #[mh(code = 0x1054, hasher = Ripemd256)] + Ripemd256, + #[cfg(feature = "ripemd")] + #[mh(code = 0x1055, hasher = Ripemd320)] + Ripemd320, } macro_rules! assert_encode { @@ -97,6 +109,13 @@ fn multihash_encode() { Blake2s128, Code::Blake2s128, b"hello world", "d0e4021037deae0226c30da2ab424a7b8ee14e83"; Blake3_256, Code::Blake3_256, b"hello world", "1e20d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24"; } + + #[cfg(feature = "ripemd")] + assert_encode! { + Ripemd160, Code::Ripemd160, b"hello world", "d3201498c615784ccb5fe5936fbc0cbe9dfdb408d92f0f"; + Ripemd256, Code::Ripemd256, b"hello world", "d420200d375cf9d9ee95a3bb15f757c81e93bb0ad963edf69dc4d12264031814608e37"; + Ripemd320, Code::Ripemd320, b"hello world", "d520280e12fe7d075f8e319e07c106917eddb0135e9a10aefb50a8a07ccb0582ff1fa27b95ed5af57fd5c6"; + } } macro_rules! assert_decode { @@ -134,6 +153,12 @@ fn assert_decode() { Code::Blake2s128, "d0e4021037deae0226c30da2ab424a7b8ee14e83"; Code::Blake3_256, "1e20d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24"; } + #[cfg(feature = "ripemd")] + assert_decode! { + Code::Ripemd160, "d3201498c615784ccb5fe5936fbc0cbe9dfdb408d92f0f"; + Code::Ripemd256, "d420200d375cf9d9ee95a3bb15f757c81e93bb0ad963edf69dc4d12264031814608e37"; + Code::Ripemd320, "d520280e12fe7d075f8e319e07c106917eddb0135e9a10aefb50a8a07ccb0582ff1fa27b95ed5af57fd5c6"; + } } macro_rules! assert_roundtrip { @@ -191,6 +216,13 @@ fn assert_roundtrip() { Code::Blake2s256, Blake2s256; Code::Blake3_256, Blake3_256; ); + + #[cfg(feature = "ripemd")] + assert_roundtrip! { + Code::Ripemd160, Ripemd160; + Code::Ripemd256, Ripemd256; + Code::Ripemd320, Ripemd320; + } } /// Testing the public interface of `Multihash` and coversions to it @@ -300,6 +332,24 @@ fn test_multihash_methods() { "1e20", "d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24", ); + #[cfg(feature = "ripemd")] + { + multihash_methods::( + Code::Ripemd160, + "d32014", + "98c615784ccb5fe5936fbc0cbe9dfdb408d92f0f", + ); + multihash_methods::( + Code::Ripemd256, + "d42020", + "0d375cf9d9ee95a3bb15f757c81e93bb0ad963edf69dc4d12264031814608e37", + ); + multihash_methods::( + Code::Ripemd320, + "d52028", + "0e12fe7d075f8e319e07c106917eddb0135e9a10aefb50a8a07ccb0582ff1fa27b95ed5af57fd5c6", + ); + } } #[test]