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 inputs(&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 outputs(&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!("{}_loop", entrypoint);
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"), 0x7768250498bfbb26.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>) {
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 }
107
108 fn pseudorandom_args(
109 &self,
110 seed: [u8; 32],
111 bench_case: Option<BenchmarkCase>,
112 ) -> Self::Args {
113 let mut rng = StdRng::from_seed(seed);
114 let exponent = match bench_case {
115 Some(BenchmarkCase::CommonCase) => 20,
116 Some(BenchmarkCase::WorstCase) => 31,
117 None => rng.random_range(0..32),
118 };
119
120 (exponent, rng.random())
121 }
122
123 fn corner_case_args(&self) -> Vec<Self::Args> {
124 (0..=5)
125 .chain([30, 31])
126 .map(|log_2_exp| (log_2_exp, xfe!([14; 3])))
127 .collect()
128 }
129 }
130
131 #[test]
132 fn rust_shadow() {
133 ShadowedClosure::new(ToThePowerOfPowerOf2).test()
134 }
135
136 #[test]
137 fn compare_to_generic_pow_u32() {
138 let base = rand::random();
139 for log_2_exponent in 0..32 {
140 let final_pow_pow_stack = test_rust_equivalence_given_complete_state(
141 &ShadowedClosure::new(ToThePowerOfPowerOf2),
142 &ToThePowerOfPowerOf2.set_up_test_stack((log_2_exponent, base)),
143 &[],
144 &NonDeterminism::default(),
145 &None,
146 None,
147 )
148 .op_stack
149 .stack;
150
151 let final_generic_stack = test_rust_equivalence_given_complete_state(
152 &ShadowedClosure::new(XfeModPowU32),
153 &XfeModPowU32.set_up_test_stack((2_u32.pow(log_2_exponent), base)),
154 &[],
155 &NonDeterminism::default(),
156 &None,
157 None,
158 )
159 .op_stack
160 .stack;
161
162 assert_eq!(19, final_pow_pow_stack.len());
164 assert_eq!(19, final_generic_stack.len());
165 assert_eq!(final_pow_pow_stack[16..=18], final_generic_stack[16..=18],);
166 }
167 }
168}
169
170#[cfg(test)]
171mod benches {
172 use super::*;
173 use crate::test_prelude::*;
174
175 #[test]
176 fn benchmark() {
177 ShadowedClosure::new(ToThePowerOfPowerOf2).bench();
178 }
179}