tasm_lib/arithmetic/u32/
safe_sub.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, Default, Copy, Clone, Eq, PartialEq, Hash)]
27pub struct SafeSub;
28
29impl SafeSub {
30 pub const OVERFLOW_ERROR_ID: i128 = 470;
31}
32
33impl BasicSnippet for SafeSub {
34 fn parameters(&self) -> Vec<(DataType, String)> {
35 ["right", "left"]
36 .map(|s| (DataType::U32, s.to_string()))
37 .to_vec()
38 }
39
40 fn return_values(&self) -> Vec<(DataType, String)> {
41 vec![(DataType::U32, "left - right".to_string())]
42 }
43
44 fn entrypoint(&self) -> String {
45 "tasmlib_arithmetic_u32_safe_sub".to_string()
46 }
47
48 fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
49 triton_asm!(
50 {self.entrypoint()}:
53 pick 1
54 push -1
55 mul
56 add
57 dup 0 split pop 1 push 0 eq assert error_id {Self::OVERFLOW_ERROR_ID}
63 return
64 )
65 }
66
67 fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
68 let mut sign_offs = HashMap::new();
69 sign_offs.insert(Reviewer("ferdinand"), 0x75a4191cfa996c3f.into());
70 sign_offs
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use crate::test_prelude::*;
78
79 impl Closure for SafeSub {
80 type Args = (u32, u32);
81
82 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) -> Result<(), RustShadowError> {
83 let (right, left) = pop_encodable::<Self::Args>(stack)?;
84 let diff = left
85 .checked_sub(right)
86 .ok_or(RustShadowError::ArithmeticOverflow)?;
87 push_encodable(stack, &diff);
88 Ok(())
89 }
90
91 fn pseudorandom_args(
92 &self,
93 seed: [u8; 32],
94 bench_case: Option<BenchmarkCase>,
95 ) -> Self::Args {
96 let Some(bench_case) = bench_case else {
97 let mut rng = StdRng::from_seed(seed);
98 let left = rng.random();
99 let right = rng.random_range(0..=left);
100
101 return (right, left);
102 };
103
104 match bench_case {
105 BenchmarkCase::CommonCase => (1 << 15, 1 << 16),
106 BenchmarkCase::WorstCase => (0, u32::MAX),
107 }
108 }
109
110 fn corner_case_args(&self) -> Vec<Self::Args> {
111 vec![(0, 0), (0, u32::MAX), (u32::MAX, u32::MAX)]
112 }
113 }
114
115 #[macro_rules_attr::apply(test)]
116 fn rust_shadow() {
117 ShadowedClosure::new(SafeSub).test();
118 }
119
120 #[macro_rules_attr::apply(proptest)]
121 fn overflow_crashes_vm(
122 #[filter(#left != u32::MAX)] left: u32,
123 #[strategy(#left..)] right: u32,
124 ) {
125 test_assertion_failure(
126 &ShadowedClosure::new(SafeSub),
127 InitVmState::with_stack(SafeSub.set_up_test_stack((right, left))),
128 &[SafeSub::OVERFLOW_ERROR_ID],
129 )
130 }
131}
132
133#[cfg(test)]
134mod benches {
135 use super::*;
136 use crate::test_prelude::*;
137
138 #[macro_rules_attr::apply(test)]
139 fn safe_sub_benchmark() {
140 ShadowedClosure::new(SafeSub).bench();
141 }
142}