2020-09-29 07:23:41 +00:00
|
|
|
use super::super::{
|
|
|
|
|
commitment::{self, Blind, Params},
|
|
|
|
|
Coeff, Error, Polynomial,
|
|
|
|
|
};
|
2020-10-15 23:01:30 +00:00
|
|
|
use super::{construct_intermediate_sets, Proof, ProverQuery, Query};
|
2020-09-29 07:23:41 +00:00
|
|
|
|
|
|
|
|
use crate::arithmetic::{
|
2020-10-14 00:16:14 +00:00
|
|
|
eval_polynomial, get_challenge_scalar, kate_division, lagrange_interpolate, Challenge, Curve,
|
2020-11-13 00:08:08 +00:00
|
|
|
CurveAffine, FieldExt,
|
2020-09-29 07:23:41 +00:00
|
|
|
};
|
2020-10-14 23:35:06 +00:00
|
|
|
use crate::transcript::{Hasher, Transcript};
|
2020-11-13 00:08:08 +00:00
|
|
|
|
|
|
|
|
use ff::Field;
|
2020-10-07 16:13:06 +00:00
|
|
|
use std::marker::PhantomData;
|
2020-09-29 07:23:41 +00:00
|
|
|
|
2020-10-07 13:57:54 +00:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
struct CommitmentData<C: CurveAffine> {
|
|
|
|
|
set_index: usize,
|
|
|
|
|
blind: Blind<C::Scalar>,
|
|
|
|
|
point_indices: Vec<usize>,
|
|
|
|
|
evals: Vec<C::Scalar>,
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-29 07:23:41 +00:00
|
|
|
impl<C: CurveAffine> Proof<C> {
|
|
|
|
|
/// Create a multi-opening proof
|
2020-10-07 16:13:06 +00:00
|
|
|
pub fn create<'a, I, HBase: Hasher<C::Base>, HScalar: Hasher<C::Scalar>>(
|
2020-09-29 07:23:41 +00:00
|
|
|
params: &Params<C>,
|
2020-10-14 23:35:06 +00:00
|
|
|
transcript: &mut Transcript<C, HBase, HScalar>,
|
2020-10-07 16:13:06 +00:00
|
|
|
queries: I,
|
2020-09-29 07:23:41 +00:00
|
|
|
) -> Result<Self, Error>
|
|
|
|
|
where
|
2020-10-07 16:13:06 +00:00
|
|
|
I: IntoIterator<Item = ProverQuery<'a, C>> + Clone,
|
2020-09-29 07:23:41 +00:00
|
|
|
{
|
|
|
|
|
let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
2020-10-15 23:11:06 +00:00
|
|
|
let x_5: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
2020-09-29 07:23:41 +00:00
|
|
|
|
2020-10-15 23:01:30 +00:00
|
|
|
let (poly_map, point_sets) = construct_intermediate_sets(queries);
|
2020-10-07 16:13:06 +00:00
|
|
|
|
|
|
|
|
// Collapse openings at same point sets together into single openings using
|
2020-09-29 07:23:41 +00:00
|
|
|
// x_4 challenge.
|
2020-10-07 16:13:06 +00:00
|
|
|
let mut q_polys: Vec<Option<Polynomial<C::Scalar, Coeff>>> = vec![None; point_sets.len()];
|
|
|
|
|
let mut q_blinds = vec![Blind(C::Scalar::zero()); point_sets.len()];
|
2020-10-13 17:08:03 +00:00
|
|
|
|
|
|
|
|
// A vec of vecs of evals. The outer vec corresponds to the point set,
|
|
|
|
|
// while the inner vec corresponds to the points in a particular set.
|
2020-10-16 00:43:41 +00:00
|
|
|
let mut q_eval_sets = Vec::with_capacity(point_sets.len());
|
|
|
|
|
for point_set in point_sets.iter() {
|
|
|
|
|
q_eval_sets.push(vec![C::Scalar::zero(); point_set.len()]);
|
2020-10-07 16:13:06 +00:00
|
|
|
}
|
|
|
|
|
|
2020-09-29 07:23:41 +00:00
|
|
|
{
|
2020-10-07 16:13:06 +00:00
|
|
|
let mut accumulate = |set_idx: usize,
|
|
|
|
|
new_poly: &Polynomial<C::Scalar, Coeff>,
|
|
|
|
|
blind: Blind<C::Scalar>,
|
|
|
|
|
evals: Vec<C::Scalar>| {
|
2020-10-14 00:16:14 +00:00
|
|
|
if let Some(poly) = &q_polys[set_idx] {
|
|
|
|
|
q_polys[set_idx] = Some(poly.clone() * x_4 + new_poly);
|
|
|
|
|
} else {
|
|
|
|
|
q_polys[set_idx] = Some(new_poly.clone());
|
|
|
|
|
}
|
2020-10-07 16:13:06 +00:00
|
|
|
q_blinds[set_idx] *= x_4;
|
|
|
|
|
q_blinds[set_idx] += blind;
|
2020-10-13 17:08:03 +00:00
|
|
|
// Each polynomial is evaluated at a set of points. For each set,
|
|
|
|
|
// we collapse each polynomial's evals pointwise.
|
2020-10-15 23:12:17 +00:00
|
|
|
for (eval, set_eval) in evals.iter().zip(q_eval_sets[set_idx].iter_mut()) {
|
|
|
|
|
*set_eval *= &x_4;
|
|
|
|
|
*set_eval += eval;
|
2020-10-07 16:13:06 +00:00
|
|
|
}
|
|
|
|
|
};
|
2020-09-29 07:23:41 +00:00
|
|
|
|
2020-10-15 23:06:35 +00:00
|
|
|
for commitment_data in poly_map.into_iter() {
|
2020-09-29 07:23:41 +00:00
|
|
|
accumulate(
|
2020-10-15 23:01:30 +00:00
|
|
|
commitment_data.set_index, // set_idx,
|
|
|
|
|
commitment_data.commitment.poly, // poly,
|
|
|
|
|
commitment_data.commitment.blind, // blind,
|
2020-10-15 23:06:35 +00:00
|
|
|
commitment_data.evals, // evals
|
2020-09-29 07:23:41 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-08 04:48:40 +00:00
|
|
|
let f_poly = point_sets
|
|
|
|
|
.iter()
|
|
|
|
|
.zip(q_eval_sets.iter())
|
|
|
|
|
.zip(q_polys.iter())
|
|
|
|
|
.fold(None, |f_poly, ((points, evals), poly)| {
|
2020-10-16 00:43:41 +00:00
|
|
|
let mut poly = poly.clone().unwrap().values;
|
2020-10-08 04:48:40 +00:00
|
|
|
// TODO: makes implicit asssumption that poly degree is smaller than interpolation poly degree
|
2020-10-08 14:59:55 +00:00
|
|
|
for (p, r) in poly.iter_mut().zip(lagrange_interpolate(points, evals)) {
|
2020-10-08 04:48:40 +00:00
|
|
|
*p -= &r;
|
|
|
|
|
}
|
|
|
|
|
let mut poly = points
|
|
|
|
|
.iter()
|
|
|
|
|
.fold(poly, |poly, point| kate_division(&poly, *point));
|
|
|
|
|
poly.resize(params.n as usize, C::Scalar::zero());
|
|
|
|
|
let poly = Polynomial {
|
2020-10-07 16:13:06 +00:00
|
|
|
values: poly,
|
|
|
|
|
_marker: PhantomData,
|
|
|
|
|
};
|
2020-09-29 07:23:41 +00:00
|
|
|
|
2020-10-08 04:48:40 +00:00
|
|
|
if f_poly.is_none() {
|
|
|
|
|
Some(poly)
|
|
|
|
|
} else {
|
|
|
|
|
f_poly.map(|f_poly| f_poly * x_5 + &poly)
|
|
|
|
|
}
|
2020-10-15 23:16:44 +00:00
|
|
|
})
|
|
|
|
|
.unwrap();
|
2020-09-29 07:23:41 +00:00
|
|
|
|
2020-11-13 00:08:08 +00:00
|
|
|
let mut f_blind = Blind(C::Scalar::rand());
|
2020-09-29 07:23:41 +00:00
|
|
|
let mut f_commitment = params.commit(&f_poly, f_blind).to_affine();
|
|
|
|
|
|
|
|
|
|
let (opening, q_evals) = loop {
|
|
|
|
|
let mut transcript = transcript.clone();
|
2020-10-14 23:35:06 +00:00
|
|
|
transcript
|
|
|
|
|
.absorb_point(&f_commitment)
|
|
|
|
|
.map_err(|_| Error::SamplingError)?;
|
2020-09-29 07:23:41 +00:00
|
|
|
|
|
|
|
|
let x_6: C::Scalar =
|
|
|
|
|
get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
|
|
|
|
|
2020-10-08 04:48:40 +00:00
|
|
|
let q_evals: Vec<C::Scalar> = q_polys
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|poly| eval_polynomial(poly.as_ref().unwrap(), x_6))
|
|
|
|
|
.collect();
|
2020-09-29 07:23:41 +00:00
|
|
|
|
|
|
|
|
for eval in q_evals.iter() {
|
2020-10-14 23:35:06 +00:00
|
|
|
transcript.absorb_scalar(*eval);
|
2020-09-29 07:23:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let x_7: C::Scalar =
|
|
|
|
|
get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
|
|
|
|
|
2020-10-08 04:48:40 +00:00
|
|
|
let (f_poly, f_blind_try) = q_polys.iter().zip(q_blinds.iter()).fold(
|
|
|
|
|
(f_poly.clone(), f_blind),
|
|
|
|
|
|(f_poly, f_blind), (poly, blind)| {
|
|
|
|
|
(
|
2020-10-13 17:08:03 +00:00
|
|
|
f_poly * x_7 + poly.as_ref().unwrap(),
|
2020-10-08 04:48:40 +00:00
|
|
|
Blind((f_blind.0 * &x_7) + &blind.0),
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
);
|
2020-09-29 07:23:41 +00:00
|
|
|
|
|
|
|
|
if let Ok(opening) =
|
2020-10-08 04:48:40 +00:00
|
|
|
commitment::Proof::create(¶ms, &mut transcript, &f_poly, f_blind_try, x_6)
|
2020-09-29 07:23:41 +00:00
|
|
|
{
|
|
|
|
|
break (opening, q_evals);
|
|
|
|
|
} else {
|
|
|
|
|
f_blind += C::Scalar::one();
|
|
|
|
|
f_commitment = (f_commitment + params.h).to_affine();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(Proof {
|
|
|
|
|
q_evals,
|
|
|
|
|
f_commitment,
|
|
|
|
|
opening,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-10-07 13:59:55 +00:00
|
|
|
|
2020-10-15 23:01:30 +00:00
|
|
|
#[doc(hidden)]
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
|
pub struct PolynomialPointer<'a, C: CurveAffine> {
|
|
|
|
|
poly: &'a Polynomial<C::Scalar, Coeff>,
|
|
|
|
|
blind: commitment::Blind<C::Scalar>,
|
|
|
|
|
}
|
2020-10-07 13:59:55 +00:00
|
|
|
|
2020-10-15 23:01:30 +00:00
|
|
|
impl<'a, C: CurveAffine> PartialEq for PolynomialPointer<'a, C> {
|
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
|
std::ptr::eq(self.poly, other.poly)
|
2020-10-07 13:59:55 +00:00
|
|
|
}
|
2020-10-15 23:01:30 +00:00
|
|
|
}
|
2020-10-07 13:59:55 +00:00
|
|
|
|
2020-10-15 23:01:30 +00:00
|
|
|
impl<'a, C: CurveAffine> Query<C::Scalar> for ProverQuery<'a, C> {
|
|
|
|
|
type Commitment = PolynomialPointer<'a, C>;
|
2020-10-07 13:59:55 +00:00
|
|
|
|
2020-10-15 23:01:30 +00:00
|
|
|
fn get_point(&self) -> C::Scalar {
|
|
|
|
|
self.point
|
2020-10-07 13:59:55 +00:00
|
|
|
}
|
2020-10-15 23:01:30 +00:00
|
|
|
fn get_eval(&self) -> C::Scalar {
|
|
|
|
|
self.eval
|
2020-10-07 13:59:55 +00:00
|
|
|
}
|
2020-10-15 23:01:30 +00:00
|
|
|
fn get_commitment(&self) -> Self::Commitment {
|
|
|
|
|
PolynomialPointer {
|
|
|
|
|
poly: self.poly,
|
|
|
|
|
blind: self.blind,
|
2020-10-07 13:59:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|