1use alloc::string::ToString;
2use core::fmt;
3use core::marker::PhantomData;
4
5use crate::PasetoError;
6use crate::key::KeyType;
7use crate::paserk::KeyText;
8use crate::version::Version;
9
10pub trait IdVersion: Version {
12 fn hash_key(key_header: &'static str, key_data: &[u8]) -> [u8; 33];
14}
15
16pub struct KeyId<V: IdVersion, K: KeyType> {
18 pub(crate) id: [u8; 33],
19 _key: PhantomData<(V, K)>,
20}
21
22impl<V: IdVersion, K: KeyType> KeyId<V, K> {
23 pub fn as_bytes(&self) -> &[u8; 33] {
25 &self.id
26 }
27}
28
29impl<V: IdVersion, K: KeyType> Copy for KeyId<V, K> {}
30
31impl<V: IdVersion, K: KeyType> Clone for KeyId<V, K> {
32 fn clone(&self) -> Self {
33 *self
34 }
35}
36
37impl<V: IdVersion, K: KeyType> PartialEq for KeyId<V, K> {
38 fn eq(&self, other: &Self) -> bool {
39 self.id == other.id
40 }
41}
42
43impl<V: IdVersion, K: KeyType> PartialOrd for KeyId<V, K> {
44 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
45 Some(self.cmp(other))
46 }
47}
48
49impl<V: IdVersion, K: KeyType> Eq for KeyId<V, K> {}
50
51impl<V: IdVersion, K: KeyType> Ord for KeyId<V, K> {
52 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
53 self.id.cmp(&other.id)
54 }
55}
56
57impl<V: IdVersion, K: KeyType> core::hash::Hash for KeyId<V, K> {
58 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
59 self.id.hash(state);
60 }
61}
62
63impl<V: IdVersion, K: KeyType> From<&KeyText<V, K>> for KeyId<V, K> {
64 fn from(value: &KeyText<V, K>) -> Self {
65 Self {
66 id: V::hash_key(K::ID_HEADER, value.to_string().as_bytes()),
67 _key: PhantomData,
68 }
69 }
70}
71
72impl<V: IdVersion, K: KeyType> fmt::Display for KeyId<V, K> {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 f.write_str(V::PASERK_HEADER)?;
75 f.write_str(K::ID_HEADER)?;
76 crate::base64::write_to_fmt(&self.id, f)
77 }
78}
79
80impl<V: IdVersion, K: KeyType> core::str::FromStr for KeyId<V, K> {
81 type Err = PasetoError;
82
83 fn from_str(s: &str) -> Result<Self, Self::Err> {
84 let s = s
85 .strip_prefix(V::PASERK_HEADER)
86 .ok_or(PasetoError::InvalidKey)?;
87 let s = s
88 .strip_prefix(K::ID_HEADER)
89 .ok_or(PasetoError::InvalidKey)?;
90
91 let mut id = [0u8; 33];
92 if crate::base64::decode(s, &mut id)?.len() != 33 {
93 return Err(PasetoError::InvalidKey);
94 }
95
96 Ok(Self {
97 id,
98 _key: PhantomData,
99 })
100 }
101}
102
103serde_str!(
104 impl<V, K> KeyId<V, K>
105 where
106 V: IdVersion,
107 K: KeyType,
108 {
109 fn expecting() {
110 format_args!("a {}{} PASERK key id", V::PASERK_HEADER, K::ID_HEADER)
111 }
112 }
113);