1#![allow(clippy::needless_return)]
6
7use crate::AlgorithmError;
8#[cfg(any(
9 feature = "ed25519",
10 feature = "x25519",
11 feature = "secp256k1",
12 feature = "p256",
13 feature = "p384",
14 feature = "p521",
15 feature = "ml-dsa-44",
16 feature = "ml-dsa-65",
17 feature = "ml-dsa-87",
18 feature = "ml-kem-512",
19 feature = "ml-kem-768",
20 feature = "ml-kem-1024"
21))]
22use codec_multikey::encode_multikey;
23use crypto_core::Algorithm;
24
25#[cfg(feature = "p256")]
26fn compress_p256_public_key(input: &[u8]) -> Result<Vec<u8>, AlgorithmError> {
27 #[cfg(all(
28 feature = "p256",
29 feature = "native",
30 not(all(feature = "wasm", target_arch = "wasm32"))
31 ))]
32 {
33 return crypto_p256::compress_p256(input)
34 .map_err(|_| AlgorithmError::InvalidKey(Algorithm::P256));
35 }
36
37 #[cfg(all(feature = "p256", feature = "wasm", target_arch = "wasm32"))]
38 {
39 return crypto_p256::compress_p256(input)
40 .map_err(|_| AlgorithmError::InvalidKey(Algorithm::P256));
41 }
42
43 #[cfg(not(any(
44 all(
45 feature = "p256",
46 feature = "native",
47 not(all(feature = "wasm", target_arch = "wasm32"))
48 ),
49 all(feature = "p256", feature = "wasm", target_arch = "wasm32")
50 )))]
51 {
52 let _ = input;
53 Err(AlgorithmError::UnsupportedAlgorithm(Algorithm::P256))
54 }
55}
56
57#[cfg(feature = "p384")]
58fn compress_p384_public_key(input: &[u8]) -> Result<Vec<u8>, AlgorithmError> {
59 #[cfg(all(
60 feature = "p384",
61 feature = "native",
62 not(all(feature = "wasm", target_arch = "wasm32"))
63 ))]
64 {
65 return crypto_p384::compress_p384(input)
66 .map_err(|_| AlgorithmError::InvalidKey(Algorithm::P384));
67 }
68
69 #[cfg(all(feature = "p384", feature = "wasm", target_arch = "wasm32"))]
70 {
71 return crypto_p384::compress_p384(input)
72 .map_err(|_| AlgorithmError::InvalidKey(Algorithm::P384));
73 }
74
75 #[cfg(not(any(
76 all(
77 feature = "p384",
78 feature = "native",
79 not(all(feature = "wasm", target_arch = "wasm32"))
80 ),
81 all(feature = "p384", feature = "wasm", target_arch = "wasm32")
82 )))]
83 {
84 let _ = input;
85 Err(AlgorithmError::UnsupportedAlgorithm(Algorithm::P384))
86 }
87}
88
89#[cfg(feature = "p521")]
90fn compress_p521_public_key(input: &[u8]) -> Result<Vec<u8>, AlgorithmError> {
91 #[cfg(all(
92 feature = "p521",
93 feature = "native",
94 not(all(feature = "wasm", target_arch = "wasm32"))
95 ))]
96 {
97 return crypto_p521::compress_p521(input)
98 .map_err(|_| AlgorithmError::InvalidKey(Algorithm::P521));
99 }
100
101 #[cfg(all(feature = "p521", feature = "wasm", target_arch = "wasm32"))]
102 {
103 return crypto_p521::compress_p521(input)
104 .map_err(|_| AlgorithmError::InvalidKey(Algorithm::P521));
105 }
106
107 #[cfg(not(any(
108 all(
109 feature = "p521",
110 feature = "native",
111 not(all(feature = "wasm", target_arch = "wasm32"))
112 ),
113 all(feature = "p521", feature = "wasm", target_arch = "wasm32")
114 )))]
115 {
116 let _ = input;
117 Err(AlgorithmError::UnsupportedAlgorithm(Algorithm::P521))
118 }
119}
120
121#[cfg(any(feature = "p256", feature = "p384", feature = "p521"))]
122fn canonicalize_sec1_public_key(
123 alg: Algorithm,
124 public_key: &[u8],
125 compressed_len: usize,
126 uncompressed_len: usize,
127 raw_len: usize,
128 compress: fn(&[u8]) -> Result<Vec<u8>, AlgorithmError>,
129) -> Result<Vec<u8>, AlgorithmError> {
130 match public_key.len() {
131 len if len == compressed_len => Ok(public_key.to_vec()),
132 len if len == uncompressed_len => compress(public_key),
133 len if len == raw_len => {
134 let capacity = raw_len
135 .checked_add(1)
136 .ok_or(AlgorithmError::InvalidKey(alg))?;
137 let mut sec1 = Vec::with_capacity(capacity);
138 sec1.push(0x04);
139 sec1.extend_from_slice(public_key);
140 compress(&sec1)
141 }
142 _ => Err(AlgorithmError::InvalidKey(alg)),
143 }
144}
145
146#[cfg(not(any(
149 feature = "ed25519",
150 feature = "x25519",
151 feature = "secp256k1",
152 feature = "p256",
153 feature = "p384",
154 feature = "p521",
155 feature = "ml-dsa-44",
156 feature = "ml-dsa-65",
157 feature = "ml-dsa-87",
158 feature = "ml-kem-512",
159 feature = "ml-kem-768",
160 feature = "ml-kem-1024"
161)))]
162pub fn public_key_to_multikey(alg: Algorithm, public_key: &[u8]) -> Result<String, AlgorithmError> {
163 let _ = public_key;
164 Err(AlgorithmError::UnsupportedAlgorithm(alg))
165}
166
167#[cfg(any(
170 feature = "ed25519",
171 feature = "x25519",
172 feature = "secp256k1",
173 feature = "p256",
174 feature = "p384",
175 feature = "p521",
176 feature = "ml-dsa-44",
177 feature = "ml-dsa-65",
178 feature = "ml-dsa-87",
179 feature = "ml-kem-512",
180 feature = "ml-kem-768",
181 feature = "ml-kem-1024"
182))]
183pub fn public_key_to_multikey(alg: Algorithm, public_key: &[u8]) -> Result<String, AlgorithmError> {
184 let (codec, key_bytes) = match alg {
185 Algorithm::Ed25519 => {
186 #[cfg(feature = "ed25519")]
187 {
188 ("ed25519-pub", public_key.to_vec())
189 }
190 #[cfg(not(feature = "ed25519"))]
191 {
192 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
193 }
194 }
195 Algorithm::X25519 => {
196 #[cfg(feature = "x25519")]
197 {
198 ("x25519-pub", public_key.to_vec())
199 }
200 #[cfg(not(feature = "x25519"))]
201 {
202 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
203 }
204 }
205 Algorithm::Secp256k1 => {
206 #[cfg(feature = "secp256k1")]
207 {
208 ("secp256k1-pub", public_key.to_vec())
209 }
210 #[cfg(not(feature = "secp256k1"))]
211 {
212 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
213 }
214 }
215 Algorithm::P384 => {
216 #[cfg(feature = "p384")]
217 {
218 (
219 "p384-pub",
220 canonicalize_sec1_public_key(
221 alg,
222 public_key,
223 crypto_p384::P384_PUBLIC_KEY_COMPRESSED_LEN,
224 crypto_p384::P384_PUBLIC_KEY_UNCOMPRESSED_LEN,
225 crypto_p384::P384_PUBLIC_KEY_RAW_LEN,
226 compress_p384_public_key,
227 )?,
228 )
229 }
230 #[cfg(not(feature = "p384"))]
231 {
232 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
233 }
234 }
235 Algorithm::P521 => {
236 #[cfg(feature = "p521")]
237 {
238 (
239 "p521-pub",
240 canonicalize_sec1_public_key(
241 alg,
242 public_key,
243 crypto_p521::P521_PUBLIC_KEY_COMPRESSED_LEN,
244 crypto_p521::P521_PUBLIC_KEY_UNCOMPRESSED_LEN,
245 crypto_p521::P521_PUBLIC_KEY_RAW_LEN,
246 compress_p521_public_key,
247 )?,
248 )
249 }
250 #[cfg(not(feature = "p521"))]
251 {
252 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
253 }
254 }
255 Algorithm::MlDsa44 => {
256 #[cfg(feature = "ml-dsa-44")]
257 {
258 ("mldsa-44-pub", public_key.to_vec())
259 }
260 #[cfg(not(feature = "ml-dsa-44"))]
261 {
262 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
263 }
264 }
265 Algorithm::MlDsa65 => {
266 #[cfg(feature = "ml-dsa-65")]
267 {
268 ("mldsa-65-pub", public_key.to_vec())
269 }
270 #[cfg(not(feature = "ml-dsa-65"))]
271 {
272 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
273 }
274 }
275 Algorithm::MlDsa87 => {
276 #[cfg(feature = "ml-dsa-87")]
277 {
278 ("mldsa-87-pub", public_key.to_vec())
279 }
280 #[cfg(not(feature = "ml-dsa-87"))]
281 {
282 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
283 }
284 }
285 Algorithm::MlKem512 => {
286 #[cfg(feature = "ml-kem-512")]
287 {
288 ("mlkem-512-pub", public_key.to_vec())
289 }
290 #[cfg(not(feature = "ml-kem-512"))]
291 {
292 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
293 }
294 }
295 Algorithm::MlKem768 => {
296 #[cfg(feature = "ml-kem-768")]
297 {
298 ("mlkem-768-pub", public_key.to_vec())
299 }
300 #[cfg(not(feature = "ml-kem-768"))]
301 {
302 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
303 }
304 }
305 Algorithm::MlKem1024 => {
306 #[cfg(feature = "ml-kem-1024")]
307 {
308 ("mlkem-1024-pub", public_key.to_vec())
309 }
310 #[cfg(not(feature = "ml-kem-1024"))]
311 {
312 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
313 }
314 }
315 Algorithm::XWing768 | Algorithm::XWing1024 => {
316 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
317 }
318
319 Algorithm::P256 => {
321 #[cfg(not(feature = "p256"))]
322 {
323 return Err(AlgorithmError::UnsupportedAlgorithm(alg));
324 }
325
326 #[cfg(feature = "p256")]
327 {
328 let compressed = canonicalize_sec1_public_key(
329 alg,
330 public_key,
331 33,
332 65,
333 64,
334 compress_p256_public_key,
335 )?;
336
337 ("p256-pub", compressed)
338 }
339 }
340 };
341
342 encode_multikey(codec, &key_bytes).map_err(|_| AlgorithmError::InvalidKey(alg))
343}