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