mirror of
https://github.com/BLAKE3-team/BLAKE3
synced 2024-05-18 16:26:07 +02:00
merge "Adding from_hex and implementing FromStr for Hash"
https://github.com/BLAKE3-team/BLAKE3/pull/24
This commit is contained in:
commit
9e08f5c38d
45
src/lib.rs
45
src/lib.rs
|
@ -161,6 +161,16 @@ const KEYED_HASH: u8 = 1 << 4;
|
|||
const DERIVE_KEY_CONTEXT: u8 = 1 << 5;
|
||||
const DERIVE_KEY_MATERIAL: u8 = 1 << 6;
|
||||
|
||||
/// Errors from parsing hex values
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ParseError {
|
||||
/// Hexadecimal str contains invalid character
|
||||
InvalidChar,
|
||||
|
||||
/// Invalid str length. Only 32 byte digests can be parsed from a 64 char hex encoded str.
|
||||
InvalidLen,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn counter_low(counter: u64) -> u32 {
|
||||
counter as u32
|
||||
|
@ -232,6 +242,33 @@ impl Hash {
|
|||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// Parse a hexidecimal string and return the resulting Hash.
|
||||
///
|
||||
/// The string must be 64 characters long, producting a 32 byte digest.
|
||||
/// All other string length will return a `ParseError::InvalidLen`.
|
||||
pub fn from_hex(hex: &str) -> Result<Self, ParseError> {
|
||||
let str_bytes = hex.as_bytes();
|
||||
if str_bytes.len() != OUT_LEN * 2 {
|
||||
return Err(ParseError::InvalidLen);
|
||||
}
|
||||
|
||||
let mut bytes: [u8; OUT_LEN] = [0; OUT_LEN];
|
||||
for (i, pair) in str_bytes.chunks(2).enumerate() {
|
||||
bytes[i] = hex_val(pair[0])? << 4 | hex_val(pair[1])?;
|
||||
}
|
||||
|
||||
return Ok(Hash::from(bytes));
|
||||
|
||||
fn hex_val(byte: u8) -> Result<u8, ParseError> {
|
||||
match byte {
|
||||
b'A'..=b'F' => Ok(byte - b'A' + 10),
|
||||
b'a'..=b'f' => Ok(byte - b'a' + 10),
|
||||
b'0'..=b'9' => Ok(byte - b'0'),
|
||||
_ => Err(ParseError::InvalidChar),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; OUT_LEN]> for Hash {
|
||||
|
@ -248,6 +285,14 @@ impl From<Hash> for [u8; OUT_LEN] {
|
|||
}
|
||||
}
|
||||
|
||||
impl core::str::FromStr for Hash {
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Hash::from_hex(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// This implementation is constant-time.
|
||||
impl PartialEq for Hash {
|
||||
#[inline]
|
||||
|
|
26
src/test.rs
26
src/test.rs
|
@ -567,3 +567,29 @@ fn test_join_lengths() {
|
|||
);
|
||||
assert_eq!(CUSTOM_JOIN_CALLS.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hex_encoding_decoding() {
|
||||
let digest_str = "04e0bb39f30b1a3feb89f536c93be15055482df748674b00d26e5a75777702e9";
|
||||
let mut hasher = crate::Hasher::new();
|
||||
hasher.update(b"foo");
|
||||
let digest = hasher.finalize();
|
||||
assert_eq!(digest.to_hex().as_str(), digest_str);
|
||||
|
||||
// Test round trip
|
||||
let digest = crate::Hash::from_hex(digest_str).unwrap();
|
||||
assert_eq!(digest.to_hex().as_str(), digest_str);
|
||||
|
||||
// Test string parsing via FromStr
|
||||
let digest: crate::Hash = digest_str.parse().unwrap();
|
||||
assert_eq!(digest.to_hex().as_str(), digest_str);
|
||||
|
||||
// Test errors
|
||||
let bad_len = "04e0bb39f30b1";
|
||||
let result = crate::Hash::from_hex(bad_len).unwrap_err();
|
||||
assert_eq!(result, crate::ParseError::InvalidLen);
|
||||
|
||||
let bad_char = "Z4e0bb39f30b1a3feb89f536c93be15055482df748674b00d26e5a75777702e9";
|
||||
let result = crate::Hash::from_hex(bad_char).unwrap_err();
|
||||
assert_eq!(result, crate::ParseError::InvalidChar);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue