1use crate::{
2 add,
3 arch::word::Word,
4 cmp, div,
5 div_const::ConstLargeDivisor,
6 error::panic_different_rings,
7 helper_macros::{
8 debug_assert_zero, forward_modular_binop_to_assign, impl_modular_binop_ref_ref_by_clone,
9 impl_modular_commutative_op_for_ref,
10 },
11 memory::{self, Memory, MemoryAllocation},
12 modular::repr::{Reduced, ReducedRepr},
13 mul,
14 primitive::{extend_word, locate_top_word_plus_one, split_dword},
15 shift, sqr,
16};
17use alloc::alloc::Layout;
18use core::ops::{Deref, Mul, MulAssign};
19use num_modular::Reducer;
20
21use super::repr::{ReducedDword, ReducedLarge, ReducedWord};
22
23forward_modular_binop_to_assign!(impl Mul, mul, MulAssign, mul_assign for Reduced);
24impl_modular_commutative_op_for_ref!(impl Mul, mul for Reduced);
25impl_modular_binop_ref_ref_by_clone!(impl Mul, mul for Reduced);
26
27impl<'a> MulAssign<&Reduced<'a>> for Reduced<'a> {
28 #[inline]
29 fn mul_assign(&mut self, rhs: &Reduced<'a>) {
30 match (self.repr_mut(), rhs.repr()) {
31 (ReducedRepr::Single(raw0, ring), ReducedRepr::Single(raw1, ring1)) => {
32 Reduced::check_same_ring_single(ring, ring1);
33 ring.0.mul_in_place(&mut raw0.0, &raw1.0)
34 }
35 (ReducedRepr::Double(raw0, ring), ReducedRepr::Double(raw1, ring1)) => {
36 Reduced::check_same_ring_double(ring, ring1);
37 ring.0.mul_in_place(&mut raw0.0, &raw1.0)
38 }
39 (ReducedRepr::Large(raw0, ring), ReducedRepr::Large(raw1, ring1)) => {
40 Reduced::check_same_ring_large(ring, ring1);
41 let memory_requirement = mul_memory_requirement(ring);
42 let mut allocation = MemoryAllocation::new(memory_requirement);
43 mul_in_place(ring, raw0, raw1, &mut allocation.memory());
44 }
45 _ => panic_different_rings(),
46 }
47 }
48}
49
50impl<'a> Reduced<'a> {
51 pub fn sqr(&self) -> Self {
63 match self.repr() {
64 ReducedRepr::Single(raw, ring) => {
65 Reduced::from_single(ReducedWord(ring.0.sqr(raw.0)), ring)
66 }
67 ReducedRepr::Double(raw, ring) => {
68 Reduced::from_double(ReducedDword(ring.0.sqr(raw.0)), ring)
69 }
70 ReducedRepr::Large(raw, ring) => {
71 let mut result = raw.clone();
72 let memory_requirement = sqr::sqr_memory_requirement(ring.normalized_divisor.len());
73 let mut allocation = MemoryAllocation::new(memory_requirement);
74 sqr_in_place(ring, &mut result, &mut allocation.memory());
75 Reduced::from_large(result, ring)
76 }
77 }
78 }
79}
80
81pub(crate) fn mul_memory_requirement(ring: &ConstLargeDivisor) -> Layout {
82 let n = ring.normalized_divisor.len();
83 memory::add_layout(
84 memory::array_layout::<Word>(2 * n),
85 memory::max_layout(
86 mul::memory_requirement_exact(2 * n, n),
87 div::memory_requirement_exact(2 * n, n),
88 ),
89 )
90}
91
92pub(crate) fn mul_normalized<'a>(
94 ring: &ConstLargeDivisor,
95 a: &[Word],
96 b: &[Word],
97 memory: &'a mut Memory,
98) -> &'a [Word] {
99 let modulus = ring.normalized_divisor.deref();
100 let n = modulus.len();
101 debug_assert!(a.len() == n && b.len() == n);
102
103 let na = locate_top_word_plus_one(a);
105 let nb = locate_top_word_plus_one(b);
106
107 let (product, mut memory) = memory.allocate_slice_fill::<Word>(n.max(na + nb), 0);
109 if na | nb == 0 {
110 return product;
111 } else if na == 1 && nb == 1 {
112 let (a0, b0) = (extend_word(a[0]), extend_word(b[0]));
113 let (lo, hi) = split_dword(a0 * b0);
114 product[0] = lo;
115 product[1] = hi;
116 } else {
117 mul::multiply(&mut product[..na + nb], &a[..na], &b[..nb], &mut memory);
118 }
119
120 debug_assert_zero!(shift::shr_in_place(product, ring.shift));
122 if na + nb > n {
123 let _overflow = div::div_rem_in_place(product, modulus, ring.fast_div_top, &mut memory);
124 &product[..n]
125 } else {
126 if cmp::cmp_same_len(product, modulus).is_ge() {
127 debug_assert_zero!(add::sub_same_len_in_place(product, modulus));
128 }
129 product
130 }
131}
132
133pub(crate) fn mul_in_place(
135 ring: &ConstLargeDivisor,
136 lhs: &mut ReducedLarge,
137 rhs: &ReducedLarge,
138 memory: &mut Memory,
139) {
140 if lhs.0 == rhs.0 {
141 let prod = sqr_normalized(ring, &lhs.0, memory);
143 lhs.0.copy_from_slice(prod)
144 } else {
145 let prod = mul_normalized(ring, &lhs.0, &rhs.0, memory);
146 lhs.0.copy_from_slice(prod)
147 }
148}
149
150pub(crate) fn sqr_normalized<'a>(
152 ring: &ConstLargeDivisor,
153 a: &[Word],
154 memory: &'a mut Memory,
155) -> &'a [Word] {
156 let modulus = ring.normalized_divisor.deref();
157 let n = modulus.len();
158 debug_assert!(a.len() == n);
159
160 let na = locate_top_word_plus_one(a);
162
163 let (product, mut memory) = memory.allocate_slice_fill::<Word>(n.max(na * 2), 0);
165 if na == 0 {
166 return product;
167 } else if na == 1 {
168 let a0 = extend_word(a[0]);
169 let (lo, hi) = split_dword(a0 * a0);
170 product[0] = lo;
171 product[1] = hi;
172 } else {
173 sqr::sqr(&mut product[..na * 2], &a[..na], &mut memory);
174 }
175
176 debug_assert_zero!(shift::shr_in_place(product, ring.shift));
178 if na * 2 > n {
179 let _overflow = div::div_rem_in_place(product, modulus, ring.fast_div_top, &mut memory);
180 &product[..n]
181 } else {
182 if cmp::cmp_same_len(product, modulus).is_ge() {
183 debug_assert_zero!(add::sub_same_len_in_place(product, modulus));
184 }
185 product
186 }
187}
188
189pub(crate) fn sqr_in_place(ring: &ConstLargeDivisor, raw: &mut ReducedLarge, memory: &mut Memory) {
191 let prod = sqr_normalized(ring, &raw.0, memory);
192 raw.0.copy_from_slice(prod)
193}