labrador/relation/
witness.rs

1use rand::rng;
2
3use crate::ring::{rq::Rq, rq_vector::RqVector, zq::Zq};
4
5pub struct Witness {
6    pub s: Vec<RqVector>,
7}
8
9impl Witness {
10    pub fn new(rank: usize, multiplicity: usize, bound: Zq) -> Self {
11        #[allow(clippy::as_conversions)]
12        let std = (bound.get_value() as f64) / f64::sqrt((rank * multiplicity * Rq::DEGREE) as f64);
13        #[allow(clippy::as_conversions)]
14        let std = std as u32;
15        loop {
16            let s: Vec<RqVector> = (0..multiplicity)
17                .map(|_| RqVector::random_with_bound(&mut rng(), rank, std))
18                .collect();
19            if Self::validate_l2_norm(&s, bound) {
20                return Self { s };
21            }
22        }
23    }
24
25    fn validate_l2_norm(candidate: &[RqVector], bound: Zq) -> bool {
26        for witness in candidate {
27            if witness.l2_norm_squared() > bound * bound {
28                return false;
29            }
30        }
31        true
32    }
33}
34
35#[cfg(test)]
36mod tests {
37
38    use crate::ring::{rq::Rq, rq_vector::RqVector, zq::Zq};
39
40    use super::Witness;
41
42    #[test]
43    fn test_witness_vector_norm() {
44        let bound = Zq::new(320000);
45        let witness_vector = Witness::new(40, 100, bound);
46        assert_eq!(witness_vector.s.len(), 100);
47        assert_eq!(witness_vector.s[0].get_length(), 40);
48        for witness in witness_vector.s.iter() {
49            let l2_norm = witness.l2_norm_squared();
50            assert!(l2_norm < bound * bound)
51        }
52    }
53
54    #[test]
55    fn test_witness_with_larger_bound() {
56        let poly1 = Rq::new([Zq::new(10000); Rq::DEGREE]);
57        let poly2 = Rq::new([Zq::new(142310); Rq::DEGREE]);
58        let poly3 = Rq::new([Zq::new(9310); Rq::DEGREE]);
59        let poly_vector = vec![poly1, poly2, poly3];
60        assert!(!Witness::validate_l2_norm(
61            &[RqVector::new(poly_vector)],
62            Zq::new(1000)
63        ));
64    }
65}