use ed25519_dalek::SigningKey;
use rand::Rng;
use vta_sdk::credentials::CredentialBundle;
use vta_sdk::prelude::ed25519_multibase_pubkey;
fn mint_ed25519_did_key() -> (String, String) {
let mut seed = [0u8; 32];
rand::rng().fill_bytes(&mut seed);
let signing_key = SigningKey::from_bytes(&seed);
let public_key = signing_key.verifying_key().to_bytes();
let multibase_pubkey = ed25519_multibase_pubkey(&public_key);
let did = format!("did:key:{multibase_pubkey}");
let private_key_multibase = multibase::encode(multibase::Base::Base58Btc, seed);
(did, private_key_multibase)
}
pub fn generate_admin_did_key(
vta_did: impl Into<String>,
vta_url: Option<String>,
) -> (CredentialBundle, String) {
let (did, private_key_multibase) = mint_ed25519_did_key();
let bundle = CredentialBundle {
did: did.clone(),
private_key_multibase,
vta_did: vta_did.into(),
vta_url,
};
(bundle, did)
}
pub fn generate_unbound_admin_did_key() -> (String, String) {
mint_ed25519_did_key()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generated_did_is_did_key() {
let (bundle, did) = generate_admin_did_key("did:key:z6MkVTA", None);
assert_eq!(bundle.did, did);
assert!(did.starts_with("did:key:z"));
assert_eq!(bundle.vta_did, "did:key:z6MkVTA");
assert!(bundle.vta_url.is_none());
}
#[test]
fn generated_dids_are_unique() {
let a = generate_admin_did_key("did:key:z6MkVTA", None).1;
let b = generate_admin_did_key("did:key:z6MkVTA", None).1;
assert_ne!(a, b);
}
#[test]
fn private_key_multibase_roundtrips_to_seed() {
let (bundle, _) = generate_admin_did_key("did:key:z6MkVTA", None);
let (_, decoded) = multibase::decode(&bundle.private_key_multibase).unwrap();
assert_eq!(decoded.len(), 32, "Ed25519 seed must be 32 bytes");
}
#[test]
fn derived_did_matches_seed() {
let (bundle, did) = generate_admin_did_key("did:key:z6MkVTA", None);
let (_, seed_bytes) = multibase::decode(&bundle.private_key_multibase).unwrap();
let seed: [u8; 32] = seed_bytes.try_into().unwrap();
let signing_key = SigningKey::from_bytes(&seed);
let pubkey = signing_key.verifying_key().to_bytes();
let rederived = format!("did:key:{}", ed25519_multibase_pubkey(&pubkey));
assert_eq!(rederived, did);
}
#[test]
fn unbound_did_key_has_valid_shape() {
let (did, private_key_multibase) = generate_unbound_admin_did_key();
assert!(did.starts_with("did:key:z"));
let (_, decoded) = multibase::decode(&private_key_multibase).unwrap();
assert_eq!(decoded.len(), 32, "Ed25519 seed must be 32 bytes");
}
#[test]
fn unbound_dids_are_unique() {
let (a, _) = generate_unbound_admin_did_key();
let (b, _) = generate_unbound_admin_did_key();
assert_ne!(a, b);
}
#[test]
fn unbound_seed_round_trips_to_did() {
let (did, private_key_multibase) = generate_unbound_admin_did_key();
let (_, seed_bytes) = multibase::decode(&private_key_multibase).unwrap();
let seed: [u8; 32] = seed_bytes.try_into().unwrap();
let signing_key = SigningKey::from_bytes(&seed);
let pubkey = signing_key.verifying_key().to_bytes();
let rederived = format!("did:key:{}", ed25519_multibase_pubkey(&pubkey));
assert_eq!(rederived, did);
}
}