key_resolver/
x25519_key_agreement_key2019.rs

1use bs58::encode;
2use fi_common::error::Error;
3
4use crate::{
5    common::{AgreementKey, KeyPair, VerificationKey},
6    ed25519_verification_key2018::Ed25519VerificationKey2018,
7    util::{
8        ed25519_to_x25519_privkey, ed25519_to_x25519_pubkey, get_key_bytes_from_key_pair_bytes,
9        MULTIBASE_BASE58BTC_HEADER,
10    },
11};
12
13pub const SUITE_ID: &str = "X25519KeyAgreementKey2019";
14
15pub const SUITE_CONTEXT: &str = "https://w3id.org/security/suites/x25519-2019/v1";
16
17pub struct X25519KeyAgreementKey2019 {
18    _type: String,
19    id: Option<String>,
20    controller: Option<String>,
21    public_key_base58: String,
22    private_key_base58: Option<String>,
23    revoked: bool,
24}
25
26impl X25519KeyAgreementKey2019 {
27    pub fn new(
28        controller: Option<String>,
29        public_key_base58: String,
30        private_key_base58: Option<String>,
31        fingerprint: Option<String>,
32    ) -> Self {
33        let mut id: Option<String> = None;
34        if controller.is_some() && fingerprint.is_some() {
35            let ctrler = controller.clone().unwrap();
36            let fprint = fingerprint.clone().unwrap();
37            id = Some(format!("{}#{}", ctrler, fprint));
38        }
39
40        X25519KeyAgreementKey2019 {
41            _type: String::from(SUITE_ID),
42            id,
43            controller,
44            public_key_base58,
45            private_key_base58,
46            revoked: false,
47        }
48    }
49
50    pub fn from_ed25519_verification_key2018(
51        key_pair: &Box<dyn VerificationKey>,
52    ) -> Result<X25519KeyAgreementKey2019, Error> {
53        if !key_pair
54            .get_current_suite_id()
55            .eq(Ed25519VerificationKey2018::get_suite_id())
56        {
57            return Err(Error::new(
58                "'key_pair' is not a Ed25519VerificationKey2018 struct instance",
59            ));
60        }
61
62        let public_key_content = key_pair.get_public_key_content();
63
64        let public_key_base58 = match convert_from_ed_public_key(public_key_content) {
65            Ok(val) => val,
66            Err(error) => return Err(error),
67        };
68
69        let private_key_content_option = key_pair.get_private_key_content();
70
71        let mut private_key_base58: Option<String> = None;
72        if private_key_content_option.is_some() {
73            let private_key_content = private_key_content_option.clone().unwrap();
74
75            if !public_key_content.starts_with(MULTIBASE_BASE58BTC_HEADER) {
76                return Err(Error::new(
77                format!("Expecting 'privateKeyMultibase' value to be multibase base58btc {} encoded (must start with 'z').", private_key_content).as_str(),
78            ));
79            }
80
81            let private_key = match convert_from_ed_private_key(&private_key_content) {
82                Ok(val) => val,
83                Err(error) => return Err(error),
84            };
85
86            private_key_base58 = Some(private_key);
87        }
88
89        Ok(X25519KeyAgreementKey2019::new(
90            key_pair.get_controller().clone(),
91            public_key_base58,
92            private_key_base58,
93            Some(key_pair.get_public_key_content().clone()),
94        ))
95    }
96}
97
98fn convert_from_ed_public_key(public_key_base58: &String) -> Result<String, Error> {
99    let ed_pub_key_bytes_builder = bs58::decode(public_key_base58);
100
101    let mut ed_pub_key_bytes = match ed_pub_key_bytes_builder.into_vec() {
102        Ok(val) => val,
103        Err(error) => return Err(Error::new(error.to_string().as_str())),
104    };
105
106    let ed25519_pub_key: [u8; 32] =
107        match get_key_bytes_from_key_pair_bytes(&mut ed_pub_key_bytes, true) {
108            Ok(val) => val,
109            Err(error) => {
110                return Err(error);
111            }
112        };
113
114    let dh_pub_key_bytes = match ed25519_to_x25519_pubkey(&ed25519_pub_key) {
115        Ok(val) => val,
116        Err(error) => return Err(error),
117    };
118
119    let dh_pub_key_bytes_base58_builder = encode(dh_pub_key_bytes);
120
121    Ok(dh_pub_key_bytes_base58_builder.into_string())
122}
123
124fn convert_from_ed_private_key(private_key_base58: &String) -> Result<String, Error> {
125    let ed_pri_key_bytes_builder = bs58::decode(private_key_base58);
126
127    let mut ed_pri_key_bytes = match ed_pri_key_bytes_builder.into_vec() {
128        Ok(val) => val,
129        Err(error) => return Err(Error::new(error.to_string().as_str())),
130    };
131
132    let ed25519_priv_key: [u8; 32] =
133        match get_key_bytes_from_key_pair_bytes(&mut ed_pri_key_bytes, false) {
134            Ok(val) => val,
135            Err(error) => {
136                return Err(error);
137            }
138        };
139
140    let dh_priv_key_bytes = ed25519_to_x25519_privkey(&ed25519_priv_key);
141
142    let dh_priv_key_bytes_base58_builder = encode(dh_priv_key_bytes);
143
144    Ok(dh_priv_key_bytes_base58_builder.into_string())
145}
146
147impl AgreementKey for X25519KeyAgreementKey2019 {
148    fn export(&self, public_key: bool, private_key: bool, include_context: bool) -> KeyPair {
149        KeyPair {
150            id: self.id.clone(),
151            _type: self._type.clone(),
152            context: match include_context {
153                true => Some(String::from(SUITE_CONTEXT)),
154                false => None,
155            },
156            public_key_base58: match public_key {
157                true => Some(self.public_key_base58.clone()),
158                false => None,
159            },
160            private_key_base58: match private_key {
161                true => self.private_key_base58.clone(),
162                false => None,
163            },
164            private_key_multibase: None,
165            public_key_multibase: None,
166            revoked: self.revoked,
167            controller: self.controller.clone(),
168        }
169    }
170
171    fn get_controller(&self) -> &Option<String> {
172        &self.controller
173    }
174
175    fn get_private_key_content(&self) -> &Option<String> {
176        &self.private_key_base58
177    }
178
179    fn get_public_key_content(&self) -> &String {
180        &self.public_key_base58
181    }
182
183    fn get_suite_context() -> &'static str
184    where
185        Self: Sized,
186    {
187        SUITE_CONTEXT
188    }
189
190    fn get_current_suite_context(&self) -> &'static str
191    where
192        Self: Sized,
193    {
194        SUITE_CONTEXT
195    }
196}