ark-curves-cherry-picked/cp6_782/src/curves/mod.rs
cp6_782/src/curves/mod.rsRaw
1use ark_ec::{
2 models::short_weierstrass::SWCurveConfig,
3 pairing::{MillerLoopOutput, Pairing, PairingOutput},
4};
5use ark_ff::{
6 biginteger::BigInteger832, AdditiveGroup, BigInt, BitIteratorBE, CyclotomicMultSubgroup, Field,
7 One,
8};
9use itertools::Itertools;
10
11use crate::{Fq, Fq3, Fq6, Fr};
12
13pub mod g1;
14pub use self::g1::{G1Affine, G1Prepared, G1Projective};
15
16pub mod g2;
17pub use self::g2::{G2Affine, G2Prepared, G2Projective};
18
19#[cfg(test)]
20mod tests;
21
22pub type GT = Fq6;
23
24#[derive(Copy, Clone, Debug, PartialEq, Eq)]
25pub struct CP6_782;
26
27impl Pairing for CP6_782 {
28 type ScalarField = Fr;
29 type BaseField = Fq;
30 type G1 = G1Projective;
31 type G1Affine = G1Affine;
32 type G1Prepared = G1Prepared;
33 type G2 = G2Projective;
34 type G2Affine = G2Affine;
35 type G2Prepared = G2Prepared;
36 type TargetField = Fq6;
37
38 fn multi_miller_loop(
39 a: impl IntoIterator<Item = impl Into<Self::G1Prepared>>,
40 b: impl IntoIterator<Item = impl Into<Self::G2Prepared>>,
41 ) -> MillerLoopOutput<Self> {
42 let mut result = Self::TargetField::one();
43 a.into_iter().zip_eq(b).for_each(|(p, q)| {
44 let (p, q) = (p.into(), q.into());
45 result *= &CP6_782::ate_miller_loop(&p, &q);
46 });
47
48 MillerLoopOutput(result)
49 }
50
51 fn final_exponentiation(r: MillerLoopOutput<Self>) -> Option<PairingOutput<Self>> {
52 Some(PairingOutput(CP6_782::final_exponentiation(&r.0)))
53 }
54}
55
56impl CP6_782 {
57 fn ate_miller_loop(p: &G1Prepared, q: &G2Prepared) -> Fq6 {
58 let p = p.0;
59 let q = q.0;
60
61 let px = p.x;
62 let py = p.y;
63 let qx = q.x;
64 let qy = q.y;
65 let mut py_twist_squared = TWIST.square();
66 py_twist_squared.mul_assign_by_fp(&py);
67
68 let mut old_rx;
69 let mut old_ry;
70 let mut rx = qx;
71 let mut ry = qy;
72 let mut f = Fq6::one();
73
74 // The for loop is executed for all bits (EXCEPT the MSB itself) of
75 // cp6_782_param_p (skipping leading zeros) in MSB to LSB order
76 for bit in BitIteratorBE::without_leading_zeros(ATE_LOOP_COUNT).skip(1) {
77 old_rx = rx;
78 old_ry = ry;
79
80 let old_rx_square = old_rx.square();
81 let old_rx_square_3 = old_rx_square.double() + &old_rx_square;
82 let old_rx_square_3_a = old_rx_square_3 + &g2::Config::COEFF_A;
83 let old_ry_double_inverse = old_ry.double().inverse().unwrap();
84
85 let gamma = old_rx_square_3_a * &old_ry_double_inverse;
86 let gamma_twist = gamma * &TWIST;
87 let gamma_old_rx = gamma * &old_rx;
88 let mut gamma_twist_px = gamma_twist;
89 gamma_twist_px.mul_assign_by_fp(&px);
90
91 let x = py_twist_squared;
92 let y = gamma_old_rx - &old_ry - &gamma_twist_px;
93 let ell_rr_at_p: Fq6 = Fq6::new(x, y);
94
95 rx = gamma.square() - &old_rx.double();
96 ry = gamma * &(old_rx - &rx) - &old_ry;
97 f = f.square() * &ell_rr_at_p;
98
99 if bit {
100 old_rx = rx;
101 old_ry = ry;
102
103 let gamma = (old_ry - &qy) * &((old_rx - &qx).inverse().unwrap());
104 let gamma_twist = gamma * &TWIST;
105 let gamma_qx = gamma * &qx;
106 let mut gamma_twist_px = gamma_twist;
107 gamma_twist_px.mul_assign_by_fp(&px);
108
109 let x = py_twist_squared;
110 let y = gamma_qx - &qy - &gamma_twist_px;
111 let ell_rq_at_p: Fq6 = Fq6::new(x, y);
112
113 rx = gamma.square() - &old_rx - &qx;
114 ry = gamma * &(old_rx - &rx) - &old_ry;
115 f = f * &ell_rq_at_p;
116 }
117 }
118 f
119 }
120
121 fn final_exponentiation(value: &Fq6) -> GT {
122 let value_inv = value.inverse().unwrap();
123 let value_to_first_chunk = CP6_782::final_exponentiation_first(value, &value_inv);
124 let value_inv_to_first_chunk = CP6_782::final_exponentiation_first(&value_inv, value);
125 CP6_782::final_exponentiation_last(&value_to_first_chunk, &value_inv_to_first_chunk)
126 }
127
128 fn final_exponentiation_first(elt: &Fq6, elt_inv: &Fq6) -> Fq6 {
129 // (q^3-1)*(q+1)
130
131 // elt_q3 = elt^(q^3)
132 let mut elt_q3 = elt.clone();
133 elt_q3.frobenius_map_in_place(3);
134 // elt_q3_over_elt = elt^(q^3-1)
135 let elt_q3_over_elt = elt_q3 * elt_inv;
136 // alpha = elt^((q^3-1) * q)
137 let mut alpha = elt_q3_over_elt.clone();
138 alpha.frobenius_map_in_place(1);
139 // beta = elt^((q^3-1)*(q+1)
140 alpha * &elt_q3_over_elt
141 }
142
143 fn final_exponentiation_last(elt: &Fq6, elt_inv: &Fq6) -> Fq6 {
144 let mut elt_q = elt.clone();
145 elt_q.frobenius_map_in_place(1);
146
147 let w1_part = elt_q.cyclotomic_exp(&FINAL_EXPONENT_LAST_CHUNK_W1);
148 let w0_part = if FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG {
149 elt_inv.cyclotomic_exp(&FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0)
150 } else {
151 elt.cyclotomic_exp(&FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0)
152 };
153
154 w1_part * &w0_part
155 }
156}
157
158/// TWIST = (0, 1, 0)
159pub const TWIST: Fq3 = Fq3::new(Fq::ZERO, Fq::ONE, Fq::ZERO);
160
161/// ATE_IS_LOOP_COUNT_NEG = false
162pub const ATE_IS_LOOP_COUNT_NEG: bool = false;
163
164/// ATE_LOOP_COUNT =
165/// 506464946133393486072777102926336625944849939610982267859828541006717966526573193706126370441346337661774335955699621
166pub const ATE_LOOP_COUNT: [u64; 13] = [
167 0x55c5b9b57b942ae8,
168 0x3d52287d3dfd424a,
169 0xcf1ff9d6a543deb7,
170 0x820c9c5711ceeebc,
171 0x549a2d44305d20fe,
172 0x50f5c131afd70235,
173 0xab3596c8617c5792,
174 0x830c728d80f9d78b,
175 0x6a7223ee72023d07,
176 0xbc5d176b746af026,
177 0xe959283d8f526663,
178 0xc4d2263babf8941f,
179 0x3848,
180];
181
182/// FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG = true
183pub const FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG: bool = true;
184
185pub const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: BigInteger832 = BigInt!("7000705447348627246181409558336018323010329260726930841638672011287206690002601216854775649561085256265269640040570922609783227469279331691880282815325569032149343779036142830666859805506518426649197067288711084398033");
186
187pub const FINAL_EXPONENT_LAST_CHUNK_W1: BigInteger832 = BigInt!("86482221941698704497288378992285180119495364068003923046442785886272123124361700722982503222189455144364945735564951562986");