diff options
| author | gabrix73 <gabriel1@frozenstar.info> | 2026-06-01 18:41:36 +0200 |
|---|---|---|
| committer | gabrix73 <gabriel1@frozenstar.info> | 2026-06-01 18:41:36 +0200 |
| commit | 9f5d864d533ce86459e654f5d78212933c0269ea (patch) | |
| tree | 4b71e8c7ab4e78da93e5f3164803da4de68c7031 /timing/src/obfuscation.rs | |
| download | onioncoin-9f5d864d533ce86459e654f5d78212933c0269ea.tar.gz onioncoin-9f5d864d533ce86459e654f5d78212933c0269ea.tar.xz onioncoin-9f5d864d533ce86459e654f5d78212933c0269ea.zip | |
OnionCoin is a privacy cryptocurrency that rewards Tor relay operators
through a unique Proof-of-Contribution consensus mechanism.
Core Features:
- Proof-of-Relay: 30% of block rewards go to Tor operators
- Native .onion node identity (no IP exposure)
- Temporal obfuscation protocols
- Dandelion++ over Tor propagation
- Native inheritance system with dead man's switch
Technical Stack:
- Rust workspace with 8 crates
- Ed25519/X25519 cryptography
- arti (Rust Tor client) integration planned
- 10 minute block time, 5-10 TPS design
Status: Prototype
- Consensus logic complete with passing tests (30/33)
- Network layer conceptual design complete
- Tor integration pending
- Testnet launch planned Q3 2026
License: MIT
Author: Gabriele Salati (virebent)
Contact: g48rix@gmail.com
Website: https://www.gabrielesalati.eu
Repository: https://git.virebent.art/virebent/onioncoin
Diffstat (limited to 'timing/src/obfuscation.rs')
| -rw-r--r-- | timing/src/obfuscation.rs | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/timing/src/obfuscation.rs b/timing/src/obfuscation.rs new file mode 100644 index 0000000..b48ea82 --- /dev/null +++ b/timing/src/obfuscation.rs @@ -0,0 +1,243 @@ +use crate::{TimeRange, TimeRangeProof, DelayStrategy, MixingPool}; +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use std::time::Duration; + +/// Orchestrates all timing obfuscation strategies +#[derive(Debug)] +pub struct TimingObfuscator<T> { + /// Mixing pool for batch releases + mixing_pool: MixingPool<T>, + + /// Strategy for adding delays + delay_strategy: DelayStrategy, + + /// Configuration + config: ObfuscationConfig, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ObfuscationConfig { + /// Enable mixing pool batching + pub use_mixing_pool: bool, + + /// Enable random delays + pub use_delays: bool, + + /// Enable fuzzy timestamps + pub use_fuzzy_timestamps: bool, + + /// Ratio of fake items to inject (0.0 - 1.0) + pub fake_item_ratio: f32, +} + +impl Default for ObfuscationConfig { + fn default() -> Self { + Self { + use_mixing_pool: true, + use_delays: true, + use_fuzzy_timestamps: true, + fake_item_ratio: 0.3, // 30% fake traffic + } + } +} + +impl<T> TimingObfuscator<T> { + pub fn new(config: ObfuscationConfig) -> Self { + Self { + mixing_pool: MixingPool::default(), + delay_strategy: DelayStrategy::node_rebroadcast(), + config, + } + } + + /// Add item to mixing pool + pub fn add_to_pool(&mut self, item: T) { + if self.config.use_mixing_pool { + self.mixing_pool.add(item); + } + } + + /// Check if should release batch + pub fn should_release_batch(&self) -> bool { + if !self.config.use_mixing_pool { + return false; + } + self.mixing_pool.should_release() + } + + /// Release shuffled batch + pub fn release_batch(&mut self) -> Vec<T> { + self.mixing_pool.release_batch() + } + + /// Apply delay strategy + pub async fn apply_delay(&self) { + if self.config.use_delays { + self.delay_strategy.sleep().await; + } + } + + /// Get current pool size + pub fn pool_size(&self) -> usize { + self.mixing_pool.len() + } +} + +/// Transaction timing metadata +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TimingMetadata { + /// Fuzzy time range + pub time_range: TimeRange, + + /// Zero-knowledge proof of creation time + pub time_proof: TimeRangeProof, + + /// Optional: observed network delay (for adaptive strategies) + pub network_delay_hint: Option<Duration>, +} + +impl TimingMetadata { + /// Create timing metadata for a transaction + pub fn new(real_time: DateTime<Utc>, seed: &[u8; 32]) -> Result<Self, crate::timerange::TimeRangeError> { + let time_range = TimeRange::new_fuzzy(real_time); + let time_proof = TimeRangeProof::generate(seed, real_time, &time_range)?; + + Ok(Self { + time_range, + time_proof, + network_delay_hint: None, + }) + } + + /// Validate timing metadata + pub fn validate(&self, current_time: DateTime<Utc>) -> bool { + // Check time range is valid + if !self.time_range.is_valid(current_time) { + return false; + } + + // Verify time proof + if !self.time_proof.verify(&self.time_range) { + return false; + } + + true + } + + /// Set network delay hint for adaptive strategies + pub fn with_network_delay(mut self, delay: Duration) -> Self { + self.network_delay_hint = Some(delay); + self + } +} + +/// Strategies for transaction propagation +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum PropagationPhase { + /// Dandelion STEM phase (anonymity) + Stem, + + /// Dandelion FLUFF phase (broadcast) + Fluff, +} + +/// Transaction wrapper with timing information +#[derive(Debug, Clone)] +pub struct TimedItem<T> { + pub item: T, + pub timing: TimingMetadata, + pub phase: PropagationPhase, +} + +impl<T> TimedItem<T> { + pub fn new(item: T, timing: TimingMetadata) -> Self { + Self { + item, + timing, + phase: PropagationPhase::Stem, + } + } + + pub fn transition_to_fluff(mut self) -> Self { + self.phase = PropagationPhase::Fluff; + self + } + + pub fn is_stem(&self) -> bool { + self.phase == PropagationPhase::Stem + } + + pub fn is_fluff(&self) -> bool { + self.phase == PropagationPhase::Fluff + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_timing_metadata_creation() { + let now = Utc::now(); + let seed = [42u8; 32]; + + let metadata = TimingMetadata::new(now, &seed).unwrap(); + assert!(metadata.validate(now)); + } + + #[test] + fn test_timing_metadata_validation() { + let now = Utc::now(); + let seed = [42u8; 32]; + + let metadata = TimingMetadata::new(now, &seed).unwrap(); + + // Should validate at current time + assert!(metadata.validate(now)); + + // Should validate slightly in the future + let future = now + chrono::Duration::hours(1); + assert!(metadata.validate(future)); + } + + #[test] + fn test_obfuscator_pool() { + let config = ObfuscationConfig::default(); + let mut obfuscator = TimingObfuscator::<u32>::new(config); + + obfuscator.add_to_pool(1); + obfuscator.add_to_pool(2); + obfuscator.add_to_pool(3); + + assert_eq!(obfuscator.pool_size(), 3); + } + + #[test] + fn test_timed_item_phases() { + let now = Utc::now(); + let seed = [42u8; 32]; + let timing = TimingMetadata::new(now, &seed).unwrap(); + + let item = TimedItem::new(42u32, timing); + assert!(item.is_stem()); + assert!(!item.is_fluff()); + + let item = item.transition_to_fluff(); + assert!(!item.is_stem()); + assert!(item.is_fluff()); + } + + #[tokio::test] + async fn test_apply_delay() { + let config = ObfuscationConfig::default(); + let obfuscator = TimingObfuscator::<u32>::new(config); + + let start = std::time::Instant::now(); + obfuscator.apply_delay().await; + let elapsed = start.elapsed(); + + // Should have some delay (at least 10s from node_rebroadcast strategy) + assert!(elapsed >= Duration::from_secs(10)); + } +} |
