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
| 1 | use oxedyne_fe2o3_core::{ |
| 2 | prelude::*, |
| 3 | alt::{ |
| 4 | Alt, |
| 5 | DefAlt, |
| 6 | }, |
| 7 | byte::byte_slices_equal, |
| 8 | }; |
| 9 | use oxedyne_fe2o3_iop_hash::csum::Checksummer; |
| 10 | use oxedyne_fe2o3_namex::{ |
| 11 | id::{ |
| 12 | LocalId, |
| 13 | InNamex, |
| 14 | NamexId, |
| 15 | }, |
| 16 | }; |
| 17 | |
| 18 | use std::{ |
| 19 | fmt, |
| 20 | str, |
| 21 | }; |
| 22 | |
| 23 | use crc32fast; |
| 24 | |
| 25 | #[derive(Clone)] |
| 26 | pub enum ChecksumScheme { |
| 27 | Crc32(crc32fast::Hasher), |
| 28 | } |
| 29 | |
| 30 | impl 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 | |
| 38 | impl 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 | |
| 77 | impl 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 | |
| 157 | impl 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 | |
| 170 | impl 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 | |
| 183 | impl 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)] |
| 208 | pub struct ChecksummerDefAlt< |
| 209 | D: Checksummer, |
| 210 | G: Checksummer, |
| 211 | > (pub DefAlt<D, G>); |
| 212 | |
| 213 | impl< |
| 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 | |
| 223 | impl< |
| 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 | |
| 236 | impl< |
| 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 | |
| 249 | impl< |
| 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 | |
| 260 | impl< |
| 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 | |
| 308 | impl< |
| 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 | |
| 387 | impl< |
| 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)] |
| 518 | mod 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 | } |