use crate::prelude::*; use algebra::{Field, PairingEngine}; use core::fmt::Debug; use r1cs_core::{ConstraintSystem, SynthesisError}; pub mod bls12; pub trait PairingGadget { type G1Gadget: GroupGadget; type G2Gadget: GroupGadget; type G1PreparedGadget: ToBytesGadget + Clone + Debug; type G2PreparedGadget: ToBytesGadget + Clone + Debug; type GTGadget: FieldGadget + Clone; fn miller_loop>( cs: CS, p: &[Self::G1PreparedGadget], q: &[Self::G2PreparedGadget], ) -> Result; fn final_exponentiation>( cs: CS, p: &Self::GTGadget, ) -> Result; fn pairing>( mut cs: CS, p: Self::G1PreparedGadget, q: Self::G2PreparedGadget, ) -> Result { let tmp = Self::miller_loop(cs.ns(|| "miller loop"), &[p], &[q])?; Self::final_exponentiation(cs.ns(|| "final_exp"), &tmp) } /// Computes a product of pairings. #[must_use] fn product_of_pairings>( mut cs: CS, p: &[Self::G1PreparedGadget], q: &[Self::G2PreparedGadget], ) -> Result { let miller_result = Self::miller_loop(&mut cs.ns(|| "Miller loop"), p, q)?; Self::final_exponentiation(&mut cs.ns(|| "Final Exp"), &miller_result) } fn prepare_g1>( cs: CS, q: &Self::G1Gadget, ) -> Result; fn prepare_g2>( cs: CS, q: &Self::G2Gadget, ) -> Result; } #[cfg(test)] pub(crate) mod tests { use crate::{ bits::boolean::Boolean, prelude::*, test_constraint_system::TestConstraintSystem, Vec, }; use algebra::{ test_rng, BitIterator, Field, PairingEngine, PrimeField, ProjectiveCurve, UniformRand, }; use r1cs_core::ConstraintSystem; #[allow(dead_code)] pub(crate) fn bilinearity_test< E: PairingEngine, ConstraintF: Field, P: PairingGadget, >() { let mut cs = TestConstraintSystem::::new(); let mut rng = test_rng(); let a = E::G1Projective::rand(&mut rng); let b = E::G2Projective::rand(&mut rng); let s = E::Fr::rand(&mut rng); let mut sa = a; sa.mul_assign(s); let mut sb = b; sb.mul_assign(s); let a_g = P::G1Gadget::alloc(&mut cs.ns(|| "a"), || Ok(a)).unwrap(); let b_g = P::G2Gadget::alloc(&mut cs.ns(|| "b"), || Ok(b)).unwrap(); let sa_g = P::G1Gadget::alloc(&mut cs.ns(|| "sa"), || Ok(sa)).unwrap(); let sb_g = P::G2Gadget::alloc(&mut cs.ns(|| "sb"), || Ok(sb)).unwrap(); let a_prep_g = P::prepare_g1(&mut cs.ns(|| "a_prep"), &a_g).unwrap(); let b_prep_g = P::prepare_g2(&mut cs.ns(|| "b_prep"), &b_g).unwrap(); let sa_prep_g = P::prepare_g1(&mut cs.ns(|| "sa_prep"), &sa_g).unwrap(); let sb_prep_g = P::prepare_g2(&mut cs.ns(|| "sb_prep"), &sb_g).unwrap(); let (ans1_g, ans1_n) = { let ans_g = P::pairing(cs.ns(|| "pair(sa, b)"), sa_prep_g, b_prep_g.clone()).unwrap(); let ans_n = E::pairing(sa, b); (ans_g, ans_n) }; let (ans2_g, ans2_n) = { let ans_g = P::pairing(cs.ns(|| "pair(a, sb)"), a_prep_g.clone(), sb_prep_g).unwrap(); let ans_n = E::pairing(a, sb); (ans_g, ans_n) }; let (ans3_g, ans3_n) = { let s_iter = BitIterator::new(s.into_repr()) .map(Boolean::constant) .collect::>(); let mut ans_g = P::pairing(cs.ns(|| "pair(a, b)"), a_prep_g, b_prep_g).unwrap(); let mut ans_n = E::pairing(a, b); ans_n = ans_n.pow(s.into_repr()); ans_g = ans_g.pow(cs.ns(|| "pow"), &s_iter).unwrap(); (ans_g, ans_n) }; assert_eq!(ans1_n, ans2_n, "Failed ans1_native == ans2_native"); assert_eq!(ans2_n, ans3_n, "Failed ans2_native == ans3_native"); assert_eq!( ans1_g.get_value(), ans3_g.get_value(), "Failed ans1 == ans3" ); assert_eq!( ans1_g.get_value(), ans2_g.get_value(), "Failed ans1 == ans2" ); assert_eq!( ans2_g.get_value(), ans3_g.get_value(), "Failed ans2 == ans3" ); ans1_g .enforce_equal(&mut cs.ns(|| "ans1 == ans2?"), &ans2_g) .unwrap(); ans2_g .enforce_equal(&mut cs.ns(|| "ans2 == ans3?"), &ans3_g) .unwrap(); assert_eq!(ans1_g.get_value().unwrap(), ans1_n, "Failed native test 1"); assert_eq!(ans2_g.get_value().unwrap(), ans2_n, "Failed native test 2"); assert_eq!(ans3_g.get_value().unwrap(), ans3_n, "Failed native test 3"); if !cs.is_satisfied() { println!("Unsatisfied: {:?}", cs.which_is_unsatisfied()); } assert!(cs.is_satisfied(), "cs is not satisfied"); } }