tasm_lib/arithmetic/u64/
pow2.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, Clone, Copy, Eq, PartialEq, Hash)]
26pub struct Pow2;
27
28impl Pow2 {
29 pub const INPUT_TOO_LARGE_ERROR_ID: i128 = 360;
30}
31
32impl BasicSnippet for Pow2 {
33 fn inputs(&self) -> Vec<(DataType, String)> {
34 vec![(DataType::U32, "arg".to_string())]
35 }
36
37 fn outputs(&self) -> Vec<(DataType, String)> {
38 vec![(DataType::U64, "(2^arg)".to_string())]
39 }
40
41 fn entrypoint(&self) -> String {
42 "tasmlib_arithmetic_u64_pow2".to_string()
43 }
44
45 fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
46 triton_asm! {
47 {self.entrypoint()}:
48 push 64
49 dup 1
50 lt
51 assert error_id {Self::INPUT_TOO_LARGE_ERROR_ID}
52
53 push 2
54 pow
55 split
56 return
57 }
58 }
59
60 fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
61 let mut sign_offs = HashMap::new();
62 sign_offs.insert(Reviewer("ferdinand"), 0x3ea5807c1e92829b.into());
63 sign_offs
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use crate::test_prelude::*;
71
72 impl Pow2 {
73 fn assert_expected_behavior(&self, arg: u32) {
74 let initial_stack = self.set_up_test_stack(arg);
75
76 let mut expected_stack = initial_stack.clone();
77 self.rust_shadow(&mut expected_stack);
78
79 test_rust_equivalence_given_complete_state(
80 &ShadowedClosure::new(Self),
81 &initial_stack,
82 &[],
83 &NonDeterminism::default(),
84 &None,
85 Some(&expected_stack),
86 );
87 }
88 }
89
90 impl Closure for Pow2 {
91 type Args = u32;
92
93 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
94 let arg = pop_encodable::<Self::Args>(stack);
95 push_encodable(stack, &2_u64.pow(arg));
96 }
97
98 fn pseudorandom_args(
99 &self,
100 seed: [u8; 32],
101 bench_case: Option<BenchmarkCase>,
102 ) -> Self::Args {
103 let Some(bench_case) = bench_case else {
104 return StdRng::from_seed(seed).random_range(0..64);
105 };
106
107 match bench_case {
108 BenchmarkCase::CommonCase => 31,
109 BenchmarkCase::WorstCase => 63,
110 }
111 }
112 }
113
114 #[test]
115 fn rust_shadow() {
116 ShadowedClosure::new(Pow2).test();
117 }
118
119 #[test]
120 fn unit_test() {
121 for arg in 0..64 {
122 Pow2.assert_expected_behavior(arg);
123 }
124 }
125
126 #[proptest]
127 fn negative_property_test(#[strategy(64_u32..)] arg: u32) {
128 let stack = Pow2.set_up_test_stack(arg);
129
130 test_assertion_failure(
131 &ShadowedClosure::new(Pow2),
132 InitVmState::with_stack(stack),
133 &[Pow2::INPUT_TOO_LARGE_ERROR_ID],
134 );
135 }
136}
137
138#[cfg(test)]
139mod benches {
140 use super::*;
141 use crate::test_prelude::*;
142
143 #[test]
144 fn benchmark() {
145 ShadowedClosure::new(Pow2).bench();
146 }
147}