use codec_multibase::bytes_to_multibase58btc;
use codec_multicodec::{KeyMaterialKind, MULTICODEC_TABLE, VARIABLE_KEY_LENGTH};
use crate::error::{CodecNameReason, MultikeyError};
pub fn encode_multikey(codec_name: &str, public_key: &[u8]) -> Result<String, MultikeyError> {
let (canonical_codec_name, spec) = MULTICODEC_TABLE
.iter()
.find(|(name, _)| *name == codec_name)
.ok_or(MultikeyError::UnknownCodecName {
reason: CodecNameReason::Unsupported,
})?;
if spec.key_material != KeyMaterialKind::PublicKey {
return Err(MultikeyError::UnknownCodecName {
reason: CodecNameReason::Unsupported,
});
}
if spec.key_length == VARIABLE_KEY_LENGTH && public_key.is_empty() {
return Err(MultikeyError::KeyLengthMismatch {
codec_name: canonical_codec_name,
expected: spec.key_length,
actual: public_key.len(),
});
}
if spec.key_length != VARIABLE_KEY_LENGTH && public_key.len() != spec.key_length {
return Err(MultikeyError::KeyLengthMismatch {
codec_name: canonical_codec_name,
expected: spec.key_length,
actual: public_key.len(),
});
}
let capacity =
spec.codec
.len()
.checked_add(public_key.len())
.ok_or(MultikeyError::KeyLengthMismatch {
codec_name: canonical_codec_name,
expected: spec.key_length,
actual: public_key.len(),
})?;
let mut payload = Vec::with_capacity(capacity);
payload.extend_from_slice(spec.codec);
payload.extend_from_slice(public_key);
Ok(bytes_to_multibase58btc(&payload))
}