Skip to main content

snarkvm_fields/
macros.rs

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