tasm_lib/arithmetic/u128/
shift_left.rs1use std::collections::HashMap;
2
3use triton_vm::prelude::*;
4
5use crate::arithmetic::u128::shift_right::ShiftRight;
6use crate::prelude::*;
7use crate::traits::basic_snippet::Reviewer;
8use crate::traits::basic_snippet::SignOffFingerprint;
9
10#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
32pub struct ShiftLeft;
33
34impl ShiftLeft {
35 pub const SHIFT_AMOUNT_TOO_BIG_ERROR_ID: i128 = 530;
36}
37
38impl BasicSnippet for ShiftLeft {
39 fn inputs(&self) -> Vec<(DataType, String)> {
40 ShiftRight.inputs()
41 }
42
43 fn outputs(&self) -> Vec<(DataType, String)> {
44 ShiftRight.outputs()
45 }
46
47 fn entrypoint(&self) -> String {
48 "tasmlib_arithmetic_u128_shift_left".to_string()
49 }
50
51 fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
52 let entrypoint = self.entrypoint();
53 let shift_amount_gt_32 = format!("{entrypoint}_shift_amount_gt_32");
54
55 triton_asm!(
56 {entrypoint}:
59 push 128
61 dup 1
62 lt
63 assert error_id {Self::SHIFT_AMOUNT_TOO_BIG_ERROR_ID}
64 dup 0
68 push 32
69 lt
70 skiz
71 call {shift_amount_gt_32}
72 push 2
75 pow dup 0
78 pick 5 mul
80 place 4 xb_mul pick 3
84 split
85 pick 4
86 split
87 pick 5
88 split
89 pick 6
90 split place 7
93 add
94 place 6
95 add
96 place 5
97 add
98 place 4
99 pop 1
100
101 return
102
103 {shift_amount_gt_32}:
107 addi -32 pick 4
109 pop 1 push 0
111 place 1 dup 0
114 push 32
115 lt
116 skiz
117 recurse
118 return
119 )
120 }
121
122 fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
123 let mut sign_offs = HashMap::new();
124 sign_offs.insert(Reviewer("ferdinand"), 0x4898e915d48c39b7.into());
125 sign_offs
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 use crate::test_prelude::*;
133 use rand::rngs::StdRng;
134
135 impl Closure for ShiftLeft {
136 type Args = <ShiftRight as Closure>::Args;
137
138 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
139 let (arg, shift_amount) = pop_encodable::<Self::Args>(stack);
140 assert!(shift_amount < 128);
141 push_encodable(stack, &(arg << shift_amount));
142 }
143
144 fn pseudorandom_args(
145 &self,
146 seed: [u8; 32],
147 bench_case: Option<BenchmarkCase>,
148 ) -> Self::Args {
149 let mut rng = StdRng::from_seed(seed);
150
151 match bench_case {
152 Some(BenchmarkCase::CommonCase) => (0x1282, 15),
153 Some(BenchmarkCase::WorstCase) => (0x123456789abcdef, 125),
154 None => (rng.random(), rng.random_range(0..128)),
155 }
156 }
157
158 fn corner_case_args(&self) -> Vec<Self::Args> {
159 ShiftRight.corner_case_args()
160 }
161 }
162
163 #[test]
164 fn rust_shadow() {
165 ShadowedClosure::new(ShiftLeft).test();
166 }
167
168 #[proptest]
169 fn too_large_shift_crashes_vm(arg: u128, #[strategy(128_u32..)] shift_amount: u32) {
170 test_assertion_failure(
171 &ShadowedClosure::new(ShiftLeft),
172 InitVmState::with_stack(ShiftLeft.set_up_test_stack((arg, shift_amount))),
173 &[ShiftLeft::SHIFT_AMOUNT_TOO_BIG_ERROR_ID],
174 )
175 }
176}
177
178#[cfg(test)]
179mod benches {
180 use super::*;
181 use crate::test_prelude::*;
182
183 #[test]
184 fn benchmark() {
185 ShadowedClosure::new(ShiftLeft).bench();
186 }
187}