cairo_lang_sierra/extensions/modules/int/
unsigned256.rs

1use super::unsigned128::{U128MulGuaranteeType, Uint128Type};
2use crate::define_libfunc_hierarchy;
3use crate::extensions::lib_func::{
4    BranchSignature, LibfuncSignature, OutputVarInfo, ParamSignature, SierraApChange,
5    SignatureSpecializationContext,
6};
7use crate::extensions::modules::get_u256_type;
8use crate::extensions::non_zero::nonzero_ty;
9use crate::extensions::range_check::RangeCheckType;
10use crate::extensions::{
11    NamedType, NoGenericArgsGenericLibfunc, OutputVarReferenceInfo, SpecializationError,
12};
13
14define_libfunc_hierarchy! {
15    pub enum Uint256Libfunc {
16        IsZero(Uint256IsZeroLibfunc),
17        Divmod(Uint256DivmodLibfunc),
18        SquareRoot(Uint256SquareRootLibfunc),
19        InvModN(Uint256InvModNLibfunc),
20    }, Uint256Concrete
21}
22
23// IsZero.
24#[derive(Default)]
25pub struct Uint256IsZeroLibfunc;
26impl NoGenericArgsGenericLibfunc for Uint256IsZeroLibfunc {
27    const STR_ID: &'static str = "u256_is_zero";
28
29    fn specialize_signature(
30        &self,
31        context: &dyn SignatureSpecializationContext,
32    ) -> Result<LibfuncSignature, SpecializationError> {
33        let u256_ty = get_u256_type(context)?;
34        Ok(LibfuncSignature {
35            param_signatures: vec![ParamSignature::new(u256_ty.clone())],
36            branch_signatures: vec![
37                // Zero.
38                BranchSignature {
39                    vars: vec![],
40                    ap_change: SierraApChange::Known { new_vars_only: true },
41                },
42                // NonZero.
43                BranchSignature {
44                    vars: vec![OutputVarInfo {
45                        ty: nonzero_ty(context, &u256_ty)?,
46                        ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
47                    }],
48                    ap_change: SierraApChange::Known { new_vars_only: true },
49                },
50            ],
51            fallthrough: Some(0),
52        })
53    }
54}
55
56// Divmod.
57#[derive(Default)]
58pub struct Uint256DivmodLibfunc;
59impl NoGenericArgsGenericLibfunc for Uint256DivmodLibfunc {
60    const STR_ID: &'static str = "u256_safe_divmod";
61
62    fn specialize_signature(
63        &self,
64        context: &dyn SignatureSpecializationContext,
65    ) -> Result<LibfuncSignature, SpecializationError> {
66        let u256_type = get_u256_type(context)?;
67        let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
68        let simple_deref_u256_output_info =
69            OutputVarInfo { ty: u256_type.clone(), ref_info: OutputVarReferenceInfo::SimpleDerefs };
70        Ok(LibfuncSignature::new_non_branch_ex(
71            vec![
72                ParamSignature::new(range_check_type.clone()).with_allow_add_const(),
73                ParamSignature::new(u256_type.clone()),
74                ParamSignature::new(nonzero_ty(context, &u256_type)?),
75            ],
76            vec![
77                OutputVarInfo::new_builtin(range_check_type, 0),
78                simple_deref_u256_output_info.clone(),
79                simple_deref_u256_output_info,
80                OutputVarInfo {
81                    ty: context.get_concrete_type(U128MulGuaranteeType::id(), &[])?,
82                    ref_info: OutputVarReferenceInfo::SimpleDerefs,
83                },
84            ],
85            SierraApChange::Known { new_vars_only: false },
86        ))
87    }
88}
89
90// Square root.
91#[derive(Default)]
92pub struct Uint256SquareRootLibfunc;
93impl NoGenericArgsGenericLibfunc for Uint256SquareRootLibfunc {
94    const STR_ID: &'static str = "u256_sqrt";
95
96    fn specialize_signature(
97        &self,
98        context: &dyn SignatureSpecializationContext,
99    ) -> Result<LibfuncSignature, SpecializationError> {
100        let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
101        Ok(LibfuncSignature::new_non_branch_ex(
102            vec![
103                ParamSignature::new(range_check_type.clone()).with_allow_add_const(),
104                ParamSignature::new(get_u256_type(context)?),
105            ],
106            vec![
107                OutputVarInfo::new_builtin(range_check_type, 0),
108                OutputVarInfo {
109                    ty: context.get_concrete_type(Uint128Type::id(), &[])?,
110                    ref_info: OutputVarReferenceInfo::SimpleDerefs,
111                },
112            ],
113            SierraApChange::Known { new_vars_only: false },
114        ))
115    }
116}
117
118/// Inverse Modulo N.
119///
120/// Libfunc for calculating the inverse of a number modulo N.
121/// If `N == 1`, the value is not considered invertible.
122#[derive(Default)]
123pub struct Uint256InvModNLibfunc;
124impl NoGenericArgsGenericLibfunc for Uint256InvModNLibfunc {
125    const STR_ID: &'static str = "u256_guarantee_inv_mod_n";
126
127    fn specialize_signature(
128        &self,
129        context: &dyn SignatureSpecializationContext,
130    ) -> Result<LibfuncSignature, SpecializationError> {
131        let u256_ty = get_u256_type(context)?;
132        let nz_ty = nonzero_ty(context, &u256_ty)?;
133        let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
134        let rc_output = OutputVarInfo::new_builtin(range_check_type.clone(), 0);
135        let guarantee_output = OutputVarInfo {
136            ty: context.get_concrete_type(U128MulGuaranteeType::id(), &[])?,
137            ref_info: OutputVarReferenceInfo::SimpleDerefs,
138        };
139        Ok(LibfuncSignature {
140            param_signatures: vec![
141                // Range check.
142                ParamSignature::new(range_check_type).with_allow_add_const(),
143                // b (divisor).
144                ParamSignature::new(u256_ty),
145                // n (modulus).
146                ParamSignature::new(nz_ty.clone()),
147            ],
148            branch_signatures: vec![
149                // If the divisor has an inverse modulo n.
150                BranchSignature {
151                    vars: vec![
152                        rc_output.clone(),
153                        OutputVarInfo { ty: nz_ty, ref_info: OutputVarReferenceInfo::SimpleDerefs },
154                        guarantee_output.clone(),
155                        guarantee_output.clone(),
156                        guarantee_output.clone(),
157                        guarantee_output.clone(),
158                        guarantee_output.clone(),
159                        guarantee_output.clone(),
160                        guarantee_output.clone(),
161                        guarantee_output.clone(),
162                    ],
163                    ap_change: SierraApChange::Known { new_vars_only: false },
164                },
165                // The divisor does not have an inverse modulo n.
166                BranchSignature {
167                    vars: vec![rc_output, guarantee_output.clone(), guarantee_output],
168                    ap_change: SierraApChange::Known { new_vars_only: false },
169                },
170            ],
171            fallthrough: Some(0),
172        })
173    }
174}