Files
swaitsandClaude Opus 4.7 9232c16f7c
mdBook / build (push) Canceled after 0s
mdBook / deploy (push) Canceled after 0s
feat(versioning): snapshot corpus per spec version
A frozen spec is only meaningful if it's paired with the corpus
that was current at release time — otherwise a v0.1.0 reader
follows "see corpus/payloads/ack/" and lands on a file whose
test vectors may have changed since v0.1.0 was cut.

Three changes:

1. `cut-version` now copies BOTH src/ AND corpus/ into the
   snapshot directory. A release is the pair, not just the text.

2. The corpus URL rewriting in cut-version now retargets
   /tree/main/corpus -> /tree/main/versions/<v>/corpus (and the
   blob variant). This lets the link resolve on GitHub from main
   alone — no git tag required, since the frozen copy is a real
   path under main. Downgrades the "tag is REQUIRED" message from
   last commit back to "optionally tag the commit".

3. The frozen corpus's spec_ref fields get rewritten too: from
   `src/04-payload-ack.md` to `versions/<v>/04-payload-ack.md`,
   so a reader following a test vector lands on the spec text the
   vector was paired with at release time.

versions/v0.1.0/ regenerated from scratch via `just cut-version v0.1.0`
to pick up the corpus snapshot + the new sed patterns. The release
is now self-consistent: v0.1.0 spec links go to v0.1.0 corpus, which
links back to v0.1.0 spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 10:38:02 -06:00

75 lines
2.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MeshCore Protocol Specification
## Section 7: Payload — Anonymous Request
### Overview
The anonymous request payload allows a node to send an encrypted message to a
recipient without the recipient needing to know the sender in advance. Instead of
a 1-byte source hash, the full 32-byte Ed25519 public key of the sender is
included, enabling the recipient to compute the shared secret for decryption.
### Payload Type
Header payload type field: `0x07` (ANON_REQ)
### Wire Format
```
0
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| dest_hash(1) | |
+-+-+-+-+-+-+-+-+ |
| Sender Public Key (32 bytes) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Cipher MAC (2 bytes) | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Ciphertext (N × 16 bytes, N ≥ 1) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```
### Fields
| Field | Offset | Size | Type | Description |
|-------|--------|------|------|-------------|
| dest_hash | 0 | 1 byte | raw | First byte of recipient's Ed25519 public key |
| sender_pub_key | 1 | 32 bytes | raw | Full Ed25519 public key of sender |
| cipher_mac | 33 | 2 bytes | raw | Truncated HMAC-SHA256 over ciphertext |
| ciphertext | 35 | variable (multiple of 16) | raw | AES-128-ECB encrypted data |
### Minimum Size
- Minimum payload: 1 + 32 + 2 + 16 = 51 bytes
### Encryption
1. Sender computes ECDH shared secret using its private key and the recipient's
public key.
2. Encrypt plaintext using AES-128-ECB with first 16 bytes of shared secret.
3. Compute HMAC-SHA256 over ciphertext with full 32-byte shared secret.
Truncate to 2 bytes.
4. Assemble: dest_hash || sender_pub_key || MAC || ciphertext.
### Decryption
1. Read dest_hash. If it does not match this node, the packet is not for us
(but MAY be forwarded).
2. Read 32-byte sender_pub_key. Construct an Identity from it.
3. Compute ECDH shared secret between this node's private key and sender's
public key.
4. Verify the MAC and decrypt as in [Section 14](14-crypto.md).
### Cross-References
- [Section 6: Encrypted Payloads](06-payload-encrypted.md) — Standard encrypted format
- [Section 14: Cryptography](14-crypto.md) — Encrypt-then-MAC
- [Section 15: Identity](15-identity.md) — ECDH key exchange
- Test vectors: [`corpus/payloads/anon-req/`](https://github.com/swaits/meshcore-spec/tree/main/versions/v0.1.0/corpus/payloads/anon-req/)
### Reference Implementation
- `Mesh::createAnonDatagram()` in `src/Mesh.cpp` — Encoding
- `Mesh::onRecvPacket()`, case `PAYLOAD_TYPE_ANON_REQ` — Decoding