tasm_lib/arithmetic/xfe/
to_the_power_of_power_of_2.rs1use std::collections::HashMap;
2
3use triton_vm::prelude::*;
4
5use crate::prelude::*;
6use crate::traits::basic_snippet::Reviewer;
7use crate::traits::basic_snippet::SignOffFingerprint;
8
9#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
28pub struct ToThePowerOfPowerOf2;
29
30impl BasicSnippet for ToThePowerOfPowerOf2 {
31 fn parameters(&self) -> Vec<(DataType, String)> {
32 vec![
33 (DataType::U32, "log_2_exponent".to_owned()),
34 (DataType::Xfe, "base".to_owned()),
35 ]
36 }
37
38 fn return_values(&self) -> Vec<(DataType, String)> {
39 vec![(DataType::Xfe, "result".to_owned())]
40 }
41
42 fn entrypoint(&self) -> String {
43 "tasmlib_arithmetic_xfe_to_the_power_of_power_of_2".to_owned()
44 }
45
46 fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
47 let entrypoint = self.entrypoint();
48 let loop_label = format!("{entrypoint}_loop");
49
50 triton_asm!(
51 {entrypoint}:
52 call {loop_label}
53
54 pick 3
55 pop 1
56
57 return
58
59 {loop_label}:
61 dup 3
63 push 0
64 eq
65 skiz
66 return
67
68 dup 2
70 dup 2
71 dup 2
72 xx_mul
73 pick 3
76 addi -1
77 place 3
78 recurse
81 )
82 }
83
84 fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
85 let mut sign_offs = HashMap::new();
86 sign_offs.insert(Reviewer("ferdinand"), 0xd05170d4c435dfad.into());
87 sign_offs
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use twenty_first::math::traits::ModPowU32;
94
95 use super::*;
96 use crate::arithmetic::xfe::mod_pow_u32::XfeModPowU32;
97 use crate::test_prelude::*;
98
99 impl Closure for ToThePowerOfPowerOf2 {
100 type Args = (u32, XFieldElement);
101
102 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) -> Result<(), RustShadowError> {
103 let (exponent_log_2, base) = pop_encodable::<Self::Args>(stack)?;
104 let result = base.mod_pow_u32(2_u32.pow(exponent_log_2));
105 push_encodable(stack, &result);
106 Ok(())
107 }
108
109 fn pseudorandom_args(
110 &self,
111 seed: [u8; 32],
112 bench_case: Option<BenchmarkCase>,
113 ) -> Self::Args {
114 let mut rng = StdRng::from_seed(seed);
115 let exponent = match bench_case {
116 Some(BenchmarkCase::CommonCase) => 20,
117 Some(BenchmarkCase::WorstCase) => 31,
118 None => rng.random_range(0..32),
119 };
120
121 (exponent, rng.random())
122 }
123
124 fn corner_case_args(&self) -> Vec<Self::Args> {
125 (0..=5)
126 .chain([30, 31])
127 .map(|log_2_exp| (log_2_exp, xfe!([14; 3])))
128 .collect()
129 }
130 }
131
132 #[macro_rules_attr::apply(test)]
133 fn rust_shadow() {
134 ShadowedClosure::new(ToThePowerOfPowerOf2).test();
135 }
136
137 #[macro_rules_attr::apply(test)]
138 fn compare_to_generic_pow_u32() {
139 let base = rand::random();
140 for log_2_exponent in 0..32 {
141 let final_pow_pow_stack = test_rust_equivalence_given_complete_state(
142 &ShadowedClosure::new(ToThePowerOfPowerOf2),
143 &ToThePowerOfPowerOf2.set_up_test_stack((log_2_exponent, base)),
144 &[],
145 &NonDeterminism::default(),
146 &None,
147 None,
148 )
149 .op_stack
150 .stack;
151
152 let final_generic_stack = test_rust_equivalence_given_complete_state(
153 &ShadowedClosure::new(XfeModPowU32),
154 &XfeModPowU32.set_up_test_stack((2_u32.pow(log_2_exponent), base)),
155 &[],
156 &NonDeterminism::default(),
157 &None,
158 None,
159 )
160 .op_stack
161 .stack;
162
163 assert_eq!(19, final_pow_pow_stack.len());
165 assert_eq!(19, final_generic_stack.len());
166 assert_eq!(final_pow_pow_stack[16..=18], final_generic_stack[16..=18],);
167 }
168 }
169}
170
171#[cfg(test)]
172mod benches {
173 use super::*;
174 use crate::test_prelude::*;
175
176 #[macro_rules_attr::apply(test)]
177 fn benchmark() {
178 ShadowedClosure::new(ToThePowerOfPowerOf2).bench();
179 }
180}