1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
pub const ECMA: u64 = 0xc96c5795d7870f42; pub const ISO: u64 = 0xd800000000000000; lazy_static! { static ref ECMA_TABLE: [u64; 256] = make_table(ECMA); static ref ISO_TABLE: [u64; 256] = make_table(ISO); } pub struct Digest { table: [u64; 256], value: u64 } pub trait Hasher64 { fn reset(&mut self); fn write(&mut self, bytes: &[u8]); fn sum64(&self) -> u64; } pub fn make_table(poly: u64) -> [u64; 256] { let mut table = [0u64; 256]; for i in 0..256 { let mut value = i as u64; for _ in 0..8 { value = if (value & 1) == 1 { (value >> 1) ^ poly } else { value >> 1 } } table[i] = value; } table } pub fn update(mut value: u64, table: &[u64; 256], bytes: &[u8]) -> u64 { value = !value; for &i in bytes.iter() { value = table[((value as u8) ^ i) as usize] ^ (value >> 8) } !value } pub fn checksum_ecma(bytes: &[u8]) -> u64 { return update(0, &ECMA_TABLE, bytes); } pub fn checksum_iso(bytes: &[u8]) -> u64 { return update(0, &ISO_TABLE, bytes); } impl Digest { pub fn new(poly: u64) -> Digest { Digest { table: make_table(poly), value: 0, } } } impl Hasher64 for Digest { fn reset(&mut self) { self.value = 0; } fn write(&mut self, bytes: &[u8]) { self.value = update(self.value, &self.table, bytes); } fn sum64(&self) -> u64 { self.value } } #[cfg(test)] mod tests { use super::*; use test::Bencher; const ECMA_CHECK_VALUE: u64 = 0x995dc9bbdf1939fa; const ISO_CHECK_VALUE: u64 = 0xb90956c775a41001; #[test] fn test_checksum_ecma() { assert_eq!(checksum_ecma(b"123456789"), ECMA_CHECK_VALUE) } #[test] fn test_checksum_iso() { assert_eq!(checksum_iso(b"123456789"), ISO_CHECK_VALUE) } #[test] fn test_digest_ecma() { verify_checksum(ECMA, ECMA_CHECK_VALUE); } #[test] fn test_digest_iso() { verify_checksum(ISO, ISO_CHECK_VALUE); } #[bench] fn bench_make_table(b: &mut Bencher) { b.iter(|| make_table(ECMA)); } #[bench] fn bench_update_megabytes(b: &mut Bencher) { let table = make_table(ECMA); let bytes = Box::new([0u8; 1_000_000]); b.iter(|| update(0, &table, &*bytes)); } fn verify_checksum(poly: u64, check_value: u64) { let mut digest = Digest::new(poly); digest.write(b"123456789"); assert_eq!(digest.sum64(), check_value); digest.reset(); for i in 1..10 { digest.write(i.to_string().as_bytes()); } assert_eq!(digest.sum64(), check_value); } }