Skip to main content

pfx_mod/
fingerprint.rs

1use std::fmt;
2
3use sha2::{Digest, Sha256};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
6pub struct Fingerprint(pub [u8; 32]);
7
8impl Fingerprint {
9    pub fn of_mod(manifest: &[u8], component: &[u8]) -> Self {
10        let mut hash = Sha256::new();
11        hash.update(b"pfx-mod 1\0");
12        hash.update((manifest.len() as u64).to_le_bytes());
13        hash.update(manifest);
14        hash.update((component.len() as u64).to_le_bytes());
15        hash.update(component);
16        Self(hash.finalize().into())
17    }
18
19    pub fn of_set<'a>(mods: impl IntoIterator<Item = (&'a str, Fingerprint)>) -> Self {
20        let mut mods: Vec<(&str, Fingerprint)> = mods.into_iter().collect();
21        mods.sort();
22        let mut hash = Sha256::new();
23        hash.update(b"pfx-mod set 1\0");
24        hash.update((mods.len() as u64).to_le_bytes());
25        for (id, fingerprint) in mods {
26            hash.update((id.len() as u64).to_le_bytes());
27            hash.update(id.as_bytes());
28            hash.update(fingerprint.0);
29        }
30        Self(hash.finalize().into())
31    }
32
33    pub fn hex(&self) -> String {
34        self.0.iter().map(|b| format!("{b:02x}")).collect()
35    }
36}
37
38impl fmt::Display for Fingerprint {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        f.write_str(&self.hex())
41    }
42}