docs(core): THP synchronization layer clarification
What changed, and why it matters
This commit is purely a documentation and log-message wording update. It clarifies which message types participate in the Trezor Host Protocol (THP) synchronization layer, documents how sequence and ACK bits are encoded, and renames 'sync bit' to 'seq bit' in two debug log lines. There are no code behavior changes.
No security action required. This is a non-functional documentation and logging clarification.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff updates docs/common/thp/specification.md to state that only handshake_init_request, handshake_init_response, handshake_completion_request, handshake_completion_response, encrypted_transport, and ACK take part in the synchronization layer, while channel_allocation_request, channel_allocation_response, and transport_error do not carry sequence numbers or acknowledgments. It also documents the control-byte masks for the sequence bit (0x10) and ACK bit (0x08). In python/src/trezorlib/thp/channel.py and rust/trezor-thp/src/channel/mod.rs, debug log messages are changed from ‘sync bit’ to ‘seq bit’ for consistency. No functional logic is modified.
Changed components
docs/common/thp/specification.mdpython/src/trezorlib/thp/channel.pyrust/trezor-thp/src/channel/mod.rsInspect captured patch +11 / −6
diff --git a/docs/common/thp/specification.md b/docs/common/thp/specification.md
index 1f849747..2b9a8585 100644
--- a/docs/common/thp/specification.md
+++ b/docs/common/thp/specification.md
@@ -320,6 +320,8 @@ The primary function of the synchronization layer is to work as the *Alternating
It is possible that some packets are lost by the Data transfer layer (L1). In order to guarantee reliable communication, THP uses the *Alternating Bit Protocol* in combination with a *CRC32* checksum.
+Only the following message types take part in the synchronization layer: `handshake_init_request`, `handshake_init_response`, `handshake_completion_request`, `handshake_completion_response`, `encrypted_transport` and `ACK`. Notably `channel_allocation_request`, `channel_allocation_response` and `transport_error` don't carry a sequence number and are not acknowledged.
+
### Alternating Bit Protocol
The *Alternating Bit Protocol* (ABP) is a protocol between a sender and a receiver over an unreliable channel. The channel is unreliable in the sense that it can discard or duplicate messages, but it cannot change their order or content. The protocol guarantees the eventual and non-duplicative delivery of messages.
@@ -408,6 +410,12 @@ flowchart LR
R1 -- in: Message(Seq=0); out: Ack(Seq=0); discard Message as duplicate --> R1
```
+#### Encoding
+
+The sequence bit is encoded into the control byte of the applicable messages, mask 0x10 (00010000).
+
+The ACK bit can be similarly accessed using the mask 0x08 (00001000). On messages other than ACK, the ACK number is ignored unless piggybacking is enabled.
+
### ACK Message structure
The ACK message has no payload except for the CRC. Its *control_byte* is set to *ack* with the appropriate sequence number, i.e. <code>ACK_0 = 0010<b>0</b>000</code> and <code>ACK_1 = 0010<b>1</b>000</code>. The ACK message has the same sequence number as the message it acknowledges.
diff --git a/python/src/trezorlib/thp/channel.py b/python/src/trezorlib/thp/channel.py
index 40b89cc1..205aff3b 100644
--- a/python/src/trezorlib/thp/channel.py
+++ b/python/src/trezorlib/thp/channel.py
@@ -537,7 +537,7 @@ class Channel:
if message.seq_bit is not None:
if message.seq_bit != self.sync_bit_receive:
LOG.warning(
- "Received unexpected message: sync bit=%d, expected=%d",
+ "Received unexpected message: seq bit=%d, expected=%d",
message.seq_bit,
self.sync_bit_receive,
)
diff --git a/rust/trezor-thp/src/channel/mod.rs b/rust/trezor-thp/src/channel/mod.rs
index f0c93325..d3b7ab93 100644
--- a/rust/trezor-thp/src/channel/mod.rs
+++ b/rust/trezor-thp/src/channel/mod.rs
@@ -409,15 +409,12 @@ impl<R: Role, B: Backend> Channel<R, B> {
&& matches!(self.send_state, SendState::Sending { .. })
{
// ACK we sent was lost. Will be retransmitted along current outgoing message.
- log::debug!("[{:04x}] Bad sync bit, ignoring packet.", self.channel_id);
+ log::debug!("[{:04x}] Bad seq bit, ignoring packet.", self.channel_id);
} else if !matches!(self.receive_state, ReceiveState::Receiving { .. }) {
// Might happen when we've sent an ACK and it got lost or delayed.
// We end up sending reply while the other side is retransmitting.
// NOTE: no checksum verification because we drop the continuations
- log::debug!(
- "[{:04x}] Bad sync bit, resending last ACK.",
- self.channel_id
- );
+ log::debug!("[{:04x}] Bad seq bit, resending last ACK.", self.channel_id);
self.send_ack = Some(SyncBits::new().with_ack_bit(sb.seq_bit()));
}
Err(Error::malformed_data())
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.