diff --git a/Cargo.toml b/Cargo.toml index 86d7f21a..8df4205d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ resolver = "2" [workspace.dependencies] anyhow = "1.0.98" bincode = { version = "2.0.1", features = ["serde"] } -cairo-air = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "6b45dd698a31d76c43f1e400cdb7ed8c23f97157" } +cairo-air = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "566f5a78a83a32f51a20c32f70027791be9d3693" } cairo-lang-executable = "=2.14.1-dev.0" cairo-lang-runner = "=2.14.1-dev.0" cairo-lang-casm = "=2.14.1-dev.0" @@ -34,10 +34,10 @@ sonic-rs = "0.3.17" starknet-crypto = "=0.8.1" starknet-ff = "0.3.7" starknet-types-core = "=0.2.4" -stwo_cairo_utils = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "6b45dd698a31d76c43f1e400cdb7ed8c23f97157" } -stwo-cairo-adapter = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "6b45dd698a31d76c43f1e400cdb7ed8c23f97157" } -stwo_cairo_prover = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "6b45dd698a31d76c43f1e400cdb7ed8c23f97157" } -stwo-cairo-serialize = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "6b45dd698a31d76c43f1e400cdb7ed8c23f97157" } +stwo_cairo_utils = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "566f5a78a83a32f51a20c32f70027791be9d3693" } +stwo-cairo-adapter = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "566f5a78a83a32f51a20c32f70027791be9d3693" } +stwo_cairo_prover = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "566f5a78a83a32f51a20c32f70027791be9d3693" } +stwo-cairo-serialize = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "566f5a78a83a32f51a20c32f70027791be9d3693" } tempfile = "3.10.1" thiserror = "1.0.61" thiserror-no-std = "2.0.2" diff --git a/crates/stwo_run_and_prove/Cargo.toml b/crates/stwo_run_and_prove/Cargo.toml index 73a243d8..22dc597a 100644 --- a/crates/stwo_run_and_prove/Cargo.toml +++ b/crates/stwo_run_and_prove/Cargo.toml @@ -12,6 +12,7 @@ clap.workspace = true env_logger.workspace = true log.workspace = true serde.workspace = true +serde_json.workspace = true sonic-rs.workspace = true starknet-ff.workspace = true stwo_cairo_prover.workspace = true diff --git a/crates/stwo_run_and_prove/resources/array_sum_proof b/crates/stwo_run_and_prove/resources/expected_array_sum_proof similarity index 100% rename from crates/stwo_run_and_prove/resources/array_sum_proof rename to crates/stwo_run_and_prove/resources/expected_array_sum_proof diff --git a/crates/stwo_run_and_prove/resources/expected_prover_input.json b/crates/stwo_run_and_prove/resources/expected_prover_input.json new file mode 100644 index 00000000..a4b71f0a --- /dev/null +++ b/crates/stwo_run_and_prove/resources/expected_prover_input.json @@ -0,0 +1,674 @@ +{ + "state_transitions": { + "initial_state": { + "pc": 1, + "ap": 61, + "fp": 61 + }, + "final_state": { + "pc": 5, + "ap": 118, + "fp": 61 + }, + "casm_states_by_opcode": { + "generic_opcode": [], + "add_ap_opcode": [ + { + "pc": 1, + "ap": 61, + "fp": 61 + }, + { + "pc": 7, + "ap": 76, + "fp": 76 + } + ], + "add_opcode": [], + "add_opcode_small": [ + { + "pc": 19, + "ap": 84, + "fp": 84 + }, + { + "pc": 21, + "ap": 85, + "fp": 84 + }, + { + "pc": 19, + "ap": 88, + "fp": 88 + }, + { + "pc": 21, + "ap": 89, + "fp": 88 + }, + { + "pc": 19, + "ap": 92, + "fp": 92 + }, + { + "pc": 21, + "ap": 93, + "fp": 92 + }, + { + "pc": 26, + "ap": 98, + "fp": 92 + }, + { + "pc": 26, + "ap": 100, + "fp": 88 + }, + { + "pc": 26, + "ap": 102, + "fp": 84 + }, + { + "pc": 11, + "ap": 107, + "fp": 107 + } + ], + "assert_eq_opcode": [ + { + "pc": 39, + "ap": 80, + "fp": 74 + }, + { + "pc": 44, + "ap": 103, + "fp": 74 + }, + { + "pc": 45, + "ap": 104, + "fp": 74 + }, + { + "pc": 48, + "ap": 108, + "fp": 74 + }, + { + "pc": 49, + "ap": 109, + "fp": 74 + }, + { + "pc": 50, + "ap": 110, + "fp": 74 + }, + { + "pc": 51, + "ap": 111, + "fp": 74 + }, + { + "pc": 52, + "ap": 112, + "fp": 74 + }, + { + "pc": 53, + "ap": 113, + "fp": 74 + }, + { + "pc": 54, + "ap": 114, + "fp": 74 + }, + { + "pc": 55, + "ap": 115, + "fp": 74 + }, + { + "pc": 56, + "ap": 116, + "fp": 74 + }, + { + "pc": 57, + "ap": 117, + "fp": 74 + } + ], + "assert_eq_opcode_double_deref": [ + { + "pc": 32, + "ap": 78, + "fp": 74 + }, + { + "pc": 35, + "ap": 79, + "fp": 74 + }, + { + "pc": 38, + "ap": 80, + "fp": 74 + }, + { + "pc": 25, + "ap": 97, + "fp": 92 + }, + { + "pc": 25, + "ap": 99, + "fp": 88 + }, + { + "pc": 25, + "ap": 101, + "fp": 84 + }, + { + "pc": 10, + "ap": 107, + "fp": 107 + } + ], + "assert_eq_opcode_imm": [ + { + "pc": 30, + "ap": 77, + "fp": 74 + }, + { + "pc": 33, + "ap": 78, + "fp": 74 + }, + { + "pc": 36, + "ap": 79, + "fp": 74 + }, + { + "pc": 40, + "ap": 81, + "fp": 74 + }, + { + "pc": 16, + "ap": 96, + "fp": 96 + } + ], + "call_opcode_abs": [], + "call_opcode_rel_imm": [ + { + "pc": 3, + "ap": 72, + "fp": 61 + }, + { + "pc": 28, + "ap": 74, + "fp": 74 + }, + { + "pc": 42, + "ap": 82, + "fp": 74 + }, + { + "pc": 23, + "ap": 86, + "fp": 84 + }, + { + "pc": 23, + "ap": 90, + "fp": 88 + }, + { + "pc": 23, + "ap": 94, + "fp": 92 + }, + { + "pc": 46, + "ap": 105, + "fp": 74 + } + ], + "jnz_opcode_non_taken": [ + { + "pc": 14, + "ap": 96, + "fp": 96 + } + ], + "jnz_opcode_taken": [ + { + "pc": 14, + "ap": 84, + "fp": 84 + }, + { + "pc": 14, + "ap": 88, + "fp": 88 + }, + { + "pc": 14, + "ap": 92, + "fp": 92 + } + ], + "jump_opcode_rel_imm": [], + "jump_opcode_rel": [], + "jump_opcode_double_deref": [], + "jump_opcode_abs": [], + "mul_opcode_small": [], + "mul_opcode": [], + "ret_opcode": [ + { + "pc": 9, + "ap": 77, + "fp": 76 + }, + { + "pc": 18, + "ap": 97, + "fp": 96 + }, + { + "pc": 27, + "ap": 99, + "fp": 92 + }, + { + "pc": 27, + "ap": 101, + "fp": 88 + }, + { + "pc": 27, + "ap": 103, + "fp": 84 + }, + { + "pc": 13, + "ap": 108, + "fp": 107 + }, + { + "pc": 58, + "ap": 118, + "fp": 74 + } + ], + "blake_compress_opcode": [], + "qm_31_add_mul_opcode": [] + } + }, + "memory": { + "config": { + "small_max": 4722366482869645213695, + "log_small_value_capacity": 24 + }, + "address_to_id": [ + 1073741823, + 0, + 1, + 2, + 3, + 4, + 5, + 0, + 6, + 7, + 8, + 9, + 6, + 7, + 10, + 11, + 12, + 5, + 7, + 9, + 6, + 13, + 1073741824, + 2, + 1073741825, + 14, + 15, + 7, + 2, + 1073741826, + 12, + 16, + 17, + 12, + 18, + 19, + 12, + 3, + 20, + 21, + 12, + 22, + 2, + 1073741827, + 23, + 24, + 2, + 1073741828, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 7, + 35, + 5, + 36, + 37, + 37, + 5, + 37, + 5, + 5, + 37, + 37, + 37, + 37, + 35, + 11, + 38, + 39, + 40, + 16, + 18, + 3, + 40, + 22, + 38, + 41, + 42, + 43, + 44, + 3, + 45, + 6, + 46, + 3, + 47, + 5, + 48, + 3, + 5, + 3, + 3, + 18, + 49, + 16, + 50, + 36, + 50, + 38, + 51, + 37, + 37, + 37, + 5, + 37, + 5, + 5, + 37, + 37, + 37, + 37, + 50, + 5, + 5, + 5, + 5, + 16, + 18, + 3 + ], + "f252_values": [ + [ + 0, + 0, + 0, + 0, + 0, + 0, + 17, + 134217728 + ], + [ + 4294967288, + 4294967295, + 4294967295, + 4294967295, + 4294967295, + 4294967295, + 16, + 134217728 + ], + [ + 4294967276, + 4294967295, + 4294967295, + 4294967295, + 4294967295, + 4294967295, + 16, + 134217728 + ], + [ + 4294967269, + 4294967295, + 4294967295, + 4294967295, + 4294967295, + 4294967295, + 16, + 134217728 + ], + [ + 4294967261, + 4294967295, + 4294967295, + 4294967295, + 4294967295, + 4294967295, + 16, + 134217728 + ] + ], + "small_values": [ + 290341444919459839, + 11, + 1226245742482522112, + 25, + 74168662805676031, + 0, + 1, + 2345108766317314046, + 4612671182993129469, + 5198983563776393216, + 146226256843603965, + 5, + 5189976364521848832, + 5198983563776458752, + 5188850460319842304, + 5201798300658794496, + 9, + 4611826758063128575, + 16, + 4611826762358030335, + 4611826766652932095, + 5193354042767540224, + 3, + 5191102204299149312, + 5193354051357474816, + 5191102208594116608, + 5191102212889083904, + 5191102217184051200, + 5191102221479018496, + 5191102225773985792, + 5191102230068953088, + 5191102234363920384, + 5191102238658887680, + 5191102242953854976, + 5191102247248822272, + 61, + 118, + 119, + 74, + 30, + 123, + 44, + 124, + 2, + 84, + 125, + 88, + 126, + 92, + 41, + 50, + 48 + ] + }, + "pc_count": 40, + "public_memory_addresses": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118 + ], + "builtin_segments": { + "add_mod": null, + "bitwise": null, + "output": { + "begin_addr": 118, + "stop_ptr": 119 + }, + "mul_mod": null, + "pedersen": null, + "poseidon": null, + "range_check_bits_96": null, + "range_check_bits_128": null + }, + "public_segment_context": { + "present": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ] + } +} \ No newline at end of file diff --git a/crates/stwo_run_and_prove/src/main.rs b/crates/stwo_run_and_prove/src/main.rs index bbdd17b2..d6f980e7 100644 --- a/crates/stwo_run_and_prove/src/main.rs +++ b/crates/stwo_run_and_prove/src/main.rs @@ -20,12 +20,12 @@ use std::process::ExitCode; use stwo_cairo_adapter::ProverInput; use stwo_cairo_adapter::adapter::adapt; use stwo_cairo_prover::prover::create_and_serialize_proof; -use stwo_cairo_prover::stwo::prover::ProvingError; use stwo_cairo_utils::binary_utils::run_binary; -use stwo_cairo_utils::file_utils::IoErrorWithPath; use thiserror::Error; use tracing::{Level, error, info, span}; +static PROVER_INPUT_FILE_NAME: &str = "prover_input.json"; + /// This binary runs a cairo program and generates a Stwo proof for it. #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] @@ -56,35 +56,36 @@ struct Args { help = "Optional absolute path for the program output." )] program_output: Option, + #[clap( + long = "save_debug_data", + help = "Should save the ProverInput to a file in `debug_data_dir` for both success and failure." + )] + save_debug_data: bool, + #[clap( + long = "debug_data_dir", + help = "Absolute path to the output directory where the ProverInput will be saved in the + case of a proving error, or when the save_debug_data flag is enabled." + )] + debug_data_dir: Option, } #[derive(Debug, Error)] enum StwoRunAndProveError { #[error(transparent)] Cli(#[from] clap::Error), - #[error("IO error on file '{path:?}': {source}")] - PathIO { - path: PathBuf, - source: std::io::Error, - }, + #[error("IO error on file '{1:?}': {0}")] + PathIO(std::io::Error, PathBuf), #[error(transparent)] IO(#[from] std::io::Error), #[error(transparent)] CairoRun(Box), - #[error("Program error on file '{path:?}': {source}")] - Program { path: PathBuf, source: ProgramError }, + #[error("Program error on file '{1:?}': {0}")] + Program(ProgramError, PathBuf), #[error(transparent)] Runner(#[from] RunnerError), - #[error("File error on file '{path:?}': {source}")] - File { - path: PathBuf, - source: IoErrorWithPath, - }, #[error(transparent)] Serializing(#[from] sonic_rs::error::Error), #[error(transparent)] - Proving(#[from] ProvingError), - #[error(transparent)] VM(#[from] VirtualMachineError), #[error("Failed to parse output line as Felt decimal.")] OutputParsing, @@ -92,31 +93,13 @@ enum StwoRunAndProveError { Anyhow(#[from] anyhow::Error), } -// Implement From> manually +// Implement From> manually. impl From for StwoRunAndProveError { fn from(err: CairoRunError) -> Self { StwoRunAndProveError::CairoRun(Box::new(err)) } } -impl From<(std::io::Error, PathBuf)> for StwoRunAndProveError { - fn from((source, path): (std::io::Error, PathBuf)) -> Self { - StwoRunAndProveError::PathIO { path, source } - } -} - -impl From<(ProgramError, PathBuf)> for StwoRunAndProveError { - fn from((source, path): (ProgramError, PathBuf)) -> Self { - StwoRunAndProveError::Program { path, source } - } -} - -impl From<(IoErrorWithPath, PathBuf)> for StwoRunAndProveError { - fn from((source, path): (IoErrorWithPath, PathBuf)) -> Self { - StwoRunAndProveError::File { path, source } - } -} - struct ProveConfig { proof_path: PathBuf, proof_format: ProofFormat, @@ -145,18 +128,24 @@ fn run() -> Result<(), StwoRunAndProveError> { args.program_output, prove_config, stwo_prover, + args.debug_data_dir, + args.save_debug_data, )?; Ok(()) } /// Runs the program and generates a proof for it, then saves the proof to the given path. -/// If `program_output` is provided, saves the program output to that path. +/// If `debug_data_dir` is provided, and there is a proving error or the `save_debug_data` flag is +/// enabled, saves the debug data to that path. +/// If `program_output` is provided, the program output to that path. fn stwo_run_and_prove( program_path: PathBuf, program_input: Option, program_output: Option, prove_config: ProveConfig, prover: Box, + debug_data_dir: Option, + save_debug_data: bool, ) -> Result<(), StwoRunAndProveError> { let cairo_run_config = get_cairo_run_config( // we don't use dynamic layout in stwo @@ -174,17 +163,33 @@ fn stwo_run_and_prove( )?; let program = get_program(program_path.as_path()) - .map_err(|e| StwoRunAndProveError::from((e, program_path)))?; + .map_err(|e| StwoRunAndProveError::Program(e, program_path))?; let program_input = get_program_input(&program_input) - .map_err(|e| StwoRunAndProveError::from((e, program_input.unwrap_or_default())))?; + .map_err(|e| StwoRunAndProveError::PathIO(e, program_input.unwrap_or_default()))?; let runner = cairo_run_program(&program, program_input, cairo_run_config)?; let prover_input = adapt(&runner)?; - prove(prover_input, prove_config, prover)?; - if let Some(output_path) = program_output { + let result = prove(prover_input.clone(), prove_config, prover); + + if let Some(data_dir) = debug_data_dir + && (result.is_err() || save_debug_data) + { + // create the directory if it doesn't exist. + std::fs::create_dir_all(&data_dir)?; + let prover_input_path = data_dir.join(PROVER_INPUT_FILE_NAME); + std::fs::write( + &prover_input_path, + sonic_rs::to_string_pretty(&prover_input)?, + ) + .map_err(|e| StwoRunAndProveError::PathIO(e, data_dir))? + } + + if let Some(output_path) = program_output + && result.is_ok() + { write_output_to_file(runner, output_path)?; } - Ok(()) + result } /// Prepares the prover parameters and generates a proof given the prover input and parameters. @@ -209,7 +214,7 @@ fn prove( } Err(e) => { - if is_file_missing_or_empty(&prove_config.proof_path)? { + if file_missing_or_empty(&prove_config.proof_path)? { error!("Proving failed with error {e}"); } else { error!( @@ -274,35 +279,40 @@ fn write_output_to_file( }) .collect::, _>>()?; std::fs::write(&output_path, sonic_rs::to_string_pretty(&output_lines)?) - .map_err(|e| StwoRunAndProveError::from((e, output_path)))?; + .map_err(|e| StwoRunAndProveError::PathIO(e, output_path))?; Ok(()) } -fn is_file_empty(path: &PathBuf) -> std::io::Result { +fn file_empty(path: &PathBuf) -> std::io::Result { let metadata = fs::metadata(path)?; Ok(metadata.len() == 0) } -fn is_file_missing_or_empty(path: &PathBuf) -> std::io::Result { - match std::fs::metadata(path) { - Ok(_) => is_file_empty(path), - Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(true), - Err(e) => Err(e), +fn file_exists(path: &PathBuf) -> bool { + std::fs::metadata(path).is_ok() +} + +fn file_missing_or_empty(path: &PathBuf) -> std::io::Result { + if !file_exists(path) { + return Ok(true); } + file_empty(path) } #[cfg(test)] mod tests { use super::*; use ctor::ctor; + use serde_json::Value; use stwo_cairo_utils::logging_utils::init_logging; - use tempfile::{NamedTempFile, TempPath}; + use tempfile::{NamedTempFile, TempDir, TempPath}; const ARRAY_SUM_EXPECTED_OUTPUT: [Felt252; 1] = [Felt252::from_hex_unchecked("0x32")]; const RESOURCES_PATH: &str = "resources"; const PROGRAM_FILE_NAME: &str = "array_sum.json"; const PROVER_PARAMS_FILE_NAME: &str = "prover_params.json"; - const EXPECTED_PROOF_FILE_NAME: &str = "array_sum_proof"; + const EXPECTED_PROOF_FILE_NAME: &str = "expected_array_sum_proof"; + const EXPECTED_PROVER_INPUT_FILE_NAME: &str = "expected_prover_input.json"; #[ctor] fn init_logging_once() { @@ -314,13 +324,15 @@ mod tests { current_path.join(RESOURCES_PATH).join(file_name) } - fn prepare_args() -> (Args, TempPath, TempPath) { + fn prepare_args() -> (Args, TempPath, TempPath, TempDir) { let program_output_tempfile = NamedTempFile::new() .expect("Failed to create temp file for program output") .into_temp_path(); let proof_tempfile = NamedTempFile::new() .expect("Failed to create temp file for proof") .into_temp_path(); + let debug_data_tempdir = + TempDir::new().expect("Failed to create temp directory for debug data"); let args = Args { program: get_path(PROGRAM_FILE_NAME), program_input: None, @@ -328,10 +340,17 @@ mod tests { prover_params_json: Some(get_path(PROVER_PARAMS_FILE_NAME)), proof_path: proof_tempfile.to_path_buf(), proof_format: ProofFormat::CairoSerde, + save_debug_data: false, + debug_data_dir: Some(debug_data_tempdir.path().to_path_buf()), verify: true, }; - (args, program_output_tempfile, proof_tempfile) + ( + args, + program_output_tempfile, + proof_tempfile, + debug_data_tempdir, + ) } fn run_stwo_run_and_prove( @@ -351,11 +370,13 @@ mod tests { args.program_output, prove_config, prover, + args.debug_data_dir, + args.save_debug_data, ) } fn run_with_successful_mock_prover() -> (TempPath, TempPath) { - let (args, program_output_tempfile, proof_tempfile) = prepare_args(); + let (args, program_output_tempfile, proof_tempfile, _) = prepare_args(); let mut mock_prover = Box::new(MockProverTrait::new()); mock_prover @@ -372,8 +393,8 @@ mod tests { (program_output_tempfile, proof_tempfile) } - fn run_with_failed_mock_prover() -> (TempPath, TempPath) { - let (args, program_output_tempfile, proof_tempfile) = prepare_args(); + fn run_with_failed_mock_prover() -> (TempPath, TempPath, TempDir) { + let (args, program_output_tempfile, proof_tempfile, debug_data_tempdir) = prepare_args(); let mut mock_prover = Box::new(MockProverTrait::new()); mock_prover @@ -391,7 +412,27 @@ mod tests { "run and prove should return Err(StwoRunAndProveError::Anyhow), but got: {result:?}", ); - (program_output_tempfile, proof_tempfile) + (program_output_tempfile, proof_tempfile, debug_data_tempdir) + } + + /// Sort the public_memory_addresses array in the Json, since its order is not deterministic. + fn normalize_public_memory_addresses(value: &mut Value) { + if let Value::Object(map) = value + && let Some(Value::Array(arr)) = map.get_mut("public_memory_addresses") + { + assert!(arr.iter().all(|v| v.is_number())); + arr.sort_by_key(|v| v.as_u64().unwrap()); + } + } + + /// Reads the JSON content from the given file path and normalizes it. + fn get_json_normalized_content(file_path: &PathBuf, file_name: &str) -> serde_json::Value { + let content = std::fs::read(file_path) + .unwrap_or_else(|e| panic!("Failed to read {file_name:?} file: {e}")); + let mut json: serde_json::Value = + serde_json::from_slice(&content).expect("Failed to parse prover input JSON"); + normalize_public_memory_addresses(&mut json); + json } #[test] @@ -422,15 +463,36 @@ mod tests { #[test] fn test_stwo_run_and_prove_proving_failure() { - let (output_tempfile, proof_tempfile) = run_with_failed_mock_prover(); + let (output_tempfile, proof_tempfile, debug_data_tempdir) = run_with_failed_mock_prover(); assert!( - is_file_empty(&proof_tempfile.to_path_buf()).unwrap(), + file_empty(&proof_tempfile.to_path_buf()).unwrap(), "proof file should be empty after running with proving failure", ); assert!( - is_file_empty(&output_tempfile.to_path_buf()).unwrap(), + file_empty(&output_tempfile.to_path_buf()).unwrap(), "Output file should be empty after running with proving failure", ); + assert!( + file_exists(&debug_data_tempdir.path().join(PROVER_INPUT_FILE_NAME)), + "Prover input file was not created in the debug data directory, or was created with an + incorrect name, after running with a proving failure. NOTE: Changing the file name may + break external dependencies.", + ); + + // Verifying the prover input content. + let prover_input_json = get_json_normalized_content( + &debug_data_tempdir.path().join(PROVER_INPUT_FILE_NAME), + PROVER_INPUT_FILE_NAME, + ); + let expected_prover_input_json = get_json_normalized_content( + &get_path(EXPECTED_PROVER_INPUT_FILE_NAME), + EXPECTED_PROVER_INPUT_FILE_NAME, + ); + + assert_eq!( + prover_input_json, expected_prover_input_json, + "Prover input JSON does not match expected prover input JSON." + ); } }