Skip to main content

tasm_lib/arithmetic/u64/
wrapping_mul.rs

1use 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)]
10pub struct WrappingMul;
11
12impl BasicSnippet for WrappingMul {
13    fn parameters(&self) -> Vec<(DataType, String)> {
14        ["rhs", "lhs"]
15            .map(|side| (DataType::U64, side.to_string()))
16            .to_vec()
17    }
18
19    fn return_values(&self) -> Vec<(DataType, String)> {
20        vec![(DataType::U64, "product".to_string())]
21    }
22
23    fn entrypoint(&self) -> String {
24        "tasmlib_arithmetic_u64_wrapping_mul".to_string()
25    }
26
27    fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
28        triton_asm!(
29            // BEFORE: _ right_hi right_lo left_hi left_lo
30            // AFTER:  _ prod_hi prod_lo
31            {self.entrypoint()}:
32                /* left_lo · right_lo */
33                dup 0
34                dup 3
35                mul
36                // _ right_hi right_lo left_hi left_lo (left_lo · right_lo)
37
38                /* left_lo · right_hi (consume both) */
39                swap 4
40                mul
41                // _ (left_lo · right_lo) right_lo left_hi (left_lo · right_hi)
42
43                /* left_hi · right_lo (consume both) */
44                swap 2
45                mul
46                // _ (left_lo · right_lo) (left_lo · right_hi) (left_hi · right_lo)
47                // _ lolo                 lohi                 hilo
48
49                /* prod_hi = lolo_hi + lohi_lo + hilo_lo */
50                split
51                pick 1
52                pop 1
53                // _ lolo lohi hilo_lo
54
55                pick 1
56                split
57                pick 1
58                pop 1
59                // _ lolo hilo_lo lohi_lo
60
61                pick 2
62                split
63                // _ hilo_lo lohi_lo lolo_hi lolo_lo
64                // _ hilo_lo lohi_lo lolo_hi prod_lo
65
66                place 3
67                add
68                add
69                // _ prod_lo (hilo_lo + lohi_lo + lolo_hi)
70
71                split
72                pick 1
73                pop 1
74                // _ prod_lo (hilo_lo + lohi_lo + lolo_hi)_lo
75                // _ prod_lo prod_hi
76
77                place 1
78                return
79        )
80    }
81
82    fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
83        let mut sign_offs = HashMap::new();
84        sign_offs.insert(Reviewer("ferdinand"), 0xa50ce435d2381aca.into());
85        sign_offs
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use crate::test_prelude::*;
93
94    impl Closure for WrappingMul {
95        type Args = (u64, u64);
96
97        fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) -> Result<(), RustShadowError> {
98            let (right, left) = pop_encodable::<Self::Args>(stack)?;
99            push_encodable(stack, &left.wrapping_mul(right));
100            Ok(())
101        }
102
103        fn pseudorandom_args(
104            &self,
105            seed: [u8; 32],
106            bench_case: Option<BenchmarkCase>,
107        ) -> Self::Args {
108            match bench_case {
109                Some(BenchmarkCase::CommonCase) => (1 << 31, (1 << 25) - 1),
110                Some(BenchmarkCase::WorstCase) => (1 << 53, (1 << 33) - 1),
111                None => StdRng::from_seed(seed).random(),
112            }
113        }
114    }
115
116    #[macro_rules_attr::apply(test)]
117    fn rust_shadow() {
118        ShadowedClosure::new(WrappingMul).test();
119    }
120}
121
122#[cfg(test)]
123mod benches {
124    use super::*;
125    use crate::test_prelude::*;
126
127    #[macro_rules_attr::apply(test)]
128    fn benchmark() {
129        ShadowedClosure::new(WrappingMul).bench();
130    }
131}