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
16const MULTICODEC_ED25519_PUB_HEADER: [u8; 2] = [0xed, 0x01];
18const MULTICODEC_ED25519_PRIV_HEADER: [u8; 2] = [0x80, 0x26];
20const MULTICODEC_X25519_PUB_HEADER: [u8; 2] = [0xec, 0x01];
22const 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}