use std::collections::{BTreeMap, HashMap};
use contextgraph_types::{
ALGORITHM_ED25519, AttestationVerdict, ContextFrame, ContextQueryResult, FrameAttestation,
FrameId, InclusionProof, ProvenanceAttestation, verify_frame_attestation,
verify_frame_inclusion,
};
use serde::{Deserialize, Serialize};
const COMMITMENT_LEN: usize = "sha256:".len() + 64;
const ED25519_SIGNATURE_HEX_LEN: usize = 128;
const ED25519_PUBLIC_KEY_HEX_LEN: usize = 64;
const MAX_ECHOED_IDENTIFIER: usize = 128;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TrustedKey {
pub key_id: String,
pub public_key: String,
}
impl TrustedKey {
pub fn ed25519_hex(key_id: impl Into<String>, public_key: impl Into<String>) -> Option<Self> {
let public_key = public_key.into();
if public_key.len() != ED25519_PUBLIC_KEY_HEX_LEN || decode_hex(&public_key).is_none() {
return None;
}
Some(Self {
key_id: key_id.into(),
public_key,
})
}
pub fn ed25519_bytes(key_id: impl Into<String>, public_key: &[u8; 32]) -> Self {
Self {
key_id: key_id.into(),
public_key: encode_hex(public_key),
}
}
pub fn fingerprint(&self) -> Option<String> {
let bytes = decode_hex(&self.public_key)?;
Some(contextgraph_types::digest_string(&sha256(&bytes)))
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct TrustStore {
#[serde(default)]
keys: HashMap<String, BTreeMap<String, TrustedKey>>,
}
impl TrustStore {
pub fn new() -> Self {
Self::default()
}
pub fn trust(&mut self, provider_id: impl Into<String>, key: TrustedKey) {
self.keys
.entry(provider_id.into())
.or_default()
.insert(key.key_id.clone(), key);
}
pub fn revoke(&mut self, provider_id: &str, key_id: &str) -> bool {
let Some(keys) = self.keys.get_mut(provider_id) else {
return false;
};
let removed = keys.remove(key_id).is_some();
if keys.is_empty() {
self.keys.remove(provider_id);
}
removed
}
pub fn key(&self, provider_id: &str, key_id: &str) -> Option<&TrustedKey> {
self.keys.get(provider_id)?.get(key_id)
}
pub fn keys_for(&self, provider_id: &str) -> impl Iterator<Item = &TrustedKey> {
self.keys
.get(provider_id)
.into_iter()
.flat_map(|k| k.values())
}
pub fn is_empty(&self) -> bool {
self.keys.values().all(|keys| keys.is_empty())
}
pub fn check(
&self,
provider_id: &str,
frame: &ContextFrame,
attestation: &ProvenanceAttestation,
) -> AttestationState {
self.check_signed_as(provider_id, provider_id, frame, attestation)
}
pub fn check_signed_as(
&self,
local_id: &str,
signing_id: &str,
frame: &ContextFrame,
attestation: &ProvenanceAttestation,
) -> AttestationState {
let provider_id = local_id;
if attestation.algorithm != ALGORITHM_ED25519 {
return AttestationState::UnknownAlgorithm {
algorithm: echoed(&attestation.algorithm),
};
}
let Some(key) = self.key(provider_id, &attestation.key_id) else {
return AttestationState::NoTrustedKey {
key_id: echoed(&attestation.key_id),
};
};
if attestation.signed_commitment.len() != COMMITMENT_LEN {
return AttestationState::Invalid {
verdict: AttestationVerdict::MalformedCommitment,
};
}
if attestation.signature.len() != ED25519_SIGNATURE_HEX_LEN {
return AttestationState::Invalid {
verdict: AttestationVerdict::MalformedSignature,
};
}
let Some(public_key) = decode_hex(&key.public_key) else {
return AttestationState::Invalid {
verdict: AttestationVerdict::MalformedKey,
};
};
match verify_frame_attestation(signing_id, frame, attestation, &public_key) {
verdict @ (AttestationVerdict::Valid | AttestationVerdict::ValidIdentityOnly) => {
AttestationState::Attested {
key_id: attestation.key_id.clone(),
attester_id: echoed(&attestation.attester_id),
covers_content: verdict.binds_content(),
}
}
verdict => AttestationState::Invalid { verdict },
}
}
pub fn check_result(
&self,
provider_id: &str,
result: &ContextQueryResult,
) -> Vec<FrameAttestationOutcome> {
self.check_result_signed_as(provider_id, provider_id, result)
}
pub fn check_result_signed_as(
&self,
local_id: &str,
signing_id: &str,
result: &ContextQueryResult,
) -> Vec<FrameAttestationOutcome> {
let mut offered: HashMap<&FrameId, &FrameAttestation> = HashMap::new();
for entry in result.frame_attestations.iter().take(result.frames.len()) {
offered.entry(&entry.frame).or_insert(entry);
}
result
.frames
.iter()
.map(|frame| {
let signing_identity = frame.identity(signing_id);
let state = match offered.get(&signing_identity) {
Some(entry) => self.check_entry(
local_id,
signing_id,
frame,
entry,
result.result_attestation.as_ref(),
),
None => AttestationState::Unattested,
};
FrameAttestationOutcome {
frame: frame.identity(local_id),
state,
}
})
.collect()
}
fn check_entry(
&self,
local_id: &str,
signing_id: &str,
frame: &ContextFrame,
entry: &FrameAttestation,
result_attestation: Option<&ProvenanceAttestation>,
) -> AttestationState {
if let Some(attestation) = &entry.attestation {
return self.check_signed_as(local_id, signing_id, frame, attestation);
}
match (&entry.inclusion_proof, result_attestation) {
(Some(proof), Some(root)) => {
self.check_inclusion(local_id, signing_id, frame, proof, root)
}
_ => AttestationState::UnusableEvidence,
}
}
fn check_inclusion(
&self,
local_id: &str,
signing_id: &str,
frame: &ContextFrame,
proof: &InclusionProof,
root: &ProvenanceAttestation,
) -> AttestationState {
if root.algorithm != ALGORITHM_ED25519 {
return AttestationState::UnknownAlgorithm {
algorithm: echoed(&root.algorithm),
};
}
let Some(key) = self.key(local_id, &root.key_id) else {
return AttestationState::NoTrustedKey {
key_id: echoed(&root.key_id),
};
};
if root.signed_commitment.len() != COMMITMENT_LEN {
return AttestationState::Invalid {
verdict: AttestationVerdict::MalformedCommitment,
};
}
if root.signature.len() != ED25519_SIGNATURE_HEX_LEN {
return AttestationState::Invalid {
verdict: AttestationVerdict::MalformedSignature,
};
}
let Some(public_key) = decode_hex(&key.public_key) else {
return AttestationState::Invalid {
verdict: AttestationVerdict::MalformedKey,
};
};
match verify_frame_inclusion(signing_id, frame, proof, root, &public_key) {
verdict @ (AttestationVerdict::Valid | AttestationVerdict::ValidIdentityOnly) => {
AttestationState::Attested {
key_id: root.key_id.clone(),
attester_id: echoed(&root.attester_id),
covers_content: verdict.binds_content(),
}
}
verdict => AttestationState::Invalid { verdict },
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum AttestationState {
#[default]
NotChecked,
Unattested,
Attested {
key_id: String,
attester_id: String,
covers_content: bool,
},
NoTrustedKey {
key_id: String,
},
UnknownAlgorithm {
algorithm: String,
},
UnusableEvidence,
Invalid {
verdict: AttestationVerdict,
},
}
impl AttestationState {
pub fn is_attested(&self) -> bool {
matches!(self, Self::Attested { .. })
}
pub fn covers_content(&self) -> bool {
matches!(
self,
Self::Attested {
covers_content: true,
..
}
)
}
pub fn was_offered(&self) -> bool {
!matches!(self, Self::NotChecked | Self::Unattested)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FrameAttestationOutcome {
pub frame: FrameId,
pub state: AttestationState,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct AttestationLedger {
states: BTreeMap<FrameId, AttestationState>,
}
impl AttestationLedger {
pub fn new() -> Self {
Self::default()
}
pub fn record(&mut self, outcome: FrameAttestationOutcome) {
self.states.insert(outcome.frame, outcome.state);
}
pub fn state_for(&self, frame: &FrameId) -> AttestationState {
self.states
.get(frame)
.cloned()
.unwrap_or(AttestationState::NotChecked)
}
pub fn is_empty(&self) -> bool {
self.states.is_empty()
}
pub fn len(&self) -> usize {
self.states.len()
}
}
impl FromIterator<FrameAttestationOutcome> for AttestationLedger {
fn from_iter<I: IntoIterator<Item = FrameAttestationOutcome>>(outcomes: I) -> Self {
let mut ledger = Self::new();
for outcome in outcomes {
ledger.record(outcome);
}
ledger
}
}
fn echoed(value: &str) -> String {
if value.len() <= MAX_ECHOED_IDENTIFIER {
return value.to_string();
}
let mut end = MAX_ECHOED_IDENTIFIER;
while end > 0 && !value.is_char_boundary(end) {
end -= 1;
}
value[..end].to_string()
}
fn decode_hex(hex: &str) -> Option<Vec<u8>> {
let bytes = hex.as_bytes();
if !bytes.len().is_multiple_of(2) {
return None;
}
let mut out = Vec::with_capacity(bytes.len() / 2);
let mut index = 0;
while index < bytes.len() {
let hi = (*bytes.get(index)? as char).to_digit(16)?;
let lo = (*bytes.get(index + 1)? as char).to_digit(16)?;
out.push((hi * 16 + lo) as u8);
index += 2;
}
Some(out)
}
fn encode_hex(bytes: &[u8]) -> String {
let mut out = String::with_capacity(bytes.len() * 2);
for byte in bytes {
out.push(char::from_digit((byte >> 4) as u32, 16).expect("nibble is < 16"));
out.push(char::from_digit((byte & 0x0f) as u32, 16).expect("nibble is < 16"));
}
out
}
fn sha256(bytes: &[u8]) -> [u8; 32] {
use sha2::{Digest, Sha256};
Sha256::digest(bytes).into()
}
#[cfg(test)]
mod tests {
use super::*;
use contextgraph_types::{
FrameKind, Provenance, public_key_for, sign_commitment, sign_frame_attestation,
};
const SEED: [u8; 32] = [3u8; 32];
const OTHER_SEED: [u8; 32] = [9u8; 32];
const PROVIDER: &str = "docs";
const KEY_ID: &str = "docs-2026-08";
fn frame(id: &str) -> ContextFrame {
let mut frame = digestless_frame(id);
frame.content_digest = Some(format!("sha256:{}", "cd".repeat(32)));
frame
}
fn digestless_frame(id: &str) -> ContextFrame {
let mut frame = ContextFrame::full(id, FrameKind::Doc, "Title", "content", 0.9, 4);
frame.provenance = vec![Provenance {
kind: "file".into(),
uri: Some("file:///repo/README.md".into()),
range: Some("L1-4".into()),
digest: Some(format!("sha256:{}", "ab".repeat(32))),
method: None,
by: None,
}];
frame
}
fn signed(frame: &ContextFrame, seed: &[u8; 32]) -> ProvenanceAttestation {
sign_frame_attestation(
PROVIDER,
frame,
seed,
KEY_ID,
"docs-provider",
"2026-08-29T00:00:00Z",
)
}
fn store_trusting(seed: &[u8; 32]) -> TrustStore {
let mut store = TrustStore::new();
store.trust(
PROVIDER,
TrustedKey::ed25519_bytes(KEY_ID, &public_key_for(seed)),
);
store
}
#[test]
fn a_signature_from_a_trusted_key_is_attested() {
let frame = frame("frm_1");
let attestation = signed(&frame, &SEED);
let state = store_trusting(&SEED).check(PROVIDER, &frame, &attestation);
assert_eq!(
state,
AttestationState::Attested {
key_id: KEY_ID.to_string(),
attester_id: "docs-provider".to_string(),
covers_content: true,
}
);
assert!(state.is_attested());
assert!(state.covers_content());
}
#[test]
fn a_signed_frame_with_no_content_digest_is_attested_over_nothing_it_says() {
let original = digestless_frame("frm_1");
let attestation = signed(&original, &SEED);
let store = store_trusting(&SEED);
let state = store.check(PROVIDER, &original, &attestation);
assert!(state.is_attested());
assert!(
!state.covers_content(),
"a frame with no content_digest has no signed bytes"
);
let mut rewritten = original.clone();
rewritten.content = Some("words the provider never signed".to_string());
assert_eq!(
store.check(PROVIDER, &rewritten, &attestation),
state,
"the same signature still verifies over the rewritten content"
);
}
#[test]
fn an_unknown_key_id_is_a_configuration_gap_not_a_forgery_finding() {
let frame = frame("frm_1");
let attestation = signed(&frame, &SEED);
let mut store = TrustStore::new();
store.trust(
PROVIDER,
TrustedKey::ed25519_bytes("some-other-key", &public_key_for(&SEED)),
);
assert_eq!(
store.check(PROVIDER, &frame, &attestation),
AttestationState::NoTrustedKey {
key_id: KEY_ID.to_string()
}
);
}
#[test]
fn a_key_trusted_for_another_provider_does_not_carry_over() {
let frame = frame("frm_1");
let attestation = signed(&frame, &SEED);
let mut store = TrustStore::new();
store.trust(
"some-other-provider",
TrustedKey::ed25519_bytes(KEY_ID, &public_key_for(&SEED)),
);
assert_eq!(
store.check(PROVIDER, &frame, &attestation),
AttestationState::NoTrustedKey {
key_id: KEY_ID.to_string()
}
);
}
#[test]
fn a_signature_from_the_wrong_key_is_a_bad_signature() {
let frame = frame("frm_1");
let attestation = signed(&frame, &OTHER_SEED);
assert_eq!(
store_trusting(&SEED).check(PROVIDER, &frame, &attestation),
AttestationState::Invalid {
verdict: AttestationVerdict::BadSignature
}
);
}
#[test]
fn a_frame_altered_after_signing_is_a_commitment_mismatch() {
let original = frame("frm_1");
let attestation = signed(&original, &SEED);
let mut altered = original.clone();
altered.provenance.clear();
match store_trusting(&SEED).check(PROVIDER, &altered, &attestation) {
AttestationState::Invalid {
verdict: AttestationVerdict::CommitmentMismatch { expected, signed },
} => {
assert_ne!(expected, signed, "the two commitments must differ");
assert_eq!(signed, attestation.signed_commitment);
}
other => panic!("expected a CommitmentMismatch, got {other:?}"),
}
}
#[test]
fn a_malformed_signature_is_named_malformed_not_forged() {
let frame = frame("frm_1");
let mut attestation = signed(&frame, &SEED);
attestation.signature = "not hex, and not 128 characters either".into();
assert_eq!(
store_trusting(&SEED).check(PROVIDER, &frame, &attestation),
AttestationState::Invalid {
verdict: AttestationVerdict::MalformedSignature
}
);
}
#[test]
fn a_malformed_commitment_is_named_before_the_signature_is_touched() {
let frame = frame("frm_1");
let mut attestation = signed(&frame, &SEED);
attestation.signed_commitment = "sha256:nope".into();
assert_eq!(
store_trusting(&SEED).check(PROVIDER, &frame, &attestation),
AttestationState::Invalid {
verdict: AttestationVerdict::MalformedCommitment
}
);
}
#[test]
fn an_unrecognised_algorithm_is_uncheckable_not_invalid() {
let frame = frame("frm_1");
let mut attestation = signed(&frame, &SEED);
attestation.algorithm = "dilithium3".into();
assert_eq!(
store_trusting(&SEED).check(PROVIDER, &frame, &attestation),
AttestationState::UnknownAlgorithm {
algorithm: "dilithium3".to_string()
}
);
}
#[test]
fn an_oversized_identifier_cannot_grow_the_audit_record_without_bound() {
let frame = frame("frm_1");
let mut attestation = signed(&frame, &SEED);
attestation.key_id = "k".repeat(1_000_000);
match store_trusting(&SEED).check(PROVIDER, &frame, &attestation) {
AttestationState::NoTrustedKey { key_id } => {
assert_eq!(key_id.len(), MAX_ECHOED_IDENTIFIER);
}
other => panic!("expected NoTrustedKey, got {other:?}"),
}
let mut oversized_algorithm = signed(&frame, &SEED);
oversized_algorithm.algorithm = "å".repeat(1_000);
match store_trusting(&SEED).check(PROVIDER, &frame, &oversized_algorithm) {
AttestationState::UnknownAlgorithm { algorithm } => {
assert!(algorithm.len() <= MAX_ECHOED_IDENTIFIER);
assert!(algorithm.chars().all(|c| c == 'å'));
}
other => panic!("expected UnknownAlgorithm, got {other:?}"),
}
}
#[test]
fn an_enormous_signature_is_rejected_on_its_length_before_any_decoding() {
let frame = frame("frm_1");
let mut attestation = signed(&frame, &SEED);
attestation.signature = "ab".repeat(5_000_000);
assert_eq!(
store_trusting(&SEED).check(PROVIDER, &frame, &attestation),
AttestationState::Invalid {
verdict: AttestationVerdict::MalformedSignature
}
);
}
#[test]
fn a_result_reports_a_state_for_every_frame_including_the_unsigned_ones() {
let signed_frame = frame("frm_signed");
let bare_frame = frame("frm_bare");
let attestation = signed(&signed_frame, &SEED);
let result = ContextQueryResult {
frame_attestations: vec![FrameAttestation::signed(
signed_frame.identity(PROVIDER),
attestation,
)],
..ContextQueryResult::unattested(
vec![signed_frame.clone(), bare_frame.clone()],
false,
None,
)
};
let outcomes = store_trusting(&SEED).check_result(PROVIDER, &result);
assert_eq!(outcomes.len(), 2, "one outcome per frame, always");
assert_eq!(outcomes[0].frame, signed_frame.identity(PROVIDER));
assert!(outcomes[0].state.is_attested());
assert_eq!(outcomes[1].frame, bare_frame.identity(PROVIDER));
assert_eq!(outcomes[1].state, AttestationState::Unattested);
}
#[test]
fn a_result_matches_evidence_built_under_the_declared_name_even_when_the_local_id_differs() {
const DECLARED: &str = "acme-docs";
const LOCAL: &str = "docs-1";
let served = frame("frm_1");
let attestation = sign_frame_attestation(
DECLARED,
&served,
&SEED,
KEY_ID,
DECLARED,
"2026-08-29T00:00:00Z",
);
let result = ContextQueryResult {
frame_attestations: vec![FrameAttestation::signed(
served.identity(DECLARED),
attestation,
)],
..ContextQueryResult::unattested(vec![served.clone()], false, None)
};
let mut store = TrustStore::new();
store.trust(
LOCAL,
TrustedKey::ed25519_bytes(KEY_ID, &public_key_for(&SEED)),
);
let outcomes = store.check_result_signed_as(LOCAL, DECLARED, &result);
assert_eq!(outcomes.len(), 1);
assert!(
outcomes[0].state.is_attested(),
"matching must key on the declared name the provider actually used \
on the wire, got {:?}",
outcomes[0].state
);
assert_eq!(
outcomes[0].frame,
served.identity(LOCAL),
"the returned FrameId is keyed by the operator's local id, matching \
the rest of the composition path"
);
}
#[test]
fn an_attestation_naming_a_frame_that_is_not_in_the_result_is_ignored() {
let served = frame("frm_served");
let elsewhere = frame("frm_elsewhere");
let result = ContextQueryResult {
frame_attestations: vec![FrameAttestation::signed(
elsewhere.identity(PROVIDER),
signed(&elsewhere, &SEED),
)],
..ContextQueryResult::unattested(vec![served.clone()], false, None)
};
let outcomes = store_trusting(&SEED).check_result(PROVIDER, &result);
assert_eq!(outcomes.len(), 1);
assert_eq!(outcomes[0].state, AttestationState::Unattested);
}
#[test]
fn an_entry_matching_the_frame_id_but_not_the_digest_does_not_attest_it() {
let served = frame("frm_1");
let mut impostor_identity = served.identity(PROVIDER);
impostor_identity.content_digest = Some(format!("sha256:{}", "ee".repeat(32)));
let result = ContextQueryResult {
frame_attestations: vec![FrameAttestation::signed(
impostor_identity,
signed(&served, &SEED),
)],
..ContextQueryResult::unattested(vec![served.clone()], false, None)
};
let outcomes = store_trusting(&SEED).check_result(PROVIDER, &result);
assert_eq!(outcomes[0].state, AttestationState::Unattested);
}
#[test]
fn at_most_one_attestation_per_frame_is_examined() {
let one = frame("frm_1");
let identity = one.identity(PROVIDER);
let good = signed(&one, &SEED);
let bad = signed(&one, &OTHER_SEED);
let result = ContextQueryResult {
frame_attestations: vec![
FrameAttestation::signed(identity.clone(), good),
FrameAttestation::signed(identity.clone(), bad.clone()),
],
..ContextQueryResult::unattested(vec![one.clone()], false, None)
};
let outcomes = store_trusting(&SEED).check_result(PROVIDER, &result);
assert!(outcomes[0].state.is_attested());
let mut unrelated = identity.clone();
unrelated.frame_id = "frm_unrelated".into();
let result = ContextQueryResult {
frame_attestations: vec![
FrameAttestation::signed(unrelated, bad),
FrameAttestation::signed(identity, signed(&one, &SEED)),
],
..ContextQueryResult::unattested(vec![one.clone()], false, None)
};
let outcomes = store_trusting(&SEED).check_result(PROVIDER, &result);
assert_eq!(outcomes.len(), 1);
assert_eq!(outcomes[0].state, AttestationState::Unattested);
}
fn root_signed_result(frames: Vec<ContextFrame>, seed: &[u8; 32]) -> ContextQueryResult {
use contextgraph_types::{inclusion_proof, result_set_commitments, result_set_root};
let ordered = result_set_commitments(PROVIDER, &frames);
let commitments: Vec<[u8; 32]> = ordered.iter().map(|(_, c)| *c).collect();
let root = result_set_root(PROVIDER, &frames);
let entries = ordered
.iter()
.enumerate()
.map(|(index, (id, _))| {
FrameAttestation::proven(
id.clone(),
inclusion_proof(&commitments, index).expect("index is in range"),
)
})
.collect();
ContextQueryResult {
frame_attestations: entries,
result_attestation: Some(sign_commitment(
&root,
seed,
KEY_ID,
"docs-provider",
"2026-08-29T00:00:00Z",
)),
..ContextQueryResult::unattested(frames, false, None)
}
}
#[test]
fn a_frame_attested_only_through_an_inclusion_proof_is_attested() {
let frames = vec![frame("frm_1"), frame("frm_2"), frame("frm_3")];
let result = root_signed_result(frames.clone(), &SEED);
let outcomes = store_trusting(&SEED).check_result(PROVIDER, &result);
assert_eq!(outcomes.len(), 3);
for (outcome, frame) in outcomes.iter().zip(&frames) {
assert_eq!(outcome.frame, frame.identity(PROVIDER));
assert_eq!(
outcome.state,
AttestationState::Attested {
key_id: KEY_ID.to_string(),
attester_id: "docs-provider".to_string(),
covers_content: true,
},
"every leaf of the signed root is attested by the one signature"
);
}
}
#[test]
fn a_proof_of_a_root_this_host_holds_no_key_for_is_a_configuration_gap() {
let frames = vec![frame("frm_1"), frame("frm_2")];
let result = root_signed_result(frames, &SEED);
let outcomes = TrustStore::new().check_result(PROVIDER, &result);
assert_eq!(
outcomes[0].state,
AttestationState::NoTrustedKey {
key_id: KEY_ID.to_string()
},
"no key means nothing was checked, never that something failed"
);
}
#[test]
fn a_proof_that_recomputes_a_different_root_is_a_commitment_mismatch() {
let frames = vec![frame("frm_1"), frame("frm_2")];
let mut result = root_signed_result(frames, &SEED);
result.frames[0].provenance.clear();
match store_trusting(&SEED).check_result(PROVIDER, &result)[0].state {
AttestationState::Invalid {
verdict: AttestationVerdict::CommitmentMismatch { .. },
} => {}
ref other => panic!("expected a CommitmentMismatch, got {other:?}"),
}
}
#[test]
fn an_inclusion_proof_with_no_signed_root_is_unusable_not_unattested() {
let frames = vec![frame("frm_1"), frame("frm_2")];
let mut result = root_signed_result(frames, &SEED);
result.result_attestation = None;
let outcomes = store_trusting(&SEED).check_result(PROVIDER, &result);
assert_eq!(outcomes[0].state, AttestationState::UnusableEvidence);
assert!(!outcomes[0].state.is_attested());
assert!(
outcomes[0].state.was_offered(),
"something was offered; it just could not be checked"
);
}
#[test]
fn an_entry_carrying_neither_a_signature_nor_a_proof_asserts_nothing() {
let one = frame("frm_1");
let mut entry = FrameAttestation::signed(one.identity(PROVIDER), signed(&one, &SEED));
entry.attestation = None;
let result = ContextQueryResult {
frame_attestations: vec![entry.clone()],
..ContextQueryResult::unattested(vec![one.clone()], false, None)
};
assert!(!entry.carries_evidence());
assert_eq!(
store_trusting(&SEED).check_result(PROVIDER, &result)[0].state,
AttestationState::UnusableEvidence
);
}
#[test]
fn a_per_frame_signature_is_preferred_over_a_proof_on_the_same_entry() {
let frames = vec![frame("frm_1"), frame("frm_2")];
let mut result = root_signed_result(frames.clone(), &SEED);
result.frame_attestations[0].attestation = Some(signed(&frames[0], &OTHER_SEED));
assert_eq!(
store_trusting(&SEED).check_result(PROVIDER, &result)[0].state,
AttestationState::Invalid {
verdict: AttestationVerdict::BadSignature
}
);
}
#[test]
fn an_unbounded_inclusion_path_is_rejected_on_its_length() {
use contextgraph_types::{InclusionStep, MAX_INCLUSION_PATH_STEPS};
let one = frame("frm_1");
let mut result = root_signed_result(vec![one.clone()], &SEED);
result.frame_attestations[0].inclusion_proof = Some(InclusionProof {
leaf_index: 0,
leaf_count: usize::MAX,
path: vec![
InclusionStep {
sibling: format!("sha256:{}", "11".repeat(32)),
sibling_is_left: false,
};
MAX_INCLUSION_PATH_STEPS + 1
],
});
assert_eq!(
store_trusting(&SEED).check_result(PROVIDER, &result)[0].state,
AttestationState::Invalid {
verdict: AttestationVerdict::MalformedCommitment
}
);
}
#[test]
fn an_empty_store_checks_nothing_and_rejects_nothing() {
let frame = frame("frm_1");
let attestation = signed(&frame, &SEED);
let store = TrustStore::new();
assert!(store.is_empty());
assert_eq!(
store.check(PROVIDER, &frame, &attestation),
AttestationState::NoTrustedKey {
key_id: KEY_ID.to_string()
}
);
}
#[test]
fn revoking_a_key_stops_it_attesting_and_reports_whether_it_removed_one() {
let frame = frame("frm_1");
let attestation = signed(&frame, &SEED);
let mut store = store_trusting(&SEED);
assert!(store.check(PROVIDER, &frame, &attestation).is_attested());
assert!(store.revoke(PROVIDER, KEY_ID));
assert!(!store.revoke(PROVIDER, KEY_ID), "already gone");
assert!(store.is_empty());
assert!(!store.check(PROVIDER, &frame, &attestation).is_attested());
}
#[test]
fn a_key_whose_hex_does_not_decode_is_refused_at_the_door() {
assert!(TrustedKey::ed25519_hex("k", "not hex").is_none());
assert!(
TrustedKey::ed25519_hex("k", "ab".repeat(16)).is_none(),
"too short"
);
let valid = encode_hex(&public_key_for(&SEED));
assert!(TrustedKey::ed25519_hex("k", &valid).is_some());
}
#[test]
fn a_stored_key_that_does_not_decode_is_an_operator_bug_named_as_one() {
let frame = frame("frm_1");
let attestation = signed(&frame, &SEED);
let mut store = TrustStore::new();
store.trust(
PROVIDER,
TrustedKey {
key_id: KEY_ID.into(),
public_key: "zz".repeat(32),
},
);
assert_eq!(
store.check(PROVIDER, &frame, &attestation),
AttestationState::Invalid {
verdict: AttestationVerdict::MalformedKey
}
);
}
#[test]
fn a_fingerprint_is_over_the_key_bytes_and_survives_a_round_trip() {
let key = TrustedKey::ed25519_bytes(KEY_ID, &public_key_for(&SEED));
let fingerprint = key.fingerprint().expect("a well-formed key has one");
assert!(fingerprint.starts_with("sha256:"));
assert_eq!(fingerprint.len(), COMMITMENT_LEN);
let shouty = TrustedKey {
key_id: KEY_ID.into(),
public_key: key.public_key.to_uppercase(),
};
assert_eq!(shouty.fingerprint(), Some(fingerprint));
}
#[test]
fn the_store_round_trips_through_serde_so_a_host_can_persist_it() {
let store = store_trusting(&SEED);
let json = serde_json::to_string(&store).expect("serializable");
let back: TrustStore = serde_json::from_str(&json).expect("deserializable");
assert_eq!(store, back);
}
#[test]
fn an_empty_ledger_says_not_checked_rather_than_unattested() {
let ledger = AttestationLedger::new();
let id = frame("frm_1").identity(PROVIDER);
assert!(ledger.is_empty());
assert_eq!(ledger.state_for(&id), AttestationState::NotChecked);
assert!(!ledger.state_for(&id).was_offered());
}
#[test]
fn a_ledger_collects_outcomes_and_answers_by_identity() {
let one = frame("frm_1");
let two = frame("frm_2");
let ledger: AttestationLedger = vec![
FrameAttestationOutcome {
frame: one.identity(PROVIDER),
state: AttestationState::Attested {
key_id: KEY_ID.into(),
attester_id: "docs-provider".into(),
covers_content: true,
},
},
FrameAttestationOutcome {
frame: two.identity(PROVIDER),
state: AttestationState::Unattested,
},
]
.into_iter()
.collect();
assert_eq!(ledger.len(), 2);
assert!(ledger.state_for(&one.identity(PROVIDER)).is_attested());
assert_eq!(
ledger.state_for(&two.identity(PROVIDER)),
AttestationState::Unattested
);
assert_eq!(
ledger.state_for(&one.identity("elsewhere")),
AttestationState::NotChecked
);
}
#[test]
fn a_local_id_that_differs_from_the_declared_name_still_verifies() {
const DECLARED: &str = "acme-docs";
const LOCAL: &str = "docs-1";
let frame = frame("frm");
let attestation = sign_frame_attestation(
DECLARED,
&frame,
&SEED,
KEY_ID,
DECLARED,
"2026-08-29T00:00:00Z",
);
let mut store = TrustStore::new();
store.trust(
LOCAL,
TrustedKey::ed25519_bytes(KEY_ID, &public_key_for(&SEED)),
);
let state = store.check_signed_as(LOCAL, DECLARED, &frame, &attestation);
assert!(
state.is_attested(),
"an honest signature must verify regardless of what the operator \
named the provider locally, got {state:?}"
);
assert!(
state.covers_content(),
"the frame declares a content_digest"
);
let impostor = store.check_signed_as(DECLARED, DECLARED, &frame, &attestation);
assert!(
matches!(impostor, AttestationState::NoTrustedKey { .. }),
"no key is trusted under the declared name, got {impostor:?}"
);
}
}