1use crate::algorithms::fft::cooley_tuckey::CooleyTuckeyButterfly;
2use crate::compute_locally::InterpolationBaseRing;
3use crate::delegate::DelegateRing;
4use crate::delegate::DelegateRingImplFiniteRing;
5use crate::divisibility::*;
6use crate::impl_eq_based_self_iso;
7use crate::impl_localpir_wrap_unwrap_homs;
8use crate::impl_localpir_wrap_unwrap_isos;
9use crate::impl_field_wrap_unwrap_homs;
10use crate::impl_field_wrap_unwrap_isos;
11use crate::ordered::OrderedRingStore;
12use crate::primitive_int::*;
13use crate::integer::*;
14use crate::pid::*;
15use crate::rings::extension::FreeAlgebraStore;
16use crate::ring::*;
17use crate::rings::extension::galois_field::*;
18use crate::seq::*;
19use crate::serialization::SerializableElementRing;
20use crate::algorithms::convolution::KaratsubaHint;
21use crate::algorithms::matmul::ComputeInnerProduct;
22use crate::algorithms::matmul::StrassenHint;
23use serde::de;
24use serde::{Deserialize, Deserializer, Serialize, Serializer};
25
26use crate::homomorphism::*;
27
28use super::*;
29use super::zn_big;
30
31fn high(x: u128) -> u64 {
32 (x >> 64) as u64
33}
34
35fn low(x: u128) -> u64 {
36 (x & ((1 << 64) - 1)) as u64
37}
38
39fn mulhi(lhs: u64, rhs: u64) -> u64 {
40 high(lhs as u128 * rhs as u128)
41}
42
43fn mullo(lhs: u64, rhs: u64) -> u64 {
44 lhs.wrapping_mul(rhs)
45}
46
47#[derive(Clone, Copy)]
75pub struct ZnBase {
76 modulus: i64,
77 modulus_half: i64,
78 modulus_times_three: u64,
79 inv_modulus: u128
80}
81
82const ZZ: StaticRing<i64> = StaticRing::<i64>::RING;
83#[allow(non_upper_case_globals)]
84const ZZbig: BigIntRing = BigIntRing::RING;
85
86impl ZnBase {
87
88 pub fn new(modulus: u64) -> Self {
89 assert!(modulus > 1);
90 assert!(modulus <= ((1 << 62) / 9));
92 assert!(modulus as u128 * 6 <= u64::MAX as u128);
94 let inv_modulus = ZZbig.euclidean_div(ZZbig.power_of_two(128), &ZZbig.coerce(&ZZ, modulus as i64));
95 debug_assert!(ZZbig.is_lt(&ZZbig.mul_ref_fst(&inv_modulus, ZZbig.pow(ZZbig.int_hom().mul_map(ZZbig.coerce(&ZZ, modulus as i64), 6), 2)), &ZZbig.power_of_two(192)));
97 let inv_modulus = if ZZbig.eq_el(&inv_modulus, &ZZbig.power_of_two(127)) {
98 1u128 << 127
99 } else {
100 int_cast(inv_modulus, &StaticRing::<i128>::RING, &ZZbig) as u128
101 };
102 Self {
103 modulus: modulus as i64,
104 inv_modulus: inv_modulus,
105 modulus_half: (modulus as i64 - 1) / 2 + 1,
106 modulus_times_three: modulus * 3
107 }
108 }
109
110 fn modulus_u64(&self) -> u64 {
111 self.modulus as u64
112 }
113
114 fn repr_bound(&self) -> u64 {
119 self.modulus_times_three * 2
120 }
121
122 fn bounded_reduce(&self, value: u128) -> u64 {
126 debug_assert!(value <= self.repr_bound() as u128 * self.repr_bound() as u128);
127
128 let (in_low, in_high) = (low(value), high(value));
129 let (invmod_low, invmod_high) = (low(self.inv_modulus), high(self.inv_modulus));
130 let approx_quotient = mulhi(in_low, invmod_high) + mulhi(in_high, invmod_low) + mullo(in_high, invmod_high);
133 let result = low(value).wrapping_sub(mullo(approx_quotient, self.modulus_u64()));
134
135 debug_assert!(result < self.modulus_times_three);
136 debug_assert!((value - result as u128) % (self.modulus_u64() as u128) == 0);
137 return result;
138 }
139
140 #[inline(never)]
148 fn bounded_reduce_larger<const FACTOR: usize>(&self, value: u128) -> u64 {
149 assert!(FACTOR == 32);
150 debug_assert!(value <= FACTOR as u128 * self.repr_bound() as u128 * self.repr_bound() as u128);
151
152 let (in_low, in_high) = (low(value), high(value));
153 let invmod_high = high(self.inv_modulus);
154 let approx_quotient = in_high as u128 * invmod_high as u128 + mulhi(in_low, invmod_high) as u128;
156
157 return self.bounded_reduce(value - (approx_quotient * self.modulus as u128));
158 }
159
160 fn potential_reduce(&self, mut value: u64) -> u64 {
164 debug_assert!(value as u128 <= 2 * self.repr_bound() as u128);
165 if value >= self.repr_bound() {
166 value -= self.repr_bound();
167 }
168 if value >= self.modulus_times_three {
169 value -= self.modulus_times_three;
170 }
171 debug_assert!(value <= self.modulus_times_three);
172 return value;
173 }
174
175 fn from_u64_promise_reduced(&self, value: u64) -> ZnEl {
183 debug_assert!(value <= self.repr_bound());
184 ZnEl(value)
185 }
186
187 fn complete_reduce(&self, mut value: u64) -> u64 {
191 debug_assert!(value <= self.repr_bound());
192 if value >= 4 * self.modulus_u64() {
193 value -= 4 * self.modulus_u64();
194 }
195 if value >= 2 * self.modulus_u64() {
196 value -= 2 * self.modulus_u64();
197 }
198 if value >= self.modulus_u64() {
199 value -= self.modulus_u64();
200 }
201 debug_assert!(value < self.modulus_u64());
202 return value;
203 }
204}
205
206pub type Zn = RingValue<ZnBase>;
211
212impl Zn {
213
214 pub fn new(modulus: u64) -> Self {
215 RingValue::from(ZnBase::new(modulus))
216 }
217}
218
219#[derive(Clone, Copy, Debug)]
220pub struct ZnEl(u64);
221
222impl PartialEq for ZnBase {
223 fn eq(&self, other: &Self) -> bool {
224 self.modulus == other.modulus
225 }
226}
227
228impl RingBase for ZnBase {
229
230 type Element = ZnEl;
231
232 fn clone_el(&self, val: &Self::Element) -> Self::Element {
233 *val
234 }
235
236 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
237 debug_assert!(lhs.0 <= self.repr_bound());
238 debug_assert!(rhs.0 <= self.repr_bound());
239 lhs.0 = self.potential_reduce(lhs.0 + rhs.0);
240 }
241
242 fn negate_inplace(&self, lhs: &mut Self::Element) {
243 debug_assert!(lhs.0 <= self.repr_bound());
244 lhs.0 = self.repr_bound() - lhs.0;
245 }
246
247 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
248 debug_assert!(lhs.0 <= self.repr_bound());
249 debug_assert!(rhs.0 <= self.repr_bound());
250 lhs.0 = self.bounded_reduce(lhs.0 as u128 * rhs.0 as u128);
251 }
252
253 fn from_int(&self, value: i32) -> Self::Element {
254 RingRef::new(self).coerce(&StaticRing::<i32>::RING, value)
255 }
256
257 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
258 debug_assert!(lhs.0 <= self.repr_bound());
259 debug_assert!(rhs.0 <= self.repr_bound());
260 if lhs.0 > rhs.0 {
261 self.is_zero(&self.from_u64_promise_reduced(lhs.0 - rhs.0))
262 } else {
263 self.is_zero(&self.from_u64_promise_reduced(rhs.0 - lhs.0))
264 }
265 }
266
267 fn is_zero(&self, val: &Self::Element) -> bool {
268 debug_assert!(val.0 <= self.repr_bound());
269 self.complete_reduce(val.0) == 0
270 }
271
272 fn is_commutative(&self) -> bool { true }
273 fn is_noetherian(&self) -> bool { true }
274
275 fn dbg_within<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>, _: EnvBindingStrength) -> std::fmt::Result {
276 write!(out, "{}", self.complete_reduce(value.0))
277 }
278
279 fn characteristic<I: RingStore + Copy>(&self, other_ZZ: I) -> Option<El<I>>
280 where I::Type: IntegerRing
281 {
282 self.size(other_ZZ)
283 }
284
285 fn sum<I>(&self, els: I) -> Self::Element
286 where I: IntoIterator<Item = Self::Element>
287 {
288 let mut result = self.zero();
289 let mut els_it = els.into_iter();
290 while let Some(ZnEl(start)) = els_it.next() {
291 let mut current = start as u128;
292 for ZnEl(c) in els_it.by_ref().take(self.repr_bound() as usize / 2 - 1) {
293 current += c as u128;
294 }
295 self.add_assign(&mut result, self.from_u64_promise_reduced(self.bounded_reduce(current)));
296 }
297 debug_assert!(result.0 <= self.repr_bound());
298 return result;
299 }
300
301 fn pow_gen<R: RingStore>(&self, x: Self::Element, power: &El<R>, integers: R) -> Self::Element
302 where R::Type: IntegerRing
303 {
304 assert!(!integers.is_neg(power));
305 algorithms::sqr_mul::generic_abs_square_and_multiply(
306 x,
307 power,
308 &integers,
309 |mut a| {
310 self.square(&mut a);
311 a
312 },
313 |a, b| self.mul_ref_fst(a, b),
314 self.one()
315 )
316 }
317
318 fn is_approximate(&self) -> bool { false }
319}
320
321impl SerializableElementRing for ZnBase {
322
323 fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
324 where D: Deserializer<'de>
325 {
326 <i64 as Deserialize>::deserialize(deserializer)
327 .and_then(|x| if x < 0 || x >= *self.modulus() { Err(de::Error::custom("ring element value out of bounds for ring Z/nZ")) } else { Ok(x) })
328 .map(|x| self.from_int_promise_reduced(x))
329 }
330
331 fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
332 where S: Serializer
333 {
334 <i64 as Serialize>::serialize(&self.smallest_positive_lift(*el), serializer)
335 }
336}
337
338impl FromModulusCreateableZnRing for ZnBase {
339
340 fn create<F, E>(create_modulus: F) -> Result<Self, E>
341 where F: FnOnce(&Self::IntegerRingBase) -> Result<El<Self::IntegerRing>, E>
342 {
343 create_modulus(StaticRing::<i64>::RING.get_ring()).map(|n| Self::new(n as u64))
344 }
345}
346
347impl InterpolationBaseRing for AsFieldBase<Zn> {
348
349 type ExtendedRingBase<'a> = GaloisFieldBaseOver<RingRef<'a, Self>>
350 where Self: 'a;
351
352 type ExtendedRing<'a> = GaloisFieldOver<RingRef<'a, Self>>
353 where Self: 'a;
354
355 fn in_base<'a, S>(&self, ext_ring: S, el: El<S>) -> Option<Self::Element>
356 where Self: 'a, S: RingStore<Type = Self::ExtendedRingBase<'a>>
357 {
358 let wrt_basis = ext_ring.wrt_canonical_basis(&el);
359 if wrt_basis.iter().skip(1).all(|x| self.is_zero(&x)) {
360 return Some(wrt_basis.at(0));
361 } else {
362 return None;
363 }
364 }
365
366 fn in_extension<'a, S>(&self, ext_ring: S, el: Self::Element) -> El<S>
367 where Self: 'a, S: RingStore<Type = Self::ExtendedRingBase<'a>>
368 {
369 ext_ring.inclusion().map(el)
370 }
371
372 fn interpolation_points<'a>(&'a self, count: usize) -> (Self::ExtendedRing<'a>, Vec<El<Self::ExtendedRing<'a>>>) {
373 let ring = generic_impls::interpolation_ring(RingRef::new(self), count);
374 let points = ring.elements().take(count).collect();
375 return (ring, points);
376 }
377}
378
379impl ComputeInnerProduct for ZnBase {
380
381 fn inner_product<I: Iterator<Item = (Self::Element, Self::Element)>>(&self, mut els: I) -> Self::Element
382 {
383 fn body<I: Iterator<Item = (ZnEl, ZnEl)>>(ring: &ZnBase, els: &mut I) -> Option<ZnEl> {
384 debug_assert!(u128::MAX / (ring.repr_bound() as u128 * ring.repr_bound() as u128) >= 36);
385 const REDUCE_AFTER_STEPS: usize = 32;
386
387 let mut current = 0;
388 for i in 0..REDUCE_AFTER_STEPS {
389 let next_pair = els.next();
390 if let Some((l, r)) = next_pair {
391 debug_assert!(l.0 <= ring.repr_bound());
392 debug_assert!(r.0 <= ring.repr_bound());
393 current += l.0 as u128 * r.0 as u128;
394 debug_assert!(current <= (i + 1) as u128 * ring.repr_bound() as u128 * ring.repr_bound() as u128);
395 } else if i == 0 {
396 return None;
397 } else {
398 break;
399 }
400 }
401 return Some(ZnEl(ring.bounded_reduce_larger::<REDUCE_AFTER_STEPS>(current)));
402 }
403
404 self.sum((0..).map(|_| body(self, &mut els)).take_while(|x| x.is_some()).map(|x| x.unwrap()))
405 }
406
407 fn inner_product_ref_fst<'a, I: Iterator<Item = (&'a Self::Element, Self::Element)>>(&self, els: I) -> Self::Element
408 where Self::Element: 'a
409 {
410 self.inner_product(els.map(|(l, r)| (self.clone_el(l), r)))
411 }
412
413 fn inner_product_ref<'a, I: Iterator<Item = (&'a Self::Element, &'a Self::Element)>>(&self, els: I) -> Self::Element
414 where Self::Element: 'a
415 {
416 self.inner_product_ref_fst(els.map(|(l, r)| (l, self.clone_el(r))))
417 }
418}
419
420impl_eq_based_self_iso!{ ZnBase }
421
422impl<I: RingStore> CanHomFrom<zn_big::ZnBase<I>> for ZnBase
423 where I::Type: IntegerRing
424{
425 type Homomorphism = ();
426
427 fn has_canonical_hom(&self, from: &zn_big::ZnBase<I>) -> Option<Self::Homomorphism> {
428 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() {
429 if from.integer_ring().eq_el(from.modulus(), &int_cast(*self.modulus(), from.integer_ring(), self.integer_ring())) {
430 Some(())
431 } else {
432 None
433 }
434 } else {
435 None
436 }
437 }
438
439 fn map_in(&self, from: &zn_big::ZnBase<I>, el: <zn_big::ZnBase<I> as RingBase>::Element, _: &Self::Homomorphism) -> Self::Element {
440 self.from_u64_promise_reduced(int_cast(from.smallest_positive_lift(el), self.integer_ring(), from.integer_ring()) as u64)
441 }
442}
443
444impl<I: RingStore> CanIsoFromTo<zn_big::ZnBase<I>> for ZnBase
445 where I::Type: IntegerRing
446{
447 type Isomorphism = <zn_big::ZnBase<I> as CanHomFrom<StaticRingBase<i64>>>::Homomorphism;
448
449 fn has_canonical_iso(&self, from: &zn_big::ZnBase<I>) -> Option<Self::Isomorphism> {
450 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() {
451 if from.integer_ring().eq_el(from.modulus(), &int_cast(*self.modulus(), from.integer_ring(), self.integer_ring())) {
452 from.has_canonical_hom(self.integer_ring().get_ring())
453 } else {
454 None
455 }
456 } else {
457 None
458 }
459 }
460
461 fn map_out(&self, from: &zn_big::ZnBase<I>, el: <Self as RingBase>::Element, iso: &Self::Isomorphism) -> <zn_big::ZnBase<I> as RingBase>::Element {
462 from.map_in(self.integer_ring().get_ring(), el.0 as i64, iso)
463 }
464}
465
466#[derive(Copy, Clone, Debug)]
471pub struct ZnPreparedDivisorData {
472 unit_part: El<Zn>,
473 is_unit: bool,
474 smallest_positive_zero_divisor_part: PreparedDivisor<StaticRingBase<i64>>
475}
476
477impl DivisibilityRing for ZnBase {
478
479 type PreparedDivisorData = ZnPreparedDivisorData;
480
481 fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
482 super::generic_impls::checked_left_div(RingRef::new(self), lhs, rhs)
483 }
484
485 fn prepare_divisor(&self, x: Self::Element) -> PreparedDivisor<Self> {
486 let (s, _t, d) = algorithms::eea::signed_eea(self.smallest_positive_lift(x), *self.modulus(), self.integer_ring());
487 debug_assert!(d > 0);
488 debug_assert!(d <= *self.modulus());
489 return PreparedDivisor {
490 data: ZnPreparedDivisorData {
491 is_unit: d == 1,
492 unit_part: if s < 0 { self.negate(self.from_u64_promise_reduced(-s as u64)) } else { self.from_u64_promise_reduced(s as u64) },
493 smallest_positive_zero_divisor_part: StaticRing::<i64>::RING.get_ring().prepare_divisor(d)
494 },
495 element: x
496 };
497 }
498
499 fn checked_left_div_prepared(&self, lhs: &Self::Element, rhs: &PreparedDivisor<Self>) -> Option<Self::Element> {
500 if rhs.data.is_unit {
501 Some(self.mul_ref(lhs, &rhs.data.unit_part))
502 } else {
503 StaticRing::<i64>::RING.get_ring().checked_left_div_prepared(&self.smallest_positive_lift(*lhs), &rhs.data.smallest_positive_zero_divisor_part)
504 .map(|x| self.mul(self.from_u64_promise_reduced(x as u64), rhs.data.unit_part))
505 }
506 }
507
508 fn divides_left_prepared(&self, lhs: &Self::Element, rhs: &PreparedDivisor<Self>) -> bool {
509 self.checked_left_div_prepared(lhs, rhs).is_some()
510 }
511}
512
513impl<I: ?Sized + IntegerRing> CanHomFrom<I> for ZnBase {
514
515 type Homomorphism = super::generic_impls::BigIntToZnHom<I, StaticRingBase<i128>, Self>;
516
517 default fn has_canonical_hom(&self, from: &I) -> Option<Self::Homomorphism> {
518 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)))
519 }
520
521 default fn map_in(&self, from: &I, el: I::Element, hom: &Self::Homomorphism) -> Self::Element {
522 super::generic_impls::map_in_from_bigint(from, self, StaticRing::<i128>::RING.get_ring(), el, hom, |n| {
523 debug_assert!((n as u64) < self.modulus_u64());
524 self.from_u64_promise_reduced(n as u64)
525 }, |n| {
526 debug_assert!(n <= (self.repr_bound() as i128 * self.repr_bound() as i128));
527 self.from_u64_promise_reduced(self.bounded_reduce(n as u128))
528 })
529 }
530}
531
532macro_rules! impl_static_int_to_zn {
533 ($($int:ident),*) => {
534 $(
535 impl CanHomFrom<StaticRingBase<$int>> for ZnBase {
536
537 fn map_in(&self, _from: &StaticRingBase<$int>, el: $int, _hom: &Self::Homomorphism) -> Self::Element {
538 if el.abs() as u128 <= self.modulus_u64() as u128 {
539 if el < 0 {
540 self.negate(self.from_u64_promise_reduced(el.unsigned_abs() as u64))
541 } else {
542 self.from_u64_promise_reduced(el as u64)
543 }
544 } else if el.abs() as u128 <= self.repr_bound() as u128 {
545 if el < 0 {
546 self.negate(self.from_u64_promise_reduced(self.bounded_reduce(el.unsigned_abs() as u128)))
547 } else {
548 self.from_u64_promise_reduced(self.bounded_reduce(el as u128))
549 }
550 } else {
551 if el < 0 {
552 self.from_u64_promise_reduced(((el as i128 % self.modulus as i128) as i64 + self.modulus) as u64)
553 } else {
554 self.from_u64_promise_reduced((el as i128 % self.modulus as i128) as u64)
555 }
556 }
557 }
558 }
559 )*
560 };
561}
562
563impl_static_int_to_zn!{ i8, i16, i32, i64, i128 }
564
565#[derive(Clone, Copy)]
566pub struct ZnBaseElementsIter<'a> {
567 ring: &'a ZnBase,
568 current: u64
569}
570
571impl<'a> Iterator for ZnBaseElementsIter<'a> {
572
573 type Item = ZnEl;
574
575 fn next(&mut self) -> Option<Self::Item> {
576 if self.current < self.ring.modulus_u64() {
577 let result = self.current;
578 self.current += 1;
579 return Some(self.ring.from_u64_promise_reduced(result));
580 } else {
581 return None;
582 }
583 }
584}
585
586impl FiniteRing for ZnBase {
587
588 type ElementsIter<'a> = ZnBaseElementsIter<'a>;
589
590 fn elements<'a>(&'a self) -> Self::ElementsIter<'a> {
591 ZnBaseElementsIter {
592 ring: self,
593 current: 0
594 }
595 }
596
597 fn random_element<G: FnMut() -> u64>(&self, rng: G) -> <Self as RingBase>::Element {
598 super::generic_impls::random_element(self, rng)
599 }
600
601 fn size<I: RingStore + Copy>(&self, other_ZZ: I) -> Option<El<I>>
602 where I::Type: IntegerRing
603 {
604 if other_ZZ.get_ring().representable_bits().is_none() || self.integer_ring().abs_log2_ceil(&(self.modulus() + 1)) <= other_ZZ.get_ring().representable_bits() {
605 Some(int_cast(*self.modulus(), other_ZZ, self.integer_ring()))
606 } else {
607 None
608 }
609 }
610}
611
612impl PrincipalIdealRing for ZnBase {
613
614 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
615 generic_impls::checked_div_min(RingRef::new(self), lhs, rhs)
616 }
617
618 fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
619 let (s, t, d) = StaticRing::<i64>::RING.extended_ideal_gen(&(lhs.0 as i64), &(rhs.0 as i64));
620 let quo = RingRef::new(self).into_can_hom(StaticRing::<i64>::RING).ok().unwrap();
621 (quo.map(s), quo.map(t), quo.map(d))
622 }
623}
624
625impl StrassenHint for ZnBase {
626 default fn strassen_threshold(&self) -> usize {
627 6
628 }
629}
630
631impl KaratsubaHint for ZnBase {
632 default fn karatsuba_threshold(&self) -> usize {
633 6
634 }
635}
636
637impl ZnRing for ZnBase {
638
639 type IntegerRingBase = StaticRingBase<i64>;
640 type IntegerRing = StaticRing<i64>;
641
642 fn integer_ring(&self) -> &Self::IntegerRing {
643 &StaticRing::<i64>::RING
644 }
645
646 fn smallest_positive_lift(&self, el: Self::Element) -> El<Self::IntegerRing> {
647 self.complete_reduce(el.0) as i64
648 }
649
650 fn smallest_lift(&self, ZnEl(mut value_u64): Self::Element) -> El<Self::IntegerRing> {
651 debug_assert!(value_u64 <= self.repr_bound());
652 if value_u64 >= 3 * self.modulus_u64() {
654 value_u64 -= 3 * self.modulus_u64();
655 }
656 let mut value_i64 = value_u64 as i64;
658 if value_i64 >= self.modulus + self.modulus_half {
659 value_i64 -= 2 * self.modulus;
660 }
661 if value_i64 >= self.modulus_half {
664 value_i64 -= self.modulus;
665 }
666 debug_assert!(value_i64 < self.modulus_half);
669 debug_assert!(self.modulus() % 2 == 0 || value_i64 > -self.modulus_half);
670 debug_assert!(self.modulus() % 2 == 1 || value_i64 >= -self.modulus_half);
671 return value_i64;
672 }
673
674 fn modulus(&self) -> &El<Self::IntegerRing> {
675 &self.modulus
676 }
677
678 fn any_lift(&self, el: Self::Element) -> El<Self::IntegerRing> {
679 el.0 as i64
680 }
681
682 fn from_int_promise_reduced(&self, x: El<Self::IntegerRing>) -> Self::Element {
709 debug_assert!(self.repr_bound() == 6 * self.modulus_u64());
710 debug_assert!(x >= 0);
711 debug_assert!(x as u64 <= self.repr_bound());
712 self.from_u64_promise_reduced(x as u64)
713 }
714}
715
716impl HashableElRing for ZnBase {
717
718 fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H) {
719 self.integer_ring().hash(&self.smallest_positive_lift(*el), h)
720 }
721}
722
723#[derive(Clone, Copy)]
751pub struct ZnFastmulBase {
752 base: RingValue<ZnBase>
753}
754
755pub type ZnFastmul = RingValue<ZnFastmulBase>;
760
761impl ZnFastmul {
762
763 pub fn new(base: Zn) -> Option<Self> {
764 Some(RingValue::from(ZnFastmulBase { base }))
765 }
766}
767
768impl PartialEq for ZnFastmulBase {
769
770 fn eq(&self, other: &Self) -> bool {
771 self.base.get_ring() == other.base.get_ring()
772 }
773}
774
775impl PrincipalIdealRing for ZnFastmulBase {
776
777 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
778 let result = self.get_delegate().checked_div_min(self.delegate_ref(lhs), self.delegate_ref(rhs));
779 result.map(|x| self.rev_delegate(x))
780 }
781
782 fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
783 let (s, t, d) = self.get_delegate().extended_ideal_gen(self.delegate_ref(lhs), self.delegate_ref(rhs));
784 (self.rev_delegate(s), self.rev_delegate(t), self.rev_delegate(d))
785 }
786}
787
788impl_eq_based_self_iso!{ ZnFastmulBase }
789
790#[derive(Clone, Copy)]
791pub struct ZnFastmulEl {
792 el: ZnEl,
793 value_invmod_shifted: u64
794}
795
796impl DelegateRing for ZnFastmulBase {
797
798 type Base = ZnBase;
799 type Element = ZnFastmulEl;
800
801 fn get_delegate(&self) -> &Self::Base {
802 self.base.get_ring()
803 }
804
805 fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element {
806 el.el
807 }
808
809 fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element {
810 &mut el.el
811 }
812
813 fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element {
814 &el.el
815 }
816
817 fn postprocess_delegate_mut(&self, el: &mut Self::Element) {
818 assert!(el.el.0 <= self.base.get_ring().repr_bound());
819 el.el.0 = self.base.get_ring().complete_reduce(el.el.0);
820 let value = el.el.0;
821 el.value_invmod_shifted = (((value as u128) << 64) / self.base.get_ring().modulus_u64() as u128) as u64;
822 }
823
824 fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element {
825 let mut result = ZnFastmulEl {
826 el: el,
827 value_invmod_shifted: 0
828 };
829 self.postprocess_delegate_mut(&mut result);
830 return result;
831 }
832}
833
834impl DelegateRingImplFiniteRing for ZnFastmulBase {}
835
836impl CanHomFrom<ZnBase> for ZnFastmulBase {
837
838 type Homomorphism = ();
839
840 fn has_canonical_hom(&self, from: &ZnBase) -> Option<Self::Homomorphism> {
841 if from == self.base.get_ring() {
842 Some(())
843 } else {
844 None
845 }
846 }
847
848 fn map_in(&self, _from: &ZnBase, el: <ZnBase as RingBase>::Element, _hom: &Self::Homomorphism) -> Self::Element {
849 self.rev_delegate(el)
850 }
851}
852
853impl CanHomFrom<ZnFastmulBase> for ZnBase {
854
855 type Homomorphism = ();
856
857 fn has_canonical_hom(&self, from: &ZnFastmulBase) -> Option<Self::Homomorphism> {
858 if self == from.base.get_ring() {
859 Some(())
860 } else {
861 None
862 }
863 }
864
865 fn map_in(&self, _from: &ZnFastmulBase, el: <ZnFastmulBase as RingBase>::Element, _hom: &Self::Homomorphism) -> Self::Element {
866 el.el
867 }
868
869 fn mul_assign_map_in(&self, _from: &ZnFastmulBase, lhs: &mut Self::Element, rhs: <ZnFastmulBase as RingBase>::Element, _hom: &Self::Homomorphism) {
870 debug_assert!(lhs.0 <= self.repr_bound());
871 let lhs_original = lhs.0;
872 let product = mullo(lhs.0, rhs.el.0);
873 let approx_quotient = mulhi(lhs.0, rhs.value_invmod_shifted);
874 lhs.0 = product.wrapping_sub(mullo(approx_quotient, self.modulus_u64()));
875 debug_assert!(lhs.0 < self.modulus_times_three);
876 debug_assert!((lhs_original as u128 * rhs.el.0 as u128 - lhs.0 as u128) % (self.modulus_u64() as u128) == 0);
877 }
878
879 fn mul_assign_map_in_ref(&self, from: &ZnFastmulBase, lhs: &mut Self::Element, rhs: &<ZnFastmulBase as RingBase>::Element, hom: &Self::Homomorphism) {
880 self.mul_assign_map_in(from, lhs, *rhs, hom);
881 }
882}
883
884impl CanIsoFromTo<ZnFastmulBase> for ZnBase {
885
886 type Isomorphism = <ZnFastmulBase as CanHomFrom<Self>>::Homomorphism;
887
888 fn has_canonical_iso(&self, from: &ZnFastmulBase) -> Option<Self::Isomorphism> {
889 from.has_canonical_hom(self)
890 }
891
892 fn map_out(&self, from: &ZnFastmulBase, el: Self::Element, iso: &Self::Isomorphism) -> <ZnFastmulBase as RingBase>::Element {
893 from.map_in(self, el, iso)
894 }
895}
896
897impl CooleyTuckeyButterfly<ZnFastmulBase> for ZnBase {
898
899 #[inline(always)]
900 fn butterfly<V: crate::seq::VectorViewMut<Self::Element>, H: Homomorphism<ZnFastmulBase, Self>>(&self, hom: H, values: &mut V, twiddle: &<ZnFastmulBase as RingBase>::Element, i1: usize, i2: usize) {
901 let mut a = *values.at(i1);
902 if a.0 >= self.modulus_times_three {
903 a.0 -= self.modulus_times_three;
904 }
905 let mut b = *values.at(i2);
906 hom.mul_assign_ref_map(&mut b, twiddle);
907
908 *values.at_mut(i1) = self.from_u64_promise_reduced(a.0 + b.0);
909 *values.at_mut(i2) = self.from_u64_promise_reduced(a.0 + self.modulus_times_three - b.0);
910 }
911
912 fn inv_butterfly<V: crate::seq::VectorViewMut<Self::Element>, H: Homomorphism<ZnFastmulBase, Self>>(&self, hom: H, values: &mut V, twiddle: &<ZnFastmulBase as RingBase>::Element, i1: usize, i2: usize) {
913 let a = *values.at(i1);
914 let b = *values.at(i2);
915
916 *values.at_mut(i1) = self.add(a, b);
917 *values.at_mut(i2) = self.sub(a, b);
918 hom.mul_assign_ref_map(values.at_mut(i2), twiddle);
919 }
920}
921
922impl CooleyTuckeyButterfly<ZnBase> for ZnBase {
923
924 #[inline(always)]
925 fn butterfly<V: crate::seq::VectorViewMut<Self::Element>, H: Homomorphism<ZnBase, Self>>(&self, _hom: H, values: &mut V, twiddle: &ZnEl, i1: usize, i2: usize) {
926 let mut a = *values.at(i1);
927 if a.0 >= self.modulus_times_three {
928 a.0 -= self.modulus_times_three;
929 }
930 let mut b = *values.at(i2);
931 self.mul_assign_ref(&mut b, twiddle);
932
933 *values.at_mut(i1) = self.from_u64_promise_reduced(a.0 + b.0);
934 *values.at_mut(i2) = self.from_u64_promise_reduced(a.0 + self.modulus_times_three - b.0);
935 }
936
937 fn inv_butterfly<V: crate::seq::VectorViewMut<Self::Element>, H: Homomorphism<ZnBase, Self>>(&self, _hom: H, values: &mut V, twiddle: &ZnEl, i1: usize, i2: usize) {
938 let a = *values.at(i1);
939 let b = *values.at(i2);
940
941 *values.at_mut(i1) = self.add(a, b);
942 *values.at_mut(i2) = self.sub(a, b);
943 self.mul_assign_ref(values.at_mut(i2), twiddle);
944 }
945}
946
947impl<I: ?Sized + IntegerRing> CanHomFrom<I> for ZnFastmulBase
948 where ZnBase: CanHomFrom<I>
949{
950 type Homomorphism = <ZnBase as CanHomFrom<I>>::Homomorphism;
951
952 fn has_canonical_hom(&self, from: &I) -> Option<Self::Homomorphism> {
953 self.base.get_ring().has_canonical_hom(from)
954 }
955
956 fn map_in(&self, from: &I, el: I::Element, hom: &Self::Homomorphism) -> Self::Element {
957 self.rev_delegate(self.base.get_ring().map_in(from, el, hom))
958 }
959}
960
961impl_field_wrap_unwrap_homs!{ ZnBase, ZnBase }
962impl_field_wrap_unwrap_isos!{ ZnBase, ZnBase }
963impl_localpir_wrap_unwrap_homs!{ ZnBase, ZnBase }
964impl_localpir_wrap_unwrap_isos!{ ZnBase, ZnBase }
965
966impl<I> CanHomFrom<zn_big::ZnBase<I>> for AsFieldBase<Zn>
967 where I: RingStore,
968 I::Type: IntegerRing
969{
970 type Homomorphism = <ZnBase as CanHomFrom<zn_big::ZnBase<I>>>::Homomorphism;
971
972 fn has_canonical_hom(&self, from: &zn_big::ZnBase<I>) -> Option<Self::Homomorphism> {
973 self.get_delegate().has_canonical_hom(from)
974 }
975
976 fn map_in(&self, from: &zn_big::ZnBase<I>, el: <zn_big::ZnBase<I> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
977 self.rev_delegate(self.get_delegate().map_in(from, el, hom))
978 }
979}
980
981impl<I> CanIsoFromTo<zn_big::ZnBase<I>> for AsFieldBase<Zn>
982 where I: RingStore,
983 I::Type: IntegerRing
984{
985 type Isomorphism = <ZnBase as CanIsoFromTo<zn_big::ZnBase<I>>>::Isomorphism;
986
987 fn has_canonical_iso(&self, from: &zn_big::ZnBase<I>) -> Option<Self::Isomorphism> {
988 self.get_delegate().has_canonical_iso(from)
989 }
990
991 fn map_out(&self, from: &zn_big::ZnBase<I>, el: Self::Element, hom: &Self::Isomorphism) -> <zn_big::ZnBase<I> as RingBase>::Element {
992 self.get_delegate().map_out(from, self.delegate(el), hom)
993 }
994}
995
996#[cfg(test)]
997use test::Bencher;
998
999#[cfg(test)]
1000fn elements<'a>(ring: &'a Zn) -> impl 'a + Iterator<Item = El<Zn>> {
1001 (0..63).map(|i| ring.coerce(&ZZ, 1 << i))
1002}
1003
1004#[cfg(test)]
1005const LARGE_MODULI: [u64; 6] = [(1 << 41) - 1, (1 << 42) - 1, (1 << 58) - 1, (1 << 58) + 1, (3 << 57) - 1, (3 << 57) + 1];
1006
1007#[test]
1008fn test_complete_reduce() {
1009 let ring = Zn::new(32);
1010 assert_eq!(31, ring.get_ring().complete_reduce(4 * 32 - 1));
1011}
1012
1013#[test]
1014fn test_sum() {
1015 for n in LARGE_MODULI {
1016 let Zn = Zn::new(n);
1017 assert_el_eq!(Zn, Zn.int_hom().map(10001 * 5000), Zn.sum((0..=10000).map(|x| Zn.int_hom().map(x))));
1018 }
1019}
1020
1021#[test]
1022fn test_ring_axioms() {
1023 for n in 2..=17 {
1024 let ring = Zn::new(n);
1025 crate::ring::generic_tests::test_ring_axioms(&ring, (0..=ring.get_ring().repr_bound()).map(|n| ZnEl(n)));
1026 }
1027 for n in LARGE_MODULI {
1028 let ring = Zn::new(n);
1029 crate::ring::generic_tests::test_ring_axioms(&ring, elements(&ring));
1030 }
1031}
1032
1033#[test]
1034fn test_hash_axioms() {
1035 for n in 2..=17 {
1036 let ring = Zn::new(n);
1037 crate::ring::generic_tests::test_hash_axioms(&ring, (0..=ring.get_ring().repr_bound()).map(|n| ZnEl(n)));
1038 }
1039 for n in LARGE_MODULI {
1040 let ring = Zn::new(n);
1041 crate::ring::generic_tests::test_hash_axioms(&ring, elements(&ring));
1042 }
1043}
1044
1045#[test]
1046fn test_divisibility_axioms() {
1047 for n in 2..=17 {
1048 let Zn = Zn::new(n);
1049 crate::divisibility::generic_tests::test_divisibility_axioms(&Zn, Zn.elements());
1050 }
1051 for n in LARGE_MODULI {
1052 let Zn = Zn::new(n);
1053 crate::divisibility::generic_tests::test_divisibility_axioms(&Zn, elements(&Zn));
1054 }
1055}
1056
1057#[test]
1058fn test_zn_axioms() {
1059 for n in 2..=17 {
1060 let Zn = Zn::new(n);
1061 super::generic_tests::test_zn_axioms(&Zn);
1062 }
1063}
1064
1065#[test]
1066fn test_principal_ideal_ring_axioms() {
1067 for n in 2..=17 {
1068 let R = Zn::new(n);
1069 crate::pid::generic_tests::test_principal_ideal_ring_axioms(R, R.elements());
1070 }
1071 let R = Zn::new(63);
1072 crate::pid::generic_tests::test_principal_ideal_ring_axioms(R, R.elements());
1073}
1074
1075#[test]
1076fn test_hom_from_fastmul() {
1077 for n in 2..=17 {
1078 let Zn = Zn::new(n);
1079 let Zn_fastmul = ZnFastmul::new(Zn).unwrap();
1080 crate::ring::generic_tests::test_hom_axioms(Zn_fastmul, Zn, Zn.elements().map(|x| Zn_fastmul.coerce(&Zn, x)));
1081 }
1082 for n in [(1 << 41) - 1, (1 << 42) - 1, (1 << 58) - 1, (1 << 58) + 1, (3 << 57) - 1, (3 << 57) + 1] {
1083 let Zn = Zn::new(n);
1084 let Zn_fastmul = ZnFastmul::new(Zn).unwrap();
1085 crate::ring::generic_tests::test_hom_axioms(Zn_fastmul, Zn, elements(&Zn).map(|x| Zn_fastmul.coerce(&Zn, x)));
1086 }
1087}
1088
1089#[test]
1090fn test_finite_ring_axioms() {
1091 for n in 2..=17 {
1092 crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::new(n));
1093 }
1094 crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::new(128));
1095 crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::new(1 << 32));
1096}
1097
1098#[test]
1099fn test_from_int_hom() {
1100 for n in 2..=17 {
1101 let Zn = Zn::new(n);
1102 crate::ring::generic_tests::test_hom_axioms(StaticRing::<i8>::RING, Zn, -8..8);
1103 crate::ring::generic_tests::test_hom_axioms(StaticRing::<i16>::RING, Zn, -8..8);
1104 crate::ring::generic_tests::test_hom_axioms(StaticRing::<i32>::RING, Zn, -8..8);
1105 crate::ring::generic_tests::test_hom_axioms(StaticRing::<i64>::RING, Zn, -8..8);
1106 crate::ring::generic_tests::test_hom_axioms(StaticRing::<i128>::RING, Zn, -8..8);
1107 }
1108 let Zn = Zn::new(5);
1109 assert_el_eq!(Zn, Zn.int_hom().map(3), Zn.can_hom(&StaticRing::<i64>::RING).unwrap().map(-1596802));
1110}
1111
1112#[test]
1113fn test_bounded_reduce_large() {
1114 const FACTOR: usize = 32;
1115 let n_max = (1 << 62) / 9;
1116 for n in (n_max - 10)..=n_max {
1117 let Zn = Zn::new(n);
1118 let val_max = Zn.get_ring().repr_bound() as u128 * Zn.get_ring().repr_bound() as u128 * FACTOR as u128;
1119 for k in (val_max - 100)..=val_max {
1120 assert_eq!((k % (n as u128)) as i64, Zn.smallest_positive_lift(ZnEl(Zn.get_ring().bounded_reduce_larger::<FACTOR>(k))));
1121 }
1122 }
1123}
1124
1125#[test]
1126fn test_smallest_lift() {
1127 for n in 2..=17 {
1128 let ring = Zn::new(n);
1129 for k in 0..=ring.get_ring().repr_bound() {
1130 let expected = if (k % n) <= n / 2 { (k % n) as i64 } else { (k % n) as i64 - n as i64 };
1131 if n % 2 == 0 && (k % n) == n / 2 {
1132 assert!(ring.smallest_lift(ZnEl(k)) == n as i64 / 2 || ring.smallest_lift(ZnEl(k)) == -(n as i64) / 2)
1133 } else {
1134 assert_eq!(expected, ring.smallest_lift(ZnEl(k)));
1135 }
1136 }
1137 }
1138}
1139
1140#[test]
1141fn test_smallest_positive_lift() {
1142 for n in 2..=17 {
1143 let ring = Zn::new(n);
1144 for k in 0..=ring.get_ring().repr_bound() {
1145 let expected = (k % n) as i64;
1146 assert_eq!(expected, ring.smallest_positive_lift(ZnEl(k)));
1147 }
1148 }
1149}
1150
1151#[test]
1152fn test_bounded_reduce_small() {
1153 for n in 2..=17 {
1154 let Zn = Zn::new(n);
1155 let val_max = Zn.get_ring().repr_bound() as u128 * Zn.get_ring().repr_bound() as u128;
1156 for k in (val_max - 100)..=val_max {
1157 assert_eq!((k % (n as u128)) as i64, Zn.smallest_positive_lift(ZnEl(Zn.get_ring().bounded_reduce(k))));
1158 }
1159 }
1160}
1161
1162#[test]
1163fn test_bounded_reduce_large_small() {
1164 const FACTOR: usize = 32;
1165 for n in 2..=17 {
1166 let Zn = Zn::new(n);
1167 let val_max = Zn.get_ring().repr_bound() as u128 * Zn.get_ring().repr_bound() as u128 * FACTOR as u128;
1168 for k in (val_max - 100)..=val_max {
1169 assert_eq!((k % (n as u128)) as i64, Zn.smallest_positive_lift(ZnEl(Zn.get_ring().bounded_reduce_larger::<FACTOR>(k))));
1170 }
1171 }
1172}
1173
1174#[test]
1175fn test_bounded_reduce() {
1176 let n_max = (1 << 62) / 9;
1177 for n in (n_max - 10)..=n_max {
1178 let Zn = Zn::new(n);
1179 let val_max = Zn.get_ring().repr_bound() as u128 * Zn.get_ring().repr_bound() as u128;
1180 for k in (val_max - 100)..=val_max {
1181 assert_eq!((k % (n as u128)) as i64, Zn.smallest_positive_lift(ZnEl(Zn.get_ring().bounded_reduce(k))));
1182 }
1183 }
1184}
1185
1186#[bench]
1187fn bench_hom_from_i64_large_modulus(bencher: &mut Bencher) {
1188 let Zn = Zn::new(36028797018963971 );
1190 bencher.iter(|| {
1191 let hom = Zn.can_hom(&StaticRing::<i64>::RING).unwrap();
1192 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))))
1193 });
1194}
1195
1196#[bench]
1197fn bench_hom_from_i64_small_modulus(bencher: &mut Bencher) {
1198 let Zn = Zn::new(17);
1200 bencher.iter(|| {
1201 let hom = Zn.can_hom(&StaticRing::<i64>::RING).unwrap();
1202 assert_el_eq!(Zn, Zn.int_hom().map(2850 * 5699), Zn.sum((0..5700).map(|x| hom.map(x))))
1203 });
1204}
1205
1206#[bench]
1207fn bench_reduction_map_use_case(bencher: &mut Bencher) {
1208 let p = 17;
1210 let Zp2 = Zn::new(p * p);
1211 let Zp = Zn::new(p);
1212 let Zp2_mod_p = ZnReductionMap::new(&Zp2, &Zp).unwrap();
1213 let Zp2_p = Zp2.get_ring().prepare_divisor(Zp2.int_hom().map(p as i32));
1214
1215 let split_quo_rem = |x: El<Zn>| {
1216 let rem = Zp2_mod_p.map_ref(&x);
1217 let Zp2_rem = Zp2_mod_p.smallest_lift(rem);
1218 let quo = Zp2.get_ring().checked_left_div_prepared(&Zp2.sub(x, Zp2_rem), &Zp2_p).unwrap();
1219 (rem, Zp2_mod_p.map(quo))
1220 };
1221
1222 bencher.iter(|| {
1223 for x in Zp2.elements() {
1224 for y in Zp2.elements() {
1225 let (x_low, x_high) = split_quo_rem(x);
1226 let (y_low, y_high) = split_quo_rem(y);
1227 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)))));
1228 }
1229 }
1230 });
1231}
1232
1233#[bench]
1234fn bench_inner_product(bencher: &mut Bencher) {
1235 let Fp = Zn::new(65537);
1236 let len = 1 << 12;
1237 let lhs = (0..len).map(|i| Fp.int_hom().map(i)).collect::<Vec<_>>();
1238 let rhs = (0..len).map(|i| Fp.int_hom().map(i)).collect::<Vec<_>>();
1239 let expected = (0..len).map(|i| Fp.int_hom().map(i * i)).fold(Fp.zero(), |l, r| Fp.add(l, r));
1240
1241 bencher.iter(|| {
1242 let actual = <_ as ComputeInnerProduct>::inner_product_ref(Fp.get_ring(), lhs.iter().zip(rhs.iter()).map(|x| std::hint::black_box(x)));
1243 assert_el_eq!(Fp, expected, actual);
1244 })
1245}
1246
1247#[test]
1248fn test_serialize() {
1249 let ring = Zn::new(128);
1250 crate::serialization::generic_tests::test_serialization(ring, ring.elements())
1251}