tasm_lib/arithmetic/u128/
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)]
30pub struct Sub;
31
32impl Sub {
33 pub const OVERFLOW_ERROR_ID: i128 = 520;
34}
35
36impl BasicSnippet for Sub {
37 fn inputs(&self) -> Vec<(DataType, String)> {
38 ["subtrahend", "minuend"]
39 .map(|s| (DataType::U128, s.to_string()))
40 .to_vec()
41 }
42
43 fn outputs(&self) -> Vec<(DataType, String)> {
44 vec![(DataType::U128, "difference".to_string())]
45 }
46
47 fn entrypoint(&self) -> String {
48 "tasmlib_arithmetic_u128_sub".to_string()
49 }
50
51 fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
52 triton_asm!(
53 {self.entrypoint()}:
56 pick 4
57 push -1
58 mul
59 add push {1_u64 << 32}
61 add
62 split place 7 push 0
66 eq pick 4
68 add
69 push -1
70 mul add push {1_u64 << 32}
73 add
74 split place 6 push 0
78 eq pick 3
80 add
81 push -1
82 mul add push {1_u64 << 32}
85 add
86 split place 5 push 0
90 eq pick 2
92 add
93 push -1
94 mul add
96 split place 4 push 0
100 eq
101 assert error_id {Self::OVERFLOW_ERROR_ID}
102 return
104 )
105 }
106
107 fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
108 let mut sign_offs = HashMap::new();
109 sign_offs.insert(Reviewer("ferdinand"), 0xcfbc5c77452584fd.into());
110 sign_offs
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use BFieldElement;
117
118 use super::*;
119 use crate::test_prelude::*;
120
121 impl Closure for Sub {
122 type Args = (u128, u128);
123
124 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
125 let (subtrahend, minuend) = pop_encodable::<Self::Args>(stack);
126 let difference = minuend.checked_sub(subtrahend).unwrap();
127 push_encodable(stack, &difference);
128 }
129
130 fn pseudorandom_args(
131 &self,
132 seed: [u8; 32],
133 bench_case: Option<BenchmarkCase>,
134 ) -> Self::Args {
135 let Some(bench_case) = bench_case else {
136 let mut rng = StdRng::from_seed(seed);
137 let subtrahend = rng.random();
138 let minuend = rng.random_range(subtrahend..=u128::MAX);
139 return (subtrahend, minuend);
140 };
141
142 match bench_case {
143 BenchmarkCase::CommonCase => (1 << 126, 1 << 127),
144 BenchmarkCase::WorstCase => ((1 << 126) + (1 << 56), (1 << 127) + (1 << 64)),
145 }
146 }
147
148 fn corner_case_args(&self) -> Vec<Self::Args> {
149 vec![
150 (0, 0),
151 (0, 1),
152 (1, 1),
153 (1, 0xffff_ffff_ffff_ffff_ffff_ffff_0000_0000),
154 (2, 0xffff_ffff_ffff_ffff_0000_0000_0000_0001),
155 (3, 0xffff_ffff_0000_0000_0000_0000_0000_0002),
156 (4, 1 << 127),
157 (u32::MAX.into(), u32::MAX.into()),
158 (u64::MAX.into(), u64::MAX.into()),
159 (u128::MAX, u128::MAX),
160 ]
161 }
162 }
163
164 #[test]
165 fn rust_shadow() {
166 ShadowedClosure::new(Sub).test();
167 }
168
169 #[proptest]
170 fn overflow_crashes_vm(
171 #[strategy(1_u128..)] subtrahend: u128,
172 #[strategy(..#subtrahend)] minuend: u128,
173 ) {
174 test_assertion_failure(
175 &ShadowedClosure::new(Sub),
176 InitVmState::with_stack(Sub.set_up_test_stack((subtrahend, minuend))),
177 &[Sub::OVERFLOW_ERROR_ID],
178 );
179 }
180}
181
182#[cfg(test)]
183mod benches {
184 use super::*;
185 use crate::test_prelude::*;
186
187 #[test]
188 fn benchmark() {
189 ShadowedClosure::new(Sub).bench();
190 }
191}