1use super::repr::{Reduced, ReducedDword, ReducedLarge, ReducedRepr, ReducedWord};
4use crate::{add, cmp, div_const::ConstLargeDivisor, error::panic_different_rings, shift};
5use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
6use num_modular::Reducer;
7
8impl<'a> Neg for Reduced<'a> {
9 type Output = Reduced<'a>;
10
11 #[inline]
12 fn neg(self) -> Reduced<'a> {
13 match self.into_repr() {
14 ReducedRepr::Single(raw, ring) => {
15 Self::from_single(ReducedWord(ring.0.neg(raw.0)), ring)
16 }
17 ReducedRepr::Double(raw, ring) => {
18 Self::from_double(ReducedDword(ring.0.neg(raw.0)), ring)
19 }
20 ReducedRepr::Large(mut raw, ring) => {
21 negate_in_place(ring, &mut raw);
22 Self::from_large(raw, ring)
23 }
24 }
25 }
26}
27
28impl<'a> Neg for &Reduced<'a> {
29 type Output = Reduced<'a>;
30
31 #[inline]
32 fn neg(self) -> Reduced<'a> {
33 self.clone().neg()
34 }
35}
36
37impl<'a> Add<Reduced<'a>> for Reduced<'a> {
38 type Output = Reduced<'a>;
39
40 #[inline]
41 fn add(self, rhs: Reduced<'a>) -> Reduced<'a> {
42 self.add(&rhs)
43 }
44}
45
46impl<'a> Add<&Reduced<'a>> for Reduced<'a> {
47 type Output = Reduced<'a>;
48
49 #[inline]
50 fn add(mut self, rhs: &Reduced<'a>) -> Reduced<'a> {
51 self.add_assign(rhs);
52 self
53 }
54}
55
56impl<'a> Add<Reduced<'a>> for &Reduced<'a> {
57 type Output = Reduced<'a>;
58
59 #[inline]
60 fn add(self, rhs: Reduced<'a>) -> Reduced<'a> {
61 rhs.add(self)
62 }
63}
64
65impl<'a> Add<&Reduced<'a>> for &Reduced<'a> {
66 type Output = Reduced<'a>;
67
68 #[inline]
69 fn add(self, rhs: &Reduced<'a>) -> Reduced<'a> {
70 self.clone().add(rhs)
71 }
72}
73
74impl<'a> AddAssign<Reduced<'a>> for Reduced<'a> {
75 #[inline]
76 fn add_assign(&mut self, rhs: Reduced<'a>) {
77 self.add_assign(&rhs)
78 }
79}
80
81impl<'a> AddAssign<&Reduced<'a>> for Reduced<'a> {
82 #[inline]
83 fn add_assign(&mut self, rhs: &Reduced<'a>) {
84 match (self.repr_mut(), rhs.repr()) {
85 (ReducedRepr::Single(raw0, ring), ReducedRepr::Single(raw1, ring1)) => {
86 Reduced::check_same_ring_single(ring, ring1);
87 ring.0.add_in_place(&mut raw0.0, &raw1.0);
88 }
89 (ReducedRepr::Double(raw0, ring), ReducedRepr::Double(raw1, ring1)) => {
90 Reduced::check_same_ring_double(ring, ring1);
91 ring.0.add_in_place(&mut raw0.0, &raw1.0);
92 }
93 (ReducedRepr::Large(raw0, ring), ReducedRepr::Large(raw1, ring1)) => {
94 Reduced::check_same_ring_large(ring, ring1);
95 add_in_place(ring, raw0, raw1);
96 }
97 _ => panic_different_rings(),
98 }
99 }
100}
101
102impl<'a> Sub<Reduced<'a>> for Reduced<'a> {
103 type Output = Reduced<'a>;
104
105 #[inline]
106 fn sub(self, rhs: Reduced<'a>) -> Reduced<'a> {
107 self.sub(&rhs)
108 }
109}
110
111impl<'a> Sub<&Reduced<'a>> for Reduced<'a> {
112 type Output = Reduced<'a>;
113
114 #[inline]
115 fn sub(mut self, rhs: &Reduced<'a>) -> Reduced<'a> {
116 self.sub_assign(rhs);
117 self
118 }
119}
120
121impl<'a> Sub<Reduced<'a>> for &Reduced<'a> {
122 type Output = Reduced<'a>;
123
124 #[inline]
125 fn sub(self, mut rhs: Reduced<'a>) -> Reduced<'a> {
126 match (self.repr(), rhs.repr_mut()) {
127 (ReducedRepr::Single(raw0, ring), ReducedRepr::Single(raw1, ring1)) => {
128 Reduced::check_same_ring_single(ring, ring1);
129 raw1.0 = ring.0.sub(&raw0.0, &raw1.0);
130 }
131 (ReducedRepr::Double(raw0, ring), ReducedRepr::Double(raw1, ring1)) => {
132 Reduced::check_same_ring_double(ring, ring1);
133 raw1.0 = ring.0.sub(&raw0.0, &raw1.0);
134 }
135 (ReducedRepr::Large(raw0, ring), ReducedRepr::Large(raw1, ring1)) => {
136 Reduced::check_same_ring_large(ring, ring1);
137 sub_in_place_swap(ring, raw0, raw1);
138 }
139 _ => panic_different_rings(),
140 }
141 rhs
142 }
143}
144
145impl<'a> Sub<&Reduced<'a>> for &Reduced<'a> {
146 type Output = Reduced<'a>;
147
148 #[inline]
149 fn sub(self, rhs: &Reduced<'a>) -> Reduced<'a> {
150 self.clone().sub(rhs)
151 }
152}
153
154impl<'a> SubAssign<Reduced<'a>> for Reduced<'a> {
155 #[inline]
156 fn sub_assign(&mut self, rhs: Reduced<'a>) {
157 self.sub_assign(&rhs)
158 }
159}
160
161impl<'a> SubAssign<&Reduced<'a>> for Reduced<'a> {
162 #[inline]
163 fn sub_assign(&mut self, rhs: &Reduced<'a>) {
164 match (self.repr_mut(), rhs.repr()) {
165 (ReducedRepr::Single(raw0, ring), ReducedRepr::Single(raw1, ring1)) => {
166 Reduced::check_same_ring_single(ring, ring1);
167 ring.0.sub_in_place(&mut raw0.0, &raw1.0);
168 }
169 (ReducedRepr::Double(raw0, ring), ReducedRepr::Double(raw1, ring1)) => {
170 Reduced::check_same_ring_double(ring, ring1);
171 ring.0.sub_in_place(&mut raw0.0, &raw1.0);
172 }
173 (ReducedRepr::Large(raw0, ring), ReducedRepr::Large(raw1, ring1)) => {
174 Reduced::check_same_ring_large(ring, ring1);
175 sub_in_place(ring, raw0, raw1);
176 }
177 _ => panic_different_rings(),
178 }
179 }
180}
181
182impl<'a> Reduced<'a> {
183 pub fn dbl(self) -> Self {
195 match self.into_repr() {
196 ReducedRepr::Single(raw, ring) => {
197 Reduced::from_single(ReducedWord(ring.0.dbl(raw.0)), ring)
198 }
199 ReducedRepr::Double(raw, ring) => {
200 Reduced::from_double(ReducedDword(ring.0.dbl(raw.0)), ring)
201 }
202 ReducedRepr::Large(mut raw, ring) => {
203 dbl_in_place(ring, &mut raw);
204 Reduced::from_large(raw, ring)
205 }
206 }
207 }
208}
209
210pub(crate) fn negate_in_place(ring: &ConstLargeDivisor, raw: &mut ReducedLarge) {
211 debug_assert!(raw.is_valid(ring));
212 if !raw.0.iter().all(|w| *w == 0) {
213 let overflow = add::sub_same_len_in_place_swap(&ring.normalized_divisor, &mut raw.0);
214 debug_assert!(!overflow);
215 }
216}
217
218fn add_in_place(ring: &ConstLargeDivisor, lhs: &mut ReducedLarge, rhs: &ReducedLarge) {
219 debug_assert!(lhs.is_valid(ring) && rhs.is_valid(ring));
220 let modulus = &ring.normalized_divisor;
221 let overflow = add::add_same_len_in_place(&mut lhs.0, &rhs.0);
222 if overflow || cmp::cmp_same_len(&lhs.0, modulus).is_ge() {
223 let overflow2 = add::sub_same_len_in_place(&mut lhs.0, modulus);
224 debug_assert_eq!(overflow, overflow2);
225 }
226}
227
228fn dbl_in_place(ring: &ConstLargeDivisor, raw: &mut ReducedLarge) {
229 debug_assert!(raw.is_valid(ring));
230 let modulus = &ring.normalized_divisor;
231 let overflow = shift::shl_in_place(&mut raw.0, 1) > 0;
232 if overflow || cmp::cmp_same_len(&raw.0, modulus).is_ge() {
233 let overflow2 = add::sub_same_len_in_place(&mut raw.0, modulus);
234 debug_assert_eq!(overflow, overflow2);
235 }
236}
237
238fn sub_in_place(ring: &ConstLargeDivisor, lhs: &mut ReducedLarge, rhs: &ReducedLarge) {
239 debug_assert!(lhs.is_valid(ring) && rhs.is_valid(ring));
240 let modulus = &ring.normalized_divisor;
241 let overflow = add::sub_same_len_in_place(&mut lhs.0, &rhs.0);
242 if overflow {
243 let overflow2 = add::add_same_len_in_place(&mut lhs.0, modulus);
244 debug_assert!(overflow2);
245 }
246}
247
248fn sub_in_place_swap(ring: &ConstLargeDivisor, lhs: &ReducedLarge, rhs: &mut ReducedLarge) {
250 debug_assert!(lhs.is_valid(ring) && rhs.is_valid(ring));
251 let modulus = &ring.normalized_divisor;
252 let overflow = add::sub_same_len_in_place_swap(&lhs.0, &mut rhs.0);
253 if overflow {
254 let overflow2 = add::add_same_len_in_place(&mut rhs.0, modulus);
255 debug_assert!(overflow2);
256 }
257}