use std::fmt::Debug;
use snarkvm_curves::{traits::PairingEngine, PairingCurve};
use snarkvm_fields::PrimeField;
use snarkvm_r1cs::{errors::SynthesisError, ConstraintSystem};
use crate::{
bits::ToBytesGadget,
traits::{alloc::AllocGadget, fields::FieldGadget},
CondSelectGadget,
CurveGadget,
SumGadget,
ToConstraintFieldGadget,
ToMinimalBitsGadget,
};
pub trait PairingGadget<E: PairingEngine, F: PrimeField = <E as PairingEngine>::Fq> {
type G1Gadget: CurveGadget<E::G1Projective, F> + ToConstraintFieldGadget<F> + ToMinimalBitsGadget<F>;
type G2Gadget: CurveGadget<E::G2Projective, F> + ToConstraintFieldGadget<F> + ToMinimalBitsGadget<F>;
type G1PreparedGadget: ToBytesGadget<F> + Clone + Debug;
type G2PreparedGadget: ToBytesGadget<F>
+ AllocGadget<<E::G2Affine as PairingCurve>::Prepared, F>
+ CondSelectGadget<F>
+ SumGadget<F>
+ Clone
+ Debug;
type GTGadget: FieldGadget<E::Fqk, F> + Clone;
fn miller_loop<CS: ConstraintSystem<F>>(
cs: CS,
p: &[Self::G1PreparedGadget],
q: &[Self::G2PreparedGadget],
) -> Result<Self::GTGadget, SynthesisError>;
fn final_exponentiation<CS: ConstraintSystem<F>>(
cs: CS,
p: &Self::GTGadget,
) -> Result<Self::GTGadget, SynthesisError>;
fn pairing<CS: ConstraintSystem<F>>(
mut cs: CS,
p: Self::G1PreparedGadget,
q: Self::G2PreparedGadget,
) -> Result<Self::GTGadget, SynthesisError> {
let tmp = Self::miller_loop(cs.ns(|| "miller loop"), &[p], &[q])?;
Self::final_exponentiation(cs.ns(|| "final_exp"), &tmp)
}
fn product_of_pairings<CS: ConstraintSystem<F>>(
mut cs: CS,
p: &[Self::G1PreparedGadget],
q: &[Self::G2PreparedGadget],
) -> Result<Self::GTGadget, SynthesisError> {
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: ConstraintSystem<F>>(cs: CS, q: Self::G1Gadget)
-> Result<Self::G1PreparedGadget, SynthesisError>;
fn prepare_g2<CS: ConstraintSystem<F>>(cs: CS, q: Self::G2Gadget)
-> Result<Self::G2PreparedGadget, SynthesisError>;
}