dpp/identity/identity_public_key/
security_level.rs1use bincode::{Decode, DecodeUntrusted, 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 DecodeUntrusted,
30)]
31pub enum SecurityLevel {
32 MASTER = 0,
33 CRITICAL = 1,
34 #[default]
35 HIGH = 2,
36 MEDIUM = 3,
37}
38
39impl From<SecurityLevel> for [u8; 1] {
40 fn from(security_level: SecurityLevel) -> Self {
41 [security_level as u8]
42 }
43}
44
45impl From<SecurityLevel> for &'static [u8; 1] {
46 fn from(security_level: SecurityLevel) -> Self {
47 match security_level {
48 SecurityLevel::MASTER => &[0],
49 SecurityLevel::CRITICAL => &[1],
50 SecurityLevel::HIGH => &[2],
51 SecurityLevel::MEDIUM => &[3],
52 }
53 }
54}
55
56#[cfg(feature = "cbor")]
57impl Into<CborValue> for SecurityLevel {
58 fn into(self) -> CborValue {
59 CborValue::from(self as u128)
60 }
61}
62
63impl TryFrom<u8> for SecurityLevel {
64 type Error = ProtocolError;
65 fn try_from(value: u8) -> Result<Self, ProtocolError> {
66 match value {
67 0 => Ok(Self::MASTER),
68 1 => Ok(Self::CRITICAL),
69 2 => Ok(Self::HIGH),
70 3 => Ok(Self::MEDIUM),
71 value => Err(ProtocolError::ConsensusError(
72 ConsensusError::BasicError(BasicError::UnknownSecurityLevelError(
73 UnknownSecurityLevelError::new(vec![0, 1, 2, 3], value),
74 ))
75 .into(),
76 )),
77 }
78 }
79}
80
81impl SecurityLevel {
82 pub fn full_range() -> [SecurityLevel; 4] {
84 [Self::MASTER, Self::CRITICAL, Self::HIGH, Self::MEDIUM]
85 }
86 pub fn last() -> SecurityLevel {
87 Self::MEDIUM
88 }
89 pub fn lowest_level() -> SecurityLevel {
90 Self::MEDIUM
91 }
92 pub fn highest_level() -> SecurityLevel {
93 Self::MASTER
94 }
95 pub fn stronger_security_than(self: SecurityLevel, rhs: SecurityLevel) -> bool {
96 (self as u8) < (rhs as u8)
103 }
104
105 pub fn stronger_or_equal_security_than(self: SecurityLevel, rhs: SecurityLevel) -> bool {
106 (self as u8) <= (rhs as u8)
107 }
108}
109
110impl std::fmt::Display for SecurityLevel {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 write!(f, "{self:?}")
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
122 fn test_security_level_try_from_u8_all_valid() {
123 assert_eq!(SecurityLevel::try_from(0u8).unwrap(), SecurityLevel::MASTER);
124 assert_eq!(
125 SecurityLevel::try_from(1u8).unwrap(),
126 SecurityLevel::CRITICAL
127 );
128 assert_eq!(SecurityLevel::try_from(2u8).unwrap(), SecurityLevel::HIGH);
129 assert_eq!(SecurityLevel::try_from(3u8).unwrap(), SecurityLevel::MEDIUM);
130 }
131
132 #[test]
134 fn test_security_level_try_from_u8_invalid_is_consensus_error() {
135 let err = SecurityLevel::try_from(4u8).unwrap_err();
136 match err {
138 ProtocolError::ConsensusError(ce) => match *ce {
139 ConsensusError::BasicError(BasicError::UnknownSecurityLevelError(_)) => {}
140 other => panic!("unexpected inner consensus error: {:?}", other),
141 },
142 other => panic!("expected ProtocolError::ConsensusError, got {:?}", other),
143 }
144 }
145
146 #[test]
147 fn test_security_level_try_from_u8_invalid_255() {
148 assert!(SecurityLevel::try_from(255u8).is_err());
149 }
150
151 #[test]
153 fn test_security_level_to_owned_byte_array() {
154 let arr: [u8; 1] = SecurityLevel::MASTER.into();
155 assert_eq!(arr, [0]);
156 let arr: [u8; 1] = SecurityLevel::CRITICAL.into();
157 assert_eq!(arr, [1]);
158 let arr: [u8; 1] = SecurityLevel::HIGH.into();
159 assert_eq!(arr, [2]);
160 let arr: [u8; 1] = SecurityLevel::MEDIUM.into();
161 assert_eq!(arr, [3]);
162 }
163
164 #[test]
166 fn test_security_level_to_static_byte_ref_all_variants() {
167 let r: &'static [u8; 1] = SecurityLevel::MASTER.into();
168 assert_eq!(r, &[0u8]);
169 let r: &'static [u8; 1] = SecurityLevel::CRITICAL.into();
170 assert_eq!(r, &[1u8]);
171 let r: &'static [u8; 1] = SecurityLevel::HIGH.into();
172 assert_eq!(r, &[2u8]);
173 let r: &'static [u8; 1] = SecurityLevel::MEDIUM.into();
174 assert_eq!(r, &[3u8]);
175 }
176
177 #[test]
179 fn test_security_level_display_matches_debug_form() {
180 assert_eq!(format!("{}", SecurityLevel::MASTER), "MASTER");
181 assert_eq!(format!("{}", SecurityLevel::CRITICAL), "CRITICAL");
182 assert_eq!(format!("{}", SecurityLevel::HIGH), "HIGH");
183 assert_eq!(format!("{}", SecurityLevel::MEDIUM), "MEDIUM");
184 }
185
186 #[test]
188 fn test_security_level_default_is_high() {
189 assert_eq!(SecurityLevel::default(), SecurityLevel::HIGH);
190 }
191
192 #[test]
194 fn test_security_level_full_range() {
195 let r = SecurityLevel::full_range();
196 assert_eq!(r.len(), 4);
197 assert_eq!(
198 r,
199 [
200 SecurityLevel::MASTER,
201 SecurityLevel::CRITICAL,
202 SecurityLevel::HIGH,
203 SecurityLevel::MEDIUM,
204 ]
205 );
206 }
207
208 #[test]
209 fn test_security_level_last_and_lowest_are_medium() {
210 assert_eq!(SecurityLevel::last(), SecurityLevel::MEDIUM);
211 assert_eq!(SecurityLevel::lowest_level(), SecurityLevel::MEDIUM);
212 }
213
214 #[test]
215 fn test_security_level_highest_is_master() {
216 assert_eq!(SecurityLevel::highest_level(), SecurityLevel::MASTER);
217 }
218
219 #[test]
221 fn test_stronger_security_than_master_vs_medium() {
222 assert!(SecurityLevel::MASTER.stronger_security_than(SecurityLevel::MEDIUM));
224 assert!(!SecurityLevel::MEDIUM.stronger_security_than(SecurityLevel::MASTER));
226 }
227
228 #[test]
229 fn test_stronger_security_than_is_not_reflexive() {
230 assert!(!SecurityLevel::HIGH.stronger_security_than(SecurityLevel::HIGH));
232 assert!(!SecurityLevel::MASTER.stronger_security_than(SecurityLevel::MASTER));
233 }
234
235 #[test]
236 fn test_stronger_security_than_full_matrix() {
237 let all = SecurityLevel::full_range();
238 for (i, a) in all.iter().enumerate() {
239 for (j, b) in all.iter().enumerate() {
240 assert_eq!(a.stronger_security_than(*b), i < j);
242 }
243 }
244 }
245
246 #[test]
248 fn test_stronger_or_equal_security_than_reflexive() {
249 for lvl in SecurityLevel::full_range() {
250 assert!(lvl.stronger_or_equal_security_than(lvl));
251 }
252 }
253
254 #[test]
255 fn test_stronger_or_equal_security_than_strict() {
256 assert!(SecurityLevel::MASTER.stronger_or_equal_security_than(SecurityLevel::HIGH));
257 assert!(!SecurityLevel::HIGH.stronger_or_equal_security_than(SecurityLevel::MASTER));
258 }
259
260 #[test]
262 fn test_security_level_ordering_master_lt_critical_lt_high_lt_medium() {
263 assert!(SecurityLevel::MASTER < SecurityLevel::CRITICAL);
264 assert!(SecurityLevel::CRITICAL < SecurityLevel::HIGH);
265 assert!(SecurityLevel::HIGH < SecurityLevel::MEDIUM);
266 }
267
268 #[test]
270 fn test_security_level_round_trip_u8() {
271 for v in 0u8..=3 {
272 let lvl = SecurityLevel::try_from(v).unwrap();
273 assert_eq!(lvl as u8, v);
274 }
275 }
276}