use async_trait::async_trait;
use chrono::{DateTime, Utc};
use crate::error::Error;
const ED25519_MULTICODEC: [u8; 2] = [0xed, 0x01];
#[async_trait]
pub trait Resolver: Send + Sync {
async fn resolve(&self, did: &str, key_id: &str, at_time: DateTime<Utc>) -> Option<Vec<u8>>;
}
pub fn parse_did_key(did: &str) -> Result<Vec<u8>, Error> {
const PREFIX: &str = "did:key:";
if !did.starts_with(PREFIX) {
return Err(Error::DidKey("not a did:key".into()));
}
let multibase = &did[PREFIX.len()..];
if !multibase.starts_with('z') {
return Err(Error::DidKey(
"did:key must use 'z' (base58btc) multibase prefix".into(),
));
}
let decoded = bs58::decode(&multibase[1..])
.into_vec()
.map_err(|e| Error::DidKey(format!("base58 decode: {e}")))?;
if decoded.len() != 34
|| decoded[0] != ED25519_MULTICODEC[0]
|| decoded[1] != ED25519_MULTICODEC[1]
{
return Err(Error::DidKey(
"did:key must encode an Ed25519 public key (multicodec 0xed01)".into(),
));
}
Ok(decoded[2..].to_vec())
}
pub fn did_key_from_ed25519_pubkey(pk: &[u8]) -> Result<String, Error> {
if pk.len() != 32 {
return Err(Error::DidKey("Ed25519 public key must be 32 bytes".into()));
}
let mut mc = Vec::with_capacity(34);
mc.extend_from_slice(&ED25519_MULTICODEC);
mc.extend_from_slice(pk);
Ok(format!("did:key:z{}", bs58::encode(mc).into_string()))
}
pub struct DidKeyResolver;
#[async_trait]
impl Resolver for DidKeyResolver {
async fn resolve(&self, did: &str, _key_id: &str, _at_time: DateTime<Utc>) -> Option<Vec<u8>> {
parse_did_key(did).ok()
}
}