use std::ops::AddAssign;
use group::{prime::PrimeCurveAffine, Curve};
use rayon::prelude::*;
use crate::groth16::aggregate::inner_product;
use crate::SynthesisError;
use pairing::{Engine, MultiMillerLoop};
#[derive(Clone, Debug)]
pub struct Key<G: PrimeCurveAffine> {
pub a: Vec<G>,
pub b: Vec<G>,
}
pub type VKey<E> = Key<<E as Engine>::G2Affine>;
pub type WKey<E> = Key<<E as Engine>::G1Affine>;
impl<G> Key<G>
where
G: PrimeCurveAffine,
{
pub fn has_correct_len(&self, n: usize) -> bool {
self.a.len() == n && self.b.len() == n
}
pub fn scale(&self, s_vec: &[G::Scalar]) -> Result<Self, SynthesisError> {
if self.a.len() != s_vec.len() {
return Err(SynthesisError::IncompatibleLengthVector(
"scaling commitment key".to_string(),
));
}
let (a, b) = self
.a
.par_iter()
.zip(self.b.par_iter())
.zip(s_vec.par_iter())
.map(|((ap, bp), si)| {
let v1s = (ap.to_curve() * si).to_affine();
let v2s = (bp.to_curve() * si).to_affine();
(v1s, v2s)
})
.unzip();
Ok(Self { a, b })
}
pub fn split(mut self, at: usize) -> (Self, Self) {
let a_right = self.a.split_off(at);
let b_right = self.b.split_off(at);
(
Self {
a: self.a,
b: self.b,
},
Self {
a: a_right,
b: b_right,
},
)
}
pub fn compress(&self, right: &Self, scale: &G::Scalar) -> Result<Self, SynthesisError> {
let left = self;
if left.a.len() != right.a.len() {
return Err(SynthesisError::IncompatibleLengthVector(
"compressing commitment key".to_string(),
));
}
let (a, b): (Vec<G>, Vec<G>) = left
.a
.par_iter()
.zip(left.b.par_iter())
.zip(right.a.par_iter())
.zip(right.b.par_iter())
.map(|(((left_a, left_b), right_a), right_b)| {
let mut ra = right_a.to_curve() * scale;
let mut rb = right_b.to_curve() * scale;
ra.add_assign(left_a);
rb.add_assign(left_b);
(ra.to_affine(), rb.to_affine())
})
.unzip();
Ok(Self { a, b })
}
pub fn first(&self) -> (G, G) {
(self.a[0], self.b[0])
}
}
pub type Output<E> = (<E as Engine>::Gt, <E as Engine>::Gt);
pub fn single_g1<E>(vkey: &VKey<E>, a_vec: &[E::G1Affine]) -> Result<Output<E>, SynthesisError>
where
E: MultiMillerLoop,
{
try_par! {
let a = inner_product::pairing::<E>(a_vec, &vkey.a),
let b = inner_product::pairing::<E>(a_vec, &vkey.b)
};
Ok((a, b))
}
pub fn pair<E>(
vkey: &VKey<E>,
wkey: &WKey<E>,
a: &[E::G1Affine],
b: &[E::G2Affine],
) -> Result<Output<E>, SynthesisError>
where
E: MultiMillerLoop,
{
try_par! {
let t1 = inner_product::pairing::<E>(a, &vkey.a),
let t2 = inner_product::pairing::<E>(&wkey.a, b),
let u1 = inner_product::pairing::<E>(a, &vkey.b),
let u2 = inner_product::pairing::<E>(&wkey.b, b)
};
Ok((t1 + t2, u1 + u2))
}
#[allow(clippy::many_single_char_names)]
#[cfg(test)]
mod tests {
use super::*;
use crate::groth16::aggregate::structured_generators_scalar_power;
use blstrs::{Bls12, G1Projective, G2Projective, Scalar as Fr};
use ff::Field;
use group::Group;
use rand_core::SeedableRng;
#[test]
fn test_commit_single() {
let n = 6;
let mut rng = rand_chacha::ChaChaRng::seed_from_u64(0u64);
let h = G2Projective::generator();
let u = Fr::random(&mut rng);
let v = Fr::random(&mut rng);
let v1 = structured_generators_scalar_power(n, &h, &u);
let v2 = structured_generators_scalar_power(n, &h, &v);
let vkey = VKey::<Bls12> { a: v1, b: v2 };
let a = (0..n)
.map(|_| G1Projective::random(&mut rng).to_affine())
.collect::<Vec<_>>();
let c1 = single_g1::<Bls12>(&vkey, &a).unwrap();
let c2 = single_g1::<Bls12>(&vkey, &a).unwrap();
assert_eq!(c1, c2);
let b = (0..n)
.map(|_| G1Projective::random(&mut rng).to_affine())
.collect::<Vec<_>>();
let c3 = single_g1::<Bls12>(&vkey, &b).unwrap();
assert!(c1 != c3);
}
#[test]
fn test_commit_pair() {
let n = 6;
let mut rng = rand_chacha::ChaChaRng::seed_from_u64(0u64);
let h = G2Projective::generator();
let g = G1Projective::generator();
let u = Fr::random(&mut rng);
let v = Fr::random(&mut rng);
let v1 = structured_generators_scalar_power(n, &h, &u);
let v2 = structured_generators_scalar_power(n, &h, &v);
let w1 = structured_generators_scalar_power(2 * n, &g, &u);
let w2 = structured_generators_scalar_power(2 * n, &g, &v);
let vkey = VKey::<Bls12> { a: v1, b: v2 };
let wkey = WKey::<Bls12> {
a: w1[n..].to_vec(),
b: w2[n..].to_vec(),
};
let a = (0..n)
.map(|_| G1Projective::random(&mut rng).to_affine())
.collect::<Vec<_>>();
let b = (0..n)
.map(|_| G2Projective::random(&mut rng).to_affine())
.collect::<Vec<_>>();
let c1 = pair::<Bls12>(&vkey, &wkey, &a, &b).unwrap();
let c2 = pair::<Bls12>(&vkey, &wkey, &a, &b).unwrap();
assert_eq!(c1, c2);
pair::<Bls12>(&vkey, &wkey, &a[1..2], &b).expect_err("this should have failed");
}
}