binius_field/arch/portable/
m128.rs1use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, Shr};
4
5use binius_utils::{
6 DeserializeBytes, SerializationError, SerializeBytes,
7 bytes::{Buf, BufMut},
8 serialization::{assert_enough_data_for, assert_enough_space_for},
9};
10use bytemuck::{Pod, Zeroable};
11use derive_more::{From, Into};
12use rand::{
13 distr::{Distribution, StandardUniform},
14 prelude::*,
15};
16
17use crate::{
18 BinaryField,
19 arch::portable::packed::PackedPrimitiveType,
20 underlier::{
21 Divisible, NumCast, SmallU, UnderlierType, impl_divisible_bitmask, impl_divisible_memcast,
22 impl_divisible_self,
23 },
24};
25
26#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, From, Into)]
33#[repr(transparent)]
34pub struct M128(u128);
35
36impl M128 {
37 #[inline(always)]
38 pub const fn from_u128(value: u128) -> Self {
39 Self(value)
40 }
41}
42
43impl From<u64> for M128 {
44 #[inline(always)]
45 fn from(value: u64) -> Self {
46 Self(value as u128)
47 }
48}
49impl From<u32> for M128 {
50 #[inline(always)]
51 fn from(value: u32) -> Self {
52 Self(value as u128)
53 }
54}
55impl From<u16> for M128 {
56 #[inline(always)]
57 fn from(value: u16) -> Self {
58 Self(value as u128)
59 }
60}
61impl From<u8> for M128 {
62 #[inline(always)]
63 fn from(value: u8) -> Self {
64 Self(value as u128)
65 }
66}
67
68impl<const N: usize> From<SmallU<N>> for M128 {
69 #[inline(always)]
70 fn from(value: SmallU<N>) -> Self {
71 Self(value.val() as u128)
72 }
73}
74
75impl<U: NumCast<u128>> NumCast<M128> for U {
76 #[inline(always)]
77 fn num_cast_from(val: M128) -> Self {
78 Self::num_cast_from(val.0)
79 }
80}
81
82impl SerializeBytes for M128 {
83 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
84 assert_enough_space_for(&write_buf, std::mem::size_of::<Self>())?;
85 write_buf.put_u128_le(self.0);
86 Ok(())
87 }
88}
89
90impl DeserializeBytes for M128 {
91 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
92 where
93 Self: Sized,
94 {
95 assert_enough_data_for(&read_buf, std::mem::size_of::<Self>())?;
96 Ok(Self(read_buf.get_u128_le()))
97 }
98}
99
100unsafe impl Zeroable for M128 {}
101
102unsafe impl Pod for M128 {}
103
104impl_divisible_memcast!(M128, u128, u64, u32, u16, u8);
105impl_divisible_bitmask!(M128, 1, 2, 4);
106impl_divisible_self!(M128);
107
108impl BitAnd for M128 {
109 type Output = Self;
110
111 #[inline(always)]
112 fn bitand(self, rhs: Self) -> Self::Output {
113 Self(self.0 & rhs.0)
114 }
115}
116
117impl BitAndAssign for M128 {
118 #[inline(always)]
119 fn bitand_assign(&mut self, rhs: Self) {
120 self.0 &= rhs.0;
121 }
122}
123
124impl BitOr for M128 {
125 type Output = Self;
126
127 #[inline(always)]
128 fn bitor(self, rhs: Self) -> Self::Output {
129 Self(self.0 | rhs.0)
130 }
131}
132
133impl BitOrAssign for M128 {
134 #[inline(always)]
135 fn bitor_assign(&mut self, rhs: Self) {
136 self.0 |= rhs.0;
137 }
138}
139
140impl BitXor for M128 {
141 type Output = Self;
142
143 #[inline(always)]
144 fn bitxor(self, rhs: Self) -> Self::Output {
145 Self(self.0 ^ rhs.0)
146 }
147}
148
149impl BitXorAssign for M128 {
150 #[inline(always)]
151 fn bitxor_assign(&mut self, rhs: Self) {
152 self.0 ^= rhs.0;
153 }
154}
155
156impl Not for M128 {
157 type Output = Self;
158
159 #[inline(always)]
160 fn not(self) -> Self::Output {
161 Self(!self.0)
162 }
163}
164
165impl Shl<usize> for M128 {
166 type Output = Self;
167
168 #[inline(always)]
169 fn shl(self, rhs: usize) -> Self::Output {
170 Self(self.0 << rhs)
171 }
172}
173
174impl Shr<usize> for M128 {
175 type Output = Self;
176
177 #[inline(always)]
178 fn shr(self, rhs: usize) -> Self::Output {
179 Self(self.0 >> rhs)
180 }
181}
182
183impl Distribution<M128> for StandardUniform {
184 #[inline]
185 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> M128 {
186 M128(rng.random())
187 }
188}
189
190impl std::fmt::Display for M128 {
191 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192 write!(f, "{:032X}", self.0)
193 }
194}
195
196impl std::fmt::Debug for M128 {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 write!(f, "M128({self})")
199 }
200}
201
202impl std::fmt::LowerHex for M128 {
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 std::fmt::LowerHex::fmt(&self.0, f)
205 }
206}
207
208impl UnderlierType for M128 {
209 const LOG_BITS: usize = 7;
210 const ZERO: Self = Self(0);
211 const ONE: Self = Self(1);
212 const ONES: Self = Self(u128::MAX);
213
214 #[inline(always)]
215 fn interleave(self, other: Self, log_block_len: usize) -> (Self, Self) {
216 let (a, b) = self.0.interleave(other.0, log_block_len);
217 (Self(a), Self(b))
218 }
219}
220
221impl<Scalar: BinaryField> From<u128> for PackedPrimitiveType<M128, Scalar> {
222 #[inline]
223 fn from(value: u128) -> Self {
224 Self::from(M128::from(value))
225 }
226}
227
228impl<Scalar: BinaryField> From<PackedPrimitiveType<M128, Scalar>> for u128 {
229 #[inline]
230 fn from(value: PackedPrimitiveType<M128, Scalar>) -> Self {
231 value.to_underlier().into()
232 }
233}