halo2curves/pluto_eris/
fp2.rs
1use core::convert::TryInto;
2use std::cmp::Ordering;
3
4use subtle::{Choice, CtOption};
5
6use super::fp::Fp;
7use crate::{
8 ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup},
9 ff_ext::{
10 quadratic::{QuadExtField, QuadExtFieldArith, SQRT},
11 ExtField, Legendre,
12 },
13};
14
15crate::impl_binops_additive!(Fp2, Fp2);
16crate::impl_binops_multiplicative!(Fp2, Fp2);
17crate::impl_binops_calls!(Fp2);
18crate::impl_sum_prod!(Fp2);
19crate::impl_tower2!(Fp, Fp2);
20crate::impl_tower2_from_uniform_bytes!(Fp, Fp2, 128);
21
22pub type Fp2 = QuadExtField<Fp>;
23
24impl QuadExtFieldArith for Fp2 {
25 type Base = Fp;
26 const SQRT: SQRT<Fp> = SQRT::Algorithm10 {
27 precompute_e: Fp2 {
28 c0: Fp::ZERO,
29 c1: Fp::from_raw([
30 0x67153f9701e19938,
31 0x5d232408689b4c6c,
32 0x021848271d63f087,
33 0x03b21f15823a404a,
34 0x667c70cf991a36e6,
35 0x7a82a3d83bc9e63a,
36 0x13e275a1fa6a13af,
37 ]),
38 },
39 precompute_f: Fp2 {
40 c0: Fp::from_raw([0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
41 c1: Fp::ZERO,
42 },
43 q_minus_1_over_4: &[
44 0x67ffff34c0000000,
45 0xa8a9fa30c001ae51,
46 0xf929e97fa3eb7ff5,
47 0xd10fe69736a29b1e,
48 0x2a00f29dbd0e499b,
49 0x004c3800035fdc39,
50 0x0900000000000900,
51 ],
52 };
53}
54
55impl ExtField for Fp2 {
56 const NON_RESIDUE: Self = Fp2 {
57 c0: Fp::from_raw([
58 0xddb6da4b5b6db6e8,
59 0x833bf7b35b701d98,
60 0x3f6072240ebe2483,
61 0x73cd928ee056022c,
62 0xce4a7f2a7bcb4495,
63 0xdbda9924971b3a9a,
64 0x0cdb6db6db6dc3b6,
65 ]),
66
67 c1: Fp::from_raw([
68 0xeb6db62d36db6db3,
69 0xb523fb0536dcde8e,
70 0x8c6d1148d5a5491b,
71 0x457b57ef5366ce1a,
72 0x489319197d79f5f3,
73 0xb71cc2492776bcc3,
74 0x07b6db6db6db756d,
75 ]),
76 };
77 fn frobenius_map(&mut self, power: usize) {
78 if power % 2 != 0 {
79 self.conjugate();
80 }
81 }
82}
83
84#[cfg(test)]
85mod test {
86
87 use rand_core::RngCore;
88
89 use super::*;
90 use crate::{arith_test, constants_test, legendre_test, serde_test, test};
91
92 constants_test!(Fp2);
93
94 arith_test!(Fp2);
95 legendre_test!(Fp2);
96 test!(arith, Fp2, sqrt_test, 1000);
97
98 serde_test!(Fp2);
99
100 crate::f2_test!(Fp2, Fp);
101 crate::frobenius_test!(Fp2, Fp, 20);
102
103 #[test]
104 fn test_fp2_squaring() {
105 let mut a = Fp2 {
107 c0: Fp::one(),
108 c1: Fp::one(),
109 };
110 a.square_assign();
112 let minus_4 = -Fp::from(4u64);
113 assert_eq!(
114 a,
115 Fp2 {
116 c0: minus_4,
117 c1: Fp::one() + Fp::one(),
118 }
119 );
120
121 let mut a = Fp2 {
123 c0: Fp::zero(),
124 c1: Fp::one(),
125 };
126 a.square_assign();
128 assert_eq!(
129 a,
130 Fp2 {
131 c0: Fp::NON_RESIDUE,
132 c1: Fp::zero(),
133 }
134 );
135 }
136
137 #[test]
138 fn test_fp2_mul_nonresidue() {
139 use rand::SeedableRng;
140 use rand_xorshift::XorShiftRng;
141 let mut rng = XorShiftRng::from_seed(crate::tests::SEED);
142 for _ in 0..1000 {
143 let mut a = Fp2::random(&mut rng);
144 let mut b = a;
145 a = a.mul_by_nonresidue();
146 b.mul_assign(&Fp2::NON_RESIDUE);
147
148 assert_eq!(a, b);
149 }
150 }
151}