1010//! - `BUILD_PROJECT`: Comma-separated list of projects to build (e.g., "chunk,batch"). Defaults to "chunk,batch,bundle".
1111//! - `BUILD_STAGES`: Comma-separated list of stages to run (e.g., "stage1,stage3"). Defaults to "stage1,stage2,stage3".
1212
13- use std:: { collections:: HashSet , env, path:: Path , time:: Instant } ;
13+ use std:: {
14+ collections:: { HashMap , HashSet } ,
15+ env,
16+ path:: Path ,
17+ time:: Instant ,
18+ } ;
1419
1520use dotenv:: dotenv;
16- use eyre:: Result ; // Use eyre::Result directly
21+ use eyre:: Result ;
1722use openvm_native_compiler:: ir:: DIGEST_SIZE ;
1823use openvm_sdk:: { config:: SdkVmConfig , Sdk , F } ;
1924use openvm_stark_sdk:: { openvm_stark_backend:: p3_field:: PrimeField32 , p3_baby_bear:: BabyBear } ;
@@ -53,43 +58,13 @@ fn compress_commitment(commitment: &[u32; DIGEST_SIZE]) -> Fr {
5358 compressed_value
5459}
5560
56- /// Generates the root verifier assembly code if required by the selected projects.
57- fn generate_root_verifier ( project_names : & [ & str ] , workspace_dir : & Path ) -> Result < ( ) > {
58- use openvm_sdk:: { config:: AggStarkConfig , keygen:: AggStarkProvingKey } ;
59- // Only generate if "batch" or "bundle" is being built, as they use recursive verification.
60- if project_names
61- . iter ( )
62- . any ( |& name| name == "batch" || name == "bundle" )
63- {
64- println ! ( "{LOG_PREFIX} Generating root verifier assembly..." ) ;
65- let root_verifier_path = workspace_dir
66- . join ( "crates" )
67- . join ( "build-guest" )
68- . join ( "root_verifier.asm" ) ;
69-
70- println ! ( "generating AggStarkProvingKey" ) ;
71- let ( agg_stark_pk, _) =
72- AggStarkProvingKey :: dummy_proof_and_keygen ( AggStarkConfig :: default ( ) ) ;
73-
74- println ! ( "generating root_verifier.asm" ) ;
75- let asm = openvm_sdk:: Sdk :: new ( ) . generate_root_verifier_asm ( & agg_stark_pk) ;
76- std:: fs:: write ( & root_verifier_path, asm) . expect ( "fail to write" ) ;
77-
78- println ! (
79- "{LOG_PREFIX} Root verifier generated at: {}" ,
80- root_verifier_path. display( )
81- ) ;
82- } else {
83- println ! (
84- "{LOG_PREFIX} Skipping root verifier generation (not needed for selected projects)."
85- ) ;
86- }
87- Ok ( ( ) )
88- }
89-
9061/// Stage 1: Generates and writes leaf commitments for each specified project.
91- fn run_stage1_leaf_commitments ( project_names : & [ & str ] , workspace_dir : & Path ) -> Result < ( ) > {
62+ fn run_stage1_leaf_commitments (
63+ project_names : & [ & str ] ,
64+ workspace_dir : & Path ,
65+ ) -> Result < HashMap < String , [ u32 ; DIGEST_SIZE ] > > {
9266 println ! ( "{LOG_PREFIX} === Stage 1: Generating Leaf Commitments ===" ) ;
67+ let mut leaf_commitments = HashMap :: new ( ) ;
9368 for & project_name in project_names {
9469 println ! ( "{LOG_PREFIX} Processing project: {project_name}" ) ;
9570 let project_dir = workspace_dir
@@ -106,6 +81,7 @@ fn run_stage1_leaf_commitments(project_names: &[&str], workspace_dir: &Path) ->
10681 . commitment
10782 . into ( ) ;
10883 let leaf_vm_verifier_commit_u32 = leaf_vm_verifier_commit_f. map ( |f| f. as_canonical_u32 ( ) ) ;
84+ leaf_commitments. insert ( project_name. to_string ( ) , leaf_vm_verifier_commit_u32) ;
10985
11086 // Write the commitment to a .rs file
11187 let output_path = project_dir. join ( format ! ( "{project_name}_leaf_commit.rs" ) ) ;
@@ -128,20 +104,52 @@ fn run_stage1_leaf_commitments(project_names: &[&str], workspace_dir: &Path) ->
128104 }
129105 }
130106 println ! ( "{LOG_PREFIX} === Stage 1 Finished ===" ) ;
131- Ok ( ( ) )
107+ Ok ( leaf_commitments )
132108}
133109
134110/// Stage 2: Generates the root verifier assembly code.
135111fn run_stage2_root_verifier ( project_names : & [ & str ] , workspace_dir : & Path ) -> Result < ( ) > {
136112 println ! ( "{LOG_PREFIX} === Stage 2: Generating Root Verifier ===" ) ;
137- generate_root_verifier ( project_names, workspace_dir) ?;
113+ use openvm_sdk:: { config:: AggStarkConfig , keygen:: AggStarkProvingKey } ;
114+ // Only generate if "batch" or "bundle" is being built, as they use recursive verification.
115+ if project_names
116+ . iter ( )
117+ . any ( |& name| name == "batch" || name == "bundle" )
118+ {
119+ println ! ( "{LOG_PREFIX} Generating root verifier assembly..." ) ;
120+ let root_verifier_path = workspace_dir
121+ . join ( "crates" )
122+ . join ( "build-guest" )
123+ . join ( "root_verifier.asm" ) ;
124+
125+ println ! ( "generating AggStarkProvingKey" ) ;
126+ let ( agg_stark_pk, _) =
127+ AggStarkProvingKey :: dummy_proof_and_keygen ( AggStarkConfig :: default ( ) ) ;
128+
129+ println ! ( "generating root_verifier.asm" ) ;
130+ let asm = openvm_sdk:: Sdk :: new ( ) . generate_root_verifier_asm ( & agg_stark_pk) ;
131+ std:: fs:: write ( & root_verifier_path, asm) . expect ( "fail to write" ) ;
132+
133+ println ! (
134+ "{LOG_PREFIX} Root verifier generated at: {}" ,
135+ root_verifier_path. display( )
136+ ) ;
137+ } else {
138+ println ! (
139+ "{LOG_PREFIX} Skipping root verifier generation (not needed for selected projects)."
140+ ) ;
141+ }
138142 println ! ( "{LOG_PREFIX} === Stage 2 Finished ===" ) ;
139143 Ok ( ( ) )
140144}
141145
142146/// Stage 3: Builds guest programs, transpiles them, and generates executable commitments.
143- fn run_stage3_exe_commits ( project_names : & [ & str ] , workspace_dir : & Path ) -> Result < ( ) > {
147+ fn run_stage3_exe_commits (
148+ project_names : & [ & str ] ,
149+ workspace_dir : & Path ,
150+ ) -> Result < HashMap < String , [ u32 ; DIGEST_SIZE ] > > {
144151 println ! ( "{LOG_PREFIX} === Stage 3: Generating Executable Commitments ===" ) ;
152+ let mut exe_commitments = HashMap :: new ( ) ;
145153 for & project_name in project_names {
146154 let project_path = workspace_dir
147155 . join ( "crates" )
@@ -196,6 +204,7 @@ fn run_stage3_exe_commits(project_names: &[&str], workspace_dir: &Path) -> Resul
196204 )
197205 . into ( ) ;
198206 let exe_commit_u32: [ u32 ; DIGEST_SIZE ] = exe_commit_f. map ( |f| f. as_canonical_u32 ( ) ) ;
207+ exe_commitments. insert ( project_name. to_string ( ) , exe_commit_u32) ;
199208
200209 let commit_filename = format ! ( "{project_name}_exe_commit.rs" ) ;
201210 let output_path = Path :: new ( project_dir) . join ( & commit_filename) ;
@@ -225,6 +234,57 @@ fn run_stage3_exe_commits(project_names: &[&str], workspace_dir: &Path) -> Resul
225234 ) ;
226235 }
227236 println ! ( "{LOG_PREFIX} === Stage 3 Finished ===" ) ;
237+ Ok ( exe_commitments)
238+ }
239+
240+ /// Stage 4: Dumps VK data to a JSON file if both exe and leaf commitments are available.
241+ fn run_stage4_dump_vk_json (
242+ leaf_commitments : Option < HashMap < String , [ u32 ; DIGEST_SIZE ] > > ,
243+ exe_commitments : Option < HashMap < String , [ u32 ; DIGEST_SIZE ] > > ,
244+ ) -> Result < ( ) > {
245+ println ! ( "{LOG_PREFIX} === Stage 4: Dumping VK JSON ===" ) ;
246+
247+ // Only dump VKs when both exe_commitments and leaf_commitments are available
248+ if let ( Some ( exe_commitments) , Some ( leaf_commitments) ) = ( & exe_commitments, & leaf_commitments) {
249+ #[ derive( Default , Debug , serde:: Serialize ) ]
250+ struct VKDump {
251+ pub chunk_vk : String ,
252+ pub batch_vk : String ,
253+ pub bundle_vk : String ,
254+ }
255+ let [ chunk_vk, batch_vk, bundle_vk] = [ "chunk" , "batch" , "bundle" ] . map ( |circuit| {
256+ if let ( Some ( exe) , Some ( leaf) ) =
257+ ( exe_commitments. get ( circuit) , leaf_commitments. get ( circuit) )
258+ {
259+ let app_vk = scroll_zkvm_types:: types_agg:: ProgramCommitment {
260+ exe : * exe,
261+ leaf : * leaf,
262+ }
263+ . serialize ( ) ;
264+
265+ use base64:: { Engine , prelude:: BASE64_STANDARD } ;
266+ let app_vk = BASE64_STANDARD . encode ( app_vk) ;
267+ println ! ( "{circuit}: {app_vk}" ) ;
268+ app_vk
269+ } else {
270+ String :: new ( ) // Empty string for circuits that weren't built
271+ }
272+ } ) ;
273+
274+ let dump = VKDump {
275+ chunk_vk,
276+ batch_vk,
277+ bundle_vk,
278+ } ;
279+
280+ let f = std:: fs:: File :: create ( "openVmVk.json" ) ?;
281+ serde_json:: to_writer ( f, & dump) ?;
282+ println ! (
283+ "{LOG_PREFIX} openVmVk.json: {}" ,
284+ serde_json:: to_string_pretty( & dump) ?
285+ ) ;
286+ println ! ( "{LOG_PREFIX} VK data written to openVmVk.json" ) ;
287+ }
228288 Ok ( ( ) )
229289}
230290
@@ -272,23 +332,30 @@ pub fn main() -> Result<()> {
272332 println ! ( "{LOG_PREFIX} Stages to run: {:?}" , stages_to_run) ;
273333
274334 // Execute selected stages
275- if stages_to_run. contains ( "stage1" ) {
276- run_stage1_leaf_commitments ( & projects_to_build, & workspace_dir) ?;
335+ let leaf_commitments = if stages_to_run. contains ( "stage1" ) {
336+ Some ( run_stage1_leaf_commitments (
337+ & projects_to_build,
338+ & workspace_dir,
339+ ) ?)
277340 } else {
278341 println ! ( "{LOG_PREFIX} Skipping Stage 1: Leaf Commitments" ) ;
279- }
342+ None
343+ } ;
280344
281345 if stages_to_run. contains ( "stage2" ) {
282346 run_stage2_root_verifier ( & projects_to_build, & workspace_dir) ?;
283347 } else {
284348 println ! ( "{LOG_PREFIX} Skipping Stage 2: Root Verifier" ) ;
285- }
349+ } ;
286350
287- if stages_to_run. contains ( "stage3" ) {
288- run_stage3_exe_commits ( & projects_to_build, & workspace_dir) ?;
351+ let exe_commitments = if stages_to_run. contains ( "stage3" ) {
352+ Some ( run_stage3_exe_commits ( & projects_to_build, & workspace_dir) ?)
289353 } else {
290354 println ! ( "{LOG_PREFIX} Skipping Stage 3: Exe Commits" ) ;
291- }
355+ None
356+ } ;
357+
358+ run_stage4_dump_vk_json ( leaf_commitments, exe_commitments) ?;
292359
293360 println ! ( "{LOG_PREFIX} Build process completed successfully." ) ;
294361 Ok ( ( ) )
0 commit comments