1use crate::table::crc8_table;
2use crate::util::crc8;
3use crate::*;
4use crc_catalog::Algorithm;
5
6impl<const L: usize> Crc<u8, Table<L>>
7where
8 Table<L>: private::Sealed,
9{
10 pub const fn new(algorithm: &'static Algorithm<u8>) -> Self {
11 Self {
12 algorithm,
13 data: crc8_table(algorithm.width, algorithm.poly, algorithm.refin),
14 }
15 }
16
17 pub const fn checksum(&self, bytes: &[u8]) -> u8 {
18 let mut crc = init(self.algorithm, self.algorithm.init);
19 crc = self.update(crc, bytes);
20 finalize(self.algorithm, crc)
21 }
22
23 const fn update(&self, crc: u8, bytes: &[u8]) -> u8 {
24 update_table(crc, self.algorithm, &self.data, bytes)
25 }
26
27 pub const fn digest(&self) -> Digest<u8, Table<L>> {
28 self.digest_with_initial(self.algorithm.init)
29 }
30
31 pub const fn digest_with_initial(&self, initial: u8) -> Digest<u8, Table<L>> {
37 let value = init(self.algorithm, initial);
38 Digest::new(self, value)
39 }
40
41 pub const fn table(&self) -> &<Table<L> as Implementation>::Data<u8> {
42 &self.data
43 }
44}
45
46impl<'a, const L: usize> Digest<'a, u8, Table<L>>
47where
48 Table<L>: private::Sealed,
49{
50 const fn new(crc: &'a Crc<u8, Table<L>>, value: u8) -> Self {
51 Digest { crc, value }
52 }
53
54 pub fn update(&mut self, bytes: &[u8]) {
55 self.value = self.crc.update(self.value, bytes);
56 }
57
58 pub const fn finalize(self) -> u8 {
59 finalize(self.crc.algorithm, self.value)
60 }
61}
62
63const fn init(algorithm: &Algorithm<u8>, initial: u8) -> u8 {
64 if algorithm.refin {
65 initial.reverse_bits() >> (8u8 - algorithm.width)
66 } else {
67 initial << (8u8 - algorithm.width)
68 }
69}
70
71const fn finalize(algorithm: &Algorithm<u8>, mut crc: u8) -> u8 {
72 if algorithm.refin ^ algorithm.refout {
73 crc = crc.reverse_bits();
74 }
75 if !algorithm.refout {
76 crc >>= 8u8 - algorithm.width;
77 }
78 crc ^ algorithm.xorout
79}
80
81const fn update_table<const L: usize>(
82 mut crc: u8,
83 algorithm: &Algorithm<u8>,
84 table: &[[u8; 256]; L],
85 bytes: &[u8],
86) -> u8 {
87 let len = bytes.len();
88 let mut i = 0;
89
90 if L == 16 {
92 while i + 16 <= len {
93 crc = table[0][bytes[i + 15] as usize]
94 ^ table[1][bytes[i + 14] as usize]
95 ^ table[2][bytes[i + 13] as usize]
96 ^ table[3][bytes[i + 12] as usize]
97 ^ table[4][bytes[i + 11] as usize]
98 ^ table[5][bytes[i + 10] as usize]
99 ^ table[6][bytes[i + 9] as usize]
100 ^ table[7][bytes[i + 8] as usize]
101 ^ table[8][bytes[i + 7] as usize]
102 ^ table[9][bytes[i + 6] as usize]
103 ^ table[10][bytes[i + 5] as usize]
104 ^ table[11][bytes[i + 4] as usize]
105 ^ table[12][bytes[i + 3] as usize]
106 ^ table[13][bytes[i + 2] as usize]
107 ^ table[14][bytes[i + 1] as usize]
108 ^ table[15][(bytes[i] ^ crc) as usize];
109 i += 16;
110 }
111 }
112
113 if L > 0 {
115 while i < len {
116 crc = table[0][(crc ^ bytes[i]) as usize];
117 i += 1;
118 }
119 } else {
120 let poly = if algorithm.refin {
122 let poly = algorithm.poly.reverse_bits();
123 poly >> (8u8 - algorithm.width)
124 } else {
125 algorithm.poly << (8u8 - algorithm.width)
126 };
127
128 while i < len {
129 crc = crc8(poly, algorithm.refin, crc ^ bytes[i]);
130 i += 1;
131 }
132 }
133
134 crc
135}
136
137#[cfg(test)]
138mod test {
139 use crate::*;
140 use crc_catalog::{Algorithm, CRC_8_BLUETOOTH};
141
142 #[test]
144 fn correctness() {
145 let data: &[&str] = &[
146 "",
147 "1",
148 "1234",
149 "123456789",
150 "0123456789ABCDE",
151 "01234567890ABCDEFGHIJK",
152 "01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK01234567890ABCDEFGHIJK",
153 ];
154
155 pub const CRC_8_BLUETOOTH_NONREFLEX: Algorithm<u8> = Algorithm {
156 width: 8,
157 poly: 0xa7,
158 init: 0x00,
159 refin: false,
160 refout: true,
161 xorout: 0x00,
162 check: 0x26,
163 residue: 0x00,
164 };
165
166 let algs_to_test = [&CRC_8_BLUETOOTH, &CRC_8_BLUETOOTH_NONREFLEX];
167
168 for alg in algs_to_test {
169 for data in data {
170 let crc_slice16 = Crc::<u8, Table<16>>::new(alg);
171 let crc_nolookup = Crc::<u8, NoTable>::new(alg);
173 let expected = Crc::<u8, Table<1>>::new(alg).checksum(data.as_bytes());
174
175 assert_eq!(crc_slice16.checksum(data.as_bytes()), expected);
177 assert_eq!(crc_nolookup.checksum(data.as_bytes()), expected);
178
179 let mut digest = crc_slice16.digest();
180 digest.update(data.as_bytes());
181 assert_eq!(digest.finalize(), expected);
182
183 let mut digest = crc_nolookup.digest();
184 digest.update(data.as_bytes());
185 assert_eq!(digest.finalize(), expected);
186
187 if data.len() > 2 {
189 let data = data.as_bytes();
190 let data1 = &data[..data.len() / 2];
191 let data2 = &data[data.len() / 2..];
192 let mut digest = crc_slice16.digest();
193 digest.update(data1);
194 digest.update(data2);
195 assert_eq!(digest.finalize(), expected);
196 let mut digest = crc_nolookup.digest();
197 digest.update(data1);
198 digest.update(data2);
199 assert_eq!(digest.finalize(), expected);
200 }
201 }
202 }
203 }
204}