use auths_keri::KeriPublicKey;
use auths_verifier::types::IdentityDID;
use super::kel_port::KelPort;
use crate::keri::{DidKeriResolution, Event, Prefix, ResolveError, parse_did_keri, validate_kel};
pub fn resolve_from_events(
events: &[Event],
did: &str,
prefix: &Prefix,
) -> Result<DidKeriResolution, ResolveError> {
let state = validate_kel(events)?;
let key_encoded = state.current_key().ok_or(ResolveError::NoCurrentKey)?;
let keri_key = KeriPublicKey::parse(key_encoded.as_str())
.map_err(|e| ResolveError::InvalidKeyEncoding(e.to_string()))?;
let curve = keri_key.curve();
let public_key = keri_key.as_bytes().to_vec();
Ok(DidKeriResolution {
#[allow(clippy::disallowed_methods)] did: IdentityDID::new_unchecked(did),
prefix: prefix.clone(),
public_key,
curve,
sequence: state.sequence,
can_rotate: state.can_rotate(),
is_abandoned: state.is_abandoned,
})
}
pub fn resolve_from_events_at_sequence(
events: &[Event],
did: &str,
prefix: &Prefix,
target_sequence: u128,
) -> Result<DidKeriResolution, ResolveError> {
let events_subset: Vec<_> = events
.iter()
.take_while(|e| e.sequence().value() <= target_sequence)
.cloned()
.collect();
if events_subset.is_empty() {
return Err(ResolveError::NotFound(format!(
"No events at sequence {}",
target_sequence
)));
}
resolve_from_events(&events_subset, did, prefix)
}
pub fn resolve_did_keri_via_port(
kel: &dyn KelPort,
did: &str,
) -> Result<DidKeriResolution, ResolveError> {
let prefix = parse_did_keri(did)?;
if !kel.exists(&prefix) {
return Err(ResolveError::NotFound(prefix.as_str().to_string()));
}
let events = kel.get_events(&prefix)?;
resolve_from_events(&events, did, &prefix)
}
pub fn resolve_did_keri_at_sequence_via_port(
kel: &dyn KelPort,
did: &str,
target_sequence: u128,
) -> Result<DidKeriResolution, ResolveError> {
let prefix = parse_did_keri(did)?;
if !kel.exists(&prefix) {
return Err(ResolveError::NotFound(prefix.as_str().to_string()));
}
let events = kel.get_events(&prefix)?;
resolve_from_events_at_sequence(&events, did, &prefix, target_sequence)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::keri::{
CesrKey, Event, IcpEvent, KeriSequence, Said, Threshold, VersionString, finalize_icp_event,
};
use auths_core::crypto::said::compute_next_commitment;
use ring::rand::SystemRandom;
use ring::signature::{Ed25519KeyPair, KeyPair};
fn make_test_inception() -> (IcpEvent, Vec<u8>) {
let rng = SystemRandom::new();
let current_pkcs8 = Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
let current_kp = Ed25519KeyPair::from_pkcs8(current_pkcs8.as_ref()).unwrap();
let next_pkcs8 = Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
let next_kp = Ed25519KeyPair::from_pkcs8(next_pkcs8.as_ref()).unwrap();
let current_pub_encoded =
auths_keri::KeriPublicKey::ed25519(current_kp.public_key().as_ref())
.expect("ed25519 verkey is 32 bytes")
.to_qb64()
.expect("cesride verkey encode is infallible");
let next_commitment = compute_next_commitment(
&auths_keri::KeriPublicKey::ed25519(next_kp.public_key().as_ref())
.expect("ed25519 verkey is 32 bytes"),
);
let icp = IcpEvent {
v: VersionString::placeholder(),
d: Said::default(),
i: Prefix::default(),
s: KeriSequence::new(0),
kt: Threshold::Simple(1),
k: vec![CesrKey::new_unchecked(current_pub_encoded)],
nt: Threshold::Simple(1),
n: vec![next_commitment],
bt: Threshold::Simple(0),
b: vec![],
c: vec![],
a: vec![],
};
let finalized = finalize_icp_event(icp).unwrap();
let pub_key = current_kp.public_key().as_ref().to_vec();
(finalized, pub_key)
}
#[test]
fn resolve_from_events_succeeds() {
let (icp, expected_key) = make_test_inception();
let prefix = icp.i.clone();
let did = format!("did:keri:{}", prefix.as_str());
let events = vec![Event::Icp(icp)];
let resolution = resolve_from_events(&events, &did, &prefix).unwrap();
assert_eq!(resolution.public_key, expected_key);
assert_eq!(resolution.sequence, 0);
assert!(resolution.can_rotate);
}
#[test]
fn resolve_from_events_empty_fails() {
let prefix = Prefix::new_unchecked("ETest".to_string());
let result = resolve_from_events_at_sequence(&[], "did:keri:ETest", &prefix, 0);
assert!(matches!(result, Err(ResolveError::NotFound(_))));
}
#[test]
fn resolve_via_port_not_found() {
let kel = InMemoryKelForTest::new();
let result = resolve_did_keri_via_port(&kel, "did:keri:ENonexistent");
assert!(matches!(result, Err(ResolveError::NotFound(_))));
}
#[test]
fn resolve_via_port_succeeds() {
let (icp, expected_key) = make_test_inception();
let prefix = icp.i.clone();
let did = format!("did:keri:{}", prefix);
let kel = InMemoryKelForTest::new();
kel.insert(&prefix, vec![Event::Icp(icp)]);
let resolution = resolve_did_keri_via_port(&kel, &did).unwrap();
assert_eq!(resolution.public_key, expected_key);
assert_eq!(resolution.sequence, 0);
}
#[test]
fn resolve_at_sequence_via_port() {
let (icp, expected_key) = make_test_inception();
let prefix = icp.i.clone();
let did = format!("did:keri:{}", prefix);
let kel = InMemoryKelForTest::new();
kel.insert(&prefix, vec![Event::Icp(icp)]);
let resolution = resolve_did_keri_at_sequence_via_port(&kel, &did, 0).unwrap();
assert_eq!(resolution.public_key, expected_key);
}
struct InMemoryKelForTest {
events: std::sync::Mutex<std::collections::HashMap<String, Vec<Event>>>,
}
impl InMemoryKelForTest {
fn new() -> Self {
Self {
events: std::sync::Mutex::new(std::collections::HashMap::new()),
}
}
fn insert(&self, prefix: &Prefix, events: Vec<Event>) {
self.events
.lock()
.unwrap()
.insert(prefix.as_str().to_string(), events);
}
}
impl KelPort for InMemoryKelForTest {
fn exists(&self, prefix: &Prefix) -> bool {
self.events.lock().unwrap().contains_key(prefix.as_str())
}
fn get_events(&self, prefix: &Prefix) -> Result<Vec<Event>, crate::keri::KelError> {
self.events
.lock()
.unwrap()
.get(prefix.as_str())
.cloned()
.ok_or_else(|| {
crate::keri::KelError::NotFound(format!(
"KEL not found for {}",
prefix.as_str()
))
})
}
fn create(&self, prefix: &Prefix, event: &IcpEvent) -> Result<(), crate::keri::KelError> {
let mut store = self.events.lock().unwrap();
store.insert(prefix.as_str().to_string(), vec![Event::Icp(event.clone())]);
Ok(())
}
fn append(&self, prefix: &Prefix, event: &Event) -> Result<(), crate::keri::KelError> {
let mut store = self.events.lock().unwrap();
store
.entry(prefix.as_str().to_string())
.or_default()
.push(event.clone());
Ok(())
}
}
}