cairo_lang_sierra/extensions/modules/starknet/
syscalls.rs

1use itertools::chain;
2
3use super::interoperability::ClassHashType;
4use super::u64_span_ty;
5use crate::extensions::array::ArrayType;
6use crate::extensions::boxing::box_ty;
7use crate::extensions::felt252::Felt252Type;
8use crate::extensions::gas::GasBuiltinType;
9use crate::extensions::int::unsigned::Uint32Type;
10use crate::extensions::lib_func::{
11    BranchSignature, DeferredOutputKind, LibfuncSignature, OutputVarInfo, ParamSignature,
12    SierraApChange, SignatureSpecializationContext,
13};
14use crate::extensions::modules::get_u256_type;
15use crate::extensions::starknet::ContractAddressType;
16use crate::extensions::utils::fixed_size_array_ty;
17use crate::extensions::{
18    NamedType, NoGenericArgsGenericLibfunc, NoGenericArgsGenericType, OutputVarReferenceInfo,
19    SpecializationError,
20};
21use crate::ids::{ConcreteTypeId, GenericTypeId};
22
23/// Type for Starknet system object.
24/// Used to make system calls.
25#[derive(Default)]
26pub struct SystemType {}
27impl NoGenericArgsGenericType for SystemType {
28    const ID: GenericTypeId = GenericTypeId::new_inline("System");
29    const STORABLE: bool = true;
30    const DUPLICATABLE: bool = false;
31    const DROPPABLE: bool = false;
32    const ZERO_SIZED: bool = false;
33}
34
35/// Trait for implementing a library function for syscalls.
36pub trait SyscallGenericLibfunc: Default {
37    /// The library function id.
38    const STR_ID: &'static str;
39    /// The non implicits inputs for the libfunc.
40    fn input_tys(
41        context: &dyn SignatureSpecializationContext,
42    ) -> Result<Vec<ConcreteTypeId>, SpecializationError>;
43    /// The success case non implicits outputs of the libfunc.
44    fn success_output_tys(
45        context: &dyn SignatureSpecializationContext,
46    ) -> Result<Vec<ConcreteTypeId>, SpecializationError>;
47}
48
49impl<T: SyscallGenericLibfunc> NoGenericArgsGenericLibfunc for T {
50    const STR_ID: &'static str = T::STR_ID;
51
52    fn specialize_signature(
53        &self,
54        context: &dyn SignatureSpecializationContext,
55    ) -> Result<LibfuncSignature, SpecializationError> {
56        let gas_builtin_ty = context.get_concrete_type(GasBuiltinType::id(), &[])?;
57        let system_ty = context.get_concrete_type(SystemType::id(), &[])?;
58        let felt252_ty = context.get_concrete_type(Felt252Type::id(), &[])?;
59        let felt252_array_ty = context.get_wrapped_concrete_type(ArrayType::id(), felt252_ty)?;
60
61        let gb_output_info = OutputVarInfo {
62            ty: gas_builtin_ty.clone(),
63            ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
64        };
65        let system_output_info = OutputVarInfo::new_builtin(system_ty.clone(), 1);
66        Ok(LibfuncSignature {
67            param_signatures: chain!(
68                [
69                    // Gas builtin
70                    ParamSignature::new(gas_builtin_ty),
71                    // System
72                    ParamSignature::new(system_ty).with_allow_add_const(),
73                ],
74                T::input_tys(context)?.into_iter().map(ParamSignature::new)
75            )
76            .collect(),
77            branch_signatures: vec![
78                // Success branch.
79                BranchSignature {
80                    vars: chain!(
81                        [
82                            // Gas builtin
83                            gb_output_info.clone(),
84                            // System
85                            system_output_info.clone()
86                        ],
87                        T::success_output_tys(context)?.into_iter().map(|ty| OutputVarInfo {
88                            ty,
89                            ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
90                        })
91                    )
92                    .collect(),
93                    ap_change: SierraApChange::Known { new_vars_only: false },
94                },
95                // Failure branch.
96                BranchSignature {
97                    vars: vec![
98                        // Gas builtin
99                        gb_output_info,
100                        // System
101                        system_output_info,
102                        // Revert reason
103                        OutputVarInfo {
104                            ty: felt252_array_ty,
105                            ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
106                        },
107                    ],
108                    ap_change: SierraApChange::Known { new_vars_only: false },
109                },
110            ],
111            fallthrough: Some(0),
112        })
113    }
114}
115
116/// Libfunc for the replace_class system call.
117#[derive(Default)]
118pub struct ReplaceClassLibfunc {}
119impl SyscallGenericLibfunc for ReplaceClassLibfunc {
120    const STR_ID: &'static str = "replace_class_syscall";
121
122    fn input_tys(
123        context: &dyn SignatureSpecializationContext,
124    ) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
125        let class_hash_ty = context.get_concrete_type(ClassHashType::id(), &[])?;
126        Ok(vec![
127            // class_hash
128            class_hash_ty,
129        ])
130    }
131
132    fn success_output_tys(
133        _context: &dyn SignatureSpecializationContext,
134    ) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
135        Ok(vec![])
136    }
137}
138
139/// Libfunc for the keccak system call.
140/// The libfunc does not add any padding and the input needs to be a multiple of 1088 bits
141/// (== 17 u64 word).
142#[derive(Default)]
143pub struct KeccakLibfunc {}
144impl SyscallGenericLibfunc for KeccakLibfunc {
145    const STR_ID: &'static str = "keccak_syscall";
146
147    fn input_tys(
148        context: &dyn SignatureSpecializationContext,
149    ) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
150        Ok(vec![
151            // input
152            u64_span_ty(context)?,
153        ])
154    }
155
156    fn success_output_tys(
157        context: &dyn SignatureSpecializationContext,
158    ) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
159        Ok(vec![get_u256_type(context)?])
160    }
161}
162
163/// Type representing the sha256 state handle.
164#[derive(Default)]
165pub struct Sha256StateHandleType {}
166
167impl NoGenericArgsGenericType for Sha256StateHandleType {
168    const ID: GenericTypeId = GenericTypeId::new_inline("Sha256StateHandle");
169    const STORABLE: bool = true;
170    const DUPLICATABLE: bool = true;
171    const DROPPABLE: bool = true;
172    const ZERO_SIZED: bool = false;
173}
174
175/// Libfunc for the sha256_process_block system call.
176/// The input needs a Sha256StateHandleType for the previous state and a span of 16 words
177/// (each word is 32 bits).
178#[derive(Default)]
179pub struct Sha256ProcessBlockLibfunc {}
180impl SyscallGenericLibfunc for Sha256ProcessBlockLibfunc {
181    const STR_ID: &'static str = "sha256_process_block_syscall";
182
183    fn input_tys(
184        context: &dyn SignatureSpecializationContext,
185    ) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
186        Ok(vec![
187            // Previous state of the hash.
188            context.get_concrete_type(Sha256StateHandleType::id(), &[])?,
189            // The current block to process.
190            boxed_u32_fixed_array_ty(context, 16)?,
191        ])
192    }
193
194    fn success_output_tys(
195        context: &dyn SignatureSpecializationContext,
196    ) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
197        Ok(vec![context.get_concrete_type(Sha256StateHandleType::id(), &[])?])
198    }
199}
200
201/// Libfunc for converting a ContractAddress into a felt252.
202#[derive(Default)]
203pub struct Sha256StateHandleInitLibfunc {}
204impl NoGenericArgsGenericLibfunc for Sha256StateHandleInitLibfunc {
205    const STR_ID: &'static str = "sha256_state_handle_init";
206
207    fn specialize_signature(
208        &self,
209        context: &dyn SignatureSpecializationContext,
210    ) -> Result<LibfuncSignature, SpecializationError> {
211        Ok(LibfuncSignature::new_non_branch_ex(
212            vec![
213                ParamSignature::new(sha256_state_handle_unwrapped_type(context)?).with_allow_all(),
214            ],
215            vec![OutputVarInfo {
216                ty: context.get_concrete_type(Sha256StateHandleType::id(), &[])?,
217                ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
218            }],
219            SierraApChange::Known { new_vars_only: false },
220        ))
221    }
222}
223
224/// Libfunc for converting a ContractAddress into a felt252.
225#[derive(Default)]
226pub struct Sha256StateHandleDigestLibfunc {}
227impl NoGenericArgsGenericLibfunc for Sha256StateHandleDigestLibfunc {
228    const STR_ID: &'static str = "sha256_state_handle_digest";
229
230    fn specialize_signature(
231        &self,
232        context: &dyn SignatureSpecializationContext,
233    ) -> Result<LibfuncSignature, SpecializationError> {
234        Ok(LibfuncSignature::new_non_branch_ex(
235            vec![
236                ParamSignature::new(context.get_concrete_type(Sha256StateHandleType::id(), &[])?)
237                    .with_allow_all(),
238            ],
239            vec![OutputVarInfo {
240                ty: sha256_state_handle_unwrapped_type(context)?,
241                ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
242            }],
243            SierraApChange::Known { new_vars_only: false },
244        ))
245    }
246}
247
248/// The inner type of the Sha256StateHandle: `Box<[u32; 8]>`.
249pub fn sha256_state_handle_unwrapped_type(
250    context: &dyn SignatureSpecializationContext,
251) -> Result<ConcreteTypeId, SpecializationError> {
252    boxed_u32_fixed_array_ty(context, 8)
253}
254
255/// Returns `Box<[u32; size]>` according to the given size.
256fn boxed_u32_fixed_array_ty(
257    context: &dyn SignatureSpecializationContext,
258    size: i16,
259) -> Result<ConcreteTypeId, SpecializationError> {
260    let ty = context.get_concrete_type(Uint32Type::id(), &[])?;
261    box_ty(context, fixed_size_array_ty(context, ty, size)?)
262}
263
264/// Libfunc for the get_class_hash_at system call.
265#[derive(Default)]
266pub struct GetClassHashAtLibfunc {}
267impl SyscallGenericLibfunc for GetClassHashAtLibfunc {
268    const STR_ID: &'static str = "get_class_hash_at_syscall";
269
270    fn input_tys(
271        context: &dyn SignatureSpecializationContext,
272    ) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
273        Ok(vec![context.get_concrete_type(ContractAddressType::id(), &[])?])
274    }
275
276    fn success_output_tys(
277        context: &dyn SignatureSpecializationContext,
278    ) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
279        Ok(vec![context.get_concrete_type(ClassHashType::id(), &[])?])
280    }
281}