config_generator/crc.rs
1// Copyright (c) 2026 Tuloup Simon
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program. If not, see <https://www.gnu.org/licenses/>.
15
16//! CRC-16 implementation used to compute the lock-confirmation hash of
17//! the writable portion of the configuration zone.
18//!
19//! This is a deliberate duplicate of the same algorithm used in the
20//! firmware (`crates/atecc608b/src/crc.rs`). The duplication keeps the
21//! generator self-contained: it does not pull the embedded driver crate
22//! and its no_std machinery into a host build. Both implementations are
23//! tested against the same set of reference vectors taken from the
24//! Microchip CryptoAuthLib C source.
25//!
26//! Parameters:
27//! - Polynomial: 0x8005
28//! - Initial value: 0x0000
29//! - Reflect in: false (MSB first)
30//! - Reflect out: false
31//! - XOR out: 0x0000
32
33/// Compute the CRC-16 over `data`.
34#[must_use]
35pub(crate) fn crc16(data: &[u8]) -> u16
36{
37 const POLY: u16 = 0x8005;
38 let mut crc: u16 = 0x0000;
39 for byte in data
40 {
41 for bit_index in 0..8u8
42 {
43 let data_bit = (byte >> bit_index) & 0x01;
44 let crc_bit = ((crc >> 15) & 0x0001) as u8;
45 crc <<= 1;
46 if data_bit != crc_bit
47 {
48 crc ^= POLY;
49 }
50 }
51 }
52 crc
53}
54
55#[cfg(test)]
56mod tests
57{
58 use super::*;
59
60 /// Reference vectors taken from `crates/atecc608b/src/crc.rs` tests.
61 /// Both implementations must agree on these.
62
63 #[test]
64 fn empty_input_is_zero()
65 {
66 assert_eq!(crc16(&[]), 0x0000);
67 }
68
69 #[test]
70 fn info_command_frame()
71 {
72 // Frame { count=0x07, opcode=Info=0x30, p1=0, p2=0,0 }
73 let frame = [0x07, 0x30, 0x00, 0x00, 0x00];
74 assert_eq!(crc16(&frame), 0x5D03);
75 }
76
77 #[test]
78 fn random_command_frame()
79 {
80 let frame = [0x07, 0x1B, 0x00, 0x00, 0x00];
81 assert_eq!(crc16(&frame), 0xCD24);
82 }
83
84 #[test]
85 fn wake_response_prefix()
86 {
87 let prefix = [0x04, 0x11];
88 assert_eq!(crc16(&prefix), 0x4333);
89 }
90}