pub(crate) trait ToHex {
fn to_hex(&self) -> String;
}
impl<T: AsRef<[u8]>> ToHex for T {
fn to_hex(&self) -> String {
const HEX: &[u8; 16] = b"0123456789abcdef";
let bytes = self.as_ref();
let mut out = String::with_capacity(bytes.len() * 2);
for b in bytes {
out.push(HEX[(b >> 4) as usize] as char);
out.push(HEX[(b & 0x0f) as usize] as char);
}
out
}
}
pub(crate) trait ConstantTimeEq {
fn ct_eq(&self, other: &Self) -> bool;
}
impl ConstantTimeEq for str {
fn ct_eq(&self, other: &Self) -> bool {
let (a, b) = (self.as_bytes(), other.as_bytes());
if a.len() != b.len() {
return false;
}
let mut diff = 0u8;
for (x, y) in a.iter().zip(b) {
diff |= x ^ y;
}
diff == 0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn to_hex_round_trips_known_value() {
assert_eq!([0x00, 0xff, 0x10].to_hex(), "00ff10");
assert_eq!(Vec::<u8>::new().to_hex(), "");
}
#[test]
fn ct_eq_matches_str_eq() {
assert!("abcdef".ct_eq("abcdef"));
assert!(!"abcdef".ct_eq("abcdeg"));
assert!(!"abc".ct_eq("abcd"));
}
}