feanor_math/rings/zn/
zn_64.rs

1use crate::algorithms::fft::cooley_tuckey::CooleyTuckeyButterfly;
2use crate::algorithms::fft::radix3::CooleyTukeyRadix3Butterfly;
3use crate::reduce_lift::poly_eval::InterpolationBaseRing;
4use crate::delegate::DelegateRing;
5use crate::delegate::DelegateRingImplFiniteRing;
6use crate::divisibility::*;
7use crate::{impl_eq_based_self_iso, impl_localpir_wrap_unwrap_homs, impl_localpir_wrap_unwrap_isos, impl_field_wrap_unwrap_homs, impl_field_wrap_unwrap_isos};
8use crate::ordered::OrderedRingStore;
9use crate::primitive_int::*;
10use crate::integer::*;
11use crate::pid::*;
12use crate::rings::extension::FreeAlgebraStore;
13use crate::ring::*;
14use crate::rings::extension::galois_field::*;
15use crate::seq::*;
16use crate::serialization::*;
17use crate::algorithms::convolution::KaratsubaHint;
18use crate::algorithms::matmul::ComputeInnerProduct;
19use crate::algorithms::matmul::StrassenHint;
20use crate::specialization::*;
21use crate::homomorphism::*;
22
23use std::marker::PhantomData;
24use std::fmt::Debug;
25
26use feanor_serde::newtype_struct::*;
27use serde::de::{DeserializeSeed, Error};
28use serde::{Deserialize, Deserializer, Serialize, Serializer}; 
29
30use super::*;
31use super::zn_big;
32
33fn high(x: u128) -> u64 {
34    (x >> 64) as u64
35}
36
37fn low(x: u128) -> u64 {
38    (x & ((1 << 64) - 1)) as u64
39}
40
41fn mulhi(lhs: u64, rhs: u64) -> u64 {
42    high(lhs as u128 * rhs as u128)
43}
44
45fn mullo(lhs: u64, rhs: u64) -> u64 {
46    lhs.wrapping_mul(rhs)
47}
48
49///
50/// Assuming that `x <= 2 * bound`, computes `x' <= bound` that is congruent
51/// to `x` modulo `bound`
52/// 
53fn reduce_to_half(x: u64, bound: u64) -> u64 {
54    let (result, overflow) = x.overflowing_sub(bound);
55    if overflow {
56        x
57    } else {
58        result
59    }
60}
61
62///
63/// Represents the ring `Z/nZ`.
64/// A variant of Barett reduction is used to perform fast modular
65/// arithmetic for `n` slightly smaller than 64 bit.
66/// 
67/// More concretely, the currently maximal supported modulus is `floor(2^62 / 9)`.
68/// Note that the exact value might change in the future.
69/// 
70/// # Examples
71/// ```rust
72/// # use feanor_math::assert_el_eq;
73/// # use feanor_math::ring::*;
74/// # use feanor_math::homomorphism::*;
75/// # use feanor_math::rings::zn::*;
76/// # use feanor_math::rings::zn::zn_64::*;
77/// let zn = Zn::new(7);
78/// assert_el_eq!(zn, zn.one(), zn.mul(zn.int_hom().map(3), zn.int_hom().map(5)));
79/// ```
80/// Too large moduli will give an error.
81/// ```should_panic
82/// # use feanor_math::assert_el_eq;
83/// # use feanor_math::ring::*;
84/// # use feanor_math::rings::zn::*;
85/// # use feanor_math::rings::zn::zn_64::*;
86/// Zn::new((1 << 62) / 9 + 1);
87/// ```
88/// 
89#[derive(Clone, Copy)]
90pub struct ZnBase {
91    modulus: i64,
92    modulus_half: i64,
93    modulus_times_three: u64,
94    modulus_times_six: u64,
95    inv_modulus: u128
96}
97
98const fn two_pow_128_div(x: u64) -> u128 {
99    let q_high = (1u128 << 64) / (x as u128);
100    let r_high = (1u128 << 64) % (x as u128);
101    let q_low = (r_high << 64) / (x as u128);
102    let result = (q_high << 64) | q_low;
103    debug_assert!(result.wrapping_mul(x as u128) == 0 || result.wrapping_mul(x as u128) >= 0u128.wrapping_sub(x as u128));
104    return result;
105}
106
107impl ZnBase {
108
109    pub const fn new(modulus: u64) -> Self {
110        assert!(modulus > 1);
111        // this should imply the statement we need later
112        assert!(modulus <= ((1 << 62) / 9));
113        // we want representatives to grow up to 6 * modulus
114        assert!(modulus as u128 * 6 <= u64::MAX as u128);
115        let modulus_i64: i64 = modulus as i64;
116        let inv_modulus = two_pow_128_div(modulus);
117        // we need the product `inv_modulus * (6 * modulus)^2` to fit into 192 bit, should be implied by `modulus < ((1 << 62) / 9)`
118        // debug_assert!(ZZbig.is_lt(&ZZbig.mul_ref_fst(&int_cast(inv_modulus as i128, ZZbig, StaticRing::<i128>::RING), ZZbig.pow(ZZbig.int_hom().mul_map(ZZbig.coerce(&ZZ, modulus_i64), 6), 2)), &ZZbig.power_of_two(192)));
119        Self {
120            modulus: modulus_i64,
121            inv_modulus: inv_modulus,
122            modulus_half: (modulus_i64 - 1) / 2 + 1,
123            modulus_times_three: modulus * 3,
124            modulus_times_six: modulus * 6
125        }
126    }
127
128    fn modulus_u64(&self) -> u64 {
129        self.modulus as u64
130    }
131
132    ///
133    /// Positive integers bounded by `self.repr_bound()` (inclusive) are considered
134    /// valid representatives of ring elements.
135    /// 
136    fn repr_bound(&self) -> u64 {
137        self.modulus_times_six
138    }
139
140    ///
141    /// Reduces from `[0, self.repr_bound() * self.repr_bound()]` to `[0, 3 * self.modulus()[`.
142    /// 
143    fn bounded_reduce(&self, value: u128) -> u64 {
144        debug_assert!(value <= self.repr_bound() as u128 * self.repr_bound() as u128);
145
146        let (in_low, in_high) = (low(value), high(value));
147        let (invmod_low, invmod_high) = (low(self.inv_modulus), high(self.inv_modulus));
148        // we ignore the lowest part of the sum, causing an error of at most 1;
149        // we also assume that `repr_bound * repr_bound * inv_modulus` fits into 192 bit
150        let approx_quotient = mulhi(in_low, invmod_high) + mulhi(in_high, invmod_low) + mullo(in_high, invmod_high);
151        let result = low(value).wrapping_sub(mullo(approx_quotient, self.modulus_u64()));
152
153        debug_assert!(result < self.modulus_times_three);
154        debug_assert!((value - result as u128) % (self.modulus_u64() as u128) == 0);
155        return result;
156    }
157
158    ///
159    /// Reduces from `[0, FACTOR * self.repr_bound() * self.repr_bound()]` to `[0, 3 * self.modulus()]`.
160    /// 
161    /// As opposed to the faster [`ZnBase::bounded_reduce()`], this should work for all inputs in `u128`
162    /// (assuming configured with the right value of `FACTOR`). Currently only used by the specialization of 
163    /// [`ComputeInnerProduct::inner_product()`].
164    /// 
165    #[inline(never)]
166    fn bounded_reduce_larger<const FACTOR: usize>(&self, value: u128) -> u64 {
167        assert!(FACTOR == 32);
168        debug_assert!(value <= FACTOR as u128 * self.repr_bound() as u128 * self.repr_bound() as u128);
169
170        let (in_low, in_high) = (low(value), high(value));
171        let invmod_high = high(self.inv_modulus);
172        // `approx_quotient` can be just slightly larger than 64 bits, since we optimized for `bounded_reduce()`
173        let approx_quotient = in_high as u128 * invmod_high as u128 + mulhi(in_low, invmod_high) as u128;
174
175        return self.bounded_reduce(value - (approx_quotient * self.modulus as u128));
176    }
177
178    ///
179    /// Creates a `ZnEl` from an integer that is already sufficiently reduced,
180    /// i.e. within `[0, self.repr_bound()]`.
181    /// 
182    /// The reducedness of the input is only checked when debug assertions are
183    /// enabled.
184    /// 
185    fn from_u64_promise_reduced(&self, value: u64) -> ZnEl {
186        debug_assert!(value <= self.repr_bound());
187        ZnEl(value)
188    }
189
190    ///
191    /// Reduces from `[0, self.repr_bound()]` to `[0, self.modulus()[`
192    /// 
193    fn complete_reduce(&self, mut value: u64) -> u64 {
194        debug_assert!(value <= self.repr_bound());
195        if value >= 4 * self.modulus_u64() {
196            value -= 4 * self.modulus_u64();
197        }
198        if value >= 2 * self.modulus_u64() {
199            value -= 2 * self.modulus_u64();
200        }
201        if value >= self.modulus_u64() {
202            value -= self.modulus_u64();
203        }
204        debug_assert!(value < self.modulus_u64());
205        return value;
206    }
207
208    #[stability::unstable(feature = "enable")]
209    pub fn from_primitive_int<T: PrimitiveInt>(&self, el: T) -> ZnEl {
210        let is_neg = StaticRing::<T>::RING.is_neg(&el);
211        let el_abs = <T as Into<i128>>::into(el).unsigned_abs();
212        if el_abs <= self.modulus_u64() as u128 {
213            if is_neg {
214                self.negate(self.from_u64_promise_reduced(el_abs as u64))
215            } else {
216                self.from_u64_promise_reduced(el_abs as u64)
217            }
218        } else if el_abs <= self.repr_bound() as u128 {
219            if is_neg {
220                self.negate(self.from_u64_promise_reduced(self.bounded_reduce(el_abs)))
221            } else {
222                self.from_u64_promise_reduced(self.bounded_reduce(el_abs))
223            }
224        } else {
225            let el_i128 = <T as Into<i128>>::into(el);
226            if is_neg {
227                self.from_u64_promise_reduced(((el_i128 % self.modulus as i128) as i64 + self.modulus) as u64)
228            } else {
229                self.from_u64_promise_reduced((el_i128 % self.modulus as i128) as u64)
230            }
231        }
232    }
233}
234
235/// 
236/// Represents the ring `Z/nZ`, using a variant of Barett reduction
237/// for moduli somewhat smaller than 64 bits. For details, see [`ZnBase`].
238/// 
239pub type Zn = RingValue<ZnBase>;
240
241impl Zn {
242
243    pub const fn new(modulus: u64) -> Self {
244        RingValue::from(ZnBase::new(modulus))
245    }
246}
247
248#[derive(Clone, Copy, Debug)]
249pub struct ZnEl(/* a representative within `[0, ring.repr_bound()]` */ u64);
250
251impl PartialEq for ZnBase {
252    fn eq(&self, other: &Self) -> bool {
253        self.modulus == other.modulus
254    }
255}
256
257impl Debug for ZnBase {
258
259    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
260        write!(f, "Z/{}Z", self.modulus)
261    }
262}
263
264impl RingBase for ZnBase {
265
266    type Element = ZnEl;
267
268    fn clone_el(&self, val: &Self::Element) -> Self::Element {
269        *val
270    }
271
272    fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
273        debug_assert!(lhs.0 <= self.repr_bound());
274        debug_assert!(rhs.0 <= self.repr_bound());
275        lhs.0 += rhs.0;
276        lhs.0 = reduce_to_half(lhs.0, self.repr_bound());
277        debug_assert!(lhs.0 <= self.repr_bound());
278    }
279
280    fn sub_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
281        debug_assert!(lhs.0 <= self.repr_bound());
282        debug_assert!(rhs.0 <= self.repr_bound());
283        let (result, overflow) = lhs.0.overflowing_sub(rhs.0);
284        if overflow {
285            lhs.0 = result.wrapping_add(self.repr_bound());
286        } else {
287            lhs.0 = result;
288        }
289        debug_assert!(lhs.0 <= self.repr_bound());
290    }
291
292    fn negate_inplace(&self, lhs: &mut Self::Element) {
293        debug_assert!(lhs.0 <= self.repr_bound());
294        lhs.0 = self.repr_bound() - lhs.0;
295    }
296
297    fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
298        debug_assert!(lhs.0 <= self.repr_bound());
299        debug_assert!(rhs.0 <= self.repr_bound());
300        lhs.0 = self.bounded_reduce(lhs.0 as u128 * rhs.0 as u128);
301    }
302
303    fn from_int(&self, value: i32) -> Self::Element {
304        self.from_primitive_int(value)
305    }
306
307    fn zero(&self) -> Self::Element {
308        ZnEl(0)
309    }
310
311    fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
312        debug_assert!(lhs.0 <= self.repr_bound());
313        debug_assert!(rhs.0 <= self.repr_bound());
314        if lhs.0 > rhs.0 {
315            self.is_zero(&self.from_u64_promise_reduced(lhs.0 - rhs.0))
316        } else {
317            self.is_zero(&self.from_u64_promise_reduced(rhs.0 - lhs.0))
318        }
319    }
320
321    fn is_zero(&self, val: &Self::Element) -> bool {
322        debug_assert!(val.0 <= self.repr_bound());
323        self.complete_reduce(val.0) == 0
324    }
325
326    fn is_commutative(&self) -> bool { true }
327    fn is_noetherian(&self) -> bool { true }
328
329    fn dbg_within<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>, _: EnvBindingStrength) -> std::fmt::Result {
330        write!(out, "{}", self.complete_reduce(value.0))
331    }
332    
333    fn characteristic<I: RingStore + Copy>(&self, other_ZZ: I) -> Option<El<I>>
334        where I::Type: IntegerRing
335    {
336        self.size(other_ZZ)
337    }
338    
339    fn sum<I>(&self, els: I) -> Self::Element 
340        where I: IntoIterator<Item = Self::Element>
341    {
342        let mut result = self.zero();
343        let mut els_it = els.into_iter();
344        while let Some(ZnEl(start)) = els_it.next() {
345            let mut current = start as u128;
346            for ZnEl(c) in els_it.by_ref().take(self.repr_bound() as usize / 2 - 1) {
347                current += c as u128;
348            }
349            self.add_assign(&mut result, self.from_u64_promise_reduced(self.bounded_reduce(current)));
350        }
351        debug_assert!(result.0 <= self.repr_bound());
352        return result;
353    }
354
355    fn pow_gen<R: RingStore>(&self, x: Self::Element, power: &El<R>, integers: R) -> Self::Element 
356        where R::Type: IntegerRing
357    {
358        assert!(!integers.is_neg(power));
359        algorithms::sqr_mul::generic_abs_square_and_multiply(
360            x, 
361            power, 
362            &integers,
363            |mut a| {
364                self.square(&mut a);
365                a
366            },
367            |a, b| self.mul_ref_fst(a, b),
368            self.one()
369        )
370    }
371
372    fn is_approximate(&self) -> bool { false }
373}
374
375impl SerializableElementRing for ZnBase {
376
377    fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
378        where D: Deserializer<'de>
379    {
380        <i64 as Deserialize>::deserialize(deserializer)
381            .and_then(|x| if x < 0 || x >= *self.modulus() { Err(Error::custom("ring element value out of bounds for ring Z/nZ")) } else { Ok(x) })
382            .map(|x| self.from_int_promise_reduced(x))
383    }
384
385    fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
386        where S: Serializer
387    {
388        <i64 as Serialize>::serialize(&self.smallest_positive_lift(*el), serializer)
389    }
390}
391
392impl FromModulusCreateableZnRing for ZnBase {
393
394    fn from_modulus<F, E>(create_modulus: F) -> Result<Self, E>
395        where F: FnOnce(&Self::IntegerRingBase) -> Result<El<Self::IntegerRing>, E>
396    {
397        create_modulus(StaticRing::<i64>::RING.get_ring()).map(|n| Self::new(n as u64))
398    }
399}
400
401impl InterpolationBaseRing for AsFieldBase<Zn> {
402
403    type ExtendedRingBase<'a> = GaloisFieldBaseOver<RingRef<'a, Self>>
404        where Self: 'a;
405
406    type ExtendedRing<'a> = GaloisFieldOver<RingRef<'a, Self>>
407        where Self: 'a;
408
409    fn in_base<'a, S>(&self, ext_ring: S, el: El<S>) -> Option<Self::Element>
410        where Self: 'a, S: RingStore<Type = Self::ExtendedRingBase<'a>>
411    {
412        let wrt_basis = ext_ring.wrt_canonical_basis(&el);
413        if wrt_basis.iter().skip(1).all(|x| self.is_zero(&x)) {
414            return Some(wrt_basis.at(0));
415        } else {
416            return None;
417        }
418    }
419
420    fn in_extension<'a, S>(&self, ext_ring: S, el: Self::Element) -> El<S>
421        where Self: 'a, S: RingStore<Type = Self::ExtendedRingBase<'a>>
422    {
423        ext_ring.inclusion().map(el)
424    }
425
426    fn interpolation_points<'a>(&'a self, count: usize) -> (Self::ExtendedRing<'a>, Vec<El<Self::ExtendedRing<'a>>>) {
427        let ring = super::generic_impls::interpolation_ring(RingRef::new(self), count);
428        let points = ring.elements().take(count).collect();
429        return (ring, points);
430    }
431}
432
433impl ComputeInnerProduct for ZnBase {
434
435    fn inner_product<I: Iterator<Item = (Self::Element, Self::Element)>>(&self, els: I) -> Self::Element {
436
437        debug_assert!(u128::MAX / (self.repr_bound() as u128 * self.repr_bound() as u128) >= 36);
438        const REDUCE_AFTER_STEPS: usize = 32;
439        let mut array_chunks = els.array_chunks::<REDUCE_AFTER_STEPS>();
440        let mut result = self.zero();
441        while let Some(chunk) = array_chunks.next() {
442            let mut sum: u128 = 0;
443            for (l, r) in chunk {
444                debug_assert!(l.0 <= self.repr_bound());
445                debug_assert!(r.0 <= self.repr_bound());
446                sum += l.0 as u128 * r.0 as u128;
447            }
448            self.add_assign(&mut result, ZnEl(self.bounded_reduce_larger::<REDUCE_AFTER_STEPS>(sum)));
449        }
450        let mut sum: u128 = 0;
451        for (l, r) in array_chunks.into_remainder() {
452            debug_assert!(l.0 <= self.repr_bound());
453            debug_assert!(r.0 <= self.repr_bound());
454            sum += l.0 as u128 * r.0 as u128;
455        }
456        self.add_assign(&mut result, ZnEl(self.bounded_reduce_larger::<REDUCE_AFTER_STEPS>(sum)));
457        return result;
458    }
459
460    fn inner_product_ref_fst<'a, I: Iterator<Item = (&'a Self::Element, Self::Element)>>(&self, els: I) -> Self::Element
461        where Self::Element: 'a
462    {
463        self.inner_product(els.map(|(l, r)| (self.clone_el(l), r)))
464    }
465
466    fn inner_product_ref<'a, I: Iterator<Item = (&'a Self::Element, &'a Self::Element)>>(&self, els: I) -> Self::Element
467        where Self::Element: 'a
468    {
469        self.inner_product_ref_fst(els.map(|(l, r)| (l, self.clone_el(r))))
470    }
471}
472
473impl_eq_based_self_iso!{ ZnBase }
474
475impl<I: RingStore> CanHomFrom<zn_big::ZnBase<I>> for ZnBase
476    where I::Type: IntegerRing
477{
478    type Homomorphism = ();
479
480    fn has_canonical_hom(&self, from: &zn_big::ZnBase<I>) -> Option<Self::Homomorphism> {
481        if from.integer_ring().get_ring().representable_bits().is_none() || from.integer_ring().get_ring().representable_bits().unwrap() >= self.integer_ring().abs_log2_ceil(self.modulus()).unwrap() {
482            if from.integer_ring().eq_el(from.modulus(), &int_cast(*self.modulus(), from.integer_ring(), self.integer_ring())) {
483                Some(())
484            } else {
485                None
486            }
487        } else {
488            None
489        }
490    }
491
492    fn map_in(&self, from: &zn_big::ZnBase<I>, el: <zn_big::ZnBase<I> as RingBase>::Element, _: &Self::Homomorphism) -> Self::Element {
493        self.from_u64_promise_reduced(int_cast(from.smallest_positive_lift(el), self.integer_ring(), from.integer_ring()) as u64)
494    }
495}
496
497impl<I: RingStore> CanIsoFromTo<zn_big::ZnBase<I>> for ZnBase
498    where I::Type: IntegerRing
499{
500    type Isomorphism = <zn_big::ZnBase<I> as CanHomFrom<StaticRingBase<i64>>>::Homomorphism;
501
502    fn has_canonical_iso(&self, from: &zn_big::ZnBase<I>) -> Option<Self::Isomorphism> {
503        if from.integer_ring().get_ring().representable_bits().is_none() || from.integer_ring().get_ring().representable_bits().unwrap() >= self.integer_ring().abs_log2_ceil(self.modulus()).unwrap() {
504            if from.integer_ring().eq_el(from.modulus(), &int_cast(*self.modulus(), from.integer_ring(), self.integer_ring())) {
505                from.has_canonical_hom(self.integer_ring().get_ring())
506            } else {
507                None
508            }
509        } else {
510            None
511        }
512    }
513
514    fn map_out(&self, from: &zn_big::ZnBase<I>, el: <Self as RingBase>::Element, iso: &Self::Isomorphism) -> <zn_big::ZnBase<I> as RingBase>::Element {
515        from.map_in(self.integer_ring().get_ring(), el.0.try_into().unwrap(), iso)
516    }
517}
518
519///
520/// Data associated to an element of [`ZnBase`] that allows for faster division. 
521/// For details, see [`DivisibilityRing::prepare_divisor()`].
522/// 
523#[derive(Copy, Clone, Debug)]
524pub struct ZnPreparedDivisorData {
525    unit_part: El<Zn>,
526    is_unit: bool,
527    smallest_positive_zero_divisor_part: PreparedDivisor<StaticRingBase<i64>>
528}
529
530impl DivisibilityRing for ZnBase {
531
532    type PreparedDivisorData = ZnPreparedDivisorData;
533
534    fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
535        super::generic_impls::checked_left_div(RingRef::new(self), lhs, rhs)
536    }
537
538    fn prepare_divisor(&self, x: &Self::Element) -> Self::PreparedDivisorData {
539        let (s, _t, d) = algorithms::eea::signed_eea(self.smallest_positive_lift(*x), *self.modulus(), self.integer_ring());
540        debug_assert!(d > 0);
541        debug_assert!(d <= *self.modulus());
542        return ZnPreparedDivisorData {
543            is_unit: d == 1,
544            unit_part: if s < 0 { self.negate(self.from_u64_promise_reduced(-s as u64)) } else { self.from_u64_promise_reduced(s as u64) },
545            smallest_positive_zero_divisor_part: PreparedDivisor::new(StaticRing::<i64>::RING.get_ring(), d)
546        };
547    }
548
549    fn checked_left_div_prepared(&self, lhs: &Self::Element, _rhs: &Self::Element, rhs_prep: &Self::PreparedDivisorData) -> Option<Self::Element> {
550        if rhs_prep.is_unit {
551            Some(self.mul_ref(lhs, &rhs_prep.unit_part))
552        } else {
553            StaticRing::<i64>::RING.get_ring().checked_left_div_prepared(&self.smallest_positive_lift(*lhs), &rhs_prep.smallest_positive_zero_divisor_part.element, &rhs_prep.smallest_positive_zero_divisor_part.data)
554                .map(|x| self.mul(self.from_u64_promise_reduced(x as u64), rhs_prep.unit_part))
555        }
556    }
557}
558
559impl<I: ?Sized + IntegerRing> CanHomFrom<I> for ZnBase {
560
561    type Homomorphism = super::generic_impls::BigIntToZnHom<I, StaticRingBase<i128>, Self>;
562
563    default fn has_canonical_hom(&self, from: &I) -> Option<Self::Homomorphism> {
564        super::generic_impls::has_canonical_hom_from_bigint(from, self, StaticRing::<i128>::RING.get_ring(), Some(&(self.repr_bound() as i128 * self.repr_bound() as i128)))
565    }
566
567    default fn map_in(&self, from: &I, el: I::Element, hom: &Self::Homomorphism) -> Self::Element {
568        super::generic_impls::map_in_from_bigint(from, self, StaticRing::<i128>::RING.get_ring(), el, hom, |n| {
569            debug_assert!((n as u64) < self.modulus_u64());
570            self.from_u64_promise_reduced(n as u64)
571        }, |n| {
572            debug_assert!(n <= (self.repr_bound() as i128 * self.repr_bound() as i128));
573            self.from_u64_promise_reduced(self.bounded_reduce(n as u128))
574        })
575    }
576}
577
578impl Serialize for ZnBase {
579    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
580        where S: Serializer
581    {
582        SerializableNewtypeStruct::new("Zn", *self.modulus()).serialize(serializer)
583    }
584}
585
586impl<'de> Deserialize<'de> for ZnBase {
587    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
588        where D: Deserializer<'de>
589    {
590        DeserializeSeedNewtypeStruct::new("Zn", PhantomData::<i64>).deserialize(deserializer).map(|n| ZnBase::new(n as u64))
591    }
592}
593
594macro_rules! impl_static_int_to_zn {
595    ($($int:ident),*) => {
596        $(
597            impl CanHomFrom<StaticRingBase<$int>> for ZnBase {
598                fn map_in(&self, _from: &StaticRingBase<$int>, el: $int, _hom: &Self::Homomorphism) -> Self::Element {
599                    self.from_primitive_int(el)
600                }
601            }
602        )*
603    };
604}
605
606impl_static_int_to_zn!{ i8, i16, i32, i64, i128 }
607
608#[derive(Clone, Copy)]
609pub struct ZnBaseElementsIter<'a> {
610    ring: &'a ZnBase,
611    current: u64
612}
613
614impl<'a> Iterator for ZnBaseElementsIter<'a> {
615
616    type Item = ZnEl;
617
618    fn next(&mut self) -> Option<Self::Item> {
619        if self.current < self.ring.modulus_u64() {
620            let result = self.current;
621            self.current += 1;
622            return Some(self.ring.from_u64_promise_reduced(result));
623        } else {
624            return None;
625        }
626    }
627}
628
629impl FiniteRingSpecializable for ZnBase {
630    fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output {
631        op.execute()
632    }
633}
634
635impl FiniteRing for ZnBase {
636
637    type ElementsIter<'a> = ZnBaseElementsIter<'a>;
638
639    fn elements<'a>(&'a self) -> Self::ElementsIter<'a> {
640        ZnBaseElementsIter {
641            ring: self,
642            current: 0
643        }
644    }
645
646    fn random_element<G: FnMut() -> u64>(&self, rng: G) -> <Self as RingBase>::Element {
647        super::generic_impls::random_element(self, rng)
648    }
649
650    fn size<I: RingStore + Copy>(&self, other_ZZ: I) -> Option<El<I>>
651        where I::Type: IntegerRing
652    {
653        if other_ZZ.get_ring().representable_bits().is_none() || self.integer_ring().abs_log2_ceil(&(self.modulus() + 1)) <= other_ZZ.get_ring().representable_bits() {
654            Some(int_cast(*self.modulus(), other_ZZ, self.integer_ring()))
655        } else {
656            None
657        }
658    }
659}
660
661impl PrincipalIdealRing for ZnBase {
662
663    fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
664        super::generic_impls::checked_div_min(RingRef::new(self), lhs, rhs)
665    }
666
667    fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
668        let (s, t, d) = StaticRing::<i64>::RING.extended_ideal_gen(&lhs.0.try_into().unwrap(), &rhs.0.try_into().unwrap());
669        let quo = RingRef::new(self).into_can_hom(StaticRing::<i64>::RING).ok().unwrap();
670        (quo.map(s), quo.map(t), quo.map(d))
671    }
672}
673
674impl StrassenHint for ZnBase {
675    default fn strassen_threshold(&self) -> usize {
676        6
677    }
678}
679
680impl KaratsubaHint for ZnBase {
681    default fn karatsuba_threshold(&self) -> usize {
682        6
683    }
684}
685
686impl ZnRing for ZnBase {
687
688    type IntegerRingBase = StaticRingBase<i64>;
689    type IntegerRing = StaticRing<i64>;
690
691    fn integer_ring(&self) -> &Self::IntegerRing {
692        &StaticRing::<i64>::RING
693    }
694
695    fn smallest_positive_lift(&self, el: Self::Element) -> El<Self::IntegerRing> {
696        self.complete_reduce(el.0) as i64
697    }
698
699    fn smallest_lift(&self, ZnEl(mut value_u64): Self::Element) -> El<Self::IntegerRing> {
700        debug_assert!(value_u64 <= self.repr_bound());
701        // value is in [0, 6 * self.modulus]
702        if value_u64 >= 3 * self.modulus_u64() {
703            value_u64 -= 3 * self.modulus_u64();
704        }
705        // value is in [0, 3 * self.modulus]
706        let mut value_i64 = value_u64 as i64;
707        if value_i64 >= self.modulus + self.modulus_half {
708            value_i64 -= 2 * self.modulus;
709        }
710        // value is in ]-self.modulus_half, self.modulus + self.modulus_half[ if modulus is odd
711        // value is in [-self.modulus_half, self.modulus + self.modulus_half[ if modulus is even
712        if value_i64 >= self.modulus_half {
713            value_i64 -= self.modulus;
714        }
715        // value is in ]-self.modulus_half, self.modulus_half[ if modulus is odd
716        // value is in [-self.modulus_half, self.modulus_half[ if modulus is even
717        debug_assert!(value_i64 < self.modulus_half);
718        debug_assert!(self.modulus() % 2 == 0 || value_i64 > -self.modulus_half);
719        debug_assert!(self.modulus() % 2 == 1 || value_i64 >= -self.modulus_half);
720        return value_i64;
721    }
722
723    fn modulus(&self) -> &El<Self::IntegerRing> {
724        &self.modulus
725    }
726
727    fn any_lift(&self, el: Self::Element) -> El<Self::IntegerRing> {
728        el.0 as i64
729    }
730
731    ///
732    /// If the given integer is within `{ 0, ..., 6 * n }`, returns the corresponding
733    /// element in `Z/nZ`. Any other input is considered a logic error.
734    /// 
735    /// This function follows [`ZnRing::from_int_promise_reduced()`], but is guaranteed
736    /// to work on elements `{ 0, ..., 6 * n }` instead of only `{ 0, ..., n - 1 }`.
737    /// 
738    /// # Examples
739    /// ```rust
740    /// # use feanor_math::rings::zn::*;
741    /// # use feanor_math::assert_el_eq;
742    /// # use feanor_math::ring::*;
743    /// # use feanor_math::rings::zn::zn_64::*;
744    /// let ring = Zn::new(7);
745    /// assert_el_eq!(ring, ring.zero(), ring.get_ring().from_int_promise_reduced(42));
746    /// ```
747    /// Larger values lead to a panic in debug mode, and to a logic error in release mode.
748    /// ```should_panic
749    /// # use feanor_math::rings::zn::*;
750    /// # use feanor_math::assert_el_eq;
751    /// # use feanor_math::ring::*;
752    /// # use feanor_math::rings::zn::zn_64::*;
753    /// let ring = Zn::new(7);
754    /// ring.get_ring().from_int_promise_reduced(43);
755    /// ```
756    /// 
757    fn from_int_promise_reduced(&self, x: El<Self::IntegerRing>) -> Self::Element {
758        debug_assert!(self.repr_bound() == 6 * self.modulus_u64());
759        debug_assert!(x >= 0);
760        debug_assert!(x as u64 <= self.repr_bound());
761        self.from_u64_promise_reduced(x as u64)
762    }
763}
764
765impl HashableElRing for ZnBase {
766
767    fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H) {
768        self.integer_ring().hash(&self.smallest_positive_lift(*el), h)
769    }
770}
771
772///
773/// Wraps [`ZnBase`] to represent an instance of the ring `Z/nZ`.
774/// As opposed to [`ZnBase`], elements are stored with additional information
775/// to speed up multiplication `ZnBase x ZnFastmulBase -> ZnBase`, by
776/// using [`CanHomFrom::mul_assign_map_in()`].
777/// Note that normal arithmetic in this ring is much slower than [`ZnBase`].
778/// 
779/// # Example
780/// The following use of the FFT is usually faster than the standard use, as
781/// the FFT requires a high amount of multiplications with the internally stored
782/// roots of unity.
783/// ```rust
784/// # #![feature(const_type_name)]
785/// # use feanor_math::homomorphism::*;
786/// # use feanor_math::ring::*;
787/// # use feanor_math::rings::zn::zn_64::*;
788/// # use feanor_math::algorithms::fft::*;
789/// # use feanor_math::algorithms::fft::cooley_tuckey::*;
790/// let ring = Zn::new(1073872897);
791/// let fastmul_ring = ZnFastmul::new(ring).unwrap();
792/// // The values stored by the FFT table are elements of `ZnFastmulBase`
793/// let fft = CooleyTuckeyFFT::for_zn_with_hom(ring.can_hom(&fastmul_ring).unwrap(), 15).unwrap();
794/// // Note that data uses `ZnBase`
795/// let mut data = (0..(1 << 15)).map(|i| ring.int_hom().map(i)).collect::<Vec<_>>();
796/// fft.unordered_fft(&mut data[..], &ring);
797/// ```
798/// 
799#[derive(Clone, Copy, Debug)]
800pub struct ZnFastmulBase {
801    base: RingValue<ZnBase>
802}
803
804///
805/// An implementation of `Z/nZ` for `n` that is optimized to provide fast multiplication with elements
806/// of [`Zn`]. For details, see [`ZnFastmulBase`].
807/// 
808pub type ZnFastmul = RingValue<ZnFastmulBase>;
809
810impl ZnFastmul {
811
812    pub fn new(base: Zn) -> Option<Self> {
813        Some(RingValue::from(ZnFastmulBase { base }))
814    }
815}
816
817impl PartialEq for ZnFastmulBase {
818    
819    fn eq(&self, other: &Self) -> bool {
820        self.base.get_ring() == other.base.get_ring()
821    }
822}
823
824impl PrincipalIdealRing for ZnFastmulBase {
825
826    fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
827        let result = self.get_delegate().checked_div_min(self.delegate_ref(lhs), self.delegate_ref(rhs));
828        result.map(|x| self.rev_delegate(x))
829    }
830
831    fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
832        let (s, t, d) = self.get_delegate().extended_ideal_gen(self.delegate_ref(lhs), self.delegate_ref(rhs));
833        (self.rev_delegate(s), self.rev_delegate(t), self.rev_delegate(d))
834    }
835}
836
837impl_eq_based_self_iso!{ ZnFastmulBase }
838
839#[derive(Clone, Copy, Debug)]
840pub struct ZnFastmulEl {
841    el: ZnEl,
842    value_invmod_shifted: u64
843}
844
845impl DelegateRing for ZnFastmulBase {
846
847    type Base = ZnBase;
848    type Element = ZnFastmulEl;
849
850    fn get_delegate(&self) -> &Self::Base {
851        self.base.get_ring()
852    }
853
854    fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element {
855        el.el
856    }
857
858    fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element {
859        &mut el.el
860    }
861
862    fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element {
863        &el.el
864    }
865
866    fn postprocess_delegate_mut(&self, el: &mut Self::Element) {
867        assert!(el.el.0 <= self.base.get_ring().repr_bound());
868        el.el.0 = self.base.get_ring().complete_reduce(el.el.0);
869        let value = el.el.0;
870        el.value_invmod_shifted = (((value as u128) << 64) / self.base.get_ring().modulus_u64() as u128) as u64;
871    }
872
873    fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element {
874        let mut result = ZnFastmulEl {
875            el: el,
876            value_invmod_shifted: 0
877        };
878        self.postprocess_delegate_mut(&mut result);
879        return result;
880    }
881}
882
883impl DelegateRingImplFiniteRing for ZnFastmulBase {}
884
885impl CanHomFrom<ZnBase> for ZnFastmulBase {
886
887    type Homomorphism = ();
888
889    fn has_canonical_hom(&self, from: &ZnBase) -> Option<Self::Homomorphism> {
890        if from == self.base.get_ring() {
891            Some(())
892        } else {
893            None
894        }
895    }
896
897    fn map_in(&self, _from: &ZnBase, el: <ZnBase as RingBase>::Element, _hom: &Self::Homomorphism) -> Self::Element {
898        self.rev_delegate(el)
899    }
900}
901
902impl CanHomFrom<ZnFastmulBase> for ZnBase {
903
904    type Homomorphism = ();
905
906    fn has_canonical_hom(&self, from: &ZnFastmulBase) -> Option<Self::Homomorphism> {
907        if self == from.base.get_ring() {
908            Some(())
909        } else {
910            None
911        }
912    }
913
914    fn map_in(&self, _from: &ZnFastmulBase, el: <ZnFastmulBase as RingBase>::Element, _hom: &Self::Homomorphism) -> Self::Element {
915        el.el
916    }
917
918    fn mul_assign_map_in(&self, _from: &ZnFastmulBase, lhs: &mut Self::Element, rhs: <ZnFastmulBase as RingBase>::Element, _hom: &Self::Homomorphism) {
919        debug_assert!(lhs.0 <= self.repr_bound());
920        let lhs_original = lhs.0;
921        let product = mullo(lhs.0, rhs.el.0);
922        let approx_quotient = mulhi(lhs.0, rhs.value_invmod_shifted);
923        lhs.0 = product.wrapping_sub(mullo(approx_quotient, self.modulus_u64()));
924        debug_assert!(lhs.0 < self.modulus_times_three);
925        debug_assert!((lhs_original as u128 * rhs.el.0 as u128 - lhs.0 as u128) % (self.modulus_u64() as u128) == 0);
926    }
927
928    fn mul_assign_map_in_ref(&self, from: &ZnFastmulBase, lhs: &mut Self::Element, rhs: &<ZnFastmulBase as RingBase>::Element, hom: &Self::Homomorphism) {
929        self.mul_assign_map_in(from, lhs, *rhs, hom);
930    }
931}
932
933impl CanIsoFromTo<ZnFastmulBase> for ZnBase {
934
935    type Isomorphism = <ZnFastmulBase as CanHomFrom<Self>>::Homomorphism;
936
937    fn has_canonical_iso(&self, from: &ZnFastmulBase) -> Option<Self::Isomorphism> {
938        from.has_canonical_hom(self)
939    }
940
941    fn map_out(&self, from: &ZnFastmulBase, el: Self::Element, iso: &Self::Isomorphism) -> <ZnFastmulBase as RingBase>::Element {
942        from.map_in(self, el, iso)
943    }
944}
945
946impl CooleyTuckeyButterfly<ZnFastmulBase> for ZnBase {
947
948    #[inline(always)]
949    fn butterfly_new<H: Homomorphism<ZnFastmulBase, Self>>(hom: H, a: &mut ZnEl, b: &mut ZnEl, twiddle: &<ZnFastmulBase as RingBase>::Element) {
950        let self_ = hom.codomain().get_ring();
951        
952        a.0 = reduce_to_half(a.0, self_.modulus_times_three);
953        hom.mul_assign_ref_map(b, twiddle);
954
955        (a.0, b.0) = (a.0 + b.0, a.0 + self_.modulus_times_three - b.0);
956    }
957
958    #[inline(always)]
959    fn inv_butterfly_new<H: Homomorphism<ZnFastmulBase, Self>>(hom: H, a: &mut ZnEl, b: &mut ZnEl, twiddle: &<ZnFastmulBase as RingBase>::Element) {
960        let self_ = hom.codomain().get_ring();
961
962        // we assume that a, b are already at most `self.modulus_times_three`
963
964        (a.0, b.0) = (a.0 + b.0, a.0 + self_.modulus_times_three - b.0);
965        a.0 = reduce_to_half(a.0, self_.modulus_times_three);
966        hom.mul_assign_ref_map(b, twiddle);
967    }
968
969    #[inline(always)]
970    fn prepare_for_inv_fft(&self, value: &mut Self::Element) {
971        if value.0 >= self.modulus_times_three {
972            value.0 -= self.modulus_times_three;
973        }
974    }
975}
976
977impl CooleyTukeyRadix3Butterfly<ZnFastmulBase> for ZnBase {
978    
979    fn butterfly<H: Homomorphism<ZnFastmulBase, Self>>(
980        hom: H, 
981        a: &mut Self::Element, 
982        b: &mut Self::Element, 
983        c: &mut Self::Element, 
984        z: &ZnFastmulEl,
985        t: &ZnFastmulEl,
986        t_sqr_z_sqr: &ZnFastmulEl
987    ) {
988        let self_ = hom.codomain().get_ring();
989
990        hom.mul_assign_ref_map(b, t);
991        hom.mul_assign_ref_map(c, t_sqr_z_sqr);
992        let b_ = hom.mul_ref_map(b, z);
993        let c_ = hom.mul_ref_map(c, z);
994
995        let mut s1 = b.0 + c_.0;
996        let mut s2 = b_.0 + c.0;
997        a.0 = reduce_to_half(a.0, self_.modulus_times_three);
998        s1 = reduce_to_half(s1, self_.modulus_times_three);
999        s2 = reduce_to_half(s2, self_.modulus_times_three);
1000
1001        let mut s3 = s1 + s2;
1002        s3 = reduce_to_half(s3, self_.modulus_times_three);
1003
1004        b.0 = a.0 + s2;
1005        c.0 = a.0 + self_.modulus_times_three - s3;
1006        a.0 = a.0 + s1;
1007    }
1008    
1009    fn inv_butterfly<H: Homomorphism<ZnFastmulBase, Self>>(
1010        hom: H, 
1011        a: &mut Self::Element, 
1012        b: &mut Self::Element,
1013        c: &mut Self::Element,
1014        z: &ZnFastmulEl,
1015        t: &ZnFastmulEl,
1016        t_sqr: &ZnFastmulEl
1017    ) {
1018        let self_ = hom.codomain().get_ring();
1019
1020        // we assume that a, b, c are already at most `self.modulus_times_three`
1021
1022        let b_ = hom.mul_ref_map(b, z);
1023        let mut s1 = b.0 + c.0;
1024        s1 = reduce_to_half(s1, self_.modulus_times_three);
1025
1026        let s2 = b_.0 + c.0;
1027        let s2_ = hom.mul_ref_snd_map(self_.from_u64_promise_reduced(s2), z);
1028
1029        let mut s3 = s1 + s2_.0;
1030        s3 = reduce_to_half(s3, self_.modulus_times_three);
1031
1032        b.0 = a.0 + s2_.0;
1033        c.0 = a.0 + self_.modulus_times_three - s3;
1034        a.0 = a.0 + s1;
1035
1036        a.0 = reduce_to_half(a.0, self_.modulus_times_three);
1037        hom.mul_assign_ref_map(b, t);
1038        hom.mul_assign_ref_map(c, t_sqr);
1039    }
1040
1041    #[inline(always)]
1042    fn prepare_for_fft(&self, _value: &mut Self::Element) {}
1043    
1044    #[inline(always)]
1045    fn prepare_for_inv_fft(&self, value: &mut Self::Element) {
1046        if value.0 >= self.modulus_times_three {
1047            value.0 -= self.modulus_times_three
1048        }
1049    }
1050}
1051
1052impl CooleyTuckeyButterfly<ZnBase> for ZnBase {
1053
1054    #[inline(always)]
1055    fn butterfly_new<H: Homomorphism<Self, Self>>(hom: H, a: &mut ZnEl, b: &mut ZnEl, twiddle: &ZnEl) {
1056        let self_ = hom.codomain().get_ring();
1057        
1058        a.0 = reduce_to_half(a.0, self_.modulus_times_three);
1059        hom.mul_assign_ref_map(b, twiddle);
1060
1061        (a.0, b.0) = (a.0 + b.0, a.0 + self_.modulus_times_three - b.0);
1062    }
1063
1064    #[inline(always)]
1065    fn inv_butterfly_new<H: Homomorphism<Self, Self>>(hom: H, a: &mut ZnEl, b: &mut ZnEl, twiddle: &ZnEl) {
1066        let self_ = hom.codomain().get_ring();
1067
1068        (a.0, b.0) = (a.0 + b.0, a.0 + self_.modulus_times_three - b.0);
1069        a.0 = reduce_to_half(a.0, self_.modulus_times_three);
1070        hom.mul_assign_ref_map(b, twiddle);
1071    }
1072    
1073    #[inline(always)]
1074    fn prepare_for_inv_fft(&self, value: &mut Self::Element) {
1075        if value.0 >= self.modulus_times_three {
1076            value.0 -= self.modulus_times_three;
1077        }
1078    }
1079}
1080
1081impl CooleyTukeyRadix3Butterfly<ZnBase> for ZnBase {
1082    
1083    fn butterfly<H: Homomorphism<ZnBase, Self>>(
1084        hom: H, 
1085        a: &mut Self::Element, 
1086        b: &mut Self::Element, 
1087        c: &mut Self::Element, 
1088        z: &ZnEl,
1089        t: &ZnEl,
1090        t_sqr_z_sqr: &ZnEl
1091    ) {
1092        let self_ = hom.codomain().get_ring();
1093
1094        hom.mul_assign_ref_map(b, t);
1095        hom.mul_assign_ref_map(c, t_sqr_z_sqr);
1096        let b_ = hom.mul_ref_map(b, z);
1097        let c_ = hom.mul_ref_map(c, z);
1098
1099        let mut s1 = b.0 + c_.0;
1100        let mut s2 = b_.0 + c.0;
1101        a.0 = reduce_to_half(a.0, self_.modulus_times_three);
1102        s1 = reduce_to_half(s1, self_.modulus_times_three);
1103        s2 = reduce_to_half(s2, self_.modulus_times_three);
1104        let mut s3 = s1 + s2;
1105        s3 = reduce_to_half(s3, self_.modulus_times_three);
1106
1107        b.0 = a.0 + s2;
1108        c.0 = a.0 + self_.modulus_times_three - s3;
1109        a.0 = a.0 + s1;
1110    }
1111    
1112    fn inv_butterfly<H: Homomorphism<ZnBase, Self>>(
1113        hom: H, 
1114        a: &mut Self::Element, 
1115        b: &mut Self::Element,
1116        c: &mut Self::Element,
1117        z: &ZnEl,
1118        t: &ZnEl,
1119        t_sqr: &ZnEl
1120    ) {
1121        let self_ = hom.codomain().get_ring();
1122
1123        // we assume that a, b, c are already at most `self.modulus_times_three`
1124
1125        let b_ = hom.mul_ref_map(b, z);
1126        let mut s1 = b.0 + c.0;
1127        s1 = reduce_to_half(s1, self_.modulus_times_three);
1128
1129        let s2 = b_.0 + c.0;
1130        let s2_ = hom.mul_ref_snd_map(self_.from_u64_promise_reduced(s2), z);
1131
1132        let mut s3 = s1 + s2_.0;
1133        s3 = reduce_to_half(s3, self_.modulus_times_three);
1134
1135        b.0 = a.0 + s2_.0;
1136        c.0 = a.0 + self_.modulus_times_three - s3;
1137        a.0 = a.0 + s1;
1138        a.0 = reduce_to_half(a.0, self_.modulus_times_three);
1139
1140        hom.mul_assign_ref_map(b, t);
1141        hom.mul_assign_ref_map(c, t_sqr);
1142    }
1143
1144    #[inline(always)]
1145    fn prepare_for_fft(&self, _value: &mut Self::Element) {}
1146    
1147    #[inline(always)]
1148    fn prepare_for_inv_fft(&self, value: &mut Self::Element) {
1149        if value.0 >= self.modulus_times_three {
1150            value.0 -= self.modulus_times_three
1151        }
1152    }
1153}
1154
1155impl<I: ?Sized + IntegerRing> CanHomFrom<I> for ZnFastmulBase 
1156    where ZnBase: CanHomFrom<I>
1157{
1158    type Homomorphism = <ZnBase as CanHomFrom<I>>::Homomorphism;
1159
1160    fn has_canonical_hom(&self, from: &I) -> Option<Self::Homomorphism> {
1161        self.base.get_ring().has_canonical_hom(from)
1162    }
1163
1164    fn map_in(&self, from: &I, el: I::Element, hom: &Self::Homomorphism) -> Self::Element {
1165        self.rev_delegate(self.base.get_ring().map_in(from, el, hom))
1166    }
1167}
1168
1169impl_field_wrap_unwrap_homs!{ ZnBase, ZnBase }
1170impl_field_wrap_unwrap_isos!{ ZnBase, ZnBase }
1171impl_localpir_wrap_unwrap_homs!{ ZnBase, ZnBase }
1172impl_localpir_wrap_unwrap_isos!{ ZnBase, ZnBase }
1173
1174impl<I> CanHomFrom<zn_big::ZnBase<I>> for AsFieldBase<Zn>
1175    where I: RingStore,
1176        I::Type: IntegerRing
1177{
1178    type Homomorphism = <ZnBase as CanHomFrom<zn_big::ZnBase<I>>>::Homomorphism;
1179
1180    fn has_canonical_hom(&self, from: &zn_big::ZnBase<I>) -> Option<Self::Homomorphism> {
1181        self.get_delegate().has_canonical_hom(from)
1182    }
1183
1184    fn map_in(&self, from: &zn_big::ZnBase<I>, el: <zn_big::ZnBase<I> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
1185        self.rev_delegate(self.get_delegate().map_in(from, el, hom))
1186    }
1187}
1188
1189impl<I> CanIsoFromTo<zn_big::ZnBase<I>> for AsFieldBase<Zn>
1190    where I: RingStore,
1191        I::Type: IntegerRing
1192{
1193    type Isomorphism = <ZnBase as CanIsoFromTo<zn_big::ZnBase<I>>>::Isomorphism;
1194
1195    fn has_canonical_iso(&self, from: &zn_big::ZnBase<I>) -> Option<Self::Isomorphism> {
1196        self.get_delegate().has_canonical_iso(from)
1197    }
1198
1199    fn map_out(&self, from: &zn_big::ZnBase<I>, el: Self::Element, hom: &Self::Isomorphism) -> <zn_big::ZnBase<I> as RingBase>::Element {
1200        self.get_delegate().map_out(from, self.delegate(el), hom)
1201    }
1202}
1203
1204#[cfg(test)]
1205use test::Bencher;
1206
1207#[cfg(test)]
1208fn elements<'a>(ring: &'a Zn) -> impl 'a + Iterator<Item = El<Zn>> {
1209    (0..63).map(|i| ring.coerce(&StaticRing::<i64>::RING, 1 << i))
1210}
1211
1212#[cfg(test)]
1213const LARGE_MODULI: [u64; 6] = [(1 << 41) - 1, (1 << 42) - 1, (1 << 58) - 1, (1 << 58) + 1, (3 << 57) - 1, (3 << 57) + 1];
1214
1215#[test]
1216fn test_complete_reduce() {
1217    let ring = Zn::new(32);
1218    assert_eq!(31, ring.get_ring().complete_reduce(4 * 32 - 1));
1219}
1220
1221#[test]
1222fn test_sum() {
1223    for n in LARGE_MODULI {
1224        let Zn = Zn::new(n);
1225        assert_el_eq!(Zn, Zn.int_hom().map(10001 * 5000), Zn.sum((0..=10000).map(|x| Zn.int_hom().map(x))));
1226    }
1227}
1228
1229#[test]
1230fn test_ring_axioms() {
1231    for n in 2..=17 {
1232        let ring = Zn::new(n);
1233        crate::ring::generic_tests::test_ring_axioms(&ring, (0..=ring.get_ring().repr_bound()).map(|n| ZnEl(n)));
1234    }
1235    for n in LARGE_MODULI {
1236        let ring = Zn::new(n);
1237        crate::ring::generic_tests::test_ring_axioms(&ring, elements(&ring));
1238    }
1239}
1240
1241#[test]
1242fn test_hash_axioms() {
1243    for n in 2..=17 {
1244        let ring = Zn::new(n);
1245        crate::ring::generic_tests::test_hash_axioms(&ring, (0..=ring.get_ring().repr_bound()).map(|n| ZnEl(n)));
1246    }
1247    for n in LARGE_MODULI {
1248        let ring = Zn::new(n);
1249        crate::ring::generic_tests::test_hash_axioms(&ring, elements(&ring));
1250    }
1251}
1252
1253#[test]
1254fn test_divisibility_axioms() {
1255    for n in 2..=17 {
1256        let Zn = Zn::new(n);
1257        crate::divisibility::generic_tests::test_divisibility_axioms(&Zn, Zn.elements());
1258    }
1259    for n in LARGE_MODULI {
1260        let Zn = Zn::new(n);
1261        crate::divisibility::generic_tests::test_divisibility_axioms(&Zn, elements(&Zn));
1262    }
1263}
1264
1265#[test]
1266fn test_zn_axioms() {
1267    for n in 2..=17 {
1268        let Zn = Zn::new(n);
1269        super::generic_tests::test_zn_axioms(&Zn);
1270    }
1271}
1272
1273#[test]
1274fn test_principal_ideal_ring_axioms() {
1275    for n in 2..=17 {
1276        let R = Zn::new(n);
1277        crate::pid::generic_tests::test_principal_ideal_ring_axioms(R, R.elements());
1278    }
1279    let R = Zn::new(63);
1280    crate::pid::generic_tests::test_principal_ideal_ring_axioms(R, R.elements());
1281}
1282
1283#[test]
1284fn test_hom_from_fastmul() {
1285    for n in 2..=17 {
1286        let Zn = Zn::new(n);
1287        let Zn_fastmul = ZnFastmul::new(Zn).unwrap();
1288        crate::ring::generic_tests::test_hom_axioms(Zn_fastmul, Zn, Zn.elements().map(|x| Zn_fastmul.coerce(&Zn, x)));
1289    }
1290    for n in [(1 << 41) - 1, (1 << 42) - 1, (1 << 58) - 1, (1 << 58) + 1, (3 << 57) - 1, (3 << 57) + 1] {
1291        let Zn = Zn::new(n);
1292        let Zn_fastmul = ZnFastmul::new(Zn).unwrap();
1293        crate::ring::generic_tests::test_hom_axioms(Zn_fastmul, Zn, elements(&Zn).map(|x| Zn_fastmul.coerce(&Zn, x)));
1294    }
1295}
1296
1297#[test]
1298fn test_finite_ring_axioms() {
1299    for n in 2..=17 {
1300        crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::new(n));
1301    }
1302    crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::new(128));
1303    crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::new(1 << 32));
1304}
1305
1306#[test]
1307fn test_from_int_hom() {
1308    for n in 2..=17 {
1309        let Zn = Zn::new(n);
1310        crate::ring::generic_tests::test_hom_axioms(StaticRing::<i8>::RING, Zn, -8..8);
1311        crate::ring::generic_tests::test_hom_axioms(StaticRing::<i16>::RING, Zn, -8..8);
1312        crate::ring::generic_tests::test_hom_axioms(StaticRing::<i32>::RING, Zn, -8..8);
1313        crate::ring::generic_tests::test_hom_axioms(StaticRing::<i64>::RING, Zn, -8..8);
1314        crate::ring::generic_tests::test_hom_axioms(StaticRing::<i128>::RING, Zn, -8..8);
1315    }
1316    let Zn = Zn::new(5);
1317    assert_el_eq!(Zn, Zn.int_hom().map(3), Zn.can_hom(&StaticRing::<i64>::RING).unwrap().map(-1596802));
1318}
1319
1320#[test]
1321fn test_bounded_reduce_large() {
1322    const FACTOR: usize = 32;
1323    let n_max = (1 << 62) / 9;
1324    for n in (n_max - 10)..=n_max {
1325        let Zn = Zn::new(n);
1326        let val_max = Zn.get_ring().repr_bound() as u128 * Zn.get_ring().repr_bound() as u128 * FACTOR as u128;
1327        for k in (val_max - 100)..=val_max {
1328            assert_eq!((k % (n as u128)) as i64, Zn.smallest_positive_lift(ZnEl(Zn.get_ring().bounded_reduce_larger::<FACTOR>(k))));
1329        }
1330    }
1331}
1332
1333#[test]
1334fn test_smallest_lift() {
1335    for n in 2..=17 {
1336        let ring = Zn::new(n);
1337        for k in 0..=ring.get_ring().repr_bound() {
1338            let expected = if (k % n) <= n / 2 { (k % n) as i64 } else { (k % n) as i64 - n as i64 };
1339            if n % 2 == 0 && (k % n) == n / 2 {
1340                assert!(ring.smallest_lift(ZnEl(k)) == n as i64 / 2 || ring.smallest_lift(ZnEl(k)) == -(n as i64) / 2)
1341            } else {
1342                assert_eq!(expected, ring.smallest_lift(ZnEl(k)));
1343            }
1344        }
1345    }
1346}
1347
1348#[test]
1349fn test_smallest_positive_lift() {
1350    for n in 2..=17 {
1351        let ring = Zn::new(n);
1352        for k in 0..=ring.get_ring().repr_bound() {
1353            let expected = (k % n) as i64;
1354            assert_eq!(expected, ring.smallest_positive_lift(ZnEl(k)));
1355        }
1356    }
1357}
1358
1359#[test]
1360fn test_bounded_reduce_small() {
1361    for n in 2..=17 {
1362        let Zn = Zn::new(n);
1363        let val_max = Zn.get_ring().repr_bound() as u128 * Zn.get_ring().repr_bound() as u128;
1364        for k in (val_max - 100)..=val_max {
1365            assert_eq!((k % (n as u128)) as i64, Zn.smallest_positive_lift(ZnEl(Zn.get_ring().bounded_reduce(k))));
1366        }
1367    }
1368}
1369
1370#[test]
1371fn test_bounded_reduce_large_small() {
1372    const FACTOR: usize = 32;
1373    for n in 2..=17 {
1374        let Zn = Zn::new(n);
1375        let val_max = Zn.get_ring().repr_bound() as u128 * Zn.get_ring().repr_bound() as u128 * FACTOR as u128;
1376        for k in (val_max - 100)..=val_max {
1377            assert_eq!((k % (n as u128)) as i64, Zn.smallest_positive_lift(ZnEl(Zn.get_ring().bounded_reduce_larger::<FACTOR>(k))));
1378        }
1379    }
1380}
1381
1382#[test]
1383fn test_bounded_reduce() {
1384    let n_max = (1 << 62) / 9;
1385    for n in (n_max - 10)..=n_max {
1386        let Zn = Zn::new(n);
1387        let val_max = Zn.get_ring().repr_bound() as u128 * Zn.get_ring().repr_bound() as u128;
1388        for k in (val_max - 100)..=val_max {
1389            assert_eq!((k % (n as u128)) as i64, Zn.smallest_positive_lift(ZnEl(Zn.get_ring().bounded_reduce(k))));
1390        }
1391    }
1392}
1393
1394#[bench]
1395fn bench_hom_from_i64_large_modulus(bencher: &mut Bencher) {
1396    // the case that the modulus is large
1397    let Zn = Zn::new(36028797018963971 /* = 2^55 + 3 */);
1398    bencher.iter(|| {
1399        let hom = Zn.can_hom(&StaticRing::<i64>::RING).unwrap();
1400        assert_el_eq!(Zn, Zn.int_hom().map(-1300), Zn.sum((0..100).flat_map(|_| (0..=56).map(|k| 1 << k)).map(|x| hom.map(x))))
1401    });
1402}
1403
1404#[bench]
1405fn bench_hom_from_i64_small_modulus(bencher: &mut Bencher) {
1406    // the case that the modulus is large
1407    let Zn = Zn::new(17);
1408    bencher.iter(|| {
1409        let hom = Zn.can_hom(&StaticRing::<i64>::RING).unwrap();
1410        assert_el_eq!(Zn, Zn.int_hom().map(2850 * 5699), Zn.sum((0..5700).map(|x| hom.map(x))))
1411    });
1412}
1413
1414#[bench]
1415fn bench_reduction_map_use_case(bencher: &mut Bencher) {
1416    // this benchmark is inspired by the use in https://eprint.iacr.org/2023/1510.pdf
1417    let p = 17;
1418    let Zp2 = Zn::new(p * p);
1419    let Zp = Zn::new(p);
1420    let Zp2_mod_p = ZnReductionMap::new(&Zp2, &Zp).unwrap();
1421    let Zp2_p = PreparedDivisor::new(Zp2.get_ring(), Zp2.int_hom().map(p as i32));
1422
1423    let split_quo_rem = |x: El<Zn>| {
1424        let rem = Zp2_mod_p.map_ref(&x);
1425        let Zp2_rem = Zp2_mod_p.smallest_lift(rem);
1426        let quo = Zp2_p.checked_left_div_by(&Zp2.sub(x, Zp2_rem), Zp2.get_ring()).unwrap();
1427        (rem, Zp2_mod_p.map(quo))
1428    };
1429
1430    bencher.iter(|| {
1431        for x in Zp2.elements() {
1432            for y in Zp2.elements() {
1433                let (x_low, x_high) = split_quo_rem(x);
1434                let (y_low, y_high) = split_quo_rem(y);
1435                assert_el_eq!(Zp2, Zp2.mul(x, y), &Zp2.add(Zp2.mul(Zp2_mod_p.smallest_lift(x_low), Zp2_mod_p.smallest_lift(y_low)), Zp2_mod_p.mul_quotient_fraction(Zp.add(Zp.mul(x_low, y_high), Zp.mul(x_high, y_low)))));
1436            }
1437        }
1438    });
1439}
1440
1441#[bench]
1442fn bench_inner_product(bencher: &mut Bencher) {
1443    let Fp = Zn::new(65537);
1444    let len = 1 << 12;
1445    let lhs = (0..len).map(|i| Fp.int_hom().map(i)).collect::<Vec<_>>();
1446    let rhs = (0..len).map(|i| Fp.int_hom().map(i)).collect::<Vec<_>>();
1447    let expected = (0..len).map(|i| Fp.int_hom().map(i * i)).fold(Fp.zero(), |l, r| Fp.add(l, r));
1448
1449    bencher.iter(|| {
1450        let actual = <_ as ComputeInnerProduct>::inner_product_ref(Fp.get_ring(), lhs.iter().zip(rhs.iter()).map(|x| std::hint::black_box(x)));
1451        assert_el_eq!(Fp, expected, actual);
1452    })
1453}
1454
1455#[test]
1456fn test_serialize() {
1457    let ring = Zn::new(128);
1458    crate::serialization::generic_tests::test_serialization(ring, ring.elements())
1459}