Skip to content

Commit

Permalink
Implement CairoRunner.get_cairo_pie (#1375)
Browse files Browse the repository at this point in the history
* Add skeletons

* Move func + progress

* Add CairoPieMetadata

* Improve stripped program representation

* Use stripped program in cairo pie

* Add Pie representation of memory

* Add execution resources

* Add BuiltinAdditionalInfo struct

* Add get_additional_info for output & signature

* Add get_additional info for hash builtin

* Add get_additional_data for builtin enum + rename

* Add additional_data to pie

* Fixex

* fmt

* Clippy + remove unused impl

* Fix hash additional data format

* Fix logic

* Fix hash additional data

* Add wip test

* Use struct for SegmentInfo

* Strip _builtin suffix

* Complete test

* Undo change

* Add test

* Add test

* Add test

* Derive relevant traits for public structures

* Add tests

* More tests

* Add tests

* Add test

* Add changelog entry

* Add tests

* Add tests

* Fix imports

* Fix imports

* Add wasm imports

---------

Co-authored-by: Pedro Fontana <[email protected]>
  • Loading branch information
fmoletta and pefontana authored Aug 22, 2023
1 parent 6828b6a commit 2d214f7
Show file tree
Hide file tree
Showing 14 changed files with 812 additions and 5 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#### Upcoming Changes

#### [0.8.6] - 2023-8-11
* feat: Implement `CairoRunner.get_cairo_pie`[#1375](https://github.com/lambdaclass/cairo-vm/pull/1375/files)

* fix: Fix `SPLIT_FELT` hint [#1387](https://github.com/lambdaclass/cairo-vm/pull/1387)

Expand All @@ -12,6 +12,8 @@
* Various functions in the `math_utils` crate can now return a `MathError` : `div_mod`, `ec_add`, `line_slope`, `ec_double`, `ec_double_slope`.
* Fixes `UINT256_MUL_INV_MOD_P` hint so that it behaves like the python code.

#### [0.8.6] - 2023-8-11

* fix: Handle error in hint `UINT256_MUL_DIV_MOD` when divides by zero [#1367](https://github.com/lambdaclass/cairo-vm/pull/1367)

* Add HintError::SyscallError and VmErrors::HINT_ERROR_STR constant [#1357](https://github.com/lambdaclass/cairo-rs/pull/1357)
Expand Down
247 changes: 247 additions & 0 deletions vm/src/tests/get_cairo_pie_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
use crate::stdlib::{collections::HashMap, prelude::*};

use felt::felt_str;

#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*;

#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::{
string::{String, ToString},
vec::Vec,
};

use crate::{
cairo_run::{cairo_run, CairoRunConfig},
hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor,
types::relocatable::Relocatable,
vm::runners::{
builtin_runner::{
HASH_BUILTIN_NAME, OUTPUT_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME,
SIGNATURE_BUILTIN_NAME,
},
cairo_pie::{
BuiltinAdditionalData, CairoPieMemory, OutputBuiltinAdditionalData, SegmentInfo,
},
cairo_runner::ExecutionResources,
},
};

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn pedersen_test() {
// Run the program
let program_content = include_bytes!("../../../cairo_programs/pedersen_test.json");
let mut hint_processor = BuiltinHintProcessor::new_empty();
let result = cairo_run(
program_content,
&CairoRunConfig {
layout: "all_cairo",
..Default::default()
},
&mut hint_processor,
);
assert!(result.is_ok());
let (runner, vm) = result.unwrap();
// Obtain the pie
let result = runner.get_cairo_pie(&vm);
assert!(result.is_ok());
let cairo_pie = result.unwrap();
// Check pie values
// CairoPieMedatada
let pie_metadata = cairo_pie.metadata;
// ret_pc_segment
assert_eq!(pie_metadata.ret_pc_segment, SegmentInfo::from((6, 0)));
// builtin_segments
let expected_builtin_segments = HashMap::from([
(String::from("output"), SegmentInfo::from((2, 1))),
(String::from("pedersen"), SegmentInfo::from((3, 3))),
(String::from("range_check"), SegmentInfo::from((4, 0))),
]);
assert_eq!(pie_metadata.builtin_segments, expected_builtin_segments);
// program_segment
assert_eq!(pie_metadata.program_segment, SegmentInfo::from((0, 19)));
// ret_fp_segment
assert_eq!(pie_metadata.ret_fp_segment, SegmentInfo::from((5, 0)));
//program
assert_eq!(pie_metadata.program.main, 6);
assert_eq!(pie_metadata.program.builtins, runner.program.builtins);
assert_eq!(
pie_metadata.program.data,
runner.program.shared_program_data.data
);
// execution_segment
assert_eq!(pie_metadata.execution_segment, SegmentInfo::from((1, 15)));
// extra_segments
assert!(pie_metadata.extra_segments.is_empty());

// execution_resources
let expected_execution_resources = ExecutionResources {
n_steps: 14,
n_memory_holes: 0,
builtin_instance_counter: HashMap::from([
(RANGE_CHECK_BUILTIN_NAME.to_string(), 0),
(OUTPUT_BUILTIN_NAME.to_string(), 1),
(HASH_BUILTIN_NAME.to_string(), 1),
]),
};
assert_eq!(cairo_pie.execution_resources, expected_execution_resources);
// additional_data
let expected_additional_data = HashMap::from([
(
OUTPUT_BUILTIN_NAME.to_string(),
BuiltinAdditionalData::Output(OutputBuiltinAdditionalData {
pages: HashMap::new(),
attributes: HashMap::new(),
}),
),
(
HASH_BUILTIN_NAME.to_string(),
BuiltinAdditionalData::Hash(vec![Relocatable::from((3, 2))]),
),
(
RANGE_CHECK_BUILTIN_NAME.to_string(),
BuiltinAdditionalData::None,
),
]);
assert_eq!(cairo_pie.additional_data, expected_additional_data);
// memory
assert_eq!(
cairo_pie.memory,
Into::<CairoPieMemory>::into(&vm.segments.memory)
);
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn common_signature() {
// Run the program
let program_content = include_bytes!("../../../cairo_programs/common_signature.json");
let mut hint_processor = BuiltinHintProcessor::new_empty();
let result = cairo_run(
program_content,
&CairoRunConfig {
layout: "all_cairo",
..Default::default()
},
&mut hint_processor,
);
assert!(result.is_ok());
let (runner, vm) = result.unwrap();
// Obtain the pie
let result = runner.get_cairo_pie(&vm);
assert!(result.is_ok());
let cairo_pie = result.unwrap();
// Check pie values
// CairoPieMedatada
let pie_metadata = cairo_pie.metadata;
// ret_pc_segment
assert_eq!(pie_metadata.ret_pc_segment, SegmentInfo::from((4, 0)));
// builtin_segments
let expected_builtin_segments =
HashMap::from([(String::from("ecdsa"), SegmentInfo::from((2, 2)))]);
assert_eq!(pie_metadata.builtin_segments, expected_builtin_segments);
// program_segment
assert_eq!(pie_metadata.program_segment, SegmentInfo::from((0, 21)));
// ret_fp_segment
assert_eq!(pie_metadata.ret_fp_segment, SegmentInfo::from((3, 0)));
//program
assert_eq!(pie_metadata.program.main, 9);
assert_eq!(pie_metadata.program.builtins, runner.program.builtins);
assert_eq!(
pie_metadata.program.data,
runner.program.shared_program_data.data
);
// execution_segment
assert_eq!(pie_metadata.execution_segment, SegmentInfo::from((1, 11)));
// extra_segments
assert!(pie_metadata.extra_segments.is_empty());

// execution_resources
let expected_execution_resources = ExecutionResources {
n_steps: 11,
n_memory_holes: 0,
builtin_instance_counter: HashMap::from([(SIGNATURE_BUILTIN_NAME.to_string(), 1)]),
};
assert_eq!(cairo_pie.execution_resources, expected_execution_resources);
// additional_data
let expected_additional_data = HashMap::from([(
SIGNATURE_BUILTIN_NAME.to_string(),
BuiltinAdditionalData::Signature(HashMap::from([(
Relocatable::from((2, 0)),
(
felt_str!(
"3086480810278599376317923499561306189851900463386393948998357832163236918254"
),
felt_str!(
"598673427589502599949712887611119751108407514580626464031881322743364689811"
),
),
)])),
)]);
assert_eq!(cairo_pie.additional_data, expected_additional_data);
// memory
assert_eq!(
cairo_pie.memory,
Into::<CairoPieMemory>::into(&vm.segments.memory)
);
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn relocate_segments() {
// Run the program
let program_content = include_bytes!("../../../cairo_programs/relocate_segments.json");
let mut hint_processor = BuiltinHintProcessor::new_empty();
let result = cairo_run(
program_content,
&CairoRunConfig {
layout: "all_cairo",
..Default::default()
},
&mut hint_processor,
);
assert!(result.is_ok());
let (runner, vm) = result.unwrap();
// Obtain the pie
let result = runner.get_cairo_pie(&vm);
assert!(result.is_ok());
let cairo_pie = result.unwrap();
// Check pie values
// CairoPieMedatada
let pie_metadata = cairo_pie.metadata;
// ret_pc_segment
assert_eq!(pie_metadata.ret_pc_segment, SegmentInfo::from((3, 0)));
// builtin_segments
assert!(pie_metadata.builtin_segments.is_empty());
// program_segment
assert_eq!(pie_metadata.program_segment, SegmentInfo::from((0, 32)));
// ret_fp_segment
assert_eq!(pie_metadata.ret_fp_segment, SegmentInfo::from((2, 0)));
//program
assert_eq!(pie_metadata.program.main, 5);
assert!(pie_metadata.program.builtins.is_empty());
assert_eq!(
pie_metadata.program.data,
runner.program.shared_program_data.data
);
// execution_segment
assert_eq!(pie_metadata.execution_segment, SegmentInfo::from((1, 16)));
// extra_segments
assert_eq!(pie_metadata.extra_segments, vec![SegmentInfo::from((4, 3))]);

// execution_resources
let expected_execution_resources = ExecutionResources {
n_steps: 22,
n_memory_holes: 0,
builtin_instance_counter: HashMap::default(),
};
assert_eq!(cairo_pie.execution_resources, expected_execution_resources);
// additional_data
assert!(cairo_pie.additional_data.is_empty());
// memory
assert_eq!(
cairo_pie.memory,
Into::<CairoPieMemory>::into(&vm.segments.memory)
);
}
1 change: 1 addition & 0 deletions vm/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ mod cairo_run_test;
mod pedersen_test;
mod struct_test;

mod get_cairo_pie_tests;
#[cfg(feature = "skip_next_instruction_hint")]
mod skip_instruction_test;

Expand Down
2 changes: 2 additions & 0 deletions vm/src/types/errors/program_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub enum ProgramError {
ConstWithoutValue(String),
#[error("Expected prime {PRIME_STR}, got {0}")]
PrimeDiffers(String),
#[error("Can't build a StrippedProgram from a Program without main")]
StrippedProgramNoMain,
#[error("Hint PC ({0}) is greater or equal to program length ({1})")]
InvalidHintPc(usize, usize),
}
Expand Down
47 changes: 47 additions & 0 deletions vm/src/types/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ pub struct Program {
pub(crate) builtins: Vec<BuiltinName>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StrippedProgram {
pub data: Vec<MaybeRelocatable>,
pub builtins: Vec<BuiltinName>,
pub main: usize,
}

impl Program {
#[allow(clippy::too_many_arguments)]
pub fn new(
Expand Down Expand Up @@ -252,6 +259,20 @@ impl Program {
})
.collect()
}

// Obtains a reduced version of the program
// Doesn't contain hints
// Can be used for verifying execution.
pub fn get_stripped_program(&self) -> Result<StrippedProgram, ProgramError> {
Ok(StrippedProgram {
data: self.shared_program_data.data.clone(),
builtins: self.builtins.clone(),
main: self
.shared_program_data
.main
.ok_or(ProgramError::StrippedProgramNoMain)?,
})
}
}

impl Default for Program {
Expand Down Expand Up @@ -318,6 +339,8 @@ mod tests {
use felt::felt_str;
use num_traits::Zero;

use assert_matches::assert_matches;

#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*;

Expand Down Expand Up @@ -1042,4 +1065,28 @@ mod tests {

assert_eq!(program, Program::default());
}

#[test]
fn get_stripped_program() {
let program_content = include_bytes!("../../../cairo_programs/pedersen_test.json");
let program = Program::from_bytes(program_content, Some("main")).unwrap();
let stripped_program = program.get_stripped_program().unwrap();
assert_eq!(stripped_program.builtins, program.builtins);
assert_eq!(stripped_program.data, program.shared_program_data.data);
assert_eq!(
stripped_program.main,
program.shared_program_data.main.unwrap()
);
}

#[test]
fn get_stripped_no_main() {
let program_content =
include_bytes!("../../../cairo_programs/proof_programs/fibonacci.json");
let program = Program::from_bytes(program_content, None).unwrap();
assert_matches!(
program.get_stripped_program(),
Err(ProgramError::StrippedProgramNoMain)
);
}
}
18 changes: 17 additions & 1 deletion vm/src/vm/errors/runner_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::stdlib::{collections::HashSet, prelude::*};

use thiserror_no_std::Error;

use super::memory_errors::MemoryError;
use super::{memory_errors::MemoryError, trace_errors::TraceError};
use crate::types::{errors::math_errors::MathError, relocatable::Relocatable};
use felt::Felt252;

Expand Down Expand Up @@ -85,6 +85,22 @@ pub enum RunnerError {
BuiltinExpectedInteger(Box<(&'static str, Relocatable)>),
#[error("keccak_builtin: Failed to convert input cells to u64 values")]
KeccakInputCellsNotU64,
#[error("Unexpected ret_fp_segment size")]
UnexpectedRetFpSegmentSize,
#[error("Unexpected ret_pc_segment size")]
UnexpectedRetPcSegmentSize,
#[error("Expected program base offset to be zero")]
ProgramBaseOffsetNotZero,
#[error("Expected execution base offset to be zero")]
ExecBaseOffsetNotZero,
#[error("Expected ret_fp offset to be zero")]
RetFpOffsetNotZero,
#[error("Expected ret_pc offset to be zero")]
RetPcOffsetNotZero,
#[error("Can't build a StrippedProgram from a Program without main")]
StrippedProgramNoMain,
#[error(transparent)]
Trace(#[from] TraceError),
}

#[cfg(test)]
Expand Down
Loading

1 comment on commit 2d214f7

@github-actions
Copy link

Choose a reason for hiding this comment

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

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.30.

Benchmark suite Current: 2d214f7 Previous: 6828b6a Ratio
add_u64_with_felt/1 4 ns/iter (± 0) 3 ns/iter (± 0) 1.33
add_u64_with_felt/2 4 ns/iter (± 0) 3 ns/iter (± 0) 1.33
add_u64_with_felt/6 5 ns/iter (± 0) 3 ns/iter (± 0) 1.67
add_u64_with_felt/7 5 ns/iter (± 0) 3 ns/iter (± 0) 1.67
add_u64_with_felt/8 4 ns/iter (± 0) 3 ns/iter (± 0) 1.33

This comment was automatically generated by workflow using github-action-benchmark.

CC: @unbalancedparentheses

Please sign in to comment.