cairo_lang_sierra/extensions/modules/int/
mod.rs

1use std::marker::PhantomData;
2
3use num_bigint::BigInt;
4
5use super::felt252::Felt252Type;
6use super::try_from_felt252::{TryFromFelt252, TryFromFelt252Libfunc};
7use super::utils::reinterpret_cast_signature;
8use crate::extensions::lib_func::{
9    BranchSignature, DeferredOutputKind, LibfuncSignature, OutputVarInfo, ParamSignature,
10    SierraApChange, SignatureSpecializationContext, SpecializationContext,
11};
12use crate::extensions::{
13    NamedLibfunc, NamedType, NoGenericArgsGenericLibfunc, NoGenericArgsGenericType,
14    OutputVarReferenceInfo, SignatureBasedConcreteLibfunc, SpecializationError,
15};
16use crate::ids::GenericTypeId;
17use crate::program::GenericArg;
18
19pub mod signed;
20pub mod signed128;
21pub mod unsigned;
22pub mod unsigned128;
23pub mod unsigned256;
24pub mod unsigned512;
25
26/// Operators for integers.
27#[derive(Copy, Clone, Debug, PartialEq, Eq)]
28pub enum IntOperator {
29    OverflowingAdd,
30    OverflowingSub,
31}
32
33pub struct IntOperationConcreteLibfunc {
34    pub operator: IntOperator,
35    pub signature: LibfuncSignature,
36}
37impl SignatureBasedConcreteLibfunc for IntOperationConcreteLibfunc {
38    fn signature(&self) -> &LibfuncSignature {
39        &self.signature
40    }
41}
42
43/// Trait for implementing integers.
44pub trait IntTraits: Default {
45    /// The rust matching type to this type.
46    type IntType: TryFrom<BigInt> + Into<BigInt> + Copy;
47    /// Is the type smaller than 128 bits.
48    /// Relevant since some implementations are different due to range check being 128 bits based.
49    const IS_SMALL: bool;
50    /// The generic type id for this type.
51    const GENERIC_TYPE_ID: GenericTypeId;
52    /// The generic libfunc id for getting a const of this type.
53    const CONST: &'static str;
54    /// The generic libfunc id for comparing equality.
55    const EQUAL: &'static str;
56    /// The generic libfunc id for conversion to felt252.
57    const TO_FELT252: &'static str;
58    /// The generic libfunc id for conversion from felt252.
59    const TRY_FROM_FELT252: &'static str;
60}
61
62/// Trait for implementing multiplication for integers.
63pub trait IntMulTraits: IntTraits {
64    /// The generic libfunc id that multiplies two integers.
65    const WIDE_MUL: &'static str;
66    /// The generic type id for this type multiplication result.
67    const WIDE_MUL_RES_TYPE_ID: GenericTypeId;
68}
69
70#[derive(Default)]
71pub struct IntType<TIntTraits: IntTraits> {
72    _phantom: PhantomData<TIntTraits>,
73}
74impl<TIntTraits: IntTraits> NoGenericArgsGenericType for IntType<TIntTraits> {
75    const ID: GenericTypeId = TIntTraits::GENERIC_TYPE_ID;
76    const STORABLE: bool = true;
77    const DUPLICATABLE: bool = true;
78    const DROPPABLE: bool = true;
79    const ZERO_SIZED: bool = false;
80}
81
82/// Libfunc for creating a constant integer.
83#[derive(Default)]
84pub struct IntConstLibfunc<TIntTraits: IntTraits> {
85    _phantom: PhantomData<TIntTraits>,
86}
87impl<TIntTraits: IntTraits> NamedLibfunc for IntConstLibfunc<TIntTraits> {
88    const STR_ID: &'static str = TIntTraits::CONST;
89    type Concrete = IntConstConcreteLibfunc<TIntTraits>;
90
91    fn specialize_signature(
92        &self,
93        context: &dyn SignatureSpecializationContext,
94        _args: &[GenericArg],
95    ) -> Result<LibfuncSignature, SpecializationError> {
96        Ok(LibfuncSignature::new_non_branch(
97            vec![],
98            vec![OutputVarInfo {
99                ty: context.get_concrete_type(TIntTraits::GENERIC_TYPE_ID, &[])?,
100                ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Const),
101            }],
102            SierraApChange::Known { new_vars_only: true },
103        ))
104    }
105
106    fn specialize(
107        &self,
108        context: &dyn SpecializationContext,
109        args: &[GenericArg],
110    ) -> Result<Self::Concrete, SpecializationError> {
111        match args {
112            [GenericArg::Value(c)] => Ok(Self::Concrete {
113                c: TIntTraits::IntType::try_from(c.clone())
114                    .map_err(|_| SpecializationError::UnsupportedGenericArg)?,
115                signature: <Self as NamedLibfunc>::specialize_signature(
116                    self,
117                    context.upcast(),
118                    args,
119                )?,
120            }),
121            _ => Err(SpecializationError::UnsupportedGenericArg),
122        }
123    }
124}
125
126pub struct IntConstConcreteLibfunc<TIntTraits: IntTraits> {
127    pub c: TIntTraits::IntType,
128    pub signature: LibfuncSignature,
129}
130impl<TIntTraits: IntTraits> SignatureBasedConcreteLibfunc for IntConstConcreteLibfunc<TIntTraits> {
131    fn signature(&self) -> &LibfuncSignature {
132        &self.signature
133    }
134}
135
136/// Libfunc for comparing integers` equality.
137#[derive(Default)]
138pub struct IntEqualLibfunc<TIntTraits: IntTraits> {
139    _phantom: PhantomData<TIntTraits>,
140}
141impl<TIntTraits: IntTraits> NoGenericArgsGenericLibfunc for IntEqualLibfunc<TIntTraits> {
142    const STR_ID: &'static str = TIntTraits::EQUAL;
143
144    fn specialize_signature(
145        &self,
146        context: &dyn SignatureSpecializationContext,
147    ) -> Result<LibfuncSignature, SpecializationError> {
148        let ty = context.get_concrete_type(TIntTraits::GENERIC_TYPE_ID, &[])?;
149        let param_signatures =
150            vec![ParamSignature::new(ty.clone()), ParamSignature::new(ty).with_allow_const()];
151        let branch_signatures = (0..2)
152            .map(|_| BranchSignature {
153                vars: vec![],
154                ap_change: SierraApChange::Known { new_vars_only: false },
155            })
156            .collect();
157        Ok(LibfuncSignature { param_signatures, branch_signatures, fallthrough: Some(0) })
158    }
159}
160
161/// Libfunc for converting an integer into a felt252.
162#[derive(Default)]
163pub struct IntToFelt252Libfunc<TIntTraits: IntTraits> {
164    _phantom: PhantomData<TIntTraits>,
165}
166impl<TIntTraits: IntTraits> NoGenericArgsGenericLibfunc for IntToFelt252Libfunc<TIntTraits> {
167    const STR_ID: &'static str = TIntTraits::TO_FELT252;
168
169    fn specialize_signature(
170        &self,
171        context: &dyn SignatureSpecializationContext,
172    ) -> Result<LibfuncSignature, SpecializationError> {
173        Ok(reinterpret_cast_signature(
174            context.get_concrete_type(TIntTraits::GENERIC_TYPE_ID, &[])?,
175            context.get_concrete_type(Felt252Type::id(), &[])?,
176        ))
177    }
178}
179
180/// Libfunc for attempting to convert a felt252 into an integer.
181#[derive(Default)]
182pub struct IntFromFelt252Trait<TIntTraits: IntTraits> {
183    _phantom: PhantomData<TIntTraits>,
184}
185impl<TIntTraits: IntTraits> TryFromFelt252 for IntFromFelt252Trait<TIntTraits> {
186    const STR_ID: &'static str = TIntTraits::TRY_FROM_FELT252;
187    const GENERIC_TYPE_ID: GenericTypeId = TIntTraits::GENERIC_TYPE_ID;
188}
189
190pub type IntFromFelt252Libfunc<T> = TryFromFelt252Libfunc<IntFromFelt252Trait<T>>;
191/// Libfunc for integer wide multiplication.
192#[derive(Default)]
193pub struct IntWideMulLibfunc<TIntMulTraits: IntMulTraits> {
194    _phantom: PhantomData<TIntMulTraits>,
195}
196impl<TIntMulTraits: IntMulTraits> NoGenericArgsGenericLibfunc for IntWideMulLibfunc<TIntMulTraits> {
197    const STR_ID: &'static str = TIntMulTraits::WIDE_MUL;
198
199    fn specialize_signature(
200        &self,
201        context: &dyn SignatureSpecializationContext,
202    ) -> Result<LibfuncSignature, SpecializationError> {
203        let ty = context.get_concrete_type(TIntMulTraits::GENERIC_TYPE_ID, &[])?;
204        Ok(LibfuncSignature::new_non_branch_ex(
205            vec![ParamSignature::new(ty.clone()), ParamSignature::new(ty).with_allow_const()],
206            vec![OutputVarInfo {
207                ty: context.get_concrete_type(TIntMulTraits::WIDE_MUL_RES_TYPE_ID, &[])?,
208                ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
209            }],
210            SierraApChange::Known { new_vars_only: true },
211        ))
212    }
213}