dpp/identity/identity_public_key/
purpose.rs1use crate::identity::Purpose::{
2 AUTHENTICATION, DECRYPTION, ENCRYPTION, OWNER, SYSTEM, TRANSFER, VOTING,
3};
4use anyhow::bail;
5use bincode::{Decode, Encode};
6#[cfg(feature = "cbor")]
7use ciborium::value::Value as CborValue;
8use serde_repr::{Deserialize_repr, Serialize_repr};
9use std::convert::TryFrom;
10
11#[repr(u8)]
12#[derive(
13 Debug,
14 PartialEq,
15 Eq,
16 Clone,
17 Copy,
18 Hash,
19 Serialize_repr,
20 Deserialize_repr,
21 Ord,
22 PartialOrd,
23 Encode,
24 Decode,
25 Default,
26 strum::EnumIter,
27)]
28pub enum Purpose {
29 #[default]
31 AUTHENTICATION = 0,
32 ENCRYPTION = 1,
34 DECRYPTION = 2,
36 TRANSFER = 3,
39 SYSTEM = 4,
41 VOTING = 5,
43 OWNER = 6,
45}
46
47impl From<Purpose> for [u8; 1] {
48 fn from(purpose: Purpose) -> Self {
49 [purpose as u8]
50 }
51}
52
53impl From<Purpose> for &'static [u8; 1] {
54 fn from(purpose: Purpose) -> Self {
55 match purpose {
56 AUTHENTICATION => &[0],
57 ENCRYPTION => &[1],
58 DECRYPTION => &[2],
59 TRANSFER => &[3],
60 SYSTEM => &[4],
61 VOTING => &[5],
62 OWNER => &[6],
63 }
64 }
65}
66
67impl TryFrom<u8> for Purpose {
68 type Error = anyhow::Error;
69 fn try_from(value: u8) -> Result<Self, Self::Error> {
70 match value {
71 0 => Ok(AUTHENTICATION),
72 1 => Ok(ENCRYPTION),
73 2 => Ok(DECRYPTION),
74 3 => Ok(TRANSFER),
75 4 => Ok(SYSTEM),
76 5 => Ok(VOTING),
77 6 => Ok(OWNER),
78 value => bail!("unrecognized purpose: {}", value),
79 }
80 }
81}
82
83impl TryFrom<i32> for Purpose {
84 type Error = anyhow::Error;
85 fn try_from(value: i32) -> Result<Self, Self::Error> {
86 match value {
87 0 => Ok(AUTHENTICATION),
88 1 => Ok(ENCRYPTION),
89 2 => Ok(DECRYPTION),
90 3 => Ok(TRANSFER),
91 4 => Ok(SYSTEM),
92 5 => Ok(VOTING),
93 6 => Ok(OWNER),
94 value => bail!("unrecognized purpose: {}", value),
95 }
96 }
97}
98
99#[cfg(feature = "cbor")]
100impl Into<CborValue> for Purpose {
101 fn into(self) -> CborValue {
102 CborValue::from(self as u128)
103 }
104}
105impl std::fmt::Display for Purpose {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 write!(f, "{self:?}")
108 }
109}
110
111impl Purpose {
112 pub fn full_range() -> [Purpose; 6] {
114 [
115 AUTHENTICATION,
116 ENCRYPTION,
117 DECRYPTION,
118 TRANSFER,
119 VOTING,
120 OWNER,
121 ]
122 }
123 pub fn searchable_purposes() -> [Purpose; 3] {
125 [AUTHENTICATION, TRANSFER, VOTING]
126 }
127 pub fn encryption_decryption() -> [Purpose; 2] {
129 [ENCRYPTION, DECRYPTION]
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 #[test]
139 fn test_purpose_try_from_u8_valid_all_variants() {
140 assert_eq!(Purpose::try_from(0u8).unwrap(), AUTHENTICATION);
141 assert_eq!(Purpose::try_from(1u8).unwrap(), ENCRYPTION);
142 assert_eq!(Purpose::try_from(2u8).unwrap(), DECRYPTION);
143 assert_eq!(Purpose::try_from(3u8).unwrap(), TRANSFER);
144 assert_eq!(Purpose::try_from(4u8).unwrap(), SYSTEM);
145 assert_eq!(Purpose::try_from(5u8).unwrap(), VOTING);
146 assert_eq!(Purpose::try_from(6u8).unwrap(), OWNER);
147 }
148
149 #[test]
151 fn test_purpose_try_from_u8_invalid() {
152 assert!(Purpose::try_from(7u8).is_err());
153 assert!(Purpose::try_from(255u8).is_err());
154 }
155
156 #[test]
158 fn test_purpose_try_from_i32_valid_all_variants() {
159 assert_eq!(Purpose::try_from(0i32).unwrap(), AUTHENTICATION);
160 assert_eq!(Purpose::try_from(1i32).unwrap(), ENCRYPTION);
161 assert_eq!(Purpose::try_from(2i32).unwrap(), DECRYPTION);
162 assert_eq!(Purpose::try_from(3i32).unwrap(), TRANSFER);
163 assert_eq!(Purpose::try_from(4i32).unwrap(), SYSTEM);
164 assert_eq!(Purpose::try_from(5i32).unwrap(), VOTING);
165 assert_eq!(Purpose::try_from(6i32).unwrap(), OWNER);
166 }
167
168 #[test]
169 fn test_purpose_try_from_i32_invalid() {
170 assert!(Purpose::try_from(-1i32).is_err());
171 assert!(Purpose::try_from(7i32).is_err());
172 assert!(Purpose::try_from(1_000_000i32).is_err());
173 }
174
175 #[test]
177 fn test_purpose_to_owned_byte_array() {
178 let arr: [u8; 1] = AUTHENTICATION.into();
179 assert_eq!(arr, [0]);
180 let arr: [u8; 1] = OWNER.into();
181 assert_eq!(arr, [6]);
182 let arr: [u8; 1] = SYSTEM.into();
183 assert_eq!(arr, [4]);
184 }
185
186 #[test]
188 fn test_purpose_to_static_byte_ref_all_variants() {
189 let r: &'static [u8; 1] = AUTHENTICATION.into();
190 assert_eq!(r, &[0u8]);
191 let r: &'static [u8; 1] = ENCRYPTION.into();
192 assert_eq!(r, &[1u8]);
193 let r: &'static [u8; 1] = DECRYPTION.into();
194 assert_eq!(r, &[2u8]);
195 let r: &'static [u8; 1] = TRANSFER.into();
196 assert_eq!(r, &[3u8]);
197 let r: &'static [u8; 1] = SYSTEM.into();
198 assert_eq!(r, &[4u8]);
199 let r: &'static [u8; 1] = VOTING.into();
200 assert_eq!(r, &[5u8]);
201 let r: &'static [u8; 1] = OWNER.into();
202 assert_eq!(r, &[6u8]);
203 }
204
205 #[test]
207 fn test_purpose_display_matches_debug_form() {
208 assert_eq!(format!("{}", AUTHENTICATION), "AUTHENTICATION");
209 assert_eq!(format!("{}", ENCRYPTION), "ENCRYPTION");
210 assert_eq!(format!("{}", DECRYPTION), "DECRYPTION");
211 assert_eq!(format!("{}", TRANSFER), "TRANSFER");
212 assert_eq!(format!("{}", SYSTEM), "SYSTEM");
213 assert_eq!(format!("{}", VOTING), "VOTING");
214 assert_eq!(format!("{}", OWNER), "OWNER");
215 }
216
217 #[test]
219 fn test_purpose_default_is_authentication() {
220 assert_eq!(Purpose::default(), AUTHENTICATION);
221 }
222
223 #[test]
225 fn test_purpose_full_range_contents() {
226 let full = Purpose::full_range();
228 assert_eq!(full.len(), 6);
229 assert!(full.contains(&AUTHENTICATION));
230 assert!(full.contains(&ENCRYPTION));
231 assert!(full.contains(&DECRYPTION));
232 assert!(full.contains(&TRANSFER));
233 assert!(full.contains(&VOTING));
234 assert!(full.contains(&OWNER));
235 assert!(!full.contains(&SYSTEM));
236 }
237
238 #[test]
239 fn test_purpose_searchable_purposes_contents() {
240 let searchable = Purpose::searchable_purposes();
241 assert_eq!(searchable.len(), 3);
242 assert_eq!(searchable, [AUTHENTICATION, TRANSFER, VOTING]);
243 }
244
245 #[test]
246 fn test_purpose_encryption_decryption_contents() {
247 let ed = Purpose::encryption_decryption();
248 assert_eq!(ed.len(), 2);
249 assert_eq!(ed, [ENCRYPTION, DECRYPTION]);
250 }
251
252 #[test]
254 fn test_purpose_round_trip_u8() {
255 for val in 0u8..=6 {
256 let p = Purpose::try_from(val).unwrap();
257 assert_eq!(p as u8, val);
258 }
259 }
260
261 #[test]
263 fn test_purpose_ordering_matches_discriminant() {
264 assert!(AUTHENTICATION < ENCRYPTION);
265 assert!(ENCRYPTION < DECRYPTION);
266 assert!(DECRYPTION < TRANSFER);
267 assert!(TRANSFER < SYSTEM);
268 assert!(SYSTEM < VOTING);
269 assert!(VOTING < OWNER);
270 }
271}