openvm_algebra_guest/
halo2curves.rs

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