openadp_ocrypt/
lib.rs

1//! # OpenADP Rust SDK
2//!
3//! This crate provides a complete Rust implementation of the OpenADP (Open Advanced Data Protection)
4//! distributed secret sharing system, designed to protect against nation-state attacks.
5//!
6//! ## Core Features
7//!
8//! - **Ed25519 elliptic curve operations** with point compression/decompression
9//! - **Shamir secret sharing** with threshold recovery
10//! - **Noise-NK protocol** for secure server communication
11//! - **JSON-RPC 2.0 API** with multi-server support
12//! - **Cross-language compatibility** with Go and Python implementations
13//!
14//! ## Quick Start
15//!
16//! ```rust,no_run
17//! use openadp_ocrypt::{generate_encryption_key, recover_encryption_key, get_servers, Identity};
18//!
19//! #[tokio::main]
20//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
21//!     // Get live servers
22//!     let servers = get_servers("").await?;
23//!     
24//!     // Create Identity for the encryption operation
25//!     let identity = Identity::new(
26//!         "user@example.com".to_string(),  // UID - user identifier
27//!         "laptop-2024".to_string(),       // DID - device identifier  
28//!         "document.pdf".to_string()       // BID - backup identifier
29//!     );
30//!     
31//!     // Generate encryption key with distributed backup
32//!     let result = generate_encryption_key(
33//!         &identity,
34//!         "secure_password",
35//!         10, // max_guesses
36//!         0,  // expiration
37//!         servers,
38//!     ).await?;
39//!     
40//!     if let Some(key) = result.encryption_key {
41//!         println!("Generated key: {} bytes", key.len());
42//!         
43//!         // Later: recover the key
44//!         let recovered = recover_encryption_key(
45//!             &identity,
46//!             "secure_password", 
47//!             result.server_infos.unwrap(),
48//!             result.threshold.unwrap(),
49//!             result.auth_codes.unwrap(),
50//!         ).await?;
51//!         
52//!         if let Some(recovered_key) = recovered.encryption_key {
53//!             assert_eq!(key, recovered_key);
54//!             println!("Successfully recovered key!");
55//!         }
56//!     }
57//!     
58//!     Ok(())
59//! }
60//! ```
61
62use std::path::Path;
63
64/// Derive identifiers from filename, user_id, and hostname
65/// This matches the Go DeriveIdentifiers function behavior
66pub fn derive_identifiers(filename: &str, user_id: &str, hostname: &str) -> (String, String, String) {
67    let hostname = if hostname.is_empty() {
68        gethostname::gethostname().to_string_lossy().to_string()
69    } else {
70        hostname.to_string()
71    };
72    
73    let bid = format!("file://{}", Path::new(filename).file_name().unwrap_or_default().to_string_lossy());
74    
75    (user_id.to_string(), hostname, bid)
76}
77
78pub mod crypto;
79pub mod client;
80pub mod keygen;
81pub mod ocrypt;
82pub mod recovery;
83
84// Re-export main functionality
85pub use crypto::*;
86pub use client::*;
87pub use keygen::*;
88pub use ocrypt::*;
89pub use recovery::*;
90
91// Error types
92use thiserror::Error;
93
94#[derive(Error, Debug)]
95pub enum OpenADPError {
96    #[error("Network error: {0}")]
97    Network(#[from] reqwest::Error),
98    
99    #[error("JSON error: {0}")]
100    Json(#[from] serde_json::Error),
101    
102    #[error("Cryptographic error: {0}")]
103    Crypto(String),
104    
105    #[error("Invalid input: {0}")]
106    InvalidInput(String),
107    
108    #[error("Server error: {0}")]
109    Server(String),
110    
111    #[error("Authentication failed: {0}")]
112    Authentication(String),
113    
114    #[error("No servers available")]
115    NoServers,
116    
117    #[error("Insufficient servers for threshold")]
118    InsufficientServers,
119    
120    #[error("Invalid response from server")]
121    InvalidResponse,
122    
123    #[error("Encryption/decryption failed")]
124    EncryptionFailed,
125    
126    #[error("Point operation failed: {0}")]
127    PointOperation(String),
128    
129    #[error("Secret sharing failed: {0}")]
130    SecretSharing(String),
131    
132    #[error("I/O error: {0}")]
133    Io(String),
134    
135    #[error("Invalid format: {0}")]
136    InvalidFormat(String),
137}
138
139pub type Result<T> = std::result::Result<T, OpenADPError>;
140
141// Constants
142pub const DEFAULT_REGISTRY_URL: &str = "https://servers.openadp.org/api/servers.json";
143pub const FIELD_PRIME: &str = "57896044618658097711785492504343953926634992332820282019728792003956564819949"; // 2^255 - 19
144pub const CURVE_ORDER: &str = "7237005577332262213973186563042994240857116359379907606001950938285454250989"; // 2^252 + 27742317777372353535851937790883648493
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149
150    #[test]
151    fn test_constants() {
152        // Basic sanity checks
153        assert!(FIELD_PRIME.len() > 50);
154        assert!(CURVE_ORDER.len() > 50);
155    }
156    
157    #[test]
158    fn test_error_types() {
159        let err = OpenADPError::InvalidInput("test".to_string());
160        assert!(err.to_string().contains("Invalid input"));
161    }
162}