1use rns_crypto::Rng;
2
3use crate::constants;
4
5pub fn full_hash(data: &[u8]) -> [u8; 32] {
7 rns_crypto::sha256::sha256(data)
8}
9
10pub fn truncated_hash(data: &[u8]) -> [u8; 16] {
12 let full = full_hash(data);
13 let mut result = [0u8; 16];
14 result.copy_from_slice(&full[..16]);
15 result
16}
17
18pub fn get_random_hash(rng: &mut dyn Rng) -> [u8; 16] {
20 let mut random_bytes = [0u8; 16];
21 rng.fill_bytes(&mut random_bytes);
22 truncated_hash(&random_bytes)
23}
24
25pub fn name_hash(app_name: &str, aspects: &[&str]) -> [u8; constants::NAME_HASH_LENGTH / 8] {
31 assert!(!app_name.contains('.'), "Dots can't be used in app names");
32 for aspect in aspects {
33 assert!(!aspect.contains('.'), "Dots can't be used in aspects");
34 }
35 let mut name = alloc::string::String::from(app_name);
36 for aspect in aspects {
37 name.push('.');
38 name.push_str(aspect);
39 }
40 let full = full_hash(name.as_bytes());
41 let mut result = [0u8; constants::NAME_HASH_LENGTH / 8];
42 result.copy_from_slice(&full[..constants::NAME_HASH_LENGTH / 8]);
43 result
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn test_truncated_hash_is_prefix_of_full_hash() {
52 let data = b"test data";
53 let full = full_hash(data);
54 let trunc = truncated_hash(data);
55 assert_eq!(&full[..16], &trunc);
56 }
57
58 #[test]
59 fn test_name_hash_basic() {
60 let nh = name_hash("app", &["aspect"]);
61 assert_eq!(nh.len(), 10);
62 let nh2 = name_hash("app", &["aspect"]);
64 assert_eq!(nh, nh2);
65 }
66
67 #[test]
68 fn test_name_hash_multiple_aspects() {
69 let nh = name_hash("app", &["a", "b"]);
71 let expected = full_hash(b"app.a.b");
72 assert_eq!(nh, expected[..10]);
73 }
74
75 #[test]
76 fn test_get_random_hash() {
77 let mut rng = rns_crypto::FixedRng::new(&[0x42; 32]);
78 let h = get_random_hash(&mut rng);
79 assert_eq!(h.len(), 16);
80 }
81
82 #[test]
83 #[should_panic(expected = "Dots can't be used in app names")]
84 fn test_name_hash_rejects_dot_in_app_name() {
85 name_hash("app.bad", &["aspect"]);
86 }
87
88 #[test]
89 #[should_panic(expected = "Dots can't be used in aspects")]
90 fn test_name_hash_rejects_dot_in_aspect() {
91 name_hash("app", &["bad.aspect"]);
92 }
93}