ab_core_primitives/sectors/
nano_u256.rs1use core::ops::Rem;
2
3#[derive(Clone, Copy, PartialEq, Eq)]
6pub(super) struct NanoU256 {
7 lo: u128,
8 hi: u128,
9}
10
11impl NanoU256 {
12 #[inline(always)]
13 pub(super) const fn from_le_bytes(bytes: [u8; 32]) -> Self {
14 let lo = u128::from_le_bytes([
15 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
16 bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
17 ]);
18 let hi = u128::from_le_bytes([
19 bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23],
20 bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31],
21 ]);
22
23 Self { lo, hi }
24 }
25}
26
27impl Rem<u64> for NanoU256 {
28 type Output = u64;
29
30 #[inline(always)]
31 fn rem(self, rhs: u64) -> u64 {
32 if rhs == 0 {
33 panic!("division by zero");
34 }
35
36 let rhs = rhs as u128;
37
38 if self.hi == 0 {
40 return (self.lo % rhs) as u64;
41 }
42
43 let hi_rem = self.hi % rhs;
45
46 let combined = (hi_rem << 64) | (self.lo >> 64);
49 let combined_rem = combined % rhs;
50
51 let low = self.lo & 0xffffffffffffffff;
53 let final_rem = ((combined_rem << 64) | low) % rhs;
54
55 final_rem as u64
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::NanoU256;
62 use crate::hashes::blake3_hash;
63
64 #[test]
65 fn basic() {
66 let input = NanoU256::from_le_bytes(*blake3_hash(&[1, 2, 3]));
67 let vectors = [
68 (749265838, 96295755),
69 (4294967296, 468481969),
70 (9588891412677391755, 5746309610232603432),
71 (3050220159935725727, 1594047135082657684),
72 (9163698234407261922, 137811727784537481),
73 (8110910621974504463, 772103028532207994),
74 (10066003301207900840, 3710011681387425537),
75 (6326525170861459176, 4054803448573033593),
76 (16971852880362673803, 14857223653279674036),
77 (5479364763909636908, 2217175580314974257),
78 (14850578606861073142, 5959274540802056661),
79 (6477421758110557520, 2913281736886846177),
80 (u64::MAX, 11641615165612301982),
81 ];
82
83 for (n, rem) in vectors {
84 assert_eq!(input % n, rem);
85 }
86 }
87
88 #[test]
89 #[should_panic]
90 fn no_division_by_zero() {
91 let input = NanoU256::from_le_bytes(*blake3_hash(&[1, 2, 3]));
92 let _ = input % 0;
93 }
94}