Changelog

# Changelog

All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/).


## [0.2.0] - 2026-10-14

Additive release: `msg_auth_verify()` and every 0.1.0 behaviour are unchanged.

### Added
- `msg_auth_verify_from()`: verification for callers that know the only
  acceptable sender (e.g. one peer per link). Any other sender is rejected
  with the new `ESP_ERR_MSG_AUTH_WRONG_SENDER` before the tag is checked,
  without touching that sender's freshness state or per-peer statistics.
  Fixes the cross-link case where a genuine envelope relayed onto the wrong
  link advanced its sender's state and caused the real copy to be rejected
  as a replay. An invalid `expected_sender` is `ESP_ERR_INVALID_ARG`
  whatever the envelope contains. Outputs are written only on `ESP_OK`.
- `msg_auth_rx_info_t`: the verified `(epoch, counter)` of an accepted
  envelope, returned by `msg_auth_verify_from()`, for event identity.
- `msg_auth_get_stats()` and `msg_auth_stats_t`: context-wide
  `bad_tag_total` and `wrong_sender` counters.
- `msg_auth_err_to_name()` names `ESP_ERR_MSG_AUTH_WRONG_SENDER`.
- Host tests T26–T33: right and wrong sender, the cross-link scenario,
  check order, argument checks and untouched outputs, bit flips, injected
  crypto failure, context statistics and concurrency through
  `msg_auth_verify_from()`. T1–T25 unchanged.
- `examples/sign_verify`: node C, `verify_from` scenarios including a
  relayed envelope on the wrong link, and `target_checks.c`, which measures
  every `MSG_AUTH_SPEC.md` §9.3 row (CPU frequency, MAC path, HMAC driver, concurrency on
  one key ID, `psa_crypto_init`, heap at create and per call, stack per
  call, latency at 0/64/512/1432 bytes) and prints it as one block.

### Changed
- Steps 1–7 of verification are one internal function shared by both
  entry points.
- Per-peer `bad_tag` is documented as tag failures *claiming* that sender
  (the ID is unauthenticated); `bad_tag_total` is the reliable count.

### Documentation
- `MSG_AUTH_SPEC.md`: §1 points to `verify_from`; new §5.4a and §5.8; §5.7
  seven codes; §6.3 event identity from `info.epoch`; §7 concurrency table;
  §7 memory notes PSA's per-call heap use; §9.3 names the HMAC driver
  actually used (ESP's transparent HMAC driver on the SHA accelerator, not
  the eFuse-key HMAC peripheral) and records ESP32 QEMU results; §10 tests
  T26–T33; §11 example; §12 open point 2 resolved.
- README: `verify_from` usage, results table, statistics, chip status.

### Verified
- Host: T1–T33 pass on both MAC paths with ASan/UBSan (TF-PSA-Crypto from
  Mbed TLS 4.0.0).
- ESP-IDF v6.0.3, hardware: `examples/sign_verify` passes 27/27 on an ESP32
  and an ESP32-S3 board (primary MAC path, 160 MHz); the §9.3 record is
  complete for both. Also builds for both MAC paths and passes in ESP32 QEMU.


## [0.1.0] - 2026-10-12

### Added
- Initial release of `msg_auth`: per-message authentication for ESP-IDF v6.0.x
  between nodes that share an installation key. Pure logic on bytes: no
  network, no tasks, no callbacks, no flash access.
- Handle-based API: `msg_auth_create()`, `msg_auth_delete()`,
  `msg_auth_sign()`, `msg_auth_verify()`, `msg_auth_reset_peer()`,
  `msg_auth_get_peer_stats()` and `msg_auth_err_to_name()`.
- Envelope version 1: a 12-byte big-endian header (version, mode, sender,
  receiver, epoch, counter), the message (0 to 1432 bytes) and a 16-byte
  HMAC-SHA256 tag over both; at most 1460 bytes, one `udp_link` datagram.
- Purpose keys derived with HKDF-SHA256 (salt `"msg_auth v1"`, info = purpose
  label) directly into a volatile, non-exportable PSA HMAC key.
- Replay protection with a strict `(epoch, counter)` high-water mark per
  sender. The tag is checked before freshness state is read or changed.
- Distinct results for malformed, misaddressed, unknown-sender, bad-tag,
  replayed and counter-exhausted cases. Crypto-library failures return
  `ESP_FAIL` and never count as a bad tag.
- Zero-copy verify: the message is returned as a pointer into the caller's
  buffer.
- Thread safety: concurrent sign and verify on one context, with the
  counter reserved under a mutex and the MAC computed outside it.
- Two MAC paths with identical wire format: truncated-MAC key policy
  (default) and full HMAC with constant-time truncated compare
  (`-DMSG_AUTH_MAC_FALLBACK=1`).
- Build-time checks for the ESP-IDF release and the PSA algorithms and
  threading support msg_auth depends on.
- `MSG_AUTH_SPEC.md`: the complete implementation specification.
- `examples/sign_verify`: in-process acceptance test on any board, with an
  NVS boot-counter epoch, PASS/FAIL per scenario, timing and statistics.
- `host_test/`: tests T1–T25 on `msg_auth.c` against the real PSA Crypto
  library from ESP-IDF's Mbed TLS tree, on both MAC paths, with ASan/UBSan,
  fault injection and multi-threaded tests, plus known-answer vectors
  generated independently in Python.

### Changed (specification)
- `MSG_AUTH_SPEC.md` §5.1 step 5: the installation key is imported as a
  volatile PSA derivation key and passed with `psa_key_derivation_input_key()`.
  PSA does not permit `psa_key_derivation_output_key()` when the secret was
  given as raw bytes (`PSA_ERROR_NOT_PERMITTED`). The imported key is destroyed
  as soon as derivation ends, on every path.