halo2_axiom/poly/kzg/multiopen/
shplonk.rs
1mod prover;
2mod verifier;
3
4use std::hash::Hash;
5
6use crate::multicore::IntoParallelIterator;
7use crate::{poly::query::Query, transcript::ChallengeScalar};
8use ff::Field;
9pub use prover::ProverSHPLONK;
10use rustc_hash::FxHashSet;
11pub use verifier::VerifierSHPLONK;
12
13#[cfg(feature = "multicore")]
14use crate::multicore::ParallelIterator;
15
16#[derive(Clone, Copy, Debug)]
17struct U {}
18type ChallengeU<F> = ChallengeScalar<F, U>;
19
20#[derive(Clone, Copy, Debug)]
21struct V {}
22type ChallengeV<F> = ChallengeScalar<F, V>;
23
24#[derive(Clone, Copy, Debug)]
25struct Y {}
26type ChallengeY<F> = ChallengeScalar<F, Y>;
27
28#[derive(Debug, Clone, PartialEq)]
29struct Commitment<F: Field, T: PartialEq + Clone>((T, Vec<F>));
30
31impl<F: Field, T: PartialEq + Clone> Commitment<F, T> {
32 fn get(&self) -> T {
33 self.0 .0.clone()
34 }
35
36 fn evals(&self) -> Vec<F> {
37 self.0 .1.clone()
38 }
39}
40
41#[derive(Debug, Clone, PartialEq)]
42struct RotationSet<F: Field, T: PartialEq + Clone> {
43 commitments: Vec<Commitment<F, T>>,
44 points: Vec<F>,
45}
46
47#[derive(Debug, PartialEq)]
48struct IntermediateSets<F: Field + Hash, Q: Query<F>> {
49 rotation_sets: Vec<RotationSet<F, Q::Commitment>>,
50 super_point_set: FxHashSet<F>,
51}
52
53fn construct_intermediate_sets<F: Field + Hash, I, Q: Query<F, Eval = F>>(
54 queries: I,
55) -> IntermediateSets<F, Q>
56where
57 I: IntoIterator<Item = Q> + Clone,
58{
59 let queries = queries.into_iter().collect::<Vec<_>>();
60
61 let get_eval = |commitment: Q::Commitment, rotation: F| -> F {
63 queries
64 .iter()
65 .find(|query| query.get_commitment() == commitment && query.get_point() == rotation)
66 .unwrap()
67 .get_eval()
68 };
69
70 let mut super_point_set = FxHashSet::default();
72
73 let mut commitment_rotation_set_map: Vec<(Q::Commitment, FxHashSet<F>)> = vec![];
81 for query in queries.iter() {
82 let rotation = query.get_point();
83 super_point_set.insert(rotation);
84 if let Some(commitment_rotation_set) = commitment_rotation_set_map
85 .iter_mut()
86 .find(|(commitment, _)| *commitment == query.get_commitment())
87 {
88 let (_, rotation_set) = commitment_rotation_set;
89 rotation_set.insert(rotation);
90 } else {
91 commitment_rotation_set_map.push((
92 query.get_commitment(),
93 FxHashSet::from_iter(core::iter::once(rotation)),
94 ));
95 };
96 }
97
98 let mut rotation_set_commitment_map: Vec<(FxHashSet<F>, Vec<Q::Commitment>)> = vec![];
105 for (commitment, rotation_set) in commitment_rotation_set_map.into_iter() {
106 if let Some(rotation_set_commitment) = rotation_set_commitment_map
107 .iter_mut()
108 .find(|(set, _)| set == &rotation_set)
109 {
110 let (_, commitments) = rotation_set_commitment;
111 commitments.push(commitment);
112 } else {
113 rotation_set_commitment_map.push((rotation_set, vec![commitment]));
114 };
115 }
116
117 let rotation_sets = rotation_set_commitment_map
118 .into_par_iter()
119 .map(|(rotations, commitments)| {
120 let rotations_vec = rotations.iter().collect::<Vec<_>>();
121 let commitments: Vec<Commitment<F, Q::Commitment>> = commitments
122 .into_par_iter()
123 .map(|commitment| {
124 let evals: Vec<F> = rotations_vec
125 .as_slice()
126 .into_par_iter()
127 .map(|&&rotation| get_eval(commitment, rotation))
128 .collect();
129 Commitment((commitment, evals))
130 })
131 .collect();
132
133 RotationSet {
134 commitments,
135 points: rotations.into_iter().collect(),
136 }
137 })
138 .collect::<Vec<RotationSet<_, _>>>();
139
140 IntermediateSets {
141 rotation_sets,
142 super_point_set,
143 }
144}
145
146#[cfg(test)]
147mod proptests {
148 use super::{construct_intermediate_sets, Commitment, IntermediateSets};
149 use ff::FromUniformBytes;
150 use halo2curves::bn256::Fr;
151 use proptest::{collection::vec, prelude::*, sample::select};
152 use std::convert::TryFrom;
153
154 #[derive(Debug, Clone)]
155 struct MyQuery<F> {
156 point: F,
157 eval: F,
158 commitment: usize,
159 }
160
161 impl super::Query<Fr> for MyQuery<Fr> {
162 type Commitment = usize;
163 type Eval = Fr;
164
165 fn get_point(&self) -> Fr {
166 self.point
167 }
168
169 fn get_eval(&self) -> Self::Eval {
170 self.eval
171 }
172
173 fn get_commitment(&self) -> Self::Commitment {
174 self.commitment
175 }
176 }
177
178 prop_compose! {
179 fn arb_point()(
180 bytes in vec(any::<u8>(), 64)
181 ) -> Fr {
182 Fr::from_uniform_bytes(&<[u8; 64]>::try_from(bytes).unwrap())
183 }
184 }
185
186 prop_compose! {
187 fn arb_query(commitment: usize, point: Fr)(
188 eval in arb_point()
189 ) -> MyQuery<Fr> {
190 MyQuery {
191 point,
192 eval,
193 commitment
194 }
195 }
196 }
197
198 prop_compose! {
199 fn arb_queries_inner(num_points: usize, num_cols: usize, num_queries: usize)(
201 col_indices in vec(select((0..num_cols).collect::<Vec<_>>()), num_queries),
202 point_indices in vec(select((0..num_points).collect::<Vec<_>>()), num_queries)
203 ) -> Vec<(usize, usize)> {
204 col_indices.into_iter().zip(point_indices).collect()
205 }
206 }
207
208 prop_compose! {
209 fn compare_queries(
210 num_points: usize,
211 num_cols: usize,
212 num_queries: usize,
213 )(
214 points_1 in vec(arb_point(), num_points),
215 points_2 in vec(arb_point(), num_points),
216 mapping in arb_queries_inner(num_points, num_cols, num_queries)
217 )(
218 queries_1 in mapping.iter().map(|(commitment, point_idx)| arb_query(*commitment, points_1[*point_idx])).collect::<Vec<_>>(),
219 queries_2 in mapping.iter().map(|(commitment, point_idx)| arb_query(*commitment, points_2[*point_idx])).collect::<Vec<_>>(),
220 ) -> (
221 Vec<MyQuery<Fr>>,
222 Vec<MyQuery<Fr>>
223 ) {
224 (
225 queries_1,
226 queries_2,
227 )
228 }
229 }
230
231 proptest! {
232 #[test]
233 fn test_intermediate_sets(
234 (queries_1, queries_2) in compare_queries(8, 8, 16)
235 ) {
236 let IntermediateSets { rotation_sets, .. } = construct_intermediate_sets(queries_1);
237 let commitment_sets = rotation_sets.iter().map(|data|
238 data.commitments.iter().map(Commitment::get).collect::<Vec<_>>()
239 ).collect::<Vec<_>>();
240
241 let IntermediateSets { rotation_sets: new_rotation_sets, .. } = construct_intermediate_sets(queries_2);
244 let new_commitment_sets = new_rotation_sets.iter().map(|data|
245 data.commitments.iter().map(Commitment::get).collect::<Vec<_>>()
246 ).collect::<Vec<_>>();
247
248 assert_eq!(commitment_sets, new_commitment_sets);
249 }
250 }
251}