use crate::{
curves::templates::bls12::{
Bls12PairingGadget,
G1Gadget as Bls12G1Gadget,
G1PreparedGadget as Bls12G1PreparedGadget,
G2Gadget as Bls12G2Gadget,
G2PreparedGadget as Bls12G2PreparedGadget,
},
fields::{Fp12Gadget, Fp2Gadget, Fp6Gadget, FpGadget},
};
use snarkvm_curves::bls12_377::{Bls12_377Parameters, Fq, Fq12Parameters, Fq2Parameters, Fq6Parameters};
pub type FqGadget = FpGadget<Fq>;
pub type Fq2Gadget = Fp2Gadget<Fq2Parameters, Fq>;
pub type Fq6Gadget = Fp6Gadget<Fq6Parameters, Fq>;
pub type Fq12Gadget = Fp12Gadget<Fq12Parameters, Fq>;
pub type G1Gadget = Bls12G1Gadget<Bls12_377Parameters>;
pub type G1PreparedGadget = Bls12G1PreparedGadget<Bls12_377Parameters>;
pub type G2Gadget = Bls12G2Gadget<Bls12_377Parameters>;
pub type G2PreparedGadget = Bls12G2PreparedGadget<Bls12_377Parameters>;
pub type PairingGadget = Bls12PairingGadget<Bls12_377Parameters>;
#[cfg(test)]
mod test {
use super::*;
use crate::{
bits::boolean::{AllocatedBit, Boolean},
traits::{
alloc::AllocGadget,
curves::GroupGadget,
eq::EqGadget,
fields::FieldGadget,
select::CondSelectGadget,
},
};
use snarkvm_curves::{
bls12_377::{Fq, Fr, G1Projective as G1, G2Projective as G2},
traits::ProjectiveCurve,
Group,
};
use snarkvm_fields::PrimeField;
use snarkvm_r1cs::{ConstraintSystem, TestConstraintSystem};
use snarkvm_utilities::{bititerator::BitIteratorBE, rand::UniformRand};
use core::ops::Mul;
use rand::{
SeedableRng,
{self},
};
use rand_xorshift::XorShiftRng;
#[test]
fn bls12_g1_constraint_costs() {
let mut cs = TestConstraintSystem::<Fq>::new();
let bit = AllocatedBit::alloc(&mut cs.ns(|| "bool"), || Ok(true)).unwrap().into();
let a: G1 = rand::random();
let b: G1 = rand::random();
let gadget_a = G1Gadget::alloc(&mut cs.ns(|| "a"), || Ok(a)).unwrap();
let gadget_b = G1Gadget::alloc(&mut cs.ns(|| "b"), || Ok(b)).unwrap();
let alloc_cost = cs.num_constraints();
let _ = G1Gadget::conditionally_select(&mut cs.ns(|| "cond_select"), &bit, &gadget_a, &gadget_b).unwrap();
let cond_select_cost = cs.num_constraints() - alloc_cost;
let _ = gadget_a.add(&mut cs.ns(|| "ab"), &gadget_b).unwrap();
let add_cost = cs.num_constraints() - cond_select_cost - alloc_cost;
assert!(cs.is_satisfied());
assert_eq!(cond_select_cost, <G1Gadget as CondSelectGadget<Fq>>::cost());
assert_eq!(add_cost, G1Gadget::cost_of_add());
}
#[test]
fn bls12_g2_constraint_costs() {
let mut cs = TestConstraintSystem::<Fq>::new();
let bit = AllocatedBit::alloc(&mut cs.ns(|| "bool"), || Ok(true)).unwrap().into();
let a: G2 = rand::random();
let b: G2 = rand::random();
let gadget_a = G2Gadget::alloc(&mut cs.ns(|| "a"), || Ok(a)).unwrap();
let gadget_b = G2Gadget::alloc(&mut cs.ns(|| "b"), || Ok(b)).unwrap();
let alloc_cost = cs.num_constraints();
let _ = G2Gadget::conditionally_select(&mut cs.ns(|| "cond_select"), &bit, &gadget_a, &gadget_b).unwrap();
let cond_select_cost = cs.num_constraints() - alloc_cost;
let _ = gadget_a.add(&mut cs.ns(|| "ab"), &gadget_b).unwrap();
let add_cost = cs.num_constraints() - cond_select_cost - alloc_cost;
assert!(cs.is_satisfied());
assert_eq!(cond_select_cost, <G2Gadget as CondSelectGadget<Fq>>::cost());
assert_eq!(add_cost, G2Gadget::cost_of_add());
}
#[test]
fn bls12_g1_gadget_test() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
let mut cs = TestConstraintSystem::<Fq>::new();
let a = G1::rand(&mut rng);
let b = G1::rand(&mut rng);
let a_affine = a.into_affine();
let b_affine = b.into_affine();
let mut gadget_a = G1Gadget::alloc(&mut cs.ns(|| "a"), || Ok(a)).unwrap();
let gadget_b = G1Gadget::alloc(&mut cs.ns(|| "b"), || Ok(b)).unwrap();
assert_eq!(gadget_a.x.get_value().unwrap(), a_affine.x);
assert_eq!(gadget_a.y.get_value().unwrap(), a_affine.y);
assert_eq!(gadget_b.x.get_value().unwrap(), b_affine.x);
assert_eq!(gadget_b.y.get_value().unwrap(), b_affine.y);
let ab = a + b;
let ab_affine = ab.into_affine();
let gadget_ab = gadget_a.add(&mut cs.ns(|| "ab"), &gadget_b).unwrap();
let gadget_ba = gadget_b.add(&mut cs.ns(|| "ba"), &gadget_a).unwrap();
gadget_ba
.enforce_equal(&mut cs.ns(|| "b + a == a + b?"), &gadget_ab)
.unwrap();
let ab_val = gadget_ab
.get_value()
.expect("Doubling should be successful")
.into_affine();
assert_eq!(ab_val, ab_affine, "Result of addition is unequal");
let aa = a.double();
let aa_affine = aa.into_affine();
gadget_a.double_in_place(&mut cs.ns(|| "2a")).unwrap();
let aa_val = gadget_a
.get_value()
.expect("Doubling should be successful")
.into_affine();
assert_eq!(aa_val, aa_affine, "Gadget and native values are unequal after double.");
let scalar = Fr::rand(&mut rng);
let native_result = aa.mul(scalar) + b;
let native_result = native_result.into_affine();
let mut scalar: Vec<bool> = BitIteratorBE::new(scalar.to_repr()).collect();
scalar.reverse();
let input = Vec::<Boolean>::alloc(cs.ns(|| "Input"), || Ok(scalar)).unwrap();
let result = gadget_a
.mul_bits(cs.ns(|| "mul_bits"), &gadget_b, input.into_iter())
.unwrap();
let result_val = result.get_value().unwrap().into_affine();
assert_eq!(
result_val, native_result,
"gadget & native values are diff. after scalar mul"
);
if !cs.is_satisfied() {
println!("{:?}", cs.which_is_unsatisfied().unwrap());
}
assert!(cs.is_satisfied());
}
#[test]
fn bls12_g2_gadget_test() {
let mut cs = TestConstraintSystem::<Fq>::new();
let a: G2 = rand::random();
let b: G2 = rand::random();
let a_affine = a.into_affine();
let b_affine = b.into_affine();
let mut gadget_a = G2Gadget::alloc(&mut cs.ns(|| "a"), || Ok(a)).unwrap();
let gadget_b = G2Gadget::alloc(&mut cs.ns(|| "b"), || Ok(b)).unwrap();
assert_eq!(gadget_a.x.get_value().unwrap(), a_affine.x);
assert_eq!(gadget_a.y.get_value().unwrap(), a_affine.y);
assert_eq!(gadget_b.x.get_value().unwrap(), b_affine.x);
assert_eq!(gadget_b.y.get_value().unwrap(), b_affine.y);
let ab = a + b;
let ab_affine = ab.into_affine();
let gadget_ab = gadget_a.add(&mut cs.ns(|| "ab"), &gadget_b).unwrap();
let gadget_ba = gadget_b.add(&mut cs.ns(|| "ba"), &gadget_a).unwrap();
gadget_ba
.enforce_equal(&mut cs.ns(|| "b + a == a + b?"), &gadget_ab)
.unwrap();
assert_eq!(gadget_ab.x.get_value().unwrap(), ab_affine.x);
assert_eq!(gadget_ab.y.get_value().unwrap(), ab_affine.y);
let aa = a.double();
let aa_affine = aa.into_affine();
gadget_a.double_in_place(&mut cs.ns(|| "2a")).unwrap();
assert_eq!(gadget_a.x.get_value().unwrap(), aa_affine.x);
assert_eq!(gadget_a.y.get_value().unwrap(), aa_affine.y);
if !cs.is_satisfied() {
println!("{:?}", cs.which_is_unsatisfied().unwrap());
}
assert!(cs.is_satisfied());
}
#[test]
fn bls12_g1_gadget_is_eq_test() {
let mut cs = TestConstraintSystem::<Fq>::new();
let a: G1 = rand::random();
let b: G1 = a;
let c: G1 = rand::random();
let a = G1Gadget::alloc(&mut cs.ns(|| "generate_a"), || Ok(a)).unwrap();
let b = G1Gadget::alloc(&mut cs.ns(|| "generate_b"), || Ok(b)).unwrap();
let c = G1Gadget::alloc(&mut cs.ns(|| "generate_c"), || Ok(c)).unwrap();
let a_is_eq_b = a.is_eq(cs.ns(|| "a_is_eq_b"), &b).unwrap();
let a_is_eq_c = a.is_eq(cs.ns(|| "a_is_eq_c"), &c).unwrap();
a_is_eq_b
.enforce_equal(cs.ns(|| " a_is_eq_b is true"), &Boolean::constant(true))
.unwrap();
a_is_eq_c
.enforce_equal(cs.ns(|| " a_is_eq_c is false"), &Boolean::constant(false))
.unwrap();
assert!(cs.is_satisfied());
}
#[test]
fn bls12_g2_gadget_is_eq_test() {
let mut cs = TestConstraintSystem::<Fq>::new();
let a: G2 = rand::random();
let b: G2 = a;
let c: G2 = rand::random();
let a = G2Gadget::alloc(&mut cs.ns(|| "generate_a"), || Ok(a)).unwrap();
let b = G2Gadget::alloc(&mut cs.ns(|| "generate_b"), || Ok(b)).unwrap();
let c = G2Gadget::alloc(&mut cs.ns(|| "generate_c"), || Ok(c)).unwrap();
let a_is_eq_b = a.is_eq(cs.ns(|| "a_is_eq_b"), &b).unwrap();
let a_is_eq_c = a.is_eq(cs.ns(|| "a_is_eq_c"), &c).unwrap();
a_is_eq_b
.enforce_equal(cs.ns(|| " a_is_eq_b is true"), &Boolean::constant(true))
.unwrap();
a_is_eq_c
.enforce_equal(cs.ns(|| " a_is_eq_c is false"), &Boolean::constant(false))
.unwrap();
assert!(cs.is_satisfied());
}
}