he_ring/ciphertext_ring/
double_rns_ring.rs

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
37///
38/// Implementation of the ring `Z[𝝵_n]/(q)`, where `q = p1 ... pr` is a product of "RNS factors".
39/// Elements are (by default) stored in double-RNS-representation for efficient arithmetic.
40/// 
41/// As opposed to [`SingleRNSRing`], this means multiplications are very cheap, but non-arithmetic
42/// operations like [`FreeAlgebra::from_canonical_basis()`] and [`FreeAlgebra::wrt_canonical_basis()`] 
43/// are expensive, and in some cases only supported for elements that have explicitly been converted 
44/// to [`SmallBasisEl`] via [`DoubleRNSRingBase::undo_fft()`]. This conversion is expensive in terms of
45/// performance.
46/// 
47/// # Mathematical details
48/// 
49/// The "double-RNS representation" refers to the representation of an element via its value modulo
50/// each prime ideal of `Z[𝝵_n]/(q)`. Since we require each `Z/(pi)` to have a primitive `n`-th root
51/// of unity `z`, these prime ideals are of the form `(pi, 𝝵_n - z^j)` with `j in (Z/nZ)*`.
52/// In other words, the double-RNS representation refers to the evaluation of an element (considered
53/// as polyomial in `𝝵_n`) at all primitive `n`-th roots of unity, modulo each `pi`.
54/// This is also the multiplicative basis, as specified by [`HENumberRingMod`].
55/// In particular, multiplication of elements refers to component-wise multiplication of these vectors.
56/// 
57pub struct DoubleRNSRingBase<NumberRing, A = Global> 
58    where NumberRing: HENumberRing,
59        A: Allocator + Clone
60{
61    /// The number ring whose quotient we represent
62    number_ring: NumberRing,
63    /// The number ring modulo each RNS factor `pi`, use for conversion between small and multiplicative basis
64    ring_decompositions: Vec<Arc<<NumberRing as HENumberRing>::Decomposed>>,
65    /// The current RNS base
66    rns_base: zn_rns::Zn<Zn, BigIntRing>,
67    /// Use to allocate memory for ring elements
68    allocator: A
69}
70
71///
72/// [`RingStore`] for [`DoubleRNSRingBase`].
73/// 
74pub type DoubleRNSRing<NumberRing, A = Global> = RingValue<DoubleRNSRingBase<NumberRing, A>>;
75
76///
77/// A [`DoubleRNSRing`] element, stored by its coefficients w.r.t. the multiplicative basis.
78/// In particular, this is the only representation that allows for multiplications.
79/// 
80pub 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
89///
90/// A [`DoubleRNSRing`] element, stored by its coefficients w.r.t. the "small basis".
91/// 
92pub 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    ///
105    /// Creates a new [`DoubleRNSRing`].
106    /// 
107    /// Each RNS factor `Z/(pi)` in `rns_base` must have suitable roots of unity,
108    /// as specified by [`HENumberRing::mod_p_required_root_of_unity()`].
109    /// 
110    #[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    ///
150    /// Creates a new [`DoubleRNSRing`].
151    /// 
152    /// Each RNS factor `Z/(pi)` in `rns_base` must have suitable roots of unity,
153    /// as specified by [`HENumberRing::mod_p_required_root_of_unity()`].
154    /// 
155    #[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    ///
199    /// Converts the element to its representation w.r.t. the small basis.
200    /// 
201    /// The coefficients w.r.t. this basis can be accessed using [`DoubleRNSRingBase::as_matrix_wrt_small_basis()`].
202    /// 
203    #[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    ///
263    /// Converts the element to its representation w.r.t. the multiplicative basis.
264    /// 
265    /// The main use of this basis is to compute multiplications (via [`RingBase::mul()`] etc.).
266    /// You can also access the coefficients w.r.t. the multiplicative basis using [`DoubleRNSRingBase::as_matrix_wrt_mult_basis()`].
267    /// 
268    #[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        // this works, since the mult basis is, by definition, given by an isomorphism `R/p -> Fp^n`, so
812        // in particular `Fp` mapsto to the diagonal `(x, ..., x) <= Fp^n`
813        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}