Skip to content

Privacy Features

Overview

Moby Market implements comprehensive privacy features to protect trader identities, transaction amounts, and trading patterns. The privacy system combines zero-knowledge proofs, confidential transfers, and mixing protocols to achieve institutional-grade financial privacy.

Zero-Knowledge Proof Integration

Supported ZK Protocols

The system supports multiple ZK proof systems optimized for different use cases:

pub enum ZKProtocol {
    Groth16,        // Fast verification, trusted setup
    PLONK,          // Universal setup, moderate size
    STARKs,         // No trusted setup, quantum resistant
    Bulletproofs,   // No trusted setup, range proofs
}

pub struct ZKProofSystem {
    pub protocol: ZKProtocol,
    pub circuit_registry: Vec<Circuit>,
    pub verification_key_store: KeyStore,
    pub proof_cache: ProofCache,
}

Core Proof Circuits

Transaction Privacy Circuit

// Private transaction circuit
pub struct PrivateTransactionCircuit {
    // Public inputs
    pub nullifier_hash: [u8; 32],
    pub commitment_root: [u8; 32],
    pub recipient_commitment: [u8; 32],

    // Private witnesses
    pub sender_private_key: [u8; 32],
    pub amount: u64,
    pub randomness: [u8; 32],
    pub merkle_path: MerklePath,
}

impl Circuit<Fr> for PrivateTransactionCircuit {
    fn synthesize<CS: ConstraintSystem<Fr>>(
        self,
        cs: &mut CS,
    ) -> Result<(), SynthesisError> {
        // Prove:
        // 1. Sender knows private key for input commitment
        // 2. Input commitment exists in merkle tree
        // 3. Nullifier is correctly computed
        // 4. Output commitment is well-formed
        // 5. Amount is in valid range
    }
}

Range Proof Circuit

// Prove amount is within valid range without revealing exact value
pub struct RangeProofCircuit {
    pub amount: u64,        // Private witness
    pub min_amount: u64,    // Public input
    pub max_amount: u64,    // Public input
    pub commitment: [u8; 32], // Public commitment to amount
    pub blinding_factor: [u8; 32], // Private randomness
}

Compliance Circuit

// Prove compliance requirements without revealing identity
pub struct ComplianceCircuit {
    pub user_credential: Credential,     // Private witness
    pub jurisdiction_proof: [u8; 32],    // Private jurisdiction proof
    pub accredited_investor_proof: [u8; 32], // Private status proof
    pub compliance_hash: [u8; 32],       // Public compliance commitment
}

Proof Generation and Verification

impl ZKProofSystem {
    pub fn generate_proof<C: Circuit<Fr>>(
        &self,
        circuit: C,
        proving_key: &ProvingKey,
    ) -> Result<Proof, ProofError> {
        match self.protocol {
            ZKProtocol::Groth16 => {
                let rng = &mut thread_rng();
                groth16::create_random_proof(circuit, proving_key, rng)
                    .map_err(ProofError::Groth16Error)
            }
            ZKProtocol::PLONK => {
                plonk::prove(&circuit, proving_key)
                    .map_err(ProofError::PlonkError)
            }
            ZKProtocol::STARKs => {
                starks::prove(&circuit)
                    .map_err(ProofError::StarksError)
            }
            ZKProtocol::Bulletproofs => {
                bulletproofs::prove(&circuit)
                    .map_err(ProofError::BulletproofsError)
            }
        }
    }

    pub fn verify_proof(
        &self,
        proof: &Proof,
        verification_key: &VerificationKey,
        public_inputs: &[Fr],
    ) -> Result<bool, VerificationError> {
        match self.protocol {
            ZKProtocol::Groth16 => {
                groth16::verify_proof(verification_key, proof, public_inputs)
            }
            // ... other protocols
        }
    }
}

Confidential Transfers

Amount Privacy

Hide transaction amounts using Pedersen commitments:

pub struct ConfidentialAmount {
    pub commitment: [u8; 32],      // Pedersen commitment to amount
    pub encrypted_amount: Vec<u8>, // Encrypted for recipient
    pub range_proof: Vec<u8>,      // Proof amount is positive
}

impl ConfidentialAmount {
    pub fn new(amount: u64, recipient_key: &PublicKey) -> Self {
        let blinding_factor = generate_random_scalar();

        // Create Pedersen commitment: C = aG + rH
        let commitment = pedersen_commit(amount, &blinding_factor);

        // Encrypt amount for recipient
        let encrypted_amount = encrypt_for_key(
            &amount.to_le_bytes(),
            recipient_key
        );

        // Generate range proof
        let range_proof = bulletproofs::prove_range(
            amount,
            &blinding_factor,
            0,
            u64::MAX
        );

        Self {
            commitment: commitment.to_bytes(),
            encrypted_amount,
            range_proof,
        }
    }

    pub fn verify(&self, min_amount: u64, max_amount: u64) -> bool {
        bulletproofs::verify_range(
            &self.commitment,
            &self.range_proof,
            min_amount,
            max_amount
        )
    }
}

Asset Privacy

Obfuscate token types using asset commitments:

pub struct ConfidentialAsset {
    pub asset_commitment: [u8; 32],    // Commitment to asset type
    pub encrypted_asset_id: Vec<u8>,   // Encrypted asset identifier
    pub asset_proof: Vec<u8>,          // Proof of valid asset
}

impl ConfidentialAsset {
    pub fn new(asset_id: Pubkey, recipient_key: &PublicKey) -> Self {
        let asset_randomness = generate_random_scalar();

        // Commit to asset type
        let asset_commitment = pedersen_commit_asset(
            &asset_id.to_bytes(),
            &asset_randomness
        );

        // Encrypt asset ID
        let encrypted_asset_id = encrypt_for_key(
            &asset_id.to_bytes(),
            recipient_key
        );

        // Generate proof that asset is in allowed set
        let asset_proof = generate_asset_membership_proof(
            &asset_id,
            &asset_randomness
        );

        Self {
            asset_commitment: asset_commitment.to_bytes(),
            encrypted_asset_id,
            asset_proof,
        }
    }
}

Stealth Addresses

Protect sender and receiver identities:

pub struct StealthAddress {
    pub view_key: [u8; 32],        // For detecting payments
    pub spend_key: [u8; 32],       // For spending funds
    pub address_commitment: [u8; 32], // One-time address commitment
}

impl StealthAddress {
    pub fn generate_payment_address(
        recipient_view_key: &PublicKey,
        recipient_spend_key: &PublicKey,
    ) -> (StealthAddress, EphemeralKey) {
        let ephemeral_private = generate_random_scalar();
        let ephemeral_public = ephemeral_private * GENERATOR;

        // Derive shared secret
        let shared_secret = ephemeral_private * recipient_view_key.point();

        // Generate one-time keys
        let one_time_spend = recipient_spend_key.point() +
            hash_to_scalar(&shared_secret) * GENERATOR;
        let one_time_view = recipient_view_key.point();

        let stealth_address = StealthAddress {
            view_key: one_time_view.to_bytes(),
            spend_key: one_time_spend.to_bytes(),
            address_commitment: hash(&one_time_spend.to_bytes()),
        };

        (stealth_address, EphemeralKey(ephemeral_public))
    }

    pub fn can_spend(&self, private_view_key: &[u8; 32]) -> bool {
        // Check if this stealth address belongs to the user
        let derived_view = derive_view_key(private_view_key);
        derived_view == self.view_key
    }
}

Privacy Pools

Pool Structure

pub struct PrivacyPool {
    pub pool_id: Pubkey,
    pub anonymity_set_size: u32,      // Current number of participants
    pub min_deposit: u64,             // Minimum deposit amount
    pub withdrawal_delay: i64,        // Time delay for withdrawals
    pub merkle_tree_root: [u8; 32],   // Merkle tree of all deposits
    pub nullifier_set: HashSet<[u8; 32]>, // Spent nullifiers
    pub compliance_module: Option<ComplianceHook>,
    pub pool_statistics: PoolStats,
}

pub struct PoolStats {
    pub total_deposits: u64,
    pub total_withdrawals: u64,
    pub average_deposit_size: u64,
    pub deposit_count: u32,
    pub withdrawal_count: u32,
    pub entropy_score: f64,           // Measure of privacy quality
}

Deposit Process

impl PrivacyPool {
    pub fn deposit(
        &mut self,
        amount: u64,
        depositor: &Pubkey,
    ) -> Result<DepositReceipt, PoolError> {
        // Validate minimum deposit
        if amount < self.min_deposit {
            return Err(PoolError::InsufficientAmount);
        }

        // Generate commitment
        let randomness = generate_random_scalar();
        let commitment = pedersen_commit(amount, &randomness);

        // Add to merkle tree
        let leaf_index = self.add_to_merkle_tree(&commitment);

        // Create deposit receipt
        let receipt = DepositReceipt {
            commitment: commitment.to_bytes(),
            randomness,
            leaf_index,
            deposit_time: get_current_timestamp(),
        };

        // Update pool statistics
        self.update_deposit_stats(amount);

        Ok(receipt)
    }

    pub fn withdraw(
        &mut self,
        proof: WithdrawalProof,
        recipient: &Pubkey,
    ) -> Result<(), PoolError> {
        // Verify withdrawal proof
        if !self.verify_withdrawal_proof(&proof) {
            return Err(PoolError::InvalidProof);
        }

        // Check nullifier hasn't been used
        if self.nullifier_set.contains(&proof.nullifier) {
            return Err(PoolError::DoubleSpend);
        }

        // Add nullifier to prevent double spending
        self.nullifier_set.insert(proof.nullifier);

        // Process withdrawal
        self.transfer_funds(proof.amount, recipient)?;
        self.update_withdrawal_stats(proof.amount);

        Ok(())
    }
}

Withdrawal Proof

pub struct WithdrawalProof {
    pub nullifier: [u8; 32],          // Prevents double spending
    pub merkle_root: [u8; 32],        // Root of deposit merkle tree
    pub amount: u64,                  // Withdrawal amount
    pub recipient: Pubkey,            // Withdrawal recipient
    pub zk_proof: Vec<u8>,           // ZK proof of valid withdrawal
}

impl WithdrawalProof {
    pub fn generate(
        deposit_receipt: &DepositReceipt,
        merkle_path: &MerklePath,
        recipient: &Pubkey,
    ) -> Self {
        // Generate nullifier
        let nullifier = hash_to_nullifier(
            &deposit_receipt.randomness,
            deposit_receipt.leaf_index
        );

        // Create withdrawal circuit
        let circuit = WithdrawalCircuit {
            deposit_amount: deposit_receipt.amount,
            randomness: deposit_receipt.randomness,
            merkle_path: merkle_path.clone(),
            nullifier,
            recipient: *recipient,
        };

        // Generate ZK proof
        let proving_key = load_withdrawal_proving_key();
        let zk_proof = generate_proof(circuit, &proving_key)
            .expect("Proof generation failed");

        Self {
            nullifier,
            merkle_root: merkle_path.root,
            amount: deposit_receipt.amount,
            recipient: *recipient,
            zk_proof: zk_proof.to_bytes(),
        }
    }
}

Transaction Mixing

Mix Network Architecture

pub struct MixNetwork {
    pub mix_nodes: Vec<MixNode>,
    pub routing_strategy: RoutingStrategy,
    pub batch_size: u32,
    pub mix_delay: i64,
}

pub struct MixNode {
    pub node_id: Pubkey,
    pub public_key: [u8; 32],
    pub reputation_score: f64,
    pub throughput_capacity: u32,
    pub uptime_percentage: f64,
}

pub enum RoutingStrategy {
    Onion,          // Layer encryption like Tor
    Cascade,        // Sequential mix through all nodes
    Pool,           // Batch mixing with timing delays
    Hybrid,         // Combination of strategies
}

Transaction Mixing Process

impl MixNetwork {
    pub fn submit_for_mixing(
        &self,
        transaction: PrivateTransaction,
        mix_level: MixLevel,
    ) -> Result<MixTicket, MixError> {
        let route = self.select_mix_route(mix_level);
        let encrypted_layers = self.create_onion_layers(&transaction, &route);

        let mix_ticket = MixTicket {
            ticket_id: generate_unique_id(),
            route_commitment: hash(&route),
            estimated_completion: calculate_completion_time(&route),
            privacy_score: calculate_privacy_score(mix_level, &route),
        };

        self.submit_to_first_mixer(encrypted_layers, &mix_ticket)?;
        Ok(mix_ticket)
    }

    fn create_onion_layers(
        &self,
        transaction: &PrivateTransaction,
        route: &[MixNode],
    ) -> Vec<EncryptedLayer> {
        let mut encrypted_data = transaction.serialize();

        // Encrypt in reverse order (innermost first)
        route.iter().rev().map(|node| {
            encrypted_data = encrypt_for_node(encrypted_data, &node.public_key);
            EncryptedLayer {
                node_id: node.node_id,
                encrypted_data: encrypted_data.clone(),
                timing_delay: calculate_delay(node),
            }
        }).collect()
    }
}

Privacy Pool Mixing

pub struct PoolMixer {
    pub pending_transactions: Vec<PendingMix>,
    pub batch_threshold: u32,
    pub mix_timeout: i64,
}

pub struct PendingMix {
    pub transaction_hash: [u8; 32],
    pub commitment: [u8; 32],
    pub submission_time: i64,
    pub mix_fee: u64,
}

impl PoolMixer {
    pub fn add_to_mix_pool(&mut self, transaction: PrivateTransaction) {
        let pending = PendingMix {
            transaction_hash: hash(&transaction),
            commitment: transaction.commitment,
            submission_time: get_current_timestamp(),
            mix_fee: calculate_mix_fee(&transaction),
        };

        self.pending_transactions.push(pending);

        // Check if we can execute a mix batch
        if self.should_execute_batch() {
            self.execute_mix_batch();
        }
    }

    fn execute_mix_batch(&mut self) {
        let batch = self.select_mix_batch();
        let shuffled_batch = self.shuffle_transactions(batch);

        // Execute all transactions in random order
        for transaction in shuffled_batch {
            self.execute_mixed_transaction(transaction);
        }

        // Clear processed transactions
        self.clear_processed_transactions();
    }
}

Privacy Analytics

Privacy Scoring

pub struct PrivacyAnalyzer {
    pub entropy_calculator: EntropyCalculator,
    pub anonymity_assessor: AnonymityAssessor,
    pub linkability_analyzer: LinkabilityAnalyzer,
}

impl PrivacyAnalyzer {
    pub fn calculate_privacy_score(&self, transaction: &PrivateTransaction) -> PrivacyScore {
        let entropy_score = self.entropy_calculator.calculate_entropy(transaction);
        let anonymity_score = self.anonymity_assessor.assess_anonymity(transaction);
        let linkability_score = self.linkability_analyzer.analyze_linkability(transaction);

        PrivacyScore {
            overall_score: self.combine_scores(entropy_score, anonymity_score, linkability_score),
            entropy_level: entropy_score,
            anonymity_set_size: anonymity_score.set_size,
            linkability_risk: linkability_score.risk_level,
            recommendations: self.generate_recommendations(entropy_score, anonymity_score, linkability_score),
        }
    }
}

pub struct PrivacyScore {
    pub overall_score: f64,        // 0.0 to 1.0
    pub entropy_level: f64,        // Information-theoretic entropy
    pub anonymity_set_size: u32,   // Size of anonymity set
    pub linkability_risk: RiskLevel, // Risk of transaction linking
    pub recommendations: Vec<PrivacyRecommendation>,
}

Compliance Integration

pub struct ComplianceModule {
    pub jurisdiction_checker: JurisdictionChecker,
    pub sanctions_screener: SanctionsScreener,
    pub reporting_module: ReportingModule,
    pub selective_disclosure: SelectiveDisclosure,
}

impl ComplianceModule {
    pub fn verify_compliance(
        &self,
        transaction: &PrivateTransaction,
        compliance_requirements: &ComplianceRequirements,
    ) -> ComplianceResult {
        // Verify jurisdiction compliance without revealing location
        let jurisdiction_proof = self.jurisdiction_checker
            .verify_jurisdiction(&transaction.compliance_commitment)?;

        // Screen against sanctions lists without revealing identity
        let sanctions_proof = self.sanctions_screener
            .verify_not_sanctioned(&transaction.identity_commitment)?;

        // Generate compliance report if required
        if compliance_requirements.reporting_required {
            self.reporting_module.generate_privacy_preserving_report(transaction)?;
        }

        ComplianceResult {
            compliant: true,
            jurisdiction_verified: jurisdiction_proof.verified,
            sanctions_cleared: sanctions_proof.cleared,
            reporting_completed: compliance_requirements.reporting_required,
        }
    }
}

API Reference

Privacy Operations

interface PrivacyAPI {
  // ZK Proof Operations
  generateProof<T extends Circuit>(
    circuit: T,
    provingKey: ProvingKey
  ): Promise<Proof>;

  verifyProof(
    proof: Proof,
    verificationKey: VerificationKey,
    publicInputs: PublicInput[]
  ): Promise<boolean>;

  // Confidential Transfers
  createConfidentialTransfer(params: {
    amount: bigint;
    recipient: PublicKey;
    asset: PublicKey;
  }): Promise<ConfidentialTransaction>;

  // Stealth Addresses
  generateStealthAddress(
    recipientViewKey: PublicKey,
    recipientSpendKey: PublicKey
  ): Promise<{ address: StealthAddress; ephemeralKey: EphemeralKey }>;

  // Privacy Pools
  depositToPool(
    poolId: PublicKey,
    amount: bigint
  ): Promise<DepositReceipt>;

  withdrawFromPool(
    proof: WithdrawalProof
  ): Promise<TxSignature>;

  // Mix Network
  submitForMixing(
    transaction: PrivateTransaction,
    mixLevel: MixLevel
  ): Promise<MixTicket>;

  // Privacy Analytics
  analyzePrivacy(
    transaction: PrivateTransaction
  ): Promise<PrivacyScore>;
}

Event Types

type PrivacyEvent =
  | { type: 'ProofGenerated'; proofId: string; circuit: string }
  | { type: 'ConfidentialTransfer'; commitment: string; nullifier: string }
  | { type: 'PoolDeposit'; poolId: string; commitment: string }
  | { type: 'PoolWithdrawal'; poolId: string; nullifier: string }
  | { type: 'MixCompleted'; mixId: string; privacyScore: number }
  | { type: 'ComplianceVerified'; transactionId: string; status: string };

Best Practices

For Maximum Privacy

  1. Use Privacy Pools: Always use privacy pools for large transactions
  2. Wait for Anonymity Set: Ensure sufficient anonymity set size before withdrawing
  3. Vary Timing: Don't follow predictable patterns for deposits/withdrawals
  4. Mix Regularly: Use transaction mixing even for smaller amounts
  5. Fresh Addresses: Generate new stealth addresses for each transaction

For Compliance

  1. Selective Disclosure: Only reveal necessary information for compliance
  2. Jurisdiction Proofs: Prove compliance without revealing location
  3. Audit Trails: Maintain privacy-preserving audit capabilities
  4. Regular Updates: Keep compliance modules updated with latest requirements

For Performance

  1. Proof Caching: Cache frequently used proofs and verification keys
  2. Batch Operations: Combine multiple privacy operations when possible
  3. Async Processing: Use background processing for proof generation
  4. Circuit Optimization: Use most efficient circuits for each use case

Security Considerations

  1. Key Management: Secure storage of private keys and randomness
  2. Trusted Setup: Verify integrity of any trusted setup ceremonies
  3. Circuit Audits: Ensure all circuits are properly audited
  4. Side Channel Protection: Guard against timing and other side channel attacks