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 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 #[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 pub fn lexicographically_largest(&self) -> Choice {
69 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 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}