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![OutputVarInfo::new_builtin(range_check_type, 0), OutputVarInfo {
107                ty: context.get_concrete_type(Uint128Type::id(), &[])?,
108                ref_info: OutputVarReferenceInfo::SimpleDerefs,
109            }],
110            SierraApChange::Known { new_vars_only: false },
111        ))
112    }
113}
114
115/// Inverse Modulo N.
116///
117/// Libfunc for calculating the inverse of a number modulo N.
118/// If `N == 1`, the value is not considered invertible.
119#[derive(Default)]
120pub struct Uint256InvModNLibfunc;
121impl NoGenericArgsGenericLibfunc for Uint256InvModNLibfunc {
122    const STR_ID: &'static str = "u256_guarantee_inv_mod_n";
123
124    fn specialize_signature(
125        &self,
126        context: &dyn SignatureSpecializationContext,
127    ) -> Result<LibfuncSignature, SpecializationError> {
128        let u256_ty = get_u256_type(context)?;
129        let nz_ty = nonzero_ty(context, &u256_ty)?;
130        let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
131        let rc_output = OutputVarInfo::new_builtin(range_check_type.clone(), 0);
132        let guarantee_output = OutputVarInfo {
133            ty: context.get_concrete_type(U128MulGuaranteeType::id(), &[])?,
134            ref_info: OutputVarReferenceInfo::SimpleDerefs,
135        };
136        Ok(LibfuncSignature {
137            param_signatures: vec![
138                // Range check.
139                ParamSignature::new(range_check_type).with_allow_add_const(),
140                // b (divisor).
141                ParamSignature::new(u256_ty),
142                // n (modulus).
143                ParamSignature::new(nz_ty.clone()),
144            ],
145            branch_signatures: vec![
146                // If the divisor has an inverse modulo n.
147                BranchSignature {
148                    vars: vec![
149                        rc_output.clone(),
150                        OutputVarInfo { ty: nz_ty, ref_info: OutputVarReferenceInfo::SimpleDerefs },
151                        guarantee_output.clone(),
152                        guarantee_output.clone(),
153                        guarantee_output.clone(),
154                        guarantee_output.clone(),
155                        guarantee_output.clone(),
156                        guarantee_output.clone(),
157                        guarantee_output.clone(),
158                        guarantee_output.clone(),
159                    ],
160                    ap_change: SierraApChange::Known { new_vars_only: false },
161                },
162                // The divisor does not have an inverse modulo n.
163                BranchSignature {
164                    vars: vec![rc_output, guarantee_output.clone(), guarantee_output],
165                    ap_change: SierraApChange::Known { new_vars_only: false },
166                },
167            ],
168            fallthrough: Some(0),
169        })
170    }
171}