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 inputs(&self) -> Vec<(DataType, String)> {
35 ["right", "left"]
36 .map(|s| (DataType::U32, s.to_string()))
37 .to_vec()
38 }
39
40 fn outputs(&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"), 0x40fd42d47d3b4bf4.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>) {
83 let (right, left) = pop_encodable::<Self::Args>(stack);
84 let diff = left.checked_sub(right).unwrap();
85 push_encodable(stack, &diff);
86 }
87
88 fn pseudorandom_args(
89 &self,
90 seed: [u8; 32],
91 bench_case: Option<BenchmarkCase>,
92 ) -> Self::Args {
93 let Some(bench_case) = bench_case else {
94 let mut rng = StdRng::from_seed(seed);
95 let left = rng.random();
96 let right = rng.random_range(0..=left);
97
98 return (right, left);
99 };
100
101 match bench_case {
102 BenchmarkCase::CommonCase => (1 << 15, 1 << 16),
103 BenchmarkCase::WorstCase => (0, u32::MAX),
104 }
105 }
106
107 fn corner_case_args(&self) -> Vec<Self::Args> {
108 vec![(0, 0), (0, u32::MAX), (u32::MAX, u32::MAX)]
109 }
110 }
111
112 #[test]
113 fn rust_shadow() {
114 ShadowedClosure::new(SafeSub).test();
115 }
116
117 #[proptest]
118 fn overflow_crashes_vm(
119 #[filter(#left != u32::MAX)] left: u32,
120 #[strategy(#left..)] right: u32,
121 ) {
122 test_assertion_failure(
123 &ShadowedClosure::new(SafeSub),
124 InitVmState::with_stack(SafeSub.set_up_test_stack((right, left))),
125 &[SafeSub::OVERFLOW_ERROR_ID],
126 )
127 }
128}
129
130#[cfg(test)]
131mod benches {
132 use super::*;
133 use crate::test_prelude::*;
134
135 #[test]
136 fn safe_sub_benchmark() {
137 ShadowedClosure::new(SafeSub).bench();
138 }
139}