Skip to main content

si_commitment_scheme/
hiding.rs

1//! Statistical hiding property verification.
2//!
3//! The hiding property ensures that a commitment reveals nothing about
4//! the committed value. For Pedersen commitments with proper randomness,
5//! the commitment distribution is uniform regardless of the value.
6
7use crate::pedersen::{PedersenCommitment, PedersenParams};
8use curve25519_dalek::scalar::Scalar;
9
10/// Verifier for the hiding property of commitments.
11#[derive(Debug, Clone)]
12pub struct HidingVerifier {
13    /// Number of commitment samples per value.
14    pub samples: usize,
15}
16
17impl HidingVerifier {
18    /// Create a new verifier with the given sample count.
19    pub fn new(samples: usize) -> Self {
20        Self { samples }
21    }
22
23    /// Test that commitments to the same value produce different outputs.
24    ///
25    /// This confirms that randomness is being used properly.
26    pub fn test_unique_commitments(&self, params: &PedersenParams, value: u64) -> bool {
27        let scalar = Scalar::from(value);
28        let mut seen = std::collections::HashSet::new();
29        for _ in 0..self.samples {
30            let (comm, _) = PedersenCommitment::commit(params, &scalar);
31            let bytes = comm.compressed.to_bytes();
32            if seen.contains(&bytes) {
33                return false;
34            }
35            seen.insert(bytes);
36        }
37        seen.len() == self.samples
38    }
39
40    /// Test that commitments to different values are indistinguishable.
41    ///
42    /// Verifies that the commitment set for value A overlaps with the
43    /// commitment set for value B at most minimally (statistical check).
44    pub fn test_indistinguishability(
45        &self,
46        params: &PedersenParams,
47        value_a: u64,
48        value_b: u64,
49    ) -> bool {
50        let scalar_a = Scalar::from(value_a);
51        let scalar_b = Scalar::from(value_b);
52        let mut set_a = std::collections::HashSet::new();
53        for _ in 0..self.samples {
54            let (comm, _) = PedersenCommitment::commit(params, &scalar_a);
55            set_a.insert(comm.compressed.to_bytes());
56        }
57        // No commitment to B should match any commitment to A
58        for _ in 0..self.samples {
59            let (comm, _) = PedersenCommitment::commit(params, &scalar_b);
60            if set_a.contains(&comm.compressed.to_bytes()) {
61                return false;
62            }
63        }
64        true
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    fn unique_commitments() {
74        let params = PedersenParams::default();
75        let verifier = HidingVerifier::new(50);
76        assert!(verifier.test_unique_commitments(&params, 42));
77    }
78
79    #[test]
80    fn indistinguishability() {
81        let params = PedersenParams::default();
82        let verifier = HidingVerifier::new(50);
83        assert!(verifier.test_indistinguishability(&params, 0, 1));
84    }
85
86    #[test]
87    fn hiding_different_values() {
88        let params = PedersenParams::default();
89        let verifier = HidingVerifier::new(30);
90        assert!(verifier.test_indistinguishability(&params, 100, 200));
91    }
92}