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, 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
185/// FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0 =
186/// 7000705447348627246181409558336018323010329260726930841638672011287206690002601216854775649561085256265269640040570922609783227469279331691880282815325569032149343779036142830666859805506518426649197067288711084398033
187pub const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: BigInteger832 = BigInt::new([
188    0xb62ef36af72855d1,
189    0x676b5cef49d290fa,
190    0xd17fcf3c60947427,
191    0x5b93d992bc1b2849,
192    0x2171887cecd072cb,
193    0x879a2873f1516f4a,
194    0x8cc6856bd2cdf24e,
195    0xbff4fb6644d01993,
196    0x5dcbeea3e31ea667,
197    0x5f256f47681649f3,
198    0x2355a2b0839967fe,
199    0x144ed,
200    0x0,
201]);
202
203/// FINAL_EXPONENT_LAST_CHUNK_W1 =
204/// 86482221941698704497288378992285180119495364068003923046442785886272123124361700722982503222189455144364945735564951562986
205pub const FINAL_EXPONENT_LAST_CHUNK_W1: BigInteger832 = BigInt::new([
206    0x5657b9b57b942aea,
207    0x84f9a65f3bd54eaf,
208    0x5ea4214e35cd127,
209    0xe3cbcbc14ec1501d,
210    0xf196cb845a3092ab,
211    0x7e14627ad0e19017,
212    0x217db4,
213    0x0,
214    0x0,
215    0x0,
216    0x0,
217    0x0,
218    0x0,
219]);