tasm_lib/arithmetic/u64/
trailing_zeros.rs1use std::collections::HashMap;
2
3use triton_vm::prelude::*;
4
5use crate::arithmetic::u32::trailing_zeros::TrailingZeros as U32TrailingZeros;
6use crate::prelude::*;
7use crate::traits::basic_snippet::Reviewer;
8use crate::traits::basic_snippet::SignOffFingerprint;
9
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
29pub struct TrailingZeros;
30
31impl BasicSnippet for TrailingZeros {
32 fn parameters(&self) -> Vec<(DataType, String)> {
33 vec![(DataType::U64, "arg".to_string())]
34 }
35
36 fn return_values(&self) -> Vec<(DataType, String)> {
37 vec![(DataType::U32, "trailing_zeros(arg)".to_string())]
38 }
39
40 fn entrypoint(&self) -> String {
41 "tasmlib_arithmetic_u64_trailing_zeros".to_string()
42 }
43
44 fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
45 let u32_trailing_zeros = library.import(Box::new(U32TrailingZeros));
46
47 let entrypoint = self.entrypoint();
48 let hi_bits_dominate = format!("{entrypoint}_hi_bits_dominate");
49 let lo_bits_dominate = format!("{entrypoint}_lo_bits_dominate");
50
51 triton_asm! {
52 {entrypoint}:
55 push 1
56 dup 1
57 push 0
58 eq
59 skiz call {hi_bits_dominate}
62 skiz call {lo_bits_dominate}
63 return
66
67 {hi_bits_dominate}:
71 pop 2
72 call {u32_trailing_zeros}
73 addi 32
74 push 0
75 return
76
77 {lo_bits_dominate}:
81 pick 1
82 pop 1
83 call {u32_trailing_zeros}
84 return
85 }
86 }
87
88 fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
89 let mut sign_offs = HashMap::new();
90 sign_offs.insert(Reviewer("ferdinand"), 0xf8428d5ca58ed29f.into());
91 sign_offs
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use crate::test_prelude::*;
99
100 impl Closure for TrailingZeros {
101 type Args = u64;
102
103 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) -> Result<(), RustShadowError> {
104 let arg = pop_encodable::<Self::Args>(stack)?;
105 push_encodable(stack, &arg.trailing_zeros());
106 Ok(())
107 }
108
109 fn pseudorandom_args(
110 &self,
111 seed: [u8; 32],
112 bench_case: Option<BenchmarkCase>,
113 ) -> Self::Args {
114 match bench_case {
115 Some(BenchmarkCase::CommonCase) => 0b1111_1111 << 15,
116 Some(BenchmarkCase::WorstCase) => 1 << 63,
117 None => StdRng::from_seed(seed).random(),
118 }
119 }
120
121 fn corner_case_args(&self) -> Vec<Self::Args> {
122 [1, 1 << 31, 1 << 32, 1 << 33, 1 << 63, u64::MAX - 1]
123 .into_iter()
124 .flat_map(|i| [i - 1, i, i + 1])
125 .collect()
126 }
127 }
128
129 #[macro_rules_attr::apply(test)]
130 fn unit() {
131 ShadowedClosure::new(TrailingZeros).test();
132 }
133}
134
135#[cfg(test)]
136mod benches {
137 use super::*;
138 use crate::test_prelude::*;
139
140 #[macro_rules_attr::apply(test)]
141 fn benchmark() {
142 ShadowedClosure::new(TrailingZeros).bench()
143 }
144}