si-commitment-scheme 0.1.0

Pedersen commitments, Blake3-based polynomial commitments, batch opening/verification with binding and hiding properties
Documentation
//! Computational binding property verification.
//!
//! The binding property ensures that a commitment cannot be opened to
//! two different values. We test this computationally by attempting to
//! find alternative openings (which should fail for secure schemes).

use crate::pedersen::{PedersenCommitment, PedersenParams};
use curve25519_dalek::scalar::Scalar;
use rand::rngs::OsRng;
use rand::Rng;

/// Verifier for the binding property of commitments.
#[derive(Debug, Clone)]
pub struct BindingVerifier {
    /// Number of binding attempts.
    pub attempts: usize,
}

impl BindingVerifier {
    /// Create a new verifier with the given number of attempts.
    pub fn new(attempts: usize) -> Self {
        Self { attempts }
    }

    /// Test that Pedersen commitments are binding.
    ///
    /// Commits to a value, then attempts `self.attempts` random openings
    /// and verifies none of them produce the same commitment.
    pub fn test_binding(&self, params: &PedersenParams, value: u64) -> bool {
        let scalar_val = Scalar::from(value);
        let (commitment, original_opening) = PedersenCommitment::commit(params, &scalar_val);

        for _ in 0..self.attempts {
            // Try a random different value
            let mut rng = OsRng;
            let fake_value: u64 = rng.gen_range(0..u64::MAX);
            if fake_value == value {
                continue;
            }
            let fake_scalar = Scalar::from(fake_value);
            let fake_randomness = Scalar::random(&mut OsRng);
            let fake_opening = crate::pedersen::PedersenOpening {
                value: fake_scalar,
                randomness: fake_randomness,
            };
            // If this verifies, binding is broken
            if PedersenCommitment::verify(params, &fake_opening, &commitment) {
                // Extremely unlikely — would break discrete log assumption
                return false;
            }
        }
        // Also verify original still works
        PedersenCommitment::verify(params, &original_opening, &commitment)
    }

    /// Verify binding holds for a batch of values.
    pub fn test_binding_batch(&self, params: &PedersenParams, values: &[u64]) -> bool {
        values.iter().all(|&v| self.test_binding(params, v))
    }
}

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

    #[test]
    fn binding_holds_single() {
        let params = PedersenParams::default();
        let verifier = BindingVerifier::new(100);
        assert!(verifier.test_binding(&params, 42));
    }

    #[test]
    fn binding_holds_batch() {
        let params = PedersenParams::default();
        let verifier = BindingVerifier::new(50);
        assert!(verifier.test_binding_batch(&params, &[1, 100, 999, 0]));
    }

    #[test]
    fn binding_holds_zero_value() {
        let params = PedersenParams::default();
        let verifier = BindingVerifier::new(50);
        assert!(verifier.test_binding(&params, 0));
    }
}