From a9ecfbfc052d23a6d197720fb3fcd3f48920b28b Mon Sep 17 00:00:00 2001 From: Tomek Czajka Date: Tue, 7 Nov 2023 15:29:21 +0100 Subject: [PATCH] progress --- CHANGELOG.md | 4 + src/lib.rs | 2 +- src/modular/add.rs | 306 ++++++++++++------------------------- src/modular/cmp.rs | 71 +++------ src/modular/convert.rs | 233 +++------------------------- src/modular/div.rs | 108 +++++-------- src/modular/fmt.rs | 41 +---- src/modular/modulo.rs | 214 ++++---------------------- src/modular/modulo_ring.rs | 95 ++---------- src/modular/mul.rs | 160 +++++-------------- src/modular/pow.rs | 16 +- 11 files changed, 266 insertions(+), 984 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52ed66c..83acb65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Breaking changes * Modular arithmetic moved from `modular` to the top-level module. +* `Modulo` is now a fully owned type without a reference to `ModuloRing`. + +### Features +* `Modulo::ring`. ### Dependencies * Minimum Rust version is now 1.61. diff --git a/src/lib.rs b/src/lib.rs index cca568e..32ac455 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,7 @@ extern crate alloc; pub use crate::{ ibig::IBig, - modular::{convert::IntoModulo, modulo::Modulo, modulo_ring::ModuloRing}, + modular::{modulo::Modulo, modulo_ring::ModuloRing}, ubig::UBig, }; diff --git a/src/modular/add.rs b/src/modular/add.rs index 2918cb0..5b9eaaa 100644 --- a/src/modular/add.rs +++ b/src/modular/add.rs @@ -1,287 +1,177 @@ //! Modular addition and subtraction. -use crate::{ - add, cmp, - modular::{ - modulo::{Modulo, ModuloLarge, ModuloRepr, ModuloSmall, ModuloSmallRaw}, - modulo_ring::ModuloRingSmall, - }, -}; -use core::{ - cmp::Ordering, - ops::{Add, AddAssign, Neg, Sub, SubAssign}, -}; +use crate::{modular::modulo::Modulo, UBig}; +use core::ops::{Add, AddAssign, Neg, Sub, SubAssign}; -impl<'a> Neg for Modulo<'a> { - type Output = Modulo<'a>; +impl Neg for Modulo { + type Output = Modulo; #[inline] - fn neg(mut self) -> Modulo<'a> { - match self.repr_mut() { - ModuloRepr::Small(self_small) => self_small.negate_in_place(), - ModuloRepr::Large(self_large) => self_large.negate_in_place(), + fn neg(mut self) -> Modulo { + if self.value() == UBig::from_word(0) { + self + } else { + self.ring() + .from_normalized_value(self.ring().normalized_modulus() - self.normalized_value()) } - self } } -impl<'a> Neg for &Modulo<'a> { - type Output = Modulo<'a>; +impl Neg for &Modulo { + type Output = Modulo; #[inline] - fn neg(self) -> Modulo<'a> { + fn neg(self) -> Modulo { self.clone().neg() } } -impl<'a> Add> for Modulo<'a> { - type Output = Modulo<'a>; +impl Add for Modulo { + type Output = Modulo; #[inline] - fn add(self, rhs: Modulo<'a>) -> Modulo<'a> { - self.add(&rhs) + fn add(mut self, rhs: Modulo) -> Modulo { + self.add_assign(rhs); + self } } -impl<'a> Add<&Modulo<'a>> for Modulo<'a> { - type Output = Modulo<'a>; +impl Add<&Modulo> for Modulo { + type Output = Modulo; #[inline] - fn add(mut self, rhs: &Modulo<'a>) -> Modulo<'a> { + fn add(mut self, rhs: &Modulo) -> Modulo { self.add_assign(rhs); self } } -impl<'a> Add> for &Modulo<'a> { - type Output = Modulo<'a>; +impl Add for &Modulo { + type Output = Modulo; #[inline] - fn add(self, rhs: Modulo<'a>) -> Modulo<'a> { + fn add(self, rhs: Modulo) -> Modulo { rhs.add(self) } } -impl<'a> Add<&Modulo<'a>> for &Modulo<'a> { - type Output = Modulo<'a>; +impl Add<&Modulo> for &Modulo { + type Output = Modulo; #[inline] - fn add(self, rhs: &Modulo<'a>) -> Modulo<'a> { - self.clone().add(rhs) + fn add(self, rhs: &Modulo) -> Modulo { + self.check_same_ring(rhs); + let mut val = self.normalized_value() + rhs.normalized_value(); + if val >= self.ring().normalized_modulus() { + val -= self.ring().normalized_modulus(); + } + self.ring().from_normalized_value(val) } } -impl<'a> AddAssign> for Modulo<'a> { +impl AddAssign for Modulo { #[inline] - fn add_assign(&mut self, rhs: Modulo<'a>) { - self.add_assign(&rhs) + fn add_assign(&mut self, rhs: Modulo) { + self.check_same_ring(rhs); + let mut val = self.take_normalized_value() + rhs.take_normalized_value(); + if val >= self.ring().normalized_modulus() { + val -= self.ring().normalized_modulus(); + } + self.set_normalized_value(val); } } -impl<'a> AddAssign<&Modulo<'a>> for Modulo<'a> { +impl AddAssign<&Modulo> for Modulo { #[inline] - fn add_assign(&mut self, rhs: &Modulo<'a>) { - match (self.repr_mut(), rhs.repr()) { - (ModuloRepr::Small(self_small), ModuloRepr::Small(rhs_small)) => { - self_small.add_in_place(rhs_small) - } - (ModuloRepr::Large(self_large), ModuloRepr::Large(rhs_large)) => { - self_large.add_in_place(rhs_large) - } - _ => Modulo::panic_different_rings(), + fn add_assign(&mut self, rhs: &Modulo) { + self.check_same_ring(rhs); + let mut val = self.take_normalized_value() + rhs.normalized_value(); + if val >= self.ring().normalized_modulus() { + val -= self.ring().normalized_modulus(); } + self.set_normalized_value(val); } } -impl<'a> Sub> for Modulo<'a> { - type Output = Modulo<'a>; +impl Sub for Modulo { + type Output = Modulo; #[inline] - fn sub(self, rhs: Modulo<'a>) -> Modulo<'a> { - self.sub(&rhs) + fn sub(mut self, rhs: Modulo) -> Modulo { + self.sub_assign(rhs); + self } } -impl<'a> Sub<&Modulo<'a>> for Modulo<'a> { - type Output = Modulo<'a>; +impl Sub for Modulo { + type Output = Modulo; #[inline] - fn sub(mut self, rhs: &Modulo<'a>) -> Modulo<'a> { + fn sub(mut self, rhs: &Modulo) -> Modulo { self.sub_assign(rhs); self } } -impl<'a> Sub> for &Modulo<'a> { - type Output = Modulo<'a>; +impl Sub for &Modulo { + type Output = Modulo; #[inline] - fn sub(self, mut rhs: Modulo<'a>) -> Modulo<'a> { - match (self.repr(), rhs.repr_mut()) { - (ModuloRepr::Small(self_small), ModuloRepr::Small(rhs_small)) => { - self_small.sub_in_place_swap(rhs_small) - } - (ModuloRepr::Large(self_large), ModuloRepr::Large(rhs_large)) => { - self_large.sub_in_place_swap(rhs_large) - } - _ => Modulo::panic_different_rings(), - } + fn sub(self, rhs: Modulo) -> Modulo { + self.check_same_ring(rhs); + let val = self.normalized_value(); + let rhs_val = rhs.take_normalized_value(); + let val = if val < rhs_val { + val + (self.ring().normalized_modulus() - rhs_val) + } else { + val - rhs_val + }; + rhs.set_normalized_value(val); rhs } } -impl<'a> Sub<&Modulo<'a>> for &Modulo<'a> { - type Output = Modulo<'a>; +impl Sub<&Modulo> for &Modulo { + type Output = Modulo; #[inline] - fn sub(self, rhs: &Modulo<'a>) -> Modulo<'a> { - self.clone().sub(rhs) - } -} - -impl<'a> SubAssign> for Modulo<'a> { - #[inline] - fn sub_assign(&mut self, rhs: Modulo<'a>) { - self.sub_assign(&rhs) - } -} - -impl<'a> SubAssign<&Modulo<'a>> for Modulo<'a> { - #[inline] - fn sub_assign(&mut self, rhs: &Modulo<'a>) { - match (self.repr_mut(), rhs.repr()) { - (ModuloRepr::Small(self_small), ModuloRepr::Small(rhs_small)) => { - self_small.sub_in_place(rhs_small) - } - (ModuloRepr::Large(self_large), ModuloRepr::Large(rhs_large)) => { - self_large.sub_in_place(rhs_large) - } - _ => Modulo::panic_different_rings(), - } - } -} - -impl ModuloSmallRaw { - /// -self - #[inline] - fn negate(self, ring: &ModuloRingSmall) -> ModuloSmallRaw { - debug_assert!(self.is_valid(ring)); - let normalized_val = match self.normalized() { - 0 => 0, - x => ring.normalized_modulus() - x, + fn sub(self, rhs: &Modulo) -> Modulo { + self.check_same_ring(rhs); + let val = self.normalized_value(); + let rhs = rhs.normalized_value(); + let val = if val < rhs { + val + (self.ring().normalized_modulus() - rhs) + } else { + val - rhs }; - ModuloSmallRaw::from_normalized(normalized_val) - } - - /// self + other - #[inline] - fn add(self, other: ModuloSmallRaw, ring: &ModuloRingSmall) -> ModuloSmallRaw { - debug_assert!(self.is_valid(ring) && other.is_valid(ring)); - let (mut val, overflow) = self.normalized().overflowing_add(other.normalized()); - let m = ring.normalized_modulus(); - if overflow || val >= m { - let (v, overflow2) = val.overflowing_sub(m); - debug_assert_eq!(overflow, overflow2); - val = v; - } - ModuloSmallRaw::from_normalized(val) - } - - /// self - other - #[inline] - fn sub(self, other: ModuloSmallRaw, ring: &ModuloRingSmall) -> ModuloSmallRaw { - debug_assert!(self.is_valid(ring) && other.is_valid(ring)); - let (mut val, overflow) = self.normalized().overflowing_sub(other.normalized()); - if overflow { - let m = ring.normalized_modulus(); - let (v, overflow2) = val.overflowing_add(m); - debug_assert!(overflow2); - val = v; - } - ModuloSmallRaw::from_normalized(val) + self.ring().from_normalized_value(val) } } -impl<'a> ModuloSmall<'a> { - /// self = -self - #[inline] - fn negate_in_place(&mut self) { - let ring = self.ring(); - self.set_raw(self.raw().negate(ring)); - } - - /// self += rhs - #[inline] - fn add_in_place(&mut self, rhs: &ModuloSmall<'a>) { - self.check_same_ring(rhs); - self.set_raw(self.raw().add(rhs.raw(), self.ring())); - } - - /// self -= rhs - #[inline] - fn sub_in_place(&mut self, rhs: &ModuloSmall<'a>) { - self.check_same_ring(rhs); - self.set_raw(self.raw().sub(rhs.raw(), self.ring())); - } - - /// rhs = self - rhs +impl SubAssign for Modulo { #[inline] - fn sub_in_place_swap(&self, rhs: &mut ModuloSmall<'a>) { + fn sub_assign(&mut self, rhs: Modulo) { self.check_same_ring(rhs); - rhs.set_raw(self.raw().sub(rhs.raw(), self.ring())); + let mut val = self.take_normalized_value(); + let rhs = rhs.take_normalized_value(); + if val < rhs { + val += self.ring().normalized_modulus(); + } + val -= rhs; + self.set_normalized_value(val); } } -impl<'a> ModuloLarge<'a> { - /// self = -self - fn negate_in_place(&mut self) { - self.modify_normalized_value(|words, ring| { - if !words.iter().all(|w| *w == 0) { - let overflow = add::sub_same_len_in_place_swap(ring.normalized_modulus(), words); - assert!(!overflow); - } - }); - } - - /// self += rhs - fn add_in_place(&mut self, rhs: &ModuloLarge<'a>) { - self.check_same_ring(rhs); - let rhs_words = rhs.normalized_value(); - self.modify_normalized_value(|words, ring| { - let modulus = ring.normalized_modulus(); - let overflow = add::add_same_len_in_place(words, rhs_words); - if overflow || cmp::cmp_same_len(words, modulus) >= Ordering::Equal { - let overflow2 = add::sub_same_len_in_place(words, modulus); - debug_assert_eq!(overflow, overflow2); - } - }); - } - - /// self -= rhs - fn sub_in_place(&mut self, rhs: &ModuloLarge<'a>) { - self.check_same_ring(rhs); - let rhs_words = rhs.normalized_value(); - self.modify_normalized_value(|words, ring| { - let modulus = ring.normalized_modulus(); - let overflow = add::sub_same_len_in_place(words, rhs_words); - if overflow { - let overflow2 = add::add_same_len_in_place(words, modulus); - debug_assert!(overflow2); - } - }); - } - - /// rhs = self - rhs - fn sub_in_place_swap(&self, rhs: &mut ModuloLarge<'a>) { +impl SubAssign<&Modulo> for Modulo { + #[inline] + fn sub_assign(&mut self, rhs: &Modulo) { self.check_same_ring(rhs); - let words = self.normalized_value(); - rhs.modify_normalized_value(|rhs_words, ring| { - let modulus = ring.normalized_modulus(); - let overflow = add::sub_same_len_in_place_swap(words, rhs_words); - if overflow { - let overflow2 = add::add_same_len_in_place(rhs_words, modulus); - debug_assert!(overflow2); - } - }); + let mut val = self.take_normalized_value(); + let rhs = rhs.normalized_value(); + if val < rhs { + val += self.ring().normalized_modulus(); + } + val -= rhs; + self.set_normalized_value(val); } } diff --git a/src/modular/cmp.rs b/src/modular/cmp.rs index c5be3ff..28d1125 100644 --- a/src/modular/cmp.rs +++ b/src/modular/cmp.rs @@ -1,74 +1,37 @@ //! Comparisons. -use crate::modular::{ - modulo::{Modulo, ModuloLarge, ModuloRepr, ModuloSmall}, - modulo_ring::{ModuloRing, ModuloRingLarge, ModuloRingSmall}, -}; -use core::ptr; +use alloc::sync::Arc; -/// Equality is identity: two rings are not equal even if they have the same modulus. +use crate::modular::{modulo::Modulo, modulo_ring::ModuloRing}; + +/// Two rings are equal only if they are clones of each other. +/// +/// # Examples +/// +/// ``` +/// # use ibig::{ModuloRing, ubig}; +/// let ring1 = ModuloRing::new(&ubig!(100)); +/// let ring2 = ring1.clone(); +/// let ring3 = ModuloRing::new(&ubig!(100)); +/// assert_eq!(ring1, ring2); +/// assert_ne!(ring1, ring3); +/// ``` impl PartialEq for ModuloRing { #[inline] fn eq(&self, other: &Self) -> bool { - ptr::eq(self, other) + Arc::eq(self, other) } } impl Eq for ModuloRing {} -/// Equality is identity: two rings are not equal even if they have the same modulus. -impl PartialEq for ModuloRingSmall { - #[inline] - fn eq(&self, other: &Self) -> bool { - ptr::eq(self, other) - } -} - -impl Eq for ModuloRingSmall {} - -/// Equality is identity: two rings are not equal even if they have the same modulus. -impl PartialEq for ModuloRingLarge { - #[inline] - fn eq(&self, other: &Self) -> bool { - ptr::eq(self, other) - } -} - -impl Eq for ModuloRingLarge {} - /// Equality within a ring. /// /// # Panics /// /// Panics if the two values are from different rings. -impl PartialEq for Modulo<'_> { - #[inline] - fn eq(&self, other: &Self) -> bool { - match (self.repr(), other.repr()) { - (ModuloRepr::Small(self_small), ModuloRepr::Small(other_small)) => { - self_small.eq(other_small) - } - (ModuloRepr::Large(self_large), ModuloRepr::Large(other_large)) => { - self_large.eq(other_large) - } - _ => Modulo::panic_different_rings(), - } - } -} - -impl Eq for Modulo<'_> {} - -impl PartialEq for ModuloSmall<'_> { +impl PartialEq for Modulo { #[inline] - fn eq(&self, other: &Self) -> bool { - self.check_same_ring(other); - self.raw() == other.raw() - } -} - -impl Eq for ModuloLarge<'_> {} - -impl PartialEq for ModuloLarge<'_> { fn eq(&self, other: &Self) -> bool { self.check_same_ring(other); self.normalized_value() == other.normalized_value() diff --git a/src/modular/convert.rs b/src/modular/convert.rs index d709966..5cc324d 100644 --- a/src/modular/convert.rs +++ b/src/modular/convert.rs @@ -1,22 +1,11 @@ //! Conversion between Modulo, UBig and IBig. use crate::{ - arch::word::Word, - buffer::Buffer, - div, ibig::IBig, - memory::MemoryAllocation, - modular::{ - modulo::{Modulo, ModuloLarge, ModuloRepr, ModuloSmall, ModuloSmallRaw}, - modulo_ring::{ModuloRing, ModuloRingLarge, ModuloRingRepr, ModuloRingSmall}, - }, - primitive::extend_word, - shift, + modular::{modulo::Modulo, modulo_ring::ModuloRing}, sign::Sign::*, - ubig::{Repr, UBig}, + ubig::UBig, }; -use alloc::vec::Vec; -use core::iter; impl ModuloRing { /// The ring modulus. @@ -30,10 +19,7 @@ impl ModuloRing { /// ``` #[inline] pub fn modulus(&self) -> UBig { - match self.repr() { - ModuloRingRepr::Small(self_small) => UBig::from_word(self_small.modulus()), - ModuloRingRepr::Large(self_large) => self_large.modulus(), - } + self.normalized_modulus() >> self.shift() } /// Create an element of the ring from another type. @@ -48,30 +34,30 @@ impl ModuloRing { /// assert!(x == y); /// ``` #[inline] - pub fn from(&self, x: T) -> Modulo { - x.into_modulo(self) + pub fn from>(&self, source: T) -> Modulo { + // TODO: Avoid copy for huge numbers. + let source = IBig::from(source); + let (sign, mag) = source.into_sign_magnitude(); + let modulo = self.from_ubig(mag); + match sign { + Positive => modulo, + Negative => -modulo, + } } -} -impl ModuloRingSmall { - #[inline] - pub(crate) fn modulus(&self) -> Word { - self.normalized_modulus() >> self.shift() + pub(crate) fn from_ubig(&self, mut value: UBig) -> Modulo { + value <<= self.shift(); + // TODO: Optimize using fast_div_top. + value %= self.normalized_modulus(); + self.from_normalized_value(value) } -} -impl ModuloRingLarge { - pub(crate) fn modulus(&self) -> UBig { - let normalized_modulus = self.normalized_modulus(); - let mut buffer = Buffer::allocate(normalized_modulus.len()); - buffer.extend(normalized_modulus); - let low_bits = shift::shr_in_place(&mut buffer, self.shift()); - assert!(low_bits == 0); - buffer.into() + pub(crate) fn from_normalized_value(&self, normalized_value: UBig) -> Modulo { + Modulo::from_normalized_value(normalized_value, self) } } -impl Modulo<'_> { +impl Modulo { /// Get the residue in range `0..n` in an n-element ring. /// /// # Examples @@ -84,183 +70,6 @@ impl Modulo<'_> { /// ``` #[inline] pub fn residue(&self) -> UBig { - match self.repr() { - ModuloRepr::Small(self_small) => UBig::from_word(self_small.residue()), - ModuloRepr::Large(self_large) => self_large.residue(), - } - } -} - -impl ModuloSmallRaw { - #[inline] - pub(crate) fn residue(self, ring: &ModuloRingSmall) -> Word { - debug_assert!(self.is_valid(ring)); - self.normalized() >> ring.shift() - } - - #[inline] - pub(crate) const fn from_word(word: Word, ring: &ModuloRingSmall) -> ModuloSmallRaw { - let rem = if ring.shift() == 0 { - ring.fast_div().div_rem_word(word).1 - } else { - ring.fast_div().div_rem(extend_word(word) << ring.shift()).1 - }; - ModuloSmallRaw::from_normalized(rem) - } - - fn from_large(words: &[Word], ring: &ModuloRingSmall) -> ModuloSmallRaw { - let mut rem = div::fast_rem_by_normalized_word(words, ring.fast_div()); - if ring.shift() != 0 { - rem = ring.fast_div().div_rem(extend_word(rem) << ring.shift()).1 - } - ModuloSmallRaw::from_normalized(rem) - } -} - -impl ModuloSmall<'_> { - #[inline] - pub(crate) fn residue(&self) -> Word { - self.raw().residue(self.ring()) - } -} - -impl ModuloLarge<'_> { - pub(crate) fn residue(&self) -> UBig { - let words = self.normalized_value(); - let mut buffer = Buffer::allocate(words.len()); - buffer.extend(words); - let low_bits = shift::shr_in_place(&mut buffer, self.ring().shift()); - assert!(low_bits == 0); - buffer.into() - } -} - -/// Trait for types that can be converted into [Modulo] in a [ModuloRing]. -pub trait IntoModulo { - fn into_modulo(self, ring: &ModuloRing) -> Modulo; -} - -impl IntoModulo for UBig { - #[inline] - fn into_modulo(self, ring: &ModuloRing) -> Modulo { - match ring.repr() { - ModuloRingRepr::Small(ring_small) => ModuloSmall::from_ubig(&self, ring_small).into(), - ModuloRingRepr::Large(ring_large) => ModuloLarge::from_ubig(self, ring_large).into(), - } + self.normalized() >> self.ring().shift() } } - -impl IntoModulo for &UBig { - #[inline] - fn into_modulo(self, ring: &ModuloRing) -> Modulo { - match ring.repr() { - ModuloRingRepr::Small(ring_small) => ModuloSmall::from_ubig(self, ring_small).into(), - ModuloRingRepr::Large(ring_large) => { - ModuloLarge::from_ubig(self.clone(), ring_large).into() - } - } - } -} - -impl IntoModulo for IBig { - #[inline] - fn into_modulo(self, ring: &ModuloRing) -> Modulo { - let (sign, mag) = self.into_sign_magnitude(); - let modulo = mag.into_modulo(ring); - match sign { - Positive => modulo, - Negative => -modulo, - } - } -} - -impl IntoModulo for &IBig { - #[inline] - fn into_modulo(self, ring: &ModuloRing) -> Modulo { - let modulo = self.magnitude().into_modulo(ring); - match self.sign() { - Positive => modulo, - Negative => -modulo, - } - } -} - -impl<'a> ModuloSmall<'a> { - #[inline] - pub(crate) fn from_ubig(x: &UBig, ring: &'a ModuloRingSmall) -> ModuloSmall<'a> { - let raw = match x.repr() { - Repr::Small(word) => ModuloSmallRaw::from_word(*word, ring), - Repr::Large(words) => ModuloSmallRaw::from_large(words, ring), - }; - ModuloSmall::new(raw, ring) - } -} - -impl<'a> ModuloLarge<'a> { - pub(crate) fn from_ubig(mut x: UBig, ring: &'a ModuloRingLarge) -> ModuloLarge<'a> { - x <<= ring.shift() as usize; - let modulus = ring.normalized_modulus(); - let mut vec = Vec::with_capacity(modulus.len()); - match x.into_repr() { - Repr::Small(word) => vec.push(word), - Repr::Large(mut words) => { - if words.len() < modulus.len() { - vec.extend(&*words); - } else { - let mut allocation = MemoryAllocation::new(div::memory_requirement_exact( - words.len(), - modulus.len(), - )); - let mut memory = allocation.memory(); - let _overflow = div::div_rem_in_place( - &mut words, - modulus, - ring.fast_div_top(), - &mut memory, - ); - vec.extend(&words[..modulus.len()]); - } - } - } - vec.extend(iter::repeat(0).take(modulus.len() - vec.len())); - ModuloLarge::new(vec, ring) - } -} - -/// Implement `IntoModulo` for unsigned primitives. -macro_rules! impl_into_modulo_for_unsigned { - ($t:ty) => { - impl IntoModulo for $t { - #[inline] - fn into_modulo(self, ring: &ModuloRing) -> Modulo { - UBig::from(self).into_modulo(ring) - } - } - }; -} - -/// Implement `IntoModulo` for signed primitives. -macro_rules! impl_into_modulo_for_signed { - ($t:ty) => { - impl IntoModulo for $t { - #[inline] - fn into_modulo(self, ring: &ModuloRing) -> Modulo { - IBig::from(self).into_modulo(ring) - } - } - }; -} - -impl_into_modulo_for_unsigned!(bool); -impl_into_modulo_for_unsigned!(u8); -impl_into_modulo_for_unsigned!(u16); -impl_into_modulo_for_unsigned!(u32); -impl_into_modulo_for_unsigned!(u64); -impl_into_modulo_for_unsigned!(u128); -impl_into_modulo_for_unsigned!(usize); -impl_into_modulo_for_signed!(i8); -impl_into_modulo_for_signed!(i16); -impl_into_modulo_for_signed!(i32); -impl_into_modulo_for_signed!(i64); -impl_into_modulo_for_signed!(i128); -impl_into_modulo_for_signed!(isize); diff --git a/src/modular/div.rs b/src/modular/div.rs index 032ac60..74dd970 100644 --- a/src/modular/div.rs +++ b/src/modular/div.rs @@ -1,13 +1,7 @@ -use crate::{ - arch::word::Word, - ibig::IBig, - modular::modulo::{Modulo, ModuloLarge, ModuloRepr, ModuloSmall, ModuloSmallRaw}, - ops::RemEuclid, - ubig::UBig, -}; +use crate::{ibig::IBig, modular::modulo::Modulo, ops::RemEuclid, ubig::UBig}; use core::ops::{Div, DivAssign}; -impl<'a> Modulo<'a> { +impl Modulo { /// Inverse. /// /// Returns `None` if there is no unique inverse. @@ -20,101 +14,69 @@ impl<'a> Modulo<'a> { /// assert_eq!(ring.from(7).inverse(), Some(ring.from(3))); /// assert_eq!(ring.from(2).inverse(), None); /// ``` - pub fn inverse(&self) -> Option> { - match self.repr() { - ModuloRepr::Small(self_small) => self_small.inverse().map(Into::into), - ModuloRepr::Large(self_large) => self_large.inverse().map(Into::into), + pub fn inverse(&self) -> Option { + let a = self.residue(); + let b = self.ring().modulus(); + let (gcd, x, _) = a.extended_gcd(&b); + if gcd == UBig::from_word(1) { + // TODO: Get rid of redundant remainder computations. + let res: UBig = x.rem_euclid(IBig::from(b)).try_into().unwrap(); + Some(self.ring().from_ubig(res)) + } else { + None } } } -impl<'a> Div> for Modulo<'a> { - type Output = Modulo<'a>; +impl Div for Modulo { + type Output = Modulo; #[inline] - fn div(self, rhs: Modulo<'a>) -> Modulo<'a> { - (&self).div(&rhs) + fn div(self, rhs: Modulo) -> Modulo { + self.div(&rhs) } } -impl<'a> Div<&Modulo<'a>> for Modulo<'a> { - type Output = Modulo<'a>; +impl Div<&Modulo> for Modulo { + type Output = Modulo; #[inline] - fn div(self, rhs: &Modulo<'a>) -> Modulo<'a> { - (&self).div(rhs) + fn div(mut self, rhs: &Modulo) -> Modulo { + self.div_assign(rhs); + self } } -impl<'a> Div> for &Modulo<'a> { - type Output = Modulo<'a>; +impl Div for &Modulo { + type Output = Modulo; #[inline] - fn div(self, rhs: Modulo<'a>) -> Modulo<'a> { + fn div(self, rhs: Modulo) -> Modulo { self.div(&rhs) } } -impl<'a> Div<&Modulo<'a>> for &Modulo<'a> { - type Output = Modulo<'a>; +impl Div<&Modulo> for &Modulo { + type Output = Modulo; #[inline] - fn div(self, rhs: &Modulo<'a>) -> Modulo<'a> { - // Clippy doesn't like that division is implemented using multiplication. - #[allow(clippy::suspicious_arithmetic_impl)] - match rhs.inverse() { - None => panic!("Division by a non-invertible Modulo"), - Some(inv_rhs) => self * inv_rhs, - } + fn div(self, rhs: &Modulo) -> Modulo { + let inv_rhs = rhs.inverse.expect("Division by a non-invertible Modulo"); + self * inv_rhs } } -impl<'a> DivAssign> for Modulo<'a> { +impl DivAssign for Modulo { #[inline] - fn div_assign(&mut self, rhs: Modulo<'a>) { + fn div_assign(&mut self, rhs: Modulo) { self.div_assign(&rhs) } } -impl<'a> DivAssign<&Modulo<'a>> for Modulo<'a> { +impl<'a> DivAssign<&Modulo> for Modulo { #[inline] - fn div_assign(&mut self, rhs: &Modulo<'a>) { - *self = (&*self).div(rhs) - } -} - -impl<'a> ModuloSmall<'a> { - /// Inverse. - fn inverse(&self) -> Option> { - let a = self.residue(); - let b = self.ring().modulus(); - // TODO: Optimized `extended_gcd` for `Word`s. - // x * a + _ * b == gcd - let (gcd, x, _) = UBig::from(a).extended_gcd(&UBig::from(b)); - if gcd == UBig::from_word(1) { - let res: Word = x.rem_euclid(IBig::from(b)).try_into().unwrap(); - Some(ModuloSmall::new( - ModuloSmallRaw::from_word(res, self.ring()), - self.ring(), - )) - } else { - None - } - } -} - -impl<'a> ModuloLarge<'a> { - /// Inverse. - fn inverse(&self) -> Option> { - let a = self.residue(); - let b = self.ring().modulus(); - let (gcd, x, _) = a.extended_gcd(&b); - if gcd == UBig::from_word(1) { - // TODO: Get rid of redundant remainder computations. - let res: UBig = x.rem_euclid(IBig::from(b)).try_into().unwrap(); - Some(ModuloLarge::from_ubig(res, self.ring())) - } else { - None - } + fn div_assign(&mut self, rhs: &Modulo) { + let inv_rhs = rhs.inverse.expect("Division by a non-invertible Modulo"); + self.mul_assign(inv_rhs); } } diff --git a/src/modular/fmt.rs b/src/modular/fmt.rs index 312805d..4e48679 100644 --- a/src/modular/fmt.rs +++ b/src/modular/fmt.rs @@ -1,55 +1,18 @@ //! Formatting modular rings and modular numbers. -use crate::modular::{ - modulo::{Modulo, ModuloLarge, ModuloRepr, ModuloSmall}, - modulo_ring::{ModuloRing, ModuloRingLarge, ModuloRingRepr, ModuloRingSmall}, -}; +use crate::modular::{modulo::Modulo, modulo_ring::ModuloRing}; use core::fmt::{self, Binary, Debug, Display, Formatter, LowerHex, Octal, UpperHex}; macro_rules! impl_fmt { ($t:ident) => { impl $t for ModuloRing { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self.repr() { - ModuloRingRepr::Small(self_small) => $t::fmt(self_small, f), - ModuloRingRepr::Large(self_large) => $t::fmt(self_large, f), - } - } - } - - impl $t for ModuloRingSmall { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.write_str("mod ")?; $t::fmt(&self.modulus(), f) } } - impl $t for ModuloRingLarge { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.write_str("mod ")?; - $t::fmt(&self.modulus(), f) - } - } - - impl $t for Modulo<'_> { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self.repr() { - ModuloRepr::Small(self_small) => $t::fmt(self_small, f), - ModuloRepr::Large(self_large) => $t::fmt(self_large, f), - } - } - } - - impl $t for ModuloSmall<'_> { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - $t::fmt(&self.residue(), f)?; - f.write_str(" (")?; - $t::fmt(self.ring(), f)?; - f.write_str(")") - } - } - - impl $t for ModuloLarge<'_> { + impl $t for Modulo { fn fmt(&self, f: &mut Formatter) -> fmt::Result { $t::fmt(&self.residue(), f)?; f.write_str(" (")?; diff --git a/src/modular/modulo.rs b/src/modular/modulo.rs index b9184df..5076398 100644 --- a/src/modular/modulo.rs +++ b/src/modular/modulo.rs @@ -1,11 +1,6 @@ //! Element of modular arithmetic. -use crate::{ - arch::word::Word, - math, - modular::modulo_ring::{ModuloRingLarge, ModuloRingSmall}, -}; -use alloc::vec::Vec; +use crate::{modular::modulo_ring::ModuloRing, ubig::UBig}; /// Modular arithmetic. /// @@ -18,204 +13,61 @@ use alloc::vec::Vec; /// let y = ring.from(55443); /// assert_eq!((x - y).residue(), ubig!(6902)); /// ``` -pub struct Modulo<'a>(ModuloRepr<'a>); - -pub(crate) enum ModuloRepr<'a> { - Small(ModuloSmall<'a>), - Large(ModuloLarge<'a>), -} - -/// Modular value in some unknown ring. The ring must be provided to operations. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub(crate) struct ModuloSmallRaw { - /// must be in range 0..modulus and divisible by the shift for ModuloSmallRing - normalized_value: Word, -} - -#[derive(Clone)] -pub(crate) struct ModuloSmall<'a> { - ring: &'a ModuloRingSmall, - raw: ModuloSmallRaw, +pub struct Modulo { + ring: ModuloRing, + normalized_value: UBig, } -pub(crate) struct ModuloLarge<'a> { - ring: &'a ModuloRingLarge, - /// normalized_value.len() == ring.normalized_modulus.len() - normalized_value: Vec, -} - -impl<'a> Modulo<'a> { - /// Get representation. - #[inline] - pub(crate) fn repr(&self) -> &ModuloRepr<'a> { - &self.0 - } - - /// Get mutable representation. - #[inline] - pub(crate) fn repr_mut(&mut self) -> &mut ModuloRepr<'a> { - &mut self.0 - } - +impl Modulo { /// Panics when trying to do operations on [Modulo] values from different rings. pub(crate) fn panic_different_rings() -> ! { panic!("Modulo values from different rings") } -} - -impl<'a> From> for Modulo<'a> { - #[inline] - fn from(a: ModuloSmall<'a>) -> Self { - Modulo(ModuloRepr::Small(a)) - } -} - -impl<'a> From> for Modulo<'a> { - fn from(a: ModuloLarge<'a>) -> Self { - Modulo(ModuloRepr::Large(a)) - } -} - -impl ModuloSmallRaw { - #[inline] - pub(crate) const fn normalized(self) -> Word { - self.normalized_value - } - #[inline] - pub(crate) const fn from_normalized(normalized_value: Word) -> Self { - ModuloSmallRaw { normalized_value } - } - - #[inline] - pub(crate) const fn is_valid(&self, ring: &ModuloRingSmall) -> bool { - self.normalized_value < ring.normalized_modulus() - && self.normalized_value & math::ones_word(ring.shift()) == 0 - } -} - -impl<'a> ModuloSmall<'a> { - #[inline] - pub(crate) fn new(raw: ModuloSmallRaw, ring: &'a ModuloRingSmall) -> Self { - debug_assert!(raw.is_valid(ring)); - ModuloSmall { ring, raw } - } - - /// Get the ring. - #[inline] - pub(crate) fn ring(&self) -> &'a ModuloRingSmall { - self.ring - } - - #[inline] - pub(crate) fn raw(&self) -> ModuloSmallRaw { - self.raw - } - - #[inline] - pub(crate) fn set_raw(&mut self, raw: ModuloSmallRaw) { - debug_assert!(raw.is_valid(self.ring)); - self.raw = raw; - } - - /// Checks that two values are from the same ring. - #[inline] - pub(crate) fn check_same_ring(&self, other: &ModuloSmall) { - if self.ring() != other.ring() { - Modulo::panic_different_rings(); - } - } -} - -impl<'a> ModuloLarge<'a> { - /// Create new ModuloLarge. + /// Get the ring of this value. /// - /// normalized_value must have the same length as the modulus, be in range 0..modulus, - /// and be divisible by the shift. - pub(crate) fn new(normalized_value: Vec, ring: &'a ModuloRingLarge) -> Self { - debug_assert!(ring.is_valid(&normalized_value)); - ModuloLarge { - ring, + /// # Examples + /// + /// ``` + /// # use ibig::{ModuloRing, ubig}; + /// let ring = ModuloRing::new(&ubig!(10000)); + /// let x = ring.from(12345); + /// assert_eq!(x.ring().modulus(), ubig!(10000)); + /// ``` + pub fn ring(&self) -> &ModuloRing { + &self.ring + } + + pub(crate) fn from_normalized_value(normalized_value: UBig, ring: &ModuloRing) -> Modulo { + debug_assert!(normalized_value < ring.normalized_modulus()); + Modulo { + ring: ring.clone(), normalized_value, } } - /// Get the ring. - pub(crate) fn ring(&self) -> &'a ModuloRingLarge { - self.ring - } - - /// Get normalized value. - pub(crate) fn normalized_value(&self) -> &[Word] { - &self.normalized_value + pub(crate) fn set_normalized_value(&mut self, normalized_value: UBig) { + debug_assert!(normalized_value < self.ring.normalized_modulus()); + self.normalized_value = normalized_value; } - /// Modify normalized value. - pub(crate) fn modify_normalized_value(&mut self, f: F) - where - F: FnOnce(&mut [Word], &ModuloRingLarge), - { - f(&mut self.normalized_value, self.ring); - debug_assert!(self.ring.is_valid(&self.normalized_value)); - } - - /// Checks that two values are from the same ring. - pub(crate) fn check_same_ring(&self, other: &ModuloLarge) { - if self.ring() != other.ring() { - Modulo::panic_different_rings(); - } + pub(crate) fn take_normalized_value(&mut self) -> UBig { + std::mem::take(&mut self.normalized_value) } } -impl Clone for Modulo<'_> { +impl Clone for Modulo { #[inline] fn clone(&self) -> Self { - Modulo(self.0.clone()) - } - - #[inline] - fn clone_from(&mut self, source: &Self) { - self.0.clone_from(&source.0); - } -} - -impl Clone for ModuloRepr<'_> { - #[inline] - fn clone(&self) -> Self { - match self { - ModuloRepr::Small(modulo_small) => ModuloRepr::Small(modulo_small.clone()), - ModuloRepr::Large(modulo_large) => ModuloRepr::Large(modulo_large.clone()), - } - } - - #[inline] - fn clone_from(&mut self, source: &Self) { - if let (ModuloRepr::Large(modulo_large), ModuloRepr::Large(source_large)) = - (&mut *self, source) - { - modulo_large.clone_from(source_large); - } else { - *self = source.clone(); - } - } -} - -impl Clone for ModuloLarge<'_> { - fn clone(&self) -> Self { - ModuloLarge { - ring: self.ring, + Modulo { + ring: self.ring.clone(), normalized_value: self.normalized_value.clone(), } } + #[inline] fn clone_from(&mut self, source: &Self) { - self.ring = source.ring; - if self.normalized_value.len() == source.normalized_value.len() { - self.normalized_value - .copy_from_slice(&source.normalized_value) - } else { - // We don't want to have spare capacity, so do not clone_from. - self.normalized_value = source.normalized_value.clone(); - } + self.ring.clone_from(&source.ring); + self.normalized_value.clone_from(&source.normalized_value); } } diff --git a/src/modular/modulo_ring.rs b/src/modular/modulo_ring.rs index 13dd0b1..07a34d9 100644 --- a/src/modular/modulo_ring.rs +++ b/src/modular/modulo_ring.rs @@ -1,14 +1,7 @@ //! A ring of integers modulo a positive integer. -use crate::{ - arch::word::Word, - cmp, div, - fast_divide::FastDivideNormalized, - math, - ubig::{Repr, UBig}, -}; -use alloc::vec::Vec; -use core::cmp::Ordering; +use crate::{fast_divide::FastDivideNormalized, ubig::UBig}; +use alloc::sync::Arc; /// A ring of integers modulo a positive integer. /// @@ -19,21 +12,11 @@ use core::cmp::Ordering; /// let ring = ModuloRing::new(&ubig!(100)); /// assert_eq!(ring.modulus(), ubig!(100)); /// ``` -pub struct ModuloRing(ModuloRingRepr); +#[derive(Clone)] +pub struct ModuloRing(Arc); -pub(crate) enum ModuloRingRepr { - Small(ModuloRingSmall), - Large(ModuloRingLarge), -} - -pub(crate) struct ModuloRingSmall { - normalized_modulus: Word, - shift: u32, - fast_div: FastDivideNormalized, -} - -pub(crate) struct ModuloRingLarge { - normalized_modulus: Vec, +struct ModuloRingRepr { + normalized_modulus: UBig, shift: u32, fast_div_top: FastDivideNormalized, } @@ -59,77 +42,29 @@ impl ModuloRing { /// Panics if `n` is zero. #[inline] pub fn new(n: &UBig) -> ModuloRing { - match n.repr() { - Repr::Small(0) => panic!("ModuloRing::new(0)"), - Repr::Small(word) => ModuloRing(ModuloRingRepr::Small(ModuloRingSmall::new(*word))), - Repr::Large(words) => ModuloRing(ModuloRingRepr::Large(ModuloRingLarge::new(words))), - } - } - - #[inline] - pub(crate) fn repr(&self) -> &ModuloRingRepr { - &self.0 - } -} - -impl ModuloRingSmall { - /// Create a new small ring of integers modulo `n`. - #[inline] - pub(crate) const fn new(n: Word) -> ModuloRingSmall { - debug_assert!(n != 0); - let shift = n.leading_zeros(); + let last = n.as_words().last().expect("ModuloRing::new(0)"); + let shift = last.leading_zeros(); let normalized_modulus = n << shift; - let fast_div = FastDivideNormalized::new(normalized_modulus); - ModuloRingSmall { - normalized_modulus, - shift, - fast_div, - } - } - - #[inline] - pub(crate) const fn normalized_modulus(&self) -> Word { - self.normalized_modulus - } - - #[inline] - pub(crate) const fn shift(&self) -> u32 { - self.shift - } - - #[inline] - pub(crate) const fn fast_div(&self) -> FastDivideNormalized { - self.fast_div - } -} - -impl ModuloRingLarge { - /// Create a new large ring of integers modulo `n`. - fn new(n: &[Word]) -> ModuloRingLarge { - let mut normalized_modulus = n.to_vec(); - let (shift, fast_div_top) = div::normalize_large(&mut normalized_modulus); - ModuloRingLarge { + let fast_div_top = FastDivideNormalized::new(last); + ModuloRing(Arc::new(ModuloRingRepr { normalized_modulus, shift, fast_div_top, - } + })) } - pub(crate) fn normalized_modulus(&self) -> &[Word] { + #[inline] + pub(crate) fn normalized_modulus(&self) -> &UBig { &self.normalized_modulus } + #[inline] pub(crate) fn shift(&self) -> u32 { self.shift } + #[inline] pub(crate) fn fast_div_top(&self) -> FastDivideNormalized { self.fast_div_top } - - pub(crate) fn is_valid(&self, val: &[Word]) -> bool { - val.len() == self.normalized_modulus.len() - && cmp::cmp_same_len(val, &self.normalized_modulus) == Ordering::Less - && val[0] & math::ones::(self.shift) == 0 - } } diff --git a/src/modular/mul.rs b/src/modular/mul.rs index 844cc8f..713aa88 100644 --- a/src/modular/mul.rs +++ b/src/modular/mul.rs @@ -1,158 +1,68 @@ -use crate::{ - arch::word::Word, - div, - memory::{self, Memory, MemoryAllocation}, - modular::{ - modulo::{Modulo, ModuloLarge, ModuloRepr, ModuloSmall, ModuloSmallRaw}, - modulo_ring::{ModuloRingLarge, ModuloRingSmall}, - }, - mul, - primitive::extend_word, - shift, - sign::Sign::Positive, -}; -use alloc::alloc::Layout; +use crate::modular::modulo::Modulo; use core::ops::{Mul, MulAssign}; -impl<'a> Mul> for Modulo<'a> { - type Output = Modulo<'a>; +impl Mul for Modulo { + type Output = Modulo; #[inline] - fn mul(self, rhs: Modulo<'a>) -> Modulo<'a> { - self.mul(&rhs) + fn mul(mut self, rhs: Modulo) -> Modulo { + self.mul_assign(rhs); + self } } -impl<'a> Mul<&Modulo<'a>> for Modulo<'a> { - type Output = Modulo<'a>; +impl Mul<&Modulo> for Modulo { + type Output = Modulo; #[inline] - fn mul(mut self, rhs: &Modulo<'a>) -> Modulo<'a> { + fn mul(mut self, rhs: &Modulo) -> Modulo { self.mul_assign(rhs); self } } -impl<'a> Mul> for &Modulo<'a> { - type Output = Modulo<'a>; +impl Mul for &Modulo { + type Output = Modulo; #[inline] - fn mul(self, rhs: Modulo<'a>) -> Modulo<'a> { + fn mul(self, rhs: Modulo) -> Modulo { rhs.mul(self) } } -impl<'a> Mul<&Modulo<'a>> for &Modulo<'a> { - type Output = Modulo<'a>; +impl Mul<&Modulo> for &Modulo { + type Output = Modulo; #[inline] - fn mul(self, rhs: &Modulo<'a>) -> Modulo<'a> { - self.clone().mul(rhs) - } -} - -impl<'a> MulAssign> for Modulo<'a> { - #[inline] - fn mul_assign(&mut self, rhs: Modulo<'a>) { - self.mul_assign(&rhs) - } -} - -impl<'a> MulAssign<&Modulo<'a>> for Modulo<'a> { - #[inline] - fn mul_assign(&mut self, rhs: &Modulo<'a>) { - match (self.repr_mut(), rhs.repr()) { - (ModuloRepr::Small(self_small), ModuloRepr::Small(rhs_small)) => { - self_small.check_same_ring(rhs_small); - self_small.mul_in_place(rhs_small); - } - (ModuloRepr::Large(self_large), ModuloRepr::Large(rhs_large)) => { - self_large.check_same_ring(rhs_large); - let memory_requirement = self_large.ring().mul_memory_requirement(); - let mut allocation = MemoryAllocation::new(memory_requirement); - let mut memory = allocation.memory(); - self_large.mul_in_place(rhs_large, &mut memory); - } - _ => Modulo::panic_different_rings(), - } + fn mul(self, rhs: &Modulo) -> Modulo { + self.check_same_ring(rhs); + let mut val = (self.normalized_value() >> self.ring().shift()) * rhs.normalized_value(); + // TODO: Optimize using fast_div_top. + val %= self.ring().normalized_modulus(); + self.ring().from_normalized_value(val) } } -impl ModuloSmallRaw { +impl MulAssign for Modulo { #[inline] - pub(crate) const fn mul(self, other: ModuloSmallRaw, ring: &ModuloRingSmall) -> ModuloSmallRaw { - debug_assert!(self.is_valid(ring) && other.is_valid(ring)); - let a = self.normalized(); - let b = other.normalized(); - let product = extend_word(a >> ring.shift()) * extend_word(b); - let (_, rem) = ring.fast_div().div_rem(product); - ModuloSmallRaw::from_normalized(rem) + fn mul_assign(&mut self, rhs: Modulo) { + self.check_same_ring(rhs); + let mut val = + (self.take_normalized_value() >> self.ring().shift()) * rhs.take_normalized_value(); + // TODO: Optimize using fast_div_top. + val %= self.ring().normalized_modulus(); + self.set_normalized_value(val); } } -impl<'a> ModuloSmall<'a> { - /// self *= rhs +impl MulAssign<&Modulo> for Modulo { #[inline] - pub(crate) fn mul_in_place(&mut self, rhs: &ModuloSmall<'a>) { + fn mul_assign(&mut self, rhs: &Modulo) { self.check_same_ring(rhs); - self.set_raw(self.raw().mul(rhs.raw(), self.ring())); - } -} - -impl ModuloRingLarge { - pub(crate) fn mul_memory_requirement(&self) -> Layout { - let n = self.normalized_modulus().len(); - memory::add_layout( - memory::array_layout::(2 * n), - memory::max_layout( - mul::memory_requirement_exact(2 * n, n), - div::memory_requirement_exact(2 * n, n), - ), - ) - } - - /// Returns a * b allocated in memory. - pub(crate) fn mul_normalized<'a>( - &self, - a: &[Word], - b: &[Word], - memory: &'a mut Memory, - ) -> &'a [Word] { - let modulus = self.normalized_modulus(); - let n = modulus.len(); - debug_assert!(a.len() == n && b.len() == n); - - let (product, mut memory) = memory.allocate_slice_fill::(2 * n, 0); - let overflow = mul::add_signed_mul_same_len(product, Positive, a, b, &mut memory); - assert_eq!(overflow, 0); - shift::shr_in_place(product, self.shift()); - - let _overflow = div::div_rem_in_place(product, modulus, self.fast_div_top(), &mut memory); - &product[..n] - } -} - -impl<'a> ModuloLarge<'a> { - /// self *= rhs - pub(crate) fn mul_in_place(&mut self, rhs: &ModuloLarge<'a>, memory: &mut Memory) { - self.mul_normalized_in_place(rhs.normalized_value(), memory); - } - - /// self *= self - pub(crate) fn square_in_place(&mut self, memory: &mut Memory) { - self.modify_normalized_value(|words, ring| { - words.copy_from_slice(ring.mul_normalized(words, words, memory)); - }); - } - - /// self *= rhs - pub(crate) fn mul_normalized_in_place( - &mut self, - normalized_value: &[Word], - memory: &mut Memory, - ) { - self.modify_normalized_value(|words, ring| { - words.copy_from_slice(ring.mul_normalized(words, normalized_value, memory)); - }); + let mut val = + (self.take_normalized_value() >> self.ring().shift()) * rhs.normalized_value(); + // TODO: Optimize using fast_div_top. + val %= self.ring().normalized_modulus(); + self.set_normalized_value(val); } } diff --git a/src/modular/pow.rs b/src/modular/pow.rs index fa05139..1b3214e 100644 --- a/src/modular/pow.rs +++ b/src/modular/pow.rs @@ -3,16 +3,13 @@ use crate::{ ibig::IBig, math, memory::{self, MemoryAllocation}, - modular::{ - modulo::{Modulo, ModuloLarge, ModuloRepr, ModuloSmall, ModuloSmallRaw}, - modulo_ring::ModuloRingSmall, - }, + modular::modulo::Modulo, primitive::{double_word, split_double_word, WORD_BITS, WORD_BITS_USIZE}, sign::Sign::*, ubig::{Repr::*, UBig}, }; -impl<'a> Modulo<'a> { +impl Modulo { /// Exponentiation. /// /// # Examples @@ -27,11 +24,8 @@ impl<'a> Modulo<'a> { /// assert_eq!(a.pow(&(p - ubig!(1))), ring.from(1)); /// ``` #[inline] - pub fn pow(&self, exp: &UBig) -> Modulo<'a> { - match self.repr() { - ModuloRepr::Small(self_small) => self_small.pow(exp).into(), - ModuloRepr::Large(self_large) => self_large.pow(exp).into(), - } + pub fn pow(&self, exp: &UBig) -> Modulo { + todo!() } /// Exponentiation to a signed exponent. @@ -49,7 +43,7 @@ impl<'a> Modulo<'a> { /// assert_eq!(ring.from(3).pow_signed(&ibig!(-3)), ring.from(3)); /// ``` #[inline] - pub fn pow_signed(&self, exp: &IBig) -> Modulo<'a> { + pub fn pow_signed(&self, exp: &IBig) -> Modulo { match exp.sign() { Positive => self.pow(exp.magnitude()), Negative => match self.inverse() {