Skip to content

Commit

Permalink
feat: two optional stable hash algos
Browse files Browse the repository at this point in the history
  • Loading branch information
weihanglo committed Nov 19, 2024
1 parent e6401bb commit cb947dd
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 14 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ rand = "0.8.5"
regex = "1.10.5"
rusqlite = { version = "0.32.0", features = ["bundled"] }
rustc-hash = "2.0.0"
rustc-stable-hash = "0.1.0"
rustfix = { version = "0.9.0", path = "crates/rustfix" }
same-file = "1.0.6"
schemars = "0.8.21"
Expand Down Expand Up @@ -193,6 +194,7 @@ rand.workspace = true
regex.workspace = true
rusqlite.workspace = true
rustc-hash.workspace = true
rustc-stable-hash = { workspace = true, optional = true }
rustfix.workspace = true
same-file.workspace = true
semver.workspace = true
Expand Down Expand Up @@ -264,6 +266,8 @@ test = false
doc = false

[features]
stable-hash-siphash = ["dep:rustc-stable-hash"]
stable-hash-blake3 = ["dep:rustc-stable-hash"]
vendored-openssl = ["openssl/vendored"]
vendored-libgit2 = ["libgit2-sys/vendored"]
# This is primarily used by rust-lang/rust distributing cargo the executable.
Expand Down
92 changes: 78 additions & 14 deletions src/cargo/util/hasher.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,88 @@
//! Implementation of a hasher that produces the same values across releases.
//!
//! The hasher should be fast and have a low chance of collisions (but is not
//! sufficient for cryptographic purposes).
#![allow(deprecated)]

use std::hash::{Hasher, SipHasher};
pub use self::imp::StableHasher;

pub struct StableHasher(SipHasher);
#[cfg(not(any(feature = "stable-hash-siphash", feature = "stable-hash-blake3")))]
mod imp {
#![allow(deprecated)]

impl StableHasher {
pub fn new() -> StableHasher {
StableHasher(SipHasher::new())
use std::hash::Hasher;
use std::hash::SipHasher;

pub struct StableHasher(SipHasher);

impl StableHasher {
pub fn new() -> StableHasher {
StableHasher(SipHasher::new())
}
}

impl Hasher for StableHasher {
fn finish(&self) -> u64 {
self.0.finish()
}
fn write(&mut self, bytes: &[u8]) {
self.0.write(bytes)
}
}
}

impl Hasher for StableHasher {
fn finish(&self) -> u64 {
self.0.finish()
#[cfg(all(not(feature = "stable-hash-siphash"), feature = "stable-hash-blake3"))]
mod imp {
use std::hash::Hasher;

use rustc_stable_hash::ExtendedHasher;

#[derive(Debug, Clone)]
pub struct StableHasher {
state: blake3::Hasher,
}

impl StableHasher {
pub fn new() -> StableHasher {
StableHasher {
state: Default::default(),
}
}
}
fn write(&mut self, bytes: &[u8]) {
self.0.write(bytes)

impl ExtendedHasher for StableHasher {
type Hash = blake3::Hash;

#[inline]
fn finish(self) -> Self::Hash {
self.state.finalize()
}
}

impl Hasher for StableHasher {
#[inline]
fn write(&mut self, bytes: &[u8]) {
self.state.update(bytes);
}

#[inline]
fn finish(&self) -> u64 {
let hash = self.state.finalize();
let [a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, b3, b4, b5, b6, b7, c0, c1, c2, c3, c4, c5, c6, c7, d0, d1, d2, d3, d4, d5, d6, d7] =
*hash.as_bytes();
let p0 = u64::from_ne_bytes([a0, a1, a2, a3, a4, a5, a6, a7]);
let p1 = u64::from_ne_bytes([b0, b1, b2, b3, b4, b5, b6, b7]);
let p2 = u64::from_ne_bytes([c0, c1, c2, c3, c4, c5, c6, c7]);
let p3 = u64::from_ne_bytes([d0, d1, d2, d3, d4, d5, d6, d7]);
p0.wrapping_mul(3)
.wrapping_add(p1)
.wrapping_add(p2)
.wrapping_mul(p3)
.to_le()
}
}
}

#[cfg(all(feature = "stable-hash-siphash", not(feature = "stable-hash-blake3")))]
mod imp {
pub use rustc_stable_hash::StableSipHasher128 as StableHasher;
}

#[cfg(all(feature = "stable-hash-siphash", feature = "stable-hash-blake3"))]
compile_error!("must choose only one of `siphash` or `blake3`");

0 comments on commit cb947dd

Please sign in to comment.