1use codec_multibase::bytes_to_multibase58btc;
6use codec_multicodec::{KeyMaterialKind, MULTICODEC_TABLE, VARIABLE_KEY_LENGTH};
7
8use crate::error::{CodecNameReason, MultikeyError};
9
10pub fn encode_multikey(codec_name: &str, public_key: &[u8]) -> Result<String, MultikeyError> {
15 let (canonical_codec_name, spec) = MULTICODEC_TABLE
16 .iter()
17 .find(|(name, _)| *name == codec_name)
18 .ok_or(MultikeyError::UnknownCodecName {
19 reason: CodecNameReason::Unsupported,
20 })?;
21
22 if spec.key_material != KeyMaterialKind::PublicKey {
23 return Err(MultikeyError::UnknownCodecName {
24 reason: CodecNameReason::Unsupported,
25 });
26 }
27
28 if spec.key_length == VARIABLE_KEY_LENGTH && public_key.is_empty() {
29 return Err(MultikeyError::KeyLengthMismatch {
30 codec_name: canonical_codec_name,
31 expected: spec.key_length,
32 actual: public_key.len(),
33 });
34 }
35
36 if spec.key_length != VARIABLE_KEY_LENGTH && public_key.len() != spec.key_length {
37 return Err(MultikeyError::KeyLengthMismatch {
38 codec_name: canonical_codec_name,
39 expected: spec.key_length,
40 actual: public_key.len(),
41 });
42 }
43
44 let capacity =
45 spec.codec
46 .len()
47 .checked_add(public_key.len())
48 .ok_or(MultikeyError::KeyLengthMismatch {
49 codec_name: canonical_codec_name,
50 expected: spec.key_length,
51 actual: public_key.len(),
52 })?;
53 let mut payload = Vec::with_capacity(capacity);
54 payload.extend_from_slice(spec.codec);
55 payload.extend_from_slice(public_key);
56
57 Ok(bytes_to_multibase58btc(&payload))
58}