use sha1::{Digest, Sha1};
const HEX_LOWER: [u8; 16] = *b"0123456789abcdef";
pub(crate) fn hex_string_from_bytes(bytes: &[u8]) -> String {
let mut out = vec![0u8; bytes.len() * 2];
for (i, &b) in bytes.iter().enumerate() {
out[i * 2] = HEX_LOWER[(b >> 4) as usize];
out[i * 2 + 1] = HEX_LOWER[(b & 0x0f) as usize];
}
String::from_utf8(out).expect("hex digits are ASCII")
}
pub fn sha1_hex(s: &str) -> String {
sha1_hex_bytes(s.as_bytes())
}
pub fn sha1_digest(bytes: &[u8]) -> [u8; 20] {
let mut hasher = Sha1::new();
hasher.update(bytes);
hasher.finalize().into()
}
pub fn hex_encode_20(digest: &[u8; 20]) -> [u8; 40] {
let mut out = [0u8; 40];
for (i, &b) in digest.iter().enumerate() {
out[i * 2] = HEX_LOWER[(b >> 4) as usize];
out[i * 2 + 1] = HEX_LOWER[(b & 0x0f) as usize];
}
out
}
#[inline]
fn hex_val(c: u8) -> Option<u8> {
match c {
b'0'..=b'9' => Some(c - b'0'),
b'a'..=b'f' => Some(c - b'a' + 10),
b'A'..=b'F' => Some(c - b'A' + 10),
_ => None,
}
}
pub fn hex_decode_20(s: &str) -> Option<[u8; 20]> {
let bytes = s.as_bytes();
if bytes.len() != 40 {
return None;
}
let mut out = [0u8; 20];
for (i, slot) in out.iter_mut().enumerate() {
let hi = hex_val(bytes[i * 2])?;
let lo = hex_val(bytes[i * 2 + 1])?;
*slot = (hi << 4) | lo;
}
Some(out)
}
pub fn sha1_hex_of_digest_hexes<'a, I>(digests: I) -> String
where
I: IntoIterator<Item = &'a [u8; 20]>,
{
let mut hasher = Sha1::new();
for d in digests {
hasher.update(hex_encode_20(d));
}
hex_string_from_bytes(&hasher.finalize())
}
pub fn sha1_hex_bytes(bytes: &[u8]) -> String {
let mut hasher = Sha1::new();
hasher.update(bytes);
hex_string_from_bytes(&hasher.finalize())
}
pub fn sha1_hex_parts<'a, I>(parts: I) -> String
where
I: IntoIterator<Item = &'a str>,
{
let mut hasher = Sha1::new();
for p in parts {
hasher.update(p.as_bytes());
}
hex_string_from_bytes(&hasher.finalize())
}
pub fn sha1_fingerprint(s: &str) -> u64 {
const OFFSET_BASIS: u64 = 0xcbf2_9ce4_8422_2325;
const PRIME: u64 = 0x0000_0100_0000_01b3;
let mut hash = OFFSET_BASIS;
for &b in s.as_bytes() {
hash ^= b as u64;
hash = hash.wrapping_mul(PRIME);
}
hash
}
pub fn sha1_fingerprint128(s: &str) -> u128 {
const OFFSET_BASIS: u128 = 0x6c62_272e_07bb_0142_62b8_2175_6295_c58d;
const PRIME: u128 = 0x0000_0000_0100_0000_0000_0000_0000_013b;
let mut hash = OFFSET_BASIS;
for &b in s.as_bytes() {
hash ^= b as u128;
hash = hash.wrapping_mul(PRIME);
}
hash
}