snarkvm_fields/
macros.rs

1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#[macro_export]
17macro_rules! field {
18    ($name:ident, $c0:expr) => {
19        $name { 0: $c0, 1: std::marker::PhantomData }
20    };
21    ($name:ident, $c0:expr, $c1:expr $(,)?) => {
22        $name { c0: $c0, c1: $c1 }
23    };
24    ($name:ident, $c0:expr, $c1:expr, $c2:expr $(,)?) => {
25        $name { c0: $c0, c1: $c1, c2: $c2 }
26    };
27}
28
29macro_rules! impl_field_to_biginteger {
30    ($field: ident, $biginteger: ident, $parameters: ident) => {
31        #[allow(clippy::from_over_into)]
32        impl<P: $parameters> Into<$biginteger> for $field<P> {
33            fn into(self) -> $biginteger {
34                self.to_bigint()
35            }
36        }
37    };
38}
39
40macro_rules! impl_primefield_standard_sample {
41    ($field: ident, $params: ident) => {
42        impl<P: $params> rand::distributions::Distribution<$field<P>> for rand::distributions::Standard {
43            #[inline]
44            fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $field<P> {
45                loop {
46                    let mut tmp = $field(rng.sample(rand::distributions::Standard), PhantomData);
47                    // Mask away the unused bits at the beginning.
48                    tmp.0.as_mut().last_mut().map(|val| *val &= u64::MAX >> P::REPR_SHAVE_BITS);
49
50                    if tmp.is_valid() {
51                        return tmp;
52                    }
53                }
54            }
55        }
56    };
57}
58
59macro_rules! impl_primefield_from_int {
60    ($field: ident, u128, $params: ident) => {
61        impl<P: $params> From<u128> for $field<P> {
62            /// Attempts to convert an integer into a field element.
63            /// Panics if the provided integer is invalid (e.g. larger than the field modulus).
64            fn from(other: u128) -> Self {
65                let upper = (other >> 64) as u64;
66                let lower = ((other << 64) >> 64) as u64;
67                let mut default_int = P::BigInteger::default();
68                default_int.0[0] = lower;
69                default_int.0[1] = upper;
70                Self::from_bigint(default_int).unwrap()
71            }
72        }
73    };
74    ($field: ident, $int: ident, $params: ident) => {
75        impl<P: $params> From<$int> for $field<P> {
76            /// Attempts to convert an integer into a field element.
77            /// Panics if the provided integer is invalid (e.g. larger than the field modulus).
78            fn from(other: $int) -> Self {
79                Self::from_bigint(P::BigInteger::from(u64::from(other))).unwrap()
80            }
81        }
82    };
83}
84
85macro_rules! sqrt_impl {
86    ($Self:ident, $P:tt, $self:expr) => {{
87        use crate::LegendreSymbol::*;
88        // https://eprint.iacr.org/2020/1407.pdf (page 4, algorithm 1)
89        match $self.legendre() {
90            Zero => Some(*$self),
91            QuadraticNonResidue => None,
92            QuadraticResidue => {
93                let n = $P::TWO_ADICITY as u64;
94                // `T` is equivalent to `m` in the paper.
95                let v = $self.pow($P::T_MINUS_ONE_DIV_TWO);
96                let x = *$self * v.square();
97
98                let k = ((n - 1) as f64).sqrt().floor() as u64;
99                // It's important that k_2 results in a number which makes `l_minus_one_times_k`
100                // divisible by `k`, because the native arithmetic will not match the field
101                // arithmetic otherwise (native numbers will divide and round down, but field
102                // elements will end up nowhere near the native number).
103                let k_2 = if n % 2 == 0 { k / 2 } else { (n - 1) % k };
104                let k_1 = k - k_2;
105                let l_minus_one_times_k = n - 1 - k_2;
106                let l_minus_one = l_minus_one_times_k / k;
107                let l = l_minus_one + 1;
108
109                let l_s =
110                    || std::iter::repeat(l_minus_one).take(k_1 as usize).chain(std::iter::repeat(l).take(k_2 as usize));
111
112                let mut l_sum = 0;
113                let x_s = l_s().take((k as usize) - 1).map(|l| {
114                    l_sum += l;
115                    x.pow(BigInteger::from(2u64.pow((n - 1 - l_sum) as u32)))
116                });
117                let x_s = x_s.chain(Some(x));
118
119                let find = |delta: $Self| -> u64 {
120                    let mut mu = delta;
121                    let mut i = 0;
122                    while mu != -$Self::one() {
123                        mu.square_in_place();
124                        i += 1;
125                    }
126                    i
127                };
128
129                let eval = |mut delta: $Self| -> u64 {
130                    let mut s = 0u64;
131                    while delta != $Self::one() {
132                        let i = find(delta);
133                        let n_minus_one_minus_i = n - 1 - i;
134                        s += 2u64.pow(n_minus_one_minus_i as u32);
135                        if i > 0 {
136                            delta *= $Self($P::POWERS_OF_ROOTS_OF_UNITY[n_minus_one_minus_i as usize], PhantomData);
137                        } else {
138                            delta = -delta;
139                        }
140                    }
141                    s
142                };
143
144                let calculate_gamma = |i: usize, q_s: &[u64], last: bool| -> $Self {
145                    let mut gamma = $Self::one();
146                    if i != 0 {
147                        q_s.iter().zip(l_s()).enumerate().for_each(|(j, (q, l))| {
148                            let mut kappa = l_s().take(j).sum::<u64>() + 1 + l_s().skip(i + 1).sum::<u64>();
149                            if last {
150                                kappa -= 1;
151                            }
152                            let mut value = *q;
153                            (0..l as usize).for_each(|k| {
154                                let bit = value & 1 == 1;
155                                if bit {
156                                    gamma *= $Self($P::POWERS_OF_ROOTS_OF_UNITY[(kappa as usize) + k], PhantomData);
157                                }
158                                value = value.wrapping_shr(1u32);
159                            });
160                        });
161                    }
162                    gamma
163                };
164
165                let mut q_s = Vec::<u64>::with_capacity(k as usize);
166                let two_to_n_minus_l = 2u64.pow((n - l) as u32);
167                let two_to_n_minus_l_minus_one = 2u64.pow((n - l_minus_one) as u32);
168                x_s.enumerate().for_each(|(i, x)| {
169                    // Calculate g^t.
170                    // This algorithm deviates from the standard description in the paper, and is
171                    // explained in detail in page 6, in section 2.1.
172                    let gamma = calculate_gamma(i, &q_s, false);
173                    let alpha = x * gamma;
174                    q_s.push(
175                        eval(alpha) / if i < k_1 as usize { two_to_n_minus_l_minus_one } else { two_to_n_minus_l },
176                    );
177                });
178
179                // Calculate g^{t/2}.
180                let gamma = calculate_gamma(k as usize, &q_s, true);
181                Some(*$self * v * gamma)
182            }
183        }
184    }};
185}
186
187macro_rules! impl_primefield_serializer {
188    ($field: ident, $params: ident, $byte_size: expr) => {
189        impl<P: $params> CanonicalSerializeWithFlags for $field<P> {
190            #[allow(unused_qualifications)]
191            fn serialize_with_flags<W: snarkvm_utilities::io::Write, F: snarkvm_utilities::Flags>(
192                &self,
193                mut writer: W,
194                flags: F,
195            ) -> Result<(), snarkvm_utilities::serialize::SerializationError> {
196                use snarkvm_utilities::serialize::{SerializationError, number_of_bits_and_bytes};
197                // All reasonable `Flags` should be less than 8 bits in size
198                // (256 values are enough for anyone!)
199                if F::BIT_SIZE > 8 {
200                    return Err(SerializationError::NotEnoughSpace);
201                }
202
203                // Calculate the number of bytes required to represent a field element
204                // serialized with `flags`. If `F::BIT_SIZE < 8`,
205                // this is at most `$byte_size + 1`
206                let output_byte_size = number_of_bits_and_bytes(P::MODULUS_BITS as usize + F::BIT_SIZE).1;
207
208                // Write out `self` to a temporary buffer.
209                // The size of the buffer is $byte_size + 1 because `F::BIT_SIZE`
210                // is at most 8 bits.
211                let mut bytes = [0u8; $byte_size + 1];
212                self.write_le(&mut bytes[..$byte_size])?;
213
214                // Mask out the bits of the last byte that correspond to the flag.
215                bytes[output_byte_size - 1] |= flags.u8_bitmask();
216
217                writer.write_all(&bytes[..output_byte_size])?;
218                Ok(())
219            }
220
221            // Let `m = 8 * n` for some `n` be the smallest multiple of 8 greater
222            // than `P::MODULUS_BITS`.
223            // If `(m - P::MODULUS_BITS) >= F::BIT_SIZE` , then this method returns `n`;
224            // otherwise, it returns `n + 1`.
225            fn serialized_size_with_flags<F: snarkvm_utilities::Flags>(&self) -> usize {
226                snarkvm_utilities::serialize::number_of_bits_and_bytes(P::MODULUS_BITS as usize + F::BIT_SIZE).1
227            }
228        }
229
230        impl<P: $params> CanonicalSerialize for $field<P> {
231            #[allow(unused_qualifications)]
232            #[inline]
233            fn serialize_with_mode<W: snarkvm_utilities::io::Write>(
234                &self,
235                writer: W,
236                _compress: snarkvm_utilities::serialize::Compress,
237            ) -> Result<(), snarkvm_utilities::serialize::SerializationError> {
238                self.serialize_with_flags(writer, snarkvm_utilities::serialize::EmptyFlags)
239            }
240
241            #[inline]
242            fn serialized_size(&self, _compress: snarkvm_utilities::serialize::Compress) -> usize {
243                use snarkvm_utilities::EmptyFlags;
244                self.serialized_size_with_flags::<EmptyFlags>()
245            }
246        }
247
248        impl<P: $params> $field<P> {
249            const SERIALIZED_SIZE: usize =
250                snarkvm_utilities::serialize::number_of_bits_to_number_of_bytes(P::MODULUS_BITS as usize);
251        }
252
253        impl<P: $params> CanonicalDeserializeWithFlags for $field<P> {
254            #[allow(unused_qualifications)]
255            fn deserialize_with_flags<R: snarkvm_utilities::io::Read, F: snarkvm_utilities::Flags>(
256                mut reader: R,
257            ) -> Result<(Self, F), snarkvm_utilities::serialize::SerializationError> {
258                use snarkvm_utilities::serialize::SerializationError;
259                // All reasonable `Flags` should be less than 8 bits in size
260                // (256 values are enough for anyone!)
261                if F::BIT_SIZE > 8 {
262                    return Err(SerializationError::NotEnoughSpace);
263                }
264                // Calculate the number of bytes required to represent a field element
265                // serialized with `flags`. If `F::BIT_SIZE < 8`,
266                // this is at most `$byte_size + 1`
267                let output_byte_size = Self::SERIALIZED_SIZE;
268
269                let mut masked_bytes = [0; $byte_size + 1];
270                reader.read_exact(&mut masked_bytes[..output_byte_size])?;
271
272                let flags = F::from_u8_remove_flags(&mut masked_bytes[output_byte_size - 1])
273                    .ok_or(SerializationError::UnexpectedFlags)?;
274
275                Ok((Self::read_le(&masked_bytes[..])?, flags))
276            }
277        }
278
279        impl<P: $params> snarkvm_utilities::Valid for $field<P> {
280            fn check(&self) -> Result<(), snarkvm_utilities::SerializationError> {
281                Ok(())
282            }
283
284            fn batch_check<'a>(
285                _batch: impl Iterator<Item = &'a Self> + Send,
286            ) -> Result<(), snarkvm_utilities::SerializationError>
287            where
288                Self: 'a,
289            {
290                Ok(())
291            }
292        }
293
294        impl<P: $params> CanonicalDeserialize for $field<P> {
295            #[allow(unused_qualifications)]
296            fn deserialize_with_mode<R: snarkvm_utilities::io::Read>(
297                reader: R,
298                _compress: snarkvm_utilities::serialize::Compress,
299                _validate: snarkvm_utilities::serialize::Validate,
300            ) -> Result<Self, snarkvm_utilities::SerializationError> {
301                use snarkvm_utilities::serialize::EmptyFlags;
302                Self::deserialize_with_flags::<R, EmptyFlags>(reader).map(|(r, _)| r)
303            }
304        }
305
306        impl<P: $params> serde::Serialize for $field<P> {
307            fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
308                let mut bytes = Vec::with_capacity(Self::SERIALIZED_SIZE);
309                self.serialize_uncompressed(&mut bytes).map_err(serde::ser::Error::custom)?;
310
311                if serializer.is_human_readable() {
312                    serializer.collect_str(self)
313                } else {
314                    snarkvm_utilities::ToBytesSerializer::serialize(&bytes, serializer)
315                }
316            }
317        }
318
319        impl<'de, P: $params> serde::Deserialize<'de> for $field<P> {
320            fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
321                match deserializer.is_human_readable() {
322                    true => {
323                        let s: String = serde::Deserialize::deserialize(deserializer)?;
324                        core::str::FromStr::from_str(&s).map_err(serde::de::Error::custom)
325                    }
326                    false => {
327                        struct SerVisitor<P>(std::marker::PhantomData<P>);
328
329                        impl<'de, P: $params> serde::de::Visitor<'de> for SerVisitor<P> {
330                            type Value = $field<P>;
331
332                            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
333                                formatter.write_str("a valid field element")
334                            }
335
336                            fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
337                            where
338                                S: serde::de::SeqAccess<'de>,
339                            {
340                                let len = $field::<P>::SERIALIZED_SIZE;
341                                let bytes = (0..len)
342                                    .map(|_| {
343                                        seq.next_element()?
344                                            .ok_or_else(|| serde::de::Error::custom("could not read bytes"))
345                                    })
346                                    .collect::<Result<Vec<_>, _>>()?;
347
348                                CanonicalDeserialize::deserialize_compressed(&*bytes).map_err(serde::de::Error::custom)
349                            }
350                        }
351
352                        let visitor = SerVisitor(std::marker::PhantomData);
353                        deserializer.deserialize_tuple(Self::SERIALIZED_SIZE, visitor)
354                    }
355                }
356            }
357        }
358    };
359}
360
361macro_rules! impl_field_from_random_bytes_with_flags {
362    ($u64_limbs: expr) => {
363        #[inline]
364        fn from_random_bytes_with_flags<F: snarkvm_utilities::Flags>(bytes: &[u8]) -> Option<(Self, F)> {
365            (F::BIT_SIZE <= 8)
366                .then(|| {
367                    let mut result_bytes = [0u8; $u64_limbs * 8 + 1];
368                    // Copy the input into a temporary buffer.
369                    result_bytes.iter_mut().zip(bytes).for_each(|(result, input)| {
370                        *result = *input;
371                    });
372                    // This mask retains everything in the last limb
373                    // that is below `P::MODULUS_BITS`.
374                    let last_limb_mask = (u64::MAX >> P::REPR_SHAVE_BITS).to_le_bytes();
375                    let mut last_bytes_mask = [0u8; 9];
376                    last_bytes_mask[..8].copy_from_slice(&last_limb_mask);
377
378                    // Length of the buffer containing the field element and the flag.
379                    let output_byte_size = Self::SERIALIZED_SIZE;
380                    // Location of the flag is the last byte of the serialized
381                    // form of the field element.
382                    let flag_location = output_byte_size - 1;
383
384                    // At which byte is the flag located in the last limb?
385                    let flag_location_in_last_limb = flag_location - (8 * ($u64_limbs - 1));
386
387                    // Take all but the last 9 bytes.
388                    let last_bytes = &mut result_bytes[8 * ($u64_limbs - 1)..];
389
390                    // The mask only has the last `F::BIT_SIZE` bits set
391                    let flags_mask = u8::MAX.checked_shl(8 - (F::BIT_SIZE as u32)).unwrap_or(0);
392
393                    // Mask away the remaining bytes, and try to reconstruct the
394                    // flag
395                    let mut flags: u8 = 0;
396                    for (i, (b, m)) in last_bytes.iter_mut().zip(&last_bytes_mask).enumerate() {
397                        if i == flag_location_in_last_limb {
398                            flags = *b & flags_mask
399                        }
400                        *b &= m;
401                    }
402                    Self::deserialize_uncompressed(&result_bytes[..($u64_limbs * 8)])
403                        .ok()
404                        .and_then(|f| F::from_u8(flags).map(|flag| (f, flag)))
405                })
406                .flatten()
407        }
408    };
409}
410
411/// Implements Add, Sub, AddAssign, and SubAssign on Self by deferring to an implementation on &Self
412#[macro_export]
413macro_rules! impl_add_sub_from_field_ref {
414    ($type: ident, $params: ident) => {
415        #[allow(unused_qualifications)]
416        impl<P: $params> core::ops::Add<Self> for $type<P> {
417            type Output = Self;
418
419            #[inline]
420            fn add(self, other: Self) -> Self {
421                let mut result = self;
422                result.add_assign(&other);
423                result
424            }
425        }
426
427        #[allow(unused_qualifications)]
428        impl<P: $params> core::ops::Sub<Self> for $type<P> {
429            type Output = Self;
430
431            #[inline]
432            fn sub(self, other: Self) -> Self {
433                let mut result = self;
434                result.sub_assign(&other);
435                result
436            }
437        }
438
439        #[allow(unused_qualifications)]
440        impl<P: $params> core::ops::Add<&&Self> for $type<P> {
441            type Output = Self;
442
443            #[inline]
444            fn add(self, other: &&Self) -> Self {
445                let mut result = self;
446                result.add_assign(*other);
447                result
448            }
449        }
450
451        #[allow(unused_qualifications)]
452        impl<P: $params> core::ops::Sub<&&Self> for $type<P> {
453            type Output = Self;
454
455            #[inline]
456            fn sub(self, other: &&Self) -> Self {
457                let mut result = self;
458                result.sub_assign(*other);
459                result
460            }
461        }
462
463        #[allow(unused_qualifications)]
464        impl<'a, P: $params> core::ops::Add<&'a mut Self> for $type<P> {
465            type Output = Self;
466
467            #[inline]
468            fn add(self, other: &'a mut Self) -> Self {
469                let mut result = self;
470                result.add_assign(&*other);
471                result
472            }
473        }
474
475        #[allow(unused_qualifications)]
476        impl<'a, P: $params> core::ops::Sub<&'a mut Self> for $type<P> {
477            type Output = Self;
478
479            #[inline]
480            fn sub(self, other: &'a mut Self) -> Self {
481                let mut result = self;
482                result.sub_assign(&*other);
483                result
484            }
485        }
486
487        #[allow(unused_qualifications)]
488        impl<P: $params> core::ops::AddAssign<Self> for $type<P> {
489            fn add_assign(&mut self, other: Self) {
490                self.add_assign(&other)
491            }
492        }
493
494        #[allow(unused_qualifications)]
495        impl<P: $params> core::ops::SubAssign<Self> for $type<P> {
496            fn sub_assign(&mut self, other: Self) {
497                self.sub_assign(&other)
498            }
499        }
500
501        #[allow(unused_qualifications)]
502        impl<P: $params> core::ops::AddAssign<&&Self> for $type<P> {
503            fn add_assign(&mut self, other: &&Self) {
504                self.add_assign(*other)
505            }
506        }
507
508        #[allow(unused_qualifications)]
509        impl<P: $params> core::ops::SubAssign<&&Self> for $type<P> {
510            fn sub_assign(&mut self, other: &&Self) {
511                self.sub_assign(*other)
512            }
513        }
514
515        #[allow(unused_qualifications)]
516        impl<'a, P: $params> core::ops::AddAssign<&'a mut Self> for $type<P> {
517            fn add_assign(&mut self, other: &'a mut Self) {
518                self.add_assign(&*other)
519            }
520        }
521
522        #[allow(unused_qualifications)]
523        impl<'a, P: $params> core::ops::SubAssign<&'a mut Self> for $type<P> {
524            fn sub_assign(&mut self, other: &'a mut Self) {
525                self.sub_assign(&*other)
526            }
527        }
528
529        #[allow(unused_qualifications)]
530        impl<P: $params> core::iter::Sum<Self> for $type<P> {
531            fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
532                iter.fold(Self::zero(), core::ops::Add::add)
533            }
534        }
535
536        #[allow(unused_qualifications)]
537        impl<'a, P: $params> core::iter::Sum<&'a Self> for $type<P> {
538            fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
539                iter.fold(Self::zero(), core::ops::Add::add)
540            }
541        }
542    };
543}
544
545/// Implements Mul, Div, MulAssign, and DivAssign on Self by deferring to an implementation on &Self
546#[macro_export]
547macro_rules! impl_mul_div_from_field_ref {
548    ($type: ident, $params: ident) => {
549        #[allow(unused_qualifications)]
550        impl<P: $params> core::ops::Mul<Self> for $type<P> {
551            type Output = Self;
552
553            #[inline]
554            fn mul(self, other: Self) -> Self {
555                let mut result = self;
556                result.mul_assign(&other);
557                result
558            }
559        }
560
561        #[allow(unused_qualifications)]
562        impl<P: $params> core::ops::Div<Self> for $type<P> {
563            type Output = Self;
564
565            #[inline]
566            fn div(self, other: Self) -> Self {
567                let mut result = self;
568                result.div_assign(&other);
569                result
570            }
571        }
572
573        #[allow(unused_qualifications)]
574        impl<P: $params> core::ops::Mul<&&Self> for $type<P> {
575            type Output = Self;
576
577            #[inline]
578            fn mul(self, other: &&Self) -> Self {
579                let mut result = self;
580                result.mul_assign(*other);
581                result
582            }
583        }
584
585        #[allow(unused_qualifications)]
586        impl<P: $params> core::ops::Div<&&Self> for $type<P> {
587            type Output = Self;
588
589            #[inline]
590            fn div(self, other: &&Self) -> Self {
591                let mut result = self;
592                result.div_assign(*other);
593                result
594            }
595        }
596
597        #[allow(unused_qualifications)]
598        impl<'a, P: $params> core::ops::Mul<&'a mut Self> for $type<P> {
599            type Output = Self;
600
601            #[inline]
602            fn mul(self, other: &'a mut Self) -> Self {
603                let mut result = self;
604                result.mul_assign(&*other);
605                result
606            }
607        }
608
609        #[allow(unused_qualifications)]
610        impl<'a, P: $params> core::ops::Div<&'a mut Self> for $type<P> {
611            type Output = Self;
612
613            #[inline]
614            fn div(self, other: &'a mut Self) -> Self {
615                let mut result = self;
616                result.div_assign(&*other);
617                result
618            }
619        }
620
621        #[allow(unused_qualifications)]
622        impl<P: $params> core::ops::MulAssign<Self> for $type<P> {
623            fn mul_assign(&mut self, other: Self) {
624                self.mul_assign(&other)
625            }
626        }
627
628        #[allow(unused_qualifications)]
629        impl<P: $params> core::ops::DivAssign<Self> for $type<P> {
630            fn div_assign(&mut self, other: Self) {
631                self.div_assign(&other)
632            }
633        }
634
635        #[allow(unused_qualifications)]
636        impl<P: $params> core::ops::MulAssign<&&Self> for $type<P> {
637            fn mul_assign(&mut self, other: &&Self) {
638                self.mul_assign(*other)
639            }
640        }
641
642        #[allow(unused_qualifications)]
643        impl<P: $params> core::ops::DivAssign<&&Self> for $type<P> {
644            fn div_assign(&mut self, other: &&Self) {
645                self.div_assign(*other)
646            }
647        }
648
649        #[allow(unused_qualifications)]
650        impl<'a, P: $params> core::ops::MulAssign<&'a mut Self> for $type<P> {
651            fn mul_assign(&mut self, other: &'a mut Self) {
652                self.mul_assign(&*other)
653            }
654        }
655
656        #[allow(unused_qualifications)]
657        impl<'a, P: $params> core::ops::DivAssign<&'a mut Self> for $type<P> {
658            fn div_assign(&mut self, other: &'a mut Self) {
659                self.div_assign(&*other)
660            }
661        }
662
663        #[allow(unused_qualifications)]
664        impl<P: $params> core::iter::Product<Self> for $type<P> {
665            fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
666                iter.fold(Self::one(), core::ops::Mul::mul)
667            }
668        }
669
670        #[allow(unused_qualifications)]
671        impl<'a, P: $params> core::iter::Product<&'a Self> for $type<P> {
672            fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
673                iter.fold(Self::one(), Mul::mul)
674            }
675        }
676    };
677}