Refactor attestation engine and synchronize project documentation
- Refine session and storage lifecycle handling - Improve VM extension architecture across server, shared, and WASM runtimes - Enhance synthetic gene mutation engine integration and parity guarantees - Align deterministic state progression between server and browser execution paths - Update configuration examples and deployment guidance - Expand architecture, API, threat model, privacy, and WASM build documentation - Refresh README with comprehensive project overview, operational workflows, browser integration details, storage backend documentation, and security model - Document v0.6.0 refactoring outcomes and design rationale - Improve consistency across documentation, configuration, and implementation This commit consolidates the v0.6.0 architectural refactoring effort, strengthening deterministic browser/server parity while improving maintainability, operational clarity, and project documentation.
This commit is contained in:
1 parent
2b8afd54e0
commit
0ed3cb444d
15 files changed
+2357
-797
No files matched your search
@@ -9,15 +9,15 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Privacy-first • Deterministic WASM parity • Silent rejection • Low overhead
|
||||
Privacy-first | Deterministic WASM parity | Silent rejection | Low overhead
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/thakares/chronoseal-rs/blob/main/LICENSE">
|
||||
<img src="https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg" alt="License: MIT OR Apache-2.0">
|
||||
</a>
|
||||
<img src="https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg" alt="License: MIT OR Apache-2.0">
|
||||
</a>
|
||||
<a href="https://github.com/thakares/chronoseal-rs">
|
||||
<img src="https://img.shields.io/badge/rust-stable%20%E2%89%A5%201.87-orange.svg" alt="Rust stable ≥ 1.87">
|
||||
<img src="https://img.shields.io/badge/rust-stable%20%E2%89%A5%201.87-orange.svg" alt="Rust stable >= 1.87">
|
||||
</a>
|
||||
<a href="https://github.com/thakares/chronoseal-rs/blob/main/docs/REFRACTORING-v0.6.0.md">
|
||||
<img src="https://img.shields.io/badge/version-v0.6.0-green.svg" alt="v0.6.0">
|
||||
@@ -27,200 +27,722 @@
|
||||
|
||||
---
|
||||
|
||||
ChronoSeal is a mature Unix-native cryptographic attestation daemon for browser session continuity and anti-automation defense.
|
||||
ChronoSeal is a Linux-native cryptographic attestation service for browser session continuity and anti-automation defense. It runs as a small daemon, serves a browser WASM runtime, and validates signed heartbeat requests through deterministic server/client state progression.
|
||||
|
||||
It provides a low-overhead, privacy-respecting proof-of-runtime system built around a deterministic **Synthetic Gene Mutation Engine** and a silent, replay-resistant heartbeat protocol.
|
||||
The core idea is simple: a real browser session should be able to keep advancing a private cryptographic state, a hash chain, and a deterministic synthetic gene mutation chain. Basic HTTP clients, stale replay attempts, and incomplete automation should fail without receiving a useful failure reason.
|
||||
|
||||
v0.6.0 introduces the core innovation: a deterministic synthetic gene mutation chain with server/WASM parity, stronger liveness guarantees, and a domain-separated mutation commitment handshake.
|
||||
ChronoSeal is a cost-raising attestation layer. It is not a CAPTCHA replacement, identity provider, fingerprinting product, or perfect bot blocker.
|
||||
|
||||
---
|
||||
## Contents
|
||||
|
||||
## What ChronoSeal Provides
|
||||
- [Features](#features)
|
||||
- [How It Works](#how-it-works)
|
||||
- [Repository Layout](#repository-layout)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Build From Source](#build-from-source)
|
||||
- [Run Locally](#run-locally)
|
||||
- [Install as a Service](#install-as-a-service)
|
||||
- [Docker](#docker)
|
||||
- [CLI Reference](#cli-reference)
|
||||
- [Configuration](#configuration)
|
||||
- [HTTP API](#http-api)
|
||||
- [Browser Integration](#browser-integration)
|
||||
- [Storage Backends](#storage-backends)
|
||||
- [Operations](#operations)
|
||||
- [Security Model](#security-model)
|
||||
- [Development](#development)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Further Reading](#further-reading)
|
||||
- [License](#license)
|
||||
|
||||
* Native Linux daemon with hardened `systemd` integration
|
||||
* Deterministic mutation engine running in both server Rust and client WASM
|
||||
* Silent rejection semantics for attacker resilience
|
||||
* Multi-backend storage: `sqlite-in-memory`, `sqlite-disk`, and `valkey`
|
||||
* CLI-first operation with rich subcommands
|
||||
* Structured logging, PID file management, graceful shutdown
|
||||
* Prometheus-compatible metrics and runtime statistics
|
||||
* Lightweight browser runtime with WASM-based attestation
|
||||
* Privacy-first design with ephemeral session state and no persistent tracking
|
||||
## Features
|
||||
|
||||
---
|
||||
- Native Unix daemon with `systemd` service support.
|
||||
- Axum-based HTTP service exposing `/init`, `/hb`, `/health`, `/metrics`, and `/stats`.
|
||||
- Rust/WASM browser runtime for key generation, signing, VM execution, and mutation preview.
|
||||
- Deterministic Synthetic Gene Mutation Engine shared by the server and WASM crates.
|
||||
- Ed25519 signatures over canonical heartbeat payloads.
|
||||
- Blake3 hash chain continuity across accepted heartbeats.
|
||||
- Silent rejection semantics: invalid heartbeats still return `{"status":"ok"}`.
|
||||
- Configurable behavioral trust checks for mouse movement, pauses, timing, and browser signals.
|
||||
- Runtime storage abstraction with `sqlite-in-memory`, `sqlite-in-disk`, and `valkey` modes.
|
||||
- CLI-first lifecycle, status, health, metrics, stats, config validation, key generation, and shell completions.
|
||||
- Privacy-oriented design based on ephemeral session state rather than long-term identity tracking.
|
||||
|
||||
## Why ChronoSeal
|
||||
## How It Works
|
||||
|
||||
ChronoSeal raises the operational cost of automation by combining:
|
||||
ChronoSeal creates a short-lived browser attestation session and advances it through signed heartbeats.
|
||||
|
||||
* cryptographic session continuity
|
||||
* deterministic VM execution
|
||||
* behavioral entropy validation
|
||||
* mutation commitment parity
|
||||
* silent, ambiguous rejection behavior
|
||||
1. The browser loads the generated WASM package from `frontend/pkg`.
|
||||
2. The WASM runtime generates an Ed25519 keypair and returns the public key to JavaScript.
|
||||
3. The browser calls `POST /init` with the public key.
|
||||
4. The server creates a session and returns:
|
||||
- `session_id`
|
||||
- initial salt
|
||||
- initial hash chain head
|
||||
- VM opcode program
|
||||
- gene size
|
||||
- mutation step
|
||||
- mutation order
|
||||
- heartbeat timing bounds
|
||||
5. For each heartbeat, the browser:
|
||||
- executes the VM opcode program
|
||||
- collects entropy and browser signal data
|
||||
- previews the next synthetic gene commitment in WASM
|
||||
- signs the canonical heartbeat payload
|
||||
- posts the request to `POST /hb`
|
||||
6. The server validates:
|
||||
- session existence and expiration
|
||||
- rate limit
|
||||
- timestamp drift
|
||||
- Ed25519 signature
|
||||
- hash chain continuity
|
||||
- behavioral trust checks
|
||||
- mutation step
|
||||
- gene commitment parity
|
||||
7. If the heartbeat is accepted, the server advances session state and returns the next salt and mutation order.
|
||||
8. If the heartbeat is rejected, the server returns only `{"status":"ok"}`.
|
||||
|
||||
This is not a fingerprinting or surveillance platform. ChronoSeal is designed to make automation expensive, not to collect user identities.
|
||||
The silent failure model deliberately avoids exposing which validation failed.
|
||||
|
||||
---
|
||||
## Repository Layout
|
||||
|
||||
```text
|
||||
.
|
||||
├── Cargo.toml # Rust workspace
|
||||
├── server/ # chronoseal daemon and CLI
|
||||
├── shared/ # shared protocol, gene model, mutation engine
|
||||
├── wasm/ # WASM runtime crate
|
||||
├── frontend/ # static browser integration files
|
||||
├── docs/ # architecture, API, deployment, threat model
|
||||
├── scripts/ # build, install, release, dev helpers
|
||||
├── chronoseal.service # systemd unit
|
||||
├── Dockerfile # container image
|
||||
└── docker-compose.yml # local container orchestration
|
||||
```
|
||||
|
||||
Workspace members:
|
||||
|
||||
- `chronoseal-server`: daemon binary crate. Binary name: `chronoseal`.
|
||||
- `shared`: common cryptographic and mutation logic used by server and WASM.
|
||||
- `chronoseal-wasm`: browser runtime compiled with `wasm-pack`.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Install
|
||||
For a full native install:
|
||||
|
||||
```bash
|
||||
sudo bash scripts/install.sh
|
||||
```
|
||||
|
||||
### Verify status
|
||||
Check the daemon:
|
||||
|
||||
```bash
|
||||
chronoseal status --format json
|
||||
```
|
||||
|
||||
### Health probe
|
||||
|
||||
```bash
|
||||
chronoseal health
|
||||
```
|
||||
|
||||
### View metrics
|
||||
|
||||
```bash
|
||||
chronoseal metrics
|
||||
```
|
||||
|
||||
### Follow logs
|
||||
|
||||
```bash
|
||||
sudo journalctl -u chronoseal -f
|
||||
```
|
||||
|
||||
---
|
||||
For local development without installing:
|
||||
|
||||
## CLI Overview
|
||||
```bash
|
||||
bash scripts/build.sh
|
||||
cargo run -p chronoseal-server --bin chronoseal -- run \
|
||||
--bind 127.0.0.1:3000 \
|
||||
--frontend-dir frontend
|
||||
```
|
||||
|
||||
Then open:
|
||||
|
||||
```text
|
||||
http://127.0.0.1:3000
|
||||
```
|
||||
|
||||
## Build From Source
|
||||
|
||||
### Requirements
|
||||
|
||||
| Tool | Minimum | Purpose |
|
||||
|---|---:|---|
|
||||
| Rust | 1.87 stable | Build server, shared crate, and tests |
|
||||
| wasm-pack | 0.13 | Build browser WASM package |
|
||||
| wasm32 target | current stable | WASM compilation target |
|
||||
| systemd | 248+ | Optional native service management |
|
||||
| Docker | 24.x | Optional container workflow |
|
||||
| Docker Compose | 2.x | Optional local orchestration |
|
||||
|
||||
Install the WASM target and `wasm-pack`:
|
||||
|
||||
```bash
|
||||
rustup target add wasm32-unknown-unknown
|
||||
cargo install wasm-pack
|
||||
```
|
||||
|
||||
Build everything needed for the browser and server:
|
||||
|
||||
```bash
|
||||
bash scripts/build.sh
|
||||
```
|
||||
|
||||
That script:
|
||||
|
||||
1. Builds `wasm/` with `wasm-pack build --target web --release`.
|
||||
2. Replaces `frontend/pkg` with the generated WASM package.
|
||||
3. Builds the `chronoseal` release binary.
|
||||
|
||||
Manual build:
|
||||
|
||||
```bash
|
||||
wasm-pack build wasm --target web --release
|
||||
rm -rf frontend/pkg
|
||||
mv wasm/pkg frontend/pkg
|
||||
|
||||
cargo build -p chronoseal-server --bin chronoseal --release
|
||||
```
|
||||
|
||||
The binary is written to:
|
||||
|
||||
```text
|
||||
target/release/chronoseal
|
||||
```
|
||||
|
||||
## Run Locally
|
||||
|
||||
Run the daemon directly from Cargo:
|
||||
|
||||
```bash
|
||||
cargo run -p chronoseal-server --bin chronoseal -- run \
|
||||
--bind 127.0.0.1:3000 \
|
||||
--frontend-dir frontend
|
||||
```
|
||||
|
||||
Probe it:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:3000/health
|
||||
curl http://127.0.0.1:3000/stats
|
||||
curl http://127.0.0.1:3000/metrics
|
||||
```
|
||||
|
||||
Use the CLI wrappers:
|
||||
|
||||
```bash
|
||||
cargo run -p chronoseal-server --bin chronoseal -- status --bind 127.0.0.1:3000
|
||||
cargo run -p chronoseal-server --bin chronoseal -- health --bind 127.0.0.1:3000
|
||||
cargo run -p chronoseal-server --bin chronoseal -- stats --bind 127.0.0.1:3000 --format json
|
||||
```
|
||||
|
||||
## Install as a Service
|
||||
|
||||
The installer builds the project, installs the binary, copies frontend assets, installs the `systemd` unit, and starts the service.
|
||||
|
||||
```bash
|
||||
sudo bash scripts/install.sh
|
||||
```
|
||||
|
||||
Installed paths:
|
||||
|
||||
| Path | Purpose |
|
||||
|---|---|
|
||||
| `/usr/local/bin/chronoseal` | daemon and CLI binary |
|
||||
| `/opt/chronoseal/frontend` | static frontend assets copied by installer |
|
||||
| `/etc/systemd/system/chronoseal.service` | service unit |
|
||||
| `/run/chronoseal.pid` | default PID file |
|
||||
|
||||
Service commands:
|
||||
|
||||
```bash
|
||||
sudo systemctl status chronoseal
|
||||
sudo systemctl restart chronoseal
|
||||
sudo systemctl disable --now chronoseal
|
||||
sudo journalctl -u chronoseal -f
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
Build and run with Compose:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The provided container exposes port `3000`.
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:3000/health
|
||||
```
|
||||
|
||||
Important: the Dockerfile copies `frontend/` from the working tree. Build the WASM package into `frontend/pkg` before building the container if you need the browser runtime inside the image:
|
||||
|
||||
```bash
|
||||
bash scripts/build.sh
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
## CLI Reference
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
chronoseal --help
|
||||
```
|
||||
|
||||
### Available commands
|
||||
Global options:
|
||||
|
||||
| Command | Description |
|
||||
| ------------ | ------------------------------------------ |
|
||||
| `run` | Run the ChronoSeal daemon |
|
||||
| `status` | Report daemon status |
|
||||
| `health` | Perform daemon health probe |
|
||||
| `config` | Validate and print effective configuration |
|
||||
| `generate` | Generate operational material |
|
||||
| `db-type` | List database backend support status |
|
||||
| `metrics` | Output Prometheus metrics |
|
||||
| `stats` | Print runtime statistics |
|
||||
| `completion` | Generate shell completions |
|
||||
| `version` | Print version/build information |
|
||||
| Option | Environment | Description |
|
||||
|---|---|---|
|
||||
| `--config <path>` | `CHRONOSEAL_CONFIG` | Explicit TOML config path |
|
||||
| `--format <text|json|yaml>` | - | Output format for machine-readable commands |
|
||||
| `--output <text|json|yaml>` | - | Alias for `--format` |
|
||||
| `--log <filter>` | `CHRONOSEAL_LOG` | Tracing filter, for example `info` or `chronoseal=debug` |
|
||||
|
||||
---
|
||||
Commands:
|
||||
|
||||
## Example
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `chronoseal run` | Run the daemon |
|
||||
| `chronoseal status` | Check configured daemon reachability and PID state |
|
||||
| `chronoseal health` | Perform an HTTP health probe |
|
||||
| `chronoseal config check` | Validate and print effective configuration |
|
||||
| `chronoseal generate keypair` | Generate an Ed25519 keypair |
|
||||
| `chronoseal version` | Print version/build information |
|
||||
| `chronoseal db-type` | List database backend support status |
|
||||
| `chronoseal metrics` | Fetch Prometheus metrics from the running daemon |
|
||||
| `chronoseal stats` | Fetch service statistics from the running daemon |
|
||||
| `chronoseal completion <shell>` | Generate shell completions |
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
chronoseal run --bind 127.0.0.1:3000 --frontend-dir frontend
|
||||
chronoseal run --db-type sqlite-in-memory
|
||||
chronoseal status --format json
|
||||
chronoseal health --config /etc/chronoseal/config.toml
|
||||
chronoseal config check --output yaml
|
||||
chronoseal generate keypair --format json
|
||||
chronoseal completion bash > chronoseal.bash
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration precedence:
|
||||
|
||||
1. CLI flags
|
||||
2. `CHRONOSEAL_*` environment variables
|
||||
3. TOML config file
|
||||
4. built-in defaults
|
||||
|
||||
Default config discovery:
|
||||
|
||||
1. path from `CHRONOSEAL_CONFIG`, if it exists
|
||||
2. `/etc/chronoseal/config.toml`
|
||||
3. `$XDG_CONFIG_HOME/chronoseal/config.toml`
|
||||
4. `~/.config/chronoseal/config.toml`
|
||||
|
||||
Example:
|
||||
|
||||
```toml
|
||||
bind = "0.0.0.0:3000"
|
||||
db_type = "sqlite-in-memory"
|
||||
pid_file = "/run/chronoseal.pid"
|
||||
db_path = "/var/lib/chronoseal/chronoseal.sqlite"
|
||||
frontend_dir = "/usr/share/chronoseal/frontend"
|
||||
log_file = "/var/log/chronoseal/chronoseal.jsonl"
|
||||
|
||||
heartbeat_min_interval_ms = 12000
|
||||
heartbeat_max_interval_ms = 25000
|
||||
expiration_minutes = 30
|
||||
rate_limit_count = 5
|
||||
rate_limit_window_secs = 10
|
||||
max_timestamp_drift_ms = 30000
|
||||
|
||||
min_mouse_total_dist = 10.0
|
||||
max_mouse_avg_speed = 2.0
|
||||
min_pause_count = 1
|
||||
require_mouse_activity = true
|
||||
|
||||
gene_size = 512
|
||||
mutation_rounds = 4
|
||||
```
|
||||
|
||||
Common environment variables:
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `CHRONOSEAL_CONFIG` | Config file path |
|
||||
| `CHRONOSEAL_BIND` | Bind address, for example `127.0.0.1:3000` |
|
||||
| `CHRONOSEAL_DB_TYPE` | `sqlite-in-memory`, `sqlite-in-disk`, or `valkey` |
|
||||
| `CHRONOSEAL_DB_PATH` | SQLite database path |
|
||||
| `CHRONOSEAL_FRONTEND_DIR` | Static frontend directory served at `/` |
|
||||
| `CHRONOSEAL_PID_FILE` | PID file path |
|
||||
| `CHRONOSEAL_LOG` | Tracing filter |
|
||||
| `CHRONOSEAL_LOG_FILE` | Optional JSON log file |
|
||||
| `CHRONOSEAL_STATE_DIR` | Base state directory used for default `db_path` |
|
||||
| `CHRONOSEAL_HEARTBEAT_MIN_INTERVAL_MS` | Minimum accepted heartbeat interval |
|
||||
| `CHRONOSEAL_HEARTBEAT_MAX_INTERVAL_MS` | Maximum accepted heartbeat interval |
|
||||
| `CHRONOSEAL_EXPIRATION_MINUTES` | Session lifetime |
|
||||
| `CHRONOSEAL_RATE_LIMIT_COUNT` | Requests allowed in the rate-limit window |
|
||||
| `CHRONOSEAL_RATE_LIMIT_WINDOW_SECS` | Rate-limit window length |
|
||||
| `CHRONOSEAL_MAX_TIMESTAMP_DRIFT_MS` | Accepted client timestamp drift |
|
||||
| `CHRONOSEAL_MIN_MOUSE_TOTAL_DIST` | Minimum mouse movement distance |
|
||||
| `CHRONOSEAL_MAX_MOUSE_AVG_SPEED` | Maximum average mouse speed |
|
||||
| `CHRONOSEAL_MIN_PAUSE_COUNT` | Minimum detected pause count |
|
||||
| `CHRONOSEAL_REQUIRE_MOUSE_ACTIVITY` | Enable or disable mouse activity requirement |
|
||||
| `CHRONOSEAL_GENE_SIZE` | Synthetic gene buffer size |
|
||||
| `CHRONOSEAL_MUTATION_ROUNDS` | Mutation rounds per program |
|
||||
|
||||
Validate configuration:
|
||||
|
||||
```bash
|
||||
chronoseal config check --format yaml
|
||||
```
|
||||
|
||||
## HTTP API
|
||||
|
||||
ChronoSeal exposes a small HTTP surface:
|
||||
|
||||
| Method | Path | Purpose |
|
||||
|---|---|---|
|
||||
| `POST` | `/init` | Start a browser attestation session |
|
||||
| `POST` | `/hb` | Submit a signed heartbeat |
|
||||
| `GET` | `/health` | Health probe |
|
||||
| `GET` | `/metrics` | Prometheus metrics |
|
||||
| `GET` | `/stats` | Runtime statistics |
|
||||
| `GET` | `/` | Static frontend files from `frontend_dir` |
|
||||
|
||||
### `POST /init`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"public_key": "hex-encoded 32-byte Ed25519 verifying key"
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "64-char hex string",
|
||||
"salt": "32-char hex string",
|
||||
"opcodes_b64": "base64-encoded VM program",
|
||||
"initial_hash": "64-char hex string",
|
||||
"expires_at": 1234567890123,
|
||||
"heartbeat_min_interval_ms": 12000,
|
||||
"heartbeat_max_interval_ms": 25000,
|
||||
"gene_size": 512,
|
||||
"mutation_step": 1,
|
||||
"mutation_order_b64": "base64-encoded mutation program"
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /hb`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "64-char hex",
|
||||
"prev_hash": "64-char hex",
|
||||
"timestamp": 1234567890123,
|
||||
"entropy_data": {
|
||||
"events": [
|
||||
{ "x": 412.0, "y": 308.5, "t": 1234.567 }
|
||||
]
|
||||
},
|
||||
"stack_state": {
|
||||
"stack": [2971406957, 1234567890],
|
||||
"ip": 42
|
||||
},
|
||||
"fingerprint": {
|
||||
"aspectRatio": "1.7777777778",
|
||||
"devicePixelRatio": 2,
|
||||
"hardwareConcurrency": 8
|
||||
},
|
||||
"mutation_step": 1,
|
||||
"gene_commitment": "64-char hex",
|
||||
"signature": "128-char hex"
|
||||
}
|
||||
```
|
||||
|
||||
Accepted response:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"next_salt": "32-char hex string",
|
||||
"next_mutation_step": 2,
|
||||
"next_mutation_order_b64": "base64-encoded mutation program"
|
||||
}
|
||||
```
|
||||
|
||||
Rejected response:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok"
|
||||
}
|
||||
```
|
||||
|
||||
Detailed API semantics are documented in [docs/API.md](docs/API.md).
|
||||
|
||||
## Browser Integration
|
||||
|
||||
The frontend imports the generated WASM module from `frontend/pkg`.
|
||||
|
||||
```js
|
||||
import init, {
|
||||
generate_keypair,
|
||||
get_public_key,
|
||||
sign_message,
|
||||
compute_next_hash,
|
||||
run_program,
|
||||
init_gene_state,
|
||||
preview_gene_commitment,
|
||||
commit_gene_preview,
|
||||
discard_gene_preview,
|
||||
current_gene_commitment
|
||||
} from './pkg/chronoseal_wasm.js';
|
||||
```
|
||||
|
||||
Call `await init()` before invoking exported functions.
|
||||
|
||||
WASM exports:
|
||||
|
||||
| Function | Purpose |
|
||||
|---|---|
|
||||
| `generate_keypair()` | Generate a browser-local Ed25519 keypair and return public key hex |
|
||||
| `get_public_key()` | Return current public key hex |
|
||||
| `sign_message(msg)` | Sign a canonical UTF-8 payload and return signature hex |
|
||||
| `compute_next_hash(prev, ts, entropy, stack, salt)` | Compute next Blake3 hash-chain value |
|
||||
| `run_program(b64)` | Execute a base64 VM program and return stack state |
|
||||
| `init_gene_state(gene_size)` | Initialize the synthetic gene buffer |
|
||||
| `preview_gene_commitment(order_b64, session_id, mutation_step, rounds)` | Preview next gene commitment |
|
||||
| `commit_gene_preview()` | Commit the previewed gene mutation after accepted heartbeat |
|
||||
| `discard_gene_preview()` | Discard previewed mutation after rejection or error |
|
||||
| `current_gene_commitment(session_id, mutation_step)` | Return current committed gene commitment |
|
||||
|
||||
String-returning WASM functions return an empty string on error. Boolean-returning functions indicate success or failure directly.
|
||||
|
||||
## Storage Backends
|
||||
|
||||
Set storage mode with `db_type` or `CHRONOSEAL_DB_TYPE`.
|
||||
|
||||
| Backend | Description |
|
||||
|---|---|
|
||||
| `sqlite-in-memory` | Default ephemeral session storage. State is lost on restart. |
|
||||
| `sqlite-in-disk` | SQLite database persisted at `db_path`. |
|
||||
| `valkey` | Valkey-compatible backend mode. |
|
||||
|
||||
For Valkey mode, the server reads `CHRONOSEAL_VALKEY_ADDR` and defaults to `127.0.0.1:6666` when it is not set. If the Valkey connection fails, the current implementation falls back to in-memory SQLite and logs a warning.
|
||||
|
||||
## Operations
|
||||
|
||||
### Health
|
||||
|
||||
```bash
|
||||
chronoseal health
|
||||
curl http://127.0.0.1:3000/health
|
||||
```
|
||||
|
||||
### Status
|
||||
|
||||
```bash
|
||||
chronoseal status --format json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"running": true,
|
||||
"healthy": true,
|
||||
"bind": "0.0.0.0:3000",
|
||||
"pid_file": "/run/chronoseal.pid",
|
||||
"pid": 79459
|
||||
### Metrics
|
||||
|
||||
```bash
|
||||
chronoseal metrics
|
||||
curl http://127.0.0.1:3000/metrics
|
||||
```
|
||||
|
||||
### Stats
|
||||
|
||||
```bash
|
||||
chronoseal stats --format json
|
||||
curl http://127.0.0.1:3000/stats
|
||||
```
|
||||
|
||||
### Logs
|
||||
|
||||
```bash
|
||||
sudo journalctl -u chronoseal -f
|
||||
```
|
||||
|
||||
Use `RUST_LOG=info` or `CHRONOSEAL_LOG=info` for normal production operation. Avoid debug logging in production because internal identifiers may appear in logs.
|
||||
|
||||
### Reverse Proxy
|
||||
|
||||
ChronoSeal should run behind TLS in production. Terminate HTTPS at a reverse proxy such as nginx, Caddy, HAProxy, or a cloud load balancer, then proxy to the local daemon.
|
||||
|
||||
Example nginx location:
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture Summary
|
||||
|
||||
ChronoSeal is composed of three primary runtime components:
|
||||
|
||||
* `shared/` — shared cryptographic primitives, hash chaining, gene model, and mutation engine used by both server and WASM
|
||||
* `server/` — Axum-based Unix-native daemon, session lifecycle, storage, trust evaluation, and `POST /init` / `POST /hb` routes
|
||||
* `wasm/` — browser runtime for key generation, signature creation, VM execution, and mutation preview/commit lifecycle
|
||||
|
||||
### Key innovations in v0.6.0
|
||||
|
||||
* Synthetic Gene Mutation Engine with deterministic, shared opcode semantics
|
||||
* Server-side gene commitment validation on every heartbeat
|
||||
* `mutation_step` and `mutation_order_b64` handshake in init and heartbeat responses
|
||||
* `db_type` runtime backend selection with SQLite and Valkey support
|
||||
|
||||
---
|
||||
|
||||
## How ChronoSeal Works
|
||||
|
||||
ChronoSeal establishes continuity by chaining signed heartbeats between client and server.
|
||||
|
||||
### Session flow
|
||||
|
||||
1. Client loads the WASM runtime and generates an Ed25519 keypair in WASM memory.
|
||||
2. Client calls `POST /init` with the public key.
|
||||
3. Server creates an ephemeral session and returns a `session_id`, initial salt, VM program, and mutation order metadata.
|
||||
4. Client executes the VM program, collects browser entropy, previews the mutation commitment, signs the heartbeat payload, and sends `POST /hb`.
|
||||
5. Server verifies signature, hash chain continuity, behavioral sanity, mutation step parity, and gene commitment before returning the next salt and mutation order.
|
||||
|
||||
### Silent failure model
|
||||
|
||||
Invalid heartbeats are returned as `{"status":"ok"}` without mutation fields. This avoids giving attackers explicit feedback.
|
||||
|
||||
---
|
||||
|
||||
## Storage Backends
|
||||
|
||||
ChronoSeal supports multiple runtime storage backends configured via `db_type`:
|
||||
|
||||
* `sqlite-in-memory` — default ephemeral session storage
|
||||
* `sqlite-disk` — persisted SQLite storage on disk
|
||||
* `valkey` — alternative backend compatibility mode for future high-performance storage
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
ChronoSeal is intended to run as a systemd-managed Unix daemon with strict sandboxing and observable metrics.
|
||||
|
||||
See [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) for build, installation, and production deployment guidance.
|
||||
|
||||
---
|
||||
|
||||
## Security Model
|
||||
|
||||
ChronoSeal is a cost-raising attestations layer, not a perfect bot blocker.
|
||||
ChronoSeal is designed to raise the cost of automation and replay attacks.
|
||||
|
||||
It protects against:
|
||||
It helps defend against:
|
||||
|
||||
* replay attacks
|
||||
* session cloning
|
||||
* invalid signature injection
|
||||
* broken hash chain continuity
|
||||
* mutation tampering
|
||||
* simple synthetic mouse and browser automation
|
||||
- replayed heartbeats
|
||||
- stale hash chain state
|
||||
- forged heartbeat signatures
|
||||
- mutation commitment tampering
|
||||
- session cloning using only a stolen `session_id`
|
||||
- simple scripted clients that do not run the WASM runtime
|
||||
- basic browser automation with weak interaction simulation
|
||||
|
||||
It does not attempt to protect against:
|
||||
It does not claim to stop:
|
||||
|
||||
* real users acting as bots
|
||||
* server-side application vulnerabilities
|
||||
* fully resourced adversaries with real browsers and hardware input devices
|
||||
- real users intentionally acting as bots
|
||||
- fully resourced browser farms
|
||||
- attackers with complete control of a real browser and realistic input
|
||||
- server-side application vulnerabilities
|
||||
- account abuse outside ChronoSeal's attestation boundary
|
||||
- long-term identity or fraud decisions by itself
|
||||
|
||||
See [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md) for the full threat model.
|
||||
Privacy posture:
|
||||
|
||||
---
|
||||
- Sessions are short-lived.
|
||||
- The private key is generated in the browser runtime and is not sent to the server.
|
||||
- ChronoSeal validates continuity and plausibility rather than creating persistent user identities.
|
||||
- Invalid heartbeats are rejected silently to reduce oracle feedback.
|
||||
|
||||
Read the full model in [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md).
|
||||
|
||||
## Development
|
||||
|
||||
Run the standard checks:
|
||||
|
||||
```bash
|
||||
cargo fmt --check
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets -- -D warnings
|
||||
```
|
||||
|
||||
Format:
|
||||
|
||||
```bash
|
||||
cargo fmt
|
||||
```
|
||||
|
||||
Build WASM during frontend/runtime changes:
|
||||
|
||||
```bash
|
||||
wasm-pack build wasm --target web
|
||||
rm -rf frontend/pkg
|
||||
mv wasm/pkg frontend/pkg
|
||||
```
|
||||
|
||||
Build release artifacts:
|
||||
|
||||
```bash
|
||||
bash scripts/build.sh
|
||||
```
|
||||
|
||||
Generate shell completion:
|
||||
|
||||
```bash
|
||||
chronoseal completion bash > chronoseal.bash
|
||||
chronoseal completion zsh > _chronoseal
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Browser fails to load WASM
|
||||
|
||||
Rebuild the WASM package and make sure `frontend/pkg/chronoseal_wasm.js` and the `.wasm` file exist:
|
||||
|
||||
```bash
|
||||
bash scripts/build.sh
|
||||
```
|
||||
|
||||
The `.wasm` file must be served as `application/wasm`. The built-in static file service handles this for normal ChronoSeal deployments.
|
||||
|
||||
### `chronoseal health` fails
|
||||
|
||||
Check that the daemon is running and that the CLI is probing the correct bind address:
|
||||
|
||||
```bash
|
||||
sudo systemctl status chronoseal
|
||||
chronoseal health --bind 127.0.0.1:3000
|
||||
curl http://127.0.0.1:3000/health
|
||||
```
|
||||
|
||||
### Heartbeats return only `{"status":"ok"}`
|
||||
|
||||
That is the expected response for rejected heartbeats. Common causes include:
|
||||
|
||||
- invalid signature
|
||||
- stale `prev_hash`
|
||||
- stale `mutation_step`
|
||||
- mismatched `gene_commitment`
|
||||
- timestamp drift beyond the configured window
|
||||
- insufficient mouse movement or pause data
|
||||
- rate limiting
|
||||
- expired session
|
||||
|
||||
Use local development logs and tests to debug integration issues. Avoid debug logs in production.
|
||||
|
||||
### SQLite disk mode cannot persist state
|
||||
|
||||
Ensure the daemon user can create and write the configured database path:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /var/lib/chronoseal
|
||||
sudo chown -R chronoseal:chronoseal /var/lib/chronoseal
|
||||
```
|
||||
|
||||
Use:
|
||||
|
||||
```toml
|
||||
db_type = "sqlite-in-disk"
|
||||
db_path = "/var/lib/chronoseal/chronoseal.sqlite"
|
||||
```
|
||||
|
||||
### Config changes do not apply
|
||||
|
||||
Check precedence. CLI flags override environment variables, environment variables override config files, and config files override built-in defaults.
|
||||
|
||||
Print the effective config:
|
||||
|
||||
```bash
|
||||
chronoseal config check --format yaml
|
||||
```
|
||||
|
||||
## Further Reading
|
||||
|
||||
* [Architecture](docs/ARCHITECTURE.md)
|
||||
* [API Reference](docs/API.md)
|
||||
* [Deployment](docs/DEPLOYMENT.md)
|
||||
* [Threat Model](docs/THREAT_MODEL.md)
|
||||
* [Design Philosophy](docs/DESIGN-PHILOSOPHY.md)
|
||||
* [Privacy Policy](docs/PRIVACY%20POLICY.md)
|
||||
* [WASM Build](docs/WASM_BUILD.md)
|
||||
* [Refactoring v0.6.0](docs/REFRACTORING-v0.6.0.md)
|
||||
- [Architecture](docs/ARCHITECTURE.md)
|
||||
- [API Reference](docs/API.md)
|
||||
- [Deployment Guide](docs/DEPLOYMENT.md)
|
||||
- [Threat Model](docs/THREAT_MODEL.md)
|
||||
- [Design Philosophy](docs/DESIGN-PHILOSOPHY.md)
|
||||
- [Privacy Policy](docs/PRIVACY%20POLICY.md)
|
||||
- [WASM Build Guide](docs/WASM_BUILD.md)
|
||||
- [Refactoring v0.6.0](docs/REFRACTORING-v0.6.0.md)
|
||||
- [Contributing](CONTRIBUTING.md)
|
||||
- [Security Policy](SECURITY.md)
|
||||
|
||||
## License
|
||||
|
||||
ChronoSeal is licensed under either of:
|
||||
|
||||
- MIT, see [LICENSE](LICENSE)
|
||||
- Apache-2.0, see [LICENSE-APACHE](LICENSE-APACHE)
|
||||
|
||||
at your option.
|
||||
Reference in new issue
Block a user