Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_hash/src/csum.rs

16.5 KiB, 106 runs

created by r1870400018:349, 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 oxedyne_fe2o3_core::{
2 prelude::*,
3 alt::{
4 Alt,
5 DefAlt,
6 },
7 byte::byte_slices_equal,
8};
9use oxedyne_fe2o3_iop_hash::csum::Checksummer;
10use oxedyne_fe2o3_namex::{
11 id::{
12 LocalId,
13 InNamex,
14 NamexId,
15 },
16};
17
18use std::{
19 fmt,
20 str,
21};
22
23use crc32fast;
24
25#[derive(Clone)]
26pub enum ChecksumScheme {
27 Crc32(crc32fast::Hasher),
28}
29
30impl fmt::Debug for ChecksumScheme {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 match self {
33 Self::Crc32(..) => write!(f, "Crc32"),
34 }
35 }
36}
37
38impl InNamex for ChecksumScheme {
39
40 fn name_id(&self) -> Outcome<NamexId> {
41 Ok(match self {
42 Self::Crc32(..) =>
43 res!(NamexId::try_from("+n9EN0dPKFF7q6iiwjtkgAUyT3odnl95JwnQd4z+jfw=")),
44 })
45 }
46
47 fn local_id(&self) -> LocalId {
48 match self {
49 Self::Crc32(..) => LocalId(1),
50 }
51 }
52
53 fn assoc_names_base64(
54 gname: &'static str,
55 )
56 -> Outcome<Option<Vec<(
57 &'static str,
58 &'static str,
59 )>>>
60 {
61 let ids = match gname {
62 "schemes" => [
63 ("CRC32", "9m5ja11mi86oosyB7LG4Kvcx83ln3stpD0/8Pnq01tE="),
64 ],
65 _ => return Err(err!(
66 "The Namex group name '{}' is not recognised for ChecksumScheme.", gname;
67 Invalid, Input)),
68 };
69 Ok(if ids.len() == 0 {
70 None
71 } else {
72 Some(ids.to_vec())
73 })
74 }
75}
76
77impl Checksummer for ChecksumScheme {
78
79 fn len(&self) -> Outcome<usize> {
80 match self {
81 Self::Crc32(_) => Ok(4),
82 }
83 }
84
85 /// Calculate the checksum of the supplied byte slice.
86 fn calculate(mut self, buf: &[u8]) -> Outcome<Vec<u8>> {
87 res!(self.update(buf));
88 self.finalize()
89 }
90
91 fn update(&mut self, buf: &[u8]) -> Outcome<()> {
92 match self {
93 Self::Crc32(hasher) => hasher.update(&buf),
94 }
95 Ok(())
96 }
97
98 /// Calculate the checksum of the supplied byte slice.
99 fn finalize(self) -> Outcome<Vec<u8>> {
100 match self {
101 Self::Crc32(hasher) => {
102 let csum = hasher.finalize();
103 Ok(csum.to_be_bytes().to_vec())
104 },
105 }
106 }
107
108 fn copy(&self, buf: &[u8]) -> Outcome<Vec<u8>> {
109 let clen = res!(self.len());
110 if buf.len() < clen {
111 return Err(err!(
112 "Cannot snip checksum from given byte slice of length {} \
113 because it is less than the required minimum {}.",
114 buf.len(), clen;
115 Input, Mismatch))
116 }
117 Ok(buf[buf.len() - clen..].to_vec())
118 }
119
120 fn append(self, mut buf: Vec<u8>) -> Outcome<(Vec<u8>, Vec<u8>)> {
121 let csum = res!(self.calculate(&buf));
122 buf.extend_from_slice(&csum);
123 Ok((buf, csum))
124 }
125
126 /// Assumes that the specified buffer contains data with an appended checksum. This function
127 /// returns an error if the checksum cannot be reproduced.
128 fn verify(self, buf: &[u8]) -> Outcome<Vec<u8>> {
129 let clen = res!(self.len());
130 if buf.len() < clen {
131 return Err(err!(
132 "A request to verify the checksum of a slice of bytes of length {} \
133 requires the slice to be at least the length of a checksum, {}.",
134 buf.len(), clen;
135 Input, Mismatch))
136 }
137 let csum1 = res!(self.calculate(&buf[..buf.len() - clen]));
138 let csum2 = &buf[buf.len() - clen..];
139 res!(byte_slices_equal(&csum1, csum2), Checksum);
140 Ok(csum1)
141 }
142
143 fn read_bytes<R: std::io::Read>(
144 &self,
145 r: &mut R,
146 )
147 -> Outcome<(Vec<u8>, usize)>
148 {
149 let clen = res!(self.len());
150 let mut csum = vec![0u8; clen];
151 res!(r.read_exact(&mut csum));
152 Ok((csum.to_vec(), clen))
153 }
154
155}
156
157impl str::FromStr for ChecksumScheme {
158 type Err = Error<ErrTag>;
159
160 fn from_str(name: &str) -> std::result::Result<Self, Self::Err> {
161 match name {
162 "CRC32" => Ok(Self::new_crc32()),
163 _ => Err(err!(
164 "The checksum scheme '{}' is not recognised.", name;
165 Invalid, Input)),
166 }
167 }
168}
169
170impl TryFrom<LocalId> for ChecksumScheme {
171 type Error = Error<ErrTag>;
172
173 fn try_from(n: LocalId) -> std::result::Result<Self, Self::Error> {
174 match n {
175 LocalId(1) => Ok(Self::new_crc32()),
176 _ => Err(err!(
177 "The checksum scheme with local id {} is not recognised.", n;
178 Invalid, Input)),
179 }
180 }
181}
182
183impl ChecksumScheme {
184
185 pub const CRC32_BYTE_LEN: usize = 4;
186 //pub const USR_VERSION: SemVer = SemVer::new(0,0,1);
187
188 //pub fn new(name: &str) -> Outcome<Self> {
189 // match name {
190 // "CRC32" => Ok(Self::new_crc32()),
191 // _ => Err(err!(
192 // "The checksum scheme '{}' is not recognised.", name,
193 // ), Invalid, Input)),
194 // }
195 //}
196
197 pub fn new_crc32() -> Self {
198 Self::Crc32(crc32fast::Hasher::new())
199 }
200
201 pub fn compare(csum1: &[u8], csum2: &[u8]) -> Outcome<()> {
202 res!(byte_slices_equal(csum1, csum2), Checksum);
203 Ok(())
204 }
205}
206
207#[derive(Clone, Debug, Default)]
208pub struct ChecksummerDefAlt<
209 D: Checksummer,
210 G: Checksummer,
211> (pub DefAlt<D, G>);
212
213impl<
214 D: Checksummer,
215 G: Checksummer,
216>
217 std::ops::Deref for ChecksummerDefAlt<D, G>
218{
219 type Target = DefAlt<D, G>;
220 fn deref(&self) -> &Self::Target { &self.0 }
221}
222
223impl<
224 D: Checksummer,
225 G: Checksummer,
226>
227 From<Option<G>> for ChecksummerDefAlt<D, G>
228{
229 fn from(opt: Option<G>) -> Self {
230 Self(
231 DefAlt::from(opt),
232 )
233 }
234}
235
236impl<
237 D: Checksummer,
238 G: Checksummer,
239>
240 From<Alt<G>> for ChecksummerDefAlt<D, G>
241{
242 fn from(alt: Alt<G>) -> Self {
243 Self(
244 DefAlt::from(alt),
245 )
246 }
247}
248
249impl<
250 D: Checksummer,
251 G: Checksummer,
252>
253 fmt::Display for ChecksummerDefAlt<D, G>
254{
255 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256 write!(f, "{:?}", self)
257 }
258}
259
260impl<
261 D: Checksummer + InNamex,
262 G: Checksummer + InNamex,
263>
264 InNamex for ChecksummerDefAlt<D, G>
265{
266 fn name_id(&self) -> Outcome<NamexId> {
267 match &self.0 {
268 DefAlt::Default(inner) => inner.name_id(),
269 DefAlt::Given(inner) => inner.name_id(),
270 DefAlt::None => Err(err!(
271 "No Namex id can be specified for DefAlt::None.";
272 Missing, Bug)),
273 }
274 }
275
276 fn local_id(&self) -> LocalId {
277 match &self.0 {
278 DefAlt::Default(inner) => inner.local_id(),
279 DefAlt::Given(inner) => inner.local_id(),
280 DefAlt::None => LocalId::default(),
281 }
282 }
283
284 fn assoc_names_base64(
285 gname: &'static str,
286 )
287 -> Outcome<Option<Vec<(
288 &'static str,
289 &'static str,
290 )>>>
291 {
292 match res!(D::assoc_names_base64(gname)) {
293 Some(mut vd) => match res!(G::assoc_names_base64(gname)) {
294 Some(vg) => {
295 vd.extend(vg);
296 Ok(Some(vd))
297 },
298 None => Ok(Some(vd)),
299 },
300 None => match res!(G::assoc_names_base64(gname)) {
301 Some(vg) => Ok(Some(vg)),
302 None => Ok(None),
303 },
304 }
305 }
306}
307
308impl<
309 D: Checksummer,
310 G: Checksummer,
311>
312 Checksummer for ChecksummerDefAlt<D, G>
313{
314 fn len(&self) -> Outcome<usize> {
315 match &self.0 {
316 DefAlt::Default(inner) => inner.len(),
317 DefAlt::Given(inner) => inner.len(),
318 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
319 Configuration, Missing)),
320 }
321 }
322
323 fn calculate(self, buf: &[u8]) -> Outcome<Vec<u8>> {
324 match self.0 {
325 DefAlt::Default(inner) => inner.calculate(buf),
326 DefAlt::Given(inner) => inner.calculate(buf),
327 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
328 Configuration, Missing)),
329 }
330 }
331
332 fn update(&mut self, buf: &[u8]) -> Outcome<()> {
333 match &mut self.0 {
334 DefAlt::Default(inner) => inner.update(buf),
335 DefAlt::Given(inner) => inner.update(buf),
336 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
337 Configuration, Missing)),
338 }
339 }
340
341 fn finalize(self) -> Outcome<Vec<u8>> {
342 match self.0 {
343 DefAlt::Default(inner) => inner.finalize(),
344 DefAlt::Given(inner) => inner.finalize(),
345 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
346 Configuration, Missing)),
347 }
348 }
349
350 fn copy(&self, buf: &[u8]) -> Outcome<Vec<u8>>{
351 match &self.0 {
352 DefAlt::Default(inner) => inner.copy(buf),
353 DefAlt::Given(inner) => inner.copy(buf),
354 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
355 Configuration, Missing)),
356 }
357 }
358
359 fn append(self, buf: Vec<u8>) -> Outcome<(Vec<u8>, Vec<u8>)> {
360 match self.0 {
361 DefAlt::Default(inner) => inner.append(buf),
362 DefAlt::Given(inner) => inner.append(buf),
363 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
364 Configuration, Missing)),
365 }
366 }
367
368 fn verify(self, buf: &[u8]) -> Outcome<Vec<u8>> {
369 match self.0 {
370 DefAlt::Default(inner) => inner.verify(buf),
371 DefAlt::Given(inner) => inner.verify(buf),
372 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
373 Configuration, Missing)),
374 }
375 }
376
377 fn read_bytes<R: std::io::Read>(&self, r: &mut R) -> Outcome<(Vec<u8>, usize)> {
378 match &self.0 {
379 DefAlt::Default(inner) => inner.read_bytes(r),
380 DefAlt::Given(inner) => inner.read_bytes(r),
381 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
382 Configuration, Missing)),
383 }
384 }
385}
386
387impl<
388 D: Checksummer,
389 G: Checksummer,
390>
391 ChecksummerDefAlt<D, G>
392{
393 pub const HASHER_MISSING_MSG: &'static str = "Checksum hasher not specified.";
394
395 pub fn or_len<OR: Checksummer>(&self, alt: &Alt<OR>) -> Outcome<usize> {
396 match &alt {
397 Alt::Specific(Some(inner)) => inner.len(),
398 Alt::Specific(None) => Err(err!("{}", Self::HASHER_MISSING_MSG;
399 Configuration, Missing)),
400 Alt::Unspecified => match &self.0 {
401 DefAlt::Default(inner) => inner.len(),
402 DefAlt::Given(inner) => inner.len(),
403 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
404 Configuration, Missing)),
405 },
406 }
407 }
408
409 pub fn or_calculate<OR: Checksummer>(self, buf: &[u8], alt: Alt<OR>) -> Outcome<Vec<u8>> {
410 match alt {
411 Alt::Specific(Some(inner)) => inner.calculate(buf),
412 Alt::Specific(None) => Err(err!("{}", Self::HASHER_MISSING_MSG;
413 Configuration, Missing)),
414 Alt::Unspecified => match self.0 {
415 DefAlt::Default(inner) => inner.calculate(buf),
416 DefAlt::Given(inner) => inner.calculate(buf),
417 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
418 Configuration, Missing)),
419 },
420 }
421 }
422
423 pub fn or_update<OR: Checksummer>(&mut self, buf: &[u8], mut alt: &mut Alt<OR>) -> Outcome<()> {
424 match &mut alt {
425 Alt::Specific(Some(inner)) => inner.update(buf),
426 Alt::Specific(None) => Err(err!("{}", Self::HASHER_MISSING_MSG;
427 Configuration, Missing)),
428 Alt::Unspecified => match &mut self.0 {
429 DefAlt::Default(inner) => inner.update(buf),
430 DefAlt::Given(inner) => inner.update(buf),
431 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
432 Configuration, Missing)),
433 },
434 }
435 }
436
437 pub fn or_finalize<OR: Checksummer>(self, alt: Alt<OR>) -> Outcome<Vec<u8>> {
438 match alt {
439 Alt::Specific(Some(inner)) => inner.finalize(),
440 Alt::Specific(None) => Err(err!("{}", Self::HASHER_MISSING_MSG;
441 Configuration, Missing)),
442 Alt::Unspecified => match self.0 {
443 DefAlt::Default(inner) => inner.finalize(),
444 DefAlt::Given(inner) => inner.finalize(),
445 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
446 Configuration, Missing)),
447 },
448 }
449 }
450
451 pub fn or_copy<OR: Checksummer>(&self, buf: &[u8], alt: &Alt<OR>) -> Outcome<Vec<u8>>{
452 match &alt {
453 Alt::Specific(Some(inner)) => inner.copy(buf),
454 Alt::Specific(None) => Err(err!("{}", Self::HASHER_MISSING_MSG;
455 Configuration, Missing)),
456 Alt::Unspecified => match &self.0 {
457 DefAlt::Default(inner) => inner.copy(buf),
458 DefAlt::Given(inner) => inner.copy(buf),
459 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
460 Configuration, Missing)),
461 },
462 }
463 }
464
465 pub fn or_append<OR: Checksummer>(self, buf: Vec<u8>, alt: Alt<OR>) -> Outcome<(Vec<u8>, Vec<u8>)> {
466 match alt {
467 Alt::Specific(Some(inner)) => inner.append(buf),
468 Alt::Specific(None) => Err(err!("{}", Self::HASHER_MISSING_MSG;
469 Configuration, Missing)),
470 Alt::Unspecified => match self.0 {
471 DefAlt::Default(inner) => inner.append(buf),
472 DefAlt::Given(inner) => inner.append(buf),
473 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
474 Configuration, Missing)),
475 },
476 }
477 }
478
479 pub fn or_verify<OR: Checksummer>(self, buf: &[u8], alt: Alt<OR>) -> Outcome<Vec<u8>> {
480 match alt {
481 Alt::Specific(Some(inner)) => inner.verify(buf),
482 Alt::Specific(None) => Err(err!("{}", Self::HASHER_MISSING_MSG;
483 Configuration, Missing)),
484 Alt::Unspecified => match self.0 {
485 DefAlt::Default(inner) => inner.verify(buf),
486 DefAlt::Given(inner) => inner.verify(buf),
487 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
488 Configuration, Missing)),
489 },
490 }
491 }
492
493 pub fn or_read_bytes<
494 R: std::io::Read,
495 OR: Checksummer,
496 >(
497 &self,
498 r: &mut R,
499 alt: &Alt<OR>,
500 )
501 -> Outcome<(Vec<u8>, usize)>
502 {
503 match &alt {
504 Alt::Specific(Some(inner)) => inner.read_bytes(r),
505 Alt::Specific(None) => Err(err!("{}", Self::HASHER_MISSING_MSG;
506 Configuration, Missing)),
507 Alt::Unspecified => match &self.0 {
508 DefAlt::Default(inner) => inner.read_bytes(r),
509 DefAlt::Given(inner) => inner.read_bytes(r),
510 DefAlt::None => Err(err!("{}", Self::HASHER_MISSING_MSG;
511 Configuration, Missing)),
512 },
513 }
514 }
515}
516
517#[cfg(test)]
518mod tests {
519 use super::*;
520
521 /// The CRC-32 check value: the standard, published checksum of the string "123456789".
522 #[test]
523 fn test_crc32_check_value() -> Outcome<()> {
524 let crc32 = ChecksumScheme::new_crc32();
525 // `calculate` consumes the scheme, and `req!` renders its arguments a second time when it
526 // fails, so the value is taken once and compared as a binding.
527 let csum = res!(crc32.calculate(b"123456789"));
528 req!(csum, 0xCBF4_3926u32.to_be_bytes().to_vec());
529 Ok(())
530 }
531
532 #[test]
533 fn test_read_checksum() -> Outcome<()> {
534 let byts = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
535 let crc32 = ChecksumScheme::new_crc32();
536 let (csum, len) = res!(crc32.read_bytes(&mut byts.as_slice()));
537 req!(len, ChecksumScheme::CRC32_BYTE_LEN);
538 req!(csum, vec![1u8, 2, 3, 4]);
539 Ok(())
540 }
541
542 /// An appended checksum verifies, and a single altered byte does not.
543 #[test]
544 fn test_append_and_verify() -> Outcome<()> {
545 let byts = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
546 let (mut buf, csum) = res!(ChecksumScheme::new_crc32().append(byts.clone()));
547 req!(buf.len(), byts.len() + ChecksumScheme::CRC32_BYTE_LEN);
548 req!(res!(ChecksumScheme::new_crc32().verify(&buf)), csum);
549 buf[2] ^= 0x01; // Corrupt one byte of the data.
550 match ChecksumScheme::new_crc32().verify(&buf) {
551 Ok(_) => Err(err!(
552 "A buffer with an altered byte should not have verified."; Test, Unexpected)),
553 Err(_) => Ok(()),
554 }
555 }
556}