lib-compression 0.1.0

Universal lossless compression via network-wide deduplication
Documentation
//! Abstraction traits for external dependencies
//!
//! This module defines minimal traits that abstract away internal workspace
//! dependencies. Each trait has a default implementation that works standalone,
//! allowing lib-compression to function without requiring lib-proofs, lib-storage,
//! or lib-neural-mesh.
//!
//! # Usage
//!
//! ```rust
//! use lib_compression::traits::{ProofBackend, DhtStorage, ModelCompressor};
//!
//! // Use default implementations (no external deps required)
//! let proof = DefaultProofBackend;
//! let dht = MemoryDht::default();
//! let compressor = DefaultModelCompressor;
//! ```

use std::collections::HashMap;
use std::sync::{Arc, RwLock};

use crate::error::Result;

// =============================================================================
// Proof Backend Trait (abstracts lib-proofs)
// =============================================================================

/// Zero-knowledge proof backend for range proofs and Merkle trees.
///
/// Default implementation uses BLAKE3 hashes as a lightweight fallback.
/// Enable `zk-proofs` feature for real Bulletproofs/Plonky2 support.
pub trait ProofBackend: Send + Sync {
    /// Generate a range proof for a value.
    fn generate_range_proof(&self, value: u64, min: u64, max: u64) -> Result<Vec<u8>>;

    /// Verify a range proof.
    fn verify_range_proof(&self, proof: &[u8], min: u64, max: u64) -> Result<bool>;

    /// Compute Merkle root from leaves.
    fn merkle_root(&self, leaves: &[Vec<u8>]) -> Result<[u8; 32]>;

    /// Generate Merkle inclusion proof.
    fn generate_merkle_proof(&self, leaves: &[Vec<u8>], index: usize) -> Result<MerkleProof>;

    /// Verify Merkle inclusion proof.
    fn verify_merkle_proof(&self, proof: &MerkleProof, root: &[u8; 32], leaf: &[u8]) -> Result<bool>;
}

/// Merkle proof structure.
#[derive(Debug, Clone)]
pub struct MerkleProof {
    pub leaf: Vec<u8>,
    pub path: Vec<[u8; 32]>,
    pub indices: Vec<u8>,
}

/// Default proof backend using BLAKE3 (no ZK, just hashes).
#[derive(Debug, Clone, Copy)]
pub struct DefaultProofBackend;

impl ProofBackend for DefaultProofBackend {
    fn generate_range_proof(&self, value: u64, min: u64, max: u64) -> Result<Vec<u8>> {
        // Fallback: just encode the value as "proof" (not cryptographically sound,
        // but works for testing and non-ZK use cases)
        if value < min || value > max {
            return Err(crate::error::CompressionError::InvalidParameter(
                format!("Value {} outside range [{}, {}]", value, min, max)
            ));
        }
        Ok(value.to_le_bytes().to_vec())
    }

    fn verify_range_proof(&self, proof: &[u8], min: u64, max: u64) -> Result<bool> {
        if proof.len() != 8 {
            return Ok(false);
        }
        let value = u64::from_le_bytes(proof.try_into().unwrap());
        Ok(value >= min && value <= max)
    }

    fn merkle_root(&self, leaves: &[Vec<u8>]) -> Result<[u8; 32]> {
        if leaves.is_empty() {
            return Ok([0u8; 32]);
        }
        
        // Simple BLAKE3-based Merkle tree
        let mut current_level: Vec<[u8; 32]> = leaves
            .iter()
            .map(|leaf| blake3::hash(leaf).into())
            .collect();

        while current_level.len() > 1 {
            let mut next_level = Vec::new();
            for chunk in current_level.chunks(2) {
                let hash = if chunk.len() == 2 {
                    let mut hasher = blake3::Hasher::new();
                    hasher.update(&chunk[0]);
                    hasher.update(&chunk[1]);
                    hasher.finalize()
                } else {
                    blake3::Hasher::new().finalize()
                };
                next_level.push(hash.into());
            }
            current_level = next_level;
        }

        Ok(current_level[0])
    }

    fn generate_merkle_proof(&self, leaves: &[Vec<u8>], index: usize) -> Result<MerkleProof> {
        if index >= leaves.len() {
            return Err(crate::error::CompressionError::InvalidParameter(
                format!("Index {} out of bounds for {} leaves", index, leaves.len())
            ));
        }

        let leaf_hash = blake3::hash(&leaves[index]);
        let mut path = Vec::new();
        let mut indices = Vec::new();
        
        let mut current_level: Vec<[u8; 32]> = leaves
            .iter()
            .map(|leaf| blake3::hash(leaf).into())
            .collect();
        
        let mut current_index = index;

        while current_level.len() > 1 {
            let sibling_index = if current_index % 2 == 0 {
                current_index + 1
            } else {
                current_index - 1
            };

            if sibling_index < current_level.len() {
                path.push(current_level[sibling_index]);
                indices.push((current_index % 2) as u8);
            }

            // Build next level
            let mut next_level = Vec::new();
            for chunk in current_level.chunks(2) {
                let hash = if chunk.len() == 2 {
                    let mut hasher = blake3::Hasher::new();
                    hasher.update(&chunk[0]);
                    hasher.update(&chunk[1]);
                    hasher.finalize()
                } else {
                    blake3::Hasher::new().finalize()
                };
                next_level.push(hash.into());
            }
            
            current_level = next_level;
            current_index /= 2;
        }

        Ok(MerkleProof {
            leaf: leaf_hash.as_bytes().to_vec(),
            path,
            indices,
        })
    }

    fn verify_merkle_proof(&self, proof: &MerkleProof, root: &[u8; 32], leaf: &[u8]) -> Result<bool> {
        let mut current_hash: [u8; 32] = blake3::hash(leaf).into();
        
        for (i, sibling) in proof.path.iter().enumerate() {
            let mut hasher = blake3::Hasher::new();
            if proof.indices[i] == 0 {
                hasher.update(&current_hash);
                hasher.update(sibling);
            } else {
                hasher.update(sibling);
                hasher.update(&current_hash);
            }
            current_hash = hasher.finalize().into();
        }

        Ok(current_hash == *root)
    }
}

// =============================================================================
// DHT Storage Trait (abstracts lib-storage::DhtNodeManager)
// =============================================================================

/// Distributed hash table storage backend.
///
/// Default implementation is in-memory (for testing/standalone usage).
/// Enable `dht-storage` feature for real lib-storage integration.
pub trait DhtStorage: Send + Sync {
    /// Store a value in the DHT.
    fn store(&self, key: &[u8], data: &[u8]) -> Result<()>;

    /// Retrieve a value from the DHT.
    fn retrieve(&self, key: &[u8]) -> Result<Option<Vec<u8>>>;

    /// Delete a value from the DHT.
    fn delete(&self, key: &[u8]) -> Result<()>;

    /// Check if a key exists in the DHT.
    fn exists(&self, key: &[u8]) -> Result<bool>;
}

/// In-memory DHT storage (default implementation).
#[derive(Clone)]
pub struct MemoryDht {
    data: Arc<RwLock<HashMap<[u8; 32], Vec<u8>>>>,
}

impl Default for MemoryDht {
    fn default() -> Self {
        Self::new()
    }
}

impl MemoryDht {
    pub fn new() -> Self {
        Self {
            data: Arc::new(RwLock::new(HashMap::new())),
        }
    }
}

impl DhtStorage for MemoryDht {
    fn store(&self, key: &[u8], data: &[u8]) -> Result<()> {
        let mut key_array = [0u8; 32];
        key_array.copy_from_slice(&key[..32.min(key.len())]);
        
        let mut guard = self.data.write().unwrap();
        guard.insert(key_array, data.to_vec());
        Ok(())
    }

    fn retrieve(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
        let mut key_array = [0u8; 32];
        key_array.copy_from_slice(&key[..32.min(key.len())]);
        
        let guard = self.data.read().unwrap();
        Ok(guard.get(&key_array).cloned())
    }

    fn delete(&self, key: &[u8]) -> Result<()> {
        let mut key_array = [0u8; 32];
        key_array.copy_from_slice(&key[..32.min(key.len())]);
        
        let mut guard = self.data.write().unwrap();
        guard.remove(&key_array);
        Ok(())
    }

    fn exists(&self, key: &[u8]) -> Result<bool> {
        let mut key_array = [0u8; 32];
        key_array.copy_from_slice(&key[..32.min(key.len())]);
        
        let guard = self.data.read().unwrap();
        Ok(guard.contains_key(&key_array))
    }
}

// =============================================================================
// Model Compressor Trait (abstracts lib-neural-mesh)
// =============================================================================

/// Model-based compression interface.
///
/// Default implementation is a no-op (passthrough).
/// Enable `ml-support` feature for real neural mesh integration.
pub trait ModelCompressor: Send + Sync {
    /// Compress data using model-based techniques.
    fn compress(&self, data: &[u8]) -> Result<Vec<u8>>;

    /// Decompress model-compressed data.
    fn decompress(&self, data: &[u8]) -> Result<Vec<u8>>;

    /// Get the name of this compressor.
    fn name(&self) -> &str;
}

/// Default passthrough compressor (no compression).
#[derive(Debug, Clone, Copy)]
pub struct DefaultModelCompressor;

impl ModelCompressor for DefaultModelCompressor {
    fn compress(&self, data: &[u8]) -> Result<Vec<u8>> {
        Ok(data.to_vec())
    }

    fn decompress(&self, data: &[u8]) -> Result<Vec<u8>> {
        Ok(data.to_vec())
    }

    fn name(&self) -> &str {
        "passthrough"
    }
}