use triton_vm::prelude::*;
use crate::prelude::*;
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct ShiftLeftStatic<const N: u8>;
impl<const N: u8> BasicSnippet for ShiftLeftStatic<N> {
fn parameters(&self) -> Vec<(DataType, String)> {
vec![(DataType::U128, "value".to_string())]
}
fn return_values(&self) -> Vec<(DataType, String)> {
vec![(DataType::U128, "shifted_value".to_string())]
}
fn entrypoint(&self) -> String {
format!("tasmlib_arithmetic_u128_shift_left_static_{N}")
}
fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
assert!(N <= 32, "shift amount must be in range 0..=32");
triton_asm!(
{self.entrypoint()}:
push {1_u64 << N}
xb_mul pick 3 push {1_u64 << N}
mul
split pick 4 split pick 5 split pick 6 split
place 7 add place 6 add place 5 add place 4 pop 1 return
)
}
}
#[cfg(test)]
pub(crate) mod tests {
use rand::rngs::StdRng;
use super::*;
use crate::test_prelude::*;
impl<const N: u8> Closure for ShiftLeftStatic<N> {
type Args = u128;
fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
let v = pop_encodable::<Self::Args>(stack);
push_encodable(stack, &(v << N));
}
fn pseudorandom_args(
&self,
seed: [u8; 32],
bench_case: Option<BenchmarkCase>,
) -> Self::Args {
match bench_case {
Some(BenchmarkCase::CommonCase) => 0x1282,
Some(BenchmarkCase::WorstCase) => 0x123456789abcdef,
None => StdRng::from_seed(seed).random(),
}
}
fn corner_case_args(&self) -> Vec<Self::Args> {
vec![0, 1, 8, u32::MAX.into(), u64::MAX.into(), u128::MAX]
}
}
#[test]
fn rust_shadow() {
macro_rules! test_shift_left_static {
($($i:expr),*$(,)?) => {
$(ShadowedClosure::new(ShiftLeftStatic::<$i>).test();)*
};
}
test_shift_left_static!(0, 1, 2, 3, 4, 5, 6, 7);
test_shift_left_static!(8, 9, 10, 11, 12, 13, 14, 15);
test_shift_left_static!(16, 17, 18, 19, 20, 21, 22, 23);
test_shift_left_static!(24, 25, 26, 27, 28, 29, 30, 31);
test_shift_left_static!(32);
}
#[test]
#[should_panic]
fn shift_beyond_limit() {
ShadowedClosure::new(ShiftLeftStatic::<33>).test();
}
}
#[cfg(test)]
mod benches {
use super::*;
use crate::test_prelude::*;
#[test]
fn benchmark() {
ShadowedClosure::new(ShiftLeftStatic::<5>).bench();
}
}