@@ -86,9 +86,10 @@ pub const INTERNAL_LOG_BLOWUP: usize = 2;
8686pub const ROOT_LOG_BLOWUP : usize = 3 ;
8787pub const SBOX_SIZE : usize = 7 ;
8888const VM_MAX_TRACE_HEIGHTS : & [ u32 ] = & [
89- 4194304 , 4 , 128 , 2097152 , 8388608 , 4194304 , 262144 , 8388608 , 16777216 , 2097152 , 16777216 ,
90- 2097152 , 8388608 , 262144 , 2097152 , 1048576 , 4194304 , 1048576 , 262144 ,
89+ 4194304 , 4 , 128 , 2097152 , 8388608 , 4194304 , 262144 , 8388608 , 16777216 , 16777216 , 2097152 ,
90+ 16777216 , 2097152 , 8388608 , 262144 , 2097152 , 1048576 , 4194304 , 1048576 , 262144 ,
9191] ;
92+
9293pub struct CenoAggregationProver {
9394 pub base_vk : ZKVMVerifyingKey < E , Basefold < E , BasefoldRSParams > > ,
9495 pub leaf_prover : VmInstance < BabyBearPoseidon2Engine , NativeBuilder > ,
@@ -290,7 +291,7 @@ impl CenoAggregationProver {
290291
291292 // _debug: export
292293 // let file =
293- // File::create(format!("leaf_proof_{:?}.bin", proof_idx)).expect("Create export proof file");
294+ // File::create(format!("leaf_proof_{:?}.bin", proof_idx)).expect("Create export proof file");
294295 // bincode::serialize_into(file, &leaf_proof).expect("failed to serialize leaf proof");
295296
296297 println ! (
@@ -304,14 +305,28 @@ impl CenoAggregationProver {
304305 } )
305306 . collect :: < Vec < _ > > ( ) ;
306307
307- // Aggregate tree to root proof
308+ // Aggregate leaf proofs into a single internal proof via binary tree
309+ let root_inner = self . aggregate_internal_proofs ( leaf_proofs) ;
310+
311+ // Export e2e stark proof (used in verify_e2e_stark_proof)
312+ VmStarkProof {
313+ inner : root_inner,
314+ user_public_values,
315+ }
316+ }
317+
318+ /// Aggregate leaf (or internal) proofs into a single root internal proof
319+ /// via a binary tree of internal proving rounds.
320+ pub fn aggregate_internal_proofs ( & mut self , leaf_proofs : Vec < Proof < SC > > ) -> Proof < SC > {
321+ let start = Instant :: now ( ) ;
322+
308323 let mut internal_node_idx = -1 ;
309324 let mut internal_node_height = 0 ;
310325 let mut proofs = leaf_proofs;
311326
312327 println ! (
313328 "Aggregation - Start internal aggregation at: {:?}" ,
314- aggregation_start_timestamp . elapsed( )
329+ start . elapsed( )
315330 ) ;
316331 // We will always generate at least one internal proof, even if there is only one leaf
317332 // proof, in order to shrink the proof size
@@ -321,7 +336,6 @@ impl CenoAggregationProver {
321336 & proofs,
322337 DEFAULT_NUM_CHILDREN_INTERNAL ,
323338 ) ;
324-
325339 let layer_proofs: Vec < Proof < _ > > = internal_inputs
326340 . into_iter ( )
327341 . map ( |input| {
@@ -337,7 +351,7 @@ impl CenoAggregationProver {
337351 "Aggregation - Completed internal node (idx: {:?}) at height {:?}: {:?}" ,
338352 internal_node_idx,
339353 internal_node_height,
340- aggregation_start_timestamp . elapsed( )
354+ start . elapsed( )
341355 ) ;
342356
343357 // _debug: export
@@ -356,17 +370,13 @@ impl CenoAggregationProver {
356370 }
357371 println ! (
358372 "Aggregation - Completed internal aggregation at: {:?}" ,
359- aggregation_start_timestamp . elapsed( )
373+ start . elapsed( )
360374 ) ;
361375 println ! ( "Aggregation - Final height: {:?}" , internal_node_height) ;
362376
363377 // TODO: generate root proof from last internal proof
364378
365- // Export e2e stark proof (used in verify_e2e_stark_proof)
366- VmStarkProof {
367- inner : proofs. pop ( ) . unwrap ( ) ,
368- user_public_values,
369- }
379+ proofs. pop ( ) . unwrap ( )
370380 }
371381}
372382
@@ -415,6 +425,25 @@ impl CenoLeafVmVerifierConfig {
415425 builder. assign ( & stark_pvs. connector . initial_pc , init_pc) ;
416426 builder. assign ( & stark_pvs. connector . final_pc , end_pc) ;
417427 builder. assign ( & stark_pvs. connector . exit_code , exit_code) ;
428+ // Internal aggregation asserts connector chaining on this field.
429+ builder
430+ . if_eq ( ceno_leaf_input. is_last , Usize :: from ( 1 ) )
431+ . then_or_else (
432+ |builder| {
433+ builder. assign ( & stark_pvs. connector . is_terminate , F :: ONE ) ;
434+ } ,
435+ |builder| {
436+ builder. assign ( & stark_pvs. connector . is_terminate , F :: ZERO ) ;
437+ } ,
438+ ) ;
439+
440+ // Keep remaining committed PVs deterministic until real memory/public-values
441+ // commitments are wired through this custom leaf program.
442+ for i in 0 ..DIGEST_SIZE {
443+ builder. assign ( & stark_pvs. memory . initial_root [ i] , F :: ZERO ) ;
444+ builder. assign ( & stark_pvs. memory . final_root [ i] , F :: ZERO ) ;
445+ builder. assign ( & stark_pvs. public_values_commit [ i] , F :: ZERO ) ;
446+ }
418447
419448 // TODO: assign shard_ec_sum to stark_pvs.shard_ec_sum
420449
@@ -693,6 +722,7 @@ pub fn verify_proofs(
693722
694723 let fri_params = standard_fri_params_with_100_bits_conjectured_security ( 1 ) ;
695724 let vb = NativeBuilder :: default ( ) ;
725+
696726 air_test_impl :: < BabyBearPoseidon2Engine , _ > (
697727 fri_params,
698728 vb,
@@ -703,14 +733,21 @@ pub fn verify_proofs(
703733 true ,
704734 )
705735 . unwrap ( ) ;
736+
737+ // _debug
738+ // let engine = BabyBearPoseidon2Engine::new(fri_params);
739+ // let (mut vm, pk) = VirtualMachine::new_with_keygen(engine, vb, config).expect("create vm");
740+ // let vk = pk.get_vk();
741+ // vm.verify(&vk, &proofs)
742+ // .expect("segment proofs should verify");
706743 }
707744}
708745
709746#[ cfg( test) ]
710747mod tests {
711748 use super :: verify_e2e_stark_proof;
712749 use crate :: {
713- aggregation:: { CenoAggregationProver , verify_proofs} ,
750+ aggregation:: { CenoAggregationProver , SC , verify_proofs} ,
714751 zkvm_verifier:: binding:: E ,
715752 } ;
716753 use ceno_zkvm:: {
@@ -719,6 +756,7 @@ mod tests {
719756 structs:: ZKVMVerifyingKey ,
720757 } ;
721758 use mpcs:: { Basefold , BasefoldRSParams } ;
759+ use openvm_stark_backend:: proof:: Proof ;
722760 use openvm_stark_sdk:: { config:: setup_tracing_with_log_level, p3_bn254_fr:: Bn254Fr } ;
723761 use p3:: field:: FieldAlgebra ;
724762 use std:: fs:: File ;
@@ -785,6 +823,30 @@ mod tests {
785823 verify ( zkvm_proofs. clone ( ) , & verifier) . expect ( "Verification failed" ) ;
786824 }
787825
826+ pub fn internal_aggregation_inner_thread ( ) {
827+ setup_tracing_with_log_level ( tracing:: Level :: WARN ) ;
828+
829+ let vk_path = "./src/imported/vk.bin" ;
830+ let vk: ZKVMVerifyingKey < E , Basefold < E , BasefoldRSParams > > =
831+ bincode:: deserialize_from ( File :: open ( vk_path) . expect ( "Failed to open vk file" ) )
832+ . expect ( "Failed to deserialize vk file" ) ;
833+
834+ let mut agg_prover = CenoAggregationProver :: from_base_vk ( vk) ;
835+
836+ // Load exported leaf proofs
837+ let leaf_proof_0: Proof < SC > = bincode:: deserialize_from (
838+ File :: open ( "./leaf_proof_0.bin" ) . expect ( "Failed to open leaf_proof_0.bin" ) ,
839+ )
840+ . expect ( "Failed to deserialize leaf_proof_0" ) ;
841+ let leaf_proof_1: Proof < SC > = bincode:: deserialize_from (
842+ File :: open ( "./leaf_proof_1.bin" ) . expect ( "Failed to open leaf_proof_1.bin" ) ,
843+ )
844+ . expect ( "Failed to deserialize leaf_proof_1" ) ;
845+
846+ let leaf_proofs = vec ! [ leaf_proof_0, leaf_proof_1] ;
847+ let _root_proof = agg_prover. aggregate_internal_proofs ( leaf_proofs) ;
848+ }
849+
788850 #[ test]
789851 #[ ignore = "need to generate proof first" ]
790852 pub fn test_aggregation ( ) {
@@ -798,6 +860,19 @@ mod tests {
798860 handler. join ( ) . expect ( "Thread panicked" ) ;
799861 }
800862
863+ #[ test]
864+ #[ ignore = "need to generate proof first" ]
865+ pub fn test_internal_aggregation ( ) {
866+ let stack_size = 256 * 1024 * 1024 ;
867+
868+ let handler = std:: thread:: Builder :: new ( )
869+ . stack_size ( stack_size)
870+ . spawn ( internal_aggregation_inner_thread)
871+ . expect ( "Failed to spawn thread" ) ;
872+
873+ handler. join ( ) . expect ( "Thread panicked" ) ;
874+ }
875+
801876 #[ test]
802877 #[ ignore = "need to generate proof first" ]
803878 pub fn test_single ( ) {
0 commit comments