use crate::polynomial::{Eval, Poly, PrivatePoly};
use fastcrypto::error::{FastCryptoError, FastCryptoResult};
use fastcrypto::groups::{bls12381, GroupElement, MultiScalarMul, Pairing, Scalar};
use fastcrypto::traits::AllowedRng;
use std::num::NonZeroU16;
fn dot<S: Scalar>(v1: &[S], v2: &[S]) -> S {
assert_eq!(v1.len(), v2.len());
v1.iter()
.zip(v2.iter())
.fold(S::zero(), |acc, (a, b)| acc + *a * *b)
}
pub(crate) fn batch_coefficients<S: Scalar>(r: &[S], indexes: &[S], degree: usize) -> Vec<S> {
assert!(r.len() == indexes.len() && degree > 0); let mut multiplies = r.to_vec();
let mut res = Vec::<S>::new();
for i in 0..=degree {
let sum = multiplies.iter().fold(S::zero(), |acc, r| acc + *r);
res.push(sum);
if i == degree {
break;
}
multiplies = multiplies
.iter()
.zip(indexes.iter())
.map(|(r, c)| *r * c)
.collect::<Vec<_>>();
}
res
}
pub fn verify_poly_evals<G: GroupElement + MultiScalarMul, R: AllowedRng>(
evals: &[Eval<G::ScalarType>],
poly: &Poly<G>,
rng: &mut R,
) -> FastCryptoResult<()> {
assert!(poly.degree() > 0);
if evals.is_empty() {
return Ok(());
}
let rs = get_random_scalars::<G::ScalarType, R>(evals.len(), rng);
let lhs = G::generator() * dot(&rs, &evals.iter().map(|e| e.value).collect::<Vec<_>>());
let evals_as_scalars = evals
.iter()
.map(|e| G::ScalarType::from(e.index.get().into()))
.collect::<Vec<_>>();
let coeffs = batch_coefficients(&rs, &evals_as_scalars, poly.degree());
let rhs = G::multi_scalar_mul(&coeffs, poly.as_vec()).expect("sizes match");
if lhs != rhs {
Err(FastCryptoError::InvalidProof)
} else {
Ok(())
}
}
pub fn verify_pairs<G: GroupElement + MultiScalarMul, R: AllowedRng>(
pairs: &[(G::ScalarType, G)],
rng: &mut R,
) -> FastCryptoResult<()> {
if pairs.is_empty() {
return Ok(());
}
let rs = get_random_scalars::<G::ScalarType, R>(pairs.len(), rng);
let lhs = G::generator()
* rs.iter()
.zip(pairs.iter())
.map(|(r, (k, _))| *r * *k)
.reduce(|a, b| a + b)
.expect("Iterators are non-empty");
let rhs = G::multi_scalar_mul(
&rs[..],
&pairs.iter().map(|(_, g)| *g).collect::<Vec<_>>()[..],
)
.expect("valid sizes");
if lhs == rhs {
Ok(())
} else {
Err(FastCryptoError::InvalidProof)
}
}
pub fn verify_triplets<G: GroupElement + MultiScalarMul, R: AllowedRng>(
triplets: &[(G::ScalarType, G, G)],
rng: &mut R,
) -> FastCryptoResult<()> {
if triplets.is_empty() {
return Ok(());
}
let rs = get_random_scalars::<G::ScalarType, R>(triplets.len(), rng);
let lhs_coeffs = rs
.iter()
.zip(triplets.iter())
.map(|(r, (k, _, _))| *r * *k)
.collect::<Vec<_>>();
let lhs = G::multi_scalar_mul(
&lhs_coeffs[..],
&triplets.iter().map(|(_, b, _)| *b).collect::<Vec<_>>()[..],
)
.expect("valid sizes");
let rhs = G::multi_scalar_mul(
&rs[..],
&triplets.iter().map(|(_, _, k_b)| *k_b).collect::<Vec<_>>()[..],
)
.expect("valid sizes");
if lhs == rhs {
Ok(())
} else {
Err(FastCryptoError::InvalidProof)
}
}
pub fn verify_deg_t_poly<G: GroupElement + MultiScalarMul, R: AllowedRng>(
deg_f: u16,
values: &[G],
precomputed_dual_code_coefficients: &[G::ScalarType],
rng: &mut R,
) -> FastCryptoResult<()> {
let poly_f = PrivatePoly::<G>::rand(deg_f, rng);
let coefficients = precomputed_dual_code_coefficients
.iter()
.enumerate()
.map(|(i, c)| *c * poly_f.eval(NonZeroU16::new((i + 1) as u16).unwrap()).value)
.collect::<Vec<_>>();
let lhs = G::multi_scalar_mul(&coefficients[..], values).expect("sizes match");
if lhs != G::zero() {
return Err(FastCryptoError::InvalidProof);
}
Ok(())
}
pub fn verify_equal_exponents<R: AllowedRng>(
v1: &[bls12381::G1Element],
v2: &[bls12381::G2Element],
rng: &mut R,
) -> FastCryptoResult<()> {
if v1.len() != v2.len() {
return Err(FastCryptoError::InvalidProof);
}
let rs = get_random_scalars::<bls12381::Scalar, R>(v1.len(), rng);
let lhs = bls12381::G1Element::multi_scalar_mul(&rs[..], v1).expect("sizes match");
let rhs = bls12381::G2Element::multi_scalar_mul(&rs[..], v2).expect("sizes match");
if lhs.pairing(&bls12381::G2Element::generator())
!= bls12381::G1Element::generator().pairing(&rhs)
{
return Err(FastCryptoError::InvalidProof);
}
Ok(())
}
pub(crate) fn get_random_scalars<S: Scalar, R: AllowedRng>(n: usize, rng: &mut R) -> Vec<S> {
(0..n)
.map(|_| S::from(rng.next_u64() as u128))
.collect::<Vec<_>>()
}