Skip to main content

si_commitment_scheme/
binding.rs

1//! Computational binding property verification.
2//!
3//! The binding property ensures that a commitment cannot be opened to
4//! two different values. We test this computationally by attempting to
5//! find alternative openings (which should fail for secure schemes).
6
7use crate::pedersen::{PedersenCommitment, PedersenParams};
8use curve25519_dalek::scalar::Scalar;
9use rand::rngs::OsRng;
10use rand::Rng;
11
12/// Verifier for the binding property of commitments.
13#[derive(Debug, Clone)]
14pub struct BindingVerifier {
15    /// Number of binding attempts.
16    pub attempts: usize,
17}
18
19impl BindingVerifier {
20    /// Create a new verifier with the given number of attempts.
21    pub fn new(attempts: usize) -> Self {
22        Self { attempts }
23    }
24
25    /// Test that Pedersen commitments are binding.
26    ///
27    /// Commits to a value, then attempts `self.attempts` random openings
28    /// and verifies none of them produce the same commitment.
29    pub fn test_binding(&self, params: &PedersenParams, value: u64) -> bool {
30        let scalar_val = Scalar::from(value);
31        let (commitment, original_opening) = PedersenCommitment::commit(params, &scalar_val);
32
33        for _ in 0..self.attempts {
34            // Try a random different value
35            let mut rng = OsRng;
36            let fake_value: u64 = rng.gen_range(0..u64::MAX);
37            if fake_value == value {
38                continue;
39            }
40            let fake_scalar = Scalar::from(fake_value);
41            let fake_randomness = Scalar::random(&mut OsRng);
42            let fake_opening = crate::pedersen::PedersenOpening {
43                value: fake_scalar,
44                randomness: fake_randomness,
45            };
46            // If this verifies, binding is broken
47            if PedersenCommitment::verify(params, &fake_opening, &commitment) {
48                // Extremely unlikely — would break discrete log assumption
49                return false;
50            }
51        }
52        // Also verify original still works
53        PedersenCommitment::verify(params, &original_opening, &commitment)
54    }
55
56    /// Verify binding holds for a batch of values.
57    pub fn test_binding_batch(&self, params: &PedersenParams, values: &[u64]) -> bool {
58        values.iter().all(|&v| self.test_binding(params, v))
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn binding_holds_single() {
68        let params = PedersenParams::default();
69        let verifier = BindingVerifier::new(100);
70        assert!(verifier.test_binding(&params, 42));
71    }
72
73    #[test]
74    fn binding_holds_batch() {
75        let params = PedersenParams::default();
76        let verifier = BindingVerifier::new(50);
77        assert!(verifier.test_binding_batch(&params, &[1, 100, 999, 0]));
78    }
79
80    #[test]
81    fn binding_holds_zero_value() {
82        let params = PedersenParams::default();
83        let verifier = BindingVerifier::new(50);
84        assert!(verifier.test_binding(&params, 0));
85    }
86}