Skip to main content

holographic_memory/core/provenance/
trust.rs

1// Copyright 2024-2026 WritersLogic Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4//! Caller-supplied trust anchors for provenance verification.
5//!
6//! Signature checks alone only prove a record is *internally self-consistent*:
7//! the key embedded in the record verifies the signature the record carries.
8//! Authenticity requires an independent trust decision — "do I trust the party
9//! that holds this key?". A [`TrustStore`] is the set of keys/issuers the caller
10//! has decided to trust; verification is authentic only when the key that
11//! produced a signature is present in the store.
12
13use std::collections::HashSet;
14
15use anyhow::Result;
16use ed25519_dalek::VerifyingKey;
17
18use super::did;
19
20/// A set of trusted Ed25519 verification keys.
21///
22/// A record is treated as authentic only if the key that produced its
23/// signature is in this set. Keys can be added directly or via their
24/// `did:key` representation.
25#[derive(Default, Clone)]
26pub struct TrustStore {
27    keys: HashSet<[u8; 32]>,
28}
29
30impl TrustStore {
31    /// An empty trust store. It trusts nothing, so every record verifies as
32    /// non-authentic until keys are added.
33    pub fn new() -> Self {
34        Self::default()
35    }
36
37    /// Trust a raw verifying key.
38    pub fn trust_key(&mut self, key: &VerifyingKey) -> &mut Self {
39        self.keys.insert(key.to_bytes());
40        self
41    }
42
43    /// Trust the holder of a `did:key` identifier. Errors if the DID is not a
44    /// valid Ed25519 `did:key`.
45    pub fn trust_did(&mut self, did_key: &str) -> Result<&mut Self> {
46        let pk = did::ed25519_from_did_key(did_key)?;
47        self.keys.insert(pk);
48        Ok(self)
49    }
50
51    /// Trust the holder of a `did:jwk` identifier (used by CAWG ICA issuers).
52    /// Errors if the DID is not a valid Ed25519 `did:jwk`.
53    pub fn trust_did_jwk(&mut self, did_jwk: &str) -> Result<&mut Self> {
54        let pk = did::ed25519_from_did_jwk(did_jwk)?;
55        self.keys.insert(pk);
56        Ok(self)
57    }
58
59    /// Convenience constructor: a store trusting a single verifying key.
60    pub fn trusting_key(key: &VerifyingKey) -> Self {
61        let mut s = Self::new();
62        s.trust_key(key);
63        s
64    }
65
66    /// Convenience constructor: a store trusting a single `did:key` issuer.
67    pub fn trusting_did(did_key: &str) -> Result<Self> {
68        let mut s = Self::new();
69        s.trust_did(did_key)?;
70        Ok(s)
71    }
72
73    /// Whether the given key is trusted.
74    pub fn is_trusted(&self, key: &VerifyingKey) -> bool {
75        self.keys.contains(&key.to_bytes())
76    }
77
78    /// Whether the store trusts nothing.
79    pub fn is_empty(&self) -> bool {
80        self.keys.is_empty()
81    }
82
83    /// Number of distinct trusted keys.
84    pub fn len(&self) -> usize {
85        self.keys.len()
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use ed25519_dalek::SigningKey;
93
94    fn key() -> SigningKey {
95        SigningKey::from_bytes(&rand::random())
96    }
97
98    #[test]
99    fn empty_trusts_nothing() {
100        let store = TrustStore::new();
101        assert!(store.is_empty());
102        assert!(!store.is_trusted(&key().verifying_key()));
103    }
104
105    #[test]
106    fn trusts_added_key_only() {
107        let trusted = key();
108        let other = key();
109        let store = TrustStore::trusting_key(&trusted.verifying_key());
110        assert!(store.is_trusted(&trusted.verifying_key()));
111        assert!(!store.is_trusted(&other.verifying_key()));
112        assert_eq!(store.len(), 1);
113    }
114
115    #[test]
116    fn trust_via_did_roundtrips() {
117        let k = key();
118        let did = did::did_key_from_ed25519(&k.verifying_key().to_bytes());
119        let store = TrustStore::trusting_did(&did).unwrap();
120        assert!(store.is_trusted(&k.verifying_key()));
121    }
122}