labrador/ring/
rq_vector.rs

1use crate::ring::rq::Rq;
2use crate::ring::zq::Zq;
3use core::ops::Mul;
4use rand::{CryptoRng, Rng};
5use std::ops::Add;
6
7/// Vector of polynomials in Rq
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct RqVector {
10    elements: Vec<Rq>,
11}
12
13impl RqVector {
14    pub fn new(elements: Vec<Rq>) -> Self {
15        Self { elements }
16    }
17
18    pub fn new_from_zq_vector(elements: Vec<Zq>) -> Self {
19        let mut result = Vec::new();
20        debug_assert!(elements.len() % Rq::DEGREE == 0);
21        elements.chunks_exact(Rq::DEGREE).for_each(|chunk| {
22            result.push(Rq::new(chunk.try_into().unwrap()));
23        });
24
25        RqVector { elements: result }
26    }
27
28    /// Create a zero vector
29    pub fn zero(length: usize) -> Self {
30        Self {
31            elements: vec![Rq::zero(); length],
32        }
33    }
34
35    pub fn set(&mut self, index: usize, val: Rq) {
36        self.elements[index] = val;
37    }
38
39    pub fn get_length(&self) -> usize {
40        self.elements.len()
41    }
42
43    pub fn get_elements(&self) -> &Vec<Rq> {
44        &self.elements
45    }
46
47    /// Create a random vector
48    pub fn random<R: Rng + CryptoRng>(rng: &mut R, length: usize) -> Self {
49        Self {
50            elements: (0..length).map(|_| Rq::random(rng)).collect(),
51        }
52    }
53
54    pub fn random_with_bound<R: Rng + CryptoRng>(rng: &mut R, length: usize, bound: u32) -> Self {
55        Self {
56            elements: (0..length)
57                .map(|_| Rq::random_with_bound(rng, bound))
58                .collect(),
59        }
60    }
61
62    /// Function to concatenate coefficients from multiple Rq into a Vec<Zq>
63    pub fn concatenate_coefficients(&self) -> Vec<Zq> {
64        let total_coeffs = self.elements.len() * Rq::DEGREE;
65        let mut concatenated_coeffs: Vec<Zq> = Vec::with_capacity(total_coeffs);
66        // Iterate over each Rq, extracting the coefficients and concatenating them
67        for rq in &self.elements {
68            let coeffs = rq.get_coefficients();
69            concatenated_coeffs.extend_from_slice(coeffs);
70        }
71        concatenated_coeffs
72    }
73
74    // Compute the squared norm of a vector of polynomials
75    pub fn l2_norm_squared(&self) -> Zq {
76        self.elements
77            .iter()
78            .map(|poly| poly.l2_norm_squared()) // Collect coefficients from all polynomials
79            .sum()
80    }
81
82    pub fn decompose(&self, b: Zq, parts: usize) -> Vec<RqVector> {
83        self.get_elements()
84            .iter()
85            .map(|i| RqVector::new(Rq::decompose(i, b, parts)))
86            .collect()
87    }
88}
89
90impl Add<&RqVector> for &RqVector {
91    type Output = RqVector;
92    // add two poly vectors
93    fn add(self, other: &RqVector) -> RqVector {
94        self.get_elements()
95            .iter()
96            .zip(other.get_elements())
97            .map(|(a, b)| a + b)
98            .collect()
99    }
100}
101
102impl FromIterator<Rq> for RqVector {
103    fn from_iter<T: IntoIterator<Item = Rq>>(iter: T) -> Self {
104        let mut elements = Vec::new();
105        for item in iter {
106            elements.push(item);
107        }
108        RqVector::new(elements)
109    }
110}
111
112/// Create a new vector from a `Vec` of elements
113impl From<Vec<Rq>> for RqVector {
114    fn from(elements: Vec<Rq>) -> Self {
115        Self { elements }
116    }
117}
118
119impl Mul<&Rq> for &RqVector {
120    type Output = RqVector;
121    // A poly vector multiple by a PolyRing
122    fn mul(self, other: &Rq) -> RqVector {
123        self.get_elements().iter().map(|s| s * other).collect()
124    }
125}
126
127impl Mul<&Zq> for &RqVector {
128    type Output = RqVector;
129    // A poly vector multiple by a PolyRing
130    fn mul(self, other: &Zq) -> RqVector {
131        self.get_elements().iter().map(|s| s * other).collect()
132    }
133}
134
135impl Mul<Zq> for &RqVector {
136    type Output = RqVector;
137    // A poly vector multiple by a PolyRing
138    fn mul(self, other: Zq) -> RqVector {
139        self.get_elements().iter().map(|s| s * &other).collect()
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use rand::rng;
146
147    use super::*;
148    use crate::{core::inner_product, ring::rq::tests::generate_rq_from_zq_vector};
149
150    #[test]
151    fn test_rqvector_from_iterator() {
152        let expected = vec![
153            Rq::random(&mut rng()),
154            Rq::random(&mut rng()),
155            Rq::random(&mut rng()),
156        ];
157        let vector_of_polynomials = expected.clone().into_iter();
158        let result: RqVector = vector_of_polynomials.collect();
159
160        assert_eq!(result.get_elements(), &expected);
161    }
162
163    #[test]
164    fn test_rq_vector_multiplication_with_zq() {
165        let poly1: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(22)]);
166        let poly2: Rq = generate_rq_from_zq_vector(vec![Zq::new(17), Zq::new(12)]);
167        let rq_vector = RqVector::from(vec![poly1, poly2]);
168        let result = &rq_vector * Zq::new(3);
169
170        assert_eq!(
171            result.get_elements()[0],
172            generate_rq_from_zq_vector(vec![Zq::new(3), Zq::new(66)])
173        );
174        assert_eq!(
175            result.get_elements()[1],
176            generate_rq_from_zq_vector(vec![Zq::new(51), Zq::new(36)])
177        );
178
179        #[allow(clippy::op_ref)]
180        let result2 = &rq_vector * &Zq::new(3);
181        assert_eq!(
182            result2.get_elements()[0],
183            generate_rq_from_zq_vector(vec![Zq::new(3), Zq::new(66)])
184        );
185        assert_eq!(
186            result2.get_elements()[1],
187            generate_rq_from_zq_vector(vec![Zq::new(51), Zq::new(36)])
188        );
189    }
190
191    #[test]
192    fn test_rqvector_mul() {
193        let poly1: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2)]);
194        let poly2: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(4)]);
195        let vec_1: RqVector = RqVector::from(vec![poly1]);
196        let vec_2: RqVector = RqVector::from(vec![poly2]);
197        let result =
198            inner_product::compute_linear_combination(vec_1.get_elements(), vec_2.get_elements());
199        let poly_exp: Rq = generate_rq_from_zq_vector(vec![Zq::new(1), Zq::new(6), Zq::new(8)]);
200        assert_eq!(result, poly_exp);
201
202        let poly3: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::ONE, Zq::ONE]);
203        let poly4: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::ONE, Zq::ONE]);
204        let vec_3: RqVector = RqVector::from(vec![poly3]);
205        let vec_4: RqVector = RqVector::from(vec![poly4]);
206        let result_1 =
207            inner_product::compute_linear_combination(vec_3.get_elements(), vec_4.get_elements());
208        let poly_exp_1: Rq = generate_rq_from_zq_vector(vec![
209            Zq::new(1),
210            Zq::new(2),
211            Zq::new(3),
212            Zq::new(4),
213            Zq::new(3),
214            Zq::new(2),
215            Zq::new(1),
216        ]);
217        assert_eq!(result_1, poly_exp_1);
218
219        let poly5: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::ONE, Zq::ONE]);
220        let poly6: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::ONE, Zq::ONE]);
221        let poly7: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::ONE, Zq::ONE]);
222        let poly8: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::ONE, Zq::ONE]);
223        let vec_5: RqVector = RqVector::from(vec![poly5, poly6]);
224        let vec_6: RqVector = RqVector::from(vec![poly7, poly8]);
225        let result_2 =
226            inner_product::compute_linear_combination(vec_5.get_elements(), vec_6.get_elements());
227        let poly_exp_2: Rq = generate_rq_from_zq_vector(vec![
228            Zq::new(2),
229            Zq::new(4),
230            Zq::new(6),
231            Zq::new(8),
232            Zq::new(6),
233            Zq::new(4),
234            Zq::new(2),
235        ]);
236        assert_eq!(result_2, poly_exp_2);
237    }
238
239    // Test the square of the norm
240    #[test]
241    fn test_norm() {
242        let poly1 = generate_rq_from_zq_vector(vec![
243            Zq::ONE,
244            Zq::ZERO,
245            Zq::new(5),
246            Zq::NEG_ONE - Zq::new(1),
247        ]);
248        let poly2 = generate_rq_from_zq_vector(vec![Zq::ZERO, Zq::ZERO, Zq::new(5), Zq::ONE]);
249        let poly_vec1: RqVector = vec![poly1.clone(), poly2.clone()].into();
250        assert_eq!(
251            poly_vec1.l2_norm_squared(),
252            poly1.l2_norm_squared() + poly2.l2_norm_squared()
253        );
254
255        let zero_vec: RqVector = RqVector::zero(4);
256        assert_eq!(zero_vec.l2_norm_squared(), Zq::ZERO);
257    }
258}