kontor-crypto 0.1.1

Kontor Proof-of-Retrievability system for decentralized storage
Documentation
//! Compile-time and runtime safety checks for circuit uniformity.
//!
//! This module provides macros and functions to ensure that circuit
//! constraint structures remain uniform across all execution paths.

/// Macro to mark circuit code that MUST maintain uniform constraint count.
///
/// Use this to wrap any circuit code that could potentially create
/// different constraint counts based on witness values.
///
/// # Example
///
/// ```ignore
/// uniform_constraints! {
///     // This code must generate the same number of constraints
///     // regardless of witness values
///     let result = if condition {
///         // BAD: This would fail uniformity check
///         cs.alloc(|| Ok(value))?
///     } else {
///         existing_var
///     };
/// }
/// ```
#[macro_export]
macro_rules! uniform_constraints {
    ($($body:tt)*) => {
        {
            // In debug mode, we could add runtime checks here
            #[cfg(debug_assertions)]
            {
                // Mark the beginning of a uniform section
                let _uniformity_guard = $crate::circuit_safety::UniformityGuard::new();
            }

            $($body)*
        }
    };
}

/// Macro to explicitly mark non-uniform code that's acceptable.
///
/// Use this ONLY for code that's guaranteed to execute the same way
/// during parameter generation and proving (e.g., based on public parameters
/// rather than witness values).
#[macro_export]
macro_rules! non_uniform_ok {
    ($reason:literal, $($body:tt)*) => {
        {
            // Document why this non-uniformity is safe
            #[cfg(debug_assertions)]
            {
                eprintln!("[CIRCUIT] Non-uniform section (OK): {}", $reason);
            }

            $($body)*
        }
    };
}

/// Guard type for tracking uniformity sections in debug builds.
#[cfg(debug_assertions)]
#[derive(Default)]
pub struct UniformityGuard {
    // Empty guard - could be extended with tracking fields if needed
}

#[cfg(debug_assertions)]
impl UniformityGuard {
    pub fn new() -> Self {
        Self::default()
    }
}

#[cfg(debug_assertions)]
impl Drop for UniformityGuard {
    fn drop(&mut self) {
        // Could add runtime tracking here if needed
    }
}

/// Trait for circuit components that must maintain uniformity.
pub trait UniformCircuit {
    /// Verify that this circuit component maintains uniform structure.
    ///
    /// This should be called during tests with different witness configurations
    /// to ensure the constraint count doesn't vary.
    fn verify_uniformity(&self) -> Result<(), String>;
}

/// Helper to ensure witness vectors are always the correct length.
///
/// This prevents accidental size mismatches that could cause non-uniformity.
pub fn ensure_witness_count<T>(witnesses: Vec<T>, expected: usize, default: T) -> Vec<T>
where
    T: Clone,
{
    let mut result = witnesses;

    // Truncate if too long
    result.truncate(expected);

    // Pad if too short
    while result.len() < expected {
        result.push(default.clone());
    }

    debug_assert_eq!(result.len(), expected, "Witness count mismatch");
    result
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_ensure_witness_count() {
        // Test padding
        let witnesses = vec![1, 2, 3];
        let padded = ensure_witness_count(witnesses, 5, 0);
        assert_eq!(padded, vec![1, 2, 3, 0, 0]);

        // Test truncation
        let witnesses = vec![1, 2, 3, 4, 5];
        let truncated = ensure_witness_count(witnesses, 3, 0);
        assert_eq!(truncated, vec![1, 2, 3]);

        // Test exact match
        let witnesses = vec![1, 2, 3];
        let exact = ensure_witness_count(witnesses, 3, 0);
        assert_eq!(exact, vec![1, 2, 3]);
    }
}