tasm_lib/arithmetic/xfe/
mod_pow_u32.rs1use triton_vm::prelude::*;
2
3use crate::prelude::*;
4
5#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
6pub struct XfeModPowU32;
7
8impl BasicSnippet for XfeModPowU32 {
9 fn inputs(&self) -> Vec<(DataType, String)> {
10 vec![
11 (DataType::U32, "exponent".to_owned()),
12 (DataType::Xfe, "base".to_owned()),
13 ]
14 }
15
16 fn outputs(&self) -> Vec<(DataType, String)> {
17 vec![(DataType::Xfe, "result".to_owned())]
18 }
19
20 fn entrypoint(&self) -> String {
21 "tasmlib_arithmetic_xfe_mod_pow_u32".to_owned()
22 }
23
24 fn code(&self, _library: &mut Library) -> Vec<LabelledInstruction> {
28 let entrypoint = self.entrypoint();
48 let loop_code_label = format!("{entrypoint}_loop");
49 let acc_mul_x_label = format!("{entrypoint}_acc_mul_x");
50
51 triton_asm!(
52 {entrypoint}:
53 push 0
56 push 0
57 push 1
58 call {loop_code_label}
64 swap 4
67 pop 1
68 swap 4
69 pop 1
70 swap 4
71 pop 2
72 return
75
76 {loop_code_label}:
78
79 dup 6
81 push 0
82 eq
83 skiz
84 return
85 dup 6
88 push 1
89 and
90 skiz
93 call {acc_mul_x_label}
94
95 dup 5 dup 5 dup 5
98 dup 2 dup 2 dup 2
99 xx_mul
102 swap 6
105 pop 1
106 swap 6
107 pop 1
108 swap 6
109 pop 1
110 swap 6
113 push 2
116 swap 1
117 div_mod
120 pop 1
121 swap 6
124 recurse
128
129 {acc_mul_x_label}:
130 dup 5
133 dup 5
134 dup 5
135 xx_mul
136 return
139 )
140 }
141}
142
143#[cfg(test)]
144pub mod tests {
145 use twenty_first::math::traits::ModPowU32;
146
147 use super::*;
148 use crate::empty_stack;
149 use crate::execute_with_terminal_state;
150 use crate::test_prelude::*;
151
152 impl Closure for XfeModPowU32 {
153 type Args = (u32, XFieldElement);
154
155 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
156 let (exponent, base) = pop_encodable::<Self::Args>(stack);
157 let result = base.mod_pow_u32(exponent);
158 push_encodable(stack, &result);
159 }
160
161 fn pseudorandom_args(
162 &self,
163 seed: [u8; 32],
164 bench_case: Option<BenchmarkCase>,
165 ) -> Self::Args {
166 let mut rng = StdRng::from_seed(seed);
167 let exponent = match bench_case {
168 Some(BenchmarkCase::CommonCase) => 1 << 25,
169 Some(BenchmarkCase::WorstCase) => u32::MAX,
170 None => rng.random(),
171 };
172
173 (exponent, rng.random())
174 }
175
176 fn corner_case_args(&self) -> Vec<Self::Args> {
177 let an_xfe = xfe!([14; 3]);
178
179 (0..=5)
180 .chain([u32::MAX - 1, u32::MAX])
181 .map(|exp| (exp, an_xfe))
182 .collect()
183 }
184 }
185
186 #[test]
187 fn mod_pow_u32_xfe_pbt() {
188 ShadowedClosure::new(XfeModPowU32).test()
189 }
190
191 #[test]
192 fn verify_crash_if_exponent_not_u32() {
193 let bfe_14 = BFieldElement::new(14);
194 let xfe_14 = XFieldElement::new([bfe_14, bfe_14, bfe_14]);
195 let xfe_14: Vec<_> = xfe_14.coefficients.into_iter().rev().collect();
196 let code = XfeModPowU32.link_for_isolated_run();
197
198 for exponent in [
199 1 << 32,
200 1 << 33,
201 1 << 32,
202 1 << 63,
203 BFieldElement::MAX - 1,
204 BFieldElement::MAX,
205 ] {
206 let init_stack = [empty_stack(), bfe_vec![exponent], xfe_14.clone()].concat();
207 let tvm_result = execute_with_terminal_state(
208 Program::new(&code),
209 &[],
210 &init_stack,
211 &NonDeterminism::default(),
212 None,
213 );
214 assert!(matches!(
215 tvm_result.unwrap_err(),
216 InstructionError::OpStackError(OpStackError::FailedU32Conversion(_))
217 ));
218 }
219 }
220}
221
222#[cfg(test)]
223mod benches {
224 use super::*;
225 use crate::test_prelude::*;
226
227 #[test]
228 fn benchmark() {
229 ShadowedClosure::new(XfeModPowU32).bench();
230 }
231}