1use crate::ring::rq::Rq;
2use crate::ring::zq::Zq;
3use core::ops::Mul;
4use rand::{CryptoRng, Rng};
5use std::ops::Add;
6
7#[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 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 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 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 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 pub fn l2_norm_squared(&self) -> Zq {
76 self.elements
77 .iter()
78 .map(|poly| poly.l2_norm_squared()) .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 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
112impl 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 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 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 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]
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}