fixed_bigint/heapless/
bytes.rs1use super::{HeaplessBigInt, zero};
15use crate::MachineWord;
16use const_num_traits::{ByteSliceError, ByteSliceErrorKind, FromByteSlice, Personality};
17use core::marker::PhantomData;
18
19#[inline]
24fn read_be_word<T: MachineWord>(bytes: &[u8]) -> T {
25 let mut val = zero::<T>();
26 let mut first = true;
27 for &b in bytes {
28 if !first {
29 val <<= 8;
30 }
31 val |= <T as From<u8>>::from(b);
32 first = false;
33 }
34 val
35}
36
37#[inline]
39fn read_le_word<T: MachineWord>(bytes: &[u8]) -> T {
40 let mut val = zero::<T>();
41 let mut shift = 0;
42 for &b in bytes {
43 val |= <T as From<u8>>::from(b) << shift;
44 shift += 8;
45 }
46 val
47}
48
49impl<T: MachineWord, const CAP: usize, P: Personality> HeaplessBigInt<T, CAP, P> {
50 pub fn to_be_bytes<'a>(&self, out: &'a mut [u8]) -> &'a [u8] {
54 let word_size = core::mem::size_of::<T>();
55 let byte_count = self.len as usize * word_size;
56 assert!(
57 out.len() >= byte_count,
58 "HeaplessBigInt::to_be_bytes: out.len() < required ({byte_count} bytes)"
59 );
60 for (chunk, word) in out[..byte_count]
61 .chunks_exact_mut(word_size)
62 .zip(self.limbs[..self.len as usize].iter().rev())
63 {
64 let word_bytes = word.to_be_bytes();
65 for (dst, src) in chunk.iter_mut().zip(word_bytes.as_ref()) {
66 *dst = *src;
67 }
68 }
69 &out[..byte_count]
70 }
71
72 pub fn to_le_bytes<'a>(&self, out: &'a mut [u8]) -> &'a [u8] {
75 let word_size = core::mem::size_of::<T>();
76 let byte_count = self.len as usize * word_size;
77 assert!(
78 out.len() >= byte_count,
79 "HeaplessBigInt::to_le_bytes: out.len() < required ({byte_count} bytes)"
80 );
81 for (chunk, word) in out[..byte_count]
82 .chunks_exact_mut(word_size)
83 .zip(self.limbs[..self.len as usize].iter())
84 {
85 let word_bytes = word.to_le_bytes();
86 for (dst, src) in chunk.iter_mut().zip(word_bytes.as_ref()) {
87 *dst = *src;
88 }
89 }
90 &out[..byte_count]
91 }
92
93 pub fn from_be_bytes(bytes: &[u8]) -> Self {
99 let word_size = core::mem::size_of::<T>();
100 let max_bytes = CAP * word_size;
101 assert!(
102 bytes.len() <= max_bytes,
103 "HeaplessBigInt::from_be_bytes: input {} bytes > CAP * word_size ({max_bytes})",
104 bytes.len()
105 );
106 let byte_count = bytes.len();
107 let out_len = byte_count.div_ceil(word_size);
108
109 let mut limbs = [zero::<T>(); CAP];
110 let mut hi = byte_count;
113 let mut word_idx = 0;
114 while hi > 0 {
115 let take = core::cmp::min(word_size, hi);
116 let lo = hi - take;
117 limbs[word_idx] = read_be_word::<T>(&bytes[lo..hi]);
118 word_idx += 1;
119 hi = lo;
120 }
121
122 Self {
123 limbs,
124 len: out_len as u16,
125 _p: PhantomData,
126 }
127 }
128
129 pub fn from_le_bytes(bytes: &[u8]) -> Self {
132 let word_size = core::mem::size_of::<T>();
133 let max_bytes = CAP * word_size;
134 assert!(
135 bytes.len() <= max_bytes,
136 "HeaplessBigInt::from_le_bytes: input {} bytes > CAP * word_size ({max_bytes})",
137 bytes.len()
138 );
139 let byte_count = bytes.len();
140 let out_len = byte_count.div_ceil(word_size);
141
142 let mut limbs = [zero::<T>(); CAP];
143 let mut offset = 0;
144 let mut word_idx = 0;
145 while offset < byte_count {
146 let take = core::cmp::min(word_size, byte_count - offset);
147 limbs[word_idx] = read_le_word::<T>(&bytes[offset..offset + take]);
148 word_idx += 1;
149 offset += take;
150 }
151
152 Self {
153 limbs,
154 len: out_len as u16,
155 _p: PhantomData,
156 }
157 }
158}
159
160impl<T: MachineWord, const CAP: usize, P: Personality> HeaplessBigInt<T, CAP, P> {
168 #[inline]
169 fn check_slice_len(len: usize) -> Result<(), ByteSliceError> {
170 if len == 0 {
171 return Err(ByteSliceError {
172 kind: ByteSliceErrorKind::Empty,
173 });
174 }
175 if len > CAP * core::mem::size_of::<T>() {
176 return Err(ByteSliceError {
177 kind: ByteSliceErrorKind::Overflow,
178 });
179 }
180 Ok(())
181 }
182}
183
184impl<T: MachineWord, const CAP: usize, P: Personality> FromByteSlice for HeaplessBigInt<T, CAP, P> {
185 fn from_be_slice(bytes: &[u8]) -> Result<Self, ByteSliceError> {
186 Self::check_slice_len(bytes.len())?;
187 Ok(Self::from_be_bytes(bytes))
188 }
189
190 fn from_le_slice(bytes: &[u8]) -> Result<Self, ByteSliceError> {
191 Self::check_slice_len(bytes.len())?;
192 Ok(Self::from_le_bytes(bytes))
193 }
194}