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