@@ -173,6 +173,7 @@ pub fn pcs_local_open_impl<C: GKREngine>(
173173
174174 let poly = RefMultiLinearPoly :: from_ref ( vals) ;
175175 // TODO: Change this function in Expander to use rayon.
176+ eprintln ! ( " PCS: vals={} rz={} simd={} mpi={}" , vals. len( ) , challenge. rz. len( ) , challenge. r_simd. len( ) , challenge. r_mpi. len( ) ) ;
176177 let v = <C :: FieldConfig as FieldEngine >:: single_core_eval_circuit_vals_at_expander_challenge (
177178 vals, challenge,
178179 ) ;
@@ -258,3 +259,69 @@ pub fn partition_gkr_claims_and_open_pcs_no_mpi<C: GKREngine>(
258259 ) ;
259260 } ) ;
260261}
262+
263+ /// Batch-compatible PCS opening: allows non-empty r_mpi and uses max-length key.
264+ pub fn pcs_batch_open_impl < C : GKREngine > (
265+ vals : & [ <C :: FieldConfig as FieldEngine >:: SimdCircuitField ] ,
266+ challenge : & ExpanderSingleVarChallenge < C :: FieldConfig > ,
267+ p_keys : & ExpanderProverSetup < C :: FieldConfig , C :: PCSConfig > ,
268+ transcript : & mut C :: TranscriptConfig ,
269+ ) {
270+ let max_len = * p_keys. p_keys . keys ( ) . max ( ) . expect ( "no PCS keys" ) ;
271+ let params =
272+ <C :: PCSConfig as ExpanderPCS < C :: FieldConfig > >:: gen_params ( max_len. ilog2 ( ) as usize , 1 ) ;
273+ let p_key = p_keys. p_keys . get ( & max_len) . unwrap ( ) ;
274+
275+ // Truncate rz to match commitment size
276+ let local_size = vals. len ( ) >> challenge. r_mpi . len ( ) ;
277+ let n_local_vars = if local_size > 0 { local_size. ilog2 ( ) as usize } else { 0 } ;
278+ let mut eval_challenge = challenge. clone ( ) ;
279+ eval_challenge. rz . truncate ( n_local_vars) ;
280+
281+ let v = <C :: FieldConfig as FieldEngine >:: single_core_eval_circuit_vals_at_expander_challenge (
282+ vals, & eval_challenge,
283+ ) ;
284+ transcript. append_field_element ( & v) ;
285+
286+ // For PCS: merge r_mpi into rz and pad vals to max_len
287+ let mut pcs_challenge = challenge. clone ( ) ;
288+ pcs_challenge. rz . extend_from_slice ( & pcs_challenge. r_mpi ) ;
289+ pcs_challenge. r_mpi = vec ! [ ] ;
290+
291+ // Pad to max_len for PCS key compatibility
292+ let padded: Vec < _ > = if vals. len ( ) < max_len {
293+ let mut p = vals. to_vec ( ) ;
294+ p. resize ( max_len, Default :: default ( ) ) ;
295+ p
296+ } else {
297+ vals. to_vec ( )
298+ } ;
299+ // Extend rz to match padded length
300+ let target_rz_len = max_len. ilog2 ( ) as usize ;
301+ while pcs_challenge. rz . len ( ) < target_rz_len {
302+ pcs_challenge. rz . push ( <C :: FieldConfig as FieldEngine >:: ChallengeField :: ZERO ) ;
303+ }
304+ let poly = RefMultiLinearPoly :: from_ref ( & padded) ;
305+
306+ transcript. lock_proof ( ) ;
307+ let opening = <C :: PCSConfig as ExpanderPCS < C :: FieldConfig > >:: open (
308+ & params,
309+ & MPIConfig :: prover_new ( None , None ) ,
310+ p_key,
311+ & poly,
312+ & pcs_challenge,
313+ transcript,
314+ & <C :: PCSConfig as ExpanderPCS < C :: FieldConfig > >:: init_scratch_pad (
315+ & params,
316+ & MPIConfig :: prover_new ( None , None ) ,
317+ ) ,
318+ )
319+ . unwrap ( ) ;
320+ transcript. unlock_proof ( ) ;
321+
322+ let mut buffer = vec ! [ ] ;
323+ opening
324+ . serialize_into ( & mut buffer)
325+ . expect ( "Failed to serialize opening" ) ;
326+ transcript. append_u8_slice ( & buffer) ;
327+ }
0 commit comments