cairo_vm/
air_private_input.rs

1use crate::{
2    stdlib::{
3        collections::{BTreeMap, HashMap},
4        prelude::{String, Vec},
5    },
6    types::builtin_name::BuiltinName,
7};
8use serde::{Deserialize, Serialize};
9
10use crate::Felt252;
11
12// Serializable format, matches the file output of the python implementation
13#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
14pub struct AirPrivateInputSerializable {
15    trace_path: String,
16    memory_path: String,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pedersen: Option<Vec<PrivateInput>>,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    range_check: Option<Vec<PrivateInput>>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    range_check96: Option<Vec<PrivateInput>>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    ecdsa: Option<Vec<PrivateInput>>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    bitwise: Option<Vec<PrivateInput>>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    ec_op: Option<Vec<PrivateInput>>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    keccak: Option<Vec<PrivateInput>>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    poseidon: Option<Vec<PrivateInput>>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    add_mod: Option<PrivateInput>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    mul_mod: Option<PrivateInput>,
37}
38
39// Contains only builtin public inputs, useful for library users
40#[derive(Clone, Debug, PartialEq, Eq)]
41pub struct AirPrivateInput(pub HashMap<BuiltinName, Vec<PrivateInput>>);
42
43#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
44#[serde(untagged)]
45pub enum PrivateInput {
46    Value(PrivateInputValue),
47    Pair(PrivateInputPair),
48    EcOp(PrivateInputEcOp),
49    PoseidonState(PrivateInputPoseidonState),
50    KeccakState(PrivateInputKeccakState),
51    Signature(PrivateInputSignature),
52    Mod(ModInput),
53}
54
55#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
56pub struct PrivateInputValue {
57    pub index: usize,
58    pub value: Felt252,
59}
60
61#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
62pub struct PrivateInputPair {
63    pub index: usize,
64    pub x: Felt252,
65    pub y: Felt252,
66}
67
68#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
69pub struct PrivateInputEcOp {
70    pub index: usize,
71    pub p_x: Felt252,
72    pub p_y: Felt252,
73    pub m: Felt252,
74    pub q_x: Felt252,
75    pub q_y: Felt252,
76}
77
78#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
79pub struct PrivateInputPoseidonState {
80    pub index: usize,
81    pub input_s0: Felt252,
82    pub input_s1: Felt252,
83    pub input_s2: Felt252,
84}
85
86#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
87pub struct PrivateInputKeccakState {
88    pub index: usize,
89    pub input_s0: Felt252,
90    pub input_s1: Felt252,
91    pub input_s2: Felt252,
92    pub input_s3: Felt252,
93    pub input_s4: Felt252,
94    pub input_s5: Felt252,
95    pub input_s6: Felt252,
96    pub input_s7: Felt252,
97}
98
99#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
100pub struct PrivateInputSignature {
101    pub index: usize,
102    pub pubkey: Felt252,
103    pub msg: Felt252,
104    pub signature_input: SignatureInput,
105}
106
107#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
108pub struct SignatureInput {
109    pub r: Felt252,
110    pub w: Felt252,
111}
112
113#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
114pub struct ModInput {
115    pub instances: Vec<ModInputInstance>,
116    pub zero_value_address: usize,
117}
118
119#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
120pub struct ModInputInstance {
121    pub index: usize,
122    pub p0: Felt252,
123    pub p1: Felt252,
124    pub p2: Felt252,
125    pub p3: Felt252,
126    pub values_ptr: usize,
127    pub offsets_ptr: usize,
128    pub n: usize,
129    #[serde(deserialize_with = "mod_input_instance_batch_serde::deserialize")]
130    #[serde(serialize_with = "mod_input_instance_batch_serde::serialize")]
131    pub batch: BTreeMap<usize, ModInputMemoryVars>,
132}
133
134#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
135pub struct ModInputMemoryVars {
136    pub a_offset: usize,
137    pub a0: Felt252,
138    pub a1: Felt252,
139    pub a2: Felt252,
140    pub a3: Felt252,
141    pub b_offset: usize,
142    pub b0: Felt252,
143    pub b1: Felt252,
144    pub b2: Felt252,
145    pub b3: Felt252,
146    pub c_offset: usize,
147    pub c0: Felt252,
148    pub c1: Felt252,
149    pub c2: Felt252,
150    pub c3: Felt252,
151}
152
153impl AirPrivateInput {
154    pub fn to_serializable(
155        &self,
156        trace_path: String,
157        memory_path: String,
158    ) -> AirPrivateInputSerializable {
159        AirPrivateInputSerializable {
160            trace_path,
161            memory_path,
162            pedersen: self.0.get(&BuiltinName::pedersen).cloned(),
163            range_check: self.0.get(&BuiltinName::range_check).cloned(),
164            range_check96: self.0.get(&BuiltinName::range_check96).cloned(),
165            ecdsa: self.0.get(&BuiltinName::ecdsa).cloned(),
166            bitwise: self.0.get(&BuiltinName::bitwise).cloned(),
167            ec_op: self.0.get(&BuiltinName::ec_op).cloned(),
168            keccak: self.0.get(&BuiltinName::keccak).cloned(),
169            poseidon: self.0.get(&BuiltinName::poseidon).cloned(),
170            add_mod: self
171                .0
172                .get(&BuiltinName::add_mod)
173                .and_then(|pi| pi.first())
174                .cloned(),
175            mul_mod: self
176                .0
177                .get(&BuiltinName::mul_mod)
178                .and_then(|pi| pi.first())
179                .cloned(),
180        }
181    }
182}
183
184impl From<AirPrivateInputSerializable> for AirPrivateInput {
185    fn from(private_input: AirPrivateInputSerializable) -> Self {
186        let mut inputs = HashMap::new();
187        let mut insert_input = |input_name, input| {
188            if let Some(input) = input {
189                inputs.insert(input_name, input);
190            }
191        };
192        insert_input(BuiltinName::pedersen, private_input.pedersen);
193        insert_input(BuiltinName::range_check, private_input.range_check);
194        insert_input(BuiltinName::ecdsa, private_input.ecdsa);
195        insert_input(BuiltinName::bitwise, private_input.bitwise);
196        insert_input(BuiltinName::ec_op, private_input.ec_op);
197        insert_input(BuiltinName::keccak, private_input.keccak);
198        insert_input(BuiltinName::poseidon, private_input.poseidon);
199
200        Self(inputs)
201    }
202}
203
204impl AirPrivateInputSerializable {
205    pub fn serialize_json(&self) -> Result<String, serde_json::Error> {
206        serde_json::to_string_pretty(&self)
207    }
208}
209
210mod mod_input_instance_batch_serde {
211    use super::*;
212
213    use serde::{Deserializer, Serializer};
214
215    pub(crate) fn serialize<S: Serializer>(
216        value: &BTreeMap<usize, ModInputMemoryVars>,
217        s: S,
218    ) -> Result<S::Ok, S::Error> {
219        let value = value.iter().map(|v| v.1).collect::<Vec<_>>();
220
221        value.serialize(s)
222    }
223
224    pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
225        d: D,
226    ) -> Result<BTreeMap<usize, ModInputMemoryVars>, D::Error> {
227        let value = Vec::<ModInputMemoryVars>::deserialize(d)?;
228
229        Ok(value.into_iter().enumerate().collect())
230    }
231
232    #[cfg(feature = "std")]
233    #[test]
234    fn test_serde() {
235        let input_value = vec![
236            (
237                0,
238                ModInputMemoryVars {
239                    a_offset: 5,
240                    b_offset: 5,
241                    c_offset: 5,
242                    a0: Felt252::from(5u32),
243                    a1: Felt252::from(5u32),
244                    a2: Felt252::from(5u32),
245                    a3: Felt252::from(5u32),
246                    b0: Felt252::from(5u32),
247                    b1: Felt252::from(5u32),
248                    b2: Felt252::from(5u32),
249                    b3: Felt252::from(5u32),
250                    c0: Felt252::from(5u32),
251                    c1: Felt252::from(5u32),
252                    c2: Felt252::from(5u32),
253                    c3: Felt252::from(5u32),
254                },
255            ),
256            (
257                1,
258                ModInputMemoryVars {
259                    a_offset: 7,
260                    b_offset: 7,
261                    c_offset: 7,
262                    a0: Felt252::from(7u32),
263                    a1: Felt252::from(7u32),
264                    a2: Felt252::from(7u32),
265                    a3: Felt252::from(7u32),
266                    b0: Felt252::from(7u32),
267                    b1: Felt252::from(7u32),
268                    b2: Felt252::from(7u32),
269                    b3: Felt252::from(7u32),
270                    c0: Felt252::from(7u32),
271                    c1: Felt252::from(7u32),
272                    c2: Felt252::from(7u32),
273                    c3: Felt252::from(7u32),
274                },
275            ),
276        ]
277        .into_iter()
278        .collect::<BTreeMap<usize, _>>();
279
280        let bytes = Vec::new();
281        let mut serializer = serde_json::Serializer::new(bytes);
282        serialize(&input_value, &mut serializer).unwrap();
283        let bytes = serializer.into_inner();
284
285        let mut deserializer = serde_json::Deserializer::from_slice(&bytes);
286        let output_value = deserialize(&mut deserializer).unwrap();
287
288        assert_eq!(input_value, output_value);
289    }
290}
291
292#[cfg(test)]
293mod tests {
294    use crate::types::layout_name::LayoutName;
295    #[cfg(feature = "std")]
296    use {
297        super::*,
298        crate::air_private_input::{AirPrivateInput, AirPrivateInputSerializable},
299        assert_matches::assert_matches,
300    };
301
302    #[cfg(any(target_arch = "wasm32", not(feature = "std")))]
303    use crate::alloc::string::ToString;
304
305    #[cfg(feature = "std")]
306    #[test]
307    fn test_from_serializable() {
308        let serializable_private_input = AirPrivateInputSerializable {
309            trace_path: "trace.bin".to_string(),
310            memory_path: "memory.bin".to_string(),
311            pedersen: Some(vec![PrivateInput::Pair(PrivateInputPair {
312                index: 0,
313                x: Felt252::from(100),
314                y: Felt252::from(200),
315            })]),
316            range_check: Some(vec![PrivateInput::Value(PrivateInputValue {
317                index: 10000,
318                value: Felt252::from(8000),
319            })]),
320            range_check96: Some(vec![PrivateInput::Value(PrivateInputValue {
321                index: 10000,
322                value: Felt252::from(8000),
323            })]),
324            ecdsa: Some(vec![PrivateInput::Signature(PrivateInputSignature {
325                index: 0,
326                pubkey: Felt252::from(123),
327                msg: Felt252::from(456),
328                signature_input: SignatureInput {
329                    r: Felt252::from(654),
330                    w: Felt252::from(321),
331                },
332            })]),
333            bitwise: Some(vec![PrivateInput::Pair(PrivateInputPair {
334                index: 4,
335                x: Felt252::from(7),
336                y: Felt252::from(8),
337            })]),
338            ec_op: Some(vec![PrivateInput::EcOp(PrivateInputEcOp {
339                index: 1,
340                p_x: Felt252::from(10),
341                p_y: Felt252::from(10),
342                m: Felt252::from(100),
343                q_x: Felt252::from(11),
344                q_y: Felt252::from(14),
345            })]),
346            keccak: Some(vec![PrivateInput::KeccakState(PrivateInputKeccakState {
347                index: 0,
348                input_s0: Felt252::from(0),
349                input_s1: Felt252::from(1),
350                input_s2: Felt252::from(2),
351                input_s3: Felt252::from(3),
352                input_s4: Felt252::from(4),
353                input_s5: Felt252::from(5),
354                input_s6: Felt252::from(6),
355                input_s7: Felt252::from(7),
356            })]),
357            poseidon: Some(vec![PrivateInput::PoseidonState(
358                PrivateInputPoseidonState {
359                    index: 42,
360                    input_s0: Felt252::from(1),
361                    input_s1: Felt252::from(2),
362                    input_s2: Felt252::from(3),
363                },
364            )]),
365            add_mod: None,
366            mul_mod: None,
367        };
368
369        let private_input = AirPrivateInput::from(serializable_private_input.clone());
370
371        assert_matches!(private_input.0.get(&BuiltinName::pedersen), data if data == serializable_private_input.pedersen.as_ref());
372        assert_matches!(private_input.0.get(&BuiltinName::range_check), data if data == serializable_private_input.range_check.as_ref());
373        assert_matches!(private_input.0.get(&BuiltinName::ecdsa), data if data == serializable_private_input.ecdsa.as_ref());
374        assert_matches!(private_input.0.get(&BuiltinName::bitwise), data if data == serializable_private_input.bitwise.as_ref());
375        assert_matches!(private_input.0.get(&BuiltinName::ec_op), data if data == serializable_private_input.ec_op.as_ref());
376        assert_matches!(private_input.0.get(&BuiltinName::keccak), data if data == serializable_private_input.keccak.as_ref());
377        assert_matches!(private_input.0.get(&BuiltinName::poseidon), data if data == serializable_private_input.poseidon.as_ref());
378    }
379
380    #[test]
381    fn serialize_air_private_input_small_layout_only_builtins() {
382        let config = crate::cairo_run::CairoRunConfig {
383            proof_mode: true,
384            relocate_mem: true,
385            trace_enabled: true,
386            layout: LayoutName::small,
387            ..Default::default()
388        };
389        let runner = crate::cairo_run::cairo_run(include_bytes!("../../cairo_programs/proof_programs/fibonacci.json"), &config, &mut crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor::new_empty()).unwrap();
390        let public_input = runner.get_air_private_input();
391        let serialized_public_input =
392            public_input.to_serializable("/dev/null".to_string(), "/dev/null".to_string());
393        assert!(serialized_public_input.pedersen.is_some());
394        assert!(serialized_public_input.range_check.is_some());
395        assert!(serialized_public_input.ecdsa.is_some());
396        assert!(serialized_public_input.bitwise.is_none());
397        assert!(serialized_public_input.ec_op.is_none());
398        assert!(serialized_public_input.keccak.is_none());
399        assert!(serialized_public_input.poseidon.is_none());
400    }
401}