From 29f74391543924517bf8018d5ae178100e97c59e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 7 Sep 2026 00:39:22 +0200 Subject: [PATCH] [noise] Shorten the comments --- esphome/components/api/api_frame_helper.h | 3 +-- esphome/components/api/api_server.cpp | 10 +++------- .../components/esphome/ota/ota_esphome_noise.cpp | 2 +- esphome/components/noise/noise.cpp | 5 ++--- esphome/components/noise/noise.h | 16 ++++++---------- esphome/components/noise/noise_handshake.cpp | 2 +- esphome/components/noise/noise_handshake.h | 6 ++---- 7 files changed, 16 insertions(+), 28 deletions(-) diff --git a/esphome/components/api/api_frame_helper.h b/esphome/components/api/api_frame_helper.h index 3319fad391..a09d93b7df 100644 --- a/esphome/components/api/api_frame_helper.h +++ b/esphome/components/api/api_frame_helper.h @@ -118,8 +118,7 @@ class APIFrameHelper { virtual APIError loop() = 0; virtual APIError read_packet(ReadPacketBuffer *buffer) = 0; bool can_write_without_blocking() { return this->state_ == State::DATA && this->overflow_buf_.empty(); } - /// True once the transport handshake is done and the connection carries - /// api messages (immediately for plaintext, after the noise handshake). + /// Transport handshake done (immediately for plaintext) bool is_handshake_complete() const { return this->state_ == State::DATA; } int getpeername(struct sockaddr *addr, socklen_t *addrlen) { return socket_->getpeername(addr, addrlen); } APIError close() { diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 7fab3697aa..dc19824f0f 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -42,9 +42,7 @@ void APIServer::setup() { #ifdef USE_API_NOISE #ifdef USE_ESP8266 - // Refilling the spare ephemeral key blocks the loop for about 60 ms on - // this core; the same generation used to run inside every handshake. - // Cover it so the first refill does not log a blocking warning at boot. + // The spare ephemeral refill blocks ~60 ms here; keep it under the warning this->warn_if_blocking_over_ = 8; // centiseconds #endif // Always reserve the slot: flash preferences are positional on esp8266, so @@ -198,10 +196,8 @@ void APIServer::loop() { } #ifdef USE_API_NOISE -// Refill the spare ephemeral key while nobody is waiting for it: not before -// the network is up, and not while an api client is still in its noise -// handshake (an OTA handshake is not visible here; it took the previous -// spare and pays the refill instead, no worse than generating its own key). +// Refill only while no api client waits on a noise handshake; an OTA +// handshake is not visible here and just pays the refill it triggered. void APIServer::prepare_spare_ephemeral_() { if (noise::has_spare_ephemeral() || !network::is_connected()) { return; diff --git a/esphome/components/esphome/ota/ota_esphome_noise.cpp b/esphome/components/esphome/ota/ota_esphome_noise.cpp index 4b362a8890..747f99053c 100644 --- a/esphome/components/esphome/ota/ota_esphome_noise.cpp +++ b/esphome/components/esphome/ota/ota_esphome_noise.cpp @@ -66,7 +66,7 @@ bool ESPHomeOTAComponent::noise_start_session_(uint8_t server_feature_flags) { *p++ = ota::OTA_RESPONSE_FEATURE_FLAGS; *p++ = server_feature_flags; - // The api server keeps the spare; without an encrypted api there is none + // Only the api server refills the spare const uint8_t *ephemeral = nullptr; #ifdef USE_API_NOISE noise::ephemeral_keypair_t spare; diff --git a/esphome/components/noise/noise.cpp b/esphome/components/noise/noise.cpp index 2fc0f2787c..53a012f975 100644 --- a/esphome/components/noise/noise.cpp +++ b/esphome/components/noise/noise.cpp @@ -37,9 +37,8 @@ void prepare_spare_ephemeral() { spare_ephemeral_ready = false; uint8_t *private_key = spare_ephemeral; uint8_t *public_key = spare_ephemeral + EPHEMERAL_PRIVATE_KEY_SIZE; - // Same generation as noise-c's curve25519 backend: random bytes, X25519 - // clamping, then the public key. A random source failure leaves the slot - // empty; the handshake then generates its own key. + // Same steps as noise-c's curve25519 keygen; on RNG failure the slot stays + // empty and the handshake generates its own key if (!random_bytes(private_key, EPHEMERAL_PRIVATE_KEY_SIZE)) { return; } diff --git a/esphome/components/noise/noise.h b/esphome/components/noise/noise.h index ade22e22be..b30695f787 100644 --- a/esphome/components/noise/noise.h +++ b/esphome/components/noise/noise.h @@ -38,24 +38,20 @@ class NoiseContext { /// Convert a noise error code to a readable error const LogString *noise_err_to_logstr(int err); -// An X25519 key pair as the spare ephemeral hands it out: private key first +// Spare key pair layout: private key then public key static constexpr size_t EPHEMERAL_PRIVATE_KEY_SIZE = 32; static constexpr size_t EPHEMERAL_PUBLIC_KEY_SIZE = 32; static constexpr size_t EPHEMERAL_KEYPAIR_SIZE = EPHEMERAL_PRIVATE_KEY_SIZE + EPHEMERAL_PUBLIC_KEY_SIZE; using ephemeral_keypair_t = std::array; #ifdef USE_API_NOISE -// A responder ephemeral key pair generated ahead of time. The base point -// multiply behind one costs about 60 ms on ESP8266, so the api server fills -// the slot while idle and a connecting client does not wait for it. One slot -// serves every noise transport; a handshake that finds it empty generates -// its own key as before. The api server is the only refiller, so the slot -// only exists in builds with an encrypted api. +// One responder ephemeral key pair generated ahead of time (about 60 ms on +// ESP8266), refilled by the api server while idle, shared by every noise +// transport; an empty slot means the handshake generates its own key. bool has_spare_ephemeral(); -/// Generate a key pair into the slot; blocks for the base point multiply. +/// Fill the slot; blocks for the base point multiply void prepare_spare_ephemeral(); -/// Move the slot's key pair into out and empty the slot. Returns false, -/// leaving out untouched, when the slot is empty. +/// Move the slot into out and empty it; false (out untouched) when empty bool take_spare_ephemeral(ephemeral_keypair_t &out); #endif diff --git a/esphome/components/noise/noise_handshake.cpp b/esphome/components/noise/noise_handshake.cpp index 51d5315f8c..3def02708c 100644 --- a/esphome/components/noise/noise_handshake.cpp +++ b/esphome/components/noise/noise_handshake.cpp @@ -62,7 +62,7 @@ int NoiseResponderHandshake::init(const NoiseContext &ctx, const uint8_t *prolog err = noise_handshakestate_set_local_ephemeral(this->handshake_, ephemeral_keypair, EPHEMERAL_PRIVATE_KEY_SIZE, ephemeral_keypair + EPHEMERAL_PRIVATE_KEY_SIZE, EPHEMERAL_PUBLIC_KEY_SIZE); - // Not fatal: the handshake generates its own key when the spare is refused + // Not fatal: the handshake generates its own key instead if (err != 0) { HANDSHAKE_STEP_LOG("noise_handshakestate_set_local_ephemeral", err); } diff --git a/esphome/components/noise/noise_handshake.h b/esphome/components/noise/noise_handshake.h index 05f8bb94bb..dd53e6db14 100644 --- a/esphome/components/noise/noise_handshake.h +++ b/esphome/components/noise/noise_handshake.h @@ -38,10 +38,8 @@ class NoiseResponderHandshake { /// Create and start the handshake with the context's PSK and the prologue. /// A repeated call frees the previous handshake state and starts over. - /// ephemeral_keypair, when not null, is a key pair from - /// take_spare_ephemeral() that the handshake uses as its ephemeral key - /// instead of generating one; if noise-c refuses it the handshake - /// generates its own key and init() still succeeds. + /// ephemeral_keypair, when set, is a take_spare_ephemeral() key pair used + /// instead of generating one; a refused pair falls back to generating. [[nodiscard]] int init(const NoiseContext &ctx, const uint8_t *prologue, size_t prologue_len, const uint8_t *ephemeral_keypair = nullptr); /// ACTION_FAILED is the catch-all: returned before init(), after split()