@@ -47,12 +47,26 @@ struct IntermediateSets<F: Field, Q: Query<F>> {
4747
4848fn construct_intermediate_sets < F : Field + Ord , I , Q : Query < F , Eval = F > > (
4949 queries : I ,
50- ) -> IntermediateSets < F , Q >
50+ ) -> Option < IntermediateSets < F , Q > >
5151where
5252 I : IntoIterator < Item = Q > + Clone ,
5353{
5454 let queries = queries. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
5555
56+ // Caller tried to provide two different evaluations for the same
57+ // commitment. Permitting this would be unsound.
58+ {
59+ let mut query_set: Vec < ( Q :: Commitment , F ) > = vec ! [ ] ;
60+ for query in queries. iter ( ) {
61+ let commitment = query. get_commitment ( ) ;
62+ let rotation = query. get_point ( ) ;
63+ if query_set. contains ( & ( commitment, rotation) ) {
64+ return None ;
65+ }
66+ query_set. push ( ( commitment, rotation) ) ;
67+ }
68+ }
69+
5670 // Find evaluation of a commitment at a rotation
5771 let get_eval = |commitment : Q :: Commitment , rotation : F | -> F {
5872 queries
@@ -133,18 +147,22 @@ where
133147 } )
134148 . collect :: < Vec < RotationSet < _ , _ > > > ( ) ;
135149
136- IntermediateSets {
150+ Some ( IntermediateSets {
137151 rotation_sets,
138152 super_point_set,
139- }
153+ } )
140154}
141155
142156#[ cfg( test) ]
143157mod proptests {
144158 use super :: { construct_intermediate_sets, Commitment , IntermediateSets } ;
145159 use halo2_middleware:: ff:: FromUniformBytes ;
146160 use halo2curves:: pasta:: Fp ;
147- use proptest:: { collection:: vec, prelude:: * , sample:: select} ;
161+ use proptest:: {
162+ collection:: { hash_set, vec} ,
163+ prelude:: * ,
164+ sample:: select,
165+ } ;
148166 use std:: convert:: TryFrom ;
149167
150168 #[ derive( Debug , Clone ) ]
@@ -194,10 +212,16 @@ mod proptests {
194212 prop_compose ! {
195213 // Mapping from column index to point index.
196214 fn arb_queries_inner( num_points: usize , num_cols: usize , num_queries: usize ) (
197- col_indices in vec( select( ( 0 ..num_cols) . collect:: <Vec <_>>( ) ) , num_queries) ,
198- point_indices in vec( select( ( 0 ..num_points) . collect:: <Vec <_>>( ) ) , num_queries)
215+ // Use a HashSet to ensure we sample distinct (column, point) queries.
216+ queries in hash_set(
217+ (
218+ select( ( 0 ..num_cols) . collect:: <Vec <_>>( ) ) ,
219+ select( ( 0 ..num_points) . collect:: <Vec <_>>( ) ) ,
220+ ) ,
221+ num_queries,
222+ )
199223 ) -> Vec <( usize , usize ) > {
200- col_indices . into_iter( ) . zip ( point_indices . into_iter ( ) ) . collect( )
224+ queries . into_iter( ) . collect( )
201225 }
202226 }
203227
@@ -229,14 +253,14 @@ mod proptests {
229253 fn test_intermediate_sets(
230254 ( queries_1, queries_2) in compare_queries( 8 , 8 , 16 )
231255 ) {
232- let IntermediateSets { rotation_sets, .. } = construct_intermediate_sets( queries_1) ;
256+ let IntermediateSets { rotation_sets, .. } = construct_intermediate_sets( queries_1) . ok_or_else ( || TestCaseError :: Fail ( "mismatched evals" . into ( ) ) ) ? ;
233257 let commitment_sets = rotation_sets. iter( ) . map( |data|
234258 data. commitments. iter( ) . map( Commitment :: get) . collect:: <Vec <_>>( )
235259 ) . collect:: <Vec <_>>( ) ;
236260
237261 // It shouldn't matter what the point or eval values are; we should get
238262 // the same exact point set indices and point indices again.
239- let IntermediateSets { rotation_sets: new_rotation_sets, .. } = construct_intermediate_sets( queries_2) ;
263+ let IntermediateSets { rotation_sets: new_rotation_sets, .. } = construct_intermediate_sets( queries_2) . ok_or_else ( || TestCaseError :: Fail ( "mismatched evals" . into ( ) ) ) ? ;
240264 let new_commitment_sets = new_rotation_sets. iter( ) . map( |data|
241265 data. commitments. iter( ) . map( Commitment :: get) . collect:: <Vec <_>>( )
242266 ) . collect:: <Vec <_>>( ) ;
0 commit comments