@@ -11,6 +11,7 @@ use super::utils::TreeVec;
1111use super :: PcsConfig ;
1212use crate :: core:: channel:: { Channel , MerkleChannel } ;
1313use crate :: core:: pcs:: quotients:: CommitmentSchemeProof ;
14+ use crate :: core:: pcs:: utils:: prepare_preprocessed_query_positions;
1415use crate :: core:: vcs_lifted:: merkle_hasher:: MerkleHasherLifted ;
1516use crate :: core:: vcs_lifted:: verifier:: MerkleVerifierLifted ;
1617use crate :: core:: verifier:: VerificationError ;
@@ -62,31 +63,69 @@ impl<MC: MerkleChannel> CommitmentSchemeVerifier<MC> {
6263 ) -> Result < ( ) , VerificationError > {
6364 channel. mix_felts ( & proof. sampled_values . clone ( ) . flatten_cols ( ) ) ;
6465 let random_coeff = channel. draw_secure_felt ( ) ;
65- let max_log_size = * self . column_log_sizes ( ) . iter ( ) . flatten ( ) . max ( ) . unwrap ( ) ;
66+ // The lifting log size is the length of the longest column which has at least one sample
67+ // (i.e. a column which is actually used in the constraints). Usually, the only columns
68+ // that have an empty vector of samples are among the preprocessed columns.
69+ let lifting_log_size = self
70+ . column_log_sizes ( )
71+ . zip_cols ( & sampled_points)
72+ . flatten ( )
73+ . iter ( )
74+ . filter ( |( _, sampled_points) | !sampled_points. is_empty ( ) )
75+ . map ( |( log_size, _) | * log_size)
76+ . max ( )
77+ . unwrap ( ) ;
6678
6779 let bound =
68- CirclePolyDegreeBound :: new ( max_log_size - self . config . fri_config . log_blowup_factor ) ;
80+ CirclePolyDegreeBound :: new ( lifting_log_size - self . config . fri_config . log_blowup_factor ) ;
6981
7082 // FRI commitment phase on OODS quotients.
7183 let mut fri_verifier =
7284 FriVerifier :: < MC > :: commit ( channel, self . config . fri_config , proof. fri_proof , bound) ?;
7385
7486 // Verify proof of work.
75-
7687 if !channel. verify_pow_nonce ( self . config . pow_bits , proof. proof_of_work ) {
7788 return Err ( VerificationError :: ProofOfWork ) ;
7889 }
7990 channel. mix_u64 ( proof. proof_of_work ) ;
8091 // Get FRI query positions.
8192 let query_positions = fri_verifier. sample_query_positions ( channel) ;
82- // Verify merkle decommitments.
93+ let preprocessed_query_positions = prepare_preprocessed_query_positions (
94+ & query_positions,
95+ lifting_log_size,
96+ self . column_log_sizes ( ) [ 0 ]
97+ . iter ( )
98+ . max ( )
99+ . copied ( )
100+ . unwrap_or_default ( ) ,
101+ ) ;
102+
103+ // Build the query positions tree: the preprocessed tree needs a different treatment than
104+ // the other trees.
105+ let query_positions_tree = TreeVec :: new (
106+ self . trees
107+ . iter ( )
108+ . enumerate ( )
109+ . map ( |( i, _) | {
110+ if i == 0 {
111+ preprocessed_query_positions. as_slice ( )
112+ } else {
113+ query_positions. as_slice ( )
114+ }
115+ } )
116+ . collect :: < Vec < _ > > ( ) ,
117+ ) ;
118+ // Verify decommitments.
83119 self . trees
84120 . as_ref ( )
85121 . zip_eq ( proof. decommitments )
86122 . zip_eq ( proof. queried_values . clone ( ) )
87- . map ( |( ( tree, decommitment) , queried_values) | {
88- tree. verify ( & query_positions, queried_values, decommitment)
89- } )
123+ . zip_eq ( query_positions_tree)
124+ . map (
125+ |( ( ( tree, decommitment) , queried_values) , query_positions) | {
126+ tree. verify ( query_positions, queried_values, decommitment)
127+ } ,
128+ )
90129 . 0
91130 . into_iter ( )
92131 . collect :: < Result < ( ) , _ > > ( ) ?;
0 commit comments