mirror of https://github.com/zcash/halo2.git
Unify the construct_intermediate_sets function between multiopen prover and verifier.
This commit is contained in:
parent
d3f593e89c
commit
55ef4ea1f7
|
@ -3,6 +3,8 @@
|
||||||
//!
|
//!
|
||||||
//! [halo]: https://eprint.iacr.org/2019/1021
|
//! [halo]: https://eprint.iacr.org/2019/1021
|
||||||
|
|
||||||
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::arithmetic::CurveAffine;
|
use crate::arithmetic::CurveAffine;
|
||||||
|
|
||||||
|
@ -45,3 +47,297 @@ pub struct VerifierQuery<'a, C: CurveAffine> {
|
||||||
/// evaluation of polynomial at query point
|
/// evaluation of polynomial at query point
|
||||||
pub eval: C::Scalar,
|
pub eval: C::Scalar,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CommitmentData<F: Field, T: PartialEq> {
|
||||||
|
commitment: T,
|
||||||
|
set_index: usize,
|
||||||
|
point_indices: Vec<usize>,
|
||||||
|
evals: Vec<F>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field, T: PartialEq> CommitmentData<F, T> {
|
||||||
|
fn new(commitment: T) -> Self {
|
||||||
|
CommitmentData {
|
||||||
|
commitment,
|
||||||
|
set_index: 0,
|
||||||
|
point_indices: vec![],
|
||||||
|
evals: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Query<F>: Sized {
|
||||||
|
type Commitment: PartialEq + Copy;
|
||||||
|
|
||||||
|
fn get_point(&self) -> F;
|
||||||
|
fn get_eval(&self) -> F;
|
||||||
|
fn get_commitment(&self) -> Self::Commitment;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_intermediate_sets<F: Field, I, Q: Query<F>>(
|
||||||
|
queries: I,
|
||||||
|
) -> (Vec<CommitmentData<F, Q::Commitment>>, Vec<Vec<F>>)
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = Q> + Clone,
|
||||||
|
{
|
||||||
|
// Construct sets of unique commitments and corresponding information about
|
||||||
|
// their queries.
|
||||||
|
let mut commitment_map: Vec<CommitmentData<F, Q::Commitment>> = vec![];
|
||||||
|
|
||||||
|
// Also construct mapping from a unique point to a point_index. This defines
|
||||||
|
// an ordering on the points.
|
||||||
|
let mut point_index_map = BTreeMap::new();
|
||||||
|
|
||||||
|
// Iterate over all of the queries, computing the ordering of the points
|
||||||
|
// while also creating new commitment data.
|
||||||
|
for query in queries.clone() {
|
||||||
|
let num_points = point_index_map.len();
|
||||||
|
let point_idx = point_index_map
|
||||||
|
.entry(query.get_point())
|
||||||
|
.or_insert(num_points);
|
||||||
|
|
||||||
|
if let Some(pos) = commitment_map
|
||||||
|
.iter()
|
||||||
|
.position(|comm| comm.commitment == query.get_commitment())
|
||||||
|
{
|
||||||
|
commitment_map[pos].point_indices.push(*point_idx);
|
||||||
|
} else {
|
||||||
|
let mut tmp = CommitmentData::new(query.get_commitment());
|
||||||
|
tmp.point_indices.push(*point_idx);
|
||||||
|
commitment_map.push(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also construct inverse mapping from point_index to the point
|
||||||
|
let mut inverse_point_index_map = BTreeMap::new();
|
||||||
|
for (&point, &point_index) in point_index_map.iter() {
|
||||||
|
inverse_point_index_map.insert(point_index, point);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct map of unique ordered point_idx_sets to their set_idx
|
||||||
|
let mut point_idx_sets = BTreeMap::new();
|
||||||
|
// Also construct mapping from commitment to point_idx_set
|
||||||
|
let mut commitment_set_map = Vec::new();
|
||||||
|
|
||||||
|
for commitment_data in commitment_map.iter() {
|
||||||
|
let mut point_index_set = BTreeSet::new();
|
||||||
|
// Note that point_index_set is ordered, unlike point_indices
|
||||||
|
for &point_index in commitment_data.point_indices.iter() {
|
||||||
|
point_index_set.insert(point_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push point_index_set to CommitmentData for the relevant commitment
|
||||||
|
commitment_set_map.push((commitment_data.commitment, point_index_set.clone()));
|
||||||
|
|
||||||
|
let num_sets = point_idx_sets.len();
|
||||||
|
point_idx_sets.entry(point_index_set).or_insert(num_sets);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise empty evals vec for each unique commitment
|
||||||
|
for commitment_data in commitment_map.iter_mut() {
|
||||||
|
let len = commitment_data.point_indices.len();
|
||||||
|
commitment_data.evals = vec![F::zero(); len];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate set_index, evals and points for each commitment using point_idx_sets
|
||||||
|
for query in queries {
|
||||||
|
// The index of the point at which the commitment is queried
|
||||||
|
let point_index = point_index_map.get(&query.get_point()).unwrap();
|
||||||
|
|
||||||
|
// The point_index_set at which the commitment was queried
|
||||||
|
let mut point_index_set = BTreeSet::new();
|
||||||
|
for (commitment, point_idx_set) in commitment_set_map.iter() {
|
||||||
|
if query.get_commitment() == *commitment {
|
||||||
|
point_index_set = point_idx_set.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(!point_index_set.is_empty());
|
||||||
|
|
||||||
|
// The set_index of the point_index_set
|
||||||
|
let set_index = point_idx_sets.get(&point_index_set).unwrap();
|
||||||
|
for commitment_data in commitment_map.iter_mut() {
|
||||||
|
if query.get_commitment() == commitment_data.commitment {
|
||||||
|
commitment_data.set_index = *set_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let point_index_set: Vec<usize> = point_index_set.iter().cloned().collect();
|
||||||
|
|
||||||
|
// The offset of the point_index in the point_index_set
|
||||||
|
let point_index_in_set = point_index_set
|
||||||
|
.iter()
|
||||||
|
.position(|i| i == point_index)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for commitment_data in commitment_map.iter_mut() {
|
||||||
|
if query.get_commitment() == commitment_data.commitment {
|
||||||
|
// Insert the eval using the ordering of the point_index_set
|
||||||
|
commitment_data.evals[point_index_in_set] = query.get_eval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get actual points in each point set
|
||||||
|
let mut point_sets: Vec<Vec<F>> = vec![Vec::new(); point_idx_sets.len()];
|
||||||
|
for (point_idx_set, &set_idx) in point_idx_sets.iter() {
|
||||||
|
for &point_idx in point_idx_set.iter() {
|
||||||
|
let point = inverse_point_index_map.get(&point_idx).unwrap();
|
||||||
|
point_sets[set_idx].push(*point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(commitment_map, point_sets)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{construct_intermediate_sets, Query};
|
||||||
|
use crate::arithmetic::{Field, Fp};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct MyQuery<F> {
|
||||||
|
commitment: usize,
|
||||||
|
point: F,
|
||||||
|
eval: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Copy> Query<F> for MyQuery<F> {
|
||||||
|
type Commitment = usize;
|
||||||
|
|
||||||
|
fn get_point(&self) -> F {
|
||||||
|
self.point
|
||||||
|
}
|
||||||
|
fn get_eval(&self) -> F {
|
||||||
|
self.eval
|
||||||
|
}
|
||||||
|
fn get_commitment(&self) -> Self::Commitment {
|
||||||
|
self.commitment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_coherence() {
|
||||||
|
let points = &[
|
||||||
|
Fp::random(),
|
||||||
|
Fp::random(),
|
||||||
|
Fp::random(),
|
||||||
|
Fp::random(),
|
||||||
|
Fp::random(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let queries = vec![
|
||||||
|
MyQuery {
|
||||||
|
commitment: 0,
|
||||||
|
point: points[0],
|
||||||
|
eval: Fp::random(),
|
||||||
|
},
|
||||||
|
MyQuery {
|
||||||
|
commitment: 0,
|
||||||
|
point: points[1],
|
||||||
|
eval: Fp::random(),
|
||||||
|
},
|
||||||
|
MyQuery {
|
||||||
|
commitment: 1,
|
||||||
|
point: points[0],
|
||||||
|
eval: Fp::random(),
|
||||||
|
},
|
||||||
|
MyQuery {
|
||||||
|
commitment: 1,
|
||||||
|
point: points[1],
|
||||||
|
eval: Fp::random(),
|
||||||
|
},
|
||||||
|
MyQuery {
|
||||||
|
commitment: 2,
|
||||||
|
point: points[0],
|
||||||
|
eval: Fp::random(),
|
||||||
|
},
|
||||||
|
MyQuery {
|
||||||
|
commitment: 2,
|
||||||
|
point: points[1],
|
||||||
|
eval: Fp::random(),
|
||||||
|
},
|
||||||
|
MyQuery {
|
||||||
|
commitment: 2,
|
||||||
|
point: points[2],
|
||||||
|
eval: Fp::random(),
|
||||||
|
},
|
||||||
|
MyQuery {
|
||||||
|
commitment: 3,
|
||||||
|
point: points[0],
|
||||||
|
eval: Fp::random(),
|
||||||
|
},
|
||||||
|
MyQuery {
|
||||||
|
commitment: 3,
|
||||||
|
point: points[3],
|
||||||
|
eval: Fp::random(),
|
||||||
|
},
|
||||||
|
MyQuery {
|
||||||
|
commitment: 4,
|
||||||
|
point: points[4],
|
||||||
|
eval: Fp::random(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let (commitment_data, point_sets) = construct_intermediate_sets(queries);
|
||||||
|
|
||||||
|
let mut a = false;
|
||||||
|
let mut a_set = 0;
|
||||||
|
let mut b = false;
|
||||||
|
let mut b_set = 0;
|
||||||
|
let mut c = false;
|
||||||
|
let mut c_set = 0;
|
||||||
|
let mut d = false;
|
||||||
|
let mut d_set = 0;
|
||||||
|
|
||||||
|
for (i, mut point_set) in point_sets.into_iter().enumerate() {
|
||||||
|
point_set.sort();
|
||||||
|
if point_set.len() == 1 {
|
||||||
|
assert_eq!(point_set[0], points[4]);
|
||||||
|
assert!(!a);
|
||||||
|
a = true;
|
||||||
|
a_set = i;
|
||||||
|
} else if point_set.len() == 2 {
|
||||||
|
let mut v0 = [points[0], points[1]];
|
||||||
|
let mut v1 = [points[0], points[3]];
|
||||||
|
v0.sort();
|
||||||
|
v1.sort();
|
||||||
|
|
||||||
|
if &point_set[..] == &v0[..] {
|
||||||
|
assert!(!b);
|
||||||
|
b = true;
|
||||||
|
b_set = i;
|
||||||
|
} else if &point_set[..] == &v1[..] {
|
||||||
|
assert!(!c);
|
||||||
|
c = true;
|
||||||
|
c_set = i;
|
||||||
|
} else {
|
||||||
|
panic!("unexpected");
|
||||||
|
}
|
||||||
|
} else if point_set.len() == 3 {
|
||||||
|
let mut v = [points[0], points[1], points[2]];
|
||||||
|
v.sort();
|
||||||
|
assert_eq!(&point_set[..], &v[..]);
|
||||||
|
assert!(!d);
|
||||||
|
d = true;
|
||||||
|
d_set = i;
|
||||||
|
} else {
|
||||||
|
panic!("unexpected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(a & b & c & d);
|
||||||
|
|
||||||
|
for commitment_data in commitment_data {
|
||||||
|
assert_eq!(
|
||||||
|
commitment_data.set_index,
|
||||||
|
match commitment_data.commitment {
|
||||||
|
0 => b_set,
|
||||||
|
1 => b_set,
|
||||||
|
2 => d_set,
|
||||||
|
3 => c_set,
|
||||||
|
4 => a_set,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use super::super::{
|
||||||
commitment::{self, Blind, Params},
|
commitment::{self, Blind, Params},
|
||||||
Coeff, Error, Polynomial,
|
Coeff, Error, Polynomial,
|
||||||
};
|
};
|
||||||
use super::{Proof, ProverQuery};
|
use super::{construct_intermediate_sets, Proof, ProverQuery, Query};
|
||||||
|
|
||||||
use crate::arithmetic::{
|
use crate::arithmetic::{
|
||||||
eval_polynomial, get_challenge_scalar, kate_division, lagrange_interpolate, Challenge, Curve,
|
eval_polynomial, get_challenge_scalar, kate_division, lagrange_interpolate, Challenge, Curve,
|
||||||
|
@ -10,7 +10,6 @@ use crate::arithmetic::{
|
||||||
};
|
};
|
||||||
use crate::plonk::hash_point;
|
use crate::plonk::hash_point;
|
||||||
use crate::transcript::Hasher;
|
use crate::transcript::Hasher;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -34,7 +33,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
{
|
{
|
||||||
let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||||
|
|
||||||
let (poly_map, point_sets) = construct_intermediate_sets::<'a, C, I>(queries);
|
let (poly_map, point_sets) = construct_intermediate_sets(queries);
|
||||||
|
|
||||||
// Collapse openings at same point sets together into single openings using
|
// Collapse openings at same point sets together into single openings using
|
||||||
// x_4 challenge.
|
// x_4 challenge.
|
||||||
|
@ -68,12 +67,12 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (poly, commitment_data) in poly_map {
|
for commitment_data in poly_map {
|
||||||
accumulate(
|
accumulate(
|
||||||
commitment_data.set_index, // set_idx,
|
commitment_data.set_index, // set_idx,
|
||||||
&poly, // poly,
|
commitment_data.commitment.poly, // poly,
|
||||||
commitment_data.blind, // blind,
|
commitment_data.commitment.blind, // blind,
|
||||||
commitment_data.evals.to_vec(), // evals
|
commitment_data.evals.to_vec(), // evals
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,126 +161,32 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For multiopen prover: Construct intermediate representations relating polynomials to sets of points by index
|
#[doc(hidden)]
|
||||||
fn construct_intermediate_sets<'a, C: CurveAffine, I>(
|
#[derive(Copy, Clone)]
|
||||||
queries: I,
|
pub struct PolynomialPointer<'a, C: CurveAffine> {
|
||||||
) -> (
|
poly: &'a Polynomial<C::Scalar, Coeff>,
|
||||||
Vec<(&'a Polynomial<C::Scalar, Coeff>, CommitmentData<C>)>, // poly_map
|
blind: commitment::Blind<C::Scalar>,
|
||||||
Vec<Vec<C::Scalar>>, // point_sets
|
}
|
||||||
)
|
|
||||||
where
|
impl<'a, C: CurveAffine> PartialEq for PolynomialPointer<'a, C> {
|
||||||
I: IntoIterator<Item = ProverQuery<'a, C>> + Clone,
|
fn eq(&self, other: &Self) -> bool {
|
||||||
{
|
std::ptr::eq(self.poly, other.poly)
|
||||||
// Construct vec of unique polynomials and corresponding information about their queries
|
}
|
||||||
let mut poly_map: Vec<(&'a Polynomial<C::Scalar, Coeff>, CommitmentData<C>)> = Vec::new();
|
}
|
||||||
|
|
||||||
// Also construct mapping from a unique point to a point_index
|
impl<'a, C: CurveAffine> Query<C::Scalar> for ProverQuery<'a, C> {
|
||||||
let mut point_index_map: BTreeMap<C::Scalar, usize> = BTreeMap::new();
|
type Commitment = PolynomialPointer<'a, C>;
|
||||||
|
|
||||||
// Construct point_indices which each polynomial is queried at
|
fn get_point(&self) -> C::Scalar {
|
||||||
for query in queries.clone() {
|
self.point
|
||||||
let num_points = point_index_map.len();
|
}
|
||||||
let point_idx = point_index_map.entry(query.point).or_insert(num_points);
|
fn get_eval(&self) -> C::Scalar {
|
||||||
|
self.eval
|
||||||
let mut exists = false;
|
}
|
||||||
for (existing_poly, existing_commitment_data) in poly_map.iter_mut() {
|
fn get_commitment(&self) -> Self::Commitment {
|
||||||
// Add to CommitmentData for existing commitment in commitment_map
|
PolynomialPointer {
|
||||||
if std::ptr::eq(query.poly, *existing_poly) {
|
poly: self.poly,
|
||||||
exists = true;
|
blind: self.blind,
|
||||||
existing_commitment_data.point_indices.push(*point_idx);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Add new poly and CommitmentData to poly_map
|
|
||||||
if !exists {
|
|
||||||
let commitment_data = CommitmentData {
|
|
||||||
set_index: 0,
|
|
||||||
blind: query.blind,
|
|
||||||
point_indices: vec![*point_idx],
|
|
||||||
evals: vec![],
|
|
||||||
};
|
|
||||||
poly_map.push((query.poly, commitment_data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also construct inverse mapping from point_index to the point
|
|
||||||
let mut inverse_point_index_map: BTreeMap<usize, C::Scalar> = BTreeMap::new();
|
|
||||||
for (&point, &point_index) in point_index_map.iter() {
|
|
||||||
inverse_point_index_map.insert(point_index, point);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct map of unique ordered point_idx_sets to their set_idx
|
|
||||||
let mut point_idx_sets: BTreeMap<BTreeSet<usize>, usize> = BTreeMap::new();
|
|
||||||
// Also construct mapping from poly to point_idx_set
|
|
||||||
let mut poly_set_map: Vec<(&Polynomial<C::Scalar, Coeff>, BTreeSet<usize>)> = Vec::new();
|
|
||||||
|
|
||||||
for (poly, commitment_data) in poly_map.iter_mut() {
|
|
||||||
let mut point_index_set = BTreeSet::new();
|
|
||||||
// Note that point_index_set is ordered, unlike point_indices
|
|
||||||
for &point_index in commitment_data.point_indices.iter() {
|
|
||||||
point_index_set.insert(point_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push point_index_set to CommitmentData for the relevant poly
|
|
||||||
poly_set_map.push((poly, point_index_set.clone()));
|
|
||||||
|
|
||||||
let num_sets = point_idx_sets.len();
|
|
||||||
point_idx_sets
|
|
||||||
.entry(point_index_set.clone())
|
|
||||||
.or_insert(num_sets);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialise empty evals vec for each unique poly
|
|
||||||
for (_, commitment_data) in poly_map.iter_mut() {
|
|
||||||
let len = commitment_data.point_indices.len();
|
|
||||||
commitment_data.evals = vec![C::Scalar::zero(); len];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate set_index, evals and points for each poly using point_idx_sets
|
|
||||||
for query in queries.clone() {
|
|
||||||
// The index of the point at which the poly is queried
|
|
||||||
let point_index = point_index_map.get(&query.point).unwrap();
|
|
||||||
|
|
||||||
// The point_index_set at which the poly was queried
|
|
||||||
let mut point_index_set = BTreeSet::new();
|
|
||||||
for (poly, point_idx_set) in poly_set_map.iter() {
|
|
||||||
if std::ptr::eq(query.poly, *poly) {
|
|
||||||
point_index_set = point_idx_set.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The set_index of the point_index_set
|
|
||||||
let set_index = point_idx_sets.get(&point_index_set).unwrap();
|
|
||||||
for (poly, commitment_data) in poly_map.iter_mut() {
|
|
||||||
if std::ptr::eq(query.poly, *poly) {
|
|
||||||
commitment_data.set_index = *set_index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let point_index_set: Vec<usize> = point_index_set.iter().cloned().collect();
|
|
||||||
|
|
||||||
// The offset of the point_index in the point_index_set
|
|
||||||
let point_index_in_set = point_index_set
|
|
||||||
.iter()
|
|
||||||
.position(|i| i == point_index)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
for (poly, commitment_data) in poly_map.iter_mut() {
|
|
||||||
if std::ptr::eq(query.poly, *poly) {
|
|
||||||
// Insert the eval using the ordering of the point_index_set
|
|
||||||
commitment_data.evals[point_index_in_set] = query.eval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get actual points in each point set
|
|
||||||
let mut point_sets: Vec<Vec<C::Scalar>> = vec![Vec::new(); point_idx_sets.len()];
|
|
||||||
for (point_idx_set, &set_idx) in point_idx_sets.iter() {
|
|
||||||
for &point_idx in point_idx_set.iter() {
|
|
||||||
let point = inverse_point_index_map.get(&point_idx).unwrap();
|
|
||||||
point_sets[set_idx].push(*point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(poly_map, point_sets)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,12 @@ use super::super::{
|
||||||
commitment::{Guard, Params, MSM},
|
commitment::{Guard, Params, MSM},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
use super::{Proof, VerifierQuery};
|
use super::{construct_intermediate_sets, Proof, Query, VerifierQuery};
|
||||||
use crate::arithmetic::{
|
use crate::arithmetic::{
|
||||||
eval_polynomial, get_challenge_scalar, lagrange_interpolate, Challenge, CurveAffine, Field,
|
eval_polynomial, get_challenge_scalar, lagrange_interpolate, Challenge, CurveAffine, Field,
|
||||||
};
|
};
|
||||||
use crate::plonk::hash_point;
|
use crate::plonk::hash_point;
|
||||||
use crate::transcript::Hasher;
|
use crate::transcript::Hasher;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct CommitmentData<C: CurveAffine> {
|
struct CommitmentData<C: CurveAffine> {
|
||||||
|
@ -38,7 +37,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
// Sample x_4 for compressing openings at the same points together
|
// Sample x_4 for compressing openings at the same points together
|
||||||
let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||||
|
|
||||||
let (commitment_map, point_sets) = construct_intermediate_sets::<'a, C, I>(queries.clone());
|
let (commitment_map, point_sets) = construct_intermediate_sets(queries);
|
||||||
|
|
||||||
// Compress the commitments and expected evaluations at x_3 together.
|
// Compress the commitments and expected evaluations at x_3 together.
|
||||||
// using the challenge x_4
|
// using the challenge x_4
|
||||||
|
@ -62,11 +61,11 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
|
|
||||||
// Each commitment corresponds to evaluations at a set of points.
|
// Each commitment corresponds to evaluations at a set of points.
|
||||||
// For each set, we collapse each commitment's evals pointwise.
|
// For each set, we collapse each commitment's evals pointwise.
|
||||||
for (commitment, commitment_data) in commitment_map.into_iter() {
|
for commitment_data in commitment_map.into_iter() {
|
||||||
accumulate(
|
accumulate(
|
||||||
commitment_data.set_index, // set_idx,
|
commitment_data.set_index, // set_idx,
|
||||||
*commitment, // commitment,
|
*commitment_data.commitment.0, // commitment,
|
||||||
commitment_data.evals, // evals
|
commitment_data.evals, // evals
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,123 +129,26 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For multiopen verifier: Construct intermediate representations relating commitments to sets of points by index
|
#[doc(hidden)]
|
||||||
fn construct_intermediate_sets<'a, C: CurveAffine, I>(
|
#[derive(Copy, Clone)]
|
||||||
queries: I,
|
pub struct CommitmentPointer<'a, C>(&'a C);
|
||||||
) -> (
|
|
||||||
Vec<(&'a C, CommitmentData<C>)>, // commitment_map
|
|
||||||
Vec<Vec<C::Scalar>>, // point_sets
|
|
||||||
)
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = VerifierQuery<'a, C>> + Clone,
|
|
||||||
{
|
|
||||||
// Construct sets of unique commitments and corresponding information about their queries
|
|
||||||
let mut commitment_map: Vec<(&'a C, CommitmentData<C>)> = Vec::new();
|
|
||||||
|
|
||||||
// Also construct mapping from a unique point to a point_index. This defines an ordering on the points.
|
impl<'a, C> PartialEq for CommitmentPointer<'a, C> {
|
||||||
let mut point_index_map: BTreeMap<C::Scalar, usize> = BTreeMap::new();
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
std::ptr::eq(self.0, other.0)
|
||||||
// Construct point_indices which each commitment is queried at
|
}
|
||||||
for query in queries.clone() {
|
}
|
||||||
let num_points = point_index_map.len();
|
|
||||||
let point_idx = point_index_map.entry(query.point).or_insert(num_points);
|
impl<'a, C: CurveAffine> Query<C::Scalar> for VerifierQuery<'a, C> {
|
||||||
|
type Commitment = CommitmentPointer<'a, C>;
|
||||||
let mut exists = false;
|
|
||||||
for (existing_commitment, existing_commitment_data) in commitment_map.iter_mut() {
|
fn get_point(&self) -> C::Scalar {
|
||||||
// Add to CommitmentData for existing commitment in commitment_map
|
self.point
|
||||||
if std::ptr::eq(query.commitment, *existing_commitment) {
|
}
|
||||||
exists = true;
|
fn get_eval(&self) -> C::Scalar {
|
||||||
existing_commitment_data.point_indices.push(*point_idx);
|
self.eval
|
||||||
}
|
}
|
||||||
}
|
fn get_commitment(&self) -> Self::Commitment {
|
||||||
|
CommitmentPointer(self.commitment)
|
||||||
// Add new commitment and CommitmentData to commitment_map
|
|
||||||
if !exists {
|
|
||||||
let commitment_data = CommitmentData {
|
|
||||||
set_index: 0,
|
|
||||||
point_indices: vec![*point_idx],
|
|
||||||
evals: vec![],
|
|
||||||
};
|
|
||||||
commitment_map.push((query.commitment, commitment_data));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also construct inverse mapping from point_index to the point
|
|
||||||
let mut inverse_point_index_map: BTreeMap<usize, C::Scalar> = BTreeMap::new();
|
|
||||||
for (&point, &point_index) in point_index_map.iter() {
|
|
||||||
inverse_point_index_map.insert(point_index, point);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct map of unique ordered point_idx_sets to their set_idx
|
|
||||||
let mut point_idx_sets: BTreeMap<BTreeSet<usize>, usize> = BTreeMap::new();
|
|
||||||
// Also construct mapping from commitment to point_idx_set
|
|
||||||
let mut commitment_set_map: Vec<(&'a C, BTreeSet<usize>)> = Vec::new();
|
|
||||||
|
|
||||||
for (commitment, commitment_data) in commitment_map.iter_mut() {
|
|
||||||
let mut point_index_set = BTreeSet::new();
|
|
||||||
// Note that point_index_set is ordered, unlike point_indices
|
|
||||||
for &point_index in commitment_data.point_indices.iter() {
|
|
||||||
point_index_set.insert(point_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push point_index_set to CommitmentData for the relevant commitment
|
|
||||||
commitment_set_map.push((commitment, point_index_set.clone()));
|
|
||||||
|
|
||||||
let num_sets = point_idx_sets.len();
|
|
||||||
point_idx_sets
|
|
||||||
.entry(point_index_set.clone())
|
|
||||||
.or_insert(num_sets);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialise empty evals vec for each unique commitment
|
|
||||||
for (_, commitment_data) in commitment_map.iter_mut() {
|
|
||||||
let len = commitment_data.point_indices.len();
|
|
||||||
commitment_data.evals = vec![C::Scalar::zero(); len];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate set_index, evals and points for each commitment using point_idx_sets
|
|
||||||
for query in queries.clone() {
|
|
||||||
// The index of the point at which the commitment is queried
|
|
||||||
let point_index = point_index_map.get(&query.point).unwrap();
|
|
||||||
|
|
||||||
// The point_index_set at which the commitment was queried
|
|
||||||
let mut point_index_set = BTreeSet::new();
|
|
||||||
for (commitment, point_idx_set) in commitment_set_map.iter() {
|
|
||||||
if std::ptr::eq(query.commitment, *commitment) {
|
|
||||||
point_index_set = point_idx_set.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// The set_index of the point_index_set
|
|
||||||
let set_index = point_idx_sets.get(&point_index_set).unwrap();
|
|
||||||
for (commitment, commitment_data) in commitment_map.iter_mut() {
|
|
||||||
if std::ptr::eq(query.commitment, *commitment) {
|
|
||||||
commitment_data.set_index = *set_index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let point_index_set: Vec<usize> = point_index_set.iter().cloned().collect();
|
|
||||||
|
|
||||||
// The offset of the point_index in the point_index_set
|
|
||||||
let point_index_in_set = point_index_set
|
|
||||||
.iter()
|
|
||||||
.position(|i| i == point_index)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
for (commitment, commitment_data) in commitment_map.iter_mut() {
|
|
||||||
if std::ptr::eq(query.commitment, *commitment) {
|
|
||||||
// Insert the eval using the ordering of the point_index_set
|
|
||||||
commitment_data.evals[point_index_in_set] = query.eval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get actual points in each point set
|
|
||||||
let mut point_sets: Vec<Vec<C::Scalar>> = vec![Vec::new(); point_idx_sets.len()];
|
|
||||||
for (point_idx_set, &set_idx) in point_idx_sets.iter() {
|
|
||||||
for &point_idx in point_idx_set.iter() {
|
|
||||||
let point = inverse_point_index_map.get(&point_idx).unwrap();
|
|
||||||
point_sets[set_idx].push(*point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(commitment_map, point_sets)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue