From d4376fcaf5255565965c1e216c3ee01dcd7bdc06 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 5 Mar 2024 15:42:48 -0300 Subject: [PATCH 1/8] Derive deserialize for AirPublicInput --- vm/src/air_public_input.rs | 46 +++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/vm/src/air_public_input.rs b/vm/src/air_public_input.rs index 692f391f2a..0fd00d3564 100644 --- a/vm/src/air_public_input.rs +++ b/vm/src/air_public_input.rs @@ -1,5 +1,5 @@ use crate::Felt252; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use thiserror_no_std::Error; use crate::{ @@ -14,18 +14,21 @@ use crate::{ }, }; -#[derive(Serialize, Debug)] +#[derive(Serialize, Deserialize, Debug)] pub struct PublicMemoryEntry { pub address: usize, #[serde(serialize_with = "mem_value_serde::serialize")] + #[serde(deserialize_with = "mem_value_serde::deserialize")] pub value: Option, pub page: usize, } mod mem_value_serde { + use core::fmt; + use super::*; - use serde::Serializer; + use serde::{de, Deserializer, Serializer}; pub(crate) fn serialize( value: &Option, @@ -37,9 +40,41 @@ mod mem_value_serde { serializer.serialize_none() } } + + pub(crate) fn deserialize<'de, D: Deserializer<'de>>( + d: D, + ) -> Result, D::Error> { + d.deserialize_str(Felt252OptionVisitor) + } + + struct Felt252OptionVisitor; + + impl<'de> de::Visitor<'de> for Felt252OptionVisitor { + type Value = Option; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Could not deserialize hexadecimal string") + } + + fn visit_none(self) -> Result + where + E: de::Error, + { + Ok(None) + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + Felt252::from_hex(&value) + .map_err(de::Error::custom) + .map(|x| Some(x)) + } + } } -#[derive(Serialize, Debug)] +#[derive(Serialize, Deserialize, Debug)] pub struct MemorySegmentAddresses { pub begin_addr: usize, pub stop_ptr: usize, @@ -55,7 +90,7 @@ impl From<(usize, usize)> for MemorySegmentAddresses { } } -#[derive(Serialize, Debug)] +#[derive(Serialize, Deserialize, Debug)] pub struct PublicInput<'a> { pub layout: &'a str, pub rc_min: isize, @@ -64,6 +99,7 @@ pub struct PublicInput<'a> { pub memory_segments: HashMap<&'a str, MemorySegmentAddresses>, pub public_memory: Vec, #[serde(rename = "dynamic_params")] + #[serde(skip_deserializing)] layout_params: Option<&'a CairoLayout>, } From 01522070cec85a4f1b772118d2d6d25e15fde80c Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 5 Mar 2024 16:23:35 -0300 Subject: [PATCH 2/8] Add test --- vm/src/air_public_input.rs | 48 +++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/vm/src/air_public_input.rs b/vm/src/air_public_input.rs index 0fd00d3564..41d8cc9564 100644 --- a/vm/src/air_public_input.rs +++ b/vm/src/air_public_input.rs @@ -14,7 +14,7 @@ use crate::{ }, }; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct PublicMemoryEntry { pub address: usize, #[serde(serialize_with = "mem_value_serde::serialize")] @@ -74,7 +74,7 @@ mod mem_value_serde { } } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct MemorySegmentAddresses { pub begin_addr: usize, pub stop_ptr: usize, @@ -99,7 +99,7 @@ pub struct PublicInput<'a> { pub memory_segments: HashMap<&'a str, MemorySegmentAddresses>, pub public_memory: Vec, #[serde(rename = "dynamic_params")] - #[serde(skip_deserializing)] + #[serde(skip_deserializing)] // This is set to None by default so we can skip it layout_params: Option<&'a CairoLayout>, } @@ -175,3 +175,45 @@ pub enum PublicInputError { #[error(transparent)] Trace(#[from] TraceError), } +#[cfg(test)] +mod tests { + use rstest::rstest; + + use super::*; + + #[cfg(feature = "std")] + #[rstest] + #[case(include_bytes!("../../cairo_programs/proof_programs/fibonacci.json"))] + fn serialize_and_deserialize_air_public_input(#[case] program_content: &[u8]) { + let config = crate::cairo_run::CairoRunConfig { + proof_mode: true, + relocate_mem: true, + trace_enabled: true, + layout: "all_cairo", + ..Default::default() + }; + let (runner, vm) = crate::cairo_run::cairo_run(&program_content, &config, &mut crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor::new_empty()).unwrap(); + let public_input = runner.get_air_public_input(&vm).unwrap(); + // We already know serialization works as expected due to the comparison against python VM + let serialized_public_input = public_input.serialize_json().unwrap(); + let deserialized_public_input: PublicInput = + serde_json::from_str(&serialized_public_input).unwrap(); + // Check that the deserialized public input is equal to the one we obtained from the vm first + assert_eq!(public_input.layout, deserialized_public_input.layout); + assert_eq!(public_input.rc_max, deserialized_public_input.rc_max); + assert_eq!(public_input.rc_min, deserialized_public_input.rc_min); + assert_eq!(public_input.n_steps, deserialized_public_input.n_steps); + assert_eq!( + public_input.memory_segments, + deserialized_public_input.memory_segments + ); + assert_eq!( + public_input.public_memory, + deserialized_public_input.public_memory + ); + assert!( + public_input.layout_params.is_none() + && deserialized_public_input.layout_params.is_none() + ); + } +} From ceca1ea5da26d5953d6dcb4a9a0f1268b8d143d1 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 5 Mar 2024 16:26:53 -0300 Subject: [PATCH 3/8] Add more test cases --- vm/src/air_public_input.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vm/src/air_public_input.rs b/vm/src/air_public_input.rs index 41d8cc9564..cedeeb271a 100644 --- a/vm/src/air_public_input.rs +++ b/vm/src/air_public_input.rs @@ -184,6 +184,12 @@ mod tests { #[cfg(feature = "std")] #[rstest] #[case(include_bytes!("../../cairo_programs/proof_programs/fibonacci.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/bitwise_output.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/keccak_builtin.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/poseidon_builtin.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/relocate_temporary_segment_append.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/pedersen_test.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/ec_op.json"))] fn serialize_and_deserialize_air_public_input(#[case] program_content: &[u8]) { let config = crate::cairo_run::CairoRunConfig { proof_mode: true, From ad4bf45816cb8d2e0e3f001fba838a5c123d4cb1 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 5 Mar 2024 16:40:19 -0300 Subject: [PATCH 4/8] Add Changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2aa00a4e..45b358fd4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ #### Upcoming Changes +* feat: Make air public inputs deserializable [#1648](https://github.com/lambdaclass/cairo-vm/pull/1648) + * feat: Add cairo1-run output pretty-printing for felts, arrays/spans and dicts [#1630](https://github.com/lambdaclass/cairo-vm/pull/1630) * feat: output builtin features for bootloader support [#1580](https://github.com/lambdaclass/cairo-vm/pull/1580) From a920e93946b832eba5787e00559dd901202f10d9 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 5 Mar 2024 16:44:05 -0300 Subject: [PATCH 5/8] Clippy --- vm/src/air_public_input.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/src/air_public_input.rs b/vm/src/air_public_input.rs index cedeeb271a..da0346df87 100644 --- a/vm/src/air_public_input.rs +++ b/vm/src/air_public_input.rs @@ -67,9 +67,9 @@ mod mem_value_serde { where E: de::Error, { - Felt252::from_hex(&value) + Felt252::from_hex(value) .map_err(de::Error::custom) - .map(|x| Some(x)) + .map(Some) } } } @@ -198,7 +198,7 @@ mod tests { layout: "all_cairo", ..Default::default() }; - let (runner, vm) = crate::cairo_run::cairo_run(&program_content, &config, &mut crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor::new_empty()).unwrap(); + let (runner, vm) = crate::cairo_run::cairo_run(program_content, &config, &mut crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor::new_empty()).unwrap(); let public_input = runner.get_air_public_input(&vm).unwrap(); // We already know serialization works as expected due to the comparison against python VM let serialized_public_input = public_input.serialize_json().unwrap(); From e0fa3afa3efb6c4f4db031af438fa009b8041ae5 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 5 Mar 2024 17:29:47 -0300 Subject: [PATCH 6/8] Fix import --- vm/src/air_public_input.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/src/air_public_input.rs b/vm/src/air_public_input.rs index da0346df87..9ed46eb0bf 100644 --- a/vm/src/air_public_input.rs +++ b/vm/src/air_public_input.rs @@ -177,6 +177,7 @@ pub enum PublicInputError { } #[cfg(test)] mod tests { + #[cfg(feature = "std")] use rstest::rstest; use super::*; From e35dc85c79b5d18d7e5729f3a5a925133c2fee4c Mon Sep 17 00:00:00 2001 From: Federica Date: Wed, 6 Mar 2024 10:26:32 -0300 Subject: [PATCH 7/8] Fix import --- vm/src/air_public_input.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/air_public_input.rs b/vm/src/air_public_input.rs index 9ed46eb0bf..4a16e3bbce 100644 --- a/vm/src/air_public_input.rs +++ b/vm/src/air_public_input.rs @@ -179,7 +179,7 @@ pub enum PublicInputError { mod tests { #[cfg(feature = "std")] use rstest::rstest; - + #[cfg(feature = "std")] use super::*; #[cfg(feature = "std")] From 5df85822eac1c1d9d8438b2faad5ff51c842d92b Mon Sep 17 00:00:00 2001 From: Federica Date: Wed, 6 Mar 2024 10:33:50 -0300 Subject: [PATCH 8/8] fmt --- vm/src/air_public_input.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/src/air_public_input.rs b/vm/src/air_public_input.rs index 4a16e3bbce..3a2bf8bc37 100644 --- a/vm/src/air_public_input.rs +++ b/vm/src/air_public_input.rs @@ -177,10 +177,10 @@ pub enum PublicInputError { } #[cfg(test)] mod tests { - #[cfg(feature = "std")] - use rstest::rstest; #[cfg(feature = "std")] use super::*; + #[cfg(feature = "std")] + use rstest::rstest; #[cfg(feature = "std")] #[rstest]