docs: update ARCHITECTURE.md for v0.6.0 gene mutation system
This commit is contained in:
1 parent
4a64a57347
commit
b2835f454f
1 file changed
+177
-34
+177
-34
@@ -1,6 +1,6 @@
|
|||||||
# ChronoSeal — Architecture
|
# ChronoSeal — Architecture
|
||||||
|
|
||||||
> Note (v0.6.0): Synthetic Gene Mutation flow and mutation handshake updates are documented in [REFRACTORING-v0.6.0.md](REFRACTORING-v0.6.0.md) and [API.md](API.md).
|
> Note (v0.6.0): Synthetic Gene Mutation flow and mutation handshake updates are documented in [REFRACTORING-v0.6.0.md](https://github.com/thakares/chronoseal-rs/blob/main/docs/REFRACTORING-v0.6.0.md) and [API.md](https://github.com/thakares/chronoseal-rs/blob/main/docs/API.md).
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
@@ -23,8 +23,7 @@ is stored in SQLite keyed on `session_id`. Every HTTP request is independently
|
|||||||
verifiable.
|
verifiable.
|
||||||
|
|
||||||
**Silent failure.** Validation failures never return an error status or an
|
**Silent failure.** Validation failures never return an error status or an
|
||||||
error body. The server always responds `{"status":"ok"}` and simply omits
|
error body. The server always responds `{"status":"ok"}` and simply omits `next_salt`. The client degrades gracefully. Attackers cannot enumerate
|
||||||
`next_salt`. The client degrades gracefully. Attackers cannot enumerate
|
|
||||||
validation rules by probing error responses.
|
validation rules by probing error responses.
|
||||||
|
|
||||||
**Private key isolation.** The Ed25519 signing key is generated inside the
|
**Private key isolation.** The Ed25519 signing key is generated inside the
|
||||||
@@ -41,19 +40,25 @@ activity, correct WASM execution, chain state synchronisation, and a valid
|
|||||||
Ed25519 signature over a time-windowed payload. For an automated client, the
|
Ed25519 signature over a time-windowed payload. For an automated client, the
|
||||||
synchronisation burden alone makes scaled operation expensive.
|
synchronisation burden alone makes scaled operation expensive.
|
||||||
|
|
||||||
|
**Deterministic mutation parity (v0.6.0).** Each heartbeat additionally carries
|
||||||
|
a `mutation_step` and `gene_commitment` derived from a server-issued mutation
|
||||||
|
program. Server and WASM execute the same shared opcode engine
|
||||||
|
(`shared/src/vm_extensions.rs`), and the server rejects any heartbeat where
|
||||||
|
the recomputed commitment does not match the client-supplied value.
|
||||||
|
|
||||||
### High-Level Design
|
### High-Level Design
|
||||||
|
|
||||||
- **Core**: Rust + Axum (async web framework)
|
- **Core**: Rust + Axum (async web framework)
|
||||||
- **Storage**: `db_type` selectable (`sqlite-in-memory`, `sqlite-in-disk`, `valkey` compatibility mode)
|
- **Storage**: `db_type` selectable (`sqlite-in-memory`, `sqlite-in-disk`, `valkey` compatibility mode)
|
||||||
- **Client**: WASM + Rust (runs in browser for proof generation)
|
- **Client**: WASM + Rust (runs in browser for proof generation)
|
||||||
- **Security Model**: Behavioral analysis + hash chaining + entropy scoring
|
- **Security Model**: Behavioral analysis + hash chaining + entropy scoring + deterministic gene mutation parity
|
||||||
- **Deployment**: Static musl binary, systemd service, optional Docker
|
- **Deployment**: Static musl binary, systemd service, optional Docker
|
||||||
|
|
||||||
### Key Components
|
### Key Components
|
||||||
|
|
||||||
- `shared/` — Types, constants, crypto primitives used by server and WASM
|
- `shared/` — Types, constants, crypto primitives, gene model, and mutation engine used by server and WASM
|
||||||
- `server/` — Axum routes, session management, trust engine, rate limiting, cleanup tasks
|
- `server/` — Axum routes, session management, trust engine, rate limiting, cleanup tasks
|
||||||
- `wasm/` — Client-side proof generation
|
- `wasm/` — Client-side proof generation, mutation preview/commit lifecycle
|
||||||
- `frontend/` — Static assets served by the application
|
- `frontend/` — Static assets served by the application
|
||||||
|
|
||||||
### Unix-Native Design Decisions
|
### Unix-Native Design Decisions
|
||||||
@@ -62,12 +67,11 @@ synchronisation burden alone makes scaled operation expensive.
|
|||||||
- All state is either in-memory or in standard locations (`/run/`, `/var/log/`, `/etc/`)
|
- All state is either in-memory or in standard locations (`/run/`, `/var/log/`, `/etc/`)
|
||||||
- Graceful shutdown and reload support via signals
|
- Graceful shutdown and reload support via signals
|
||||||
- Logging designed for `journalctl` and structured parsing
|
- Logging designed for `journalctl` and structured parsing
|
||||||
- Configuration will be fully runtime (no recompile needed)
|
- Configuration is fully runtime (no recompile needed)
|
||||||
|
|
||||||
### Design Goal
|
### Design Goal
|
||||||
|
|
||||||
ChronoSeal should feel as natural to use as `nginx` or `redis-server` on a Linux system.
|
## ChronoSeal should feel as natural to use as `nginx` or `redis-server` on a Linux system.
|
||||||
---
|
|
||||||
|
|
||||||
## Component Map
|
## Component Map
|
||||||
|
|
||||||
@@ -89,7 +93,10 @@ ChronoSeal should feel as natural to use as `nginx` or `redis-server` on a Linux
|
|||||||
│ │ ├ generate_keypair() │ │
|
│ │ ├ generate_keypair() │ │
|
||||||
│ │ ├ sign_message() │ │
|
│ │ ├ sign_message() │ │
|
||||||
│ │ ├ compute_next_hash() │ │
|
│ │ ├ compute_next_hash() │ │
|
||||||
│ │ └ run_program() │ │
|
│ │ ├ run_program() │ │
|
||||||
|
│ │ vm_extensions.rs │ │
|
||||||
|
│ │ ├ preview_mutation() │ │
|
||||||
|
│ │ └ commit_mutation() │ │
|
||||||
│ └──────────────────────────────┘ │
|
│ └──────────────────────────────┘ │
|
||||||
└─────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────┘
|
||||||
│ HTTPS
|
│ HTTPS
|
||||||
@@ -103,6 +110,7 @@ ChronoSeal should feel as natural to use as `nginx` or `redis-server` on a Linux
|
|||||||
│ session.rs │
|
│ session.rs │
|
||||||
│ ├ create_session() │
|
│ ├ create_session() │
|
||||||
│ └ verify_heartbeat() │
|
│ └ verify_heartbeat() │
|
||||||
|
│ └ validate_mutation_parity() [v0.6.0] │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ ┌──────────┼──────────────┐ │
|
│ ┌──────────┼──────────────┐ │
|
||||||
│ ▼ ▼ ▼ │
|
│ ▼ ▼ ▼ │
|
||||||
@@ -112,9 +120,11 @@ ChronoSeal should feel as natural to use as `nginx` or `redis-server` on a Linux
|
|||||||
│ │ │
|
│ │ │
|
||||||
│ ▼ │
|
│ ▼ │
|
||||||
│ shared::hashing (Blake3 hash chain) │
|
│ shared::hashing (Blake3 hash chain) │
|
||||||
|
│ shared::gene (gene model + commitment) [v0.6.0] │
|
||||||
|
│ shared::vm_extensions (mutation opcodes) [v0.6.0] │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ ▼ │
|
│ ▼ │
|
||||||
│ storage.rs (in-memory SQLite) │
|
│ storage.rs (SQLite: in-memory / in-disk / valkey) │
|
||||||
│ │
|
│ │
|
||||||
│ ratelimit.rs cleanup.rs vm.rs middleware.rs │
|
│ ratelimit.rs cleanup.rs vm.rs middleware.rs │
|
||||||
└─────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────┘
|
||||||
@@ -137,14 +147,20 @@ Client Server
|
|||||||
│ │ salt₀ = rand::random::<[u8;16]>()
|
│ │ salt₀ = rand::random::<[u8;16]>()
|
||||||
│ │ H(0) = Blake3(session_id║pub_key║salt₀)
|
│ │ H(0) = Blake3(session_id║pub_key║salt₀)
|
||||||
│ │ opcodes = generate_random_program(8..=16)
|
│ │ opcodes = generate_random_program(8..=16)
|
||||||
|
│ │ gene = initial gene buffer [v0.6.0]
|
||||||
|
│ │ mutation_order = generate_mutation_program() [v0.6.0]
|
||||||
│ │ INSERT INTO sessions …
|
│ │ INSERT INTO sessions …
|
||||||
│ │
|
│ │
|
||||||
│◄── { session_id, salt, opcodes_b64, │
|
│◄── { session_id, salt, opcodes_b64, │
|
||||||
│ initial_hash, expires_at } ───────┤
|
│ initial_hash, expires_at, │
|
||||||
|
│ mutation_step, │ [v0.6.0]
|
||||||
|
│ mutation_order_b64 } ─────────────┤ [v0.6.0]
|
||||||
│ │
|
│ │
|
||||||
│ prevHash = initial_hash │
|
│ prevHash = initial_hash │
|
||||||
│ currentSalt = salt │
|
│ currentSalt = salt │
|
||||||
│ opcodesB64 = opcodes_b64 │
|
│ opcodesB64 = opcodes_b64 │
|
||||||
|
│ mutationStep = mutation_step │ [v0.6.0]
|
||||||
|
│ mutationOrderB64 = mutation_order_b64 │ [v0.6.0]
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Heartbeat — `POST /hb`
|
### 2. Heartbeat — `POST /hb`
|
||||||
@@ -155,20 +171,24 @@ Fired every 12–25 seconds with uniform random jitter.
|
|||||||
Client Server
|
Client Server
|
||||||
│ │
|
│ │
|
||||||
│ stackState = run_program(opcodesB64) │
|
│ stackState = run_program(opcodesB64) │
|
||||||
|
│ commitment = preview_mutation( │ [v0.6.0]
|
||||||
|
│ mutationOrderB64, mutationStep) │
|
||||||
│ events = collectEntropy(lastTime)│
|
│ events = collectEntropy(lastTime)│
|
||||||
│ ts = Date.now() │
|
│ ts = Date.now() │
|
||||||
│ │
|
│ │
|
||||||
│ signable = { │
|
│ signable = { │
|
||||||
│ entropyData, fingerprint, │ ← keys sorted alphabetically
|
│ entropyData, fingerprint, │ ← keys sorted alphabetically
|
||||||
│ prevHash, sessionId, │
|
│ prevHash, sessionId, │
|
||||||
│ stackState, timestamp │
|
│ stackState, timestamp, │
|
||||||
|
│ mutation_step, gene_commitment │ [v0.6.0]
|
||||||
│ } │
|
│ } │
|
||||||
│ sig = sign_message( │
|
│ sig = sign_message( │
|
||||||
│ JSON.stringify(signable, keys.sort))│
|
│ JSON.stringify(signable, keys.sort))│
|
||||||
│ │
|
│ │
|
||||||
├─── { session_id, prev_hash, timestamp, │
|
├─── { session_id, prev_hash, timestamp, │
|
||||||
│ entropy_data, stack_state, │
|
│ entropy_data, stack_state, │
|
||||||
│ fingerprint, signature } ────────►│
|
│ fingerprint, signature, │
|
||||||
|
│ mutation_step, gene_commitment }─►│ [v0.6.0]
|
||||||
│ │ 1. Rate limit check
|
│ │ 1. Rate limit check
|
||||||
│ │ 2. Lookup session, check expiry
|
│ │ 2. Lookup session, check expiry
|
||||||
│ │ 3. Verify Ed25519 signature
|
│ │ 3. Verify Ed25519 signature
|
||||||
@@ -176,13 +196,20 @@ Client Server
|
|||||||
│ │ 5. Validate timestamp window ±30s
|
│ │ 5. Validate timestamp window ±30s
|
||||||
│ │ 6. Validate mouse behavior
|
│ │ 6. Validate mouse behavior
|
||||||
│ │ 7. Validate fingerprint signals
|
│ │ 7. Validate fingerprint signals
|
||||||
│ │ 8. Compute H(n), rotate salt
|
│ │ 8. Validate mutation step parity [v0.6.0]
|
||||||
│ │ 9. UPDATE sessions …
|
│ │ 9. Validate gene commitment [v0.6.0]
|
||||||
|
│ │ 10. Compute H(n), rotate salt
|
||||||
|
│ │ 11. Advance gene state [v0.6.0]
|
||||||
|
│ │ 12. UPDATE sessions …
|
||||||
│ │
|
│ │
|
||||||
│◄── { status: "ok", next_salt } ────────┤
|
│◄── { status: "ok", next_salt, │
|
||||||
|
│ next_mutation_step, │ [v0.6.0]
|
||||||
|
│ next_mutation_order_b64 } ────────┤ [v0.6.0]
|
||||||
│ │
|
│ │
|
||||||
│ sentSalt = currentSalt ◄── captured BEFORE rotation
|
│ sentSalt = currentSalt ◄── captured BEFORE rotation
|
||||||
│ currentSalt = next_salt │
|
│ currentSalt = next_salt │
|
||||||
|
│ mutationStep = next_mutation_step │ [v0.6.0]
|
||||||
|
│ mutationOrderB64 = next_mutation_order_b64 [v0.6.0]
|
||||||
│ prevHash = compute_next_hash( │
|
│ prevHash = compute_next_hash( │
|
||||||
│ prevHash, ts, entropy, │
|
│ prevHash, ts, entropy, │
|
||||||
│ stackState, sentSalt) │
|
│ stackState, sentSalt) │
|
||||||
@@ -190,8 +217,7 @@ Client Server
|
|||||||
|
|
||||||
### 3. Failure Path
|
### 3. Failure Path
|
||||||
|
|
||||||
On any validation failure the server returns `{"status":"ok"}` with no
|
On any validation failure the server returns `{"status":"ok"}` with no `next_salt`. The client logs a warning and continues scheduling heartbeats.
|
||||||
`next_salt`. The client logs a warning and continues scheduling heartbeats.
|
|
||||||
The chain is broken — subsequent heartbeats will also fail silently.
|
The chain is broken — subsequent heartbeats will also fail silently.
|
||||||
No error is surfaced to the page or its visitors.
|
No error is surfaced to the page or its visitors.
|
||||||
|
|
||||||
@@ -224,15 +250,36 @@ H(n) = Blake3(
|
|||||||
Salt rotation means an attacker who intercepts a heartbeat cannot compute
|
Salt rotation means an attacker who intercepts a heartbeat cannot compute
|
||||||
future chain links without also intercepting every subsequent server response.
|
future chain links without also intercepting every subsequent server response.
|
||||||
|
|
||||||
|
### Gene Commitment (v0.6.0)
|
||||||
|
|
||||||
|
A domain-separated BLAKE3 commitment binds both the gene buffer and the sorted
|
||||||
|
environment records into a single 32-byte value that is included in the signed
|
||||||
|
heartbeat payload and validated server-side:
|
||||||
|
|
||||||
|
```
|
||||||
|
gene_commitment = BLAKE3(
|
||||||
|
"chronoseal/gene/v1" ← domain separator
|
||||||
|
║ gene_bytes ← Vec<u8> gene buffer
|
||||||
|
║ for each (symbol, qty) sorted by symbol:
|
||||||
|
symbol_u16_le ║ qty_u32_le
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
The server recomputes the candidate gene state from its authoritative
|
||||||
|
`pending_mutation` program and rejects any heartbeat where
|
||||||
|
`recomputed_commitment != client_gene_commitment`.
|
||||||
|
|
||||||
### Canonical Signing Payload
|
### Canonical Signing Payload
|
||||||
|
|
||||||
The signed message is a JSON object with top-level keys sorted alphabetically,
|
The signed message is a JSON object with top-level keys sorted alphabetically,
|
||||||
serialised with no extra whitespace:
|
serialised with no extra whitespace:
|
||||||
|
|
||||||
```json
|
```
|
||||||
{
|
{
|
||||||
"entropyData": { "events": [{"t":…,"x":…,"y":…}] },
|
"entropyData": { "events": [{"t":…,"x":…,"y":…}] },
|
||||||
"fingerprint": { "aspectRatio":"…","devicePixelRatio":"…","hardwareConcurrency":… },
|
"fingerprint": { "aspectRatio":"…","devicePixelRatio":"…","hardwareConcurrency":… },
|
||||||
|
"gene_commitment": "hex…",
|
||||||
|
"mutation_step": N,
|
||||||
"prevHash": "hex…",
|
"prevHash": "hex…",
|
||||||
"sessionId": "hex…",
|
"sessionId": "hex…",
|
||||||
"stackState": { "ip":…,"stack":[…] },
|
"stackState": { "ip":…,"stack":[…] },
|
||||||
@@ -247,8 +294,8 @@ key order difference, or whitespace difference causes a signature failure.
|
|||||||
### Hashing Algorithm
|
### Hashing Algorithm
|
||||||
|
|
||||||
Blake3 is used throughout: hash chain links, entropy data digest, stack state
|
Blake3 is used throughout: hash chain links, entropy data digest, stack state
|
||||||
digest, and the VM HASH opcode. Blake3 is chosen for speed in WASM,
|
digest, gene commitment, and the VM HASH opcode. Blake3 is chosen for speed
|
||||||
resistance to length-extension attacks, and a clean Rust API.
|
in WASM, resistance to length-extension attacks, and a clean Rust API.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -259,10 +306,10 @@ on every heartbeat and includes the resulting `StackState { stack, ip }` in
|
|||||||
the signed payload. This ensures each heartbeat carries unique, verifiable
|
the signed payload. This ensures each heartbeat carries unique, verifiable
|
||||||
computation without additional round-trips.
|
computation without additional round-trips.
|
||||||
|
|
||||||
### Instruction Set
|
### Core Instruction Set
|
||||||
|
|
||||||
| Opcode | Mnemonic | Operand | Stack effect | Description |
|
| Opcode | Mnemonic | Operand | Stack effect | Description |
|
||||||
|--------|----------|---------------|--------------|-------------|
|
| ------ | -------- | ----------- | ------------ | -------------------------------------- |
|
||||||
| `0x00` | PUSH | u32 (4B LE) | +1 | Push literal |
|
| `0x00` | PUSH | u32 (4B LE) | +1 | Push literal |
|
||||||
| `0x01` | ADD | — | −1 | `a + b` wrapping |
|
| `0x01` | ADD | — | −1 | `a + b` wrapping |
|
||||||
| `0x02` | SUB | — | −1 | `a - b` wrapping |
|
| `0x02` | SUB | — | −1 | `a - b` wrapping |
|
||||||
@@ -277,6 +324,33 @@ computation without additional round-trips.
|
|||||||
The generator ensures ≥ 2 items on the stack before any binary opcode.
|
The generator ensures ≥ 2 items on the stack before any binary opcode.
|
||||||
NOT (0x08) does not change depth. HASH resets depth to 1.
|
NOT (0x08) does not change depth. HASH resets depth to 1.
|
||||||
|
|
||||||
|
### Mutation Opcodes (v0.6.0)
|
||||||
|
|
||||||
|
The gene mutation extension operates on a separate `Vec<u8>` gene buffer and a
|
||||||
|
bounded environment map `Vec<(u16 symbol, u32 quantity)>`. These opcodes are
|
||||||
|
defined in `shared/src/vm_extensions.rs` and executed identically by both
|
||||||
|
server and WASM to guarantee deterministic parity.
|
||||||
|
|
||||||
|
| Opcode | Mnemonic | Effect |
|
||||||
|
| ------ | ------------------ | ------------------------------------------------------------- |
|
||||||
|
| `0x23` | GENE_LOAD | Push `gene[idx]` onto the stack |
|
||||||
|
| `0x24` | GENE_STORE | Pop stack top and store at `gene[idx]` |
|
||||||
|
| `0x25` | MUTATE_POINT | Apply wrapping byte delta at index |
|
||||||
|
| `0x26` | INSERT | Insert popped byte at index |
|
||||||
|
| `0x27` | DELETE | Delete byte at index and push the removed value |
|
||||||
|
| `0x28` | TRANSCRIBE | Push deterministic transcription hash of current gene state |
|
||||||
|
| `0x29` | APPLY_MUTAGEN | Mix environment symbol quantity into gene byte at index |
|
||||||
|
| `0x2A` | FINALIZE_GENE_HASH | Push commitment-derived `u32` onto the stack |
|
||||||
|
| `0x2B` | CONSUME | Pop amount, subtract from environment symbol quantity |
|
||||||
|
| `0x2C` | PRODUCE | Pop amount, add to environment symbol quantity |
|
||||||
|
|
||||||
|
**Constraints enforced at runtime:**
|
||||||
|
|
||||||
|
- Mutation program length capped at `MAX_MUTATION_PROGRAM_BYTES`
|
||||||
|
- Environment record count capped at `MAX_ENV_RECORDS`
|
||||||
|
- Environment records validated for sortedness, uniqueness, non-zero quantity
|
||||||
|
- Stack underflow and unknown opcodes cause deterministic, symmetric failures on both server and WASM paths
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Behavioral Validation
|
## Behavioral Validation
|
||||||
@@ -287,7 +361,7 @@ Every heartbeat includes the mouse events collected since the previous
|
|||||||
heartbeat. Server checks:
|
heartbeat. Server checks:
|
||||||
|
|
||||||
| Check | Threshold |
|
| Check | Threshold |
|
||||||
|---|---|
|
| --------------------------- | ------------------------------------ |
|
||||||
| Minimum event count | ≥ 3 |
|
| Minimum event count | ≥ 3 |
|
||||||
| Minimum cumulative distance | ≥ 10 px |
|
| Minimum cumulative distance | ≥ 10 px |
|
||||||
| Maximum average speed | ≤ 2.0 px/ms (distance / elapsed ms) |
|
| Maximum average speed | ≤ 2.0 px/ms (distance / elapsed ms) |
|
||||||
@@ -296,7 +370,7 @@ heartbeat. Server checks:
|
|||||||
### Browser Fingerprint
|
### Browser Fingerprint
|
||||||
|
|
||||||
| Signal | Valid range |
|
| Signal | Valid range |
|
||||||
|---|---|
|
| ------------------------------ | ------------- |
|
||||||
| `aspectRatio` (width / height) | 0.5 – 3.0 |
|
| `aspectRatio` (width / height) | 0.5 – 3.0 |
|
||||||
| `devicePixelRatio` | 0 < dpr ≤ 5.0 |
|
| `devicePixelRatio` | 0 < dpr ≤ 5.0 |
|
||||||
| `hardwareConcurrency` | ≥ 1 |
|
| `hardwareConcurrency` | ≥ 1 |
|
||||||
@@ -313,6 +387,10 @@ Rate-limited responses are indistinguishable from validation failures.
|
|||||||
|
|
||||||
## SQLite Schema
|
## SQLite Schema
|
||||||
|
|
||||||
|
The schema is extended in v0.6.0 with four new columns to persist per-session
|
||||||
|
gene mutation state. Migration is additive — columns are created when missing,
|
||||||
|
preserving compatibility with existing deployments.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE IF NOT EXISTS sessions (
|
CREATE TABLE IF NOT EXISTS sessions (
|
||||||
session_id TEXT PRIMARY KEY,
|
session_id TEXT PRIMARY KEY,
|
||||||
@@ -322,12 +400,71 @@ CREATE TABLE IF NOT EXISTS sessions (
|
|||||||
chain_length INTEGER NOT NULL DEFAULT 1,
|
chain_length INTEGER NOT NULL DEFAULT 1,
|
||||||
created_at INTEGER NOT NULL, -- Unix ms
|
created_at INTEGER NOT NULL, -- Unix ms
|
||||||
last_seen INTEGER NOT NULL, -- Unix ms
|
last_seen INTEGER NOT NULL, -- Unix ms
|
||||||
expires_at INTEGER NOT NULL -- Unix ms
|
expires_at INTEGER NOT NULL, -- Unix ms
|
||||||
|
-- v0.6.0: gene mutation state
|
||||||
|
gene BLOB NOT NULL DEFAULT X'', -- Vec<u8> gene buffer
|
||||||
|
environment BLOB NOT NULL DEFAULT X'', -- Vec<(u16, u32)> env records
|
||||||
|
pending_mutation BLOB NOT NULL DEFAULT X'', -- server-issued mutation program
|
||||||
|
pending_mutation_step INTEGER NOT NULL DEFAULT 0 -- current mutation step counter
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
In-memory SQLite — all sessions lost on server restart by design.
|
In-memory SQLite (`sqlite-in-memory`) — all sessions lost on server restart by
|
||||||
Clients re-initialise transparently on the next page load.
|
design. Clients re-initialise transparently on the next page load. Use
|
||||||
|
`sqlite-in-disk` for persistent sessions across restarts.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Storage Backend (v0.6.0)
|
||||||
|
|
||||||
|
ChronoSeal v0.6.0 introduces selectable database backends via the `db_type`
|
||||||
|
configuration option. The default remains in-memory to preserve ephemeral
|
||||||
|
session behavior.
|
||||||
|
|
||||||
|
### Backend Options
|
||||||
|
|
||||||
|
| `db_type` | Behavior |
|
||||||
|
| ------------------ | -------------------------------------------------------------------- |
|
||||||
|
| `sqlite-in-memory` | Default. All sessions ephemeral; lost on restart. Zero disk I/O. |
|
||||||
|
| `sqlite-in-disk` | Persistent sessions. Requires `db_path`. Survives restarts. |
|
||||||
|
| `valkey` | Compatibility mode. Currently falls back to in-memory. CLI contract preserved. |
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
**Config file** (`/etc/chronoseal/config.toml`):
|
||||||
|
```toml
|
||||||
|
db_type = "sqlite-in-disk"
|
||||||
|
db_path = "/var/lib/chronoseal/chronoseal.sqlite"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Environment variable**:
|
||||||
|
```bash
|
||||||
|
CHRONOSEAL_DB_TYPE=sqlite-in-disk
|
||||||
|
CHRONOSEAL_DB_PATH=/var/lib/chronoseal/chronoseal.sqlite
|
||||||
|
```
|
||||||
|
|
||||||
|
**CLI flag**:
|
||||||
|
```bash
|
||||||
|
chronoseal run --db-type sqlite-in-disk --db-path /var/lib/chronoseal/chronoseal.sqlite
|
||||||
|
```
|
||||||
|
|
||||||
|
**Inspect active backend**:
|
||||||
|
```bash
|
||||||
|
chronoseal db-type --format text
|
||||||
|
```
|
||||||
|
|
||||||
|
### Precedence
|
||||||
|
|
||||||
|
```
|
||||||
|
CLI flags > CHRONOSEAL_* environment variables > config file > defaults
|
||||||
|
```
|
||||||
|
|
||||||
|
### Migration Notes
|
||||||
|
|
||||||
|
- Schema migration is additive; new columns are created when missing on startup.
|
||||||
|
- Switching from `sqlite-in-memory` to `sqlite-in-disk` requires no code changes — only config.
|
||||||
|
- `valkey` is available in the CLI contract today; full backend support is tracked for a future release.
|
||||||
|
- Existing deployments without the v0.6.0 mutation columns will have those columns added automatically on first start.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -336,20 +473,23 @@ Clients re-initialise transparently on the next page load.
|
|||||||
### In Scope
|
### In Scope
|
||||||
|
|
||||||
| Threat | Mitigation |
|
| Threat | Mitigation |
|
||||||
|---|---|
|
| ------------------------------------------ | --------------------------------------------------------------- |
|
||||||
| Playwright / Puppeteer / Selenium | Mouse entropy + behavioral validation |
|
| Playwright / Puppeteer / Selenium | Mouse entropy + behavioral validation |
|
||||||
| Puppeteer Stealth, undetected-chromedriver | Signature over VM execution state |
|
| Puppeteer Stealth, undetected-chromedriver | Signature over VM execution state |
|
||||||
| Heartbeat replay | Hash chain + ±30s timestamp window |
|
| Heartbeat replay | Hash chain + ±30s timestamp window |
|
||||||
|
| Mutation replay | mutation_step + gene_commitment parity check (v0.6.0) |
|
||||||
|
| Mutation tampering | Server recomputes candidate gene from authoritative program (v0.6.0) |
|
||||||
| Signature forgery | Private key isolated in WASM memory |
|
| Signature forgery | Private key isolated in WASM memory |
|
||||||
| Parallel session sharing | Each session bound to a unique keypair |
|
| Parallel session sharing | Each session bound to a unique keypair |
|
||||||
| Brute-forced session IDs | 256-bit random entropy |
|
| Brute-forced session IDs | 256-bit random entropy |
|
||||||
| Flooding with fake session IDs | Rate limiter + periodic HashMap eviction |
|
| Flooding with fake session IDs | Rate limiter + periodic HashMap eviction |
|
||||||
| Traffic analysis | Uniform `{"status":"ok"}` on all failure paths |
|
| Traffic analysis | Uniform `{"status":"ok"}` on all failure paths |
|
||||||
|
| Malformed mutation programs | Strict parsing, length caps, underflow/unknown-opcode errors |
|
||||||
|
|
||||||
### Out of Scope
|
### Out of Scope
|
||||||
|
|
||||||
| Threat | Reason |
|
| Threat | Reason |
|
||||||
|---|---|
|
| ---------------------------------- | ---------------------------------------- |
|
||||||
| Real browser with real human input | Indistinguishable from a legitimate user |
|
| Real browser with real human input | Indistinguishable from a legitimate user |
|
||||||
| WASM reverse engineering | Obfuscation is not a security primitive |
|
| WASM reverse engineering | Obfuscation is not a security primitive |
|
||||||
| Server-side compromise | Outside the scope of client attestation |
|
| Server-side compromise | Outside the scope of client attestation |
|
||||||
@@ -362,22 +502,25 @@ cryptographic proof of humanity and does not claim to be.
|
|||||||
## Module Reference
|
## Module Reference
|
||||||
|
|
||||||
| Path | Purpose |
|
| Path | Purpose |
|
||||||
|---|---|
|
| ------------------------------------- | -------------------------------------------------------------------- |
|
||||||
| `shared/src/protocol.rs` | Shared types: `InitRequest`, `HeartbeatRequest`, `StackState`, … |
|
| `shared/src/protocol.rs` | Shared types: `InitRequest`, `HeartbeatRequest`, `StackState`, … |
|
||||||
| `shared/src/hashing.rs` | `initial_hash`, `next_chain_hash`, `hash_stack` |
|
| `shared/src/hashing.rs` | `initial_hash`, `next_chain_hash`, `hash_stack` |
|
||||||
| `shared/src/constants.rs` | All tunable parameters |
|
| `shared/src/constants.rs` | All tunable parameters |
|
||||||
|
| `shared/src/gene.rs` | Gene model, deterministic commitment (`chronoseal/gene/v1`) [v0.6.0] |
|
||||||
|
| `shared/src/vm_extensions.rs` | Mutation opcode set, shared engine for server/WASM parity [v0.6.0] |
|
||||||
| `server/src/routes/init.rs` | `POST /init` handler |
|
| `server/src/routes/init.rs` | `POST /init` handler |
|
||||||
| `server/src/routes/heartbeat.rs` | `POST /hb` handler |
|
| `server/src/routes/heartbeat.rs` | `POST /hb` handler |
|
||||||
| `server/src/session.rs` | `create_session`, `verify_heartbeat` |
|
| `server/src/session.rs` | `create_session`, `verify_heartbeat`, `validate_mutation_parity` |
|
||||||
| `server/src/crypto.rs` | `verify_signature` — BTreeMap canonical JSON |
|
| `server/src/crypto.rs` | `verify_signature` — BTreeMap canonical JSON |
|
||||||
| `server/src/trust.rs` | `validate_mouse` — speed, distance, pauses |
|
| `server/src/trust.rs` | `validate_mouse` — speed, distance, pauses |
|
||||||
| `server/src/fingerprint.rs` | `validate` — aspect ratio, DPR, HW concurrency |
|
| `server/src/fingerprint.rs` | `validate` — aspect ratio, DPR, HW concurrency |
|
||||||
| `server/src/vm.rs` | `generate_random_program` |
|
| `server/src/vm.rs` | `generate_random_program` |
|
||||||
| `server/src/ratelimit.rs` | `RateLimiter::check`, `evict_stale` |
|
| `server/src/ratelimit.rs` | `RateLimiter::check`, `evict_stale` |
|
||||||
| `server/src/cleanup.rs` | Background loop: expire sessions + evict rate limiter |
|
| `server/src/cleanup.rs` | Background loop: expire sessions + evict rate limiter |
|
||||||
| `server/src/storage.rs` | SQLite init, `current_time_ms` |
|
| `server/src/storage.rs` | SQLite init, backend selection, `current_time_ms` |
|
||||||
| `wasm/src/crypto.rs` | `generate_keypair`, `sign_message`, `compute_next_hash` |
|
| `wasm/src/crypto.rs` | `generate_keypair`, `sign_message`, `compute_next_hash` |
|
||||||
| `wasm/src/vm.rs` | `run_program` — stack machine executor |
|
| `wasm/src/vm.rs` | `run_program` — stack machine executor |
|
||||||
|
| `wasm/src/vm_extensions.rs` | `preview_mutation`, `commit_mutation` [v0.6.0] |
|
||||||
| `frontend/heartbeat.js` | Session init, heartbeat loop, chain advancement |
|
| `frontend/heartbeat.js` | Session init, heartbeat loop, chain advancement |
|
||||||
| `frontend/entropy.js` | Mouse event ring buffer, `collectEntropy` |
|
| `frontend/entropy.js` | Mouse event ring buffer, `collectEntropy` |
|
||||||
| `frontend/transport.js` | `sendRequest` fetch wrapper |
|
| `frontend/transport.js` | `sendRequest` fetch wrapper |
|
||||||
Reference in new issue
Block a user