Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add air_public_input flag to cairo1-run #1539

Merged
merged 21 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#### Upcoming Changes

* feat: Add `air_public_input` flag to `cairo1-run` [#1539] (https://github.com/lambdaclass/cairo-vm/pull/1539)

* feat: Implement air_private_input [#1552](https://github.com/lambdaclass/cairo-vm/pull/1552)

* feat: Add `proof_mode` flag to `cairo1-run` [#1537] (https://github.com/lambdaclass/cairo-vm/pull/1537)
Expand Down
106 changes: 82 additions & 24 deletions cairo1-run/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
use cairo_vm::vm::errors::runner_errors::RunnerError;
use cairo_vm::vm::errors::trace_errors::TraceError;
use cairo_vm::vm::errors::vm_errors::VirtualMachineError;
use cairo_vm::vm::runners::builtin_runner::{
BITWISE_BUILTIN_NAME, EC_OP_BUILTIN_NAME, HASH_BUILTIN_NAME, OUTPUT_BUILTIN_NAME,
POSEIDON_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME, SIGNATURE_BUILTIN_NAME,
};
use cairo_vm::vm::runners::cairo_runner::RunnerMode;
use cairo_vm::{
serde::deserialize_program::ReferenceManager,
Expand Down Expand Up @@ -79,6 +83,8 @@
layout: String,
#[clap(long = "proof_mode", value_parser)]
proof_mode: bool,
#[clap(long = "air_public_input", value_parser)]
air_public_input: Option<PathBuf>,
}

fn validate_layout(value: &str) -> Result<String, String> {
Expand Down Expand Up @@ -173,6 +179,13 @@

fn run(args: impl Iterator<Item = String>) -> Result<Vec<MaybeRelocatable>, Error> {
let args = Args::try_parse_from(args)?;
if args.air_public_input.is_some() && !args.proof_mode {
let error = Args::command().error(
clap::error::ErrorKind::ArgumentConflict,
"--air_public_input can only be used in proof_mode.",
);
return Err(Error::Cli(error));

Check warning on line 187 in cairo1-run/src/main.rs

View check run for this annotation

Codecov / codecov/patch

cairo1-run/src/main.rs#L183-L187

Added lines #L183 - L187 were not covered by tests
}

let compiler_config = CompilerConfig {
replace_ids: true,
Expand Down Expand Up @@ -289,20 +302,14 @@

let mut runner = CairoRunner::new_v2(&program, &args.layout, runner_mode)?;

let mut vm = VirtualMachine::new(args.trace_file.is_some());
let mut vm = VirtualMachine::new(args.trace_file.is_some() || args.air_public_input.is_some());
let end = runner.initialize(&mut vm)?;

additional_initialization(&mut vm, data_len)?;

// Run it until the end/ infinite loop in proof_mode
runner.run_until_pc(end, &mut vm, &mut hint_processor)?;

if args.proof_mode {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you remove this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous code called runner.run_until_next_power_of_2(&mut vm, &mut hint_processor) if proof_mode was activated. This same function is called in the end_run method if proof_mode is activated

// 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)?;
}
runner.end_run(false, false, &mut vm, &mut hint_processor)?;

// Fetch return type data
let return_type_id = main_func
Expand Down Expand Up @@ -351,8 +358,59 @@
}
}

// Set stop pointers for builtins so we can obtain the air public input
if args.air_public_input.is_some() {
// Cairo 1 programs have other return values aside from the used builtin's final pointers, so we need to hand-pick them
let ret_types_sizes = main_func
.signature
.ret_types
.iter()
.map(|id| type_sizes.get(id).cloned().unwrap_or_default());
let ret_types_and_sizes = main_func
.signature
.ret_types
.iter()
.zip(ret_types_sizes.clone());

let full_ret_types_size: i16 = ret_types_sizes.sum();
let mut stack_pointer = (vm.get_ap() - (full_ret_types_size as usize).saturating_sub(1))
.map_err(VirtualMachineError::Math)?;

// Calculate the stack_ptr for each return builtin in the return values
let mut builtin_name_to_stack_pointer = HashMap::new();
for (id, size) in ret_types_and_sizes {
if let Some(ref name) = id.debug_name {
let builtin_name = match &*name.to_string() {
"RangeCheck" => RANGE_CHECK_BUILTIN_NAME,
"Poseidon" => POSEIDON_BUILTIN_NAME,
"EcOp" => EC_OP_BUILTIN_NAME,
"Bitwise" => BITWISE_BUILTIN_NAME,
"Pedersen" => HASH_BUILTIN_NAME,
"Output" => OUTPUT_BUILTIN_NAME,
"Ecdsa" => SIGNATURE_BUILTIN_NAME,
_ => {
stack_pointer.offset += size as usize;
continue;
}
};
builtin_name_to_stack_pointer.insert(builtin_name, stack_pointer);
}

Check warning on line 397 in cairo1-run/src/main.rs

View check run for this annotation

Codecov / codecov/patch

cairo1-run/src/main.rs#L397

Added line #L397 was not covered by tests
stack_pointer.offset += size as usize;
}
// Set stop pointer for each builtin
vm.builtins_final_stack_from_stack_pointer_dict(&builtin_name_to_stack_pointer)?;

// Build execution public memory
runner.finalize_segments(&mut vm)?;
}

runner.relocate(&mut vm, true)?;

if let Some(file_path) = args.air_public_input {
let json = runner.get_air_public_input(&vm)?.serialize_json()?;
std::fs::write(file_path, json)?;
}

if let Some(trace_path) = args.trace_file {
let relocated_trace = runner
.relocated_trace
Expand Down Expand Up @@ -694,127 +752,127 @@

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/fibonacci.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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)]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/factorial.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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)]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/array_get.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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)]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/enum_flow.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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)]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/enum_match.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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"))]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/hello.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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)]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/ops.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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)]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/print.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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![]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/recursion.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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"))]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/sample.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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"))]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/poseidon.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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"))]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/poseidon_pedersen.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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"))]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/pedersen_example.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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"))]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/simple.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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)]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/simple_struct.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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)]);
}

#[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())]
#[case(["cairo1-run", "../cairo_programs/cairo-1-programs/dictionaries.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null"].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)]);
Expand Down
4 changes: 3 additions & 1 deletion vm/src/types/relocatable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ use serde::{Deserialize, Serialize};
use arbitrary::Arbitrary;

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Eq, Ord, Hash, PartialEq, PartialOrd, Clone, Copy, Debug, Serialize, Deserialize)]
#[derive(
Eq, Ord, Hash, PartialEq, PartialOrd, Clone, Copy, Debug, Serialize, Deserialize, Default,
)]
pub struct Relocatable {
pub segment_index: isize,
pub offset: usize,
Expand Down
17 changes: 17 additions & 0 deletions vm/src/vm/vm_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,23 @@ impl VirtualMachine {
})
.collect()
}

#[doc(hidden)]
pub fn builtins_final_stack_from_stack_pointer_dict(
&mut self,
builtin_name_to_stack_pointer: &HashMap<&'static str, Relocatable>,
) -> Result<(), RunnerError> {
for builtin in self.builtin_runners.iter_mut() {
builtin.final_stack(
&self.segments,
builtin_name_to_stack_pointer
.get(builtin.name())
.cloned()
.unwrap_or_default(),
)?;
}
Ok(())
}
}

pub struct VirtualMachineBuilder {
Expand Down
Loading