crypto_bigint/limb/
encoding.rs1use super::{Limb, Word};
4use crate::{Encoding, bitlen};
5
6impl Limb {
7 #[inline]
9 #[must_use]
10 pub const fn from_be_bytes(bytes: [u8; Self::BYTES]) -> Self {
11 Limb(Word::from_be_bytes(bytes))
12 }
13
14 #[inline]
16 #[must_use]
17 pub const fn from_le_bytes(bytes: [u8; Self::BYTES]) -> Self {
18 Limb(Word::from_le_bytes(bytes))
19 }
20
21 #[must_use]
26 #[track_caller]
27 pub const fn from_be_slice(bytes: &[u8]) -> Self {
28 let offset = Self::BYTES
29 .checked_sub(bytes.len())
30 .expect("The given slice is larger than Limb::BYTES");
31
32 let mut repr = [0u8; Self::BYTES];
33 let mut i = 0;
34 while i < bytes.len() {
35 repr[offset + i] = bytes[i];
36 i += 1;
37 }
38 Self::from_be_bytes(repr)
39 }
40
41 #[must_use]
46 #[track_caller]
47 pub const fn from_le_slice(bytes: &[u8]) -> Self {
48 assert!(
49 bytes.len() <= Self::BYTES,
50 "The given slice is larger than Limb::BYTES"
51 );
52
53 let mut repr = [0u8; Self::BYTES];
54 let mut i = 0;
55 while i < bytes.len() {
56 repr[i] = bytes[i];
57 i += 1;
58 }
59 Self::from_le_bytes(repr)
60 }
61
62 #[inline]
69 #[must_use]
70 #[track_caller]
71 pub const fn from_be_slice_truncated(mut bytes: &[u8], bits_precision: u32) -> Self {
72 assert!(bits_precision <= Self::BITS);
73 let bytes_precision = bitlen::to_bytes(bits_precision);
74 if bytes.len() > bytes_precision {
75 bytes = bytes
76 .split_at(bytes.len().saturating_sub(bytes_precision))
77 .1;
78 }
79
80 let mut ret = Self::from_be_slice(bytes);
81 ret.mask_to_precision(bits_precision);
82 ret
83 }
84
85 #[inline]
92 #[must_use]
93 #[track_caller]
94 pub const fn from_le_slice_truncated(mut bytes: &[u8], bits_precision: u32) -> Self {
95 assert!(bits_precision <= Self::BITS);
96 let bytes_precision = bitlen::to_bytes(bits_precision);
97 if bytes.len() > bytes_precision {
98 bytes = bytes.split_at(bytes_precision).0;
99 }
100
101 let mut ret = Self::from_le_slice(bytes);
102 ret.mask_to_precision(bits_precision);
103 ret
104 }
105
106 #[inline]
108 #[must_use]
109 pub const fn to_be_bytes(&self) -> [u8; Self::BYTES] {
110 self.0.to_be_bytes()
111 }
112
113 #[inline]
115 #[must_use]
116 pub const fn to_le_bytes(&self) -> [u8; Self::BYTES] {
117 self.0.to_le_bytes()
118 }
119
120 #[inline(always)]
122 pub(crate) const fn mask_to_precision(&mut self, bits_precision: u32) {
123 debug_assert!(bits_precision <= Self::BITS);
124 self.0 &= Word::MAX >> (Limb::BITS.saturating_sub(bits_precision));
125 }
126}
127
128impl Encoding for Limb {
129 type Repr = [u8; Self::BYTES];
130
131 #[inline]
132 fn from_be_bytes(bytes: Self::Repr) -> Self {
133 Self::from_be_bytes(bytes)
134 }
135
136 #[inline]
137 fn from_le_bytes(bytes: Self::Repr) -> Self {
138 Self::from_le_bytes(bytes)
139 }
140
141 #[inline]
142 fn from_be_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
143 Self::from_be_slice_truncated(bytes, bits_precision)
144 }
145
146 #[inline]
147 fn from_le_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
148 Self::from_le_slice_truncated(bytes, bits_precision)
149 }
150
151 #[inline]
152 fn to_be_bytes(&self) -> Self::Repr {
153 self.to_be_bytes()
154 }
155
156 #[inline]
157 fn to_le_bytes(&self) -> Self::Repr {
158 self.to_le_bytes()
159 }
160}
161
162#[cfg(test)]
163mod test {
164 use super::*;
165
166 cpubits::cpubits! {
167 32 => { const LIMB: Limb = Limb(0x7654_3210); }
168 64 => { const LIMB: Limb = Limb(0xFEDCBA9876543210); }
169 }
170
171 #[test]
172 fn from_be_slice_truncated() {
173 let limb = Limb::from_be_slice_truncated(&[1], 32);
175 assert_eq!(limb, Limb::ONE);
176
177 let limb = Limb::from_be_slice_truncated(&[3], 1);
179 assert_eq!(limb, Limb::ONE);
180 }
181
182 #[test]
183 #[should_panic]
184 fn from_be_slice_truncated_oversized() {
185 let _ = Limb::from_be_slice_truncated(b"", 65);
186 }
187
188 #[test]
189 fn from_le_slice_truncated() {
190 let limb = Limb::from_le_slice_truncated(&[1], 32);
192 assert_eq!(limb, Limb::ONE);
193
194 let limb = Limb::from_le_slice_truncated(&[1], 1);
196 assert_eq!(limb, Limb::ONE);
197 }
198
199 #[test]
200 #[should_panic]
201 fn from_le_slice_truncated_oversized() {
202 let _ = Limb::from_le_slice_truncated(b"", 65);
203 }
204
205 #[test]
206 fn roundtrip() {
207 assert_eq!(LIMB, Limb::from_be_bytes(LIMB.to_be_bytes()));
208 assert_eq!(LIMB, Limb::from_le_bytes(LIMB.to_le_bytes()));
209 }
210
211 #[test]
212 fn reverse() {
213 let mut bytes = LIMB.to_be_bytes();
214 bytes.reverse();
215 assert_eq!(LIMB, Limb::from_le_bytes(bytes));
216
217 let mut bytes = LIMB.to_le_bytes();
218 bytes.reverse();
219 assert_eq!(LIMB, Limb::from_be_bytes(bytes));
220 }
221}