key_resolver/
ed25519_verification_key2020.rs

1use fi_common::error::Error;
2
3use crate::common::{KeyPair, VerificationKey};
4
5pub(crate) const SUITE_ID: &str = "Ed25519VerificationKey2020";
6pub(crate) const SUITE_CONTEXT: &str = "https://w3id.org/security/suites/ed25519-2020/v1";
7
8// multibase base58-btc header
9const MULTIBASE_BASE58BTC_HEADER: &str = "z";
10// multicodec ed25519-pub header as varint
11const MULTICODEC_ED25519_PUB_HEADER: [u8; 2] = [0xed, 0x01];
12// multicodec ed25519-priv header as varint
13const MULTICODEC_ED25519_PRIV_HEADER: [u8; 2] = [0xed, 0x01];
14
15pub struct Ed25519VerificationKey2020 {
16    _type: String,
17    id: Option<String>,
18    controller: Option<String>,
19    public_key_multibase: String,
20    private_key_multibase: Option<String>,
21    revoked: bool,
22}
23
24impl Ed25519VerificationKey2020 {
25    pub fn new(
26        controller: Option<String>,
27        public_key_multibase: String,
28        private_key_multibase: Option<String>,
29        fingerprint: Option<String>,
30    ) -> Result<Self, Error> {
31        if !Ed25519VerificationKey2020::is_valid_key_header(
32            &public_key_multibase,
33            &MULTICODEC_ED25519_PUB_HEADER,
34        ) {
35            return Err(Error::new(
36                format!(
37                    "'publicKeyMultibase' has invalid header bytes: '{}'.",
38                    public_key_multibase
39                )
40                .as_str(),
41            ));
42        }
43
44        if private_key_multibase.is_some()
45            && !Ed25519VerificationKey2020::is_valid_key_header(
46                &private_key_multibase.clone().unwrap(),
47                &MULTICODEC_ED25519_PRIV_HEADER,
48            )
49        {
50            return Err(Error::new(
51                format!(
52                    "'publicKeyMultibase' has invalid header bytes: '{}'.",
53                    private_key_multibase.unwrap()
54                )
55                .as_str(),
56            ));
57        }
58
59        let mut id: Option<String> = None;
60        if controller.is_some() && fingerprint.is_some() {
61            let ctrler = controller.clone().unwrap();
62            let fprint = fingerprint.clone().unwrap();
63            id = Some(format!("{}#{}", ctrler, fprint));
64        }
65
66        Ok(Ed25519VerificationKey2020 {
67            _type: String::from(SUITE_ID),
68            id,
69            controller,
70            public_key_multibase,
71            private_key_multibase,
72            revoked: false,
73        })
74    }
75
76    fn is_valid_key_header(multibase_key: &String, expected_header: &[u8; 2]) -> bool {
77        if !multibase_key[0..1].eq(MULTIBASE_BASE58BTC_HEADER) {
78            return false;
79        }
80
81        let decoded = multibase::decode(&multibase_key);
82        let (_, decoded_key_bytes) = match decoded {
83            Ok(val) => val,
84            Err(_error) => return false,
85        };
86
87        decoded_key_bytes[0] == expected_header[0] && decoded_key_bytes[1] == expected_header[1]
88    }
89}
90
91impl VerificationKey for Ed25519VerificationKey2020 {
92    fn from_fingerprint(fingerprint: &str) -> Result<Self, Error> {
93        Ed25519VerificationKey2020::new(
94            None,
95            String::from(fingerprint),
96            None,
97            Some(String::from(fingerprint)),
98        )
99    }
100
101    fn get_suite_id() -> &'static str
102    where
103        Self: Sized,
104    {
105        SUITE_ID
106    }
107
108    fn get_suite_context() -> &'static str
109    where
110        Self: Sized,
111    {
112        SUITE_CONTEXT
113    }
114    fn get_private_key_content(&self) -> &Option<String> {
115        &self.private_key_multibase
116    }
117    fn get_public_key_content(&self) -> &String {
118        &self.public_key_multibase
119    }
120
121    fn get_current_suite_id(&self) -> &'static str
122    where
123        Self: Sized,
124    {
125        SUITE_ID
126    }
127
128    fn get_current_suite_context(&self) -> &'static str
129    where
130        Self: Sized,
131    {
132        SUITE_CONTEXT
133    }
134
135    fn get_controller(&self) -> &Option<String> {
136        &self.controller
137    }
138    fn export(&self, public_key: bool, private_key: bool, include_context: bool) -> KeyPair {
139        KeyPair {
140            id: self.id.clone(),
141            _type: self._type.clone(),
142            context: match include_context {
143                true => Some(String::from(SUITE_CONTEXT)),
144                false => None,
145            },
146            public_key_base58: None,
147            private_key_base58: None,
148            private_key_multibase: match private_key {
149                true => self.private_key_multibase.clone(),
150                false => None,
151            },
152            public_key_multibase: match public_key {
153                true => Some(self.public_key_multibase.clone()),
154                false => None,
155            },
156            revoked: self.revoked,
157            controller: self.controller.clone(),
158        }
159    }
160
161    fn get_type(&self) -> String {
162        self._type.clone()
163    }
164}