@@ -133,7 +133,7 @@ enum Commands {
133133
134134 /// Blowup factor (power of 2). Higher = fewer queries, smaller proof, slower proving.
135135 #[ arg( long, default_value = "2" ) ]
136- blowup : Option < u8 > ,
136+ blowup : u8 ,
137137
138138 /// Print proving time
139139 #[ arg( long) ]
@@ -145,7 +145,7 @@ enum Commands {
145145
146146 /// Build traces and print total main-trace field elements (rows × columns summed across
147147 /// all tables) and aux-trace field elements (committed EF columns × rows)
148- #[ arg( long) ]
148+ #[ arg( long, conflicts_with = "continuations" ) ]
149149 elements : bool ,
150150
151151 /// Prove with continuations (split execution into epochs; flat peak memory)
@@ -175,7 +175,7 @@ enum Commands {
175175
176176 /// Blowup factor used during proving (must match)
177177 #[ arg( long, default_value = "2" ) ]
178- blowup : Option < u8 > ,
178+ blowup : u8 ,
179179
180180 /// Print verification time
181181 #[ arg( long) ]
@@ -221,7 +221,15 @@ fn main() -> ExitCode {
221221 epoch_size_log2,
222222 } => {
223223 if continuations {
224- cmd_prove_continuation ( elf, output, private_input, epoch_size_log2, blowup, time)
224+ cmd_prove_continuation (
225+ elf,
226+ output,
227+ private_input,
228+ epoch_size_log2,
229+ blowup,
230+ time,
231+ cycles,
232+ )
225233 } else {
226234 cmd_prove ( elf, output, private_input, blowup, time, cycles, elements)
227235 }
@@ -253,6 +261,17 @@ fn read_private_input(path: Option<&PathBuf>) -> Result<Vec<u8>, String> {
253261 }
254262}
255263
264+ fn count_cycles ( elf_data : & [ u8 ] , private_inputs : & [ u8 ] ) -> Result < u64 , String > {
265+ let program =
266+ Elf :: load ( elf_data) . map_err ( |e| format ! ( "Failed to load ELF for cycle count: {e:?}" ) ) ?;
267+ let executor = Executor :: new ( & program, private_inputs. to_vec ( ) )
268+ . map_err ( |e| format ! ( "Failed to create executor for cycle count: {e:?}" ) ) ?;
269+ executor
270+ . run ( )
271+ . map ( |result| result. logs . len ( ) as u64 )
272+ . map_err ( |e| format ! ( "Execution failed during cycle count: {e:?}" ) )
273+ }
274+
256275fn cmd_execute (
257276 elf_path : PathBuf ,
258277 private_input_path : Option < PathBuf > ,
@@ -360,7 +379,7 @@ fn cmd_prove(
360379 elf_path : PathBuf ,
361380 output_path : PathBuf ,
362381 private_input_path : Option < PathBuf > ,
363- blowup : Option < u8 > ,
382+ blowup : u8 ,
364383 time : bool ,
365384 cycles : bool ,
366385 elements : bool ,
@@ -386,24 +405,10 @@ fn cmd_prove(
386405 // Mirrors SP1's cycle-count pass so both provers report the same kind of
387406 // number without inflating the measured proving time.
388407 let cycle_count = if cycles {
389- let program = match Elf :: load ( & elf_data) {
390- Ok ( p ) => p ,
408+ match count_cycles ( & elf_data, & private_inputs ) {
409+ Ok ( count ) => Some ( count ) ,
391410 Err ( e) => {
392- eprintln ! ( "Failed to load ELF for cycle count: {:?}" , e) ;
393- return ExitCode :: FAILURE ;
394- }
395- } ;
396- let executor = match Executor :: new ( & program, private_inputs. clone ( ) ) {
397- Ok ( e) => e,
398- Err ( e) => {
399- eprintln ! ( "Failed to create executor for cycle count: {:?}" , e) ;
400- return ExitCode :: FAILURE ;
401- }
402- } ;
403- match executor. run ( ) {
404- Ok ( result) => Some ( result. logs . len ( ) as u64 ) ,
405- Err ( e) => {
406- eprintln ! ( "Execution failed during cycle count: {:?}" , e) ;
411+ eprintln ! ( "{e}" ) ;
407412 return ExitCode :: FAILURE ;
408413 }
409414 }
@@ -434,31 +439,23 @@ fn cmd_prove(
434439 } ) ;
435440
436441 let start = Instant :: now ( ) ;
437- let proof = match blowup {
438- Some ( b) => {
439- let opts = match GoldilocksCubicProofOptions :: with_blowup ( b) {
440- Ok ( opts) => opts,
441- Err ( e) => {
442- eprintln ! ( "Invalid proof options: {e}" ) ;
443- return ExitCode :: FAILURE ;
444- }
445- } ;
446- eprintln ! (
447- "Generating proof (blowup={b}, queries={})..." ,
448- opts. fri_number_of_queries
449- ) ;
450- prover:: prove_with_options_and_inputs (
451- & elf_data,
452- & private_inputs,
453- & opts,
454- & Default :: default ( ) ,
455- )
456- }
457- None => {
458- eprintln ! ( "Generating proof..." ) ;
459- prover:: prove_with_inputs ( & elf_data, & private_inputs)
442+ let opts = match GoldilocksCubicProofOptions :: with_blowup ( blowup) {
443+ Ok ( opts) => opts,
444+ Err ( e) => {
445+ eprintln ! ( "Invalid proof options: {e}" ) ;
446+ return ExitCode :: FAILURE ;
460447 }
461448 } ;
449+ eprintln ! (
450+ "Generating proof (blowup={blowup}, queries={})..." ,
451+ opts. fri_number_of_queries
452+ ) ;
453+ let proof = prover:: prove_with_options_and_inputs (
454+ & elf_data,
455+ & private_inputs,
456+ & opts,
457+ & Default :: default ( ) ,
458+ ) ;
462459 let prove_elapsed = start. elapsed ( ) ;
463460 let proof = match proof {
464461 Ok ( proof) => proof,
@@ -510,7 +507,7 @@ fn cmd_prove(
510507 ExitCode :: SUCCESS
511508}
512509
513- fn cmd_verify ( proof_path : PathBuf , elf_path : PathBuf , blowup : Option < u8 > , time : bool ) -> ExitCode {
510+ fn cmd_verify ( proof_path : PathBuf , elf_path : PathBuf , blowup : u8 , time : bool ) -> ExitCode {
514511 eprintln ! ( "Reading ELF file..." ) ;
515512 let elf_data = match std:: fs:: read ( & elf_path) {
516513 Ok ( data) => data,
@@ -539,19 +536,14 @@ fn cmd_verify(proof_path: PathBuf, elf_path: PathBuf, blowup: Option<u8>, time:
539536
540537 eprintln ! ( "Verifying proof..." ) ;
541538 let start = Instant :: now ( ) ;
542- let result = match blowup {
543- Some ( b) => {
544- let opts = match GoldilocksCubicProofOptions :: with_blowup ( b) {
545- Ok ( opts) => opts,
546- Err ( e) => {
547- eprintln ! ( "Invalid proof options: {e}" ) ;
548- return ExitCode :: FAILURE ;
549- }
550- } ;
551- prover:: verify_with_options ( & proof, & elf_data, & opts, None , None )
539+ let opts = match GoldilocksCubicProofOptions :: with_blowup ( blowup) {
540+ Ok ( opts) => opts,
541+ Err ( e) => {
542+ eprintln ! ( "Invalid proof options: {e}" ) ;
543+ return ExitCode :: FAILURE ;
552544 }
553- None => prover:: verify ( & proof, & elf_data) ,
554545 } ;
546+ let result = prover:: verify_with_options ( & proof, & elf_data, & opts, None , None ) ;
555547 let verify_elapsed = start. elapsed ( ) ;
556548 let result = match result {
557549 Ok ( valid) => valid,
@@ -568,7 +560,7 @@ fn cmd_verify(proof_path: PathBuf, elf_path: PathBuf, blowup: Option<u8>, time:
568560 }
569561 ExitCode :: SUCCESS
570562 } else {
571- eprintln ! ( "Verification failed!" ) ;
563+ eprintln ! ( "Verification failed! Ensure --blowup matches the value used for proving. " ) ;
572564 ExitCode :: FAILURE
573565 }
574566}
@@ -578,8 +570,9 @@ fn cmd_prove_continuation(
578570 output_path : PathBuf ,
579571 private_input_path : Option < PathBuf > ,
580572 epoch_size_log2 : Option < u32 > ,
581- blowup : Option < u8 > ,
573+ blowup : u8 ,
582574 time : bool ,
575+ cycles : bool ,
583576) -> ExitCode {
584577 eprintln ! ( "Reading ELF file..." ) ;
585578 let elf_data = match std:: fs:: read ( & elf_path) {
@@ -598,6 +591,18 @@ fn cmd_prove_continuation(
598591 }
599592 } ;
600593
594+ let cycle_count = if cycles {
595+ match count_cycles ( & elf_data, & private_inputs) {
596+ Ok ( count) => Some ( count) ,
597+ Err ( e) => {
598+ eprintln ! ( "{e}" ) ;
599+ return ExitCode :: FAILURE ;
600+ }
601+ }
602+ } else {
603+ None
604+ } ;
605+
601606 let epoch_size_log2 = epoch_size_log2. unwrap_or ( DEFAULT_CONTINUATION_EPOCH_SIZE_LOG2 ) ;
602607 let epoch_size = match continuation_epoch_size ( epoch_size_log2) {
603608 Ok ( size) => size,
@@ -607,7 +612,6 @@ fn cmd_prove_continuation(
607612 }
608613 } ;
609614
610- let blowup = blowup. unwrap_or ( 2 ) ;
611615 let opts = match GoldilocksCubicProofOptions :: with_blowup ( blowup) {
612616 Ok ( opts) => opts,
613617 Err ( e) => {
@@ -656,6 +660,9 @@ fn cmd_prove_continuation(
656660 }
657661
658662 eprintln ! ( "Proof written to {:?}" , output_path) ;
663+ if let Some ( c) = cycle_count {
664+ println ! ( "Cycles: {}" , c) ;
665+ }
659666 println ! ( "Epochs: {}" , bundle. num_epochs( ) ) ;
660667 if time {
661668 println ! ( "Proving time: {:.3}s" , prove_elapsed. as_secs_f64( ) ) ;
@@ -666,7 +673,7 @@ fn cmd_prove_continuation(
666673fn cmd_verify_continuation (
667674 proof_path : PathBuf ,
668675 elf_path : PathBuf ,
669- blowup : Option < u8 > ,
676+ blowup : u8 ,
670677 time : bool ,
671678) -> ExitCode {
672679 eprintln ! ( "Reading ELF file..." ) ;
@@ -694,7 +701,6 @@ fn cmd_verify_continuation(
694701 }
695702 } ;
696703
697- let blowup = blowup. unwrap_or ( 2 ) ;
698704 let opts = match GoldilocksCubicProofOptions :: with_blowup ( blowup) {
699705 Ok ( opts) => opts,
700706 Err ( e) => {
@@ -719,7 +725,7 @@ fn cmd_verify_continuation(
719725 ExitCode :: SUCCESS
720726 }
721727 Ok ( None ) => {
722- eprintln ! ( "Verification failed!" ) ;
728+ eprintln ! ( "Verification failed! Ensure --blowup matches the value used for proving. " ) ;
723729 ExitCode :: FAILURE
724730 }
725731 Err ( e) => {
@@ -819,6 +825,34 @@ mod tests {
819825 assert ! ( r. is_ok( ) ) ;
820826 }
821827
828+ #[ test]
829+ fn cycles_accepts_continuations ( ) {
830+ let r = Cli :: command ( ) . try_get_matches_from ( [
831+ "cli" ,
832+ "prove" ,
833+ "prog.elf" ,
834+ "-o" ,
835+ "out" ,
836+ "--continuations" ,
837+ "--cycles" ,
838+ ] ) ;
839+ assert ! ( r. is_ok( ) ) ;
840+ }
841+
842+ #[ test]
843+ fn elements_conflicts_with_continuations ( ) {
844+ let r = Cli :: command ( ) . try_get_matches_from ( [
845+ "cli" ,
846+ "prove" ,
847+ "prog.elf" ,
848+ "-o" ,
849+ "out" ,
850+ "--continuations" ,
851+ "--elements" ,
852+ ] ) ;
853+ assert ! ( r. is_err( ) ) ;
854+ }
855+
822856 #[ test]
823857 fn epoch_size_log2_rejects_tiny_cli_values ( ) {
824858 let r = Cli :: command ( ) . try_get_matches_from ( [
0 commit comments