mirror of
https://github.com/arnaucube/ark-r1cs-std.git
synced 2026-01-12 00:41:32 +01:00
Move snark-gadgets to r1cs-std
This commit is contained in:
4
r1cs-std/src/pairing/bls12/bls12_377.rs
Normal file
4
r1cs-std/src/pairing/bls12/bls12_377.rs
Normal 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>;
|
||||
0
r1cs-std/src/pairing/bls12/bls12_381.rs
Normal file
0
r1cs-std/src/pairing/bls12/bls12_381.rs
Normal file
206
r1cs-std/src/pairing/bls12/mod.rs
Normal file
206
r1cs-std/src/pairing/bls12/mod.rs
Normal 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
178
r1cs-std/src/pairing/mod.rs
Normal 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");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user