Skip to main content

codec_multikey/
encode.rs

1// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2//
3// SPDX-License-Identifier: Apache-2.0
4
5use codec_multibase::bytes_to_multibase58btc;
6use codec_multicodec::{KeyMaterialKind, MULTICODEC_TABLE, VARIABLE_KEY_LENGTH};
7
8use crate::error::{CodecNameReason, MultikeyError};
9
10/// Encodes a public key as a multibase (base58btc) multikey string.
11///
12/// Fails closed: returns an error if the codec name is unknown or the key
13/// length does not match the codec.
14pub 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}