dpp/identity/identity_public_key/
security_level.rs1use bincode::{Decode, Encode};
2#[cfg(feature = "cbor")]
3use ciborium::value::Value as CborValue;
4
5use serde_repr::{Deserialize_repr, Serialize_repr};
6
7use crate::consensus::basic::data_contract::UnknownSecurityLevelError;
8use crate::consensus::basic::BasicError;
9use crate::consensus::ConsensusError;
10use crate::ProtocolError;
11use std::convert::TryFrom;
12
13#[repr(u8)]
14#[derive(
15 Debug,
16 PartialEq,
17 Eq,
18 Clone,
19 Copy,
20 Hash,
21 Serialize_repr,
22 Deserialize_repr,
23 PartialOrd,
24 Ord,
25 Encode,
26 Decode,
27 Default,
28 strum::EnumIter,
29)]
30pub enum SecurityLevel {
31 MASTER = 0,
32 CRITICAL = 1,
33 #[default]
34 HIGH = 2,
35 MEDIUM = 3,
36}
37
38impl From<SecurityLevel> for [u8; 1] {
39 fn from(security_level: SecurityLevel) -> Self {
40 [security_level as u8]
41 }
42}
43
44impl From<SecurityLevel> for &'static [u8; 1] {
45 fn from(security_level: SecurityLevel) -> Self {
46 match security_level {
47 SecurityLevel::MASTER => &[0],
48 SecurityLevel::CRITICAL => &[1],
49 SecurityLevel::HIGH => &[2],
50 SecurityLevel::MEDIUM => &[3],
51 }
52 }
53}
54
55#[cfg(feature = "cbor")]
56impl Into<CborValue> for SecurityLevel {
57 fn into(self) -> CborValue {
58 CborValue::from(self as u128)
59 }
60}
61
62impl TryFrom<u8> for SecurityLevel {
63 type Error = ProtocolError;
64 fn try_from(value: u8) -> Result<Self, ProtocolError> {
65 match value {
66 0 => Ok(Self::MASTER),
67 1 => Ok(Self::CRITICAL),
68 2 => Ok(Self::HIGH),
69 3 => Ok(Self::MEDIUM),
70 value => Err(ProtocolError::ConsensusError(
71 ConsensusError::BasicError(BasicError::UnknownSecurityLevelError(
72 UnknownSecurityLevelError::new(vec![0, 1, 2, 3], value),
73 ))
74 .into(),
75 )),
76 }
77 }
78}
79
80impl SecurityLevel {
81 pub fn full_range() -> [SecurityLevel; 4] {
83 [Self::MASTER, Self::CRITICAL, Self::HIGH, Self::MEDIUM]
84 }
85 pub fn last() -> SecurityLevel {
86 Self::MEDIUM
87 }
88 pub fn lowest_level() -> SecurityLevel {
89 Self::MEDIUM
90 }
91 pub fn highest_level() -> SecurityLevel {
92 Self::MASTER
93 }
94 pub fn stronger_security_than(self: SecurityLevel, rhs: SecurityLevel) -> bool {
95 (self as u8) < (rhs as u8)
102 }
103
104 pub fn stronger_or_equal_security_than(self: SecurityLevel, rhs: SecurityLevel) -> bool {
105 (self as u8) <= (rhs as u8)
106 }
107}
108
109impl std::fmt::Display for SecurityLevel {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 write!(f, "{self:?}")
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
121 fn test_security_level_try_from_u8_all_valid() {
122 assert_eq!(SecurityLevel::try_from(0u8).unwrap(), SecurityLevel::MASTER);
123 assert_eq!(
124 SecurityLevel::try_from(1u8).unwrap(),
125 SecurityLevel::CRITICAL
126 );
127 assert_eq!(SecurityLevel::try_from(2u8).unwrap(), SecurityLevel::HIGH);
128 assert_eq!(SecurityLevel::try_from(3u8).unwrap(), SecurityLevel::MEDIUM);
129 }
130
131 #[test]
133 fn test_security_level_try_from_u8_invalid_is_consensus_error() {
134 let err = SecurityLevel::try_from(4u8).unwrap_err();
135 match err {
137 ProtocolError::ConsensusError(ce) => match *ce {
138 ConsensusError::BasicError(BasicError::UnknownSecurityLevelError(_)) => {}
139 other => panic!("unexpected inner consensus error: {:?}", other),
140 },
141 other => panic!("expected ProtocolError::ConsensusError, got {:?}", other),
142 }
143 }
144
145 #[test]
146 fn test_security_level_try_from_u8_invalid_255() {
147 assert!(SecurityLevel::try_from(255u8).is_err());
148 }
149
150 #[test]
152 fn test_security_level_to_owned_byte_array() {
153 let arr: [u8; 1] = SecurityLevel::MASTER.into();
154 assert_eq!(arr, [0]);
155 let arr: [u8; 1] = SecurityLevel::CRITICAL.into();
156 assert_eq!(arr, [1]);
157 let arr: [u8; 1] = SecurityLevel::HIGH.into();
158 assert_eq!(arr, [2]);
159 let arr: [u8; 1] = SecurityLevel::MEDIUM.into();
160 assert_eq!(arr, [3]);
161 }
162
163 #[test]
165 fn test_security_level_to_static_byte_ref_all_variants() {
166 let r: &'static [u8; 1] = SecurityLevel::MASTER.into();
167 assert_eq!(r, &[0u8]);
168 let r: &'static [u8; 1] = SecurityLevel::CRITICAL.into();
169 assert_eq!(r, &[1u8]);
170 let r: &'static [u8; 1] = SecurityLevel::HIGH.into();
171 assert_eq!(r, &[2u8]);
172 let r: &'static [u8; 1] = SecurityLevel::MEDIUM.into();
173 assert_eq!(r, &[3u8]);
174 }
175
176 #[test]
178 fn test_security_level_display_matches_debug_form() {
179 assert_eq!(format!("{}", SecurityLevel::MASTER), "MASTER");
180 assert_eq!(format!("{}", SecurityLevel::CRITICAL), "CRITICAL");
181 assert_eq!(format!("{}", SecurityLevel::HIGH), "HIGH");
182 assert_eq!(format!("{}", SecurityLevel::MEDIUM), "MEDIUM");
183 }
184
185 #[test]
187 fn test_security_level_default_is_high() {
188 assert_eq!(SecurityLevel::default(), SecurityLevel::HIGH);
189 }
190
191 #[test]
193 fn test_security_level_full_range() {
194 let r = SecurityLevel::full_range();
195 assert_eq!(r.len(), 4);
196 assert_eq!(
197 r,
198 [
199 SecurityLevel::MASTER,
200 SecurityLevel::CRITICAL,
201 SecurityLevel::HIGH,
202 SecurityLevel::MEDIUM,
203 ]
204 );
205 }
206
207 #[test]
208 fn test_security_level_last_and_lowest_are_medium() {
209 assert_eq!(SecurityLevel::last(), SecurityLevel::MEDIUM);
210 assert_eq!(SecurityLevel::lowest_level(), SecurityLevel::MEDIUM);
211 }
212
213 #[test]
214 fn test_security_level_highest_is_master() {
215 assert_eq!(SecurityLevel::highest_level(), SecurityLevel::MASTER);
216 }
217
218 #[test]
220 fn test_stronger_security_than_master_vs_medium() {
221 assert!(SecurityLevel::MASTER.stronger_security_than(SecurityLevel::MEDIUM));
223 assert!(!SecurityLevel::MEDIUM.stronger_security_than(SecurityLevel::MASTER));
225 }
226
227 #[test]
228 fn test_stronger_security_than_is_not_reflexive() {
229 assert!(!SecurityLevel::HIGH.stronger_security_than(SecurityLevel::HIGH));
231 assert!(!SecurityLevel::MASTER.stronger_security_than(SecurityLevel::MASTER));
232 }
233
234 #[test]
235 fn test_stronger_security_than_full_matrix() {
236 let all = SecurityLevel::full_range();
237 for (i, a) in all.iter().enumerate() {
238 for (j, b) in all.iter().enumerate() {
239 assert_eq!(a.stronger_security_than(*b), i < j);
241 }
242 }
243 }
244
245 #[test]
247 fn test_stronger_or_equal_security_than_reflexive() {
248 for lvl in SecurityLevel::full_range() {
249 assert!(lvl.stronger_or_equal_security_than(lvl));
250 }
251 }
252
253 #[test]
254 fn test_stronger_or_equal_security_than_strict() {
255 assert!(SecurityLevel::MASTER.stronger_or_equal_security_than(SecurityLevel::HIGH));
256 assert!(!SecurityLevel::HIGH.stronger_or_equal_security_than(SecurityLevel::MASTER));
257 }
258
259 #[test]
261 fn test_security_level_ordering_master_lt_critical_lt_high_lt_medium() {
262 assert!(SecurityLevel::MASTER < SecurityLevel::CRITICAL);
263 assert!(SecurityLevel::CRITICAL < SecurityLevel::HIGH);
264 assert!(SecurityLevel::HIGH < SecurityLevel::MEDIUM);
265 }
266
267 #[test]
269 fn test_security_level_round_trip_u8() {
270 for v in 0u8..=3 {
271 let lvl = SecurityLevel::try_from(v).unwrap();
272 assert_eq!(lvl as u8, v);
273 }
274 }
275}