openvm_algebra_guest/
halo2curves.rs

1use core::ops::{Add, Mul, Sub};
2
3use halo2curves_axiom::ff;
4
5use crate::{field::Field, DivAssignUnsafe, DivUnsafe};
6
7impl<'a, F: ff::Field> DivUnsafe<&'a F> for F {
8    type Output = F;
9
10    fn div_unsafe(self, other: &'a F) -> Self::Output {
11        self * other.invert().unwrap()
12    }
13}
14
15impl<'a, F: ff::Field> DivUnsafe<&'a F> for &'a F {
16    type Output = F;
17
18    fn div_unsafe(self, other: &'a F) -> Self::Output {
19        *self * other.invert().unwrap()
20    }
21}
22
23impl<F: ff::Field> DivAssignUnsafe for F {
24    fn div_assign_unsafe(&mut self, other: Self) {
25        *self *= other.invert().unwrap();
26    }
27}
28
29impl<'a, F: ff::Field> DivAssignUnsafe<&'a F> for F {
30    fn div_assign_unsafe(&mut self, other: &'a F) {
31        *self *= other.invert().unwrap();
32    }
33}
34
35impl<F: ff::Field> Field for F
36where
37    for<'a> &'a F: Add<&'a F, Output = F> + Sub<&'a F, Output = F> + Mul<&'a F, Output = F>,
38{
39    const ZERO: Self = <F as ff::Field>::ZERO;
40    const ONE: Self = <F as ff::Field>::ONE;
41
42    type SelfRef<'a> = &'a F;
43
44    fn double_assign(&mut self) {
45        *self += *self;
46    }
47
48    fn square_assign(&mut self) {
49        *self = self.square();
50    }
51}
52
53mod bn254 {
54    use alloc::vec::Vec;
55
56    use halo2curves_axiom::bn256::{Fq, Fq12, Fq2, Fq6};
57
58    use crate::field::{ComplexConjugate, FieldExtension};
59
60    pub fn bytes_to_bn254_fq(bytes: &[u8]) -> Fq {
61        assert_eq!(bytes.len(), 32);
62        Fq::from_bytes(&bytes.try_into().unwrap()).unwrap()
63    }
64
65    /// FieldExtension for Fq2 with Fq as base field
66    impl FieldExtension<Fq> for Fq2 {
67        const D: usize = 2;
68        type Coeffs = [Fq; 2];
69
70        fn from_coeffs(coeffs: Self::Coeffs) -> Self {
71            Fq2 {
72                c0: coeffs[0],
73                c1: coeffs[1],
74            }
75        }
76
77        fn from_bytes(bytes: &[u8]) -> Self {
78            assert_eq!(bytes.len(), 64);
79            Self::from_coeffs([
80                bytes_to_bn254_fq(&bytes[0..32]),
81                bytes_to_bn254_fq(&bytes[32..64]),
82            ])
83        }
84
85        fn to_coeffs(self) -> Self::Coeffs {
86            [self.c0, self.c1]
87        }
88
89        fn to_bytes(&self) -> Vec<u8> {
90            let mut bytes = Vec::with_capacity(64);
91            bytes.extend_from_slice(&self.c0.to_bytes());
92            bytes.extend_from_slice(&self.c1.to_bytes());
93            bytes
94        }
95
96        fn embed(c0: Fq) -> Self {
97            Fq2 { c0, c1: Fq::zero() }
98        }
99
100        fn frobenius_map(&self, power: usize) -> Self {
101            let mut s = *self;
102            Fq2::frobenius_map(&mut s, power);
103            s
104        }
105
106        fn mul_base(&self, rhs: &Fq) -> Self {
107            Fq2 {
108                c0: self.c0 * rhs,
109                c1: self.c1 * rhs,
110            }
111        }
112    }
113
114    impl ComplexConjugate for Fq2 {
115        fn conjugate(self) -> Self {
116            let mut s = self;
117            Fq2::conjugate(&mut s);
118            s
119        }
120
121        fn conjugate_assign(&mut self) {
122            Fq2::conjugate(self);
123        }
124    }
125
126    /// FieldExtension for Fq12 with Fq6 as base field since halo2curves does not implement `Field` for Fq6.
127    impl FieldExtension<Fq2> for Fq12 {
128        const D: usize = 6;
129        type Coeffs = [Fq2; 6];
130
131        fn from_coeffs(coeffs: Self::Coeffs) -> Self {
132            Fq12 {
133                c0: Fq6 {
134                    c0: coeffs[0],
135                    c1: coeffs[2],
136                    c2: coeffs[4],
137                },
138                c1: Fq6 {
139                    c0: coeffs[1],
140                    c1: coeffs[3],
141                    c2: coeffs[5],
142                },
143            }
144        }
145
146        fn from_bytes(bytes: &[u8]) -> Self {
147            assert_eq!(bytes.len(), 384);
148            Self::from_coeffs([
149                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[0..64]),
150                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[64..128]),
151                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[128..192]),
152                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[192..256]),
153                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[256..320]),
154                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[320..384]),
155            ])
156        }
157
158        fn to_coeffs(self) -> Self::Coeffs {
159            [
160                self.c0.c0, self.c1.c0, self.c0.c1, self.c1.c1, self.c0.c2, self.c1.c2,
161            ]
162        }
163
164        fn to_bytes(&self) -> Vec<u8> {
165            let coeffs = self.to_coeffs();
166            let mut bytes = Vec::with_capacity(384);
167            for coeff in coeffs {
168                bytes.extend_from_slice(&coeff.to_bytes());
169            }
170            bytes
171        }
172
173        fn embed(c0: Fq2) -> Self {
174            let fq6_pt = Fq6 {
175                c0,
176                c1: Fq2::zero(),
177                c2: Fq2::zero(),
178            };
179            Fq12 {
180                c0: fq6_pt,
181                c1: Fq6::zero(),
182            }
183        }
184
185        fn frobenius_map(&self, power: usize) -> Self {
186            let mut s = *self;
187            Fq12::frobenius_map(&mut s, power);
188            s
189        }
190
191        fn mul_base(&self, rhs: &Fq2) -> Self {
192            let fq6_pt = Fq6 {
193                c0: *rhs,
194                c1: Fq2::zero(),
195                c2: Fq2::zero(),
196            };
197            Fq12 {
198                c0: self.c0 * fq6_pt,
199                c1: self.c1 * fq6_pt,
200            }
201        }
202    }
203
204    /// This is complex conjugation of Fq12 over Fq6
205    impl ComplexConjugate for Fq12 {
206        fn conjugate(self) -> Self {
207            let mut s = self;
208            Fq12::conjugate(&mut s);
209            s
210        }
211
212        fn conjugate_assign(&mut self) {
213            Fq12::conjugate(self);
214        }
215    }
216}
217
218mod bls12_381 {
219    use alloc::vec::Vec;
220
221    use halo2curves_axiom::bls12_381::{Fq, Fq12, Fq2, Fq6};
222
223    use crate::field::{ComplexConjugate, FieldExtension};
224
225    pub fn bytes_to_bls12_381_fq(bytes: &[u8]) -> Fq {
226        assert_eq!(bytes.len(), 48);
227        Fq::from_bytes(&bytes.try_into().unwrap()).unwrap()
228    }
229
230    /// FieldExtension for Fq2 with Fq as base field
231    impl FieldExtension<Fq> for Fq2 {
232        const D: usize = 2;
233        type Coeffs = [Fq; 2];
234
235        fn from_coeffs(coeffs: [Fq; 2]) -> Self {
236            Fq2 {
237                c0: coeffs[0],
238                c1: coeffs[1],
239            }
240        }
241
242        fn from_bytes(bytes: &[u8]) -> Self {
243            assert_eq!(bytes.len(), 96);
244            Self::from_coeffs([
245                bytes_to_bls12_381_fq(&bytes[0..48]),
246                bytes_to_bls12_381_fq(&bytes[48..96]),
247            ])
248        }
249
250        fn to_coeffs(self) -> Self::Coeffs {
251            [self.c0, self.c1]
252        }
253
254        fn to_bytes(&self) -> Vec<u8> {
255            let mut bytes = Vec::with_capacity(96);
256            bytes.extend_from_slice(&self.c0.to_bytes());
257            bytes.extend_from_slice(&self.c1.to_bytes());
258            bytes
259        }
260
261        fn embed(c0: Fq) -> Self {
262            Fq2 { c0, c1: Fq::zero() }
263        }
264
265        fn frobenius_map(&self, power: usize) -> Self {
266            if power % 2 == 0 {
267                *self
268            } else {
269                // note: Fq2::frobenius_map is same as Fq2::conjugate
270                Fq2::frobenius_map(self)
271            }
272        }
273
274        fn mul_base(&self, rhs: &Fq) -> Self {
275            Fq2 {
276                c0: self.c0 * rhs,
277                c1: self.c1 * rhs,
278            }
279        }
280    }
281
282    impl ComplexConjugate for Fq2 {
283        fn conjugate(self) -> Self {
284            Fq2::conjugate(&self)
285        }
286
287        fn conjugate_assign(&mut self) {
288            *self = Fq2::conjugate(self);
289        }
290    }
291
292    /// Note that halo2curves does not implement `Field` for Fq6, so we need to implement the intermediate points manually.
293    ///
294    /// FieldExtension for Fq12 with Fq2 as base field since halo2curves does not implement `Field` for Fq6.
295    impl FieldExtension<Fq2> for Fq12 {
296        const D: usize = 6;
297        type Coeffs = [Fq2; 6];
298
299        fn from_coeffs(coeffs: [Fq2; 6]) -> Self {
300            Fq12 {
301                c0: Fq6 {
302                    c0: coeffs[0],
303                    c1: coeffs[2],
304                    c2: coeffs[4],
305                },
306                c1: Fq6 {
307                    c0: coeffs[1],
308                    c1: coeffs[3],
309                    c2: coeffs[5],
310                },
311            }
312        }
313
314        fn from_bytes(bytes: &[u8]) -> Self {
315            assert_eq!(bytes.len(), 576);
316            Self::from_coeffs([
317                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[0..96]),
318                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[96..192]),
319                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[192..288]),
320                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[288..384]),
321                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[384..480]),
322                <Fq2 as FieldExtension<Fq>>::from_bytes(&bytes[480..576]),
323            ])
324        }
325
326        fn to_coeffs(self) -> Self::Coeffs {
327            [
328                self.c0.c0, self.c1.c0, self.c0.c1, self.c1.c1, self.c0.c2, self.c1.c2,
329            ]
330        }
331
332        fn to_bytes(&self) -> Vec<u8> {
333            let coeffs = self.to_coeffs();
334            let mut bytes = Vec::with_capacity(576);
335            for coeff in coeffs {
336                bytes.extend_from_slice(&coeff.to_bytes());
337            }
338            bytes
339        }
340
341        fn embed(base_elem: Fq2) -> Self {
342            let fq6_pt = Fq6 {
343                c0: base_elem,
344                c1: Fq2::zero(),
345                c2: Fq2::zero(),
346            };
347            Fq12 {
348                c0: fq6_pt,
349                c1: Fq6::zero(),
350            }
351        }
352
353        /// Raises this element to p^power, where p is prime characteristic of `Self`.
354        fn frobenius_map(&self, power: usize) -> Self {
355            let mut x = *self;
356            for _ in 0..power % 12 {
357                x = Fq12::frobenius_map(&x);
358            }
359            x
360        }
361
362        fn mul_base(&self, rhs: &Fq2) -> Self {
363            let fq6_pt = Fq6 {
364                c0: *rhs,
365                c1: Fq2::zero(),
366                c2: Fq2::zero(),
367            };
368            Fq12 {
369                c0: self.c0 * fq6_pt,
370                c1: self.c1 * fq6_pt,
371            }
372        }
373    }
374
375    /// This is complex conjugation of Fq12 over Fq6
376    impl ComplexConjugate for Fq12 {
377        fn conjugate(self) -> Self {
378            Fq12::conjugate(&self)
379        }
380
381        fn conjugate_assign(&mut self) {
382            *self = Fq12::conjugate(self);
383        }
384    }
385}