Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_core/src/byte.rs

7.4 KiB, 32 runs

created by r1870400018:66, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use crate::{
2 prelude::*,
3 id::ParseId,
4 string::{
5 parse_hex_char,
6 ToHexString,
7 },
8};
9
10use std::{
11 cmp::Ordering,
12 fmt,
13};
14
15pub fn byte_slices_equal(a: &[u8], b: &[u8]) -> Outcome<()> {
16 for (i, ai) in a.iter().enumerate() {
17 if *ai != b[i] {
18 return Err(err!("Mismatch detected"; Input, Mismatch));
19 }
20 }
21 Ok(())
22}
23
24/// Constant-time equality of two byte slices.
25///
26/// The running time depends only on the length of the slices, never on where or
27/// whether their contents first differ, so comparing a secret against attacker-
28/// supplied bytes leaks no timing oracle about how many leading bytes matched. A
29/// length mismatch returns `false` immediately -- the length of a token is not
30/// the secret its bytes are, and a short-circuit there reveals nothing an
31/// attacker could not measure from the response size anyway. Written to resist
32/// the compiler's urge to short-circuit by accumulating a difference over every
33/// byte and testing it once at the end.
34pub fn ct_eq(a: &[u8], b: &[u8]) -> bool {
35 if a.len() != b.len() {
36 return false;
37 }
38 let mut diff: u8 = 0;
39 for (x, y) in a.iter().zip(b.iter()) {
40 diff |= x ^ y;
41 }
42 diff == 0
43}
44
45new_type!(B32, [u8; 32], Clone, Default);
46
47impl std::marker::Copy for B32 {}
48
49impl fmt::Debug for B32 {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 write!(f, "{}", self.to_hex_string())
52 }
53}
54
55impl fmt::Display for B32 {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 write!(f, "{:?}", self.0)
58 }
59}
60
61impl ParseId<32> for B32 {
62 fn parse_id(s: &str) -> Outcome<Self> {
63 let s = s.trim_start_matches("0x");
64 if s.len() != 64 {
65 return Err(err!(
66 "The hexadecimal string '{}' has length {}, but it should be 64 for a B32.",
67 s, s.len();
68 Invalid, Input, String, Size));
69 }
70 if !s.is_ascii() {
71 return Err(err!(
72 "The hexadecimal string '{}' contains at least one non-ASCII character.", s;
73 Invalid, Input, String));
74 }
75
76 let mut result = [0u8; 32];
77 let mut hex_chars = s.chars();
78
79 let mut count: usize = 0;
80 for byt in result.iter_mut() {
81 count += 1;
82 let hc = match hex_chars.next() {
83 Some(c) => c,
84 None => return Err(err!(
85 "Expecting a character at position {} in the hexadecimal string '{}', \
86 but it was not found.", count, s;
87 Invalid, Input, String)),
88 };
89 let high_nibble = res!(parse_hex_char(hc));
90 count += 1;
91 let hc = match hex_chars.next() {
92 Some(c) => c,
93 None => return Err(err!(
94 "Expecting a character at position {} in the hexadecimal string '{}', \
95 but it was not found.", count, s;
96 Invalid, Input, String)),
97 };
98 let low_nibble = res!(parse_hex_char(hc));
99 *byt = high_nibble << 4 | low_nibble;
100 }
101 Ok(Self(result))
102 }
103}
104
105impl Eq for B32 {}
106
107impl PartialEq for B32 {
108 fn eq(&self, other: &Self) -> bool {
109 self.0 == other.0
110 }
111}
112
113impl Ord for B32 {
114 fn cmp(&self, other: &Self) -> Ordering {
115 (self.0).iter().zip((other.0).iter()).fold(Ordering::Equal, |acc, (a, b)| {
116 if a < b {
117 Ordering::Less
118 } else if a > b {
119 Ordering::Greater
120 } else {
121 acc
122 }
123 })
124 }
125}
126
127impl PartialOrd for B32 {
128 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
129 Some(self.cmp(other))
130 }
131}
132
133pub trait IntoBytes {
134 fn into_bytes(self, buf: Vec<u8>) -> Outcome<Vec<u8>>;
135}
136
137pub trait FromBytes {
138 fn from_bytes(buf: &[u8]) -> Outcome<(Self, usize)> where Self: Sized;
139 fn too_few(
140 nbyts: usize,
141 minbyts: usize,
142 desc: &str,
143 file: &'static str,
144 line: u32,
145 )
146 -> Error<ErrTag>
147 {
148 err!(fmt!("{}:{}: Only {} byte{}, require at least {} to decode the {}.",
149 file, line, nbyts, if nbyts == 1 { "" } else { "s" }, minbyts, desc,
150 ); Bytes, Input, Decode, Missing)
151 }
152}
153
154pub trait ToBytes {
155 fn to_bytes(&self, buf: Vec<u8>) -> Outcome<Vec<u8>>;
156}
157
158pub trait FromByteArray: Sized {
159 fn from_byte_array<const L: usize>(buf: [u8; L]) -> Outcome<Self>;
160}
161
162pub trait ToByteArray<const L: usize> {
163 fn to_byte_array(&self) -> [u8; L];
164}
165
166impls_for_native_integer!(u8, 1);
167impls_for_native_integer!(u16, 2);
168impls_for_native_integer!(u32, 4);
169impls_for_native_integer!(u64, 8);
170impls_for_native_integer!(u128, 16);
171//impls_for_native_integer!(usize);
172impls_for_native_integer!(i8, 1);
173impls_for_native_integer!(i16, 2);
174impls_for_native_integer!(i32, 4);
175impls_for_native_integer!(i64, 8);
176impls_for_native_integer!(i128, 16);
177//impls_for_native_integer!(isize);
178
179impl ToBytes for B32 {
180 fn to_bytes(&self, mut buf: Vec<u8>) -> Outcome<Vec<u8>> {
181 buf.extend_from_slice(&self.0);
182 Ok(buf)
183 }
184}
185
186impl FromBytes for B32 {
187 fn from_bytes(buf: &[u8]) -> Outcome<(Self, usize)> {
188 const BYTE_LEN: usize = 32;
189 if buf.len() < BYTE_LEN {
190 return Err(err!(
191 "Not enough bytes to decode, require at least {} \
192 for a {}, slice is of length {}.",
193 BYTE_LEN, std::any::type_name::<Self>(), buf.len();
194 Bytes, Invalid, Input, Decode, Missing));
195 }
196 let n = Self(res!(
197 <[u8; BYTE_LEN]>::try_from(&buf[0..BYTE_LEN]),
198 Decode, Bytes, Integer,
199 ));
200 Ok((n, BYTE_LEN))
201 }
202}
203
204impl FromByteArray for B32 {
205 fn from_byte_array<const L: usize>(buf: [u8; L]) -> Outcome<Self> {
206 const BYTE_LEN: usize = 32;
207 if L < BYTE_LEN {
208 return Err(err!(
209 "Not enough bytes to decode, require at least {} \
210 for a {}, array is of length {}.",
211 BYTE_LEN, std::any::type_name::<Self>(), L;
212 Bytes, Invalid, Input, Decode, Missing));
213 }
214 Ok(Self(res!(
215 <[u8; BYTE_LEN]>::try_from(&buf[0..BYTE_LEN]),
216 Decode, Bytes, Integer,
217 )))
218 }
219}
220
221impl ToByteArray<32> for B32 {
222 fn to_byte_array(&self) -> [u8; 32] {
223 **self
224 }
225}
226
227/// This mutable version is useful when you want to append another vector to buf, rather than
228/// copying.
229pub trait ToBytesMut {
230 fn to_bytes_mut(&mut self, buf: Vec<u8>) -> Outcome<Vec<u8>>;
231}
232
233#[allow(non_camel_case_types)]
234#[repr(u8)]
235#[derive(Clone, Copy, Debug, Eq, PartialEq)]
236pub enum Encoding {
237 Unknown = 0,
238 Binary = 1,
239 UTF8 = 2,
240}
241
242impl Default for Encoding {
243 fn default() -> Self {
244 Self::Unknown
245 }
246}
247
248impl From<u8> for Encoding {
249 fn from(b: u8) -> Self {
250 match b {
251 1 => Self::Binary,
252 2 => Self::UTF8,
253 _ => Self::Unknown,
254 }
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use super::*;
261
262 #[test]
263 fn ct_eq_matches_semantics_of_ordinary_equality() {
264 assert!(ct_eq(b"secret-token", b"secret-token"));
265 assert!(!ct_eq(b"secret-token", b"secret-tokeX"));
266 assert!(!ct_eq(b"secret-token", b"secret")); // different lengths
267 assert!(!ct_eq(b"", b"x"));
268 assert!(ct_eq(b"", b"")); // both empty are equal
269 }
270}