exo_federation/
lib.rs

1//! # exo-federation: Distributed Cognitive Mesh
2//!
3//! This crate implements federated substrate networking with:
4//! - Post-quantum cryptographic handshakes
5//! - Privacy-preserving onion routing
6//! - CRDT-based eventual consistency
7//! - Byzantine fault-tolerant consensus
8//!
9//! ## Architecture
10//!
11//! ```text
12//! ┌─────────────────────────────────────────┐
13//! │      FederatedMesh (Coordinator)        │
14//! ├─────────────────────────────────────────┤
15//! │ • Local substrate instance              │
16//! │ • Consensus coordination                │
17//! │ • Federation gateway                    │
18//! │ • Cryptographic identity                │
19//! └─────────────────────────────────────────┘
20//!          │           │           │
21//!    ┌─────┘           │           └─────┐
22//!    ▼                 ▼                 ▼
23//! Handshake         Onion            CRDT
24//! Protocol          Router      Reconciliation
25//! ```
26
27use std::sync::Arc;
28use tokio::sync::RwLock;
29use dashmap::DashMap;
30use serde::{Deserialize, Serialize};
31
32pub mod crypto;
33pub mod handshake;
34pub mod onion;
35pub mod crdt;
36pub mod consensus;
37
38pub use crypto::{PostQuantumKeypair, EncryptedChannel};
39pub use handshake::{join_federation, FederationToken, Capability};
40pub use onion::{onion_query, OnionHeader};
41pub use crdt::{GSet, LWWRegister, reconcile_crdt};
42pub use consensus::{byzantine_commit, CommitProof};
43
44use crate::crypto::SharedSecret;
45
46/// Errors that can occur in federation operations
47#[derive(Debug, thiserror::Error)]
48pub enum FederationError {
49    #[error("Cryptographic operation failed: {0}")]
50    CryptoError(String),
51
52    #[error("Network error: {0}")]
53    NetworkError(String),
54
55    #[error("Consensus failed: {0}")]
56    ConsensusError(String),
57
58    #[error("Invalid federation token")]
59    InvalidToken,
60
61    #[error("Insufficient peers for consensus: needed {needed}, got {actual}")]
62    InsufficientPeers { needed: usize, actual: usize },
63
64    #[error("CRDT reconciliation failed: {0}")]
65    ReconciliationError(String),
66
67    #[error("Peer not found: {0}")]
68    PeerNotFound(String),
69}
70
71pub type Result<T> = std::result::Result<T, FederationError>;
72
73/// Unique identifier for a peer in the federation
74#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
75pub struct PeerId(pub String);
76
77impl PeerId {
78    pub fn new(id: String) -> Self {
79        Self(id)
80    }
81
82    pub fn generate() -> Self {
83        use sha2::{Sha256, Digest};
84        let mut hasher = Sha256::new();
85        hasher.update(rand::random::<[u8; 32]>());
86        let hash = hasher.finalize();
87        Self(hex::encode(&hash[..16]))
88    }
89}
90
91/// Network address for a peer
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct PeerAddress {
94    pub host: String,
95    pub port: u16,
96    pub public_key: Vec<u8>,
97}
98
99impl PeerAddress {
100    pub fn new(host: String, port: u16, public_key: Vec<u8>) -> Self {
101        Self { host, port, public_key }
102    }
103}
104
105/// Scope for federated queries
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub enum FederationScope {
108    /// Query only local instance
109    Local,
110    /// Query direct peers only
111    Direct,
112    /// Query entire federation (multi-hop)
113    Global { max_hops: usize },
114}
115
116/// Result from a federated query
117#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct FederatedResult {
119    pub source: PeerId,
120    pub data: Vec<u8>,
121    pub score: f32,
122    pub timestamp: u64,
123}
124
125/// State update for consensus
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct StateUpdate {
128    pub update_id: String,
129    pub data: Vec<u8>,
130    pub timestamp: u64,
131}
132
133/// Substrate instance placeholder (will reference exo-core types)
134pub struct SubstrateInstance {
135    // Placeholder - will integrate with actual substrate
136}
137
138/// Federated cognitive mesh coordinator
139pub struct FederatedMesh {
140    /// Unique identifier for this node
141    pub local_id: PeerId,
142
143    /// Local substrate instance
144    pub local: Arc<RwLock<SubstrateInstance>>,
145
146    /// Post-quantum cryptographic keypair
147    pub pq_keys: PostQuantumKeypair,
148
149    /// Connected peers
150    pub peers: Arc<DashMap<PeerId, PeerAddress>>,
151
152    /// Active federation tokens
153    pub tokens: Arc<DashMap<PeerId, FederationToken>>,
154
155    /// Encrypted channels to peers
156    pub channels: Arc<DashMap<PeerId, EncryptedChannel>>,
157}
158
159impl FederatedMesh {
160    /// Create a new federated mesh node
161    pub fn new(local: SubstrateInstance) -> Result<Self> {
162        let local_id = PeerId::generate();
163        let pq_keys = PostQuantumKeypair::generate();
164
165        Ok(Self {
166            local_id,
167            local: Arc::new(RwLock::new(local)),
168            pq_keys,
169            peers: Arc::new(DashMap::new()),
170            tokens: Arc::new(DashMap::new()),
171            channels: Arc::new(DashMap::new()),
172        })
173    }
174
175    /// Join a federation by connecting to a peer
176    pub async fn join_federation(
177        &mut self,
178        peer: &PeerAddress,
179    ) -> Result<FederationToken> {
180        let token = join_federation(&self.pq_keys, peer).await?;
181
182        // Store the peer and token
183        let peer_id = PeerId::new(token.peer_id.clone());
184        self.peers.insert(peer_id.clone(), peer.clone());
185        self.tokens.insert(peer_id, token.clone());
186
187        Ok(token)
188    }
189
190    /// Execute a federated query across the mesh
191    pub async fn federated_query(
192        &self,
193        query: Vec<u8>,
194        scope: FederationScope,
195    ) -> Result<Vec<FederatedResult>> {
196        match scope {
197            FederationScope::Local => {
198                // Query only local instance
199                Ok(vec![FederatedResult {
200                    source: self.local_id.clone(),
201                    data: query, // Placeholder
202                    score: 1.0,
203                    timestamp: current_timestamp(),
204                }])
205            }
206            FederationScope::Direct => {
207                // Query direct peers
208                let mut results = Vec::new();
209
210                for entry in self.peers.iter() {
211                    let peer_id = entry.key().clone();
212                    // Placeholder: would actually send query to peer
213                    results.push(FederatedResult {
214                        source: peer_id,
215                        data: query.clone(),
216                        score: 0.8,
217                        timestamp: current_timestamp(),
218                    });
219                }
220
221                Ok(results)
222            }
223            FederationScope::Global { max_hops } => {
224                // Use onion routing for privacy
225                let relay_nodes: Vec<_> = self.peers.iter()
226                    .take(max_hops)
227                    .map(|e| e.key().clone())
228                    .collect();
229
230                // Placeholder: would use onion_query
231                Ok(vec![])
232            }
233        }
234    }
235
236    /// Commit a state update with Byzantine consensus
237    pub async fn byzantine_commit(
238        &self,
239        update: StateUpdate,
240    ) -> Result<CommitProof> {
241        let peer_count = self.peers.len() + 1; // +1 for local
242        byzantine_commit(update, peer_count).await
243    }
244
245    /// Get the count of peers in the federation
246    pub fn peer_count(&self) -> usize {
247        self.peers.len()
248    }
249}
250
251/// Get current timestamp in milliseconds
252fn current_timestamp() -> u64 {
253    use std::time::{SystemTime, UNIX_EPOCH};
254    SystemTime::now()
255        .duration_since(UNIX_EPOCH)
256        .unwrap()
257        .as_millis() as u64
258}
259
260// Re-export hex for PeerId
261use hex;
262
263#[cfg(test)]
264mod tests {
265    use super::*;
266
267    #[tokio::test]
268    async fn test_federated_mesh_creation() {
269        let substrate = SubstrateInstance {};
270        let mesh = FederatedMesh::new(substrate).unwrap();
271        assert_eq!(mesh.peer_count(), 0);
272    }
273
274    #[tokio::test]
275    async fn test_local_query() {
276        let substrate = SubstrateInstance {};
277        let mesh = FederatedMesh::new(substrate).unwrap();
278
279        let results = mesh.federated_query(
280            vec![1, 2, 3],
281            FederationScope::Local
282        ).await.unwrap();
283
284        assert_eq!(results.len(), 1);
285    }
286}