1use std::alloc::Allocator;
2use std::alloc::Global;
3use std::marker::PhantomData;
4use std::sync::Arc;
5
6use feanor_math::algorithms::convolution::PreparedConvolutionAlgorithm;
7use feanor_math::algorithms::matmul::ComputeInnerProduct;
8use feanor_math::divisibility::*;
9use feanor_math::integer::*;
10use feanor_math::iters::multi_cartesian_product;
11use feanor_math::iters::MultiProduct;
12use feanor_math::matrix::*;
13use feanor_math::rings::extension::*;
14use feanor_math::rings::finite::*;
15use feanor_math::ring::*;
16use feanor_math::rings::poly::dense_poly::DensePolyRing;
17use feanor_math::rings::zn::*;
18use feanor_math::rings::zn::zn_64::*;
19use feanor_math::homomorphism::*;
20use feanor_math::seq::*;
21use feanor_math::serialization::*;
22use feanor_math::specialization::{FiniteRingOperation, FiniteRingSpecializable};
23
24use serde::Deserializer;
25use serde::Serialize;
26use serde::de::DeserializeSeed;
27use tracing::instrument;
28
29use crate::cyclotomic::{CyclotomicGaloisGroupEl, CyclotomicRing};
30use crate::number_ring::*;
31use super::serialization::deserialize_rns_data;
32use super::serialization::serialize_rns_data;
33use super::single_rns_ring::*;
34use super::BGFVCiphertextRing;
35use super::PreparedMultiplicationRing;
36
37pub struct DoubleRNSRingBase<NumberRing, A = Global>
58 where NumberRing: HENumberRing,
59 A: Allocator + Clone
60{
61 number_ring: NumberRing,
63 ring_decompositions: Vec<Arc<<NumberRing as HENumberRing>::Decomposed>>,
65 rns_base: zn_rns::Zn<Zn, BigIntRing>,
67 allocator: A
69}
70
71pub type DoubleRNSRing<NumberRing, A = Global> = RingValue<DoubleRNSRingBase<NumberRing, A>>;
75
76pub struct DoubleRNSEl<NumberRing, A = Global>
81 where NumberRing: HENumberRing,
82 A: Allocator + Clone
83{
84 number_ring: PhantomData<NumberRing>,
85 allocator: PhantomData<A>,
86 el_wrt_mult_basis: Vec<ZnEl, A>
87}
88
89pub struct SmallBasisEl<NumberRing, A = Global>
93 where NumberRing: HENumberRing,
94 A: Allocator + Clone
95{
96 number_ring: PhantomData<NumberRing>,
97 allocator: PhantomData<A>,
98 el_wrt_small_basis: Vec<ZnEl, A>
99}
100
101impl<NumberRing> DoubleRNSRingBase<NumberRing>
102 where NumberRing: HENumberRing
103{
104 #[instrument(skip_all)]
111 pub fn new(number_ring: NumberRing, rns_base: zn_rns::Zn<Zn, BigIntRing>) -> RingValue<Self> {
112 Self::new_with(number_ring, rns_base, Global)
113 }
114}
115
116impl<NumberRing, A> Clone for DoubleRNSRingBase<NumberRing, A>
117 where NumberRing: HENumberRing + Clone,
118 A: Allocator + Clone
119{
120 fn clone(&self) -> Self {
121 Self {
122 allocator: self.allocator.clone(),
123 number_ring: self.number_ring.clone(),
124 ring_decompositions: self.ring_decompositions.clone(),
125 rns_base: self.rns_base.clone()
126 }
127 }
128}
129
130impl<NumberRing, A> DoubleRNSRingBase<NumberRing, A>
131 where NumberRing: HENumberRing + Clone,
132 A: Allocator + Clone
133{
134 #[instrument(skip_all)]
135 pub fn drop_rns_factor(&self, drop_rns_factors: &[usize]) -> RingValue<Self> {
136 RingValue::from(Self {
137 ring_decompositions: self.ring_decompositions.iter().enumerate().filter(|(i, _)| !drop_rns_factors.contains(i)).map(|(_, x)| x.clone()).collect(),
138 number_ring: self.number_ring().clone(),
139 rns_base: zn_rns::Zn::new(self.rns_base().as_iter().enumerate().filter(|(i, _)| !drop_rns_factors.contains(i)).map(|(_, x)| x.clone()).collect(), BigIntRing::RING),
140 allocator: self.allocator().clone()
141 })
142 }
143}
144
145impl<NumberRing, A> DoubleRNSRingBase<NumberRing, A>
146 where NumberRing: HENumberRing,
147 A: Allocator + Clone
148{
149 #[instrument(skip_all)]
156 pub fn new_with(number_ring: NumberRing, rns_base: zn_rns::Zn<Zn, BigIntRing>, allocator: A) -> RingValue<Self> {
157 assert!(rns_base.len() > 0);
158 RingValue::from(Self {
159 ring_decompositions: rns_base.as_iter().map(|Fp| Arc::new(number_ring.mod_p(Fp.clone()))).collect(),
160 number_ring: number_ring,
161 rns_base: rns_base,
162 allocator: allocator
163 })
164 }
165
166 pub fn ring_decompositions<'a>(&'a self) -> impl VectorFn<&'a <NumberRing as HENumberRing>::Decomposed> + use<'a, NumberRing, A> {
167 self.ring_decompositions.as_fn().map_fn(|x| &**x)
168 }
169
170 pub fn rns_base(&self) -> &zn_rns::Zn<Zn, BigIntRing> {
171 &self.rns_base
172 }
173
174 pub fn element_len(&self) -> usize {
175 self.rank() * self.rns_base().len()
176 }
177
178 pub fn as_matrix_wrt_small_basis<'a>(&self, element: &'a SmallBasisEl<NumberRing, A>) -> Submatrix<'a, AsFirstElement<ZnEl>, ZnEl> {
179 Submatrix::from_1d(&element.el_wrt_small_basis, self.rns_base().len(), self.rank())
180 }
181
182 pub fn as_matrix_wrt_small_basis_mut<'a>(&self, element: &'a mut SmallBasisEl<NumberRing, A>) -> SubmatrixMut<'a, AsFirstElement<ZnEl>, ZnEl> {
183 SubmatrixMut::from_1d(&mut element.el_wrt_small_basis, self.rns_base().len(), self.rank())
184 }
185
186 pub fn as_matrix_wrt_mult_basis<'a>(&self, element: &'a DoubleRNSEl<NumberRing, A>) -> Submatrix<'a, AsFirstElement<ZnEl>, ZnEl> {
187 Submatrix::from_1d(&element.el_wrt_mult_basis, self.rns_base().len(), self.rank())
188 }
189
190 pub fn as_matrix_wrt_mult_basis_mut<'a>(&self, element: &'a mut DoubleRNSEl<NumberRing, A>) -> SubmatrixMut<'a, AsFirstElement<ZnEl>, ZnEl> {
191 SubmatrixMut::from_1d(&mut element.el_wrt_mult_basis, self.rns_base().len(), self.rank())
192 }
193
194 pub fn number_ring(&self) -> &NumberRing {
195 &self.number_ring
196 }
197
198 #[instrument(skip_all)]
204 pub fn undo_fft(&self, element: DoubleRNSEl<NumberRing, A>) -> SmallBasisEl<NumberRing, A> {
205 assert_eq!(element.el_wrt_mult_basis.len(), self.element_len());
206 let mut result = element.el_wrt_mult_basis;
207 for i in 0..self.rns_base().len() {
208 self.ring_decompositions[i].mult_basis_to_small_basis(&mut result[(i * self.rank())..((i + 1) * self.rank())]);
209 }
210 SmallBasisEl {
211 el_wrt_small_basis: result,
212 number_ring: PhantomData,
213 allocator: PhantomData
214 }
215 }
216
217 #[instrument(skip_all)]
218 pub fn undo_fft_partial<V>(&self, element: &DoubleRNSEl<NumberRing, A>, required_rns_factors: &[usize], mut output: SubmatrixMut<V, ZnEl>)
219 where V: AsPointerToSlice<ZnEl>
220 {
221 assert_eq!(element.el_wrt_mult_basis.len(), self.element_len());
222 assert_eq!(output.col_count(), self.rank());
223 assert_eq!(output.row_count(), required_rns_factors.len());
224 for (i_out, i_in) in required_rns_factors.iter().copied().enumerate() {
225 assert!(i_in < self.rns_base().len());
226 for j in 0..self.rank() {
227 *output.at_mut(i_out, j) = element.el_wrt_mult_basis[i_in * self.rank() + j];
228 }
229 self.ring_decompositions[i_in].mult_basis_to_small_basis(output.row_mut_at(i_out));
230 }
231 }
232
233 pub fn allocator(&self) -> &A {
234 &self.allocator
235 }
236
237 pub fn zero_non_fft(&self) -> SmallBasisEl<NumberRing, A> {
238 SmallBasisEl {
239 el_wrt_small_basis: self.zero().el_wrt_mult_basis,
240 number_ring: PhantomData,
241 allocator: PhantomData
242 }
243 }
244
245 pub fn from_non_fft(&self, x: El<<Self as RingExtension>::BaseRing>) -> SmallBasisEl<NumberRing, A> {
246 let mut result = Vec::with_capacity_in(self.element_len(), self.allocator.clone());
247 let x = self.base_ring().get_congruence(&x);
248 for (i, Zp) in self.rns_base().as_iter().enumerate() {
249 result.push(Zp.clone_el(x.at(i)));
250 for _ in 1..self.rank() {
251 result.push(Zp.zero());
252 }
253 self.ring_decompositions[i].coeff_basis_to_small_basis(&mut result[(i * self.rank())..((i + 1) * self.rank())]);
254 }
255 SmallBasisEl {
256 el_wrt_small_basis: result,
257 number_ring: PhantomData,
258 allocator: PhantomData
259 }
260 }
261
262 #[instrument(skip_all)]
269 pub fn do_fft(&self, element: SmallBasisEl<NumberRing, A>) -> DoubleRNSEl<NumberRing, A> {
270 assert_eq!(element.el_wrt_small_basis.len(), self.element_len());
271 let mut result = element.el_wrt_small_basis;
272 for i in 0..self.rns_base().len() {
273 self.ring_decompositions[i].small_basis_to_mult_basis(&mut result[(i * self.rank())..((i + 1) * self.rank())]);
274 }
275 DoubleRNSEl {
276 el_wrt_mult_basis: result,
277 number_ring: PhantomData,
278 allocator: PhantomData
279 }
280 }
281
282 #[instrument(skip_all)]
283 pub fn sample_from_coefficient_distribution<G: FnMut() -> i32>(&self, mut distribution: G) -> SmallBasisEl<NumberRing, A> {
284 let mut result = self.zero_non_fft().el_wrt_small_basis;
285 for j in 0..self.rank() {
286 let c = distribution();
287 for i in 0..self.rns_base().len() {
288 result[j + i * self.rank()] = self.rns_base().at(i).int_hom().map(c);
289 }
290 }
291 for i in 0..self.rns_base().len() {
292 self.ring_decompositions[i].coeff_basis_to_small_basis(&mut result[(i * self.rank())..((i + 1) * self.rank())]);
293 }
294 return SmallBasisEl {
295 el_wrt_small_basis: result,
296 allocator: PhantomData,
297 number_ring: PhantomData
298 };
299 }
300
301 #[instrument(skip_all)]
302 pub fn clone_el_non_fft(&self, val: &SmallBasisEl<NumberRing, A>) -> SmallBasisEl<NumberRing, A> {
303 assert_eq!(self.element_len(), val.el_wrt_small_basis.len());
304 let mut result = Vec::with_capacity_in(self.element_len(), self.allocator.clone());
305 result.extend((0..self.element_len()).map(|i| self.rns_base().at(i / self.rank()).clone_el(&val.el_wrt_small_basis[i])));
306 SmallBasisEl {
307 el_wrt_small_basis: result,
308 number_ring: PhantomData,
309 allocator: PhantomData
310 }
311 }
312
313 #[instrument(skip_all)]
314 pub fn eq_el_non_fft(&self, lhs: &SmallBasisEl<NumberRing, A>, rhs: &SmallBasisEl<NumberRing, A>) -> bool {
315 assert_eq!(self.element_len(), lhs.el_wrt_small_basis.len());
316 assert_eq!(self.element_len(), rhs.el_wrt_small_basis.len());
317 for i in 0..self.rns_base().len() {
318 for j in 0..self.rank() {
319 if !self.rns_base().at(i).eq_el(&lhs.el_wrt_small_basis[i * self.rank() + j], &rhs.el_wrt_small_basis[i * self.rank() + j]) {
320 return false;
321 }
322 }
323 }
324 return true;
325 }
326
327 #[instrument(skip_all)]
328 pub fn negate_inplace_non_fft(&self, val: &mut SmallBasisEl<NumberRing, A>) {
329 assert_eq!(self.element_len(), val.el_wrt_small_basis.len());
330 for i in 0..self.rns_base().len() {
331 for j in 0..self.rank() {
332 self.rns_base().at(i).negate_inplace(&mut val.el_wrt_small_basis[i * self.rank() + j]);
333 }
334 }
335 }
336
337 #[instrument(skip_all)]
338 pub fn negate_non_fft(&self, mut val: SmallBasisEl<NumberRing, A>) -> SmallBasisEl<NumberRing, A> {
339 self.negate_inplace_non_fft(&mut val);
340 return val;
341 }
342
343 #[instrument(skip_all)]
344 pub fn sub_assign_non_fft(&self, lhs: &mut SmallBasisEl<NumberRing, A>, rhs: &SmallBasisEl<NumberRing, A>) {
345 assert_eq!(self.element_len(), lhs.el_wrt_small_basis.len());
346 assert_eq!(self.element_len(), rhs.el_wrt_small_basis.len());
347 for i in 0..self.rns_base().len() {
348 for j in 0..self.rank() {
349 self.rns_base().at(i).sub_assign_ref(&mut lhs.el_wrt_small_basis[i * self.rank() + j], &rhs.el_wrt_small_basis[i * self.rank() + j]);
350 }
351 }
352 }
353
354 #[instrument(skip_all)]
355 pub fn mul_scalar_assign_non_fft(&self, lhs: &mut SmallBasisEl<NumberRing, A>, rhs: &El<zn_rns::Zn<Zn, BigIntRing>>) {
356 assert_eq!(self.element_len(), lhs.el_wrt_small_basis.len());
357 for i in 0..self.rns_base().len() {
358 for j in 0..self.rank() {
359 self.rns_base().at(i).mul_assign_ref(&mut lhs.el_wrt_small_basis[i * self.rank() + j], self.rns_base().get_congruence(rhs).at(i));
360 }
361 }
362 }
363
364 #[instrument(skip_all)]
365 pub fn add_assign_non_fft(&self, lhs: &mut SmallBasisEl<NumberRing, A>, rhs: &SmallBasisEl<NumberRing, A>) {
366 assert_eq!(self.element_len(), lhs.el_wrt_small_basis.len());
367 assert_eq!(self.element_len(), rhs.el_wrt_small_basis.len());
368 for i in 0..self.rns_base().len() {
369 for j in 0..self.rank() {
370 self.rns_base().at(i).add_assign_ref(&mut lhs.el_wrt_small_basis[i * self.rank() + j], &rhs.el_wrt_small_basis[i * self.rank() + j]);
371 }
372 }
373 }
374
375 #[instrument(skip_all)]
376 pub fn from_canonical_basis_non_fft<V>(&self, vec: V) -> SmallBasisEl<NumberRing, A>
377 where V: IntoIterator<Item = El<<Self as RingExtension>::BaseRing>>
378 {
379 let mut result = self.zero_non_fft().el_wrt_small_basis;
380 for (j, x) in vec.into_iter().enumerate() {
381 let congruence = self.base_ring().get_ring().get_congruence(&x);
382 for i in 0..self.rns_base().len() {
383 result[i * self.rank() + j] = self.rns_base().at(i).clone_el(congruence.at(i));
384 }
385 }
386 for i in 0..self.rns_base().len() {
387 self.ring_decompositions[i].coeff_basis_to_small_basis(&mut result[(i * self.rank())..((i + 1) * self.rank())]);
388 }
389 return SmallBasisEl {
390 el_wrt_small_basis: result,
391 allocator: PhantomData,
392 number_ring: PhantomData
393 };
394 }
395
396 #[instrument(skip_all)]
397 pub fn wrt_canonical_basis_non_fft<'a>(&'a self, el: SmallBasisEl<NumberRing, A>) -> DoubleRNSRingBaseElVectorRepresentation<'a, NumberRing, A> {
398 let mut result = el.el_wrt_small_basis;
399 for i in 0..self.rns_base().len() {
400 self.ring_decompositions[i].small_basis_to_coeff_basis(&mut result[(i * self.rank())..((i + 1) * self.rank())]);
401 }
402 return DoubleRNSRingBaseElVectorRepresentation {
403 ring: self,
404 el_wrt_coeff_basis: result
405 };
406 }
407
408 #[instrument(skip_all)]
409 pub fn map_in_from_singlerns<A2, C>(&self, from: &SingleRNSRingBase<NumberRing, A2, C>, mut el: El<SingleRNSRing<NumberRing, A2, C>>, hom: &<Self as CanHomFrom<SingleRNSRingBase<NumberRing, A2, C>>>::Homomorphism) -> SmallBasisEl<NumberRing, A>
410 where NumberRing: HECyclotomicNumberRing,
411 A2: Allocator + Clone,
412 C: PreparedConvolutionAlgorithm<ZnBase>
413 {
414 let mut result = Vec::with_capacity_in(self.element_len(), self.allocator.clone());
415 let el_as_matrix = from.to_matrix(&mut el);
416 for (i, Zp) in self.rns_base().as_iter().enumerate() {
417 for j in 0..self.rank() {
418 result.push(Zp.get_ring().map_in_ref(from.rns_base().at(i).get_ring(), el_as_matrix.at(i, j), &hom[i]));
419 }
420 }
421 for i in 0..self.rns_base().len() {
422 self.ring_decompositions().at(i).coeff_basis_to_small_basis(&mut result[(i * self.rank())..((i + 1) * self.rank())]);
423 }
424 SmallBasisEl {
425 el_wrt_small_basis: result,
426 number_ring: PhantomData,
427 allocator: PhantomData
428 }
429 }
430
431 #[instrument(skip_all)]
432 pub fn map_out_to_singlerns<A2, C>(&self, to: &SingleRNSRingBase<NumberRing, A2, C>, el: SmallBasisEl<NumberRing, A>, iso: &<Self as CanIsoFromTo<SingleRNSRingBase<NumberRing, A2, C>>>::Isomorphism) -> El<SingleRNSRing<NumberRing, A2, C>>
433 where NumberRing: HECyclotomicNumberRing,
434 A2: Allocator + Clone,
435 C: PreparedConvolutionAlgorithm<ZnBase>
436 {
437 let mut result = to.zero();
438 let mut result_matrix = to.coefficients_as_matrix_mut(&mut result);
439 let mut el_coeff = el.el_wrt_small_basis;
440 for i in 0..self.rns_base().len() {
441 self.ring_decompositions().at(i).small_basis_to_coeff_basis(&mut el_coeff[(i * self.rank())..((i + 1) * self.rank())]);
442 }
443 for (i, Zp) in self.rns_base().as_iter().enumerate() {
444 for j in 0..self.rank() {
445 *result_matrix.at_mut(i, j) = Zp.get_ring().map_out(to.rns_base().at(i).get_ring(), Zp.clone_el(&el_coeff[i * self.rank() + j]), &iso[i]);
446 }
447 }
448 return result;
449 }
450
451 #[instrument(skip_all)]
452 pub fn drop_rns_factor_element(&self, from: &Self, drop_factors: &[usize], value: &DoubleRNSEl<NumberRing, A>) -> DoubleRNSEl<NumberRing, A> {
453 assert!(self.number_ring() == from.number_ring());
454 assert_eq!(self.base_ring().len() + drop_factors.len(), from.base_ring().len());
455 assert!(drop_factors.iter().all(|i| *i < from.base_ring().len()));
456 assert_eq!(from.element_len(), value.el_wrt_mult_basis.len());
457
458 let mut result = self.zero();
459 let mut i_self = 0;
460 for i_from in 0..from.base_ring().len() {
461 if drop_factors.contains(&i_from) {
462 continue;
463 }
464 assert!(self.base_ring().at(i_self).get_ring() == from.base_ring().at(i_from).get_ring());
465 for j in 0..self.rank() {
466 result.el_wrt_mult_basis[j + i_self * self.rank()] = value.el_wrt_mult_basis[j + i_from * from.rank()];
467 }
468 i_self += 1;
469 }
470
471 return result;
472 }
473
474 #[instrument(skip_all)]
475 pub fn drop_rns_factor_non_fft_element(&self, from: &Self, drop_factors: &[usize], value: &SmallBasisEl<NumberRing, A>) -> SmallBasisEl<NumberRing, A> {
476 assert!(self.number_ring() == from.number_ring());
477 assert_eq!(self.base_ring().len() + drop_factors.len(), from.base_ring().len());
478 assert!(drop_factors.iter().all(|i| *i < from.base_ring().len()));
479 assert_eq!(from.element_len(), value.el_wrt_small_basis.len());
480
481 let mut result = self.zero_non_fft();
482 let mut result_as_matrix = self.as_matrix_wrt_small_basis_mut(&mut result);
483 let value_as_matrix = from.as_matrix_wrt_small_basis(&value);
484 let mut i_self = 0;
485 for i_from in 0..from.base_ring().len() {
486 if drop_factors.contains(&i_from) {
487 continue;
488 }
489 assert!(self.base_ring().at(i_self).get_ring() == from.base_ring().at(i_from).get_ring());
490 for j in 0..self.rank() {
491 *result_as_matrix.at_mut(i_self, j) = *value_as_matrix.at(i_from, j);
492 }
493 i_self += 1;
494 }
495
496 return result;
497 }
498
499 fn inner_product_base<'a, I: Clone + Iterator<Item = (&'a DoubleRNSEl<NumberRing, A>, &'a DoubleRNSEl<NumberRing, A>)>>(&self, els: I) -> DoubleRNSEl<NumberRing, A>
500 where Self: 'a
501 {
502 let mut result = self.zero();
503 for i in 0..self.rns_base().len() {
504 for j in 0..self.rank() {
505 let idx = i * self.rank() + j;
506 result.el_wrt_mult_basis[idx] = <_ as ComputeInnerProduct>::inner_product(
507 self.rns_base().at(i).get_ring(),
508 els.clone().map(|(l, r)| (l.el_wrt_mult_basis[idx], r.el_wrt_mult_basis[idx]))
509 )
510 }
511 }
512 return result;
513 }
514}
515
516impl<NumberRing, A> PartialEq for DoubleRNSRingBase<NumberRing, A>
517 where NumberRing: HENumberRing,
518 A: Allocator + Clone
519{
520 fn eq(&self, other: &Self) -> bool {
521 self.number_ring == other.number_ring && self.rns_base.get_ring() == other.rns_base.get_ring()
522 }
523}
524
525impl<NumberRing, A> RingBase for DoubleRNSRingBase<NumberRing, A>
526 where NumberRing: HENumberRing,
527 A: Allocator + Clone
528{
529 type Element = DoubleRNSEl<NumberRing, A>;
530
531 fn clone_el(&self, val: &Self::Element) -> Self::Element {
532 assert_eq!(self.element_len(), val.el_wrt_mult_basis.len());
533 let mut result = Vec::with_capacity_in(self.element_len(), self.allocator.clone());
534 result.extend((0..self.element_len()).map(|i| self.rns_base().at(i / self.rank()).clone_el(&val.el_wrt_mult_basis[i])));
535 DoubleRNSEl {
536 el_wrt_mult_basis: result,
537 number_ring: PhantomData,
538 allocator: PhantomData
539 }
540 }
541
542 #[instrument(skip_all)]
543 fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
544 assert_eq!(self.element_len(), lhs.el_wrt_mult_basis.len());
545 assert_eq!(self.element_len(), rhs.el_wrt_mult_basis.len());
546 for i in 0..self.rns_base().len() {
547 for j in 0..self.rank() {
548 self.rns_base().at(i).add_assign_ref(&mut lhs.el_wrt_mult_basis[i * self.rank() + j], &rhs.el_wrt_mult_basis[i * self.rank() + j]);
549 }
550 }
551 }
552
553 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
554 self.add_assign_ref(lhs, &rhs);
555 }
556
557 #[instrument(skip_all)]
558 fn sub_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
559 assert_eq!(self.element_len(), lhs.el_wrt_mult_basis.len());
560 assert_eq!(self.element_len(), rhs.el_wrt_mult_basis.len());
561 for i in 0..self.rns_base().len() {
562 for j in 0..self.rank() {
563 self.rns_base().at(i).sub_assign_ref(&mut lhs.el_wrt_mult_basis[i * self.rank() + j], &rhs.el_wrt_mult_basis[i * self.rank() + j]);
564 }
565 }
566 }
567
568 #[instrument(skip_all)]
569 fn negate_inplace(&self, lhs: &mut Self::Element) {
570 assert_eq!(self.element_len(), lhs.el_wrt_mult_basis.len());
571 for i in 0..self.rns_base().len() {
572 for j in 0..self.rank() {
573 self.rns_base().at(i).negate_inplace(&mut lhs.el_wrt_mult_basis[i * self.rank() + j]);
574 }
575 }
576 }
577
578 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
579 self.mul_assign_ref(lhs, &rhs);
580 }
581
582 #[instrument(skip_all)]
583 fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
584 assert_eq!(self.element_len(), lhs.el_wrt_mult_basis.len());
585 assert_eq!(self.element_len(), rhs.el_wrt_mult_basis.len());
586 for i in 0..self.rns_base().len() {
587 for j in 0..self.rank() {
588 self.rns_base().at(i).mul_assign_ref(&mut lhs.el_wrt_mult_basis[i * self.rank() + j], &rhs.el_wrt_mult_basis[i * self.rank() + j]);
589 }
590 }
591 }
592
593 fn from_int(&self, value: i32) -> Self::Element {
594 self.from(self.base_ring().get_ring().from_int(value))
595 }
596
597 #[instrument(skip_all)]
598 fn mul_assign_int(&self, lhs: &mut Self::Element, rhs: i32) {
599 assert_eq!(self.element_len(), lhs.el_wrt_mult_basis.len());
600 for i in 0..self.rns_base().len() {
601 let rhs_mod_p = self.rns_base().at(i).get_ring().from_int(rhs);
602 for j in 0..self.rank() {
603 self.rns_base().at(i).mul_assign_ref(&mut lhs.el_wrt_mult_basis[i * self.rank() + j], &rhs_mod_p);
604 }
605 }
606 }
607
608 fn zero(&self) -> Self::Element {
609 let mut result = Vec::with_capacity_in(self.element_len(), self.allocator.clone());
610 result.extend(self.rns_base().as_iter().flat_map(|Zp| (0..self.rank()).map(|_| Zp.zero())));
611 return DoubleRNSEl {
612 el_wrt_mult_basis: result,
613 number_ring: PhantomData,
614 allocator: PhantomData
615 };
616 }
617
618 #[instrument(skip_all)]
619 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
620 assert_eq!(self.element_len(), lhs.el_wrt_mult_basis.len());
621 assert_eq!(self.element_len(), rhs.el_wrt_mult_basis.len());
622 for i in 0..self.rns_base().len() {
623 for j in 0..self.rank() {
624 if !self.rns_base().at(i).eq_el(&lhs.el_wrt_mult_basis[i * self.rank() + j], &rhs.el_wrt_mult_basis[i * self.rank() + j]) {
625 return false;
626 }
627 }
628 }
629 return true;
630 }
631
632 fn is_commutative(&self) -> bool { true }
633 fn is_noetherian(&self) -> bool { true }
634 fn is_approximate(&self) -> bool { false }
635
636 fn dbg_within<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>, env: EnvBindingStrength) -> std::fmt::Result {
637 let poly_ring = DensePolyRing::new(self.base_ring(), "X");
638 poly_ring.get_ring().dbg_within(&RingRef::new(self).poly_repr(&poly_ring, value, self.base_ring().identity()), out, env)
639 }
640
641 fn dbg<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
642 self.dbg_within(value, out, EnvBindingStrength::Weakest)
643 }
644
645 #[instrument(skip_all)]
646 fn square(&self, value: &mut Self::Element) {
647 assert_eq!(self.element_len(), value.el_wrt_mult_basis.len());
648 for i in 0..self.rns_base().len() {
649 for j in 0..self.rank() {
650 self.rns_base().at(i).square(&mut value.el_wrt_mult_basis[i * self.rank() + j]);
651 }
652 }
653 }
654
655 fn characteristic<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
656 where I::Type: IntegerRing
657 {
658 self.base_ring().characteristic(ZZ)
659 }
660}
661
662impl<NumberRing, A> CyclotomicRing for DoubleRNSRingBase<NumberRing, A>
663 where NumberRing: HECyclotomicNumberRing,
664 A: Allocator + Clone
665{
666 fn n(&self) -> usize {
667 self.number_ring.n() as usize
668 }
669
670 #[instrument(skip_all)]
671 fn apply_galois_action(&self, el: &Self::Element, g: CyclotomicGaloisGroupEl) -> Self::Element {
672 assert_eq!(self.element_len(), el.el_wrt_mult_basis.len());
673 let mut result = self.zero();
674 for (i, _) in self.rns_base().as_iter().enumerate() {
675 self.ring_decompositions().at(i).permute_galois_action(
676 &el.el_wrt_mult_basis[(i * self.rank())..((i + 1) * self.rank())],
677 &mut result.el_wrt_mult_basis[(i * self.rank())..((i + 1) * self.rank())],
678 g
679 );
680 }
681 return result;
682 }
683}
684
685impl<NumberRing, A> ComputeInnerProduct for DoubleRNSRingBase<NumberRing, A>
686 where NumberRing: HENumberRing,
687 A: Allocator + Clone
688{
689 #[instrument(skip_all)]
690 fn inner_product<I: Iterator<Item = (Self::Element, Self::Element)>>(&self, els: I) -> Self::Element {
691 let data = els.collect::<Vec<_>>();
692 return self.inner_product_base(data.iter().map(|(l, r)| (l, r)));
693 }
694
695 #[instrument(skip_all)]
696 fn inner_product_ref<'a, I: Iterator<Item = (&'a Self::Element, &'a Self::Element)>>(&self, els: I) -> Self::Element
697 where Self: 'a
698 {
699 let data = els.collect::<Vec<_>>();
700 return self.inner_product_base(data.iter().map(|(l, r)| (*l, *r)));
701 }
702
703 #[instrument(skip_all)]
704 fn inner_product_ref_fst<'a, I: Iterator<Item = (&'a Self::Element, Self::Element)>>(&self, els: I) -> Self::Element
705 where Self::Element: 'a,
706 Self: 'a
707 {
708 let data = els.collect::<Vec<_>>();
709 return self.inner_product_base(data.iter().map(|(l, r)| (*l, r)));
710 }
711}
712
713impl<NumberRing, A> DivisibilityRing for DoubleRNSRingBase<NumberRing, A>
714 where NumberRing: HENumberRing,
715 A: Allocator + Clone
716{
717 #[instrument(skip_all)]
718 fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
719 let mut result = Vec::with_capacity_in(self.element_len(), self.allocator.clone());
720 for (i, Zp) in self.rns_base().as_iter().enumerate() {
721 for j in 0..self.rank() {
722 result.push(Zp.checked_div(&lhs.el_wrt_mult_basis[i * self.rank() + j], &rhs.el_wrt_mult_basis[i * self.rank() + j])?);
723 }
724 }
725 return Some(DoubleRNSEl { el_wrt_mult_basis: result, number_ring: PhantomData, allocator: PhantomData })
726 }
727
728 fn is_unit(&self, x: &Self::Element) -> bool {
729 x.el_wrt_mult_basis.iter().enumerate().all(|(index, c)| self.rns_base().at(index / self.rank()).is_unit(c))
730 }
731}
732
733pub struct DoubleRNSRingBaseElVectorRepresentation<'a, NumberRing, A>
734 where NumberRing: HENumberRing,
735 A: Allocator + Clone
736{
737 el_wrt_coeff_basis: Vec<ZnEl, A>,
738 ring: &'a DoubleRNSRingBase<NumberRing, A>
739}
740
741impl<'a, NumberRing, A> VectorFn<El<zn_rns::Zn<Zn, BigIntRing>>> for DoubleRNSRingBaseElVectorRepresentation<'a, NumberRing, A>
742 where NumberRing: HENumberRing,
743 A: Allocator + Clone
744{
745 fn len(&self) -> usize {
746 self.ring.rank()
747 }
748
749 fn at(&self, i: usize) -> El<zn_rns::Zn<Zn, BigIntRing>> {
750 assert!(i < self.len());
751 self.ring.rns_base().from_congruence(self.el_wrt_coeff_basis[i..].iter().step_by(self.ring.rank()).enumerate().map(|(i, x)| self.ring.rns_base().at(i).clone_el(x)))
752 }
753}
754
755impl<NumberRing, A> FreeAlgebra for DoubleRNSRingBase<NumberRing, A>
756 where NumberRing: HENumberRing,
757 A: Allocator + Clone
758{
759 type VectorRepresentation<'a> = DoubleRNSRingBaseElVectorRepresentation<'a, NumberRing, A>
760 where Self: 'a;
761
762 #[instrument(skip_all)]
763 fn canonical_gen(&self) -> Self::Element {
764 let mut result = self.zero_non_fft().el_wrt_small_basis;
765 for (i, Zp) in self.rns_base().as_iter().enumerate() {
766 result[i * self.rank() + 1] = Zp.one();
767 self.ring_decompositions[i].coeff_basis_to_small_basis(&mut result[(i * self.rank())..((i + 1) * self.rank())]);
768 }
769 return self.do_fft(SmallBasisEl {
770 el_wrt_small_basis: result,
771 allocator: PhantomData,
772 number_ring: PhantomData
773 });
774 }
775
776 fn rank(&self) -> usize {
777 self.ring_decompositions[0].rank()
778 }
779
780 #[instrument(skip_all)]
781 fn wrt_canonical_basis<'a>(&'a self, el: &'a Self::Element) -> Self::VectorRepresentation<'a> {
782 self.wrt_canonical_basis_non_fft(self.undo_fft(self.clone_el(el)))
783 }
784
785 #[instrument(skip_all)]
786 fn from_canonical_basis<V>(&self, vec: V) -> Self::Element
787 where V: IntoIterator<Item = El<Self::BaseRing>>
788 {
789 return self.do_fft(self.from_canonical_basis_non_fft(vec));
790 }
791}
792
793impl<NumberRing, A> RingExtension for DoubleRNSRingBase<NumberRing, A>
794 where NumberRing: HENumberRing,
795 A: Allocator + Clone
796{
797 type BaseRing = zn_rns::Zn<Zn, BigIntRing>;
798
799 fn base_ring<'a>(&'a self) -> &'a Self::BaseRing {
800 self.rns_base()
801 }
802
803 fn from(&self, x: El<Self::BaseRing>) -> Self::Element {
804 self.from_ref(&x)
805 }
806
807 #[instrument(skip_all)]
808 fn from_ref(&self, x: &El<Self::BaseRing>) -> Self::Element {
809 let x_congruence = self.rns_base().get_congruence(x);
810 let mut result = Vec::with_capacity_in(self.element_len(), self.allocator.clone());
811 for (i, Zp) in self.rns_base().as_iter().enumerate() {
814 for _ in 0..self.rank() {
815 result.push(Zp.clone_el(x_congruence.at(i)));
816 }
817 }
818 return DoubleRNSEl {
819 el_wrt_mult_basis: result,
820 number_ring: PhantomData,
821 allocator: PhantomData
822 };
823 }
824
825 #[instrument(skip_all)]
826 fn mul_assign_base(&self, lhs: &mut Self::Element, rhs: &El<Self::BaseRing>) {
827 let x_congruence = self.rns_base().get_congruence(rhs);
828 for (i, Zp) in self.rns_base().as_iter().enumerate() {
829 for j in 0..self.rank() {
830 Zp.mul_assign_ref(&mut lhs.el_wrt_mult_basis[i * self.rank() + j], x_congruence.at(i));
831 }
832 }
833 }
834}
835
836impl<NumberRing, A> PreparedMultiplicationRing for DoubleRNSRingBase<NumberRing, A>
837 where NumberRing: HENumberRing,
838 A: Allocator + Clone
839{
840 type PreparedMultiplicant = Self::Element;
841
842 fn prepare_multiplicant(&self, x: &Self::Element) -> Self::PreparedMultiplicant {
843 self.clone_el(x)
844 }
845
846 fn mul_prepared(&self, lhs: &Self::PreparedMultiplicant, rhs: &Self::PreparedMultiplicant) -> Self::Element {
847 self.mul_ref(lhs, rhs)
848 }
849}
850
851pub struct WRTCanonicalBasisElementCreator<'a, NumberRing, A>
852 where NumberRing: HENumberRing,
853 A: Allocator + Clone
854{
855 ring: &'a DoubleRNSRingBase<NumberRing, A>
856}
857
858impl<'a, 'b, NumberRing, A> Clone for WRTCanonicalBasisElementCreator<'a, NumberRing, A>
859 where NumberRing: HENumberRing,
860 A: Allocator + Clone
861{
862 fn clone(&self) -> Self {
863 Self { ring: self.ring }
864 }
865}
866
867impl<'a, 'b, NumberRing, A> Fn<(&'b [El<zn_rns::Zn<Zn, BigIntRing>>],)> for WRTCanonicalBasisElementCreator<'a, NumberRing, A>
868 where NumberRing: HENumberRing,
869 A: Allocator + Clone
870{
871 extern "rust-call" fn call(&self, args: (&'b [El<zn_rns::Zn<Zn, BigIntRing>>],)) -> Self::Output {
872 self.ring.from_canonical_basis(args.0.iter().map(|x| self.ring.base_ring().clone_el(x)))
873 }
874}
875
876impl<'a, 'b, NumberRing, A> FnMut<(&'b [El<zn_rns::Zn<Zn, BigIntRing>>],)> for WRTCanonicalBasisElementCreator<'a, NumberRing, A>
877 where NumberRing: HENumberRing,
878 A: Allocator + Clone
879{
880 extern "rust-call" fn call_mut(&mut self, args: (&'b [El<zn_rns::Zn<Zn, BigIntRing>>],)) -> Self::Output {
881 self.call(args)
882 }
883}
884
885impl<'a, 'b, NumberRing, A> FnOnce<(&'b [El<zn_rns::Zn<Zn, BigIntRing>>],)> for WRTCanonicalBasisElementCreator<'a, NumberRing, A>
886 where NumberRing: HENumberRing,
887 A: Allocator + Clone
888{
889 type Output = El<DoubleRNSRing<NumberRing, A>>;
890
891 extern "rust-call" fn call_once(self, args: (&'b [El<zn_rns::Zn<Zn, BigIntRing>>],)) -> Self::Output {
892 self.call(args)
893 }
894}
895
896impl<NumberRing, A> FiniteRingSpecializable for DoubleRNSRingBase<NumberRing, A>
897 where NumberRing: HENumberRing,
898 A: Allocator + Clone
899{
900 fn specialize<O: FiniteRingOperation<Self>>(op: O) -> Result<O::Output, ()> {
901 Ok(op.execute())
902 }
903}
904
905impl<NumberRing, A> FiniteRing for DoubleRNSRingBase<NumberRing, A>
906 where NumberRing: HENumberRing,
907 A: Allocator + Clone
908{
909 type ElementsIter<'a> = MultiProduct<
910 <zn_rns::ZnBase<Zn, BigIntRing> as FiniteRing>::ElementsIter<'a>,
911 WRTCanonicalBasisElementCreator<'a, NumberRing, A>,
912 CloneRingEl<&'a zn_rns::Zn<Zn, BigIntRing>>,
913 El<DoubleRNSRing<NumberRing, A>>
914 > where Self: 'a;
915
916 fn elements<'a>(&'a self) -> Self::ElementsIter<'a> {
917 multi_cartesian_product((0..self.rank()).map(|_| self.base_ring().elements()), WRTCanonicalBasisElementCreator { ring: self }, CloneRingEl(self.base_ring()))
918 }
919
920 fn size<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
921 where I::Type: IntegerRing
922 {
923 let modulus = self.base_ring().size(ZZ)?;
924 if ZZ.get_ring().representable_bits().is_none() || ZZ.get_ring().representable_bits().unwrap() >= self.rank() * ZZ.abs_log2_ceil(&modulus).unwrap() {
925 Some(ZZ.pow(modulus, self.rank()))
926 } else {
927 None
928 }
929 }
930
931 fn random_element<G: FnMut() -> u64>(&self, mut rng: G) -> <Self as RingBase>::Element {
932 let mut result = self.zero();
933 for j in 0..self.rank() {
934 for i in 0..self.rns_base().len() {
935 result.el_wrt_mult_basis[j + i * self.rank()] = self.rns_base().at(i).random_element(&mut rng);
936 }
937 }
938 return result;
939 }
940}
941
942pub struct SerializableSmallBasisElWithRing<'a, NumberRing, A>
943 where NumberRing: HENumberRing,
944 A: Allocator + Clone
945{
946 ring: &'a DoubleRNSRingBase<NumberRing, A>,
947 el: &'a SmallBasisEl<NumberRing, A>
948}
949
950impl<'a, NumberRing, A> SerializableSmallBasisElWithRing<'a, NumberRing, A>
951 where NumberRing: HENumberRing,
952 A: Allocator + Clone
953{
954 pub fn new(ring: &'a DoubleRNSRingBase<NumberRing, A>, el: &'a SmallBasisEl<NumberRing, A>) -> Self {
955 Self { ring, el }
956 }
957}
958
959impl<'a, NumberRing, A> serde::Serialize for SerializableSmallBasisElWithRing<'a, NumberRing, A>
960 where NumberRing: HENumberRing,
961 A: Allocator + Clone
962{
963 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
964 where S: serde::Serializer
965 {
966 if serializer.is_human_readable() {
967 SerializableNewtype::new("RingEl", SerializableSeq::new(self.ring.wrt_canonical_basis_non_fft(self.ring.clone_el_non_fft(self.el)).map_fn(|c| SerializeOwnedWithRing::new(c, self.ring.base_ring())))).serialize(serializer)
968 } else {
969 SerializableNewtype::new("SmallBasisEl", &serialize_rns_data(self.ring.base_ring(), self.ring.as_matrix_wrt_small_basis(self.el))).serialize(serializer)
970 }
971 }
972}
973pub struct DeserializeSeedSmallBasisElWithRing<'a, NumberRing, A>
974 where NumberRing: HENumberRing,
975 A: Allocator + Clone
976{
977 ring: &'a DoubleRNSRingBase<NumberRing, A>,
978}
979
980impl<'a, 'de, NumberRing, A> DeserializeSeedSmallBasisElWithRing<'a, NumberRing, A>
981 where NumberRing: HENumberRing,
982 A: Allocator + Clone
983{
984 pub fn new(ring: &'a DoubleRNSRingBase<NumberRing, A>) -> Self {
985 Self { ring }
986 }
987}
988
989impl<'a, 'de, NumberRing, A> serde::de::DeserializeSeed<'de> for DeserializeSeedSmallBasisElWithRing<'a, NumberRing, A>
990 where NumberRing: HENumberRing,
991 A: Allocator + Clone
992{
993 type Value = SmallBasisEl<NumberRing, A>;
994
995 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
996 where D: Deserializer<'de>
997 {
998 if deserializer.is_human_readable() {
999 let data = DeserializeSeedNewtype::new("RingEl", DeserializeSeedSeq::new(
1000 (0..self.ring.rank()).map(|_| DeserializeWithRing::new(self.ring.base_ring())),
1001 Vec::with_capacity_in(self.ring.rank(), &self.ring.allocator),
1002 |mut current, next| { current.push(next); current }
1003 )).deserialize(deserializer)?;
1004 if data.len() != self.ring.rank() {
1005 return Err(serde::de::Error::invalid_length(data.len(), &format!("expected a sequence of {} elements of Z/qZ", self.ring.rank()).as_str()));
1006 }
1007 return Ok(self.ring.from_canonical_basis_non_fft(data.into_iter()));
1008 } else {
1009 let mut result = self.ring.zero_non_fft();
1010 DeserializeSeedNewtype::new("SmallBasisEl", deserialize_rns_data(self.ring.base_ring(), self.ring.as_matrix_wrt_small_basis_mut(&mut result))).deserialize(deserializer)?;
1011 return Ok(result);
1012 }
1013 }
1014}
1015
1016impl<NumberRing, A> SerializableElementRing for DoubleRNSRingBase<NumberRing, A>
1017 where NumberRing: HENumberRing,
1018 A: Allocator + Clone
1019{
1020 fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
1021 where S: serde::Serializer
1022 {
1023 if serializer.is_human_readable() {
1024 SerializableNewtype::new("RingEl", &SerializableSmallBasisElWithRing::new(self, &self.undo_fft(self.clone_el(el)))).serialize(serializer)
1025 } else {
1026 SerializableNewtype::new("DoubleRNSEl", &serialize_rns_data(self.base_ring(), self.as_matrix_wrt_mult_basis(el))).serialize(serializer)
1027 }
1028 }
1029
1030 fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
1031 where D: serde::Deserializer<'de>
1032 {
1033 if deserializer.is_human_readable() {
1034 DeserializeSeedNewtype::new("RingEl", DeserializeSeedSmallBasisElWithRing::new(self)).deserialize(deserializer).map(|x| self.do_fft(x))
1035 } else {
1036 let mut result = self.zero();
1037 DeserializeSeedNewtype::new("DoubleRNSEl", deserialize_rns_data(self.base_ring(), self.as_matrix_wrt_mult_basis_mut(&mut result))).deserialize(deserializer)?;
1038 return Ok(result);
1039 }
1040 }
1041}
1042
1043impl<NumberRing, A1, A2> CanHomFrom<DoubleRNSRingBase<NumberRing, A2>> for DoubleRNSRingBase<NumberRing, A1>
1044 where NumberRing: HENumberRing,
1045 A1: Allocator + Clone,
1046 A2: Allocator + Clone,
1047{
1048 type Homomorphism = Vec<<ZnBase as CanHomFrom<ZnBase>>::Homomorphism>;
1049
1050 fn has_canonical_hom(&self, from: &DoubleRNSRingBase<NumberRing, A2>) -> Option<Self::Homomorphism> {
1051 if self.rns_base().len() == from.rns_base().len() && self.number_ring() == from.number_ring() {
1052 (0..self.rns_base().len()).map(|i| self.rns_base().at(i).get_ring().has_canonical_hom(from.rns_base().at(i).get_ring()).ok_or(())).collect::<Result<Vec<_>, ()>>().ok()
1053 } else {
1054 None
1055 }
1056 }
1057
1058 fn map_in(&self, from: &DoubleRNSRingBase<NumberRing, A2>, el: <DoubleRNSRingBase<NumberRing, A2> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
1059 self.map_in_ref(from, &el, hom)
1060 }
1061
1062 fn map_in_ref(&self, from: &DoubleRNSRingBase<NumberRing, A2>, el: &<DoubleRNSRingBase<NumberRing, A2> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
1063 let mut result = Vec::with_capacity_in(self.element_len(), self.allocator.clone());
1064 for (i, Zp) in self.rns_base().as_iter().enumerate() {
1065 for j in 0..self.rank() {
1066 result.push(Zp.get_ring().map_in_ref(from.rns_base().at(i).get_ring(), &el.el_wrt_mult_basis[i * self.rank() + j], &hom[i]));
1067 }
1068 }
1069 DoubleRNSEl {
1070 el_wrt_mult_basis: result,
1071 number_ring: PhantomData,
1072 allocator: PhantomData
1073 }
1074 }
1075}
1076
1077impl<NumberRing, A1, A2, C2> CanHomFrom<SingleRNSRingBase<NumberRing, A2, C2>> for DoubleRNSRingBase<NumberRing, A1>
1078 where NumberRing: HECyclotomicNumberRing,
1079 A1: Allocator + Clone,
1080 A2: Allocator + Clone,
1081 C2: PreparedConvolutionAlgorithm<ZnBase>
1082{
1083 type Homomorphism = Vec<<ZnBase as CanHomFrom<ZnBase>>::Homomorphism>;
1084
1085 fn has_canonical_hom(&self, from: &SingleRNSRingBase<NumberRing, A2, C2>) -> Option<Self::Homomorphism> {
1086 if self.rns_base().len() == from.rns_base().len() && self.number_ring() == from.number_ring() {
1087 (0..self.rns_base().len()).map(|i| self.rns_base().at(i).get_ring().has_canonical_hom(from.rns_base().at(i).get_ring()).ok_or(())).collect::<Result<Vec<_>, ()>>().ok()
1088 } else {
1089 None
1090 }
1091 }
1092
1093 fn map_in(&self, from: &SingleRNSRingBase<NumberRing, A2, C2>, el: <SingleRNSRingBase<NumberRing, A2, C2> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
1094 self.do_fft(self.map_in_from_singlerns(from, el, hom))
1095 }
1096}
1097
1098impl<NumberRing, A1, A2, C2> CanIsoFromTo<SingleRNSRingBase<NumberRing, A2, C2>> for DoubleRNSRingBase<NumberRing, A1>
1099 where NumberRing: HECyclotomicNumberRing,
1100 A1: Allocator + Clone,
1101 A2: Allocator + Clone,
1102 C2: PreparedConvolutionAlgorithm<ZnBase>
1103{
1104 type Isomorphism = Vec<<ZnBase as CanIsoFromTo<ZnBase>>::Isomorphism>;
1105
1106 fn has_canonical_iso(&self, from: &SingleRNSRingBase<NumberRing, A2, C2>) -> Option<Self::Isomorphism> {
1107 if self.rns_base().len() == from.rns_base().len() && self.number_ring() == from.number_ring() {
1108 (0..self.rns_base().len()).map(|i| self.rns_base().at(i).get_ring().has_canonical_iso(from.rns_base().at(i).get_ring()).ok_or(())).collect::<Result<Vec<_>, ()>>().ok()
1109 } else {
1110 None
1111 }
1112 }
1113
1114 fn map_out(&self, from: &SingleRNSRingBase<NumberRing, A2, C2>, el: <Self as RingBase>::Element, iso: &Self::Isomorphism) -> <SingleRNSRingBase<NumberRing, A2, C2> as RingBase>::Element {
1115 self.map_out_to_singlerns(from, self.undo_fft(el), iso)
1116 }
1117}
1118
1119impl<NumberRing, A1, A2> CanIsoFromTo<DoubleRNSRingBase<NumberRing, A2>> for DoubleRNSRingBase<NumberRing, A1>
1120 where NumberRing: HENumberRing,
1121 A1: Allocator + Clone,
1122 A2: Allocator + Clone,
1123{
1124 type Isomorphism = Vec<<ZnBase as CanIsoFromTo<ZnBase>>::Isomorphism>;
1125
1126 fn has_canonical_iso(&self, from: &DoubleRNSRingBase<NumberRing, A2>) -> Option<Self::Isomorphism> {
1127 if self.rns_base().len() == from.rns_base().len() && self.number_ring() == from.number_ring() {
1128 (0..self.rns_base().len()).map(|i| self.rns_base().at(i).get_ring().has_canonical_iso(from.rns_base().at(i).get_ring()).ok_or(())).collect::<Result<Vec<_>, ()>>().ok()
1129 } else {
1130 None
1131 }
1132 }
1133
1134 fn map_out(&self, from: &DoubleRNSRingBase<NumberRing, A2>, el: Self::Element, iso: &Self::Isomorphism) -> <DoubleRNSRingBase<NumberRing, A2> as RingBase>::Element {
1135 let mut result = Vec::with_capacity_in(from.element_len(), from.allocator.clone());
1136 for (i, Zp) in self.rns_base().as_iter().enumerate() {
1137 for j in 0..self.rank() {
1138 result.push(Zp.get_ring().map_out(from.rns_base().at(i).get_ring(), Zp.clone_el(&el.el_wrt_mult_basis[i * self.rank() + j]), &iso[i]));
1139 }
1140 }
1141 DoubleRNSEl {
1142 el_wrt_mult_basis: result,
1143 number_ring: PhantomData,
1144 allocator: PhantomData
1145 }
1146 }
1147}
1148
1149#[cfg(any(test, feature = "generic_tests"))]
1150pub fn test_with_number_ring<NumberRing: Clone + HECyclotomicNumberRing>(number_ring: NumberRing) {
1151 use feanor_math::algorithms::eea::signed_lcm;
1152 use feanor_math::assert_el_eq;
1153 use feanor_math::primitive_int::*;
1154
1155 use crate::ntt::ntt_convolution::NTTConv;
1156
1157 let required_root_of_unity = signed_lcm(
1158 number_ring.mod_p_required_root_of_unity() as i64,
1159 1 << StaticRing::<i64>::RING.abs_log2_ceil(&(number_ring.n() as i64)).unwrap() + 2,
1160 StaticRing::<i64>::RING
1161 );
1162 let p1 = largest_prime_leq_congruent_to_one(20000, required_root_of_unity).unwrap();
1163 let p2 = largest_prime_leq_congruent_to_one(p1 - 1, required_root_of_unity).unwrap();
1164 assert!(p1 != p2);
1165 let rank = number_ring.rank();
1166 let base_ring = zn_rns::Zn::new(vec![Zn::new(p1 as u64), Zn::new(p2 as u64)], BigIntRing::RING);
1167 let ring = DoubleRNSRingBase::new(number_ring.clone(), base_ring.clone());
1168
1169 let base_ring = ring.base_ring();
1170 let elements = vec![
1171 ring.zero(),
1172 ring.one(),
1173 ring.neg_one(),
1174 ring.int_hom().map(p1 as i32),
1175 ring.int_hom().map(p2 as i32),
1176 ring.canonical_gen(),
1177 ring.pow(ring.canonical_gen(), rank - 1),
1178 ring.int_hom().mul_map(ring.canonical_gen(), p1 as i32),
1179 ring.int_hom().mul_map(ring.pow(ring.canonical_gen(), rank - 1), p1 as i32),
1180 ring.add(ring.canonical_gen(), ring.one())
1181 ];
1182
1183 feanor_math::ring::generic_tests::test_ring_axioms(&ring, elements.iter().map(|x| ring.clone_el(x)));
1184 feanor_math::ring::generic_tests::test_self_iso(&ring, elements.iter().map(|x| ring.clone_el(x)));
1185 feanor_math::rings::extension::generic_tests::test_free_algebra_axioms(&ring);
1186
1187 let single_rns_ring = SingleRNSRingBase::<_, _, NTTConv<_>>::new(number_ring.clone(), base_ring.clone());
1188 feanor_math::ring::generic_tests::test_hom_axioms(&ring, &single_rns_ring, elements.iter().map(|x| ring.clone_el(x)));
1189
1190 let dropped_rns_factor_ring = DoubleRNSRingBase::new(number_ring.clone(), zn_rns::Zn::new(vec![Zn::new(p2 as u64)], BigIntRing::RING));
1191
1192 for a in &elements {
1193 assert_el_eq!(
1194 &dropped_rns_factor_ring,
1195 dropped_rns_factor_ring.from_canonical_basis(ring.wrt_canonical_basis(a).iter().map(|c| dropped_rns_factor_ring.base_ring().from_congruence([*ring.base_ring().get_congruence(&c).at(1)].into_iter()))),
1196 dropped_rns_factor_ring.get_ring().drop_rns_factor_element(ring.get_ring(), &[0], a)
1197 );
1198 }
1199
1200 feanor_math::serialization::generic_tests::test_serialization(&ring, elements.iter().map(|x| ring.clone_el(x)));
1201}