diff --git a/Cargo.lock b/Cargo.lock index 7e112128f..bfe188254 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -444,7 +444,7 @@ dependencies = [ "http 0.2.12", "http 1.5.0", "percent-encoding", - "sha2 0.11.0", + "sha2", "time", "tracing", ] @@ -1896,7 +1896,7 @@ dependencies = [ "rusqlite", "serde", "serde_json", - "sha2 0.10.9", + "sha2", "tempfile", "thiserror 2.0.20", "tiktoken-rs", @@ -1959,7 +1959,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "sha2 0.10.9", + "sha2", "thiserror 2.0.20", "tokio", "tokio-stream", @@ -3962,17 +3962,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - [[package]] name = "sha2" version = "0.11.0" diff --git a/crates/headroom-core/Cargo.toml b/crates/headroom-core/Cargo.toml index c1f0d5537..903f4511f 100644 --- a/crates/headroom-core/Cargo.toml +++ b/crates/headroom-core/Cargo.toml @@ -28,7 +28,7 @@ hf-hub = { version = "0.5", default-features = false, features = ["ureq", "rustl md-5 = "0.10" # `sha2` for `_hash_field_name` in smart_crusher (SHA256 truncated to 16 # hex chars). Python uses `hashlib.sha256` so we need byte-exact parity. -sha2 = "0.10" +sha2 = "0.11" # `dashmap` for the CCR storage backend. Concurrent HashMap with sharded # locking — distinct keys hashed to different shards never contend, so # multi-worker proxy load doesn't queue on a single Mutex. Lock-free diff --git a/crates/headroom-core/src/rollout.rs b/crates/headroom-core/src/rollout.rs index fc9d4fb92..1ff027413 100644 --- a/crates/headroom-core/src/rollout.rs +++ b/crates/headroom-core/src/rollout.rs @@ -323,7 +323,12 @@ pub fn feature_names() -> BTreeSet<&'static str> { fn digest_value(value: &Value) -> String { let canonical = serde_json::to_vec(value).expect("rollout provenance is serializable"); - format!("sha256:{:x}", Sha256::digest(canonical)) + let digest = Sha256::digest(canonical); + let mut hex = String::with_capacity(digest.len() * 2); + for byte in digest { + hex.push_str(&format!("{byte:02x}")); + } + format!("sha256:{hex}") } #[cfg(test)] diff --git a/crates/headroom-core/src/transforms/smart_crusher/hashing.rs b/crates/headroom-core/src/transforms/smart_crusher/hashing.rs index 2648639c5..437278bf1 100644 --- a/crates/headroom-core/src/transforms/smart_crusher/hashing.rs +++ b/crates/headroom-core/src/transforms/smart_crusher/hashing.rs @@ -28,7 +28,10 @@ pub fn hash_field_name(field_name: &str) -> String { let digest = hasher.finalize(); // Truncate to first 8 hex chars (4 bytes of digest). MUST match // Python's `[:8]` — see module-level note above. - let hex = format!("{:x}", digest); + let mut hex = String::with_capacity(digest.len() * 2); + for byte in digest { + hex.push_str(&format!("{byte:02x}")); + } hex[..8].to_string() } diff --git a/crates/headroom-proxy/Cargo.toml b/crates/headroom-proxy/Cargo.toml index b1f5088f1..a2bf52f31 100644 --- a/crates/headroom-proxy/Cargo.toml +++ b/crates/headroom-proxy/Cargo.toml @@ -74,7 +74,7 @@ prometheus = { version = "=0.14.0", default-features = false } # `aws-smithy-runtime-api`); promoted here to a direct, normal-build # dependency so the drift detector compiles outside `cfg(test)`. Also # used by PR-E4 for `prompt_cache_key` derivation. -sha2 = "0.10" +sha2 = "0.11" # PR-E6: bounded session-scoped cache of structural hashes. The # detector evicts the oldest session at 1000 entries — we never want # unbounded memory growth from a flood of unique session keys. `lru` @@ -110,7 +110,7 @@ tokio-stream = "0.1" # way to gate "the proxy did not perturb the request" because JSON # value-equality misses whitespace, key order, and Unicode escape # differences that all bust the prompt cache. -sha2 = "0.10" +sha2 = "0.11" # PR-C1: property tests for the byte-level SSE parser. The parser # must never panic on arbitrary input bytes (TCP can hand us anything, # including malformed UTF-8 split mid-codepoint or fuzz-generated