docs: fix crypto/format drift — version byte 0x02, AttachmentId 32 hex, DCT 5-50
Punch items from doc audit: - docs/ARCHITECTURE.md: encrypted file format diagram said version byte 0x01; actual VERSION_BYTE is 0x02 (crypto.rs:59) and 0x01 is rejected with UnsupportedFormatVersion. - docs/ARCHITECTURE.md: DCT embedding diagram said "Repeat secret 20+ times" and "positions 4-15"; actual is MIN_COPIES (5) to 50 copies chosen by capacity, embedded in zig-zag positions 6-17 (imgsecret.rs:78, 99-104, 530-537). - FORMATS.md: AttachmentId table said 16 hex chars / 8 bytes; actual is 32 hex chars / first 16 bytes of SHA-256 (ids.rs:59-69). - FORMATS.md: ManifestEntry schema missing r#type field; updated to list all ten fields in declared order with serde decorations noted (manifest.rs:21-38). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -45,7 +45,7 @@ Parsed via `ParamsFile { kdf: KdfParams }` in `session.rs`. The `kdf` nesting is
|
|||||||
Decrypts to JSON matching the `Manifest` struct (`manifest.rs`).
|
Decrypts to JSON matching the `Manifest` struct (`manifest.rs`).
|
||||||
|
|
||||||
- **Schema version:** `MANIFEST_SCHEMA_VERSION = 2` (`manifest.rs:12`). v1 manifests (pre-typed-items) fail to parse and are not supported.
|
- **Schema version:** `MANIFEST_SCHEMA_VERSION = 2` (`manifest.rs:12`). v1 manifests (pre-typed-items) fail to parse and are not supported.
|
||||||
- **`ManifestEntry` fields:** `id`, `title`, `tags`, `favorite`, `group`, `icon_hint`, `modified`, `trashed_at`, `attachment_summaries`.
|
- **`ManifestEntry` fields** (declared order in `manifest.rs:21-38`): `id`, `type`, `title`, `tags`, `favorite`, `group`, `icon_hint`, `modified`, `trashed_at`, `attachment_summaries`. The `type` field is `r#type: ItemType` in Rust but serializes as the bare JSON key `"type"` (no serde rename — `r#` is just the raw-identifier escape). `group`, `icon_hint`, and `trashed_at` are `#[serde(skip_serializing_if = "Option::is_none")]`; `tags`, `favorite`, and `attachment_summaries` use `#[serde(default)]`.
|
||||||
- The manifest is rebuilt from scratch on every `upsert` — it can never drift from the source-of-truth item files.
|
- The manifest is rebuilt from scratch on every `upsert` — it can never drift from the source-of-truth item files.
|
||||||
- Supports case-insensitive title/tag search without decrypting any item.
|
- Supports case-insensitive title/tag search without decrypting any item.
|
||||||
|
|
||||||
@@ -75,9 +75,9 @@ Commits by `public_key` at or after `revoked_at` (Unix seconds) are rejected by
|
|||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `ItemId` | 16 hex chars | 64 bits | `OsRng` |
|
| `ItemId` | 16 hex chars | 64 bits | `OsRng` |
|
||||||
| `FieldId` | 16 hex chars | 64 bits | `OsRng` |
|
| `FieldId` | 16 hex chars | 64 bits | `OsRng` |
|
||||||
| `AttachmentId` | 16 hex chars | content-addressed | first 8 bytes of `SHA-256(plaintext)` |
|
| `AttachmentId` | 32 hex chars | 128 bits | first 16 bytes (32 hex chars) of `SHA-256` over the plaintext |
|
||||||
|
|
||||||
`AttachmentId` is content-addressed — identical plaintexts deduplicate in git automatically.
|
`AttachmentId` is content-addressed — identical plaintexts deduplicate in git automatically. The 128-bit truncation (`ids.rs:59-69`) was widened from 64 bits per audit I2/B4 to put birthday-collision risk out of reach.
|
||||||
|
|
||||||
## `.relbak` backup format
|
## `.relbak` backup format
|
||||||
|
|
||||||
|
|||||||
@@ -161,11 +161,14 @@ master_key ────────►│ XChaCha20 │──────
|
|||||||
│ selected block: │
|
│ selected block: │
|
||||||
│ │
|
│ │
|
||||||
│ QIM embed bits │
|
│ QIM embed bits │
|
||||||
│ in positions │
|
│ in zig-zag │
|
||||||
│ 4-15 (mid-freq) │
|
│ positions 6-17 │
|
||||||
|
│ (mid-frequency) │
|
||||||
│ │
|
│ │
|
||||||
│ Repeat secret │
|
│ Repeat secret │
|
||||||
│ 20+ times │
|
│ MIN_COPIES (5) │
|
||||||
|
│ to 50 times, │
|
||||||
|
│ by capacity │
|
||||||
└────────┬─────────┘
|
└────────┬─────────┘
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
@@ -181,6 +184,8 @@ master_key ────────►│ XChaCha20 │──────
|
|||||||
carries 256-bit secret)
|
carries 256-bit secret)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The redundancy count is chosen at embed time based on available DCT capacity: `num_copies = (total_blocks / BLOCKS_PER_COPY).min(50)`, with `BLOCKS_PER_COPY = 22` and a floor of `MIN_COPIES = 5` (`crates/relicario-core/src/imgsecret.rs:78,530-537`). Images that cannot fit at least 5 copies are rejected before embed. Majority voting across these copies at extract time requires ≥ 60 % confidence per bit.
|
||||||
|
|
||||||
## Extraction (with crop recovery)
|
## Extraction (with crop recovery)
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -214,10 +219,12 @@ Input JPEG (possibly re-encoded or cropped)
|
|||||||
┌─────────┬────────────────────────┬──────────────────┬──────────────────┐
|
┌─────────┬────────────────────────┬──────────────────┬──────────────────┐
|
||||||
│ version │ nonce │ ciphertext │ auth tag │
|
│ version │ nonce │ ciphertext │ auth tag │
|
||||||
│ 1 byte │ 24 bytes │ N bytes │ 16 bytes │
|
│ 1 byte │ 24 bytes │ N bytes │ 16 bytes │
|
||||||
│ 0x01 │ random per write │ XChaCha20 stream │ Poly1305 MAC │
|
│ 0x02 │ random per write │ XChaCha20 stream │ Poly1305 MAC │
|
||||||
└─────────┴────────────────────────┴──────────────────┴──────────────────┘
|
└─────────┴────────────────────────┴──────────────────┴──────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`VERSION_BYTE = 0x02` (`crates/relicario-core/src/crypto.rs:59`). Blobs starting with any other byte are rejected with `UnsupportedFormatVersion { found, expected: 0x02 }`. The legacy `0x01` format from the pre-typed-items era is no longer supported.
|
||||||
|
|
||||||
## Crate Architecture
|
## Crate Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user