atecc608b/opcodes.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//! Numeric constants of the ATECC608B protocol.
17//!
18//! Every byte value, command opcode, max execution time, polling parameter,
19//! and packet size lives here. The rest of the driver imports symbols by name
20//! and **never** uses magic numbers.
21//!
22//! Source of truth: Microchip `CryptoAuthLib` (`lib/calib/calib_command.h` and
23//! `lib/calib/calib_execution.c`). Cross-references to the public summary
24//! datasheet (DS40002239A) are included in comments where they exist.
25
26// I2C addressing
27
28/// Factory default 7-bit I2C address of an ATECC608B-SSHDA. Programmable via
29/// the `ChipMode.I2C_Address` byte of the config zone, but never changed in
30/// this project.
31pub(crate) const I2C_ADDRESS: u8 = 0x60;
32
33// Word addresses (first byte of every I2C transaction)
34
35/// Word address that puts the chip into deep sleep (clears volatile state).
36pub(crate) const WORD_ADDRESS_SLEEP: u8 = 0x01;
37/// Word address that puts the chip in idle (keeps `TempKey`, drops the watchdog).
38pub(crate) const WORD_ADDRESS_IDLE: u8 = 0x02;
39/// Word address sent before every command packet.
40pub(crate) const WORD_ADDRESS_COMMAND: u8 = 0x03;
41
42// Wake timings
43
44/// Minimum duration SDA must be held low to wake the chip (datasheet `tWLO`).
45pub const WAKE_LOW_DURATION_US: u32 = 60;
46
47/// Time to wait after the wake pulse before the first I2C transaction.
48///
49/// The datasheet specifies two relevant timings here:
50/// - `tWHI`: 1500 us minimum, the legacy I2C-bus-recovery delay,
51/// - `tHTSU`: 4100 us maximum, the host-to-target setup time before the
52/// chip will ACK its address.
53///
54/// `CryptoAuthLib` historically uses 1500 us and it works on most chip
55/// revisions, but some 608B silicon needs the full `tHTSU` window. We
56/// pick 4500 us as a single delay that covers both with margin. The
57/// extra ~3 ms over the strict `tWHI` is invisible to the user (PIN
58/// operations take tens of ms anyway) and removes a class of "first
59/// transaction NACKs" bring-up bugs.
60pub const WAKE_DELAY_US: u32 = 4_500;
61
62/// Bytes returned by the chip after a successful wake.
63pub(crate) const WAKE_RESPONSE_OK: [u8; 4] = [0x04, 0x11, 0x33, 0x43];
64
65/// Bytes returned if the chip's self-test failed at wake.
66pub(crate) const WAKE_RESPONSE_SELFTEST_FAIL: [u8; 4] = [0x04, 0x07, 0xC4, 0x40];
67
68// Polling parameters
69
70/// Time the driver waits between two consecutive response reads.
71pub(crate) const POLLING_PERIOD_MS: u32 = 2;
72
73/// Upper bound on the total polling window before [`crate::AteccError::Timeout`].
74pub(crate) const POLLING_MAX_MS: u32 = 2_500;
75
76// Packet sizes
77
78/// Maximum size of a command packet sent to the chip, including the word
79/// address byte prepended at the I2C level.
80///
81/// 1 (word addr) + 1 (count) + 1 (opcode) + 1 (param1) + 2 (param2)
82/// + up to 155 bytes of data + 2 (CRC) = 163 bytes.
83pub(crate) const MAX_PACKET_SIZE: usize = 163;
84
85/// Maximum size of a response read from the chip.
86pub(crate) const MAX_RESPONSE_SIZE: usize = 155;
87
88/// Number of bytes a command frame contains besides its data payload.
89///
90/// Layout: count (1) + opcode (1) + param1 (1) + param2 (2) + crc (2) = 7.
91/// This does not include the word address byte, which is prepended by the
92/// I2C transmit routine and is not covered by the CRC.
93pub(crate) const COMMAND_FRAME_OVERHEAD: usize = 7;
94
95/// Maximum size of the data field of a command, equal to
96/// `MAX_PACKET_SIZE - 1 (word addr) - COMMAND_FRAME_OVERHEAD = 155`.
97pub(crate) const MAX_COMMAND_DATA_LEN: usize = MAX_PACKET_SIZE - 1 - COMMAND_FRAME_OVERHEAD;
98
99// Command opcodes
100// Source: `lib/calib/calib_command.h` of CryptoAuthLib.
101
102/// `Info` - retrieve revision / status / `KeyValid`.
103pub(crate) const OP_INFO: u8 = 0x30;
104/// `Random` - produce 32 cryptographically random bytes.
105pub(crate) const OP_RANDOM: u8 = 0x1B;
106/// `Read` - read 4 or 32 bytes from config / data / OTP.
107pub(crate) const OP_READ: u8 = 0x02;
108/// `Write` - write 4 or 32 bytes to config / data / OTP.
109pub(crate) const OP_WRITE: u8 = 0x12;
110/// `Lock` - irreversibly lock a zone or a slot.
111pub(crate) const OP_LOCK: u8 = 0x17;
112/// `Nonce` - load `TempKey` or `MsgDigBuf` for subsequent commands.
113pub(crate) const OP_NONCE: u8 = 0x16;
114/// `GenKey` - generate a P-256 key pair in a slot, or compute a public key.
115pub(crate) const OP_GENKEY: u8 = 0x40;
116/// `Sign` - produce an ECDSA P-256 signature.
117pub(crate) const OP_SIGN: u8 = 0x41;
118/// `Verify` - verify an ECDSA P-256 signature.
119pub(crate) const OP_VERIFY: u8 = 0x45;
120/// `PrivWrite`- encrypted write of a P-256 private key into a slot.
121pub(crate) const OP_PRIVWRITE: u8 = 0x46;
122/// `Counter` - read or increment the monotonic counters.
123pub(crate) const OP_COUNTER: u8 = 0x24;
124/// `CheckMac` - verify a precomputed MAC against a stored secret.
125pub(crate) const OP_CHECKMAC: u8 = 0x28;
126/// `GenDig` - derive a digest into `TempKey` for use with `Write` encrypted.
127pub(crate) const OP_GENDIG: u8 = 0x15;
128
129// Expected execution time per command, in milliseconds
130// Source: `lib/calib/calib_execution.c`, table for ATECC608-M1 (clock divider
131// most commonly used). The driver uses these as the initial wait when
132// polling. The actual ready time is observed via the response.
133
134/// Nominal execution time of `Info`, in milliseconds.
135pub(crate) const EXEC_TIME_INFO_MS: u32 = 5;
136/// Nominal execution time of `Random`, in milliseconds.
137pub(crate) const EXEC_TIME_RANDOM_MS: u32 = 23;
138/// Nominal execution time of `Read`, in milliseconds.
139pub(crate) const EXEC_TIME_READ_MS: u32 = 5;
140/// Nominal execution time of `Write`, in milliseconds.
141pub(crate) const EXEC_TIME_WRITE_MS: u32 = 45;
142/// Nominal execution time of `Lock`, in milliseconds.
143pub(crate) const EXEC_TIME_LOCK_MS: u32 = 35;
144/// Nominal execution time of `Nonce`, in milliseconds.
145pub(crate) const EXEC_TIME_NONCE_MS: u32 = 20;
146/// Nominal execution time of `GenKey`, in milliseconds.
147pub(crate) const EXEC_TIME_GENKEY_MS: u32 = 215;
148/// Nominal execution time of `Sign`, in milliseconds.
149pub(crate) const EXEC_TIME_SIGN_MS: u32 = 220;
150/// Nominal execution time of `Verify`, in milliseconds.
151pub(crate) const EXEC_TIME_VERIFY_MS: u32 = 295;
152/// Nominal execution time of `PrivWrite`, in milliseconds.
153pub(crate) const EXEC_TIME_PRIVWRITE_MS: u32 = 50;
154/// Nominal execution time of `Counter`, in milliseconds.
155pub(crate) const EXEC_TIME_COUNTER_MS: u32 = 25;
156/// Nominal execution time of `CheckMac`, in milliseconds.
157pub(crate) const EXEC_TIME_CHECKMAC_MS: u32 = 40;
158/// Nominal execution time of `GenDig`, in milliseconds.
159pub(crate) const EXEC_TIME_GENDIG_MS: u32 = 25;