cairo_lang_sierra/extensions/modules/
felt252.rs1use num_bigint::BigInt;
2use num_traits::Zero;
3
4use super::is_zero::{IsZeroLibfunc, IsZeroTraits};
5use super::non_zero::nonzero_ty;
6use crate::define_libfunc_hierarchy;
7use crate::extensions::lib_func::{
8 DeferredOutputKind, LibfuncSignature, OutputVarInfo, ParamSignature, SierraApChange,
9 SignatureSpecializationContext, SpecializationContext,
10};
11use crate::extensions::{
12 GenericLibfunc, NamedLibfunc, NamedType, NoGenericArgsGenericType, OutputVarReferenceInfo,
13 SignatureBasedConcreteLibfunc, SpecializationError,
14};
15use crate::ids::{GenericLibfuncId, GenericTypeId};
16use crate::program::GenericArg;
17
18#[derive(Default)]
21pub struct Felt252Type {}
22impl NoGenericArgsGenericType for Felt252Type {
23 const ID: GenericTypeId = GenericTypeId::new_inline("felt252");
24 const STORABLE: bool = true;
25 const DUPLICATABLE: bool = true;
26 const DROPPABLE: bool = true;
27 const ZERO_SIZED: bool = false;
28}
29
30define_libfunc_hierarchy! {
31 pub enum Felt252Libfunc {
32 BinaryOperation(Felt252BinaryOperationLibfunc),
33 Const(Felt252ConstLibfunc),
34 IsZero(Felt252JumpNotZeroLibfunc),
35 }, Felt252Concrete
36}
37
38define_libfunc_hierarchy! {
39 pub enum Felt252BinaryOperationLibfunc {
40 WithVar(Felt252BinaryOperationWithVarLibfunc),
41 WithConst(Felt252BinaryOperationWithConstLibfunc),
42 }, Felt252BinaryOperationConcrete
43}
44
45#[derive(Default)]
46pub struct Felt252Traits {}
47impl IsZeroTraits for Felt252Traits {
48 const IS_ZERO: &'static str = "felt252_is_zero";
49 const GENERIC_TYPE_ID: GenericTypeId = <Felt252Type as NamedType>::ID;
50}
51pub type Felt252JumpNotZeroLibfunc = IsZeroLibfunc<Felt252Traits>;
52
53#[derive(Copy, Clone, Debug, PartialEq, Eq)]
55pub enum Felt252BinaryOperator {
56 Add,
57 Sub,
58 Mul,
59 Div,
60}
61
62pub struct Felt252BinaryOperationWithVarLibfunc {
64 pub operator: Felt252BinaryOperator,
65}
66impl Felt252BinaryOperationWithVarLibfunc {
67 fn new(operator: Felt252BinaryOperator) -> Self {
68 Self { operator }
69 }
70 const ADD: &'static str = "felt252_add";
71 const SUB: &'static str = "felt252_sub";
72 const MUL: &'static str = "felt252_mul";
73 const DIV: &'static str = "felt252_div";
74}
75impl GenericLibfunc for Felt252BinaryOperationWithVarLibfunc {
76 type Concrete = Felt252BinaryOpConcreteLibfunc;
77
78 fn supported_ids() -> Vec<GenericLibfuncId> {
79 vec![
80 GenericLibfuncId::from(Self::ADD),
81 GenericLibfuncId::from(Self::SUB),
82 GenericLibfuncId::from(Self::MUL),
83 GenericLibfuncId::from(Self::DIV),
84 ]
85 }
86
87 fn by_id(id: &GenericLibfuncId) -> Option<Self> {
88 match id.0.as_str() {
89 Self::ADD => Some(Self::new(Felt252BinaryOperator::Add)),
90 Self::SUB => Some(Self::new(Felt252BinaryOperator::Sub)),
91 Self::MUL => Some(Self::new(Felt252BinaryOperator::Mul)),
92 Self::DIV => Some(Self::new(Felt252BinaryOperator::Div)),
93 _ => None,
94 }
95 }
96
97 fn specialize_signature(
98 &self,
99 context: &dyn SignatureSpecializationContext,
100 args: &[GenericArg],
101 ) -> Result<LibfuncSignature, SpecializationError> {
102 let ty = context.get_concrete_type(Felt252Type::id(), &[])?;
103 let (second_param_type, output_ref_info) =
104 if matches!(self.operator, Felt252BinaryOperator::Div) {
105 (nonzero_ty(context, &ty)?, OutputVarReferenceInfo::NewTempVar { idx: 0 })
106 } else {
107 (ty.clone(), OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic))
108 };
109 match args {
110 [] => Ok(LibfuncSignature::new_non_branch_ex(
111 vec![
112 ParamSignature::new(ty.clone()),
113 ParamSignature::new(second_param_type).with_allow_const(),
114 ],
115 vec![OutputVarInfo { ty, ref_info: output_ref_info }],
116 SierraApChange::Known { new_vars_only: true },
117 )),
118 _ => Err(SpecializationError::WrongNumberOfGenericArgs),
119 }
120 }
121
122 fn specialize(
123 &self,
124 context: &dyn SpecializationContext,
125 args: &[GenericArg],
126 ) -> Result<Self::Concrete, SpecializationError> {
127 match args {
128 [] => Ok({
129 Felt252BinaryOpConcreteLibfunc {
130 operator: self.operator,
131 signature: self.specialize_signature(context.upcast(), args)?,
132 }
133 }),
134 _ => Err(SpecializationError::WrongNumberOfGenericArgs),
135 }
136 }
137}
138
139pub struct Felt252BinaryOperationWithConstLibfunc {
141 pub operator: Felt252BinaryOperator,
142}
143impl Felt252BinaryOperationWithConstLibfunc {
144 fn new(operator: Felt252BinaryOperator) -> Self {
145 Self { operator }
146 }
147 const ADD: &'static str = "felt252_add_const";
148 const SUB: &'static str = "felt252_sub_const";
149 const MUL: &'static str = "felt252_mul_const";
150 const DIV: &'static str = "felt252_div_const";
151}
152impl GenericLibfunc for Felt252BinaryOperationWithConstLibfunc {
153 type Concrete = Felt252OperationWithConstConcreteLibfunc;
154
155 fn supported_ids() -> Vec<GenericLibfuncId> {
156 vec![
157 GenericLibfuncId::from(Self::ADD),
158 GenericLibfuncId::from(Self::SUB),
159 GenericLibfuncId::from(Self::MUL),
160 GenericLibfuncId::from(Self::DIV),
161 ]
162 }
163
164 fn by_id(id: &GenericLibfuncId) -> Option<Self> {
165 match id.0.as_str() {
166 Self::ADD => Some(Self::new(Felt252BinaryOperator::Add)),
167 Self::SUB => Some(Self::new(Felt252BinaryOperator::Sub)),
168 Self::MUL => Some(Self::new(Felt252BinaryOperator::Mul)),
169 Self::DIV => Some(Self::new(Felt252BinaryOperator::Div)),
170 _ => None,
171 }
172 }
173
174 fn specialize_signature(
175 &self,
176 context: &dyn SignatureSpecializationContext,
177 args: &[GenericArg],
178 ) -> Result<LibfuncSignature, SpecializationError> {
179 let ty = context.get_concrete_type(Felt252Type::id(), &[])?;
180 match args {
181 [GenericArg::Value(c)] => {
182 let output_ref_info = if matches!(self.operator, Felt252BinaryOperator::Div) {
183 if c.is_zero() {
184 return Err(SpecializationError::UnsupportedGenericArg);
185 }
186 OutputVarReferenceInfo::NewTempVar { idx: 0 }
187 } else {
188 OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic)
189 };
190
191 Ok(LibfuncSignature::new_non_branch(
192 vec![ty.clone()],
193 vec![OutputVarInfo { ty, ref_info: output_ref_info }],
194 SierraApChange::Known { new_vars_only: true },
195 ))
196 }
197 _ => Err(SpecializationError::WrongNumberOfGenericArgs),
198 }
199 }
200
201 fn specialize(
202 &self,
203 context: &dyn SpecializationContext,
204 args: &[GenericArg],
205 ) -> Result<Self::Concrete, SpecializationError> {
206 match args {
207 [GenericArg::Value(c)] => {
208 if matches!(self.operator, Felt252BinaryOperator::Div) && c.is_zero() {
209 Err(SpecializationError::UnsupportedGenericArg)
210 } else {
211 Ok(Felt252OperationWithConstConcreteLibfunc {
212 operator: self.operator,
213 c: c.clone(),
214 signature: self.specialize_signature(context.upcast(), args)?,
215 })
216 }
217 }
218 _ => Err(SpecializationError::WrongNumberOfGenericArgs),
219 }
220 }
221}
222
223pub struct Felt252BinaryOpConcreteLibfunc {
224 pub operator: Felt252BinaryOperator,
225 pub signature: LibfuncSignature,
226}
227impl SignatureBasedConcreteLibfunc for Felt252BinaryOpConcreteLibfunc {
228 fn signature(&self) -> &LibfuncSignature {
229 &self.signature
230 }
231}
232
233pub struct Felt252OperationWithConstConcreteLibfunc {
235 pub operator: Felt252BinaryOperator,
236 pub c: BigInt,
237 pub signature: LibfuncSignature,
238}
239
240impl SignatureBasedConcreteLibfunc for Felt252OperationWithConstConcreteLibfunc {
241 fn signature(&self) -> &LibfuncSignature {
242 &self.signature
243 }
244}
245
246#[derive(Default)]
248pub struct Felt252ConstLibfunc {}
249impl NamedLibfunc for Felt252ConstLibfunc {
250 type Concrete = Felt252ConstConcreteLibfunc;
251 const STR_ID: &'static str = "felt252_const";
252
253 fn specialize_signature(
254 &self,
255 context: &dyn SignatureSpecializationContext,
256 _args: &[GenericArg],
257 ) -> Result<LibfuncSignature, SpecializationError> {
258 Ok(LibfuncSignature::new_non_branch(
259 vec![],
260 vec![OutputVarInfo {
261 ty: context.get_concrete_type(Felt252Type::id(), &[])?,
262 ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Const),
263 }],
264 SierraApChange::Known { new_vars_only: true },
265 ))
266 }
267
268 fn specialize(
269 &self,
270 context: &dyn SpecializationContext,
271 args: &[GenericArg],
272 ) -> Result<Self::Concrete, SpecializationError> {
273 match args {
274 [GenericArg::Value(c)] => Ok(Felt252ConstConcreteLibfunc {
275 c: c.clone(),
276 signature: <Self as NamedLibfunc>::specialize_signature(
277 self,
278 context.upcast(),
279 args,
280 )?,
281 }),
282 _ => Err(SpecializationError::UnsupportedGenericArg),
283 }
284 }
285}
286
287pub struct Felt252ConstConcreteLibfunc {
288 pub c: BigInt,
289 pub signature: LibfuncSignature,
290}
291impl SignatureBasedConcreteLibfunc for Felt252ConstConcreteLibfunc {
292 fn signature(&self) -> &LibfuncSignature {
293 &self.signature
294 }
295}