mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-22 07:48:26 +00:00
Add detailed packet layout diagrams to protocol documentation
Add comprehensive wire format diagrams with byte offsets, field sizes, and concrete examples to three protocol documents: fips-wire-protocol.md (Appendix A): - Encrypted frame (0x00) with plaintext structure breakdown - Noise IK msg1/msg2 with payload breakdown - Complete handshake flow diagram fips-gossip-protocol.md (Appendix A): - TreeAnnounce with ancestry entry structure and size table - FilterAnnounce with bloom filter layout - LookupRequest/LookupResponse with examples - Message flow showing packet nesting fips-session-protocol.md (§8): - SessionSetup, SessionAck, DataPacket, CoordsRequired, PathBroken - Full nested packet example showing link + session layers fips-routing.md: - Refactored Part 4 to "Route Cache Management" - Moved wire format content to fips-session-protocol.md
This commit is contained in:
@@ -368,6 +368,314 @@ Vec<T> encoding:
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: Detailed Packet Layouts
|
||||
|
||||
All gossip messages are link-layer messages carried inside encrypted frames
|
||||
(discriminator 0x00). The layouts below show the plaintext structure after
|
||||
link-layer decryption.
|
||||
|
||||
### A.1 TreeAnnounce (0x10)
|
||||
|
||||
Propagates spanning tree state between directly connected peers.
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ FULL PACKET (Link Layer + TreeAnnounce) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ LINK LAYER FRAME (encrypted) │ │
|
||||
│ ├───────────┬──────────────┬────────────┬───────────────────────────────┤ │
|
||||
│ │ 0x00 │ receiver_idx │ counter │ ciphertext + tag │ │
|
||||
│ │ 1 byte │ 4 bytes LE │ 8 bytes LE │ N + 16 bytes │ │
|
||||
│ └───────────┴──────────────┴────────────┴───────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────────┘ │
|
||||
│ │ Decrypt │
|
||||
│ ▼ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ TREE ANNOUNCE (plaintext) │ │
|
||||
│ ├────────┬──────────────────┬───────────┬───────────────────────────────┤ │
|
||||
│ │ Offset │ Field │ Size │ Description │ │
|
||||
│ ├────────┼──────────────────┼───────────┼───────────────────────────────┤ │
|
||||
│ │ 0 │ msg_type │ 1 byte │ 0x10 │ │
|
||||
│ │ 1 │ sequence │ 8 bytes │ u64 LE, monotonic counter │ │
|
||||
│ │ 9 │ timestamp │ 8 bytes │ u64 LE, Unix seconds │ │
|
||||
│ │ 17 │ parent │ 32 bytes │ NodeId of selected parent │ │
|
||||
│ │ 49 │ ancestry_count │ 2 bytes │ u16 LE, number of entries │ │
|
||||
│ │ 51 │ ancestry[0..n] │ 112 × n │ AncestryEntry array │ │
|
||||
│ │ ... │ signature │ 64 bytes │ Schnorr sig over all above │ │
|
||||
│ └────────┴──────────────────┴───────────┴───────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ ANCESTRY ENTRY (112 bytes each) │ │
|
||||
│ ├────────┬──────────────────┬───────────┬───────────────────────────────┤ │
|
||||
│ │ Offset │ Field │ Size │ Description │ │
|
||||
│ ├────────┼──────────────────┼───────────┼───────────────────────────────┤ │
|
||||
│ │ 0 │ node_id │ 32 bytes │ SHA-256(npub) of this node │ │
|
||||
│ │ 32 │ sequence │ 8 bytes │ u64 LE, node's seq number │ │
|
||||
│ │ 40 │ timestamp │ 8 bytes │ u64 LE, node's timestamp │ │
|
||||
│ │ 48 │ signature │ 64 bytes │ Node's sig over its decl │ │
|
||||
│ └────────┴──────────────────┴───────────┴───────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Size calculation**: `1 + 8 + 8 + 32 + 2 + (depth × 112) + 64` bytes
|
||||
|
||||
| Tree Depth | Payload Size | With Link Overhead |
|
||||
|------------|--------------|-------------------|
|
||||
| 1 (root) | 227 bytes | 256 bytes |
|
||||
| 3 | 451 bytes | 480 bytes |
|
||||
| 5 | 675 bytes | 704 bytes |
|
||||
| 10 | 1235 bytes | 1264 bytes |
|
||||
|
||||
**Concrete example** (node D at depth 3, ancestry = [D, P1, P2, Root]):
|
||||
|
||||
```text
|
||||
PLAINTEXT BYTES (hex layout):
|
||||
10 ← msg_type = TreeAnnounce
|
||||
05 00 00 00 00 00 00 00 ← sequence = 5
|
||||
C3 B2 A1 67 00 00 00 00 ← timestamp (Unix seconds)
|
||||
[32 bytes P1's node_id] ← parent
|
||||
04 00 ← ancestry_count = 4
|
||||
|
||||
ANCESTRY[0] - Self (D):
|
||||
[32 bytes D's node_id]
|
||||
05 00 00 00 00 00 00 00 ← D's sequence
|
||||
C3 B2 A1 67 00 00 00 00 ← D's timestamp
|
||||
[64 bytes D's signature]
|
||||
|
||||
ANCESTRY[1] - Parent (P1):
|
||||
[32 bytes P1's node_id]
|
||||
0A 00 00 00 00 00 00 00 ← P1's sequence
|
||||
00 B0 A1 67 00 00 00 00 ← P1's timestamp
|
||||
[64 bytes P1's signature]
|
||||
|
||||
ANCESTRY[2] - Grandparent (P2):
|
||||
[32 bytes P2's node_id]
|
||||
03 00 00 00 00 00 00 00 ← P2's sequence
|
||||
00 A0 A1 67 00 00 00 00 ← P2's timestamp
|
||||
[64 bytes P2's signature]
|
||||
|
||||
ANCESTRY[3] - Root:
|
||||
[32 bytes Root's node_id]
|
||||
01 00 00 00 00 00 00 00 ← Root's sequence
|
||||
00 90 A1 67 00 00 00 00 ← Root's timestamp
|
||||
[64 bytes Root's signature]
|
||||
|
||||
[64 bytes D's outer signature] ← signs entire message
|
||||
|
||||
Total payload: 1 + 8 + 8 + 32 + 2 + (4 × 112) + 64 = 563 bytes
|
||||
```
|
||||
|
||||
### A.2 FilterAnnounce (0x11)
|
||||
|
||||
Propagates Bloom filter reachability information.
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ FILTER ANNOUNCE (0x11) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ WIRE FORMAT │ │
|
||||
│ ├────────┬──────────────────┬───────────┬───────────────────────────────┤ │
|
||||
│ │ Offset │ Field │ Size │ Description │ │
|
||||
│ ├────────┼──────────────────┼───────────┼───────────────────────────────┤ │
|
||||
│ │ 0 │ msg_type │ 1 byte │ 0x11 │ │
|
||||
│ │ 1 │ sequence │ 8 bytes │ u64 LE, monotonic counter │ │
|
||||
│ │ 9 │ ttl │ 1 byte │ Remaining propagation hops │ │
|
||||
│ │ 10 │ hash_count │ 1 byte │ Number of hash functions (7) │ │
|
||||
│ │ 11 │ filter_bits │ 4096 bytes│ Bloom filter bit array │ │
|
||||
│ └────────┴──────────────────┴───────────┴───────────────────────────────┘ │
|
||||
│ │
|
||||
│ Total payload: 4107 bytes (fixed size) │
|
||||
│ With link overhead: 4136 bytes │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ BLOOM FILTER STRUCTURE │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ filter_bits[4096]: │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Byte 0 │ Byte 1 │ ... │ Byte 4095 │ │
|
||||
│ │ bits 0-7 │ bits 8-15 │ │ bits 32760-32767 │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ To test membership of node_id: │
|
||||
│ for i in 0..hash_count: │
|
||||
│ bit_index = hash(node_id, i) % 32768 │
|
||||
│ if !filter_bits[bit_index]: return false │
|
||||
│ return true // "maybe present" │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Concrete example**:
|
||||
|
||||
```text
|
||||
PLAINTEXT BYTES:
|
||||
11 ← msg_type = FilterAnnounce
|
||||
2A 00 00 00 00 00 00 00 ← sequence = 42
|
||||
02 ← ttl = 2 (will propagate 2 more hops)
|
||||
07 ← hash_count = 7
|
||||
[4096 bytes of filter bits] ← Bloom filter
|
||||
|
||||
Total: 4107 bytes
|
||||
```
|
||||
|
||||
### A.3 LookupRequest (0x12)
|
||||
|
||||
Discovers tree coordinates for distant destinations.
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ LOOKUP REQUEST (0x12) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ WIRE FORMAT │ │
|
||||
│ ├────────┬──────────────────┬───────────┬───────────────────────────────┤ │
|
||||
│ │ Offset │ Field │ Size │ Description │ │
|
||||
│ ├────────┼──────────────────┼───────────┼───────────────────────────────┤ │
|
||||
│ │ 0 │ msg_type │ 1 byte │ 0x12 │ │
|
||||
│ │ 1 │ request_id │ 8 bytes │ u64 LE, unique identifier │ │
|
||||
│ │ 9 │ target │ 32 bytes │ NodeId being searched for │ │
|
||||
│ │ 41 │ origin │ 32 bytes │ NodeId of requester │ │
|
||||
│ │ 73 │ ttl │ 1 byte │ Remaining propagation hops │ │
|
||||
│ │ 74 │ origin_coords_cnt│ 2 bytes │ u16 LE │ │
|
||||
│ │ 76 │ origin_coords │ 32 × n │ Requester's ancestry │ │
|
||||
│ │ ... │ visited_hash_cnt │ 1 byte │ Hash functions for visited │ │
|
||||
│ │ ... │ visited_bits │ 256 bytes │ Compact bloom of visited nodes│ │
|
||||
│ └────────┴──────────────────┴───────────┴───────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Size calculation**: `1 + 8 + 32 + 32 + 1 + 2 + (depth × 32) + 1 + 256` bytes
|
||||
|
||||
| Origin Depth | Payload Size |
|
||||
|--------------|--------------|
|
||||
| 3 | 429 bytes |
|
||||
| 5 | 493 bytes |
|
||||
| 10 | 653 bytes |
|
||||
|
||||
**Concrete example** (origin at depth 4):
|
||||
|
||||
```text
|
||||
PLAINTEXT BYTES:
|
||||
12 ← msg_type = LookupRequest
|
||||
[8 bytes request_id] ← random unique ID
|
||||
[32 bytes target node_id] ← who we're looking for
|
||||
[32 bytes origin node_id] ← who's asking
|
||||
08 ← ttl = 8
|
||||
04 00 ← origin_coords_count = 4
|
||||
[32 bytes] × 4 ← origin's ancestry (128 bytes)
|
||||
07 ← visited hash_count = 7
|
||||
[256 bytes visited bloom] ← nodes that have seen this request
|
||||
|
||||
Total: 1 + 8 + 32 + 32 + 1 + 2 + 128 + 1 + 256 = 461 bytes
|
||||
```
|
||||
|
||||
### A.4 LookupResponse (0x13)
|
||||
|
||||
Returns target's coordinates to the requester.
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ LOOKUP RESPONSE (0x13) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ WIRE FORMAT │ │
|
||||
│ ├────────┬──────────────────┬───────────┬───────────────────────────────┤ │
|
||||
│ │ Offset │ Field │ Size │ Description │ │
|
||||
│ ├────────┼──────────────────┼───────────┼───────────────────────────────┤ │
|
||||
│ │ 0 │ msg_type │ 1 byte │ 0x13 │ │
|
||||
│ │ 1 │ request_id │ 8 bytes │ u64 LE, echoes request │ │
|
||||
│ │ 9 │ target │ 32 bytes │ NodeId that was found │ │
|
||||
│ │ 41 │ target_coords_cnt│ 2 bytes │ u16 LE │ │
|
||||
│ │ 43 │ target_coords │ 32 × n │ Target's ancestry to root │ │
|
||||
│ │ ... │ proof │ 64 bytes │ Target's signature │ │
|
||||
│ └────────┴──────────────────┴───────────┴───────────────────────────────┘ │
|
||||
│ │
|
||||
│ Proof signature covers: (request_id || target || target_coords) │
|
||||
│ Prevents malicious nodes from claiming reachability for any target. │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Size calculation**: `1 + 8 + 32 + 2 + (depth × 32) + 64` bytes
|
||||
|
||||
| Target Depth | Payload Size |
|
||||
|--------------|--------------|
|
||||
| 3 | 203 bytes |
|
||||
| 5 | 267 bytes |
|
||||
| 10 | 427 bytes |
|
||||
|
||||
**Concrete example** (target at depth 5):
|
||||
|
||||
```text
|
||||
PLAINTEXT BYTES:
|
||||
13 ← msg_type = LookupResponse
|
||||
[8 bytes request_id] ← echoed from request
|
||||
[32 bytes target node_id] ← confirms who was found
|
||||
05 00 ← target_coords_count = 5
|
||||
[32 bytes] × 5 ← target's ancestry (160 bytes)
|
||||
[64 bytes proof signature] ← target signs to prove existence
|
||||
|
||||
Total: 1 + 8 + 32 + 2 + 160 + 64 = 267 bytes
|
||||
```
|
||||
|
||||
### A.5 Message Flow Example
|
||||
|
||||
Complete lookup flow showing packet nesting:
|
||||
|
||||
```text
|
||||
Source S wants to reach distant destination D (not in local filters)
|
||||
|
||||
1. S creates LookupRequest, sends to peer P1:
|
||||
|
||||
UDP DATAGRAM
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ LINK FRAME (S→P1 encrypted) │
|
||||
│ ┌──────┬────────────┬─────────┬─────────────────────────────┐│
|
||||
│ │ 0x00 │ P1_recv_idx│ counter │ ciphertext + tag ││
|
||||
│ └──────┴────────────┴─────────┴─────────────────────────────┘│
|
||||
│ │ │
|
||||
│ ┌───────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌──────┬───────────────────────────────────┐ │
|
||||
│ │ 0x12 │ LookupRequest payload │ │
|
||||
│ │ │ (target=D, origin=S, ttl=8, ...) │ │
|
||||
│ └──────┴───────────────────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
|
||||
2. Request propagates through network, reaches D
|
||||
|
||||
3. D creates LookupResponse, routes back via greedy routing:
|
||||
|
||||
UDP DATAGRAM
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ LINK FRAME (D→Pn encrypted) │
|
||||
│ ┌──────┬────────────┬─────────┬─────────────────────────────┐│
|
||||
│ │ 0x00 │ Pn_recv_idx│ counter │ ciphertext + tag ││
|
||||
│ └──────┴────────────┴─────────┴─────────────────────────────┘│
|
||||
│ │ │
|
||||
│ ┌───────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌──────┬───────────────────────────────────┐ │
|
||||
│ │ 0x13 │ LookupResponse payload │ │
|
||||
│ │ │ (target=D, coords=[D,P1,P2,Root]) │ │
|
||||
│ └──────┴───────────────────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
|
||||
4. S receives response, caches D's coordinates, can now route directly
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [spanning-tree-dynamics.md](spanning-tree-dynamics.md) - Tree protocol behavior
|
||||
|
||||
@@ -293,20 +293,19 @@ No global routing tables. Each node makes purely local decisions.
|
||||
|
||||
---
|
||||
|
||||
## Part 4: Routing Session Establishment
|
||||
## Part 4: Route Cache Management
|
||||
|
||||
> **Terminology note**: This section describes *routing sessions*—hop-by-hop
|
||||
> cached state at intermediate routers. FIPS also has *crypto sessions*—end-to-end
|
||||
> authenticated encryption between source and destination. See
|
||||
> [fips-session-protocol.md](fips-session-protocol.md) §3 for crypto session details
|
||||
> and §5 for route cache warming.
|
||||
> **Wire formats**: For session layer message wire formats (SessionSetup,
|
||||
> SessionAck, DataPacket, CoordsRequired, PathBroken), see
|
||||
> [fips-session-protocol.md](fips-session-protocol.md) §8.
|
||||
|
||||
### Routing Session Purpose
|
||||
### Route Cache Purpose
|
||||
|
||||
Establish cached coordinate state along a path so that subsequent data packets
|
||||
can omit coordinates, minimizing per-packet overhead.
|
||||
Intermediate routers cache coordinate mappings so that data packets can use
|
||||
minimal headers (addresses only, no coordinates). This reduces per-packet
|
||||
overhead from ~300 bytes to 38 bytes.
|
||||
|
||||
### Routing Session Lifecycle
|
||||
### Cache Lifecycle
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
@@ -318,74 +317,7 @@ can omit coordinates, minimizing per-packet overhead.
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Routing Session Message Formats
|
||||
|
||||
```rust
|
||||
/// Establishes cached state along path; optionally carries crypto handshake
|
||||
struct SessionSetup {
|
||||
src_addr: Ipv6Addr,
|
||||
dest_addr: Ipv6Addr,
|
||||
src_coords: Vec<NodeId>, // For return path caching
|
||||
dest_coords: Vec<NodeId>, // For forward path routing
|
||||
flags: SessionFlags,
|
||||
|
||||
// Crypto session establishment (see fips-session-protocol.md §6)
|
||||
// Opaque to routers; only processed by destination
|
||||
handshake_payload: Option<Vec<u8>>, // Noise IK message 1
|
||||
}
|
||||
|
||||
struct SessionFlags {
|
||||
request_ack: bool, // Ask destination to confirm
|
||||
bidirectional: bool, // Set up both directions
|
||||
}
|
||||
|
||||
/// Confirms session establishment; optionally carries crypto response
|
||||
struct SessionAck {
|
||||
src_addr: Ipv6Addr,
|
||||
dest_addr: Ipv6Addr,
|
||||
src_coords: Vec<NodeId>, // Acknowledger's coords (for return caching)
|
||||
|
||||
// Crypto session response (see fips-session-protocol.md §6)
|
||||
handshake_payload: Option<Vec<u8>>, // Noise IK message 2
|
||||
}
|
||||
|
||||
/// Data packet with optional coordinates
|
||||
struct DataPacket {
|
||||
flags: u8, // Bit 0: COORDS_PRESENT
|
||||
hop_limit: u8,
|
||||
payload_length: u16,
|
||||
src_addr: Ipv6Addr, // 16 bytes
|
||||
dest_addr: Ipv6Addr, // 16 bytes
|
||||
|
||||
// Optional: present only if COORDS_PRESENT flag is set
|
||||
src_coords: Option<Vec<NodeId>>,
|
||||
dest_coords: Option<Vec<NodeId>>,
|
||||
|
||||
payload: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Error when router cannot route (cache miss)
|
||||
struct CoordsRequired {
|
||||
dest_addr: Ipv6Addr,
|
||||
reporter: NodeId, // Which router had the miss
|
||||
}
|
||||
```
|
||||
|
||||
### Data Packet Overhead
|
||||
|
||||
| Field | Size |
|
||||
|-------|------|
|
||||
| flags | 1 byte |
|
||||
| hop_limit | 1 byte |
|
||||
| payload_length | 2 bytes |
|
||||
| src_addr | 16 bytes |
|
||||
| dest_addr | 16 bytes |
|
||||
| **Minimal header** | **36 bytes** |
|
||||
|
||||
Comparable to IPv6 (40 bytes). When COORDS_PRESENT flag is set, coordinates
|
||||
add variable overhead based on tree depth (typically 200-400 bytes).
|
||||
|
||||
### Routing Session Setup Flow
|
||||
### Session Setup Flow
|
||||
|
||||
```text
|
||||
S R1 R2 D
|
||||
@@ -460,7 +392,7 @@ impl Router {
|
||||
}
|
||||
```
|
||||
|
||||
### Cache Management
|
||||
### Cache Data Structure
|
||||
|
||||
```rust
|
||||
struct CoordCache {
|
||||
@@ -485,7 +417,7 @@ by:
|
||||
- SessionRefresh message (lightweight, just touches expiry)
|
||||
- Data packet transit (optional: refresh on use)
|
||||
|
||||
### Handling Cache Eviction
|
||||
### Cache Miss Recovery
|
||||
|
||||
When a router's cache entry is evicted mid-session:
|
||||
|
||||
@@ -501,7 +433,7 @@ When a router's cache entry is evicted mid-session:
|
||||
The crypto session remains active throughout—only routing state is refreshed.
|
||||
From application perspective: one packet delayed, transparent recovery.
|
||||
|
||||
### Sender Behavior
|
||||
### Sender State Machine
|
||||
|
||||
```rust
|
||||
impl Sender {
|
||||
|
||||
@@ -495,3 +495,228 @@ After successful Noise IK handshake:
|
||||
The first TreeAnnounce from a new peer may trigger parent reselection if that
|
||||
peer offers a better path to root. See [fips-gossip-protocol.md](fips-gossip-protocol.md)
|
||||
for TreeAnnounce and FilterAnnounce wire formats.
|
||||
|
||||
---
|
||||
|
||||
## 8. Session Layer Wire Format
|
||||
|
||||
Session layer messages are carried inside `SessionDatagram` (type 0x40) at the
|
||||
link layer. The session datagram is encrypted hop-by-hop with link keys, but
|
||||
the inner payload is encrypted end-to-end with session keys.
|
||||
|
||||
### 8.1 Message Type Codes
|
||||
|
||||
| Type Code | Message | Direction | Purpose |
|
||||
|-----------|----------------|-----------|-----------------------------------|
|
||||
| 0x00 | SessionSetup | S → D | Establish session + warm caches |
|
||||
| 0x01 | SessionAck | D → S | Confirm session establishment |
|
||||
| 0x10 | DataPacket | Both | Application data |
|
||||
| 0x20 | CoordsRequired | R → S | Router cache miss |
|
||||
| 0x21 | PathBroken | R → S | Greedy routing failed |
|
||||
|
||||
### 8.2 SessionSetup (0x00)
|
||||
|
||||
Establishes a crypto session and warms router coordinate caches along the path.
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ SESSION SETUP PACKET │
|
||||
├────────┬──────────────────┬───────────┬─────────────────────────────────────┤
|
||||
│ Offset │ Field │ Size │ Description │
|
||||
├────────┼──────────────────┼───────────┼─────────────────────────────────────┤
|
||||
│ 0 │ msg_type │ 1 byte │ 0x00 │
|
||||
│ 1 │ flags │ 1 byte │ Bit 0: REQUEST_ACK │
|
||||
│ │ │ │ Bit 1: BIDIRECTIONAL │
|
||||
│ 2 │ src_addr │ 16 bytes │ Source fd::/8 address │
|
||||
│ 18 │ dest_addr │ 16 bytes │ Destination fd::/8 address │
|
||||
│ 34 │ src_coords_count │ 2 bytes │ u16 LE, number of src coord entries │
|
||||
│ 36 │ src_coords │ 32 × n │ NodeId array (self → root) │
|
||||
│ ... │ dest_coords_count│ 2 bytes │ u16 LE, number of dest coord entries│
|
||||
│ ... │ dest_coords │ 32 × m │ NodeId array (dest → root) │
|
||||
│ ... │ handshake_len │ 2 bytes │ u16 LE, Noise payload length │
|
||||
│ ... │ handshake_payload│ variable │ Noise IK msg1 (82 bytes typical) │
|
||||
└────────┴──────────────────┴───────────┴─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Example** (depth 3 source, depth 4 destination, with Noise handshake):
|
||||
|
||||
```text
|
||||
┌──────┬───────┬──────────────────┬──────────────────┬───────┬─────────────┐
|
||||
│ 0x00 │ 0x01 │ src_addr │ dest_addr │ 0x03 │ src_coords │
|
||||
│ type │ flags │ 16 bytes │ 16 bytes │ count │ 3 × 32 bytes│
|
||||
├──────┴───────┴──────────────────┴──────────────────┴───────┴─────────────┤
|
||||
│ 0x04 │ dest_coords │ 0x52 │ handshake_payload │
|
||||
│ count │ 4 × 32 bytes │ len=82│ 82 bytes (Noise IK msg1) │
|
||||
└───────┴───────────────┴───────┴──────────────────────────────────────────┘
|
||||
|
||||
Total: 1 + 1 + 16 + 16 + 2 + 96 + 2 + 128 + 2 + 82 = 346 bytes
|
||||
```
|
||||
|
||||
### 8.3 SessionAck (0x01)
|
||||
|
||||
Confirms session establishment and completes the Noise handshake.
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ SESSION ACK PACKET │
|
||||
├────────┬──────────────────┬───────────┬─────────────────────────────────────┤
|
||||
│ Offset │ Field │ Size │ Description │
|
||||
├────────┼──────────────────┼───────────┼─────────────────────────────────────┤
|
||||
│ 0 │ msg_type │ 1 byte │ 0x01 │
|
||||
│ 1 │ flags │ 1 byte │ Reserved │
|
||||
│ 2 │ src_addr │ 16 bytes │ Acknowledger's address │
|
||||
│ 18 │ dest_addr │ 16 bytes │ Original sender's address │
|
||||
│ 34 │ src_coords_count │ 2 bytes │ u16 LE │
|
||||
│ 36 │ src_coords │ 32 × n │ Acknowledger's coords (for caching) │
|
||||
│ ... │ handshake_len │ 2 bytes │ u16 LE, Noise payload length │
|
||||
│ ... │ handshake_payload│ variable │ Noise IK msg2 (33 bytes typical) │
|
||||
└────────┴──────────────────┴───────────┴─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 8.4 DataPacket (0x10)
|
||||
|
||||
Carries encrypted application data (typically IPv6 payloads).
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ DATA PACKET (Minimal Header) │
|
||||
├────────┬──────────────────┬───────────┬─────────────────────────────────────┤
|
||||
│ Offset │ Field │ Size │ Description │
|
||||
├────────┼──────────────────┼───────────┼─────────────────────────────────────┤
|
||||
│ 0 │ msg_type │ 1 byte │ 0x10 │
|
||||
│ 1 │ flags │ 1 byte │ Bit 0: COORDS_PRESENT │
|
||||
│ 2 │ hop_limit │ 1 byte │ Decremented each hop │
|
||||
│ 3 │ reserved │ 1 byte │ Alignment padding │
|
||||
│ 4 │ payload_length │ 2 bytes │ u16 LE │
|
||||
│ 6 │ src_addr │ 16 bytes │ Source fd::/8 address │
|
||||
│ 22 │ dest_addr │ 16 bytes │ Destination fd::/8 address │
|
||||
│ 38 │ payload │ variable │ Encrypted application data │
|
||||
└────────┴──────────────────┴───────────┴─────────────────────────────────────┘
|
||||
|
||||
Minimal header: 38 bytes (comparable to IPv6's 40 bytes)
|
||||
```
|
||||
|
||||
When `COORDS_PRESENT` flag is set (route warming after CoordsRequired):
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ DATA PACKET (With Coordinates) │
|
||||
├────────┬──────────────────┬───────────┬─────────────────────────────────────┤
|
||||
│ Offset │ Field │ Size │ Description │
|
||||
├────────┼──────────────────┼───────────┼─────────────────────────────────────┤
|
||||
│ 0 │ msg_type │ 1 byte │ 0x10 │
|
||||
│ 1 │ flags │ 1 byte │ 0x01 (COORDS_PRESENT) │
|
||||
│ 2 │ hop_limit │ 1 byte │ Decremented each hop │
|
||||
│ 3 │ reserved │ 1 byte │ Alignment padding │
|
||||
│ 4 │ payload_length │ 2 bytes │ u16 LE │
|
||||
│ 6 │ src_addr │ 16 bytes │ Source fd::/8 address │
|
||||
│ 22 │ dest_addr │ 16 bytes │ Destination fd::/8 address │
|
||||
│ 38 │ src_coords_count │ 2 bytes │ u16 LE │
|
||||
│ 40 │ src_coords │ 32 × n │ Source coordinates │
|
||||
│ ... │ dest_coords_count│ 2 bytes │ u16 LE │
|
||||
│ ... │ dest_coords │ 32 × m │ Destination coordinates │
|
||||
│ ... │ payload │ variable │ Encrypted application data │
|
||||
└────────┴──────────────────┴───────────┴─────────────────────────────────────┘
|
||||
|
||||
With depth-4 coords both directions: 38 + 2 + 128 + 2 + 128 = 298 bytes header
|
||||
```
|
||||
|
||||
### 8.5 CoordsRequired (0x20)
|
||||
|
||||
Sent by an intermediate router when it cannot forward a DataPacket due to
|
||||
coordinate cache miss.
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ COORDS REQUIRED PACKET │
|
||||
├────────┬──────────────────┬───────────┬─────────────────────────────────────┤
|
||||
│ Offset │ Field │ Size │ Description │
|
||||
├────────┼──────────────────┼───────────┼─────────────────────────────────────┤
|
||||
│ 0 │ msg_type │ 1 byte │ 0x20 │
|
||||
│ 1 │ flags │ 1 byte │ Reserved │
|
||||
│ 2 │ dest_addr │ 16 bytes │ The address we couldn't route │
|
||||
│ 18 │ reporter │ 32 bytes │ NodeId of reporting router │
|
||||
└────────┴──────────────────┴───────────┴─────────────────────────────────────┘
|
||||
|
||||
Total: 50 bytes
|
||||
```
|
||||
|
||||
### 8.6 PathBroken (0x21)
|
||||
|
||||
Sent when greedy routing fails (no peer is closer to destination).
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ PATH BROKEN PACKET │
|
||||
├────────┬──────────────────┬───────────┬─────────────────────────────────────┤
|
||||
│ Offset │ Field │ Size │ Description │
|
||||
├────────┼──────────────────┼───────────┼─────────────────────────────────────┤
|
||||
│ 0 │ msg_type │ 1 byte │ 0x21 │
|
||||
│ 1 │ flags │ 1 byte │ Reserved │
|
||||
│ 2 │ dest_addr │ 16 bytes │ The unreachable destination │
|
||||
│ 18 │ reporter │ 32 bytes │ NodeId of reporting router │
|
||||
│ 50 │ last_coords_count│ 2 bytes │ u16 LE │
|
||||
│ 52 │ last_known_coords│ 32 × n │ Stale coords that failed │
|
||||
└────────┴──────────────────┴───────────┴─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 8.7 Full Packet Layout Example
|
||||
|
||||
A DataPacket from source S to destination D, transiting router R:
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ UDP DATAGRAM │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ FIPS LINK LAYER (S→R encrypted) │ │
|
||||
│ ├───────────┬──────────────┬────────────┬───────────────────────────────┤ │
|
||||
│ │ 0x00 │ R's recv_idx │ counter │ ciphertext + tag │ │
|
||||
│ │ 1 byte │ 4 bytes LE │ 8 bytes LE │ N + 16 bytes │ │
|
||||
│ └───────────┴──────────────┴────────────┴───────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────────┘ │
|
||||
│ │ Decrypt with S↔R link keys │
|
||||
│ ▼ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ LINK MESSAGE (plaintext for R) │ │
|
||||
│ ├───────────┬───────────────────────────────────────────────────────────┤ │
|
||||
│ │ 0x40 │ SessionDatagram payload │ │
|
||||
│ │ msg_type │ (routable by R, encrypted end-to-end) │ │
|
||||
│ └───────────┴───────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ SESSION LAYER (S↔D encrypted) │ │
|
||||
│ ├───────────┬───────┬──────────┬──────────┬─────────────────────────────┤ │
|
||||
│ │ 0x10 │ flags │ hop_limit│ pay_len │ src_addr │ dest_addr │ │
|
||||
│ │ DataPacket│ 0x00 │ 64 │ 1400 │ 16 bytes │ 16 bytes │ │
|
||||
│ ├───────────┴───────┴──────────┴──────────┴──────────────┴──────────────┤ │
|
||||
│ │ │ │
|
||||
│ │ ENCRYPTED PAYLOAD (S↔D session keys) │ │
|
||||
│ │ ┌─────────────────────────────────────────────┐ │ │
|
||||
│ │ │ IPv6 packet or application data │ │ │
|
||||
│ │ │ (+ 16-byte AEAD tag) │ │ │
|
||||
│ │ └─────────────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ └───────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Router R can see: dest_addr (for routing decision)
|
||||
Router R cannot see: payload contents (encrypted with S↔D keys)
|
||||
```
|
||||
|
||||
### 8.8 Encoding Rules
|
||||
|
||||
- All multi-byte integers are **little-endian**
|
||||
- NodeId is 32 bytes (SHA-256 hash of npub)
|
||||
- IPv6 addresses are 16 bytes (network byte order)
|
||||
- Variable-length coordinate arrays use 2-byte u16 count prefix
|
||||
|
||||
```text
|
||||
Vec<NodeId> encoding:
|
||||
count: u16 (little-endian)
|
||||
items: [u8; 32] × count
|
||||
```
|
||||
|
||||
@@ -803,7 +803,222 @@ protocol layers apply additional policy.
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: Message Size Summary
|
||||
## Appendix A: Detailed Packet Layouts
|
||||
|
||||
### A.1 Encrypted Frame (0x00)
|
||||
|
||||
Post-handshake data packets between authenticated peers.
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ENCRYPTED FRAME (0x00) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ WIRE FORMAT │ │
|
||||
│ ├────────┬──────────────────┬───────────┬───────────────────────────────┤ │
|
||||
│ │ Offset │ Field │ Size │ Description │ │
|
||||
│ ├────────┼──────────────────┼───────────┼───────────────────────────────┤ │
|
||||
│ │ 0 │ discriminator │ 1 byte │ 0x00 │ │
|
||||
│ │ 1 │ receiver_idx │ 4 bytes │ u32 LE, receiver's session idx│ │
|
||||
│ │ 5 │ counter │ 8 bytes │ u64 LE, monotonic nonce │ │
|
||||
│ │ 13 │ ciphertext │ N bytes │ ChaCha20 encrypted payload │ │
|
||||
│ │ 13+N │ tag │ 16 bytes │ Poly1305 auth tag │ │
|
||||
│ └────────┴──────────────────┴───────────┴───────────────────────────────┘ │
|
||||
│ │
|
||||
│ Total overhead: 29 bytes (1 + 4 + 8 + 16) │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ PLAINTEXT STRUCTURE │
|
||||
│ (after decryption) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌────────┬──────────────────┬───────────┬───────────────────────────────┐ │
|
||||
│ │ Offset │ Field │ Size │ Description │ │
|
||||
│ ├────────┼──────────────────┼───────────┼───────────────────────────────┤ │
|
||||
│ │ 0 │ msg_type │ 1 byte │ Link message type (see below) │ │
|
||||
│ │ 1 │ payload │ variable │ Message-specific payload │ │
|
||||
│ └────────┴──────────────────┴───────────┴───────────────────────────────┘ │
|
||||
│ │
|
||||
│ Link message types: │
|
||||
│ 0x10 = TreeAnnounce 0x12 = LookupRequest │
|
||||
│ 0x11 = FilterAnnounce 0x13 = LookupResponse │
|
||||
│ 0x40 = SessionDatagram │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Concrete example** (TreeAnnounce inside encrypted frame):
|
||||
|
||||
```text
|
||||
WIRE BYTES (hex):
|
||||
00 ← discriminator
|
||||
78 56 34 12 ← receiver_idx = 0x12345678 (LE)
|
||||
2A 00 00 00 00 00 00 00 ← counter = 42 (LE)
|
||||
[N bytes ciphertext] ← encrypted link message
|
||||
[16 bytes tag] ← Poly1305 authentication tag
|
||||
|
||||
DECRYPTED PLAINTEXT:
|
||||
10 ← msg_type = TreeAnnounce
|
||||
[TreeAnnounce payload] ← see fips-gossip-protocol.md
|
||||
```
|
||||
|
||||
### A.2 Noise IK Message 1 (0x01)
|
||||
|
||||
Handshake initiation from connecting party (initiator → responder).
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ NOISE IK MESSAGE 1 (0x01) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ WIRE FORMAT │ │
|
||||
│ ├────────┬──────────────────┬───────────┬───────────────────────────────┤ │
|
||||
│ │ Offset │ Field │ Size │ Description │ │
|
||||
│ ├────────┼──────────────────┼───────────┼───────────────────────────────┤ │
|
||||
│ │ 0 │ discriminator │ 1 byte │ 0x01 │ │
|
||||
│ │ 1 │ sender_idx │ 4 bytes │ u32 LE, initiator's session idx│ │
|
||||
│ │ 5 │ noise_msg1 │ 82 bytes │ Noise IK first message │ │
|
||||
│ └────────┴──────────────────┴───────────┴───────────────────────────────┘ │
|
||||
│ │
|
||||
│ Total: 87 bytes │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ NOISE MSG1 BREAKDOWN │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌────────┬──────────────────┬───────────┬───────────────────────────────┐ │
|
||||
│ │ Offset │ Field │ Size │ Description │ │
|
||||
│ ├────────┼──────────────────┼───────────┼───────────────────────────────┤ │
|
||||
│ │ 0 │ ephemeral_pubkey │ 33 bytes │ Initiator's ephemeral pubkey │ │
|
||||
│ │ │ │ │ (compressed secp256k1) │ │
|
||||
│ │ 33 │ encrypted_static │ 33 bytes │ Initiator's static pubkey │ │
|
||||
│ │ │ │ │ (encrypted with es key) │ │
|
||||
│ │ 66 │ tag │ 16 bytes │ AEAD tag for encrypted_static │ │
|
||||
│ └────────┴──────────────────┴───────────┴───────────────────────────────┘ │
|
||||
│ │
|
||||
│ Noise pattern: -> e, es, s, ss │
|
||||
│ - e: ephemeral pubkey sent in clear │
|
||||
│ - es: DH(ephemeral, responder_static) → mix into key │
|
||||
│ - s: static pubkey encrypted with current key │
|
||||
│ - ss: DH(static, responder_static) → mix into key │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Concrete example**:
|
||||
|
||||
```text
|
||||
WIRE BYTES (hex):
|
||||
01 ← discriminator
|
||||
78 56 34 12 ← sender_idx = 0x12345678 (LE)
|
||||
02 [32 bytes] ← ephemeral pubkey (compressed, 02/03 prefix)
|
||||
[33 bytes] ← encrypted static pubkey
|
||||
[16 bytes] ← AEAD tag
|
||||
|
||||
Total: 87 bytes
|
||||
```
|
||||
|
||||
### A.3 Noise IK Message 2 (0x02)
|
||||
|
||||
Handshake response from responder (responder → initiator).
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ NOISE IK MESSAGE 2 (0x02) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ WIRE FORMAT │ │
|
||||
│ ├────────┬──────────────────┬───────────┬───────────────────────────────┤ │
|
||||
│ │ Offset │ Field │ Size │ Description │ │
|
||||
│ ├────────┼──────────────────┼───────────┼───────────────────────────────┤ │
|
||||
│ │ 0 │ discriminator │ 1 byte │ 0x02 │ │
|
||||
│ │ 1 │ sender_idx │ 4 bytes │ u32 LE, responder's session idx│ │
|
||||
│ │ 5 │ receiver_idx │ 4 bytes │ u32 LE, echo of initiator's idx│ │
|
||||
│ │ 9 │ noise_msg2 │ 33 bytes │ Noise IK second message │ │
|
||||
│ └────────┴──────────────────┴───────────┴───────────────────────────────┘ │
|
||||
│ │
|
||||
│ Total: 42 bytes │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ NOISE MSG2 BREAKDOWN │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌────────┬──────────────────┬───────────┬───────────────────────────────┐ │
|
||||
│ │ Offset │ Field │ Size │ Description │ │
|
||||
│ ├────────┼──────────────────┼───────────┼───────────────────────────────┤ │
|
||||
│ │ 0 │ ephemeral_pubkey │ 33 bytes │ Responder's ephemeral pubkey │ │
|
||||
│ │ │ │ │ (compressed secp256k1) │ │
|
||||
│ └────────┴──────────────────┴───────────┴───────────────────────────────┘ │
|
||||
│ │
|
||||
│ Noise pattern: <- e, ee, se │
|
||||
│ - e: ephemeral pubkey sent in clear │
|
||||
│ - ee: DH(responder_ephemeral, initiator_ephemeral) → mix into key │
|
||||
│ - se: DH(responder_ephemeral, initiator_static) → mix into key │
|
||||
│ │
|
||||
│ After msg2, both parties derive identical session keys. │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Concrete example**:
|
||||
|
||||
```text
|
||||
WIRE BYTES (hex):
|
||||
02 ← discriminator
|
||||
01 EF CD AB ← sender_idx = 0xABCDEF01 (LE)
|
||||
78 56 34 12 ← receiver_idx = 0x12345678 (LE, echoed)
|
||||
03 [32 bytes] ← ephemeral pubkey (compressed, 02/03 prefix)
|
||||
|
||||
Total: 42 bytes
|
||||
```
|
||||
|
||||
### A.4 Complete Handshake Flow
|
||||
|
||||
```text
|
||||
Initiator (A) Responder (B)
|
||||
───────────── ─────────────
|
||||
generates sender_idx = 0x12345678
|
||||
generates ephemeral keypair
|
||||
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ 0x01 | 0x12345678 | [82 bytes noise_msg1] │
|
||||
└──────────────────────────────────────────────────────┘
|
||||
──────────────────────────────►
|
||||
|
||||
validates msg1
|
||||
learns A's static pubkey
|
||||
generates sender_idx = 0xABCDEF01
|
||||
generates ephemeral keypair
|
||||
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ 0x02 | 0xABCDEF01 | 0x12345678 | [33 bytes noise_msg2]│
|
||||
└──────────────────────────────────────────────────────┘
|
||||
◄──────────────────────────────
|
||||
|
||||
validates msg2
|
||||
derives session keys
|
||||
|
||||
═══════════════════════ HANDSHAKE COMPLETE ═══════════════════════
|
||||
|
||||
A's view: B's view:
|
||||
our_index = 0x12345678 our_index = 0xABCDEF01
|
||||
their_index = 0xABCDEF01 their_index = 0x12345678
|
||||
|
||||
A sends to B: B sends to A:
|
||||
receiver_idx = 0xABCDEF01 receiver_idx = 0x12345678
|
||||
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ 0x00 | 0xABCDEF01 | counter=0 | [ciphertext+tag] │
|
||||
└──────────────────────────────────────────────────────┘
|
||||
──────────────────────────────►
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Appendix B: Message Size Summary
|
||||
|
||||
| Packet Type | Size | Overhead |
|
||||
|-------------|------|----------|
|
||||
|
||||
Reference in New Issue
Block a user