saorsa_core/threshold/
mod.rs

1//! Threshold cryptography module
2//! 
3//! Implements FROST (Flexible Round-Optimized Schnorr Threshold) signatures
4//! and dynamic group management with Byzantine fault tolerance.
5
6pub mod frost;
7pub mod group;
8pub mod dkg;
9
10pub use self::group::*;
11
12use crate::quantum_crypto::types::*;
13use serde::{Deserialize, Serialize};
14use std::collections::HashMap;
15use std::time::SystemTime;
16use thiserror::Error;
17
18/// Threshold cryptography errors
19#[derive(Debug, Error)]
20pub enum ThresholdError {
21    #[error("Invalid threshold parameters: {0}")]
22    InvalidParameters(String),
23    
24    #[error("Insufficient participants: need {required}, have {available}")]
25    InsufficientParticipants { required: u16, available: u16 },
26    
27    #[error("Invalid share: {0}")]
28    InvalidShare(String),
29    
30    #[error("DKG ceremony failed: {0}")]
31    DkgFailed(String),
32    
33    #[error("Signature aggregation failed: {0}")]
34    AggregationFailed(String),
35    
36    #[error("Group operation failed: {0}")]
37    GroupOperationFailed(String),
38    
39    #[error("Consensus failed: {0}")]
40    ConsensusFailed(String),
41    
42    #[error("Participant not found: {0}")]
43    ParticipantNotFound(ParticipantId),
44    
45    #[error("Unauthorized operation: {0}")]
46    Unauthorized(String),
47}
48
49/// Result type for threshold operations
50pub type Result<T> = std::result::Result<T, ThresholdError>;
51
52/// Threshold signature type (placeholder)
53pub type ThresholdSignature = Vec<u8>;
54
55/// Threshold group with dynamic membership
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct ThresholdGroup {
58    /// Unique group identifier
59    pub group_id: GroupId,
60    
61    /// Current threshold (t in t-of-n)
62    pub threshold: u16,
63    
64    /// Total participants (n in t-of-n)
65    pub participants: u16,
66    
67    /// FROST group public key
68    pub frost_group_key: FrostGroupPublicKey,
69    
70    /// Active participants with their shares
71    pub active_participants: Vec<ParticipantInfo>,
72    
73    /// Participants being added
74    pub pending_participants: Vec<ParticipantInfo>,
75    
76    /// Group version (incremented on changes)
77    pub version: u64,
78    
79    /// Group metadata
80    pub metadata: GroupMetadata,
81    
82    /// Audit log of group operations
83    pub audit_log: Vec<GroupAuditEntry>,
84    
85    /// Creation timestamp
86    pub created_at: SystemTime,
87    
88    /// Last update timestamp
89    pub last_updated: SystemTime,
90}
91
92/// Participant information
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct ParticipantInfo {
95    /// Unique participant identifier
96    pub participant_id: ParticipantId,
97    
98    /// ML-DSA public key for authentication
99    pub public_key: MlDsaPublicKey,
100    
101    /// FROST share commitment
102    pub frost_share_commitment: FrostCommitment,
103    
104    /// Participant role in the group
105    pub role: ParticipantRole,
106    
107    /// Status in the group
108    pub status: ParticipantStatus,
109    
110    /// Join timestamp
111    pub joined_at: SystemTime,
112    
113    /// Custom metadata
114    pub metadata: HashMap<String, String>,
115}
116
117/// Participant roles with hierarchical permissions
118#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
119pub enum ParticipantRole {
120    /// Can initiate all group operations
121    Leader {
122        permissions: LeaderPermissions,
123    },
124    
125    /// Can participate in threshold operations
126    Member {
127        permissions: MemberPermissions,
128    },
129    
130    /// Read-only access
131    Observer,
132}
133
134/// Leader permissions
135#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
136pub struct LeaderPermissions {
137    pub can_add_participants: bool,
138    pub can_remove_participants: bool,
139    pub can_update_threshold: bool,
140    pub can_initiate_refresh: bool,
141    pub can_assign_roles: bool,
142    pub can_create_subgroups: bool,
143}
144
145impl Default for LeaderPermissions {
146    fn default() -> Self {
147        Self {
148            can_add_participants: true,
149            can_remove_participants: true,
150            can_update_threshold: true,
151            can_initiate_refresh: true,
152            can_assign_roles: true,
153            can_create_subgroups: true,
154        }
155    }
156}
157
158/// Member permissions
159#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
160pub struct MemberPermissions {
161    pub can_sign: bool,
162    pub can_propose_operations: bool,
163    pub can_vote: bool,
164}
165
166impl Default for MemberPermissions {
167    fn default() -> Self {
168        Self {
169            can_sign: true,
170            can_propose_operations: true,
171            can_vote: true,
172        }
173    }
174}
175
176/// Participant status
177#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
178pub enum ParticipantStatus {
179    /// Active and can participate
180    Active,
181    
182    /// Waiting for key ceremony completion
183    PendingJoin,
184    
185    /// Marked for removal in next refresh
186    PendingRemoval,
187    
188    /// Temporarily offline but still valid
189    Inactive,
190    
191    /// Suspended due to misbehavior
192    Suspended {
193        reason: String,
194        until: SystemTime,
195    },
196}
197
198/// Group metadata
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct GroupMetadata {
201    pub name: String,
202    pub description: String,
203    pub purpose: GroupPurpose,
204    pub parent_group: Option<GroupId>,
205    pub custom_data: HashMap<String, String>,
206}
207
208/// Group purpose
209#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
210pub enum GroupPurpose {
211    /// General multi-signature
212    MultiSig,
213    
214    /// Key management
215    KeyManagement,
216    
217    /// Access control
218    AccessControl,
219    
220    /// Governance decisions
221    Governance,
222    
223    /// Custom purpose
224    Custom(String),
225}
226
227/// Group audit entry
228#[derive(Debug, Clone, Serialize, Deserialize)]
229pub struct GroupAuditEntry {
230    pub timestamp: SystemTime,
231    pub operation: GroupOperation,
232    pub initiator: ParticipantId,
233    pub approvers: Vec<ParticipantId>,
234    pub result: OperationResult,
235    pub metadata: HashMap<String, String>,
236}
237
238/// Group operation types
239#[derive(Debug, Clone, Serialize, Deserialize)]
240pub enum GroupOperation {
241    /// Add new participant
242    AddParticipant {
243        group_id: GroupId,
244        new_participant: ParticipantInfo,
245        new_threshold: Option<u16>,
246    },
247    
248    /// Remove existing participant
249    RemoveParticipant {
250        group_id: GroupId,
251        participant_id: ParticipantId,
252        new_threshold: Option<u16>,
253    },
254    
255    /// Update threshold value
256    UpdateThreshold {
257        group_id: GroupId,
258        new_threshold: u16,
259    },
260    
261    /// Refresh keys (proactive security)
262    RefreshKeys {
263        group_id: GroupId,
264    },
265    
266    /// Update participant role
267    UpdateRole {
268        group_id: GroupId,
269        participant_id: ParticipantId,
270        new_role: ParticipantRole,
271    },
272    
273    /// Suspend participant
274    SuspendParticipant {
275        group_id: GroupId,
276        participant_id: ParticipantId,
277        reason: String,
278        duration: std::time::Duration,
279    },
280    
281    /// Create subgroup
282    CreateSubgroup {
283        parent_group_id: GroupId,
284        subgroup_config: SubgroupConfig,
285    },
286}
287
288/// Operation result
289#[derive(Debug, Clone, Serialize, Deserialize)]
290pub enum OperationResult {
291    Success,
292    Failed(String),
293    Pending,
294}
295
296/// Subgroup configuration
297#[derive(Debug, Clone, Serialize, Deserialize)]
298pub struct SubgroupConfig {
299    pub name: String,
300    pub threshold: u16,
301    pub initial_participants: Vec<ParticipantId>,
302    pub purpose: GroupPurpose,
303}
304
305/// Threshold group manager
306pub struct ThresholdGroupManager {
307    /// All managed groups
308    pub groups: HashMap<GroupId, ThresholdGroup>,
309    
310    /// Local participant's shares for each group
311    pub local_shares: HashMap<GroupId, FrostKeyShare>,
312    
313    /// Pending operations awaiting consensus
314    pub pending_operations: HashMap<OperationId, PendingOperation>,
315    
316    /// Local participant identity
317    pub local_identity: QuantumPeerIdentity,
318}
319
320/// Operation identifier
321#[derive(Debug, Clone, PartialEq, Eq, Hash)]
322pub struct OperationId([u8; 32]);
323
324/// Pending operation awaiting consensus
325#[derive(Debug, Clone)]
326pub struct PendingOperation {
327    pub id: OperationId,
328    pub operation: GroupOperation,
329    pub proposed_at: SystemTime,
330    pub proposer: ParticipantId,
331    pub approvals: Vec<ParticipantApproval>,
332    pub rejections: Vec<ParticipantRejection>,
333    pub status: ConsensusStatus,
334}
335
336/// Participant approval
337#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct ParticipantApproval {
339    pub participant_id: ParticipantId,
340    pub signature: MlDsaSignature,
341    pub timestamp: SystemTime,
342}
343
344/// Participant rejection
345#[derive(Debug, Clone, Serialize, Deserialize)]
346pub struct ParticipantRejection {
347    pub participant_id: ParticipantId,
348    pub reason: String,
349    pub signature: MlDsaSignature,
350    pub timestamp: SystemTime,
351}
352
353/// Consensus status
354#[derive(Debug, Clone, PartialEq)]
355pub enum ConsensusStatus {
356    /// Waiting for more approvals
357    Pending,
358    
359    /// Approved by threshold
360    Approved,
361    
362    /// Rejected by threshold
363    Rejected,
364    
365    /// Timed out
366    TimedOut,
367}
368
369impl ThresholdGroupManager {
370    /// Create a new threshold group manager
371    pub fn new(local_identity: QuantumPeerIdentity) -> Self {
372        Self {
373            groups: HashMap::new(),
374            local_shares: HashMap::new(),
375            pending_operations: HashMap::new(),
376            local_identity,
377        }
378    }
379    
380    /// Create a new threshold group
381    pub async fn create_group(
382        &mut self,
383        config: GroupConfig,
384    ) -> Result<ThresholdGroup> {
385        // Validate parameters
386        if config.threshold > config.participants.len() as u16 {
387            return Err(ThresholdError::InvalidParameters(
388                "Threshold cannot exceed number of participants".to_string()
389            ));
390        }
391        
392        if config.threshold == 0 {
393            return Err(ThresholdError::InvalidParameters(
394                "Threshold must be at least 1".to_string()
395            ));
396        }
397        
398        // Initiate DKG ceremony
399        let dkg_result = dkg::run_ceremony(
400            config.threshold,
401            config.participants.clone(),
402        ).await?;
403        
404        // Create group
405        let group = ThresholdGroup {
406            group_id: GroupId(rand::random()),
407            threshold: config.threshold,
408            participants: config.participants.len() as u16,
409            frost_group_key: dkg_result.group_key,
410            active_participants: config.participants.clone(),
411            pending_participants: Vec::new(),
412            version: 1,
413            metadata: config.metadata.clone(),
414            audit_log: vec![
415                GroupAuditEntry {
416                    timestamp: SystemTime::now(),
417                    operation: GroupOperation::CreateSubgroup {
418                        parent_group_id: GroupId([0; 32]),
419                        subgroup_config: SubgroupConfig {
420                            name: config.metadata.name.clone(),
421                            threshold: config.threshold,
422                            initial_participants: config.participants
423                                .iter()
424                                .map(|p| p.participant_id.clone())
425                                .collect(),
426                            purpose: config.metadata.purpose.clone(),
427                        },
428                    },
429                    initiator: self.local_identity.peer_id.clone().into(),
430                    approvers: vec![],
431                    result: OperationResult::Success,
432                    metadata: HashMap::new(),
433                },
434            ],
435            created_at: SystemTime::now(),
436            last_updated: SystemTime::now(),
437        };
438        
439        // Store group and local share
440        self.groups.insert(group.group_id.clone(), group.clone());
441        self.local_shares.insert(group.group_id.clone(), dkg_result.local_share);
442        
443        Ok(group)
444    }
445    
446    /// Propose a group operation
447    pub async fn propose_operation(
448        &mut self,
449        operation: GroupOperation,
450    ) -> Result<OperationId> {
451        let operation_id = OperationId(rand::random());
452        
453        let pending_op = PendingOperation {
454            id: operation_id.clone(),
455            operation,
456            proposed_at: SystemTime::now(),
457            proposer: self.local_identity.peer_id.clone().into(),
458            approvals: vec![],
459            rejections: vec![],
460            status: ConsensusStatus::Pending,
461        };
462        
463        self.pending_operations.insert(operation_id.clone(), pending_op);
464        
465        // Broadcast proposal to group members
466        // Implementation would send network messages here
467        
468        Ok(operation_id)
469    }
470}
471
472/// Group configuration for creation
473pub struct GroupConfig {
474    pub threshold: u16,
475    pub participants: Vec<ParticipantInfo>,
476    pub metadata: GroupMetadata,
477}
478
479/// Convert PeerId to ParticipantId (simplified for example)
480impl From<PeerId> for ParticipantId {
481    fn from(peer_id: PeerId) -> Self {
482        // In practice, this would maintain a proper mapping
483        ParticipantId(0)
484    }
485}
486
487#[cfg(test)]
488mod tests {
489    use super::*;
490    
491    #[test]
492    fn test_permission_defaults() {
493        let leader_perms = LeaderPermissions::default();
494        assert!(leader_perms.can_add_participants);
495        assert!(leader_perms.can_remove_participants);
496        
497        let member_perms = MemberPermissions::default();
498        assert!(member_perms.can_sign);
499        assert!(member_perms.can_vote);
500    }
501    
502    #[test]
503    fn test_participant_roles() {
504        let leader = ParticipantRole::Leader {
505            permissions: LeaderPermissions::default(),
506        };
507        
508        let member = ParticipantRole::Member {
509            permissions: MemberPermissions::default(),
510        };
511        
512        assert_ne!(leader, member);
513    }
514}