key_resolver/
x25519_key_agreement_key2020.rs

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