he_ring/ciphertext_ring/
double_rns_managed.rs

1use std::alloc::{Allocator, Global};
2use std::sync::*;
3
4use feanor_math::algorithms::convolution::*;
5use feanor_math::algorithms::matmul::ComputeInnerProduct;
6use feanor_math::homomorphism::*;
7use feanor_math::integer::*;
8use feanor_math::matrix::*;
9use feanor_math::ring::*;
10use feanor_math::rings::extension::*;
11use feanor_math::rings::finite::FiniteRing;
12use feanor_math::rings::zn::*;
13use feanor_math::seq::VectorView;
14use feanor_math::serialization::{DeserializeSeedNewtype, DeserializeWithRing, SerializableElementRing, SerializableNewtype, SerializeWithRing};
15use feanor_math::specialization::{FiniteRingOperation, FiniteRingSpecializable};
16use serde::{Deserialize, Serialize};
17use serde::de::DeserializeSeed;
18use tracing::instrument;
19
20use crate::cyclotomic::CyclotomicGaloisGroupEl;
21use crate::cyclotomic::CyclotomicRing;
22use crate::number_ring::HECyclotomicNumberRing;
23use crate::number_ring::HENumberRing;
24
25use super::double_rns_ring::*;
26use super::single_rns_ring::*;
27use super::BGFVCiphertextRing;
28use super::PreparedMultiplicationRing;
29
30///
31/// Like [`DoubleRNSRing`] but stores element in whatever representation they
32/// currently are available, and automatically switches representation when 
33/// necessary.
34/// 
35/// # Implementation notes
36/// 
37/// Elements can be stored both as [`DoubleRNSEl`] and [`SmallBasisEl`].
38/// Note that this includes the option of storing the element in both representations
39/// simultaneously. When a multiplication is performed, elements are automatically converted
40/// to [`DoubleRNSEl`] representation. When a small-basis representation is required (e.g. via 
41/// [`BGFVCiphertextRing::as_representation_wrt_small_generating_set()`]), the element is
42/// automatically converted to [`SmallBasisEl`] representation. These conversions can also be
43/// manually triggered using [`ManagedDoubleRNSRingBase::to_small_basis()`] and
44/// [`ManagedDoubleRNSRingBase::to_doublerns()`].
45/// 
46/// Internally, elements are stored using [`Arc`] pointers, and the pointees are logically
47/// immutable, which leads to maximal reuse of representations. For example, the following
48/// code only requires a single representation conversion:
49/// ```
50/// # use he_ring::ciphertext_ring::double_rns_managed::*;
51/// # use he_ring::ciphertext_ring::*;
52/// # use he_ring::number_ring::*;
53/// # use he_ring::number_ring::pow2_cyclotomic::*;
54/// # use feanor_math::assert_el_eq;
55/// # use feanor_math::rings::zn::*;
56/// # use feanor_math::rings::extension::FreeAlgebraStore;
57/// # use feanor_math::rings::zn::zn_64::*;
58/// # use feanor_math::homomorphism::*;
59/// # use feanor_math::ring::*;
60/// # use feanor_math::integer::*;
61/// # use feanor_math::seq::VectorFn;
62/// let rns_base = zn_rns::Zn::new(vec![Zn::new(97), Zn::new(193)], BigIntRing::RING);
63/// let ring = ManagedDoubleRNSRingBase::new(Pow2CyclotomicNumberRing::new(16), rns_base);
64/// // `element` is stored in small-basis representation
65/// let element = ring.get_ring().from_small_basis_repr(ring.get_ring().unmanaged_ring().get_ring().from_non_fft(ring.base_ring().int_hom().map(2)));
66/// // this will point to the same payload as `element`
67/// let mut element_copy = ring.clone_el(&element);
68/// // this will convert `element` to double-rns representation; it is now stored once w.r.t. small-basis
69/// // and once w.r.t. double-rns representation
70/// ring.square(&mut element_copy);
71/// // `element_copy` is of course only available in double-rns representation here, but `element` is available in
72/// // both double-rns and small-basis representation; hence, the next statement does not require a conversion
73/// let result = ring.pow(ring.clone_el(&element), 2);
74/// assert_el_eq!(ring, element_copy, result);
75/// // similarly, we don't need a conversion for `wrt_canonical_basis()`, since `element` is available in small-basis representation
76/// assert_el_eq!(ring.base_ring(), ring.base_ring().int_hom().map(2), ring.wrt_canonical_basis(&element).at(0));
77/// ```
78/// 
79pub struct ManagedDoubleRNSRingBase<NumberRing, A = Global> 
80    where NumberRing: HENumberRing,
81        A: Allocator + Clone
82{
83    base: DoubleRNSRingBase<NumberRing, A>,
84    zero: SmallBasisEl<NumberRing, A>
85}
86
87pub type ManagedDoubleRNSRing<NumberRing, A = Global> = RingValue<ManagedDoubleRNSRingBase<NumberRing, A>>;
88
89impl<NumberRing> ManagedDoubleRNSRingBase<NumberRing, Global> 
90    where NumberRing: HENumberRing,
91{
92    pub fn new(number_ring: NumberRing, rns_base: zn_rns::Zn<zn_64::Zn, BigIntRing>) -> RingValue<Self> {
93        Self::new_with(number_ring, rns_base, Global)
94    }
95}
96
97enum ManagedDoubleRNSElRepresentation<'a, NumberRing, A>
98    where NumberRing: HENumberRing,
99        A: Allocator + Clone
100{
101    Sum(MappedRwLockReadGuard<'a, (SmallBasisEl<NumberRing, A>, DoubleRNSEl<NumberRing, A>)>),
102    SmallBasis(&'a SmallBasisEl<NumberRing, A>),
103    DoubleRNS(&'a DoubleRNSEl<NumberRing, A>),
104    Both(&'a SmallBasisEl<NumberRing, A>, &'a DoubleRNSEl<NumberRing, A>),
105    Zero
106}
107
108struct DoubleRNSElInternal<NumberRing, A = Global> 
109    where NumberRing: HENumberRing,
110        A: Allocator + Clone
111{
112    small_basis_repr: OnceLock<SmallBasisEl<NumberRing, A>>,
113    double_rns_repr: OnceLock<DoubleRNSEl<NumberRing, A>>,
114    sum_repr: RwLock<Option<(SmallBasisEl<NumberRing, A>, DoubleRNSEl<NumberRing, A>)>>
115}
116
117impl<NumberRing, A> DoubleRNSElInternal<NumberRing, A> 
118    where NumberRing: HENumberRing,
119        A: Allocator + Clone
120{
121    fn get_repr<'a>(&'a self) -> ManagedDoubleRNSElRepresentation<'a, NumberRing, A> {
122        let sum_repr = self.sum_repr.read().unwrap();
123        if sum_repr.is_some() {
124            return ManagedDoubleRNSElRepresentation::Sum(RwLockReadGuard::map(sum_repr, |sum_repr: &Option<_>| sum_repr.as_ref().unwrap()));
125        }
126        // we can unlock `sum_repr` here, since if `sum_repr` was empty previously, it will always remain empty
127        drop(sum_repr);
128        if let Some(small_basis_repr) = self.small_basis_repr.get() {
129            if let Some(double_rns_repr) = self.double_rns_repr.get() {
130                return ManagedDoubleRNSElRepresentation::Both(small_basis_repr, double_rns_repr);
131            } else {
132                return ManagedDoubleRNSElRepresentation::SmallBasis(small_basis_repr);
133            }
134        } else if let Some(double_rns_repr) = self.double_rns_repr.get() {
135            return ManagedDoubleRNSElRepresentation::DoubleRNS(double_rns_repr);
136        } else {
137            return ManagedDoubleRNSElRepresentation::Zero;
138        }
139    }
140}
141
142pub struct ManagedDoubleRNSEl<NumberRing, A = Global> 
143    where NumberRing: HENumberRing,
144        A: Allocator + Clone
145{
146    internal: Arc<DoubleRNSElInternal<NumberRing, A>>
147}
148
149impl<NumberRing, A> Clone for ManagedDoubleRNSRingBase<NumberRing, A>
150    where NumberRing: HENumberRing + Clone,
151        A: Allocator + Clone
152{
153    fn clone(&self) -> Self {
154        Self {
155            base: self.base.clone(),
156            zero: self.base.zero_non_fft()
157        }
158    }
159}
160
161impl<NumberRing, A> ManagedDoubleRNSRingBase<NumberRing, A>
162    where NumberRing: HENumberRing,
163        A: Allocator + Clone
164{
165    pub fn new_with(number_ring: NumberRing, rns_base: zn_rns::Zn<zn_64::Zn, BigIntRing>, allocator: A) -> RingValue<ManagedDoubleRNSRingBase<NumberRing, A>> {
166        let result = DoubleRNSRingBase::new_with(number_ring, rns_base, allocator);
167        let zero = result.get_ring().zero_non_fft();
168        ManagedDoubleRNSRing::from(ManagedDoubleRNSRingBase { base: result.into(), zero: zero })
169    }
170
171    ///
172    /// Returns a reference to the underlying [`DoubleRNSRing`], which can be used
173    /// to manually manage the representation of elements.
174    /// 
175    /// This is most useful in combination with [`ManagedDoubleRNSRingBase::to_small_basis()`] and
176    /// [`ManagedDoubleRNSRingBase::to_doublerns()`], which can be used to access the underlying
177    /// representation of elements.
178    /// 
179    pub fn unmanaged_ring(&self) -> RingRef<DoubleRNSRingBase<NumberRing, A>> {
180        RingRef::new(&self.base)
181    }
182
183    ///
184    /// Returns the representation of the given element w.r.t. the small basis, possibly computing
185    /// this representation if it is not available. If the element is zero, `None` is returned.
186    /// 
187    pub fn to_small_basis<'a>(&self, value: &'a ManagedDoubleRNSEl<NumberRing, A>) -> Option<&'a SmallBasisEl<NumberRing, A>> {
188        match value.internal.get_repr() {
189            ManagedDoubleRNSElRepresentation::Sum(sum_repr) => {
190                drop(sum_repr);
191                let mut sum_repr_lock = value.internal.sum_repr.write().unwrap();
192                // if some other thread already cleared `sum_repr` between unlocking and relocking
193                if sum_repr_lock.is_none() {
194                    drop(sum_repr_lock);
195                    return self.to_small_basis(value);
196                }
197                let sum_repr = std::mem::replace(&mut *sum_repr_lock, None).unwrap();
198                let mut result = sum_repr.0;
199                self.base.add_assign_non_fft(&mut result, &self.base.undo_fft(sum_repr.1));
200                // no other thread is able to update this, since the previous call to `get_repr()` would alway return `Sum` (or run
201                // after we unlocked `sum_repr_lock`)
202                value.internal.small_basis_repr.set(result).ok().unwrap();
203                // keep the `sum_repr_lock` until we initialized `small_basis_repr`, otherwise threads querying this in the meantime
204                // might think the element stores zero
205                drop(sum_repr_lock);
206                return Some(value.internal.small_basis_repr.get().unwrap());
207            },
208            ManagedDoubleRNSElRepresentation::SmallBasis(small_basis_repr) | ManagedDoubleRNSElRepresentation::Both(small_basis_repr, _) => {
209                return Some(small_basis_repr);
210            },
211            ManagedDoubleRNSElRepresentation::DoubleRNS(double_rns_repr) => {
212                let result = self.base.undo_fft(self.base.clone_el(double_rns_repr));
213                // here another thread might have set `small_basis_repr` in the meantime, so this might return `Err(_)`
214                _ = value.internal.small_basis_repr.set(result);
215                return Some(value.internal.small_basis_repr.get().unwrap());
216            },
217            ManagedDoubleRNSElRepresentation::Zero => {
218                return None;
219            }
220        }
221    }
222
223    ///
224    /// Returns the representation of the given element w.r.t. the multiplicative basis, possibly computing
225    /// this representation if it is not available. If the element is zero, `None` is returned.
226    /// 
227    pub fn to_doublerns<'a>(&self, value: &'a ManagedDoubleRNSEl<NumberRing, A>) -> Option<&'a DoubleRNSEl<NumberRing, A>> {
228        match value.internal.get_repr() {
229            ManagedDoubleRNSElRepresentation::Sum(sum_repr) => {
230                drop(sum_repr);
231                let mut sum_repr_lock = value.internal.sum_repr.write().unwrap();
232                // if some other thread already cleared `sum_repr` between unlocking and relocking
233                if sum_repr_lock.is_none() {
234                    drop(sum_repr_lock);
235                    return self.to_doublerns(value);
236                }
237                let sum_repr = std::mem::replace(&mut *sum_repr_lock, None).unwrap();
238                let mut result = sum_repr.1;
239                self.base.add_assign(&mut result, self.base.do_fft(sum_repr.0));
240                // no other thread is able to update this, since the previous call to `get_repr()` would alway return `Sum` (or run
241                // after we unlocked `sum_repr_lock`)
242                value.internal.double_rns_repr.set(result).ok().unwrap();
243                // keep the `sum_repr_lock` until we initialized `small_basis_repr`, otherwise threads querying this in the meantime
244                // might think the element stores zero
245                drop(sum_repr_lock);
246                return Some(value.internal.double_rns_repr.get().unwrap());
247            },
248            ManagedDoubleRNSElRepresentation::DoubleRNS(double_rns_repr) | ManagedDoubleRNSElRepresentation::Both(_, double_rns_repr) => {
249                return Some(double_rns_repr);
250            },
251            ManagedDoubleRNSElRepresentation::SmallBasis(small_basis_repr) => {
252                let result = self.base.do_fft(self.base.clone_el_non_fft(small_basis_repr));
253                // here another thread might have set `double_rns_repr` in the meantime, so this might return `Err(_)`
254                _ = value.internal.double_rns_repr.set(result);
255                return Some(value.internal.double_rns_repr.get().unwrap());
256            },
257            ManagedDoubleRNSElRepresentation::Zero => {
258                return None;
259            }
260        }
261    }
262
263    fn new_element_sum(&self, small_basis_part: SmallBasisEl<NumberRing, A>, double_rns_part: DoubleRNSEl<NumberRing, A>) -> ManagedDoubleRNSEl<NumberRing, A> {
264        ManagedDoubleRNSEl {
265            internal: Arc::new(DoubleRNSElInternal {
266                small_basis_repr: OnceLock::new(),
267                double_rns_repr: OnceLock::new(),
268                sum_repr: RwLock::new(Some((small_basis_part, double_rns_part)))
269            })
270        }
271    }
272
273    pub fn from_small_basis_repr(&self, small_basis_repr: SmallBasisEl<NumberRing, A>) -> ManagedDoubleRNSEl<NumberRing, A> {
274        ManagedDoubleRNSEl {
275            internal: Arc::new(DoubleRNSElInternal {
276                small_basis_repr: {
277                    let result = OnceLock::new();
278                    result.set(small_basis_repr).ok().unwrap();
279                    result
280                },
281                double_rns_repr: OnceLock::new(),
282                sum_repr: RwLock::new(None)
283            })
284        }
285    }
286
287    pub fn from_double_rns_repr(&self, double_rns_repr: DoubleRNSEl<NumberRing, A>) -> ManagedDoubleRNSEl<NumberRing, A> {
288        ManagedDoubleRNSEl {
289            internal: Arc::new(DoubleRNSElInternal {
290                small_basis_repr: OnceLock::new(),
291                double_rns_repr: {
292                    let result = OnceLock::new();
293                    result.set(double_rns_repr).ok().unwrap();
294                    result
295                },
296                sum_repr: RwLock::new(None)
297            })
298        }
299    }
300
301    fn new_element_both(&self, small_basis_repr: SmallBasisEl<NumberRing, A>, double_rns_repr: DoubleRNSEl<NumberRing, A>) -> ManagedDoubleRNSEl<NumberRing, A> {
302        ManagedDoubleRNSEl {
303            internal: Arc::new(DoubleRNSElInternal {
304                small_basis_repr: {
305                    let result = OnceLock::new();
306                    result.set(small_basis_repr).ok().unwrap();
307                    result
308                },
309                double_rns_repr: {
310                    let result = OnceLock::new();
311                    result.set(double_rns_repr).ok().unwrap();
312                    result
313                },
314                sum_repr: RwLock::new(None)
315            })
316        }
317    }
318
319    fn apply_linear_operation<F_coeff_bin, F_doublerns_bin, F_coeff_un, F_doublerns_un>(
320        &self, 
321        lhs: &ManagedDoubleRNSEl<NumberRing, A>, 
322        rhs: &ManagedDoubleRNSEl<NumberRing, A>, 
323        f1: F_coeff_bin, 
324        f2: F_doublerns_bin, 
325        f3: F_coeff_un, 
326        f4: F_doublerns_un
327    ) -> ManagedDoubleRNSEl<NumberRing, A> 
328        where F_coeff_bin: FnOnce(&mut SmallBasisEl<NumberRing, A>, &SmallBasisEl<NumberRing, A>),
329            F_doublerns_bin: FnOnce(&mut DoubleRNSEl<NumberRing, A>, &DoubleRNSEl<NumberRing, A>),
330            F_coeff_un: FnOnce(&mut SmallBasisEl<NumberRing, A>),
331            F_doublerns_un: FnOnce(&mut DoubleRNSEl<NumberRing, A>),
332    {
333        match (lhs.internal.get_repr(), rhs.internal.get_repr()) {
334            (_, ManagedDoubleRNSElRepresentation::Zero) => self.clone_el(lhs),
335            (ManagedDoubleRNSElRepresentation::Zero, ManagedDoubleRNSElRepresentation::DoubleRNS(rhs_double_rns_repr)) => {
336                let mut result_fft = self.base.clone_el(rhs_double_rns_repr);
337                f4(&mut result_fft);
338                return self.from_double_rns_repr(result_fft);
339            },
340            (ManagedDoubleRNSElRepresentation::Zero, ManagedDoubleRNSElRepresentation::SmallBasis(rhs_small_basis_repr)) => {
341                let mut result_coeff = self.base.clone_el_non_fft(rhs_small_basis_repr);
342                f3(&mut result_coeff);
343                return self.from_small_basis_repr(result_coeff);
344            },
345            (ManagedDoubleRNSElRepresentation::Zero, ManagedDoubleRNSElRepresentation::Sum(rhs_sum_repr)) => {
346                let mut result_fft = self.base.clone_el(&rhs_sum_repr.1);
347                let mut result_coeff = self.base.clone_el_non_fft(&rhs_sum_repr.0);
348                f3(&mut result_coeff);
349                f4(&mut result_fft);
350                return self.new_element_sum(result_coeff, result_fft);
351            },
352            (ManagedDoubleRNSElRepresentation::Zero, ManagedDoubleRNSElRepresentation::Both(rhs_small_basis_repr, rhs_double_rns_repr)) => {
353                let mut result_fft = self.base.clone_el(rhs_double_rns_repr);
354                let mut result_coeff = self.base.clone_el_non_fft(rhs_small_basis_repr);
355                f3(&mut result_coeff);
356                f4(&mut result_fft);
357                return self.new_element_both(result_coeff, result_fft);
358            },
359            (ManagedDoubleRNSElRepresentation::Sum(lhs_sum_repr), ManagedDoubleRNSElRepresentation::Sum(rhs_sum_repr)) => {
360                let mut result_fft = self.base.clone_el(&lhs_sum_repr.1);
361                let mut result_coeff = self.base.clone_el_non_fft(&lhs_sum_repr.0);
362                f1(&mut result_coeff, &rhs_sum_repr.0);
363                f2(&mut result_fft, &rhs_sum_repr.1);
364                return self.new_element_sum(result_coeff, result_fft);
365            },
366            (ManagedDoubleRNSElRepresentation::Sum(lhs_sum_repr), ManagedDoubleRNSElRepresentation::SmallBasis(rhs_small_basis_repr)) => {
367                let mut result_coeff = self.base.clone_el_non_fft(&lhs_sum_repr.0);
368                let result_fft = self.base.clone_el(&lhs_sum_repr.1);
369                f1(&mut result_coeff, rhs_small_basis_repr);
370                return self.new_element_sum(result_coeff, result_fft);
371            },
372            (ManagedDoubleRNSElRepresentation::Sum(lhs_sum_repr), ManagedDoubleRNSElRepresentation::DoubleRNS(rhs_double_rns_repr)) => {
373                let result_coeff = self.base.clone_el_non_fft(&lhs_sum_repr.0);
374                let mut result_fft = self.base.clone_el(&lhs_sum_repr.1);
375                f2(&mut result_fft, rhs_double_rns_repr);
376                return self.new_element_sum(result_coeff, result_fft);
377            },
378            (ManagedDoubleRNSElRepresentation::Sum(lhs_sum_repr), ManagedDoubleRNSElRepresentation::Both(rhs_small_basis_repr, _)) => {
379                let mut result_coeff = self.base.clone_el_non_fft(&lhs_sum_repr.0);
380                let result_fft = self.base.clone_el(&lhs_sum_repr.1);
381                f1(&mut result_coeff, rhs_small_basis_repr);
382                return self.new_element_sum(result_coeff, result_fft);
383            },
384            (ManagedDoubleRNSElRepresentation::SmallBasis(lhs_small_basis_repr), ManagedDoubleRNSElRepresentation::Sum(rhs_sum_repr)) => {
385                let mut result_fft = self.base.clone_el(&rhs_sum_repr.1);
386                let mut result_coeff = self.base.clone_el_non_fft(lhs_small_basis_repr);
387                f1(&mut result_coeff, &rhs_sum_repr.0);
388                f4(&mut result_fft);
389                return self.new_element_sum(result_coeff, result_fft);
390            },
391            (ManagedDoubleRNSElRepresentation::SmallBasis(lhs_small_basis_repr), ManagedDoubleRNSElRepresentation::SmallBasis(rhs_small_basis_repr)) | 
392                (ManagedDoubleRNSElRepresentation::SmallBasis(lhs_small_basis_repr), ManagedDoubleRNSElRepresentation::Both(rhs_small_basis_repr, _)) | 
393                (ManagedDoubleRNSElRepresentation::Both(lhs_small_basis_repr, _), ManagedDoubleRNSElRepresentation::SmallBasis(rhs_small_basis_repr)) => 
394            {
395                let mut result_coeff = self.base.clone_el_non_fft(lhs_small_basis_repr);
396                f1(&mut result_coeff, rhs_small_basis_repr);
397                return self.from_small_basis_repr(result_coeff);
398            },
399            (ManagedDoubleRNSElRepresentation::SmallBasis(lhs_small_basis_repr), ManagedDoubleRNSElRepresentation::DoubleRNS(rhs_double_rns_repr)) => {
400                let result_coeff = self.base.clone_el_non_fft(lhs_small_basis_repr);
401                let mut result_fft = self.base.clone_el(rhs_double_rns_repr);
402                f4(&mut result_fft);
403                return self.new_element_sum(result_coeff, result_fft);
404            },
405            (ManagedDoubleRNSElRepresentation::DoubleRNS(lhs_double_rns_repr), ManagedDoubleRNSElRepresentation::Sum(rhs_sum_repr)) => {
406                let mut result_fft = self.base.clone_el(lhs_double_rns_repr);
407                let mut result_coeff = self.base.clone_el_non_fft(&rhs_sum_repr.0);
408                f2(&mut result_fft, &rhs_sum_repr.1);
409                f3(&mut result_coeff);
410                return self.new_element_sum(result_coeff, result_fft);
411            },
412            (ManagedDoubleRNSElRepresentation::DoubleRNS(lhs_double_rns_repr), ManagedDoubleRNSElRepresentation::SmallBasis(rhs_small_basis_repr)) => {
413                let mut result_coeff = self.base.clone_el_non_fft(rhs_small_basis_repr);
414                let result_fft = self.base.clone_el(lhs_double_rns_repr);
415                f3(&mut result_coeff);
416                return self.new_element_sum(result_coeff, result_fft);
417            },
418            (ManagedDoubleRNSElRepresentation::DoubleRNS(lhs_double_rns_repr), ManagedDoubleRNSElRepresentation::DoubleRNS(rhs_double_rns_repr)) | 
419                (ManagedDoubleRNSElRepresentation::DoubleRNS(lhs_double_rns_repr), ManagedDoubleRNSElRepresentation::Both(_, rhs_double_rns_repr)) | 
420                (ManagedDoubleRNSElRepresentation::Both(_, lhs_double_rns_repr), ManagedDoubleRNSElRepresentation::DoubleRNS(rhs_double_rns_repr)) =>
421            {
422                let mut result_fft = self.base.clone_el(lhs_double_rns_repr);
423                f2(&mut result_fft, rhs_double_rns_repr);
424                return self.from_double_rns_repr(result_fft);
425            },
426            (ManagedDoubleRNSElRepresentation::Both(lhs_small_basis_repr, _), ManagedDoubleRNSElRepresentation::Sum(rhs_sum_repr)) => {
427                let mut result_fft = self.base.clone_el(&rhs_sum_repr.1);
428                let mut result_coeff = self.base.clone_el_non_fft(lhs_small_basis_repr);
429                f1(&mut result_coeff, &rhs_sum_repr.0);
430                f4(&mut result_fft);
431                return self.new_element_sum(result_coeff, result_fft);
432            },
433            (ManagedDoubleRNSElRepresentation::Both(lhs_small_basis_repr, lhs_double_rns_repr), ManagedDoubleRNSElRepresentation::Both(rhs_small_basis_repr, rhs_double_rns_repr)) => {
434                let mut result_fft = self.base.clone_el(lhs_double_rns_repr);
435                let mut result_coeff = self.base.clone_el_non_fft(lhs_small_basis_repr);
436                f1(&mut result_coeff, rhs_small_basis_repr);
437                f2(&mut result_fft, rhs_double_rns_repr);
438                return self.new_element_both(result_coeff, result_fft);
439            },
440        }
441    }
442}
443
444impl<NumberRing, A> PreparedMultiplicationRing for ManagedDoubleRNSRingBase<NumberRing, A> 
445    where NumberRing: HECyclotomicNumberRing,
446        A: Allocator + Clone
447{
448    type PreparedMultiplicant = Self::Element;
449
450    fn mul_prepared(&self, lhs: &Self::PreparedMultiplicant, rhs: &Self::PreparedMultiplicant) -> Self::Element {
451        self.mul_ref(lhs, rhs)
452    }
453
454    fn prepare_multiplicant(&self, x: &Self::Element) -> Self::PreparedMultiplicant {
455        _ = self.to_doublerns(x);
456        return self.clone_el(x);
457    }
458
459    fn inner_product_prepared<'a, I>(&self, parts: I) -> Self::Element
460        where I: IntoIterator<Item = (&'a Self::PreparedMultiplicant, &'a Self::PreparedMultiplicant)>,
461            Self: 'a
462    {
463        <_ as ComputeInnerProduct>::inner_product_ref(self, parts.into_iter())
464    }
465}
466
467impl<NumberRing, A> BGFVCiphertextRing for ManagedDoubleRNSRingBase<NumberRing, A> 
468    where NumberRing: HECyclotomicNumberRing,
469        A: Allocator + Clone
470{
471    type NumberRing = NumberRing;
472
473    fn number_ring(&self) -> &NumberRing {
474        self.base.number_ring()
475    }
476
477    fn drop_rns_factor(&self, drop_rns_factors: &[usize]) -> Self {
478        let new_base = self.base.drop_rns_factor(drop_rns_factors);
479        Self {
480            zero: new_base.get_ring().zero_non_fft(),
481            base: new_base.into()
482        }
483    }
484    
485    fn drop_rns_factor_element(&self, from: &Self, dropped_rns_factors: &[usize], value: Self::Element) -> Self::Element {
486        match value.internal.get_repr() {
487            ManagedDoubleRNSElRepresentation::Zero => self.zero(),
488            ManagedDoubleRNSElRepresentation::Sum(sum_repr) => self.new_element_sum(
489                self.base.drop_rns_factor_non_fft_element(&from.base, dropped_rns_factors, &sum_repr.0),
490                self.base.drop_rns_factor_element(&from.base, dropped_rns_factors, &sum_repr.1)
491            ),
492            ManagedDoubleRNSElRepresentation::SmallBasis(small_basis_repr) => self.from_small_basis_repr(
493                self.base.drop_rns_factor_non_fft_element(&from.base, dropped_rns_factors, small_basis_repr)
494            ),
495            ManagedDoubleRNSElRepresentation::DoubleRNS(double_rns_repr) => self.from_double_rns_repr(
496                self.base.drop_rns_factor_element(&from.base, dropped_rns_factors, double_rns_repr)
497            ),
498            ManagedDoubleRNSElRepresentation::Both(small_basis_repr, double_rns_repr) => self.new_element_both(
499                self.base.drop_rns_factor_non_fft_element(&from.base, dropped_rns_factors, small_basis_repr),
500                self.base.drop_rns_factor_element(&from.base, dropped_rns_factors, double_rns_repr)
501            )
502        }
503    }
504
505    fn drop_rns_factor_prepared(&self, from: &Self, drop_factors: &[usize], value: Self::PreparedMultiplicant) -> Self::PreparedMultiplicant {
506        self.drop_rns_factor_element(from, drop_factors, value)
507    }
508
509    fn small_generating_set_len(&self) -> usize {
510        self.rank()
511    }
512
513    fn as_representation_wrt_small_generating_set<V>(&self, x: &Self::Element, mut output: SubmatrixMut<V, zn_64::ZnEl>)
514        where V: AsPointerToSlice<zn_64::ZnEl>
515    {
516        let matrix = self.base.as_matrix_wrt_small_basis(self.to_small_basis(x).unwrap_or(&self.zero));
517        assert_eq!(output.row_count(), matrix.row_count());
518        assert_eq!(output.col_count(), matrix.col_count());
519        for i in 0..matrix.row_count() {
520            for j in 0..matrix.col_count() {
521                *output.at_mut(i, j) = *matrix.at(i, j);
522            }
523        }
524    }
525
526    ///
527    /// Computes a subset of the rows of the representation that would be returned by
528    /// [`BGFVCiphertextRing::as_representation_wrt_small_generating_set()`]. Since not all rows
529    /// have to be computed, this may be faster than `as_representation_wrt_small_generating_set()`.
530    /// 
531    /// However, this also means that this function will not cache the element in small-basis
532    /// representation, if that was computed (unlike `as_representation_wrt_small_generating_set()`).
533    /// Thus, if you want to access the element in small-basis representation afterwards anyway,
534    /// it will be faster to use `as_representation_wrt_small_generating_set()`.
535    /// 
536    fn partial_representation_wrt_small_generating_set<V>(&self, x: &Self::Element, row_indices: &[usize], mut output: SubmatrixMut<V, zn_64::ZnEl>)
537        where V: AsPointerToSlice<zn_64::ZnEl>
538    {
539        assert_eq!(output.row_count(), row_indices.len());
540        assert_eq!(output.col_count(), self.base.rank());
541
542        match x.internal.get_repr() {
543            ManagedDoubleRNSElRepresentation::DoubleRNS(double_rns_repr) => self.base.undo_fft_partial(double_rns_repr, row_indices, output),
544            ManagedDoubleRNSElRepresentation::Sum(parts) => {
545                let small_basis_part = &parts.0;
546                let double_rns_part = &parts.1;
547                self.base.undo_fft_partial(double_rns_part, row_indices, output.reborrow());
548                let matrix = self.base.as_matrix_wrt_small_basis(small_basis_part);
549                for (i_out, i_in) in row_indices.iter().enumerate() {
550                    for j in 0..matrix.col_count() {
551                        self.base.base_ring().at(*i_in).add_assign(output.at_mut(i_out, j), *matrix.at(*i_in, j));
552                    }
553                }
554            },
555            ManagedDoubleRNSElRepresentation::Both(small_basis_repr, _) | ManagedDoubleRNSElRepresentation::SmallBasis(small_basis_repr) => {   
556                let matrix = self.base.as_matrix_wrt_small_basis(small_basis_repr);
557                for (i_out, i_in) in row_indices.iter().enumerate() {
558                    for j in 0..matrix.col_count() {
559                        *output.at_mut(i_out, j) = *matrix.at(*i_in, j);
560                    }
561                }
562            },
563            ManagedDoubleRNSElRepresentation::Zero => {
564                for (i_out, i_in) in row_indices.iter().enumerate() {
565                    for j in 0..self.base.rank() {
566                        *output.at_mut(i_out, j) = self.base.base_ring().at(*i_in).zero();
567                    }
568                }
569            }
570        }
571
572    }
573
574    fn from_representation_wrt_small_generating_set<V>(&self, data: Submatrix<V, zn_64::ZnEl>) -> Self::Element
575        where V: AsPointerToSlice<zn_64::ZnEl>
576    {
577        let mut x = self.base.zero_non_fft();
578        let mut x_as_matrix = self.base.as_matrix_wrt_small_basis_mut(&mut x);
579        assert_eq!(data.row_count(), x_as_matrix.row_count());
580        assert_eq!(data.col_count(), x_as_matrix.col_count());
581        for i in 0..data.row_count() {
582            for j in 0..data.col_count() {
583                *x_as_matrix.at_mut(i, j) = self.base.base_ring().at(i).clone_el(data.at(i, j));
584            }
585        }
586        return self.from_small_basis_repr(x);
587    }
588}
589
590impl<NumberRing, A> CyclotomicRing for ManagedDoubleRNSRingBase<NumberRing, A> 
591    where NumberRing: HECyclotomicNumberRing,
592        A: Allocator + Clone
593{
594    fn n(&self) -> usize {
595        self.base.n()
596    }
597
598    fn apply_galois_action(&self, el: &Self::Element, g: CyclotomicGaloisGroupEl) -> Self::Element {
599        let result = if let Some(value) = self.to_doublerns(el) {
600            self.base.apply_galois_action(&*value, g)
601        } else {
602            return self.zero();
603        };
604        return self.from_double_rns_repr(result);
605    }
606}
607
608impl<NumberRing, A> PartialEq for ManagedDoubleRNSRingBase<NumberRing, A>
609    where NumberRing: HENumberRing,
610        A: Allocator + Clone
611{
612    fn eq(&self, other: &Self) -> bool {
613        self.base == other.base
614    }
615}
616
617impl<NumberRing, A> RingBase for ManagedDoubleRNSRingBase<NumberRing, A>
618    where NumberRing: HENumberRing,
619        A: Allocator + Clone
620{
621    type Element = ManagedDoubleRNSEl<NumberRing, A>;
622
623    fn clone_el(&self, val: &Self::Element) -> Self::Element {
624        ManagedDoubleRNSEl { internal: val.internal.clone() }
625    }
626
627    fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
628        match (lhs.internal.get_repr(), rhs.internal.get_repr()) {
629            (ManagedDoubleRNSElRepresentation::Zero, _) | (_, ManagedDoubleRNSElRepresentation::Zero) => self.is_zero(lhs),
630            (ManagedDoubleRNSElRepresentation::SmallBasis(_), _) | (_, ManagedDoubleRNSElRepresentation::SmallBasis(_)) => self.base.eq_el_non_fft(&*self.to_small_basis(lhs).unwrap(), &*self.to_small_basis(rhs).unwrap()),
631            _ => self.base.eq_el(&*self.to_doublerns(lhs).unwrap(), &*self.to_doublerns(rhs).unwrap())
632        }
633    }
634
635    fn is_zero(&self, value: &Self::Element) -> bool {
636        match value.internal.get_repr() {
637            ManagedDoubleRNSElRepresentation::Zero => true,
638            ManagedDoubleRNSElRepresentation::Sum(_) | ManagedDoubleRNSElRepresentation::SmallBasis(_) | ManagedDoubleRNSElRepresentation::Both(_, _) => self.base.eq_el_non_fft(&*self.to_small_basis(value).unwrap(), &self.zero),
639            ManagedDoubleRNSElRepresentation::DoubleRNS(double_rns_repr) => self.base.is_zero(&double_rns_repr)
640        }
641    }
642
643    fn zero(&self) -> Self::Element {
644        ManagedDoubleRNSEl { internal: Arc::new(DoubleRNSElInternal { 
645            sum_repr: RwLock::new(None), 
646            small_basis_repr: OnceLock::new(), 
647            double_rns_repr: OnceLock::new()
648        }) }
649    }
650    
651    fn dbg_within<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>, env: EnvBindingStrength) -> std::fmt::Result {
652        if let Some(nonzero) = self.to_doublerns(value) {
653            self.base.dbg_within(&*nonzero, out, env)
654        } else {
655            write!(out, "0")
656        }
657    }
658
659    fn square(&self, value: &mut Self::Element) {
660        let mut result = if let Some(nonzero) = self.to_doublerns(value) {
661            self.base.clone_el(&*nonzero)
662        } else {
663            return
664        };
665        self.base.square(&mut result);
666        *value = self.from_double_rns_repr(result);
667    }
668
669    fn negate(&self, value: Self::Element) -> Self::Element {
670        self.apply_linear_operation(
671            &self.zero(), 
672            &value,
673            |_, _| unreachable!(),
674            |_, _| unreachable!(),
675            |a| self.base.negate_inplace_non_fft(a),
676            |a| self.base.negate_inplace(a)
677        )
678    }
679    
680    #[instrument(skip_all)]
681    fn mul_int_ref(&self, lhs: &Self::Element, rhs: i32) -> Self::Element {
682        self.apply_linear_operation(
683            &self.zero(), 
684            lhs,
685            |_, _| unreachable!(),
686            |_, _| unreachable!(),
687            |a| self.base.mul_scalar_assign_non_fft(a, &self.base_ring().int_hom().map(rhs)),
688            |a| self.base.mul_assign_int(a, rhs)
689        )
690    }
691
692    fn add_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
693        self.apply_linear_operation(
694            lhs, 
695            rhs,
696            |a, b| self.base.add_assign_non_fft(a, b),
697            |a, b| self.base.add_assign_ref(a, b),
698            |_| {},
699            |_| {}
700        )
701    }
702
703    fn sub_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
704        self.apply_linear_operation(
705            lhs,
706            rhs,
707            |a, b| self.base.sub_assign_non_fft(a, b),
708            |a, b| self.base.sub_assign_ref(a, b),
709            |a| self.base.negate_inplace_non_fft(a),
710            |a| self.base.negate_inplace(a)
711        )
712    }
713
714    fn mul_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
715        let result = if let (Some(lhs), Some(rhs)) = (self.to_doublerns(lhs), self.to_doublerns(rhs)) {
716            self.base.mul_ref(&*lhs, &*rhs)
717        } else {
718            return self.zero();
719        };
720        return self.from_double_rns_repr(result);
721    }
722
723    fn pow_gen<R: IntegerRingStore>(&self, x: Self::Element, power: &El<R>, integers: R) -> Self::Element 
724        where R::Type: IntegerRing
725    {
726        let result = if let Some(nonzero) = self.to_doublerns(&x) {
727            self.base.pow_gen(self.base.clone_el(&*nonzero), power, integers)
728        } else {
729            return self.zero();
730        };
731        return self.from_double_rns_repr(result);
732    }
733
734    fn characteristic<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
735        where I::Type: IntegerRing
736    {
737        self.base_ring().characteristic(ZZ)
738    }
739
740    fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
741        lhs.internal = self.add_ref(lhs, rhs).internal;
742    }
743
744    fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
745        lhs.internal = self.add_ref(lhs, &rhs).internal;
746    }
747
748    fn sub_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
749        lhs.internal = self.sub_ref(lhs, rhs).internal;
750    }
751
752    fn negate_inplace(&self, lhs: &mut Self::Element) {
753        lhs.internal = self.negate(self.clone_el(lhs)).internal;
754    }
755
756    fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
757        lhs.internal = self.mul_ref(lhs, &rhs).internal;
758    }
759
760    fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
761        lhs.internal = self.mul_ref(lhs, rhs).internal;
762    }
763
764    fn is_commutative(&self) -> bool { true }
765    fn is_noetherian(&self) -> bool { true }
766    fn is_approximate(&self) -> bool { false }
767
768    fn from_int(&self, value: i32) -> Self::Element {
769        self.from(self.base_ring().get_ring().from_int(value))
770    }
771
772    fn dbg<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
773        self.dbg_within(value, out, EnvBindingStrength::Weakest)
774    }
775
776    fn sub_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
777        lhs.internal = self.sub_ref(lhs, &rhs).internal;
778    }
779
780    fn mul_assign_int(&self, lhs: &mut Self::Element, rhs: i32) {
781        lhs.internal = self.mul_int(self.clone_el(lhs), rhs).internal;
782    }
783
784    fn mul_int(&self, lhs: Self::Element, rhs: i32) -> Self::Element {
785        self.mul_int_ref(&lhs, rhs)
786    }
787
788    fn sub_self_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
789        lhs.internal = self.sub_ref(&rhs, lhs).internal;
790    }
791
792    fn sub_self_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
793        lhs.internal = self.sub_ref(rhs, lhs).internal;
794    }
795
796    fn add_ref_fst(&self, lhs: &Self::Element, rhs: Self::Element) -> Self::Element {
797        self.add_ref(lhs, &rhs)
798    }
799
800    fn add_ref_snd(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
801        self.add_ref(&lhs, rhs)
802    }
803
804    fn add(&self, lhs: Self::Element, rhs: Self::Element) -> Self::Element {
805        self.add_ref(&lhs, &rhs)
806    }
807
808    fn sub_ref_fst(&self, lhs: &Self::Element, rhs: Self::Element) -> Self::Element {
809        self.sub_ref(lhs, &rhs)
810    }
811
812    fn sub_ref_snd(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
813        self.sub_ref(&lhs, rhs)
814    }
815
816    fn sub(&self, lhs: Self::Element, rhs: Self::Element) -> Self::Element {
817        self.sub_ref(&lhs, &rhs)
818    }
819
820    fn mul_ref_fst(&self, lhs: &Self::Element, rhs: Self::Element) -> Self::Element {
821        self.mul_ref(lhs, &rhs)
822    }
823
824    fn mul_ref_snd(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
825        self.mul_ref(&lhs, rhs)
826    }
827
828    fn mul(&self, lhs: Self::Element, rhs: Self::Element) -> Self::Element {
829        self.mul_ref(&lhs, &rhs)
830    }
831}
832
833impl<NumberRing, A> ComputeInnerProduct for ManagedDoubleRNSRingBase<NumberRing, A> 
834    where NumberRing: HENumberRing,
835        A: Allocator + Clone
836{
837    default fn inner_product<I: Iterator<Item = (Self::Element, Self::Element)>>(&self, els: I) -> Self::Element {
838        let data = els.collect::<Vec<_>>();
839        return self.inner_product_ref(data.iter().map(|(l, r)| (l, r)));
840    }
841
842    default fn inner_product_ref<'a, I: Iterator<Item = (&'a Self::Element, &'a Self::Element)>>(&self, els: I) -> Self::Element
843        where Self: 'a
844    {
845        self.from_double_rns_repr(<_ as ComputeInnerProduct>::inner_product_ref(
846            &self.base, 
847            els.map(|(l, r)| (self.to_doublerns(l), self.to_doublerns(r)))
848                .filter_map(|(l, r)| l.and_then(|l| r.map(|r| (l, r))))
849        ))
850    }
851
852    default fn inner_product_ref_fst<'a, I: Iterator<Item = (&'a Self::Element, Self::Element)>>(&self, els: I) -> Self::Element
853        where Self::Element: 'a,
854            Self: 'a
855    {
856        let data = els.collect::<Vec<_>>();
857        return self.inner_product_ref(data.iter().map(|(l, r)| (*l, r)));
858    }
859}
860
861impl<NumberRing, A> RingExtension for ManagedDoubleRNSRingBase<NumberRing, A>
862    where NumberRing: HENumberRing,
863        A: Allocator + Clone
864{
865    type BaseRing = <DoubleRNSRingBase<NumberRing, A> as RingExtension>::BaseRing;
866
867    fn base_ring<'a>(&'a self) -> &'a Self::BaseRing {
868        self.base.base_ring()
869    }
870
871    fn from(&self, x: El<Self::BaseRing>) -> Self::Element {
872        let result_fft = self.base.from(self.base_ring().clone_el(&x));
873        let result_coeff = self.base.from_non_fft(x);
874        return self.new_element_both(result_coeff, result_fft);
875    }
876
877    fn mul_assign_base(&self, lhs: &mut Self::Element, rhs: &El<Self::BaseRing>) {
878        *lhs = self.apply_linear_operation(
879            &self.zero(), 
880            lhs,
881            |_, _| unreachable!(),
882            |_, _| unreachable!(),
883            |a| self.base.mul_scalar_assign_non_fft(a, rhs),
884            |a| self.base.mul_assign_base(a, rhs)
885        )
886    }
887}
888
889impl<NumberRing, A> FreeAlgebra for ManagedDoubleRNSRingBase<NumberRing, A>
890    where NumberRing: HENumberRing,
891        A: Allocator + Clone
892{
893    type VectorRepresentation<'a> = DoubleRNSRingBaseElVectorRepresentation<'a, NumberRing, A> 
894        where Self: 'a;
895
896    fn canonical_gen(&self) -> Self::Element {
897        let result = self.base.canonical_gen();
898        return self.from_double_rns_repr(result);
899    }
900
901    fn rank(&self) -> usize { 
902        self.base.rank()
903    }
904
905    fn wrt_canonical_basis<'a>(&'a self, el: &'a Self::Element) -> Self::VectorRepresentation<'a> {
906        if let Some(result) = self.to_small_basis(el) {
907            self.base.wrt_canonical_basis_non_fft(self.base.clone_el_non_fft(&result))
908        } else {
909            self.base.wrt_canonical_basis_non_fft(self.base.clone_el_non_fft(&self.zero))
910        }
911    }
912
913    fn from_canonical_basis<V>(&self, vec: V) -> Self::Element
914        where V: IntoIterator<Item = El<Self::BaseRing>>,
915            V::IntoIter: DoubleEndedIterator
916    {
917        let result = self.base.from_canonical_basis_non_fft(vec);
918        return self.from_small_basis_repr(result);
919    }
920}
921
922impl<NumberRing, A> FiniteRingSpecializable for ManagedDoubleRNSRingBase<NumberRing, A>
923    where NumberRing: HENumberRing,
924        A: Allocator + Clone
925{
926    fn specialize<O: FiniteRingOperation<Self>>(op: O) -> Result<O::Output, ()> {
927        Ok(op.execute())
928    }
929}
930
931impl<NumberRing, A> FiniteRing for ManagedDoubleRNSRingBase<NumberRing, A>
932    where NumberRing: HENumberRing,
933        A: Allocator + Clone
934{
935    type ElementsIter<'a> = std::iter::Map<<DoubleRNSRingBase<NumberRing, A> as FiniteRing>::ElementsIter<'a>, fn(DoubleRNSEl<NumberRing, A>) -> ManagedDoubleRNSEl<NumberRing, A>>
936        where Self: 'a;
937
938    fn elements<'a>(&'a self) -> Self::ElementsIter<'a> {
939        fn from_doublerns<NumberRing, A>(x: DoubleRNSEl<NumberRing, A>) -> ManagedDoubleRNSEl<NumberRing, A>
940            where NumberRing: HENumberRing,
941                A: Allocator + Clone
942        {
943            return ManagedDoubleRNSEl { internal: Arc::new(DoubleRNSElInternal {
944                double_rns_repr: {
945                    let result = OnceLock::new();
946                    result.set(x).ok().unwrap();
947                    result
948                },
949                sum_repr: RwLock::new(None),
950                small_basis_repr: OnceLock::new()
951            })};
952        }
953        self.base.elements().map(from_doublerns)
954    }
955
956    fn random_element<G: FnMut() -> u64>(&self, rng: G) -> <Self as RingBase>::Element {
957        return self.from_double_rns_repr(self.base.random_element(rng));
958    }
959
960    fn size<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
961        where I::Type: IntegerRing
962    {
963        self.base.size(ZZ)
964    }
965}
966
967impl<NumberRing, A> SerializableElementRing for ManagedDoubleRNSRingBase<NumberRing, A>
968    where NumberRing: HENumberRing,
969        A: Allocator + Clone
970{
971    fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
972        where S: serde::Serializer
973    {
974        if serializer.is_human_readable() {
975            return SerializableNewtype::new("ManagedDoubleRNSEl", &SerializableSmallBasisElWithRing::new(&self.base, self.to_small_basis(el).unwrap_or(&self.zero))).serialize(serializer);
976        }
977        if let ManagedDoubleRNSElRepresentation::DoubleRNS(double_rns_repr) = el.internal.get_repr() {
978            serializer.serialize_newtype_variant("ManagedDoubleRNSEl", 0, "DoubleRNS", &SerializeWithRing::new(double_rns_repr, RingRef::new(&self.base)))
979        } else if let Some(small_basis_repr) = self.to_small_basis(el) {
980            serializer.serialize_newtype_variant("ManagedDoubleRNSEl", 1, "SmallBasis", &SerializableSmallBasisElWithRing::new(&self.base, small_basis_repr))
981        } else {
982            serializer.serialize_newtype_variant("ManagedDoubleRNSEl", 2, "Zero", &())
983        }
984    }
985
986    fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
987        where D: serde::Deserializer<'de>
988    {
989        use serde::de::EnumAccess;
990        use serde::de::VariantAccess;
991
992        if deserializer.is_human_readable() {
993            return DeserializeSeedNewtype::new("ManagedDoubleRNSEl", DeserializeSeedSmallBasisElWithRing::new(&self.base)).deserialize(deserializer).map(|small_basis_repr| self.from_small_basis_repr(small_basis_repr));
994        }
995
996        struct ResultVisitor<'a, NumberRing, A>
997            where NumberRing: HENumberRing,
998                A: Allocator + Clone
999        {
1000            ring: &'a ManagedDoubleRNSRingBase<NumberRing, A>,
1001        }
1002        impl<'a, 'de, NumberRing, A> serde::de::Visitor<'de> for ResultVisitor<'a, NumberRing, A>
1003            where NumberRing: HENumberRing,
1004                A: Allocator + Clone
1005        {
1006            type Value = ManagedDoubleRNSEl<NumberRing, A>;
1007
1008            fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1009                write!(f, "either ManagedDoubleRNSEl::DoubleRNS, ManagedDoubleRNSEl::SmallBasis or ManagedDoubleRNSEl::Zero")
1010            }
1011    
1012            fn visit_enum<E>(self, data: E) -> Result<Self::Value, E::Error>
1013                where E: EnumAccess<'de>
1014            {
1015                enum Discriminant {
1016                    DoubleRNS,
1017                    SmallBasis,
1018                    Zero
1019                }
1020                struct DiscriminantVisitor;
1021                impl<'de> serde::de::Visitor<'de> for DiscriminantVisitor {
1022                    type Value = Discriminant;
1023                    fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1024                        write!(f, "one of the enum discriminants `DoubleRNS` = 0, `SmallBasis` = 1 or `Zero` = 2")
1025                    }
1026                    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
1027                        where E: serde::de::Error
1028                    {
1029                        match v {
1030                            "DoubleRNS" => Ok(Discriminant::DoubleRNS),
1031                            "SmallBasis" => Ok(Discriminant::SmallBasis),
1032                            "Zero" => Ok(Discriminant::Zero),
1033                            _ => Err(serde::de::Error::unknown_variant(v, &["DoubleRNS", "SmallBasis", "Zero"]))
1034                        }
1035                    }
1036                    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
1037                        where E: serde::de::Error
1038                    {
1039                        match v {
1040                            0 => Ok(Discriminant::DoubleRNS),
1041                            1 => Ok(Discriminant::SmallBasis),
1042                            2 => Ok(Discriminant::Zero),
1043                            _ => Err(serde::de::Error::unknown_variant(format!("{}", v).as_str(), &["0", "1", "2"]))
1044                        }
1045                    }
1046                }
1047                impl<'de> Deserialize<'de> for Discriminant {
1048                    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1049                        where D: serde::Deserializer<'de>
1050                    {
1051                        deserializer.deserialize_identifier(DiscriminantVisitor)
1052                    }
1053                }
1054                let (discriminant, variant): (Discriminant, _) = data.variant()?;
1055                match discriminant {
1056                    Discriminant::DoubleRNS => variant.newtype_variant_seed(DeserializeWithRing::new(self.ring.unmanaged_ring())).map(|double_rns_repr| self.ring.from_double_rns_repr(double_rns_repr)),
1057                    Discriminant::SmallBasis => variant.newtype_variant_seed(DeserializeSeedSmallBasisElWithRing::new(self.ring.unmanaged_ring().get_ring())).map(|small_basis_repr| self.ring.from_small_basis_repr(small_basis_repr)),
1058                    Discriminant::Zero => variant.unit_variant().map(|()| self.ring.zero())
1059                }
1060            }
1061        }
1062        return deserializer.deserialize_enum("ManagedDoubleRNSEl", &["DoubleRNS", "SmallBasis", "Zero"], ResultVisitor { ring: self });
1063    }
1064}
1065
1066impl<NumberRing, A1, A2, C> CanHomFrom<SingleRNSRingBase<NumberRing, A1, C>> for ManagedDoubleRNSRingBase<NumberRing, A2>
1067    where NumberRing: HECyclotomicNumberRing,
1068        A1: Allocator + Clone,
1069        A2: Allocator + Clone,
1070        C: PreparedConvolutionAlgorithm<zn_64::ZnBase>
1071{
1072    type Homomorphism = <DoubleRNSRingBase<NumberRing, A2> as CanHomFrom<SingleRNSRingBase<NumberRing, A1, C>>>::Homomorphism;
1073
1074    fn has_canonical_hom(&self, from: &SingleRNSRingBase<NumberRing, A1, C>) -> Option<Self::Homomorphism> {
1075        self.base.has_canonical_hom(from)
1076    }
1077
1078    fn map_in(&self, from: &SingleRNSRingBase<NumberRing, A1, C>, el: <SingleRNSRingBase<NumberRing, A1, C> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
1079        if from.is_zero(&el) {
1080            return self.zero();
1081        }
1082        return self.from_small_basis_repr(self.base.map_in_from_singlerns(from, el, hom));
1083    }
1084}
1085
1086impl<NumberRing, A1, A2> CanHomFrom<DoubleRNSRingBase<NumberRing, A1>> for ManagedDoubleRNSRingBase<NumberRing, A2>
1087    where NumberRing: HECyclotomicNumberRing,
1088        A1: Allocator + Clone,
1089        A2: Allocator + Clone
1090{
1091    type Homomorphism = <DoubleRNSRingBase<NumberRing, A2> as CanHomFrom<DoubleRNSRingBase<NumberRing, A2>>>::Homomorphism;
1092
1093    fn has_canonical_hom(&self, from: &DoubleRNSRingBase<NumberRing, A1>) -> Option<Self::Homomorphism> {
1094        self.base.has_canonical_hom(from)
1095    }
1096
1097    fn map_in(&self, from: &DoubleRNSRingBase<NumberRing, A1>, el: <DoubleRNSRingBase<NumberRing, A1> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
1098        if from.is_zero(&el) {
1099            return self.zero();
1100        }
1101        return self.from_double_rns_repr(self.base.map_in(from, el, hom));
1102    }
1103}
1104
1105impl<NumberRing, A1, A2> CanHomFrom<ManagedDoubleRNSRingBase<NumberRing, A1>> for ManagedDoubleRNSRingBase<NumberRing, A2>
1106    where NumberRing: HECyclotomicNumberRing,
1107        A1: Allocator + Clone,
1108        A2: Allocator + Clone
1109{
1110    type Homomorphism = <DoubleRNSRingBase<NumberRing, A2> as CanHomFrom<DoubleRNSRingBase<NumberRing, A2>>>::Homomorphism;
1111
1112    fn has_canonical_hom(&self, from: &ManagedDoubleRNSRingBase<NumberRing, A1>) -> Option<Self::Homomorphism> {
1113        self.base.has_canonical_hom(&from.base)
1114    }
1115
1116    fn map_in_ref(&self, from: &ManagedDoubleRNSRingBase<NumberRing, A1>, el: &<ManagedDoubleRNSRingBase<NumberRing, A1> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
1117        if let Some(el) = from.to_doublerns(el) {
1118            return self.from_double_rns_repr(self.base.map_in_ref(&from.base, &*el, hom));
1119        } else {
1120            self.zero()
1121        }
1122    }
1123
1124    fn map_in(&self, from: &ManagedDoubleRNSRingBase<NumberRing, A1>, el: <ManagedDoubleRNSRingBase<NumberRing, A1> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
1125        self.map_in_ref(from, &el, hom)
1126    }
1127}
1128
1129impl<NumberRing, A1, A2, C> CanIsoFromTo<SingleRNSRingBase<NumberRing, A1, C>> for ManagedDoubleRNSRingBase<NumberRing, A2>
1130    where NumberRing: HECyclotomicNumberRing,
1131        A1: Allocator + Clone,
1132        A2: Allocator + Clone,
1133        C: PreparedConvolutionAlgorithm<zn_64::ZnBase>
1134{
1135    type Isomorphism = <DoubleRNSRingBase<NumberRing, A2> as CanIsoFromTo<SingleRNSRingBase<NumberRing, A1, C>>>::Isomorphism;
1136
1137    fn has_canonical_iso(&self, to: &SingleRNSRingBase<NumberRing, A1, C>) -> Option<Self::Isomorphism> {
1138        self.base.has_canonical_iso(to)
1139    }
1140
1141    fn map_out(&self, to: &SingleRNSRingBase<NumberRing, A1, C>, el: Self::Element, iso: &Self::Isomorphism) -> <SingleRNSRingBase<NumberRing, A1, C> as RingBase>::Element {
1142        if let Some(el) = self.to_small_basis(&el) {
1143            self.base.map_out_to_singlerns(to, self.base.clone_el_non_fft(&*&el), iso)
1144        } else {
1145            to.zero()
1146        }
1147    }
1148}
1149
1150impl<NumberRing, A1, A2> CanIsoFromTo<DoubleRNSRingBase<NumberRing, A1>> for ManagedDoubleRNSRingBase<NumberRing, A2>
1151    where NumberRing: HECyclotomicNumberRing,
1152        A1: Allocator + Clone,
1153        A2: Allocator + Clone
1154{
1155    type Isomorphism = <DoubleRNSRingBase<NumberRing, A2> as CanIsoFromTo<DoubleRNSRingBase<NumberRing, A2>>>::Isomorphism;
1156
1157    fn has_canonical_iso(&self, to: &DoubleRNSRingBase<NumberRing, A1>) -> Option<Self::Isomorphism> {
1158        self.base.has_canonical_iso(to)
1159    }
1160
1161    fn map_out(&self, to: &DoubleRNSRingBase<NumberRing, A1>, el: Self::Element, iso: &Self::Isomorphism) -> <DoubleRNSRingBase<NumberRing, A1> as RingBase>::Element {
1162        if let Some(el) = self.to_doublerns(&el) {
1163            self.base.map_out(to, self.base.clone_el(&*&el), iso)
1164        } else {
1165            to.zero()
1166        }
1167    }
1168}
1169
1170impl<NumberRing, A1, A2> CanIsoFromTo<ManagedDoubleRNSRingBase<NumberRing, A1>> for ManagedDoubleRNSRingBase<NumberRing, A2>
1171    where NumberRing: HECyclotomicNumberRing,
1172        A1: Allocator + Clone,
1173        A2: Allocator + Clone
1174{
1175    type Isomorphism = <DoubleRNSRingBase<NumberRing, A1> as CanHomFrom<DoubleRNSRingBase<NumberRing, A2>>>::Homomorphism;
1176
1177    fn has_canonical_iso(&self, to: &ManagedDoubleRNSRingBase<NumberRing, A1>) -> Option<Self::Isomorphism> {
1178        to.has_canonical_hom(self)
1179    }
1180
1181    fn map_out(&self, to: &ManagedDoubleRNSRingBase<NumberRing, A1>, el: Self::Element, iso: &Self::Isomorphism) -> <ManagedDoubleRNSRingBase<NumberRing, A1> as RingBase>::Element {
1182        to.map_in(self, el, iso)
1183    }
1184}
1185
1186#[cfg(test)]
1187use feanor_math::assert_el_eq;
1188#[cfg(test)]
1189use crate::number_ring::pow2_cyclotomic::*;
1190#[cfg(test)]
1191use crate::DefaultConvolution;
1192
1193#[cfg(test)]
1194fn ring_and_elements() -> (ManagedDoubleRNSRing<Pow2CyclotomicNumberRing>, Vec<El<ManagedDoubleRNSRing<Pow2CyclotomicNumberRing>>>) {
1195    let rns_base = zn_rns::Zn::new(vec![zn_64::Zn::new(17), zn_64::Zn::new(97)], BigIntRing::RING);
1196    let ring = ManagedDoubleRNSRingBase::new(Pow2CyclotomicNumberRing::new(16), rns_base);
1197    
1198    let elements = vec![
1199        ring.zero(),
1200        ring.one(),
1201        ring.neg_one(),
1202        ring.int_hom().map(17),
1203        ring.int_hom().map(97),
1204        ring.canonical_gen(),
1205        ring.pow(ring.canonical_gen(), 15),
1206        ring.int_hom().mul_map(ring.canonical_gen(), 17),
1207        ring.int_hom().mul_map(ring.pow(ring.canonical_gen(), 15), 17),
1208        ring.add(ring.canonical_gen(), ring.one())
1209    ];
1210    return (ring, elements);
1211}
1212
1213#[test]
1214fn test_ring_axioms() {
1215    let (ring, elements) = ring_and_elements();
1216    feanor_math::ring::generic_tests::test_ring_axioms(&ring, elements.iter().map(|x| ring.clone_el(x)));
1217    feanor_math::ring::generic_tests::test_self_iso(&ring, elements.iter().map(|x| ring.clone_el(x)));
1218}
1219
1220#[test]
1221fn test_thread_safe() {
1222    let rns_base = zn_rns::Zn::new(vec![zn_64::Zn::new(17), zn_64::Zn::new(97)], BigIntRing::RING);
1223    let ring = Arc::new(ManagedDoubleRNSRingBase::new(Pow2CyclotomicNumberRing::new(16), rns_base));
1224
1225    let test_element = Arc::new(ring.get_ring().new_element_sum(
1226        ring.get_ring().base.from_non_fft(ring.get_ring().base.base_ring().int_hom().map(1)), 
1227        ring.get_ring().base.from(ring.get_ring().base.base_ring().int_hom().map(10))
1228    ));
1229    let mut threads = Vec::new();
1230    let n = 5;
1231    let barrier = Arc::new(Barrier::new(n));
1232    for _ in 0..n {
1233        let barrier = barrier.clone();
1234        let test_element = test_element.clone();
1235        let ring = ring.clone();
1236        threads.push(std::thread::spawn(move || {
1237            barrier.wait();
1238            assert_el_eq!(ring, ring.int_hom().map(121), ring.pow(ring.clone_el(&*test_element), 2));
1239        }))
1240    }
1241    for future in threads {
1242        future.join().unwrap();
1243    }
1244}
1245
1246#[test]
1247fn test_canonical_hom_from_doublerns() {
1248    let rns_base = zn_rns::Zn::new(vec![zn_64::Zn::new(17), zn_64::Zn::new(97)], BigIntRing::RING);
1249    let ring = ManagedDoubleRNSRingBase::new(Pow2CyclotomicNumberRing::new(16), rns_base);
1250
1251    let doublerns_ring = RingRef::new(&ring.get_ring().base);
1252    let elements = vec![
1253        doublerns_ring.zero(),
1254        doublerns_ring.one(),
1255        doublerns_ring.neg_one(),
1256        doublerns_ring.int_hom().map(17),
1257        doublerns_ring.int_hom().map(97),
1258        doublerns_ring.canonical_gen(),
1259        doublerns_ring.pow(doublerns_ring.canonical_gen(), 15),
1260        doublerns_ring.int_hom().mul_map(doublerns_ring.canonical_gen(), 17),
1261        doublerns_ring.int_hom().mul_map(doublerns_ring.pow(doublerns_ring.canonical_gen(), 15), 17),
1262        doublerns_ring.add(doublerns_ring.canonical_gen(), doublerns_ring.one())
1263    ];
1264
1265    feanor_math::ring::generic_tests::test_hom_axioms(doublerns_ring, &ring, elements.iter().map(|x| doublerns_ring.clone_el(x)));
1266}
1267
1268#[test]
1269fn test_canonical_hom_from_singlerns() {
1270    let rns_base = zn_rns::Zn::new(vec![zn_64::Zn::new(97), zn_64::Zn::new(193)], BigIntRing::RING);
1271    let ring = ManagedDoubleRNSRingBase::new(Pow2CyclotomicNumberRing::new(16), rns_base.clone());
1272
1273    let singlerns_ring = SingleRNSRingBase::<_, _, DefaultConvolution>::new(Pow2CyclotomicNumberRing::new(16), rns_base);
1274    let elements = vec![
1275        singlerns_ring.zero(),
1276        singlerns_ring.one(),
1277        singlerns_ring.neg_one(),
1278        singlerns_ring.int_hom().map(97),
1279        singlerns_ring.int_hom().map(193),
1280        singlerns_ring.canonical_gen(),
1281        singlerns_ring.pow(singlerns_ring.canonical_gen(), 15),
1282        singlerns_ring.int_hom().mul_map(singlerns_ring.canonical_gen(), 97),
1283        singlerns_ring.int_hom().mul_map(singlerns_ring.pow(singlerns_ring.canonical_gen(), 15), 97),
1284        singlerns_ring.add(singlerns_ring.canonical_gen(), singlerns_ring.one())
1285    ];
1286
1287    feanor_math::ring::generic_tests::test_hom_axioms(&singlerns_ring, &ring, elements.iter().map(|x| singlerns_ring.clone_el(x)));
1288}
1289
1290#[test]
1291fn test_add_result_independent_of_repr() {
1292    let rns_base = zn_rns::Zn::new(vec![zn_64::Zn::new(17), zn_64::Zn::new(97)], BigIntRing::RING);
1293    let ring = ManagedDoubleRNSRingBase::new(Pow2CyclotomicNumberRing::new(4), rns_base);
1294    let base = &ring.get_ring().base;
1295    let reprs_of_11: [Box<dyn Fn() -> ManagedDoubleRNSEl<_, _>>; 4] = [
1296        Box::new(|| ring.get_ring().from_small_basis_repr(base.from_non_fft(base.base_ring().int_hom().map(11)))),
1297        Box::new(|| ring.get_ring().from_double_rns_repr(base.from(base.base_ring().int_hom().map(11)))),
1298        Box::new(|| ring.get_ring().new_element_sum(base.from_non_fft(base.base_ring().int_hom().map(10)), base.from(base.base_ring().int_hom().map(1)))),
1299        Box::new(|| ring.get_ring().new_element_both(base.from_non_fft(base.base_ring().int_hom().map(11)), base.from(base.base_ring().int_hom().map(11))))
1300    ];
1301    let reprs_of_102: [Box<dyn Fn() -> ManagedDoubleRNSEl<_, _>>; 4] = [
1302        Box::new(|| ring.get_ring().from_small_basis_repr(base.from_non_fft(base.base_ring().int_hom().map(102)))),
1303        Box::new(|| ring.get_ring().from_double_rns_repr(base.from(base.base_ring().int_hom().map(102)))),
1304        Box::new(|| ring.get_ring().new_element_sum(base.from_non_fft(base.base_ring().int_hom().map(100)), base.from(base.base_ring().int_hom().map(2)))),
1305        Box::new(|| ring.get_ring().new_element_both(base.from_non_fft(base.base_ring().int_hom().map(102)), base.from(base.base_ring().int_hom().map(102))))
1306    ];
1307    for a in &reprs_of_11 {
1308        for b in &reprs_of_102 {
1309            let x = a();
1310            assert_el_eq!(RingRef::new(base), base.from_int(22), ring.get_ring().to_doublerns(&ring.add_ref(&x, &x)).unwrap());
1311
1312            let x = a();
1313            let y = b();
1314            assert_el_eq!(RingRef::new(base), base.from_int(113), ring.get_ring().to_doublerns(&ring.add_ref(&x, &y)).unwrap());
1315
1316            let x = a();
1317            let y = b();
1318            assert!(base.eq_el_non_fft(&base.from_non_fft(base.base_ring().int_hom().map(113)), &*ring.get_ring().to_small_basis(&ring.add_ref(&x, &y)).unwrap()));
1319
1320            let x = a();
1321            let y = b();
1322            assert_el_eq!(RingRef::new(base), base.from_int(-91), ring.get_ring().to_doublerns(&ring.sub_ref(&x, &y)).unwrap());
1323
1324            let x = a();
1325            let y = b();
1326            assert!(base.eq_el_non_fft(&base.from_non_fft(base.base_ring().int_hom().map(-91)), &*ring.get_ring().to_small_basis(&ring.sub_ref(&x, &y)).unwrap()));
1327
1328            let x = a();
1329            assert_el_eq!(RingRef::new(base), base.from_int(121), ring.get_ring().to_doublerns(&ring.mul_ref(&x, &x)).unwrap());
1330
1331            let x = a();
1332            let y = b();
1333            assert_el_eq!(RingRef::new(base), base.from_int(1122), ring.get_ring().to_doublerns(&ring.mul_ref(&x, &y)).unwrap());
1334
1335            let x = a();
1336            let y = b();
1337            assert!(base.eq_el_non_fft(&base.from_non_fft(base.base_ring().int_hom().map(1122)), &*ring.get_ring().to_small_basis(&ring.mul_ref(&x, &y)).unwrap()));
1338        }
1339    }
1340}
1341
1342#[test]
1343fn test_serialization() {
1344    let (ring, elements) = ring_and_elements();
1345    feanor_math::serialization::generic_tests::test_serialization(&ring, elements.iter().map(|x| ring.clone_el(x)));
1346
1347    for a in &elements {
1348        if ring.is_zero(a) {
1349            continue;
1350        }
1351        let a_small_basis = ring.get_ring().from_small_basis_repr(ring.get_ring().unmanaged_ring().get_ring().clone_el_non_fft(ring.get_ring().to_small_basis(a).unwrap()));
1352        let serializer = serde_assert::Serializer::builder().is_human_readable(true).build();
1353        let tokens = ring.get_ring().serialize(&a_small_basis, &serializer).unwrap();
1354        let mut deserializer = serde_assert::Deserializer::builder(tokens).is_human_readable(true).build();
1355        let result = ring.get_ring().deserialize(&mut deserializer).unwrap();
1356        assert_el_eq!(ring, &a_small_basis, &result);
1357        match result.internal.get_repr() {
1358            ManagedDoubleRNSElRepresentation::SmallBasis(_) => {},
1359            _ => panic!("wrong representation")
1360        };
1361
1362        let a_small_basis = ring.get_ring().from_small_basis_repr(ring.get_ring().unmanaged_ring().get_ring().clone_el_non_fft(ring.get_ring().to_small_basis(a).unwrap()));
1363        let serializer = serde_assert::Serializer::builder().is_human_readable(false).build();
1364        let tokens = ring.get_ring().serialize(&a_small_basis, &serializer).unwrap();
1365        let mut deserializer = serde_assert::Deserializer::builder(tokens).is_human_readable(false).build();
1366        let result = ring.get_ring().deserialize(&mut deserializer).unwrap();
1367        assert_el_eq!(ring, &a_small_basis, &result);
1368        match result.internal.get_repr() {
1369            ManagedDoubleRNSElRepresentation::SmallBasis(_) => {},
1370            _ => panic!("wrong representation")
1371        };
1372
1373        let a_doublerns = ring.get_ring().from_double_rns_repr(ring.get_ring().unmanaged_ring().clone_el(ring.get_ring().to_doublerns(a).unwrap()));
1374        let serializer = serde_assert::Serializer::builder().is_human_readable(true).build();
1375        let tokens = ring.get_ring().serialize(&a_doublerns, &serializer).unwrap();
1376        let mut deserializer = serde_assert::Deserializer::builder(tokens).is_human_readable(true).build();
1377        let result = ring.get_ring().deserialize(&mut deserializer).unwrap();
1378        assert_el_eq!(ring, &a_doublerns, &result);
1379        match result.internal.get_repr() {
1380            ManagedDoubleRNSElRepresentation::SmallBasis(_) => {},
1381            _ => panic!("wrong representation")
1382        };
1383
1384        let a_doublerns = ring.get_ring().from_double_rns_repr(ring.get_ring().unmanaged_ring().clone_el(ring.get_ring().to_doublerns(a).unwrap()));
1385        let serializer = serde_assert::Serializer::builder().is_human_readable(false).build();
1386        let tokens = ring.get_ring().serialize(&a_doublerns, &serializer).unwrap();
1387        let mut deserializer = serde_assert::Deserializer::builder(tokens).is_human_readable(false).build();
1388        let result = ring.get_ring().deserialize(&mut deserializer).unwrap();
1389        assert_el_eq!(ring, &a_doublerns, &result);
1390        match result.internal.get_repr() {
1391            ManagedDoubleRNSElRepresentation::DoubleRNS(_) => {},
1392            _ => panic!("wrong representation")
1393        };
1394    }
1395}