halo2_axiom/poly/ipa/
multiopen.rs

1//! This module contains an optimisation of the polynomial commitment opening
2//! scheme described in the [Halo][halo] paper.
3//!
4//! [halo]: https://eprint.iacr.org/2019/1021
5
6use super::*;
7use crate::{poly::query::Query, transcript::ChallengeScalar};
8use ff::Field;
9use std::collections::{BTreeMap, BTreeSet};
10
11mod prover;
12mod verifier;
13
14pub use prover::ProverIPA;
15pub use verifier::VerifierIPA;
16
17#[derive(Clone, Copy, Debug)]
18struct X1 {}
19/// Challenge for compressing openings at the same point sets together.
20type ChallengeX1<F> = ChallengeScalar<F, X1>;
21
22#[derive(Clone, Copy, Debug)]
23struct X2 {}
24/// Challenge for keeping the multi-point quotient polynomial terms linearly independent.
25type ChallengeX2<F> = ChallengeScalar<F, X2>;
26
27#[derive(Clone, Copy, Debug)]
28struct X3 {}
29/// Challenge point at which the commitments are opened.
30type ChallengeX3<F> = ChallengeScalar<F, X3>;
31
32#[derive(Clone, Copy, Debug)]
33struct X4 {}
34/// Challenge for collapsing the openings of the various remaining polynomials at x_3
35/// together.
36type ChallengeX4<F> = ChallengeScalar<F, X4>;
37
38#[derive(Debug)]
39struct CommitmentData<F, T: PartialEq> {
40    pub(crate) commitment: T,
41    pub(crate) set_index: usize,
42    pub(crate) point_indices: Vec<usize>,
43    pub(crate) evals: Vec<F>,
44}
45
46impl<F, T: PartialEq> CommitmentData<F, T> {
47    fn new(commitment: T) -> Self {
48        CommitmentData {
49            commitment,
50            set_index: 0,
51            point_indices: vec![],
52            evals: vec![],
53        }
54    }
55}
56
57type IntermediateSets<F, Q> = (
58    Vec<CommitmentData<<Q as Query<F>>::Eval, <Q as Query<F>>::Commitment>>,
59    Vec<Vec<F>>,
60);
61
62fn construct_intermediate_sets<F: Field + Ord, I, Q: Query<F>>(queries: I) -> IntermediateSets<F, Q>
63where
64    I: IntoIterator<Item = Q> + Clone,
65{
66    // Construct sets of unique commitments and corresponding information about
67    // their queries.
68    let mut commitment_map: Vec<CommitmentData<Q::Eval, Q::Commitment>> = vec![];
69
70    // Also construct mapping from a unique point to a point_index. This defines
71    // an ordering on the points.
72    let mut point_index_map = BTreeMap::new();
73
74    // Iterate over all of the queries, computing the ordering of the points
75    // while also creating new commitment data.
76    for query in queries.clone() {
77        let num_points = point_index_map.len();
78        let point_idx = point_index_map
79            .entry(query.get_point())
80            .or_insert(num_points);
81
82        if let Some(pos) = commitment_map
83            .iter()
84            .position(|comm| comm.commitment == query.get_commitment())
85        {
86            commitment_map[pos].point_indices.push(*point_idx);
87        } else {
88            let mut tmp = CommitmentData::new(query.get_commitment());
89            tmp.point_indices.push(*point_idx);
90            commitment_map.push(tmp);
91        }
92    }
93
94    // Also construct inverse mapping from point_index to the point
95    let mut inverse_point_index_map = BTreeMap::new();
96    for (&point, &point_index) in point_index_map.iter() {
97        inverse_point_index_map.insert(point_index, point);
98    }
99
100    // Construct map of unique ordered point_idx_sets to their set_idx
101    let mut point_idx_sets = BTreeMap::new();
102    // Also construct mapping from commitment to point_idx_set
103    let mut commitment_set_map = Vec::new();
104
105    for commitment_data in commitment_map.iter() {
106        let mut point_index_set = BTreeSet::new();
107        // Note that point_index_set is ordered, unlike point_indices
108        for &point_index in commitment_data.point_indices.iter() {
109            point_index_set.insert(point_index);
110        }
111
112        // Push point_index_set to CommitmentData for the relevant commitment
113        commitment_set_map.push((commitment_data.commitment, point_index_set.clone()));
114
115        let num_sets = point_idx_sets.len();
116        point_idx_sets.entry(point_index_set).or_insert(num_sets);
117    }
118
119    // Initialise empty evals vec for each unique commitment
120    for commitment_data in commitment_map.iter_mut() {
121        let len = commitment_data.point_indices.len();
122        commitment_data.evals = vec![Q::Eval::default(); len];
123    }
124
125    // Populate set_index, evals and points for each commitment using point_idx_sets
126    for query in queries {
127        // The index of the point at which the commitment is queried
128        let point_index = point_index_map.get(&query.get_point()).unwrap();
129
130        // The point_index_set at which the commitment was queried
131        let mut point_index_set = BTreeSet::new();
132        for (commitment, point_idx_set) in commitment_set_map.iter() {
133            if query.get_commitment() == *commitment {
134                point_index_set = point_idx_set.clone();
135            }
136        }
137        assert!(!point_index_set.is_empty());
138
139        // The set_index of the point_index_set
140        let set_index = point_idx_sets.get(&point_index_set).unwrap();
141        for commitment_data in commitment_map.iter_mut() {
142            if query.get_commitment() == commitment_data.commitment {
143                commitment_data.set_index = *set_index;
144            }
145        }
146        let point_index_set: Vec<usize> = point_index_set.iter().cloned().collect();
147
148        // The offset of the point_index in the point_index_set
149        let point_index_in_set = point_index_set
150            .iter()
151            .position(|i| i == point_index)
152            .unwrap();
153
154        for commitment_data in commitment_map.iter_mut() {
155            if query.get_commitment() == commitment_data.commitment {
156                // Insert the eval using the ordering of the point_index_set
157                commitment_data.evals[point_index_in_set] = query.get_eval();
158            }
159        }
160    }
161
162    // Get actual points in each point set
163    let mut point_sets: Vec<Vec<F>> = vec![Vec::new(); point_idx_sets.len()];
164    for (point_idx_set, &set_idx) in point_idx_sets.iter() {
165        for &point_idx in point_idx_set.iter() {
166            let point = inverse_point_index_map.get(&point_idx).unwrap();
167            point_sets[set_idx].push(*point);
168        }
169    }
170
171    (commitment_map, point_sets)
172}