1use alloc::string::String;
7use core::fmt::Write;
8use sha2::{Digest, Sha256};
9
10use crate::{Error, Result};
11
12#[must_use]
14pub fn sha256_prefixed(bytes: &[u8]) -> String {
15 let digest = Sha256::digest(bytes);
16 let mut output = String::with_capacity(71);
17 output.push_str("sha256:");
18 for byte in digest {
19 write!(&mut output, "{byte:02x}").expect("writing to a String cannot fail");
20 }
21 output
22}
23
24pub fn validate_sha256(value: &str) -> Result<()> {
30 let Some(hex) = value.strip_prefix("sha256:") else {
31 return Err(Error::Validation("digest prefix must be sha256:"));
32 };
33 if hex.len() != 64
34 || !hex
35 .as_bytes()
36 .iter()
37 .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(byte))
38 {
39 return Err(Error::Validation(
40 "digest must contain 64 lowercase hexadecimal digits",
41 ));
42 }
43 Ok(())
44}