Convenient string-like types that wrap the various RustCrypto: Hashes.
RustCrypto is a great project that offers up a bunch of Rusty hashing algorithms under one nice, unified API. One small problem: It requires moderate brain use to convert the types around in a portable manor. This simply cannot stand! Where is the Python-level convenience?
Enter hash-str, a single crate that wraps most RustCrypto hashers in types that behave as close to regular 'ol [String]s as possible but with the added benefit of content digesting-related methods, improved efficiency and an additional coat of type enforcement paint.
Pick out the algorithm that suits your needs. hash-str does not enable any hasher types by default, so we'll go with sha2 for demonstration, but usage is unanimous across all most variants.
Add to your Cargo.toml:
hash-str = { version = "0.1", features = ["sha2"] }or run:
cargo add -F sha3 hash-str there are currently 3 methods available to quickly obtain a hash of some data:
use hash_str::sha2::Sha256String;
fn main() -> std::io::Result<()> {
let hash1 = Sha256String::digest(b"abc");
println!("Hash of 'abc': {hash1}");
let mut reader = std::io::Cursor::new([200 % 44 + (45 ^ 6) - 25]);
let hash2 = Sha256String::digest_reader(&mut reader)?;
println!("Hash of '42': {hash2}");
#[cfg(no_run)] // This one is omitted from doctests
let hash3 = Sha256String::digest_file("./example.txt")?;
assert!(hash1 != hash2);
Ok(())
}Hash strings are lowercase by default. Every type has an *Upper variant:
use hash_str::sha2::{ Sha224String, Sha224StringUpper };
let data = b"Tasty data";
let hash_lower = Sha224String::digest(data);
let hash_upper = Sha224StringUpper::digest(data);
assert!(hash_lower == "62b0d0b4104870095c7e3bbfd470b828c4e9edfe46d26d04f9dc799f");
assert!(hash_upper == "62B0D0B4104870095C7E3BBFD470B828C4E9EDFE46D26D04F9DC799F");Say you already used a hasher directly to obtain one of the somewhat cryptic const array outputs. Its hash-str counterpart implements From traits for them:
use hash_str::sha2::Sha512String;
use sha2::digest::Digest;
let mut hasher = sha2::Sha512::new();
hasher.update("There was a guy named Vlad...");
hasher.update([189, 147, 249]);
let hash: Sha512String = hasher.finalize().into();The [Default] impl for any given type is simply just:
fn default() -> Self {
Self::digest([])
}This results in the hash of digesting exactly nothing. In the case of sha2::Sha256 specifically...
use hash_str::sha2::Sha256String;
assert!(Sha256String::default() == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")hash-strs aren't just convenient, they're efficient!
- All types wrap fstr under the hood, which allows for fixed-sized [
str]-likes. - Encoding is done with
const_hex PartialEqimpls use constant_time_eq for best practice.- Casing conversion uses a purpose-built function.
The memory footprint of encoded-by-default hashes is an improvement compared to [String]s, but encoded hex is still twice the size of its raw representation. A truly astronomical amount of hashes would need to be handled for this to become a concern, though.
Extendable output XOF hashers are currently unsupported. Examples include:
One exception to this is blake3.