1pub 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#[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
49pub type Result<T> = std::result::Result<T, ThresholdError>;
51
52pub type ThresholdSignature = Vec<u8>;
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct ThresholdGroup {
58 pub group_id: GroupId,
60
61 pub threshold: u16,
63
64 pub participants: u16,
66
67 pub frost_group_key: FrostGroupPublicKey,
69
70 pub active_participants: Vec<ParticipantInfo>,
72
73 pub pending_participants: Vec<ParticipantInfo>,
75
76 pub version: u64,
78
79 pub metadata: GroupMetadata,
81
82 pub audit_log: Vec<GroupAuditEntry>,
84
85 pub created_at: SystemTime,
87
88 pub last_updated: SystemTime,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct ParticipantInfo {
95 pub participant_id: ParticipantId,
97
98 pub public_key: MlDsaPublicKey,
100
101 pub frost_share_commitment: FrostCommitment,
103
104 pub role: ParticipantRole,
106
107 pub status: ParticipantStatus,
109
110 pub joined_at: SystemTime,
112
113 pub metadata: HashMap<String, String>,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
119pub enum ParticipantRole {
120 Leader {
122 permissions: LeaderPermissions,
123 },
124
125 Member {
127 permissions: MemberPermissions,
128 },
129
130 Observer,
132}
133
134#[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#[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#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
178pub enum ParticipantStatus {
179 Active,
181
182 PendingJoin,
184
185 PendingRemoval,
187
188 Inactive,
190
191 Suspended {
193 reason: String,
194 until: SystemTime,
195 },
196}
197
198#[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#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
210pub enum GroupPurpose {
211 MultiSig,
213
214 KeyManagement,
216
217 AccessControl,
219
220 Governance,
222
223 Custom(String),
225}
226
227#[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#[derive(Debug, Clone, Serialize, Deserialize)]
240pub enum GroupOperation {
241 AddParticipant {
243 group_id: GroupId,
244 new_participant: ParticipantInfo,
245 new_threshold: Option<u16>,
246 },
247
248 RemoveParticipant {
250 group_id: GroupId,
251 participant_id: ParticipantId,
252 new_threshold: Option<u16>,
253 },
254
255 UpdateThreshold {
257 group_id: GroupId,
258 new_threshold: u16,
259 },
260
261 RefreshKeys {
263 group_id: GroupId,
264 },
265
266 UpdateRole {
268 group_id: GroupId,
269 participant_id: ParticipantId,
270 new_role: ParticipantRole,
271 },
272
273 SuspendParticipant {
275 group_id: GroupId,
276 participant_id: ParticipantId,
277 reason: String,
278 duration: std::time::Duration,
279 },
280
281 CreateSubgroup {
283 parent_group_id: GroupId,
284 subgroup_config: SubgroupConfig,
285 },
286}
287
288#[derive(Debug, Clone, Serialize, Deserialize)]
290pub enum OperationResult {
291 Success,
292 Failed(String),
293 Pending,
294}
295
296#[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
305pub struct ThresholdGroupManager {
307 pub groups: HashMap<GroupId, ThresholdGroup>,
309
310 pub local_shares: HashMap<GroupId, FrostKeyShare>,
312
313 pub pending_operations: HashMap<OperationId, PendingOperation>,
315
316 pub local_identity: QuantumPeerIdentity,
318}
319
320#[derive(Debug, Clone, PartialEq, Eq, Hash)]
322pub struct OperationId([u8; 32]);
323
324#[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#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct ParticipantApproval {
339 pub participant_id: ParticipantId,
340 pub signature: MlDsaSignature,
341 pub timestamp: SystemTime,
342}
343
344#[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#[derive(Debug, Clone, PartialEq)]
355pub enum ConsensusStatus {
356 Pending,
358
359 Approved,
361
362 Rejected,
364
365 TimedOut,
367}
368
369impl ThresholdGroupManager {
370 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 pub async fn create_group(
382 &mut self,
383 config: GroupConfig,
384 ) -> Result<ThresholdGroup> {
385 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 let dkg_result = dkg::run_ceremony(
400 config.threshold,
401 config.participants.clone(),
402 ).await?;
403
404 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 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 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 Ok(operation_id)
469 }
470}
471
472pub struct GroupConfig {
474 pub threshold: u16,
475 pub participants: Vec<ParticipantInfo>,
476 pub metadata: GroupMetadata,
477}
478
479impl From<PeerId> for ParticipantId {
481 fn from(peer_id: PeerId) -> Self {
482 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}