Skip to main content

cesr/core/matter/code/
verkey.rs

1use 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/// CESR codes for verification (public) keys, both transferable and non-transferable.
13#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
14pub enum VerKeyCode {
15    /// Ed25519 transferable (rotatable) public key.
16    Ed25519,
17    /// Ed25519 non-transferable (non-rotatable) public key.
18    Ed25519N,
19    /// secp256k1 (ECDSA) transferable compressed public key.
20    ECDSA256k1,
21    /// secp256k1 (ECDSA) non-transferable compressed public key.
22    ECDSA256k1N,
23    /// Ed448 transferable public key.
24    Ed448,
25    /// Ed448 non-transferable public key.
26    Ed448N,
27    /// secp256r1 / P-256 (ECDSA) transferable compressed public key.
28    ECDSA256r1,
29    /// secp256r1 / P-256 (ECDSA) non-transferable compressed public key.
30    ECDSA256r1N,
31}
32
33impl VerKeyCode {
34    /// Returns `true` if this key can be rotated (transferable prefix).
35    #[must_use]
36    pub const fn is_transferable(&self) -> bool {
37        matches!(
38            self,
39            Self::Ed25519 | Self::ECDSA256k1 | Self::Ed448 | Self::ECDSA256r1
40        )
41    }
42
43    /// Returns `true` if this key cannot be rotated (non-transferable prefix).
44    #[must_use]
45    pub const fn is_non_transferable(&self) -> bool {
46        !self.is_transferable()
47    }
48}
49
50impl Sealed for VerKeyCode {}
51
52impl CesrCode for VerKeyCode {
53    fn to_matter_code(&self) -> MatterCode {
54        match self {
55            Self::Ed25519 => MatterCode::Ed25519,
56            Self::Ed25519N => MatterCode::Ed25519N,
57            Self::ECDSA256k1 => MatterCode::ECDSA256k1,
58            Self::ECDSA256k1N => MatterCode::ECDSA256k1N,
59            Self::Ed448 => MatterCode::Ed448,
60            Self::Ed448N => MatterCode::Ed448N,
61            Self::ECDSA256r1 => MatterCode::ECDSA256r1,
62            Self::ECDSA256r1N => MatterCode::ECDSA256r1N,
63        }
64    }
65
66    fn as_str(&self) -> &'static str {
67        match self {
68            Self::Ed25519 => "D",
69            Self::Ed25519N => "B",
70            Self::ECDSA256k1 => "1AAB",
71            Self::ECDSA256k1N => "1AAA",
72            Self::Ed448 => "1AAD",
73            Self::Ed448N => "1AAC",
74            Self::ECDSA256r1 => "1AAJ",
75            Self::ECDSA256r1N => "1AAI",
76        }
77    }
78}
79
80impl TryFrom<MatterCode> for VerKeyCode {
81    type Error = ValidationError;
82
83    fn try_from(code: MatterCode) -> Result<Self, Self::Error> {
84        match code {
85            MatterCode::Ed25519 => Ok(Self::Ed25519),
86            MatterCode::Ed25519N => Ok(Self::Ed25519N),
87            MatterCode::ECDSA256k1 => Ok(Self::ECDSA256k1),
88            MatterCode::ECDSA256k1N => Ok(Self::ECDSA256k1N),
89            MatterCode::Ed448 => Ok(Self::Ed448),
90            MatterCode::Ed448N => Ok(Self::Ed448N),
91            MatterCode::ECDSA256r1 => Ok(Self::ECDSA256r1),
92            MatterCode::ECDSA256r1N => Ok(Self::ECDSA256r1N),
93            _ => Err(ValidationError::UnknownMatterCode(code.to_string())),
94        }
95    }
96}
97
98impl From<VerKeyCode> for MatterCode {
99    fn from(code: VerKeyCode) -> Self {
100        code.to_matter_code()
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    use crate::core::matter::code::MatterCode;
108
109    #[test]
110    fn verkey_code_to_matter_code_roundtrip() {
111        let codes = [
112            (VerKeyCode::Ed25519, MatterCode::Ed25519),
113            (VerKeyCode::Ed25519N, MatterCode::Ed25519N),
114            (VerKeyCode::ECDSA256k1, MatterCode::ECDSA256k1),
115            (VerKeyCode::ECDSA256k1N, MatterCode::ECDSA256k1N),
116            (VerKeyCode::Ed448, MatterCode::Ed448),
117            (VerKeyCode::Ed448N, MatterCode::Ed448N),
118            (VerKeyCode::ECDSA256r1, MatterCode::ECDSA256r1),
119            (VerKeyCode::ECDSA256r1N, MatterCode::ECDSA256r1N),
120        ];
121        for (vk, mc) in codes {
122            assert_eq!(vk.to_matter_code(), mc);
123            assert_eq!(VerKeyCode::try_from(mc).unwrap(), vk);
124            assert_eq!(MatterCode::from(vk), mc);
125        }
126    }
127
128    #[test]
129    fn verkey_code_rejects_non_verkey() {
130        assert!(VerKeyCode::try_from(MatterCode::Blake3_256).is_err());
131        assert!(VerKeyCode::try_from(MatterCode::Ed25519Seed).is_err());
132        assert!(VerKeyCode::try_from(MatterCode::Ed25519Sig).is_err());
133        assert!(VerKeyCode::try_from(MatterCode::Short).is_err());
134    }
135
136    #[test]
137    fn verkey_code_transferability() {
138        assert!(VerKeyCode::Ed25519.is_transferable());
139        assert!(!VerKeyCode::Ed25519.is_non_transferable());
140        assert!(!VerKeyCode::Ed25519N.is_transferable());
141        assert!(VerKeyCode::Ed25519N.is_non_transferable());
142    }
143
144    #[test]
145    fn verkey_code_as_str() {
146        assert_eq!(VerKeyCode::Ed25519.as_str(), "D");
147        assert_eq!(VerKeyCode::Ed25519N.as_str(), "B");
148        assert_eq!(VerKeyCode::ECDSA256k1N.as_str(), "1AAA");
149    }
150}