crypto_bigint/
encoding.rs1use crate::bitlen;
4use core::fmt;
5
6#[cfg(feature = "hybrid-array")]
7use {
8 crate::Integer,
9 core::ops::Add,
10 hybrid_array::{Array, ArraySize, typenum::Unsigned},
11};
12
13#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub enum ByteOrder {
16 BigEndian,
18
19 LittleEndian,
21}
22
23#[cfg(feature = "hybrid-array")]
25pub type ByteArray<T> = Array<u8, <T as ArrayEncoding>::ByteSize>;
26
27#[cfg(feature = "hybrid-array")]
29pub trait ArrayEncoding: Encoding {
30 type ByteSize: ArraySize + Add + Eq + Ord + Unsigned;
32
33 fn from_be_byte_array(bytes: ByteArray<Self>) -> Self;
35
36 fn from_le_byte_array(bytes: ByteArray<Self>) -> Self;
38
39 #[inline]
41 fn from_byte_array(bytes: ByteArray<Self>, byte_order: ByteOrder) -> Self {
42 match byte_order {
43 ByteOrder::BigEndian => Self::from_be_byte_array(bytes),
44 ByteOrder::LittleEndian => Self::from_le_byte_array(bytes),
45 }
46 }
47
48 fn to_be_byte_array(&self) -> ByteArray<Self>;
50
51 fn to_le_byte_array(&self) -> ByteArray<Self>;
53
54 #[inline]
56 fn to_byte_array(&self, byte_order: ByteOrder) -> ByteArray<Self> {
57 match byte_order {
58 ByteOrder::BigEndian => self.to_be_byte_array(),
59 ByteOrder::LittleEndian => self.to_le_byte_array(),
60 }
61 }
62}
63
64#[cfg(feature = "hybrid-array")]
66pub trait ArrayDecoding {
67 type Output: ArrayEncoding + Integer;
69
70 fn into_uint_be(self) -> Self::Output;
72
73 fn into_uint_le(self) -> Self::Output;
75}
76
77pub trait Encoding: Sized {
80 type Repr: AsRef<[u8]>
82 + AsMut<[u8]>
83 + Clone
84 + Sized
85 + for<'a> TryFrom<&'a [u8], Error: core::error::Error>;
86
87 #[must_use]
89 fn from_be_bytes(bytes: Self::Repr) -> Self;
90
91 #[must_use]
93 fn from_le_bytes(bytes: Self::Repr) -> Self;
94
95 #[inline]
97 #[must_use]
98 fn from_bytes(bytes: Self::Repr, byte_order: ByteOrder) -> Self {
99 match byte_order {
100 ByteOrder::BigEndian => Self::from_be_bytes(bytes),
101 ByteOrder::LittleEndian => Self::from_le_bytes(bytes),
102 }
103 }
104
105 #[must_use]
110 fn from_be_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
111 assert_eq!(bits_precision, bitlen::from_bytes(size_of::<Self::Repr>()));
112 let bytes = truncate_be(bytes, bits_precision);
113 Self::from_be_bytes(bytes.try_into().expect("input too short"))
114 }
115
116 #[must_use]
121 fn from_le_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
122 assert_eq!(bits_precision, bitlen::from_bytes(size_of::<Self::Repr>()));
123 let bytes = truncate_le(bytes, bits_precision);
124 Self::from_le_bytes(bytes.try_into().expect("input too short"))
125 }
126
127 #[inline]
133 #[must_use]
134 fn from_slice_truncated(bytes: &[u8], bits_precision: u32, byte_order: ByteOrder) -> Self {
135 match byte_order {
136 ByteOrder::BigEndian => Self::from_be_slice_truncated(bytes, bits_precision),
137 ByteOrder::LittleEndian => Self::from_le_slice_truncated(bytes, bits_precision),
138 }
139 }
140
141 #[must_use]
143 fn to_be_bytes(&self) -> Self::Repr;
144
145 #[must_use]
147 fn to_le_bytes(&self) -> Self::Repr;
148
149 #[inline]
151 #[must_use]
152 fn to_bytes(&self, byte_order: ByteOrder) -> Self::Repr {
153 match byte_order {
154 ByteOrder::BigEndian => self.to_be_bytes(),
155 ByteOrder::LittleEndian => self.to_le_bytes(),
156 }
157 }
158}
159
160pub trait EncodedSize {
162 type Target;
164}
165
166#[derive(Clone, Copy, Debug, Eq, PartialEq)]
168pub enum DecodeError {
169 Empty,
171
172 InvalidDigit,
174
175 InputSize,
177
178 Precision,
180}
181
182impl fmt::Display for DecodeError {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 match self {
185 Self::Empty => write!(f, "empty value provided"),
186 Self::InvalidDigit => {
187 write!(f, "invalid digit character")
188 }
189 Self::InputSize => write!(f, "input size is too small to fit in the given precision"),
190 Self::Precision => write!(
191 f,
192 "the deserialized number is larger than the given precision"
193 ),
194 }
195 }
196}
197
198impl core::error::Error for DecodeError {}
199
200pub(crate) fn truncate_be(bytes: &[u8], bits_precision: u32) -> &[u8] {
203 let bytes_precision = bitlen::to_bytes(bits_precision);
204 if bytes.len() > bytes_precision {
205 &bytes[bytes.len().saturating_sub(bytes_precision)..]
206 } else {
207 bytes
208 }
209}
210
211pub(crate) fn truncate_le(bytes: &[u8], bits_precision: u32) -> &[u8] {
214 let bytes_precision = bitlen::to_bytes(bits_precision);
215 if bytes.len() > bytes_precision {
216 &bytes[..bytes_precision]
217 } else {
218 bytes
219 }
220}