halo2curves/derive/field/
tower.rs

1#[macro_export]
2macro_rules! impl_tower2 {
3    (
4        $base:ident,
5        $field:ident
6    ) => {
7        impl $field {
8            pub const SIZE: usize = $base::SIZE * 2;
9        }
10
11        impl Ord for $field {
12            #[inline(always)]
13            fn cmp(&self, other: &$field) -> Ordering {
14                match self.c1.cmp(&other.c1) {
15                    Ordering::Greater => Ordering::Greater,
16                    Ordering::Less => Ordering::Less,
17                    Ordering::Equal => self.c0.cmp(&other.c0),
18                }
19            }
20        }
21
22        impl PartialOrd for $field {
23            #[inline(always)]
24            fn partial_cmp(&self, other: &$field) -> Option<Ordering> {
25                Some(self.cmp(other))
26            }
27        }
28
29        impl From<u64> for $field {
30            fn from(val: u64) -> Self {
31                $field {
32                    c0: $base::from(val),
33                    c1: $base::ZERO,
34                }
35            }
36        }
37
38        impl $field {
39            /// Attempts to convert a little-endian byte representation of
40            /// a scalar into a `$base`, failing if the input is not canonical.
41            pub fn from_bytes(bytes: &[u8; $base::SIZE * 2]) -> CtOption<$field> {
42                let c0 = $base::from_bytes(bytes[0..$base::SIZE].try_into().unwrap());
43                let c1 = $base::from_bytes(bytes[$base::SIZE..$base::SIZE * 2].try_into().unwrap());
44                CtOption::new(
45                    $field {
46                        c0: c0.unwrap(),
47                        c1: c1.unwrap(),
48                    },
49                    c0.is_some() & c1.is_some(),
50                )
51            }
52
53            /// Converts an element of `$base` into a byte representation in
54            /// little-endian byte order.
55            #[allow(clippy::wrong_self_convention)]
56            pub fn to_bytes(&self) -> [u8; $base::SIZE * 2] {
57                let mut res = [0u8; $base::SIZE * 2];
58                let c0_bytes = self.c0.to_bytes();
59                let c1_bytes = self.c1.to_bytes();
60                res[0..$base::SIZE].copy_from_slice(&c0_bytes[..]);
61                res[$base::SIZE..$base::SIZE * 2].copy_from_slice(&c1_bytes[..]);
62                res
63            }
64
65            #[inline]
66            /// Returns whether or not this element is strictly lexicographically
67            /// larger than its negation.
68            pub fn lexicographically_largest(&self) -> Choice {
69                // If this element's c1 coefficient is lexicographically largest
70                // then it is lexicographically largest. Otherwise, in the event
71                // the c1 coefficient is zero and the c0 coefficient is
72                // lexicographically largest, then this element is lexicographically
73                // largest.
74
75                self.c1.lexicographically_largest()
76                    | (self.c1.is_zero() & self.c0.lexicographically_largest())
77            }
78        }
79
80        impl WithSmallOrderMulGroup<3> for $field {
81            const ZETA: Self = $field {
82                c0: $base::ZETA.mul_const(&$base::ZETA),
83                c1: $base::ZERO,
84            };
85        }
86
87        impl Legendre for $field {
88            fn legendre(&self) -> i64 {
89                self.norm().legendre()
90            }
91        }
92
93        impl PrimeField for $field {
94            type Repr = $crate::serde::Repr<{ $base::SIZE * 2 }>;
95
96            const MODULUS: &'static str = <$base as PrimeField>::MODULUS;
97            const MULTIPLICATIVE_GENERATOR: Self = $field {
98                c0: $base::MULTIPLICATIVE_GENERATOR,
99                c1: $base::ZERO,
100            };
101            const NUM_BITS: u32 = $base::NUM_BITS;
102            const CAPACITY: u32 = $base::NUM_BITS;
103            const S: u32 = $base::S;
104
105            // Unused variables (Because this is not a Prime Field).
106            // These are just used to pass the constants test.
107            const ROOT_OF_UNITY: Self = $field {
108                c0: $base::ROOT_OF_UNITY,
109                c1: $base::ZERO,
110            };
111            const ROOT_OF_UNITY_INV: Self = $field {
112                c0: $base::ROOT_OF_UNITY_INV,
113                c1: $base::ZERO,
114            };
115
116            const DELTA: Self = $field {
117                c0: $base::DELTA,
118                c1: $base::ZERO,
119            };
120
121            const TWO_INV: Self = $field {
122                c0: $base::TWO_INV,
123                c1: $base::ZERO,
124            };
125
126            fn from_repr(repr: Self::Repr) -> CtOption<Self> {
127                let c0: [u8; $base::SIZE] = repr[..$base::SIZE].try_into().unwrap();
128                let c0: <$base as PrimeField>::Repr = c0.into();
129                let c0 = $base::from_repr(c0);
130
131                let c1: [u8; $base::SIZE] = repr[$base::SIZE..].try_into().unwrap();
132                let c1: <$base as PrimeField>::Repr = c1.into();
133                let c1 = $base::from_repr(c1);
134
135                CtOption::new($field::new(c0.unwrap(), c1.unwrap()), Choice::from(1))
136            }
137
138            fn to_repr(&self) -> Self::Repr {
139                let mut res = Self::Repr::default();
140                let c0 = self.c0.to_repr();
141                let c1 = self.c1.to_repr();
142                res[0..$base::SIZE].copy_from_slice(&c0.as_ref()[..]);
143                res[$base::SIZE..$base::SIZE * 2].copy_from_slice(&c1.as_ref()[..]);
144                res
145            }
146
147            fn is_odd(&self) -> Choice {
148                Choice::from(self.to_repr().as_ref()[0] & 1)
149            }
150        }
151
152        impl $crate::serde::SerdeObject for $field {
153            fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self {
154                debug_assert_eq!(bytes.len(), $base::SIZE * 2);
155                let [c0, c1] = [0, $base::SIZE]
156                    .map(|i| $base::from_raw_bytes_unchecked(&bytes[i..i + $base::SIZE]));
157                Self { c0, c1 }
158            }
159            fn from_raw_bytes(bytes: &[u8]) -> Option<Self> {
160                if bytes.len() != $base::SIZE * 2 {
161                    return None;
162                }
163                let [c0, c1] =
164                    [0, $base::SIZE].map(|i| $base::from_raw_bytes(&bytes[i..i + $base::SIZE]));
165                c0.zip(c1).map(|(c0, c1)| Self { c0, c1 })
166            }
167            fn to_raw_bytes(&self) -> Vec<u8> {
168                let mut res = Vec::with_capacity($base::SIZE * 2);
169                for limb in self.c0.0.iter().chain(self.c1.0.iter()) {
170                    res.extend_from_slice(&limb.to_le_bytes());
171                }
172                res
173            }
174            fn read_raw_unchecked<R: std::io::Read>(reader: &mut R) -> Self {
175                let [c0, c1] = [(); 2].map(|_| $base::read_raw_unchecked(reader));
176                Self { c0, c1 }
177            }
178            fn read_raw<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
179                let c0 = $base::read_raw(reader)?;
180                let c1 = $base::read_raw(reader)?;
181                Ok(Self { c0, c1 })
182            }
183            fn write_raw<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
184                self.c0.write_raw(writer)?;
185                self.c1.write_raw(writer)
186            }
187        }
188    };
189}
190
191#[macro_export]
192macro_rules! impl_tower2_from_uniform_bytes {
193    (
194        $base:ident,
195        $field:ident,
196        $size:expr
197    ) => {
198        impl FromUniformBytes<{ $size }> for $field {
199            fn from_uniform_bytes(bytes: &[u8; $size]) -> Self {
200                assert!($size % 2 == 0);
201                const SIZE: usize = $size / 2;
202                let c0: [u8; SIZE] = bytes[SIZE..].try_into().unwrap();
203                let c1: [u8; SIZE] = bytes[..SIZE].try_into().unwrap();
204                Self::new(
205                    $base::from_uniform_bytes(&c0),
206                    $base::from_uniform_bytes(&c1),
207                )
208            }
209        }
210    };
211}
212
213#[macro_export]
214macro_rules! impl_cyclotomic_square {
215    (
216        $tower2:ident,
217        $tower12:ident
218    ) => {
219        impl $tower12 {
220            pub fn cyclotomic_square(&mut self) {
221                fn fp4_square(c0: &mut $tower2, c1: &mut $tower2, a0: &$tower2, a1: &$tower2) {
222                    use ff::Field;
223                    let t0 = a0.square();
224                    let t1 = a1.square();
225                    *c0 = t1.mul_by_nonresidue() + t0;
226                    *c1 = (a0 + a1).square() - t0 - t1;
227                }
228
229                let mut t3 = $tower2::zero();
230                let mut t4 = $tower2::zero();
231                let mut t5 = $tower2::zero();
232                let mut t6 = $tower2::zero();
233                fp4_square(&mut t3, &mut t4, &self.c0.c0, &self.c1.c1);
234
235                self.c0.c0 = (t3 - self.c0.c0).double() + t3;
236                self.c1.c1 = (t4 + self.c1.c1).double() + t4;
237
238                fp4_square(&mut t3, &mut t4, &self.c1.c0, &self.c0.c2);
239                fp4_square(&mut t5, &mut t6, &self.c0.c1, &self.c1.c2);
240
241                self.c0.c1 = (t3 - self.c0.c1).double() + t3;
242                self.c1.c2 = (t4 + self.c1.c2).double() + t4;
243
244                let t3 = t6.mul_by_nonresidue();
245                self.c1.c0 = (t3 + self.c1.c0).double() + t3;
246                self.c0.c2 = (t5 - self.c0.c2).double() + t5;
247            }
248        }
249    };
250}