Files
nx9-chronoseal-rs/docs/API.md
T
thakares 0ed3cb444d 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.
2026-05-29 21:55:08 +05:30

11 KiB

ChronoSeal API Reference

ChronoSeal exposes a small HTTP API for browser attestation, heartbeat verification, health checks, metrics, and runtime statistics.

This document describes the wire format and acceptance semantics. The internal state model is covered in ARCHITECTURE.md.

Base URL

All paths are relative to the ChronoSeal server root.

  • Development default: http://127.0.0.1:3000
  • Production: the HTTPS origin or reverse-proxy path used by the protected site

Production deployments should use HTTPS. The daemon itself can run behind a local reverse proxy.

Content Type

JSON endpoints expect:

Content-Type: application/json

Responses are JSON except /metrics, which returns Prometheus text format.

Endpoint Summary

Method Path Purpose
POST /init Create a browser attestation session
POST /hb Submit and verify a signed heartbeat
GET /health Return daemon health
GET /stats Return storage/session statistics
GET /metrics Return Prometheus-compatible metrics
GET / Serve static frontend assets from frontend_dir

Data Types

Common encodings:

Value Encoding
Ed25519 public key 32 raw bytes encoded as 64 hex characters
Ed25519 signature 64 raw bytes encoded as 128 hex characters
session_id 32 random bytes encoded as 64 hex characters
salt 16 random bytes encoded as 32 hex characters
initial_hash, prev_hash, gene_commitment 32-byte digest encoded as 64 hex characters
opcodes_b64, mutation_order_b64 standard base64
timestamps Unix time in milliseconds unless otherwise stated

POST /init

Creates a new attestation session.

Request

POST /init
Content-Type: application/json
{
  "public_key": "hex-encoded 32-byte Ed25519 verifying key"
}
Field Type Required Description
public_key string yes Browser-generated Ed25519 public key as 64 hex characters

The private key is generated and retained by the browser WASM runtime. It is not sent to the server.

Successful Response

HTTP/1.1 200 OK
Content-Type: application/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"
}
Field Type Description
session_id string Opaque session identifier
salt string Current server salt for the first heartbeat hash computation
opcodes_b64 string Randomized VM program executed by the browser runtime
initial_hash string Initial chain head used as prev_hash for the first heartbeat
expires_at number Session expiration timestamp in milliseconds
heartbeat_min_interval_ms number Minimum heartbeat delay recommended by the server
heartbeat_max_interval_ms number Maximum heartbeat delay recommended by the server
gene_size number Initial synthetic gene buffer size
mutation_step number Mutation step expected on the first heartbeat
mutation_order_b64 string Server-authored mutation order for the first heartbeat

Error Behavior

/init uses normal route-level error handling for invalid payloads or server failures. Invalid public key length, invalid configured gene size, or storage failure can prevent session creation.

Unlike /hb, initialization failures are not part of the silent heartbeat rejection model.

POST /hb

Submits one heartbeat for an existing session.

Request

POST /hb
Content-Type: application/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"
}
Field Type Required Description
session_id string yes Session ID from /init
prev_hash string yes Current browser view of the accepted hash-chain head
timestamp number yes Browser wall-clock timestamp in milliseconds
entropy_data.events array yes Mouse samples since the previous heartbeat
entropy_data.events[].x number yes Mouse x coordinate
entropy_data.events[].y number yes Mouse y coordinate
entropy_data.events[].t number yes Event timestamp in milliseconds relative to the browser sampling window
stack_state.stack array yes VM stack output as unsigned 32-bit values
stack_state.ip number yes VM instruction pointer as an unsigned 16-bit value
fingerprint.aspectRatio string yes Screen aspect ratio; server accepts numeric strings in range 0.5..=3.0
fingerprint.devicePixelRatio string yes Device pixel ratio; server accepts numeric strings in range (0, 5]
fingerprint.hardwareConcurrency number yes Positive hardware concurrency value
mutation_step number yes Mutation step currently expected by the server
gene_commitment string yes Context-bound commitment produced by the WASM mutation preview
signature string yes Ed25519 signature over the canonical payload

Canonical Signing Payload

The signature covers a canonical JSON object with sorted top-level keys:

{
  "entropyData": { "events": [{ "t": 1234.567, "x": 412.0, "y": 308.5 }] },
  "fingerprint": {
    "aspectRatio": "1.7777777778",
    "devicePixelRatio": "2",
    "hardwareConcurrency": 8
  },
  "geneCommitment": "64-char hex",
  "mutationStep": 1,
  "prevHash": "64-char hex",
  "sessionId": "64-char hex",
  "stackState": { "ip": 42, "stack": [2971406957, 1234567890] },
  "timestamp": 1234567890123
}

Important details:

  • The transport payload uses snake_case for several fields.
  • The signed payload uses camelCase names.
  • Top-level keys must be serialized deterministically in lexical order.
  • The signature field is not part of the signed payload.
  • Nested serialization must match the server's serde_json representation.

The server reconstructs the canonical message from the received request before verifying the Ed25519 signature.

Accepted Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "status": "ok",
  "next_salt": "32-char hex string",
  "next_mutation_step": 2,
  "next_mutation_order_b64": "base64-encoded mutation program"
}
Field Type Description
status string Always ok
next_salt string Server salt for the next heartbeat
next_mutation_step number Mutation step expected on the next heartbeat
next_mutation_order_b64 string Server-authored mutation order for the next heartbeat

Clients should treat the heartbeat as accepted only when all next-state fields are present.

Rejected Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "status": "ok"
}

Rejected heartbeats omit:

  • next_salt
  • next_mutation_step
  • next_mutation_order_b64

This response shape is intentional. The server does not reveal which validation stage failed.

Heartbeat Validation Order

The server currently validates heartbeats in this order:

  1. Rate-limit check in the route handler.
  2. Load session by session_id.
  3. Check session expiration.
  4. Verify Ed25519 signature.
  5. Compare prev_hash with stored last_hash.
  6. Compare mutation_step with stored pending_mutation_step.
  7. Apply stored pending mutation to a cloned gene state.
  8. Compare expected and submitted gene_commitment.
  9. Enforce timestamp drift.
  10. Validate mouse entropy.
  11. Validate fingerprint fields.
  12. Compute next hash-chain head.
  13. Generate next mutation order and salt.
  14. Persist advanced session state.

Any failure after route-level JSON decoding returns the silent rejection body.

GET /health

Returns a basic health response.

GET /health
{
  "status": "healthy"
}

GET /stats

Returns storage-derived session statistics.

GET /stats
{
  "sessions": 1,
  "expired_sessions": 0,
  "max_chain_length": 4
}
Field Type Description
sessions number Stored session count
expired_sessions number Expired sessions not yet purged
max_chain_length number Highest stored heartbeat chain length

GET /metrics

Returns Prometheus-compatible text.

GET /metrics
# HELP chronoseal_sessions Active ChronoSeal sessions
# TYPE chronoseal_sessions gauge
chronoseal_sessions 1
# HELP chronoseal_expired_sessions Expired sessions not yet removed
# TYPE chronoseal_expired_sessions gauge
chronoseal_expired_sessions 0
# HELP chronoseal_max_chain_length Maximum heartbeat chain length
# TYPE chronoseal_max_chain_length gauge
chronoseal_max_chain_length 4

Client State Rules

After /init, the client stores:

  • session_id
  • initial_hash as the first prev_hash
  • current salt
  • VM opcode program
  • committed gene state
  • pending mutation step
  • pending mutation order

On accepted /hb:

  1. Commit the local gene preview.
  2. Compute the next local hash using the old salt that was active when the heartbeat was sent.
  3. Replace current salt with next_salt.
  4. Replace pending mutation step and order with server-provided values.

On rejected /hb:

  1. Discard the local gene preview.
  2. Do not advance hash-chain state.
  3. Do not advance mutation state.
  4. Treat the session as suspect or restart attestation.

WASM Runtime Exports

The generated chronoseal_wasm package exposes:

Function Signature Description
generate_keypair() () -> string Generate an Ed25519 keypair and return public key hex
get_public_key() () -> string Return current public key hex, or "" if no keypair exists
sign_message(msg) (string) -> string Sign a UTF-8 payload and return hex signature, or "" on failure
compute_next_hash(prev, ts, entropy, stack, salt) (string, u64, string, string, string) -> string Compute next Blake3 chain hash
run_program(b64) (string) -> JsValue Execute a base64 VM program and return stack state
init_gene_state(gene_size) (u32) -> bool Initialize the browser gene state
preview_gene_commitment(order_b64, session_id, mutation_step, rounds) (string, string, u64, u8) -> string Preview next mutation commitment
commit_gene_preview() () -> bool Commit the preview after accepted heartbeat
discard_gene_preview() () -> void Discard preview after rejection or error
current_gene_commitment(session_id, mutation_step) (string, u64) -> string Return current committed gene commitment

String-returning functions use "" to signal failure. Callers must handle empty strings explicitly.