cesr/core/matter/code/
digest.rs1use super::cesr_code::CesrCode;
2use super::matter_code::MatterCode;
3use super::sealed::Sealed;
4use crate::core::matter::error::ValidationError;
5#[cfg(feature = "alloc")]
6#[allow(
7 unused_imports,
8 reason = "alloc prelude items; subset used per cfg/feature combination"
9)]
10use alloc::string::ToString;
11
12#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
14#[allow(
15 non_camel_case_types,
16 reason = "digest algorithm names use underscores by convention"
17)]
18pub enum DigestCode {
19 Blake3_256,
21 Blake2b_256,
23 Blake2s_256,
25 SHA3_256,
27 SHA2_256,
29 Blake3_512,
31 Blake2b_512,
33 SHA3_512,
35 SHA2_512,
37}
38
39impl Sealed for DigestCode {}
40
41impl CesrCode for DigestCode {
42 fn to_matter_code(&self) -> MatterCode {
43 match self {
44 Self::Blake3_256 => MatterCode::Blake3_256,
45 Self::Blake2b_256 => MatterCode::Blake2b_256,
46 Self::Blake2s_256 => MatterCode::Blake2s_256,
47 Self::SHA3_256 => MatterCode::SHA3_256,
48 Self::SHA2_256 => MatterCode::SHA2_256,
49 Self::Blake3_512 => MatterCode::Blake3_512,
50 Self::Blake2b_512 => MatterCode::Blake2b_512,
51 Self::SHA3_512 => MatterCode::SHA3_512,
52 Self::SHA2_512 => MatterCode::SHA2_512,
53 }
54 }
55
56 fn as_str(&self) -> &'static str {
57 match self {
58 Self::Blake3_256 => "E",
59 Self::Blake2b_256 => "F",
60 Self::Blake2s_256 => "G",
61 Self::SHA3_256 => "H",
62 Self::SHA2_256 => "I",
63 Self::Blake3_512 => "0D",
64 Self::Blake2b_512 => "0E",
65 Self::SHA3_512 => "0F",
66 Self::SHA2_512 => "0G",
67 }
68 }
69}
70
71impl TryFrom<MatterCode> for DigestCode {
72 type Error = ValidationError;
73
74 fn try_from(code: MatterCode) -> Result<Self, Self::Error> {
75 match code {
76 MatterCode::Blake3_256 => Ok(Self::Blake3_256),
77 MatterCode::Blake2b_256 => Ok(Self::Blake2b_256),
78 MatterCode::Blake2s_256 => Ok(Self::Blake2s_256),
79 MatterCode::SHA3_256 => Ok(Self::SHA3_256),
80 MatterCode::SHA2_256 => Ok(Self::SHA2_256),
81 MatterCode::Blake3_512 => Ok(Self::Blake3_512),
82 MatterCode::Blake2b_512 => Ok(Self::Blake2b_512),
83 MatterCode::SHA3_512 => Ok(Self::SHA3_512),
84 MatterCode::SHA2_512 => Ok(Self::SHA2_512),
85 _ => Err(ValidationError::UnknownMatterCode(code.to_string())),
86 }
87 }
88}
89
90impl From<DigestCode> for MatterCode {
91 fn from(code: DigestCode) -> Self {
92 code.to_matter_code()
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use crate::core::matter::code::MatterCode;
100
101 #[test]
102 fn digest_code_to_matter_code_roundtrip() {
103 let codes = [
104 (DigestCode::Blake3_256, MatterCode::Blake3_256),
105 (DigestCode::Blake2b_256, MatterCode::Blake2b_256),
106 (DigestCode::Blake2s_256, MatterCode::Blake2s_256),
107 (DigestCode::SHA3_256, MatterCode::SHA3_256),
108 (DigestCode::SHA2_256, MatterCode::SHA2_256),
109 (DigestCode::Blake3_512, MatterCode::Blake3_512),
110 (DigestCode::Blake2b_512, MatterCode::Blake2b_512),
111 (DigestCode::SHA3_512, MatterCode::SHA3_512),
112 (DigestCode::SHA2_512, MatterCode::SHA2_512),
113 ];
114 for (dc, mc) in codes {
115 assert_eq!(dc.to_matter_code(), mc);
116 assert_eq!(DigestCode::try_from(mc).unwrap(), dc);
117 assert_eq!(MatterCode::from(dc), mc);
118 }
119 }
120
121 #[test]
122 fn digest_code_rejects_non_digest() {
123 assert!(DigestCode::try_from(MatterCode::Ed25519).is_err());
124 assert!(DigestCode::try_from(MatterCode::Ed25519Seed).is_err());
125 assert!(DigestCode::try_from(MatterCode::Short).is_err());
126 }
127
128 #[test]
129 fn digest_code_as_str() {
130 assert_eq!(DigestCode::Blake3_256.as_str(), "E");
131 assert_eq!(DigestCode::SHA2_256.as_str(), "I");
132 assert_eq!(DigestCode::Blake3_512.as_str(), "0D");
133 assert_eq!(DigestCode::SHA2_512.as_str(), "0G");
134 }
135
136 #[test]
137 fn placeholder_blake3_256_is_44_dummy_chars() {
138 let ph = DigestCode::Blake3_256
139 .placeholder()
140 .expect("digest codes are fixed-size");
141 assert_eq!(ph, "#".repeat(44));
142 }
143
144 #[test]
145 fn placeholder_all_digest_codes_fixed_and_hash_filled() {
146 use crate::core::matter::sizage::SizeType;
147 for code in [
148 DigestCode::Blake3_256,
149 DigestCode::Blake2b_256,
150 DigestCode::Blake2s_256,
151 DigestCode::SHA3_256,
152 DigestCode::SHA2_256,
153 DigestCode::Blake3_512,
154 DigestCode::Blake2b_512,
155 DigestCode::SHA3_512,
156 DigestCode::SHA2_512,
157 ] {
158 let ph = code.placeholder().expect("digest codes are fixed-size");
159 let SizeType::Fixed(n) = code.get_sizage().fs else {
160 unreachable!("digest codes are fixed-size")
161 };
162 assert_eq!(ph.len(), usize::from(n));
163 assert!(!ph.is_empty() && ph.bytes().all(|b| b == b'#'));
164 }
165 }
166}