From 9fc9c6ef8ae164acaec5dc205e54e3c3508258c7 Mon Sep 17 00:00:00 2001 From: fmoletta <99273364+fmoletta@users.noreply.github.com> Date: Mon, 15 Jan 2024 17:54:25 +0200 Subject: [PATCH] Add `proof_mode` flag to `cairo1-run` (#1537) * Add proof_mode flag to cairo1-run * Add Changelog entry * Clippy * clippy --------- Co-authored-by: Mario Rugiero --- CHANGELOG.md | 4 ++ cairo1-run/src/main.rs | 126 ++++++++++++++++++++++++++++------------- 2 files changed, 92 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddc963ad6e..d17d848d28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ #### Upcoming Changes +* feat: Add `proof_mode` flag to `cairo1-run` [#1537] (https://github.com/lambdaclass/cairo-vm/pull/1537) + * The cairo1-run crate no longer compiles and executes in proof_mode by default + * Add flag `proof_mode` to cairo1-run crate. Activating this flag will enable proof_mode compilation and execution + * dev: bump cairo 1 compiler dep to 2.4 [#1530](https://github.com/lambdaclass/cairo-vm/pull/1530) #### [1.0.0-rc0] - 2024-1-5 diff --git a/cairo1-run/src/main.rs b/cairo1-run/src/main.rs index 0b4056ea7b..1231f7d69c 100644 --- a/cairo1-run/src/main.rs +++ b/cairo1-run/src/main.rs @@ -77,6 +77,8 @@ struct Args { memory_file: Option, #[clap(long = "layout", default_value = "plain", value_parser=validate_layout)] layout: String, + #[clap(long = "proof_mode", value_parser)] + proof_mode: bool, } fn validate_layout(value: &str) -> Result { @@ -201,29 +203,34 @@ fn run(args: impl Iterator) -> Result, Erro &type_sizes, main_func, initial_gas, + args.proof_mode, )?; - println!("Compiling with proof mode and running ..."); - - // This information can be useful for the users using the prover. - println!("Builtins used: {:?}", builtins); - - // Prepare "canonical" proof mode instructions. These are usually added by the compiler in cairo 0 - let mut ctx = casm! {}; - casm_extend! {ctx, - call rel 4; - jmp rel 0; - }; - let proof_mode_header = ctx.instructions; - // Get the user program instructions let program_instructions = casm_program.instructions.iter(); // This footer is used by lib funcs let libfunc_footer = create_code_footer(); - // This is the program we are actually proving - // With embedded proof mode, cairo1 header and the libfunc footer + let proof_mode_header = if args.proof_mode { + println!("Compiling with proof mode and running ..."); + + // This information can be useful for the users using the prover. + println!("Builtins used: {:?}", builtins); + + // Prepare "canonical" proof mode instructions. These are usually added by the compiler in cairo 0 + let mut ctx = casm! {}; + casm_extend! {ctx, + call rel 4; + jmp rel 0; + }; + ctx.instructions + } else { + casm! {}.instructions + }; + + // This is the program we are actually running/proving + // With (embedded proof mode), cairo1 header and the libfunc footer let instructions = chain!( proof_mode_header.iter(), entry_code.iter(), @@ -243,36 +250,59 @@ fn run(args: impl Iterator) -> Result, Erro let data_len = data.len(); - let starting_pc = 0; - - let program = Program::new_for_proof( - builtins, - data, - starting_pc, - // Proof mode is on top - // jmp rel 0 is on PC == 2 - 2, - program_hints, - ReferenceManager { - references: Vec::new(), - }, - HashMap::new(), - vec![], - None, - )?; + let program = if args.proof_mode { + Program::new_for_proof( + builtins, + data, + 0, + // Proof mode is on top + // jmp rel 0 is on PC == 2 + 2, + program_hints, + ReferenceManager { + references: Vec::new(), + }, + HashMap::new(), + vec![], + None, + )? + } else { + Program::new( + builtins, + data, + Some(0), + program_hints, + ReferenceManager { + references: Vec::new(), + }, + HashMap::new(), + vec![], + None, + )? + }; - let mut runner = CairoRunner::new_v2(&program, &args.layout, RunnerMode::ProofModeCairo1)?; + let runner_mode = if args.proof_mode { + RunnerMode::ProofModeCairo1 + } else { + RunnerMode::ExecutionMode + }; + + let mut runner = CairoRunner::new_v2(&program, &args.layout, runner_mode)?; let mut vm = VirtualMachine::new(args.trace_file.is_some()); let end = runner.initialize(&mut vm)?; additional_initialization(&mut vm, data_len)?; - // Run it until the infinite loop + // Run it until the end/ infinite loop in proof_mode runner.run_until_pc(end, &mut vm, &mut hint_processor)?; - // Then pad it to the power of 2 - runner.run_until_next_power_of_2(&mut vm, &mut hint_processor)?; + if args.proof_mode { + // Then pad it to the power of 2 + runner.run_until_next_power_of_2(&mut vm, &mut hint_processor)?; + } else { + runner.end_run(true, false, &mut vm, &mut hint_processor)?; + } // Fetch return type data let return_type_id = main_func @@ -464,6 +494,7 @@ fn create_entry_code( type_sizes: &UnorderedHashMap, func: &Function, initial_gas: usize, + proof_mode: bool, ) -> Result<(Vec, Vec), Error> { let mut ctx = casm! {}; // The builtins in the formatting expected by the runner. @@ -496,8 +527,11 @@ fn create_entry_code( let ty_size = type_sizes[ty]; let generic_ty = &info.long_id.generic_id; if let Some(offset) = builtin_offset.get(generic_ty) { - // Everything is off by 2 due to the proof mode header - let offset = offset + 2; + let mut offset = *offset; + if proof_mode { + // Everything is off by 2 due to the proof mode header + offset += 2; + } casm_extend! {ctx, [ap + 0] = [fp - offset], ap++; } @@ -660,6 +694,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/fibonacci.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/fibonacci.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_fibonacci_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(89)]); @@ -667,6 +702,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/factorial.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/factorial.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_factorial_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(3628800)]); @@ -674,6 +710,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/array_get.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/array_get.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_array_get_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(3)]); @@ -681,6 +718,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/enum_flow.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/enum_flow.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_enum_flow_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(300)]); @@ -688,6 +726,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/enum_match.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/enum_match.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_enum_match_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(10), MaybeRelocatable::from(felt_str("3618502788666131213697322783095070105623107215331596699973092056135872020471"))]); @@ -695,6 +734,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/hello.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/hello.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_hello_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(1), MaybeRelocatable::from(1234)]); @@ -702,6 +742,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/ops.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/ops.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_ops_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(6)]); @@ -709,6 +750,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/print.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/print.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_print_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![]); @@ -716,6 +758,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/recursion.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/recursion.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_recursion_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(felt_str("1154076154663935037074198317650845438095734251249125412074882362667803016453"))]); @@ -723,6 +766,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/sample.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/sample.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_sample_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(felt_str("5050"))]); @@ -730,6 +774,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/poseidon.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/poseidon.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_poseidon_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(felt_str("1099385018355113290651252669115094675591288647745213771718157553170111442461"))]); @@ -737,6 +782,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/poseidon_pedersen.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/poseidon_pedersen.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_poseidon_pedersen_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(felt_str("1036257840396636296853154602823055519264738423488122322497453114874087006398"))]); @@ -744,6 +790,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/pedersen_example.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/pedersen_example.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_pedersen_example_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(felt_str("1089549915800264549621536909767699778745926517555586332772759280702396009108"))]); @@ -751,6 +798,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/simple.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/simple.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_simple_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(1)]); @@ -758,6 +806,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/simple_struct.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/simple_struct.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_simple_struct_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(100)]); @@ -765,6 +814,7 @@ mod tests { #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/dictionaries.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/dictionaries.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode"].as_slice())] fn test_run_dictionaries(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(1024)]);