kitsune2_core/
lib.rs

1#![deny(missing_docs)]
2//! Reference implementations of the [Kitsune2 API](kitsune2_api).
3
4use kitsune2_api::*;
5use std::sync::{Arc, Mutex};
6
7/// A default [Verifier] based on ed25519.
8#[derive(Debug)]
9pub struct Ed25519Verifier;
10
11impl Verifier for Ed25519Verifier {
12    fn verify(
13        &self,
14        agent_info: &AgentInfo,
15        message: &[u8],
16        signature: &[u8],
17    ) -> bool {
18        use ed25519_dalek::Verifier;
19
20        let agent: [u8; 32] = match (***agent_info.agent).try_into() {
21            Ok(agent) => agent,
22            Err(_) => return false,
23        };
24
25        let agent = match ed25519_dalek::VerifyingKey::from_bytes(&agent) {
26            Ok(agent) => agent,
27            Err(_) => return false,
28        };
29
30        let signature: [u8; 64] = match signature.try_into() {
31            Ok(signature) => signature,
32            Err(_) => return false,
33        };
34
35        let signature = ed25519_dalek::Signature::from_bytes(&signature);
36
37        agent.verify(message, &signature).is_ok()
38    }
39}
40
41struct Ed25519LocalAgentInner {
42    cb: Option<Arc<dyn Fn() + 'static + Send + Sync>>,
43    cur: DhtArc,
44    tgt: DhtArc,
45}
46
47/// A default in-memory [LocalAgent] based on ed25519.
48pub struct Ed25519LocalAgent {
49    pk: ed25519_dalek::SigningKey,
50    id: AgentId,
51    inner: Mutex<Ed25519LocalAgentInner>,
52}
53
54impl std::fmt::Debug for Ed25519LocalAgent {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        let storage_arc = self.inner.lock().unwrap().cur;
57        f.debug_struct("Ed25519LocalAgent")
58            .field("agent", &self.id)
59            .field("storage_arc", &storage_arc)
60            .finish()
61    }
62}
63
64impl Default for Ed25519LocalAgent {
65    fn default() -> Self {
66        Self::new(ed25519_dalek::SigningKey::generate(&mut rand::thread_rng()))
67    }
68}
69
70impl Ed25519LocalAgent {
71    fn new(pk: ed25519_dalek::SigningKey) -> Self {
72        let id = bytes::Bytes::copy_from_slice(pk.verifying_key().as_bytes());
73        Self {
74            pk,
75            id: id.into(),
76            inner: Mutex::new(Ed25519LocalAgentInner {
77                cb: None,
78                cur: DhtArc::Empty,
79                tgt: DhtArc::Empty,
80            }),
81        }
82    }
83
84    /// Construct an instance from seed bytes.
85    pub fn from_seed(seed: &[u8; 32]) -> Self {
86        Self::new(ed25519_dalek::SigningKey::from_bytes(seed))
87    }
88
89    /// Sign a message with this local agent.
90    pub fn sign(&self, message: &[u8]) -> bytes::Bytes {
91        use ed25519_dalek::Signer;
92        bytes::Bytes::copy_from_slice(&self.pk.sign(message).to_bytes())
93    }
94}
95
96impl Signer for Ed25519LocalAgent {
97    fn sign<'a, 'b: 'a, 'c: 'a>(
98        &'a self,
99        _agent_info: &'b AgentInfo,
100        message: &'c [u8],
101    ) -> BoxFut<'a, K2Result<bytes::Bytes>> {
102        Box::pin(async move { Ok(self.sign(message)) })
103    }
104}
105
106impl LocalAgent for Ed25519LocalAgent {
107    fn agent(&self) -> &AgentId {
108        &self.id
109    }
110
111    fn register_cb(&self, cb: Arc<dyn Fn() + 'static + Send + Sync>) {
112        self.inner.lock().unwrap().cb = Some(cb);
113    }
114
115    fn invoke_cb(&self) {
116        let cb = self.inner.lock().unwrap().cb.clone();
117        if let Some(cb) = cb {
118            cb();
119        }
120    }
121
122    fn get_cur_storage_arc(&self) -> DhtArc {
123        self.inner.lock().unwrap().cur
124    }
125
126    fn set_cur_storage_arc(&self, arc: DhtArc) {
127        self.inner.lock().unwrap().cur = arc;
128    }
129
130    fn get_tgt_storage_arc(&self) -> DhtArc {
131        self.inner.lock().unwrap().tgt
132    }
133
134    fn set_tgt_storage_arc_hint(&self, arc: DhtArc) {
135        self.inner.lock().unwrap().tgt = arc;
136    }
137}
138
139/// Construct a default builder for use in tests.
140///
141/// - `verifier` - The default verifier is [Ed25519Verifier].
142/// - `kitsune` - The default top-level kitsune module is
143///   [factories::CoreKitsuneFactory].
144/// - `space` - The default space module is [factories::CoreSpaceFactory].
145/// - `peer_store` - The default peer store is [factories::MemPeerStoreFactory].
146/// - `bootstrap` - The default bootstrap is [factories::MemBootstrapFactory].
147/// - `fetch` - The default fetch module is [factories::CoreFetchFactory].
148/// - `report` - The default report module is [factories::CoreReportFactory].
149/// - `transport` - The default transport is [factories::MemTransportFactory].
150/// - `op_store` - The default op store is [factories::MemOpStoreFactory].
151/// - `peer_meta_store` - The default peer meta store is [factories::MemPeerMetaStoreFactory].
152/// - `gossip` - The default gossip module is [factories::CoreGossipStubFactory].
153/// - `local_agent_store` - The default local agent store is [factories::CoreLocalAgentStoreFactory].
154/// - `publish` - The default publish module is [factories::CorePublishFactory].
155/// - `blocks` - The default blocks module is [factories::MemBlocksFactory].
156pub fn default_test_builder() -> Builder {
157    Builder {
158        config: Config::default(),
159        verifier: Arc::new(Ed25519Verifier),
160        auth_material: None,
161        kitsune: factories::CoreKitsuneFactory::create(),
162        space: factories::CoreSpaceFactory::create(),
163        peer_store: factories::MemPeerStoreFactory::create(),
164        bootstrap: factories::MemBootstrapFactory::create(),
165        fetch: factories::CoreFetchFactory::create(),
166        report: factories::CoreReportFactory::create(),
167        transport: factories::MemTransportFactory::create(),
168        op_store: factories::MemOpStoreFactory::create(),
169        peer_meta_store: factories::MemPeerMetaStoreFactory::create(),
170        gossip: factories::CoreGossipStubFactory::create(),
171        local_agent_store: factories::CoreLocalAgentStoreFactory::create(),
172        publish: factories::CorePublishFactory::create(),
173        blocks: factories::MemBlocksFactory::create(),
174    }
175}
176
177pub mod factories;
178
179mod common;
180pub use common::*;
181
182#[cfg(any(doc, docsrs))]
183pub mod doc;
184
185#[cfg(test)]
186mod test {
187    use super::*;
188
189    #[test]
190    fn ed25519_sanity() {
191        use kitsune2_api::*;
192        use kitsune2_test_utils::agent::*;
193
194        let i1 = AgentBuilder::default().build(Ed25519LocalAgent::default());
195        let enc = i1.encode().unwrap();
196        let i2 =
197            AgentInfoSigned::decode(&Ed25519Verifier, enc.as_bytes()).unwrap();
198
199        assert_eq!(i1, i2);
200    }
201}