Move snark-gadgets to r1cs-std

This commit is contained in:
Pratyush Mishra
2019-08-12 16:52:26 -07:00
parent 32151738b2
commit e00d667330
36 changed files with 10193 additions and 1 deletions

View File

@@ -0,0 +1,4 @@
use crate::pairing::bls12::PairingGadget as Bls12PG;
use algebra::curves::bls12_377::Bls12_377Parameters;
pub type PairingGadget = Bls12PG<Bls12_377Parameters>;

View File

View File

@@ -0,0 +1,206 @@
use r1cs_core::{ConstraintSystem, SynthesisError};
use super::PairingGadget as PG;
use crate::{
fields::{fp::FpGadget, fp12::Fp12Gadget, fp2::Fp2Gadget, FieldGadget},
groups::bls12::{G1Gadget, G1PreparedGadget, G2Gadget, G2PreparedGadget},
};
use algebra::{
curves::{
bls12::{
Bls12, Bls12Parameters, G1Affine, G1Prepared, G1Projective, G2Affine, G2Prepared,
G2Projective, TwistType,
},
models::ModelParameters,
PairingCurve,
},
fields::{fp12_2over3over2::Fp12, BitIterator},
};
use std::marker::PhantomData;
pub mod bls12_377;
pub struct PairingGadget<P: Bls12Parameters>(PhantomData<P>);
type Fp2G<P> = Fp2Gadget<<P as Bls12Parameters>::Fp2Params, <P as Bls12Parameters>::Fp>;
impl<P: Bls12Parameters> PairingGadget<P> {
// Evaluate the line function at point p.
fn ell<CS: ConstraintSystem<P::Fp>>(
mut cs: CS,
f: &mut Fp12Gadget<P::Fp12Params, P::Fp>,
coeffs: &(Fp2G<P>, Fp2G<P>),
p: &G1Gadget<P>,
) -> Result<(), SynthesisError> {
let zero = FpGadget::<P::Fp>::zero(cs.ns(|| "fpg zero"))?;
match P::TWIST_TYPE {
TwistType::M => {
let c0 = coeffs.0.clone();
let mut c1 = coeffs.1.clone();
let c2 = Fp2G::<P>::new(p.y.clone(), zero.clone());
c1.c0 = c1.c0.mul(cs.ns(|| "mul c1.c0"), &p.x)?;
c1.c1 = c1.c1.mul(cs.ns(|| "mul c1.c1"), &p.x)?;
*f = f.mul_by_014(cs.ns(|| "sparse mul f"), &c0, &c1, &c2)?;
Ok(())
},
TwistType::D => {
let c0 = Fp2G::<P>::new(p.y.clone(), zero.clone());
let mut c1 = coeffs.0.clone();
let c2 = coeffs.1.clone();
c1.c0 = c1.c0.mul(cs.ns(|| "mul c1.c0"), &p.x)?;
c1.c1 = c1.c1.mul(cs.ns(|| "mul c1.c1"), &p.x)?;
*f = f.mul_by_034(cs.ns(|| "sparse mul f"), &c0, &c1, &c2)?;
Ok(())
},
}
}
fn exp_by_x<CS: ConstraintSystem<P::Fp>>(
mut cs: CS,
f: &Fp12Gadget<P::Fp12Params, P::Fp>,
) -> Result<Fp12Gadget<P::Fp12Params, P::Fp>, SynthesisError> {
let mut result = f.cyclotomic_exp(cs.ns(|| "exp_by_x"), P::X)?;
if P::X_IS_NEGATIVE {
result.conjugate_in_place(cs.ns(|| "conjugate"))?;
}
Ok(result)
}
}
impl<P: Bls12Parameters> PG<Bls12<P>, P::Fp> for PairingGadget<P>
where
G1Affine<P>: PairingCurve<
BaseField = <P::G1Parameters as ModelParameters>::BaseField,
ScalarField = <P::G1Parameters as ModelParameters>::ScalarField,
Projective = G1Projective<P>,
PairWith = G2Affine<P>,
Prepared = G1Prepared<P>,
PairingResult = Fp12<P::Fp12Params>,
>,
G2Affine<P>: PairingCurve<
BaseField = <P::G2Parameters as ModelParameters>::BaseField,
ScalarField = <P::G1Parameters as ModelParameters>::ScalarField,
Projective = G2Projective<P>,
PairWith = G1Affine<P>,
Prepared = G2Prepared<P>,
PairingResult = Fp12<P::Fp12Params>,
>,
{
type G1Gadget = G1Gadget<P>;
type G2Gadget = G2Gadget<P>;
type G1PreparedGadget = G1PreparedGadget<P>;
type G2PreparedGadget = G2PreparedGadget<P>;
type GTGadget = Fp12Gadget<P::Fp12Params, P::Fp>;
fn miller_loop<CS: ConstraintSystem<P::Fp>>(
mut cs: CS,
ps: &[Self::G1PreparedGadget],
qs: &[Self::G2PreparedGadget],
) -> Result<Self::GTGadget, SynthesisError> {
let mut pairs = vec![];
for (p, q) in ps.into_iter().zip(qs.into_iter()) {
pairs.push((p, q.ell_coeffs.iter()));
}
let mut f = Self::GTGadget::one(cs.ns(|| "one"))?;
for (j, i) in BitIterator::new(P::X).skip(1).enumerate() {
let mut cs = cs.ns(|| format!("Iteration {}", j));
f.square_in_place(cs.ns(|| "square"))?;
for (k, &mut (p, ref mut coeffs)) in pairs.iter_mut().enumerate() {
let cs = cs.ns(|| format!("Double input {}", k));
Self::ell(cs, &mut f, coeffs.next().unwrap(), &p.0)?;
}
if i {
for (k, &mut (p, ref mut coeffs)) in pairs.iter_mut().enumerate() {
let cs = cs.ns(|| format!("Addition input {}", k));
Self::ell(cs, &mut f, &coeffs.next().unwrap(), &p.0)?;
}
}
}
if P::X_IS_NEGATIVE {
f.conjugate_in_place(cs.ns(|| "f conjugate"))?;
}
Ok(f)
}
fn final_exponentiation<CS: ConstraintSystem<P::Fp>>(
mut cs: CS,
f: &Self::GTGadget,
) -> Result<Self::GTGadget, SynthesisError> {
// Computing the final exponentation following
// https://eprint.iacr.org/2016/130.pdf.
// We don't use their "faster" formula because it is difficult to make
// it work for curves with odd `P::X`.
// Hence we implement the slower algorithm from Table 1 below.
let f1 = f.frobenius_map(cs.ns(|| "frobmap 1"), 6)?;
f.inverse(cs.ns(|| "inverse 1")).and_then(|mut f2| {
// f2 = f^(-1);
// r = f^(p^6 - 1)
let mut r = f1;
r.mul_in_place(cs.ns(|| "r = f1 * f2"), &f2)?;
// f2 = f^(p^6 - 1)
f2 = r.clone();
// r = f^((p^6 - 1)(p^2))
r.frobenius_map_in_place(cs.ns(|| "frobenius map 2"), 2)?;
// r = f^((p^6 - 1)(p^2) + (p^6 - 1))
// r = f^((p^6 - 1)(p^2 + 1))
r.mul_in_place(cs.ns(|| "mul 0"), &f2)?;
// Hard part of the final exponentation is below:
// From https://eprint.iacr.org/2016/130.pdf, Table 1
let mut y0 = r.cyclotomic_square(cs.ns(|| "cyclotomic_sq 1"))?;
y0.conjugate_in_place(&mut cs.ns(|| "conjugate 2"))?;
let mut y5 = Self::exp_by_x(&mut cs.ns(|| "exp_by_x 1"), &r)?;
let mut y1 = y5.cyclotomic_square(&mut cs.ns(|| "square 1"))?;
let mut y3 = y0.mul(&mut cs.ns(|| "mul 1"), &y5)?;
y0 = Self::exp_by_x(cs.ns(|| "exp_by_x 2"), &y3)?;
let y2 = Self::exp_by_x(cs.ns(|| "exp_by_x 3"), &y0)?;
let mut y4 = Self::exp_by_x(cs.ns(|| "exp_by_x 4"), &y2)?;
y4.mul_in_place(cs.ns(|| "mul 2"), &y1)?;
y1 = Self::exp_by_x(cs.ns(|| "exp_by_x 5"), &y4)?;
y3.conjugate_in_place(cs.ns(|| "conjugate 3"))?;
y1.mul_in_place(cs.ns(|| "mul 3"), &y3)?;
y1.mul_in_place(cs.ns(|| "mul 4"), &r)?;
y3 = r.clone();
y3.conjugate_in_place(cs.ns(|| "conjugate 4"))?;
y0.mul_in_place(cs.ns(|| "mul 5"), &r)?;
y0.frobenius_map_in_place(cs.ns(|| "frobmap 3"), 3)?;
y4.mul_in_place(cs.ns(|| "mul 6"), &y3)?;
y4.frobenius_map_in_place(cs.ns(|| "frobmap 4"), 1)?;
y5.mul_in_place(cs.ns(|| "mul 7"), &y2)?;
y5.frobenius_map_in_place(cs.ns(|| "frobmap 5"), 2)?;
y5.mul_in_place(cs.ns(|| "mul 8"), &y0)?;
y5.mul_in_place(cs.ns(|| "mul 9"), &y4)?;
y5.mul_in_place(cs.ns(|| "mul 10"), &y1)?;
Ok(y5)
})
}
fn prepare_g1<CS: ConstraintSystem<P::Fp>>(
cs: CS,
p: &Self::G1Gadget,
) -> Result<Self::G1PreparedGadget, SynthesisError> {
Self::G1PreparedGadget::from_affine(cs, p)
}
fn prepare_g2<CS: ConstraintSystem<P::Fp>>(
cs: CS,
q: &Self::G2Gadget,
) -> Result<Self::G2PreparedGadget, SynthesisError> {
Self::G2PreparedGadget::from_affine(cs, q)
}
}

178
r1cs-std/src/pairing/mod.rs Normal file
View File

@@ -0,0 +1,178 @@
use crate::prelude::*;
use algebra::{Field, PairingEngine};
use r1cs_core::{ConstraintSystem, SynthesisError};
use std::fmt::Debug;
pub mod bls12;
pub use self::bls12::bls12_377;
pub trait PairingGadget<PairingE: PairingEngine, ConstraintF: Field> {
type G1Gadget: GroupGadget<PairingE::G1Projective, ConstraintF>;
type G2Gadget: GroupGadget<PairingE::G2Projective, ConstraintF>;
type G1PreparedGadget: ToBytesGadget<ConstraintF> + Clone + Debug;
type G2PreparedGadget: ToBytesGadget<ConstraintF> + Clone + Debug;
type GTGadget: FieldGadget<PairingE::Fqk, ConstraintF> + Clone;
fn miller_loop<CS: ConstraintSystem<ConstraintF>>(
cs: CS,
p: &[Self::G1PreparedGadget],
q: &[Self::G2PreparedGadget],
) -> Result<Self::GTGadget, SynthesisError>;
fn final_exponentiation<CS: ConstraintSystem<ConstraintF>>(
cs: CS,
p: &Self::GTGadget,
) -> Result<Self::GTGadget, SynthesisError>;
fn pairing<CS: ConstraintSystem<ConstraintF>>(
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)
}
/// Computes a product of pairings.
#[must_use]
fn product_of_pairings<CS: ConstraintSystem<ConstraintF>>(
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<ConstraintF>>(
cs: CS,
q: &Self::G1Gadget,
) -> Result<Self::G1PreparedGadget, SynthesisError>;
fn prepare_g2<CS: ConstraintSystem<ConstraintF>>(
cs: CS,
q: &Self::G2Gadget,
) -> Result<Self::G2PreparedGadget, SynthesisError>;
}
#[cfg(test)]
mod test {
// use rand;
use crate::{boolean::Boolean, test_constraint_system::TestConstraintSystem};
use algebra::{BitIterator, Field};
use r1cs_core::ConstraintSystem;
#[test]
fn bls12_377_gadget_bilinearity_test() {
use algebra::{
fields::{bls12_377::{fr::Fr, fq::Fq}, PrimeField},
PairingEngine, ProjectiveCurve,
};
use super::bls12_377::PairingGadget;
use crate::{
fields::FieldGadget,
groups::bls12::bls12_377::{G1Gadget, G1PreparedGadget, G2Gadget, G2PreparedGadget},
pairing::PairingGadget as _,
utils::{AllocGadget, EqGadget},
};
use algebra::curves::bls12_377::{Bls12_377, G1Projective, G2Projective};
use std::ops::Mul;
let mut cs = TestConstraintSystem::<Fq>::new();
// let a: G1Projective = rand::random();
// let b: G2Projective = rand::random();
// let s: Fr = rand::random();
let a: G1Projective = G1Projective::prime_subgroup_generator();
let b: G2Projective = G2Projective::prime_subgroup_generator();
let s: Fr = Fr::one() + &Fr::one();
let sa = a.mul(&s);
let sb = b.mul(&s);
let a_g = G1Gadget::alloc(&mut cs.ns(|| "a"), || Ok(a)).unwrap();
let b_g = G2Gadget::alloc(&mut cs.ns(|| "b"), || Ok(b)).unwrap();
let sa_g = G1Gadget::alloc(&mut cs.ns(|| "sa"), || Ok(sa)).unwrap();
let sb_g = G2Gadget::alloc(&mut cs.ns(|| "sb"), || Ok(sb)).unwrap();
let a_prep_g = G1PreparedGadget::from_affine(&mut cs.ns(|| "a_prep"), &a_g).unwrap();
let b_prep_g = G2PreparedGadget::from_affine(&mut cs.ns(|| "b_prep"), &b_g).unwrap();
let sa_prep_g = G1PreparedGadget::from_affine(&mut cs.ns(|| "sa_prep"), &sa_g).unwrap();
let sb_prep_g = G2PreparedGadget::from_affine(&mut cs.ns(|| "sb_prep"), &sb_g).unwrap();
let (ans1_g, ans1_n) = {
let ans_g = PairingGadget::pairing(
cs.ns(|| "pair(sa, b)"),
sa_prep_g.clone(),
b_prep_g.clone(),
)
.unwrap();
let ans_n = Bls12_377::pairing(sa, b);
(ans_g, ans_n)
};
let (ans2_g, ans2_n) = {
let ans_g = PairingGadget::pairing(
cs.ns(|| "pair(a, sb)"),
a_prep_g.clone(),
sb_prep_g.clone(),
)
.unwrap();
let ans_n = Bls12_377::pairing(a, sb);
(ans_g, ans_n)
};
let (ans3_g, ans3_n) = {
let s_iter = BitIterator::new(s.into_repr())
.map(|bit| Boolean::constant(bit))
.collect::<Vec<_>>();
let mut ans_g =
PairingGadget::pairing(cs.ns(|| "pair(a, b)"), a_prep_g.clone(), b_prep_g.clone())
.unwrap();
let mut ans_n = Bls12_377::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");
}
}