Skip to main content

saorsa_seal/
lib.rs

1//! # Threshold Sealing for Group Data in the Saorsa Network
2//!
3//! `saorsa-seal` provides threshold sealing capabilities for the Saorsa network,
4//! combining threshold cryptography, forward error correction, and authenticated encryption
5//! to create a robust distributed data protection system.
6//!
7//! ## Architecture Integration
8//!
9//! This crate leverages the Saorsa ecosystem:
10//! - **[`saorsa-core`]**: Threshold cryptography and DHT abstraction
11//! - **[`saorsa-fec`]**: Forward error correction and AEAD encryption  
12//! - **[`saorsa-pqc`]**: Post-quantum cryptography
13//!
14//! ## Core Features
15//!
16//! - **Threshold Sealing**: Uses Shamir's Secret Sharing via [`saorsa-core`] for configurable threshold schemes
17//! - **Forward Error Correction**: Reed-Solomon coding via [`saorsa-fec`] for fault tolerance
18//! - **AEAD Encryption**: XChaCha20-Poly1305 content encryption via [`saorsa-fec::CryptoEngine`]
19//! - **Post-Quantum Security**: ML-KEM-768 encryption via [`saorsa-pqc`]
20//! - **Distributed Storage**: DHT abstraction from [`saorsa-core`] for decentralized storage
21//! - **Verifiable Shares**: Feldman commitments for cryptographic share verification
22//! - **Envelope Encryption**: Post-quantum recipient encryption using ML-KEM-768
23//!
24//! ## Quick Start
25//!
26//! ```rust
27//! use saorsa_seal::{seal_bytes, open_bytes, SealPolicy, FecParams, EnvelopeKind, Recipient, RecipientId};
28//! use std::collections::HashMap;
29//! use std::sync::Mutex;
30//!
31//! // Simple DHT implementation for testing
32//! #[derive(Debug)]
33//! struct TestDht {
34//!     storage: Mutex<HashMap<[u8; 32], Vec<u8>>>,
35//! }
36//!
37//! impl TestDht {
38//!     fn new() -> Self {
39//!         Self { storage: Mutex::new(HashMap::new()) }
40//!     }
41//! }
42//!
43//! impl saorsa_seal::Dht for TestDht {
44//!     fn put(&self, key: &[u8; 32], value: &[u8], _ttl: Option<u64>) -> anyhow::Result<()> {
45//!         self.storage.lock().unwrap().insert(*key, value.to_vec());
46//!         Ok(())
47//!     }
48//!
49//!     fn get(&self, key: &[u8; 32]) -> anyhow::Result<Vec<u8>> {
50//!         self.storage.lock().unwrap().get(key).cloned()
51//!             .ok_or_else(|| anyhow::anyhow!("Key not found"))
52//!     }
53//! }
54//!
55//! #[tokio::main]
56//! async fn main() -> anyhow::Result<()> {
57//!     let dht = TestDht::new();
58//!     let plaintext = b"Hello, Saorsa Network!";
59//!
60//!     // Create recipients (5 total, threshold of 3)
61//!     let recipients: Vec<Recipient> = (0..5)
62//!         .map(|i| Recipient {
63//!             id: RecipientId::from_bytes(vec![i; 32]),
64//!             public_key: None,
65//!         })
66//!         .collect();
67//!
68//!     // Configure sealing policy
69//!     let policy = SealPolicy {
70//!         n: 5, t: 3, recipients,
71//!         fec: FecParams { data_shares: 3, parity_shares: 2, symbol_size: 1024 },
72//!         envelope: EnvelopeKind::PostQuantum,
73//!         aad: vec![],
74//!     };
75//!
76//!     // Seal and recover data
77//!     let summary = seal_bytes(plaintext, &policy, &dht).await?;
78//!     // ... (recovery process)
79//!     
80//!     Ok(())
81//! }
82//! ```
83//!
84//! ## Features
85//!
86//! - **`std`** (default): Standard library support
87//! - Post-quantum cryptography is always enabled via saorsa-pqc
88//! - **`telemetry`**: Tracing and metrics support
89
90// DHT trait for storage abstraction
91pub trait Dht {
92    fn put(&self, key: &[u8; 32], value: &[u8], ttl: Option<u64>) -> anyhow::Result<()>;
93    fn get(&self, key: &[u8; 32]) -> anyhow::Result<Vec<u8>>;
94}
95pub use types::*;
96
97// Main API functions
98pub use api::{open_bytes, open_file, seal_bytes, seal_file};
99
100pub mod aead;
101pub mod api;
102pub mod envelope;
103pub mod types;
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108    use std::collections::HashMap;
109    use std::sync::Mutex;
110
111    #[derive(Debug)]
112    struct TestDht {
113        storage: Mutex<HashMap<[u8; 32], Vec<u8>>>,
114    }
115
116    impl TestDht {
117        fn new() -> Self {
118            Self {
119                storage: Mutex::new(HashMap::new()),
120            }
121        }
122    }
123
124    impl Dht for TestDht {
125        fn put(&self, key: &[u8; 32], value: &[u8], _ttl: Option<u64>) -> anyhow::Result<()> {
126            self.storage.lock().unwrap().insert(*key, value.to_vec());
127            Ok(())
128        }
129
130        fn get(&self, key: &[u8; 32]) -> anyhow::Result<Vec<u8>> {
131            self.storage
132                .lock()
133                .unwrap()
134                .get(key)
135                .cloned()
136                .ok_or_else(|| anyhow::anyhow!("Key not found"))
137        }
138    }
139
140    #[tokio::test]
141    async fn test_basic_seal_and_open() {
142        let dht = TestDht::new();
143        let plaintext = b"Hello, Saorsa Network!";
144
145        let recipients: Vec<Recipient> = (0..5)
146            .map(|i| Recipient {
147                id: RecipientId::from_bytes(vec![i; 32]),
148                public_key: None,
149            })
150            .collect();
151
152        let policy = SealPolicy {
153            n: 5,
154            t: 3,
155            recipients,
156            fec: FecParams {
157                data_shares: 3,
158                parity_shares: 2,
159                symbol_size: 1024,
160            },
161            envelope: EnvelopeKind::PostQuantum,
162            aad: vec![],
163        };
164
165        let summary = seal_bytes(plaintext, &policy, &dht).await.unwrap();
166
167        // Get shares for recovery
168        let sealed_meta_bytes = dht.get(&summary.handle.sealed_meta_key).unwrap();
169        let sealed_meta: types::SealedMetaV1 = serde_cbor::from_slice(&sealed_meta_bytes).unwrap();
170
171        let shares: Vec<ProvidedShare> = sealed_meta
172            .shares
173            .iter()
174            .take(3)
175            .map(|sr| ProvidedShare {
176                index: sr.index,
177                share_bytes: sr.share_plain.clone().unwrap(),
178                recipient_id: sr.recipient.clone(),
179            })
180            .collect();
181
182        let recovered = open_bytes(&summary.handle, &shares, &dht).unwrap();
183        assert_eq!(plaintext, &recovered[..]);
184    }
185}