Skip to main content

percolator/
i128.rs

1// ============================================================================
2// BPF-Safe 128-bit Types
3// ============================================================================
4//
5// CRITICAL: Rust 1.77/1.78 changed i128/u128 alignment from 8 to 16 bytes on x86_64,
6// but BPF/SBF still uses 8-byte alignment. This causes struct layout mismatches
7// when reading/writing 128-bit values on-chain.
8//
9// These wrapper types use [u64; 2] internally to ensure consistent 8-byte alignment
10// across all platforms. See: https://blog.rust-lang.org/2024/03/30/i128-layout-update.html
11//
12// KANI OPTIMIZATION: For Kani builds, we use transparent newtypes around raw
13// primitives. This dramatically reduces SAT solver complexity since Kani doesn't
14// have to reason about bit-shifting and array indexing for every 128-bit operation.
15
16// ============================================================================
17// I128 - Kani-optimized version (transparent newtype)
18// ============================================================================
19#[cfg(kani)]
20#[repr(transparent)]
21#[derive(Clone, Copy, PartialEq, Eq)]
22pub struct I128(i128);
23
24#[cfg(kani)]
25impl I128 {
26    pub const ZERO: Self = Self(0);
27    pub const MIN: Self = Self(i128::MIN);
28    pub const MAX: Self = Self(i128::MAX);
29
30    #[inline(always)]
31    pub const fn new(val: i128) -> Self {
32        Self(val)
33    }
34
35    #[inline(always)]
36    pub const fn get(self) -> i128 {
37        self.0
38    }
39
40    #[inline(always)]
41    pub fn set(&mut self, val: i128) {
42        self.0 = val;
43    }
44
45    #[inline(always)]
46    pub fn checked_add(self, rhs: i128) -> Option<Self> {
47        self.0.checked_add(rhs).map(Self)
48    }
49
50    #[inline(always)]
51    pub fn checked_sub(self, rhs: i128) -> Option<Self> {
52        self.0.checked_sub(rhs).map(Self)
53    }
54
55    #[inline(always)]
56    pub fn checked_mul(self, rhs: i128) -> Option<Self> {
57        self.0.checked_mul(rhs).map(Self)
58    }
59
60    #[inline(always)]
61    pub fn checked_div(self, rhs: i128) -> Option<Self> {
62        self.0.checked_div(rhs).map(Self)
63    }
64
65    #[inline(always)]
66    pub fn saturating_add(self, rhs: i128) -> Self {
67        Self(self.0.saturating_add(rhs))
68    }
69
70    #[inline(always)]
71    pub fn saturating_add_i128(self, rhs: I128) -> Self {
72        Self(self.0.saturating_add(rhs.0))
73    }
74
75    #[inline(always)]
76    pub fn saturating_sub(self, rhs: i128) -> Self {
77        Self(self.0.saturating_sub(rhs))
78    }
79
80    #[inline(always)]
81    pub fn saturating_sub_i128(self, rhs: I128) -> Self {
82        Self(self.0.saturating_sub(rhs.0))
83    }
84
85    #[inline(always)]
86    pub fn wrapping_add(self, rhs: i128) -> Self {
87        Self(self.0.wrapping_add(rhs))
88    }
89
90    #[inline(always)]
91    pub fn abs(self) -> Self {
92        Self(self.0.abs())
93    }
94
95    #[inline(always)]
96    pub fn unsigned_abs(self) -> u128 {
97        self.0.unsigned_abs()
98    }
99
100    #[inline(always)]
101    pub fn is_zero(self) -> bool {
102        self.0 == 0
103    }
104
105    #[inline(always)]
106    pub fn is_negative(self) -> bool {
107        self.0 < 0
108    }
109
110    #[inline(always)]
111    pub fn is_positive(self) -> bool {
112        self.0 > 0
113    }
114}
115
116// ============================================================================
117// I128 - BPF version (array-based for alignment)
118// ============================================================================
119/// BPF-safe signed 128-bit integer using [u64; 2] for consistent alignment.
120/// Layout: [lo, hi] in little-endian order.
121// Kani I128 trait implementations
122#[cfg(kani)]
123impl Default for I128 {
124    fn default() -> Self {
125        Self::ZERO
126    }
127}
128
129#[cfg(kani)]
130impl core::fmt::Debug for I128 {
131    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
132        write!(f, "I128({})", self.0)
133    }
134}
135
136#[cfg(kani)]
137impl core::fmt::Display for I128 {
138    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
139        write!(f, "{}", self.0)
140    }
141}
142
143#[cfg(kani)]
144impl From<i128> for I128 {
145    fn from(val: i128) -> Self {
146        Self(val)
147    }
148}
149
150#[cfg(kani)]
151impl From<i64> for I128 {
152    fn from(val: i64) -> Self {
153        Self(val as i128)
154    }
155}
156
157#[cfg(kani)]
158impl From<I128> for i128 {
159    fn from(val: I128) -> Self {
160        val.0
161    }
162}
163
164#[cfg(kani)]
165impl PartialOrd for I128 {
166    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
167        Some(self.cmp(other))
168    }
169}
170
171#[cfg(kani)]
172impl Ord for I128 {
173    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
174        self.0.cmp(&other.0)
175    }
176}
177
178#[cfg(kani)]
179impl core::ops::Add<i128> for I128 {
180    type Output = Self;
181    fn add(self, rhs: i128) -> Self {
182        Self(self.0.saturating_add(rhs))
183    }
184}
185
186#[cfg(kani)]
187impl core::ops::Add<I128> for I128 {
188    type Output = Self;
189    fn add(self, rhs: I128) -> Self {
190        Self(self.0.saturating_add(rhs.0))
191    }
192}
193
194#[cfg(kani)]
195impl core::ops::Sub<i128> for I128 {
196    type Output = Self;
197    fn sub(self, rhs: i128) -> Self {
198        Self(self.0.saturating_sub(rhs))
199    }
200}
201
202#[cfg(kani)]
203impl core::ops::Sub<I128> for I128 {
204    type Output = Self;
205    fn sub(self, rhs: I128) -> Self {
206        Self(self.0.saturating_sub(rhs.0))
207    }
208}
209
210#[cfg(kani)]
211impl core::ops::Neg for I128 {
212    type Output = Self;
213    fn neg(self) -> Self {
214        Self(self.0.saturating_neg())
215    }
216}
217
218#[cfg(kani)]
219impl core::ops::AddAssign<i128> for I128 {
220    fn add_assign(&mut self, rhs: i128) {
221        *self = *self + rhs;
222    }
223}
224
225#[cfg(kani)]
226impl core::ops::SubAssign<i128> for I128 {
227    fn sub_assign(&mut self, rhs: i128) {
228        *self = *self - rhs;
229    }
230}
231
232// ============================================================================
233// I128 - BPF version (array-based for alignment)
234// ============================================================================
235#[cfg(not(kani))]
236#[repr(C)]
237#[derive(Clone, Copy, PartialEq, Eq)]
238pub struct I128([u64; 2]);
239
240#[cfg(not(kani))]
241impl I128 {
242    pub const ZERO: Self = Self([0, 0]);
243    pub const MIN: Self = Self([0, 0x8000_0000_0000_0000]); // i128::MIN
244    pub const MAX: Self = Self([u64::MAX, 0x7FFF_FFFF_FFFF_FFFF]); // i128::MAX
245
246    #[inline]
247    pub const fn new(val: i128) -> Self {
248        Self([val as u64, (val >> 64) as u64])
249    }
250
251    #[inline]
252    pub const fn get(self) -> i128 {
253        // Sign-extend: treat hi as signed
254        ((self.0[1] as i128) << 64) | (self.0[0] as u128 as i128)
255    }
256
257    #[inline]
258    pub fn set(&mut self, val: i128) {
259        self.0[0] = val as u64;
260        self.0[1] = (val >> 64) as u64;
261    }
262
263    #[inline]
264    pub fn checked_add(self, rhs: i128) -> Option<Self> {
265        self.get().checked_add(rhs).map(Self::new)
266    }
267
268    #[inline]
269    pub fn checked_sub(self, rhs: i128) -> Option<Self> {
270        self.get().checked_sub(rhs).map(Self::new)
271    }
272
273    #[inline]
274    pub fn checked_mul(self, rhs: i128) -> Option<Self> {
275        self.get().checked_mul(rhs).map(Self::new)
276    }
277
278    #[inline]
279    pub fn checked_div(self, rhs: i128) -> Option<Self> {
280        self.get().checked_div(rhs).map(Self::new)
281    }
282
283    #[inline]
284    pub fn saturating_add(self, rhs: i128) -> Self {
285        Self::new(self.get().saturating_add(rhs))
286    }
287
288    #[inline]
289    pub fn saturating_add_i128(self, rhs: I128) -> Self {
290        Self::new(self.get().saturating_add(rhs.get()))
291    }
292
293    #[inline]
294    pub fn saturating_sub(self, rhs: i128) -> Self {
295        Self::new(self.get().saturating_sub(rhs))
296    }
297
298    #[inline]
299    pub fn saturating_sub_i128(self, rhs: I128) -> Self {
300        Self::new(self.get().saturating_sub(rhs.get()))
301    }
302
303    #[inline]
304    pub fn wrapping_add(self, rhs: i128) -> Self {
305        Self::new(self.get().wrapping_add(rhs))
306    }
307
308    #[inline]
309    pub fn abs(self) -> Self {
310        Self::new(self.get().abs())
311    }
312
313    #[inline]
314    pub fn unsigned_abs(self) -> u128 {
315        self.get().unsigned_abs()
316    }
317
318    #[inline]
319    pub fn is_zero(self) -> bool {
320        self.0[0] == 0 && self.0[1] == 0
321    }
322
323    #[inline]
324    pub fn is_negative(self) -> bool {
325        (self.0[1] as i64) < 0
326    }
327
328    #[inline]
329    pub fn is_positive(self) -> bool {
330        !self.is_zero() && !self.is_negative()
331    }
332}
333
334#[cfg(not(kani))]
335impl Default for I128 {
336    fn default() -> Self {
337        Self::ZERO
338    }
339}
340
341#[cfg(not(kani))]
342impl core::fmt::Debug for I128 {
343    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
344        write!(f, "I128({})", self.get())
345    }
346}
347
348#[cfg(not(kani))]
349impl core::fmt::Display for I128 {
350    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
351        write!(f, "{}", self.get())
352    }
353}
354
355#[cfg(not(kani))]
356impl From<i128> for I128 {
357    fn from(val: i128) -> Self {
358        Self::new(val)
359    }
360}
361
362#[cfg(not(kani))]
363impl From<i64> for I128 {
364    fn from(val: i64) -> Self {
365        Self::new(val as i128)
366    }
367}
368
369#[cfg(not(kani))]
370impl From<I128> for i128 {
371    fn from(val: I128) -> Self {
372        val.get()
373    }
374}
375
376#[cfg(not(kani))]
377impl PartialOrd for I128 {
378    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
379        Some(self.cmp(other))
380    }
381}
382
383#[cfg(not(kani))]
384impl Ord for I128 {
385    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
386        self.get().cmp(&other.get())
387    }
388}
389
390// ============================================================================
391// U128 - Kani-optimized version (transparent newtype)
392// ============================================================================
393#[cfg(kani)]
394#[repr(transparent)]
395#[derive(Clone, Copy, PartialEq, Eq)]
396pub struct U128(u128);
397
398#[cfg(kani)]
399impl U128 {
400    pub const ZERO: Self = Self(0);
401    pub const MAX: Self = Self(u128::MAX);
402
403    #[inline(always)]
404    pub const fn new(val: u128) -> Self {
405        Self(val)
406    }
407
408    #[inline(always)]
409    pub const fn get(self) -> u128 {
410        self.0
411    }
412
413    #[inline(always)]
414    pub fn set(&mut self, val: u128) {
415        self.0 = val;
416    }
417
418    #[inline(always)]
419    pub fn checked_add(self, rhs: u128) -> Option<Self> {
420        self.0.checked_add(rhs).map(Self)
421    }
422
423    #[inline(always)]
424    pub fn checked_sub(self, rhs: u128) -> Option<Self> {
425        self.0.checked_sub(rhs).map(Self)
426    }
427
428    #[inline(always)]
429    pub fn checked_mul(self, rhs: u128) -> Option<Self> {
430        self.0.checked_mul(rhs).map(Self)
431    }
432
433    #[inline(always)]
434    pub fn checked_div(self, rhs: u128) -> Option<Self> {
435        self.0.checked_div(rhs).map(Self)
436    }
437
438    #[inline(always)]
439    pub fn saturating_add(self, rhs: u128) -> Self {
440        Self(self.0.saturating_add(rhs))
441    }
442
443    #[inline(always)]
444    pub fn saturating_add_u128(self, rhs: U128) -> Self {
445        Self(self.0.saturating_add(rhs.0))
446    }
447
448    #[inline(always)]
449    pub fn saturating_sub(self, rhs: u128) -> Self {
450        Self(self.0.saturating_sub(rhs))
451    }
452
453    #[inline(always)]
454    pub fn saturating_sub_u128(self, rhs: U128) -> Self {
455        Self(self.0.saturating_sub(rhs.0))
456    }
457
458    #[inline(always)]
459    pub fn saturating_mul(self, rhs: u128) -> Self {
460        Self(self.0.saturating_mul(rhs))
461    }
462
463    #[inline(always)]
464    pub fn wrapping_add(self, rhs: u128) -> Self {
465        Self(self.0.wrapping_add(rhs))
466    }
467
468    #[inline(always)]
469    pub fn max(self, rhs: Self) -> Self {
470        if self.0 >= rhs.0 {
471            self
472        } else {
473            rhs
474        }
475    }
476
477    #[inline(always)]
478    pub fn min(self, rhs: Self) -> Self {
479        if self.0 <= rhs.0 {
480            self
481        } else {
482            rhs
483        }
484    }
485
486    #[inline(always)]
487    pub fn is_zero(self) -> bool {
488        self.0 == 0
489    }
490}
491
492#[cfg(kani)]
493impl Default for U128 {
494    fn default() -> Self {
495        Self::ZERO
496    }
497}
498
499#[cfg(kani)]
500impl core::fmt::Debug for U128 {
501    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
502        write!(f, "U128({})", self.0)
503    }
504}
505
506#[cfg(kani)]
507impl core::fmt::Display for U128 {
508    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
509        write!(f, "{}", self.0)
510    }
511}
512
513#[cfg(kani)]
514impl From<u128> for U128 {
515    fn from(val: u128) -> Self {
516        Self(val)
517    }
518}
519
520#[cfg(kani)]
521impl From<u64> for U128 {
522    fn from(val: u64) -> Self {
523        Self(val as u128)
524    }
525}
526
527#[cfg(kani)]
528impl From<U128> for u128 {
529    fn from(val: U128) -> Self {
530        val.0
531    }
532}
533
534#[cfg(kani)]
535impl PartialOrd for U128 {
536    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
537        Some(self.cmp(other))
538    }
539}
540
541#[cfg(kani)]
542impl Ord for U128 {
543    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
544        self.0.cmp(&other.0)
545    }
546}
547
548#[cfg(kani)]
549impl core::ops::Add<u128> for U128 {
550    type Output = Self;
551    fn add(self, rhs: u128) -> Self {
552        Self(self.0.saturating_add(rhs))
553    }
554}
555
556#[cfg(kani)]
557impl core::ops::Add<U128> for U128 {
558    type Output = Self;
559    fn add(self, rhs: U128) -> Self {
560        Self(self.0.saturating_add(rhs.0))
561    }
562}
563
564#[cfg(kani)]
565impl core::ops::Sub<u128> for U128 {
566    type Output = Self;
567    fn sub(self, rhs: u128) -> Self {
568        Self(self.0.saturating_sub(rhs))
569    }
570}
571
572#[cfg(kani)]
573impl core::ops::Sub<U128> for U128 {
574    type Output = Self;
575    fn sub(self, rhs: U128) -> Self {
576        Self(self.0.saturating_sub(rhs.0))
577    }
578}
579
580#[cfg(kani)]
581impl core::ops::Mul<u128> for U128 {
582    type Output = Self;
583    fn mul(self, rhs: u128) -> Self {
584        Self(self.0.saturating_mul(rhs))
585    }
586}
587
588#[cfg(kani)]
589impl core::ops::Mul<U128> for U128 {
590    type Output = Self;
591    fn mul(self, rhs: U128) -> Self {
592        Self(self.0.saturating_mul(rhs.0))
593    }
594}
595
596#[cfg(kani)]
597impl core::ops::Div<u128> for U128 {
598    type Output = Self;
599    fn div(self, rhs: u128) -> Self {
600        Self(self.0 / rhs)
601    }
602}
603
604#[cfg(kani)]
605impl core::ops::Div<U128> for U128 {
606    type Output = Self;
607    fn div(self, rhs: U128) -> Self {
608        Self(self.0 / rhs.0)
609    }
610}
611
612#[cfg(kani)]
613impl core::ops::AddAssign<u128> for U128 {
614    fn add_assign(&mut self, rhs: u128) {
615        *self = *self + rhs;
616    }
617}
618
619#[cfg(kani)]
620impl core::ops::SubAssign<u128> for U128 {
621    fn sub_assign(&mut self, rhs: u128) {
622        *self = *self - rhs;
623    }
624}
625
626// ============================================================================
627// U128 - BPF version (array-based for alignment)
628// ============================================================================
629/// BPF-safe unsigned 128-bit integer using [u64; 2] for consistent alignment.
630/// Layout: [lo, hi] in little-endian order.
631#[cfg(not(kani))]
632#[repr(C)]
633#[derive(Clone, Copy, PartialEq, Eq)]
634pub struct U128([u64; 2]);
635
636#[cfg(not(kani))]
637impl U128 {
638    pub const ZERO: Self = Self([0, 0]);
639    pub const MAX: Self = Self([u64::MAX, u64::MAX]);
640
641    #[inline]
642    pub const fn new(val: u128) -> Self {
643        Self([val as u64, (val >> 64) as u64])
644    }
645
646    #[inline]
647    pub const fn get(self) -> u128 {
648        ((self.0[1] as u128) << 64) | (self.0[0] as u128)
649    }
650
651    #[inline]
652    pub fn set(&mut self, val: u128) {
653        self.0[0] = val as u64;
654        self.0[1] = (val >> 64) as u64;
655    }
656
657    #[inline]
658    pub fn checked_add(self, rhs: u128) -> Option<Self> {
659        self.get().checked_add(rhs).map(Self::new)
660    }
661
662    #[inline]
663    pub fn checked_sub(self, rhs: u128) -> Option<Self> {
664        self.get().checked_sub(rhs).map(Self::new)
665    }
666
667    #[inline]
668    pub fn checked_mul(self, rhs: u128) -> Option<Self> {
669        self.get().checked_mul(rhs).map(Self::new)
670    }
671
672    #[inline]
673    pub fn checked_div(self, rhs: u128) -> Option<Self> {
674        self.get().checked_div(rhs).map(Self::new)
675    }
676
677    #[inline]
678    pub fn saturating_add(self, rhs: u128) -> Self {
679        Self::new(self.get().saturating_add(rhs))
680    }
681
682    #[inline]
683    pub fn saturating_add_u128(self, rhs: U128) -> Self {
684        Self::new(self.get().saturating_add(rhs.get()))
685    }
686
687    #[inline]
688    pub fn saturating_sub(self, rhs: u128) -> Self {
689        Self::new(self.get().saturating_sub(rhs))
690    }
691
692    #[inline]
693    pub fn saturating_sub_u128(self, rhs: U128) -> Self {
694        Self::new(self.get().saturating_sub(rhs.get()))
695    }
696
697    #[inline]
698    pub fn saturating_mul(self, rhs: u128) -> Self {
699        Self::new(self.get().saturating_mul(rhs))
700    }
701
702    #[inline]
703    pub fn wrapping_add(self, rhs: u128) -> Self {
704        Self::new(self.get().wrapping_add(rhs))
705    }
706
707    #[inline]
708    pub fn max(self, rhs: Self) -> Self {
709        if self.get() >= rhs.get() {
710            self
711        } else {
712            rhs
713        }
714    }
715
716    #[inline]
717    pub fn min(self, rhs: Self) -> Self {
718        if self.get() <= rhs.get() {
719            self
720        } else {
721            rhs
722        }
723    }
724
725    #[inline]
726    pub fn is_zero(self) -> bool {
727        self.0[0] == 0 && self.0[1] == 0
728    }
729}
730
731#[cfg(not(kani))]
732impl Default for U128 {
733    fn default() -> Self {
734        Self::ZERO
735    }
736}
737
738#[cfg(not(kani))]
739impl core::fmt::Debug for U128 {
740    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
741        write!(f, "U128({})", self.get())
742    }
743}
744
745#[cfg(not(kani))]
746impl core::fmt::Display for U128 {
747    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
748        write!(f, "{}", self.get())
749    }
750}
751
752#[cfg(not(kani))]
753impl From<u128> for U128 {
754    fn from(val: u128) -> Self {
755        Self::new(val)
756    }
757}
758
759#[cfg(not(kani))]
760impl From<u64> for U128 {
761    fn from(val: u64) -> Self {
762        Self::new(val as u128)
763    }
764}
765
766#[cfg(not(kani))]
767impl From<U128> for u128 {
768    fn from(val: U128) -> Self {
769        val.get()
770    }
771}
772
773#[cfg(not(kani))]
774impl PartialOrd for U128 {
775    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
776        Some(self.cmp(other))
777    }
778}
779
780#[cfg(not(kani))]
781impl Ord for U128 {
782    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
783        self.get().cmp(&other.get())
784    }
785}
786
787// Arithmetic operators for U128 (BPF version)
788#[cfg(not(kani))]
789impl core::ops::Add<u128> for U128 {
790    type Output = Self;
791    fn add(self, rhs: u128) -> Self {
792        Self::new(self.get().saturating_add(rhs))
793    }
794}
795
796#[cfg(not(kani))]
797impl core::ops::Add<U128> for U128 {
798    type Output = Self;
799    fn add(self, rhs: U128) -> Self {
800        Self::new(self.get().saturating_add(rhs.get()))
801    }
802}
803
804#[cfg(not(kani))]
805impl core::ops::Sub<u128> for U128 {
806    type Output = Self;
807    fn sub(self, rhs: u128) -> Self {
808        Self::new(self.get().saturating_sub(rhs))
809    }
810}
811
812#[cfg(not(kani))]
813impl core::ops::Sub<U128> for U128 {
814    type Output = Self;
815    fn sub(self, rhs: U128) -> Self {
816        Self::new(self.get().saturating_sub(rhs.get()))
817    }
818}
819
820#[cfg(not(kani))]
821impl core::ops::Mul<u128> for U128 {
822    type Output = Self;
823    fn mul(self, rhs: u128) -> Self {
824        Self::new(self.get().saturating_mul(rhs))
825    }
826}
827
828#[cfg(not(kani))]
829impl core::ops::Mul<U128> for U128 {
830    type Output = Self;
831    fn mul(self, rhs: U128) -> Self {
832        Self::new(self.get().saturating_mul(rhs.get()))
833    }
834}
835
836#[cfg(not(kani))]
837impl core::ops::Div<u128> for U128 {
838    type Output = Self;
839    fn div(self, rhs: u128) -> Self {
840        Self::new(self.get() / rhs)
841    }
842}
843
844#[cfg(not(kani))]
845impl core::ops::Div<U128> for U128 {
846    type Output = Self;
847    fn div(self, rhs: U128) -> Self {
848        Self::new(self.get() / rhs.get())
849    }
850}
851
852#[cfg(not(kani))]
853impl core::ops::AddAssign<u128> for U128 {
854    fn add_assign(&mut self, rhs: u128) {
855        *self = *self + rhs;
856    }
857}
858
859#[cfg(not(kani))]
860impl core::ops::SubAssign<u128> for U128 {
861    fn sub_assign(&mut self, rhs: u128) {
862        *self = *self - rhs;
863    }
864}
865
866// Arithmetic operators for I128 (BPF version)
867#[cfg(not(kani))]
868impl core::ops::Add<i128> for I128 {
869    type Output = Self;
870    fn add(self, rhs: i128) -> Self {
871        Self::new(self.get().saturating_add(rhs))
872    }
873}
874
875#[cfg(not(kani))]
876impl core::ops::Add<I128> for I128 {
877    type Output = Self;
878    fn add(self, rhs: I128) -> Self {
879        Self::new(self.get().saturating_add(rhs.get()))
880    }
881}
882
883#[cfg(not(kani))]
884impl core::ops::Sub<i128> for I128 {
885    type Output = Self;
886    fn sub(self, rhs: i128) -> Self {
887        Self::new(self.get().saturating_sub(rhs))
888    }
889}
890
891#[cfg(not(kani))]
892impl core::ops::Sub<I128> for I128 {
893    type Output = Self;
894    fn sub(self, rhs: I128) -> Self {
895        Self::new(self.get().saturating_sub(rhs.get()))
896    }
897}
898
899#[cfg(not(kani))]
900impl core::ops::Mul<i128> for I128 {
901    type Output = Self;
902    fn mul(self, rhs: i128) -> Self {
903        Self::new(self.get().saturating_mul(rhs))
904    }
905}
906
907#[cfg(not(kani))]
908impl core::ops::Neg for I128 {
909    type Output = Self;
910    fn neg(self) -> Self {
911        Self::new(-self.get())
912    }
913}
914
915#[cfg(not(kani))]
916impl core::ops::AddAssign<i128> for I128 {
917    fn add_assign(&mut self, rhs: i128) {
918        *self = *self + rhs;
919    }
920}
921
922#[cfg(not(kani))]
923impl core::ops::SubAssign<i128> for I128 {
924    fn sub_assign(&mut self, rhs: i128) {
925        *self = *self - rhs;
926    }
927}