use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::collections::HashMap;
use crate::error::{CoreError, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum EncryptionScheme {
SimpleThreshold,
Shamir,
VSS,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyShare {
pub id: String,
pub party_id: String,
pub index: u32,
pub share_data: Vec<u8>,
pub threshold: u32,
pub total_shares: u32,
pub created_at: DateTime<Utc>,
}
impl KeyShare {
pub fn new(
id: String,
party_id: String,
index: u32,
share_data: Vec<u8>,
threshold: u32,
total_shares: u32,
) -> Result<Self> {
if threshold > total_shares {
return Err(CoreError::Validation(
"Threshold cannot exceed total shares".to_string(),
));
}
if index >= total_shares {
return Err(CoreError::Validation(
"Share index must be less than total shares".to_string(),
));
}
Ok(Self {
id,
party_id,
index,
share_data,
threshold,
total_shares,
created_at: Utc::now(),
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeLockedKey {
pub id: String,
pub encrypted_key: Vec<u8>,
pub unlock_time: DateTime<Utc>,
pub unlock_block: Option<u64>,
pub time_lock_puzzle: Vec<u8>,
pub created_at: DateTime<Utc>,
}
impl TimeLockedKey {
pub fn new(
id: String,
encrypted_key: Vec<u8>,
unlock_time: DateTime<Utc>,
unlock_block: Option<u64>,
) -> Self {
let puzzle = Self::generate_puzzle(&encrypted_key, unlock_time);
Self {
id,
encrypted_key,
unlock_time,
unlock_block,
time_lock_puzzle: puzzle,
created_at: Utc::now(),
}
}
fn generate_puzzle(key: &[u8], unlock_time: DateTime<Utc>) -> Vec<u8> {
let mut hasher = Sha256::new();
hasher.update(key);
hasher.update(unlock_time.timestamp().to_le_bytes());
hasher.finalize().to_vec()
}
pub fn can_unlock(&self, current_time: DateTime<Utc>, current_block: Option<u64>) -> bool {
if current_time >= self.unlock_time {
return true;
}
if let (Some(unlock_block), Some(current)) = (self.unlock_block, current_block) {
if current >= unlock_block {
return true;
}
}
false
}
pub fn unlock(
&self,
current_time: DateTime<Utc>,
current_block: Option<u64>,
) -> Result<Vec<u8>> {
if !self.can_unlock(current_time, current_block) {
return Err(CoreError::Validation(
"Key cannot be unlocked yet".to_string(),
));
}
Ok(self.encrypted_key.clone())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EncryptedOrder {
pub id: String,
pub ciphertext: Vec<u8>,
pub encryption_metadata: EncryptionMetadata,
pub timelock_key_id: String,
pub submitted_at: DateTime<Utc>,
pub revealed_at: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EncryptionMetadata {
pub scheme: EncryptionScheme,
pub threshold: u32,
pub total_shares: u32,
pub nonce: Vec<u8>,
}
impl EncryptedOrder {
pub fn new(
id: String,
ciphertext: Vec<u8>,
scheme: EncryptionScheme,
threshold: u32,
total_shares: u32,
timelock_key_id: String,
) -> Self {
let nonce = Self::generate_nonce();
Self {
id,
ciphertext,
encryption_metadata: EncryptionMetadata {
scheme,
threshold,
total_shares,
nonce,
},
timelock_key_id,
submitted_at: Utc::now(),
revealed_at: None,
}
}
fn generate_nonce() -> Vec<u8> {
let mut hasher = Sha256::new();
hasher.update(Utc::now().timestamp_nanos_opt().unwrap_or(0).to_le_bytes());
hasher.finalize()[0..16].to_vec()
}
pub fn mark_revealed(&mut self) {
self.revealed_at = Some(Utc::now());
}
pub fn is_revealed(&self) -> bool {
self.revealed_at.is_some()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DKGParticipant {
pub id: String,
pub address: String,
pub public_key: Vec<u8>,
pub commitment: Vec<u8>,
pub status: ParticipantStatus,
pub joined_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ParticipantStatus {
Registered,
Active,
Completed,
Failed,
}
impl DKGParticipant {
pub fn new(id: String, address: String, public_key: Vec<u8>) -> Self {
let mut hasher = Sha256::new();
hasher.update(&public_key);
let commitment = hasher.finalize().to_vec();
Self {
id,
address,
public_key,
commitment,
status: ParticipantStatus::Registered,
joined_at: Utc::now(),
}
}
pub fn activate(&mut self) {
self.status = ParticipantStatus::Active;
}
pub fn complete(&mut self) {
self.status = ParticipantStatus::Completed;
}
pub fn fail(&mut self) {
self.status = ParticipantStatus::Failed;
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DKGSession {
pub id: String,
pub threshold: u32,
pub participants: HashMap<String, DKGParticipant>,
pub key_shares: Vec<KeyShare>,
pub public_key: Option<Vec<u8>>,
pub status: DKGSessionStatus,
pub started_at: DateTime<Utc>,
pub completed_at: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum DKGSessionStatus {
Initializing,
Running,
Completed,
Failed,
}
impl DKGSession {
pub fn new(id: String, threshold: u32) -> Self {
Self {
id,
threshold,
participants: HashMap::new(),
key_shares: Vec::new(),
public_key: None,
status: DKGSessionStatus::Initializing,
started_at: Utc::now(),
completed_at: None,
}
}
pub fn add_participant(&mut self, participant: DKGParticipant) -> Result<()> {
if self.status != DKGSessionStatus::Initializing {
return Err(CoreError::Validation(
"Cannot add participants after session has started".to_string(),
));
}
if self.participants.contains_key(&participant.id) {
return Err(CoreError::Validation(format!(
"Participant {} already in session",
participant.id
)));
}
self.participants
.insert(participant.id.clone(), participant);
Ok(())
}
pub fn start(&mut self) -> Result<()> {
let participant_count = self.participants.len() as u32;
if participant_count < self.threshold {
return Err(CoreError::Validation(format!(
"Not enough participants: {} < {}",
participant_count, self.threshold
)));
}
self.status = DKGSessionStatus::Running;
for participant in self.participants.values_mut() {
participant.activate();
}
Ok(())
}
pub fn generate_shares(&mut self) -> Result<()> {
if self.status != DKGSessionStatus::Running {
return Err(CoreError::Validation(
"Session must be running to generate shares".to_string(),
));
}
let participant_count = self.participants.len() as u32;
let mut hasher = Sha256::new();
hasher.update(self.id.as_bytes());
hasher.update(self.started_at.timestamp().to_le_bytes());
let master_secret = hasher.finalize().to_vec();
for (idx, (participant_id, participant)) in self.participants.iter_mut().enumerate() {
let mut share_hasher = Sha256::new();
share_hasher.update(&master_secret);
share_hasher.update((idx as u32).to_le_bytes());
share_hasher.update(participant_id.as_bytes());
let share_data = share_hasher.finalize().to_vec();
let key_share = KeyShare::new(
format!("share-{}-{}", self.id, idx),
participant_id.clone(),
idx as u32,
share_data,
self.threshold,
participant_count,
)?;
self.key_shares.push(key_share);
participant.complete();
}
let mut pk_hasher = Sha256::new();
pk_hasher.update(&master_secret);
pk_hasher.update(b"public_key");
self.public_key = Some(pk_hasher.finalize().to_vec());
self.status = DKGSessionStatus::Completed;
self.completed_at = Some(Utc::now());
Ok(())
}
pub fn get_share(&self, participant_id: &str) -> Option<&KeyShare> {
self.key_shares
.iter()
.find(|s| s.party_id == participant_id)
}
pub fn is_complete(&self) -> bool {
self.status == DKGSessionStatus::Completed
}
}
#[derive(Debug)]
pub struct EncryptedMempoolManager {
pub encrypted_orders: HashMap<String, EncryptedOrder>,
pub timelock_keys: HashMap<String, TimeLockedKey>,
pub dkg_sessions: HashMap<String, DKGSession>,
pub revealed_orders: HashMap<String, Vec<u8>>,
}
impl EncryptedMempoolManager {
pub fn new() -> Self {
Self {
encrypted_orders: HashMap::new(),
timelock_keys: HashMap::new(),
dkg_sessions: HashMap::new(),
revealed_orders: HashMap::new(),
}
}
pub fn add_timelock_key(&mut self, key: TimeLockedKey) -> Result<()> {
if self.timelock_keys.contains_key(&key.id) {
return Err(CoreError::Validation(format!(
"Time-locked key {} already exists",
key.id
)));
}
self.timelock_keys.insert(key.id.clone(), key);
Ok(())
}
pub fn submit_encrypted_order(&mut self, order: EncryptedOrder) -> Result<()> {
if !self.timelock_keys.contains_key(&order.timelock_key_id) {
return Err(CoreError::Validation(format!(
"Time-locked key {} not found",
order.timelock_key_id
)));
}
if self.encrypted_orders.contains_key(&order.id) {
return Err(CoreError::Validation(format!(
"Order {} already exists",
order.id
)));
}
self.encrypted_orders.insert(order.id.clone(), order);
Ok(())
}
pub fn reveal_expired_orders(
&mut self,
current_time: DateTime<Utc>,
current_block: Option<u64>,
) -> Result<Vec<String>> {
let mut revealed_order_ids = Vec::new();
for order in self.encrypted_orders.values_mut() {
if order.is_revealed() {
continue;
}
if let Some(timelock_key) = self.timelock_keys.get(&order.timelock_key_id) {
if timelock_key.can_unlock(current_time, current_block) {
if let Ok(_unlocked_key) = timelock_key.unlock(current_time, current_block) {
order.mark_revealed();
self.revealed_orders
.insert(order.id.clone(), order.ciphertext.clone());
revealed_order_ids.push(order.id.clone());
}
}
}
}
Ok(revealed_order_ids)
}
pub fn create_dkg_session(&mut self, session_id: String, threshold: u32) -> Result<()> {
if self.dkg_sessions.contains_key(&session_id) {
return Err(CoreError::Validation(format!(
"DKG session {} already exists",
session_id
)));
}
let session = DKGSession::new(session_id.clone(), threshold);
self.dkg_sessions.insert(session_id, session);
Ok(())
}
pub fn get_dkg_session(&self, session_id: &str) -> Option<&DKGSession> {
self.dkg_sessions.get(session_id)
}
pub fn get_dkg_session_mut(&mut self, session_id: &str) -> Option<&mut DKGSession> {
self.dkg_sessions.get_mut(session_id)
}
pub fn get_encrypted_orders(&self) -> Vec<&EncryptedOrder> {
self.encrypted_orders.values().collect()
}
pub fn get_revealed_orders(&self) -> Vec<(&String, &Vec<u8>)> {
self.revealed_orders.iter().collect()
}
pub fn stats(&self) -> MempoolStats {
let total_encrypted = self.encrypted_orders.len();
let total_revealed = self
.encrypted_orders
.values()
.filter(|o| o.is_revealed())
.count();
MempoolStats {
total_encrypted_orders: total_encrypted,
total_revealed_orders: total_revealed,
pending_orders: total_encrypted - total_revealed,
active_dkg_sessions: self
.dkg_sessions
.values()
.filter(|s| s.status == DKGSessionStatus::Running)
.count(),
total_timelock_keys: self.timelock_keys.len(),
}
}
}
impl Default for EncryptedMempoolManager {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MempoolStats {
pub total_encrypted_orders: usize,
pub total_revealed_orders: usize,
pub pending_orders: usize,
pub active_dkg_sessions: usize,
pub total_timelock_keys: usize,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_share_creation() {
let share = KeyShare::new(
"share-1".to_string(),
"party-1".to_string(),
0,
vec![1, 2, 3],
2,
3,
)
.unwrap();
assert_eq!(share.index, 0);
assert_eq!(share.threshold, 2);
assert_eq!(share.total_shares, 3);
let invalid = KeyShare::new(
"share-2".to_string(),
"party-2".to_string(),
0,
vec![1, 2, 3],
4, 3,
);
assert!(invalid.is_err());
}
#[test]
fn test_timelock_key() {
let unlock_time = Utc::now() + chrono::Duration::seconds(3600);
let key = TimeLockedKey::new(
"key-1".to_string(),
vec![1, 2, 3, 4],
unlock_time,
Some(1000),
);
assert!(!key.can_unlock(Utc::now(), Some(500)));
let future_time = Utc::now() + chrono::Duration::seconds(7200);
assert!(key.can_unlock(future_time, Some(500)));
assert!(key.can_unlock(Utc::now(), Some(1000)));
}
#[test]
fn test_dkg_session() {
let mut session = DKGSession::new("session-1".to_string(), 2);
let p1 = DKGParticipant::new("p1".to_string(), "addr1".to_string(), vec![1, 2, 3]);
let p2 = DKGParticipant::new("p2".to_string(), "addr2".to_string(), vec![4, 5, 6]);
let p3 = DKGParticipant::new("p3".to_string(), "addr3".to_string(), vec![7, 8, 9]);
session.add_participant(p1).unwrap();
session.add_participant(p2).unwrap();
session.add_participant(p3).unwrap();
session.start().unwrap();
assert_eq!(session.status, DKGSessionStatus::Running);
session.generate_shares().unwrap();
assert!(session.is_complete());
assert_eq!(session.key_shares.len(), 3);
assert!(session.public_key.is_some());
}
#[test]
fn test_encrypted_mempool() {
let mut manager = EncryptedMempoolManager::new();
let unlock_time = Utc::now() + chrono::Duration::seconds(100);
let timelock = TimeLockedKey::new("tl-1".to_string(), vec![1, 2, 3], unlock_time, None);
manager.add_timelock_key(timelock).unwrap();
let order = EncryptedOrder::new(
"order-1".to_string(),
vec![4, 5, 6],
EncryptionScheme::SimpleThreshold,
2,
3,
"tl-1".to_string(),
);
manager.submit_encrypted_order(order).unwrap();
let stats = manager.stats();
assert_eq!(stats.total_encrypted_orders, 1);
assert_eq!(stats.pending_orders, 1);
let revealed = manager.reveal_expired_orders(Utc::now(), None).unwrap();
assert_eq!(revealed.len(), 0);
let future = Utc::now() + chrono::Duration::seconds(200);
let revealed = manager.reveal_expired_orders(future, None).unwrap();
assert_eq!(revealed.len(), 1);
}
}