# Network Security and Tokens The genesis network has three orthogonal layers of cryptographic enforcement: 1. **Identity** — every peer has a stable Ed25519 identity. Every message is signed. 2. **Authority** — server-signed tokens grant a peer the right to do specific things in a specific mesh/session. 3. **Trust** — cross-mesh interactions require a `MeshTrustToken` that establishes one mesh's willingness to accept envelopes from another. This document is the reference for all three. ## Layer 1 — Message-level integrity (NET-27, NET-30) `network-plugin-crypto-messages` is the layer. ### Per-message Ed25519 signatures (NET-27) Every outbound `MessageEnvelope` from a host (Tier 0 or Tier 1) carries an Ed25519 signature in its headers. Inbound signatures are verified using peer public keys from the registry. Invalid signatures cause the message to be **dropped silently** (and the sender's reputation in `HostHistory` to take a hit). The key material is the same drive-identity key used by the chunks plugin — one Ed25519 keypair per peer, used at multiple layers. Generated and stored by `@suaveplan/crypto-vault` (BIP39 mnemonic + Argon2id KDF + zeroize on lock). ### Peer identity challenge-response (NET-30) When two peers handshake, they perform a challenge-response to verify identity: ```text A → B: peerA_pubkey, nonceA B → A: peerB_pubkey, nonceB, sigB(peerA_pubkey ‖ nonceA) A → B: sigA(peerB_pubkey ‖ nonceB) ``` Any peer claiming `peerB_pubkey` who can't produce `sigB(...)` is rejected. This catches spoofed peer-IDs at handshake before they make it into the registry. ## Layer 2 — Authority tokens (NET-28, NET-29, NET-106..NET-109) Three token shapes, all server-signed (in models with a server): ### `MeshToken` (NET-29) ```ts interface MeshToken { meshId: string; maxCapacity: number; allowedTiers: ('tier-0' | 'tier-1' | 'tier-2')[]; hostingModel: 'PURE_CLIENT' | 'SERVER_BASED' | 'SERVER_TO_CLIENT_FAILOVER' | 'CLIENT_WITH_SERVER_BACKUP'; expiresAt: number; serverSignature: Uint8Array; // Ed25519 over canonicalSerialize(this without the sig) } ``` Required for mesh creation. The mesh's hosting model lives here. Long expiry (days/weeks). ### `SessionToken` (NET-28) ```ts interface SessionToken { sessionId: string; parentSessionId: string | null; capacity: number; rulesHash: string; // hash of the session's policy doc expiresAt: number; serverSignature: Uint8Array; } ``` Required for session creation. Sessions can nest (NET-19) up to depth 4. The `rulesHash` pins the session's policy at issuance time so it can't be silently mutated. ### `CapabilityToken` (NET-108, NET-109) ```ts interface CapabilityToken { peerId: string; meshId: string; tier: 'tier-0' | 'tier-1' | 'tier-2'; capabilities: string[]; // e.g. ['relay', 'vote', 'admit-peer'] issuedAt: number; expiresAt: number; serverSignature: Uint8Array; } ``` Issued when a peer joins. The `capabilities` array constrains what the peer is *authorised* to do regardless of what the protocol allows it to *attempt*. A Tier-0 capability token includes `admit-peer`; a Tier-2 doesn't. Cross-tier escalation is blocked at the verifier (NET-48). `network-plugin-auth` (NET-106..NET-109) is the enforcement plugin. `MeshMembershipVerifier` checks the `authToken` on join against `@suaveplan/auth`. `CapabilityTokenIssuer` mints them. `CrossMeshTrustValidator` (NET-110..NET-112) handles inter-mesh acceptance. ### Tier-specific security policies (NET-48) ```text Tier 0 — full authority. Can issue tokens (when server isn't available, with grace-period restrictions). Tier 1 — relay + voting authority. Cannot issue tokens. Tier 2 — read-only for sensitive operations. ``` `SecurityManager.processTierSecurity(tierId, operation, data)` enforces this on every operation. Cross-tier delegation requires explicit credential transfer from the higher tier. ## Layer 3 — Cross-mesh trust (NET-110..NET-112) `MeshTrustToken` is what one mesh hands another mesh to say "I'll accept your relay traffic": ```ts interface MeshTrustToken { fromMeshId: string; toMeshId: string; allowedOperations: string[]; // e.g. ['relay-message', 'cd:request'] bandwidthQuotaPerHour?: number; expiresAt: number; bothServerSignatures: [Uint8Array, Uint8Array]; // signed by both meshes' Tier 0 } ``` `CrossMeshTrustValidator` rejects relay envelopes from untrusted mesh ids (NET-110). Tier 0 hosts verify trust tokens before accepting backbone connections (NET-112). Trust decisions are cached with configurable TTL (NET-111) so we don't re-verify on every envelope. This means a phone-mesh and a corporate-mesh don't automatically interoperate. Two Tier 0 hosts must explicitly establish trust (out of band: typically via a co-signed token issued by both servers, or via a bilateral capability exchange in `PURE_CLIENT` mode). ## Plugin security verifier (NET-47) `network-plugin-crypto-messages` also validates plugins themselves: ```ts class PluginSecurityVerifier { verifyPlugin(pluginId: string, pluginData: Uint8Array): Promise; authorizePluginOperation(pluginId, operation, context?): Promise; monitorPluginActivity(pluginId): void; setPluginSecurityPolicy(policy): void; } ``` The intent is plugin-code signing: a deployment may want to allow only plugins signed by a known publisher key. Plugins requesting capabilities they didn't declare are rejected. Anomalous plugin activity (excessive broadcast, unauthorised operations) is detected and reported. The old planning corpus admits (`PHASE_6_README.md`) that the resource-monitoring side of this is "currently simulated and would need real metrics in a production environment." Genesis treats it as a hardening backlog item — install the plugin, get signature verification today; resource accounting follows. ## What about the model where the server is gone? Tokens issued before the server vanished remain valid until their `expiresAt`. `network-plugin-server-bridge` (NET-32) extends grace periods so existing tokens don't expire mid-outage. New tokens cannot be issued — operations that require a fresh token (admit a brand-new peer, create a new session) are queued until the server returns. Existing peers, with valid `CapabilityToken`s, keep operating with full authority. When the server returns: 1. Buffered signed-log entries replay (NET-33). 2. The server validates each entry's Ed25519 signature against the issuing peer's pubkey. 3. Conflicts are detected (e.g., two peers both claimed Tier-0 in different partitions). Resolution depends on the partition merge strategy (NET-80). 4. The server broadcasts the reconciled state. 5. Queued token-issuance operations execute. The cryptographic chain — every message signed, every token signed, every audit-log entry signed — is what makes this replay possible. There's no ambiguity about who did what; every action is provenance-stamped. ## Audit log (NET-37..NET-39) `network-plugin-audit-mesh` keeps an append-only log where each entry includes: ```text { seq, prevHash, payload, hostSignature } ``` - `seq` is monotonic. - `prevHash` makes the log a hash chain — break detection on any tampering. - `hostSignature` is the issuing host's Ed25519 over `(seq, prevHash, payload)`. Logs are replicated to at least R sibling hosts (NET-38). CRITICAL events replicate synchronously. Old logs are compacted into signed checkpoints (NET-39) — a snapshot at a given seq, signed by the host, that downstream replicas use to skip the prefix. This is what gives you a verifiable audit trail across the entire mesh, surviving partitions and server outages. ## Where keys live, end to end | Key | Owner | Storage | Used for | | --- | --- | --- | --- | | Per-peer Ed25519 (drive identity) | The peer | `@suaveplan/crypto-vault` | Signing every message, every chunk, every audit entry | | Per-mesh server Ed25519 | Central server | Server HSM / `@suaveplan/keys` (when available) | Signing `MeshToken`, `SessionToken`, `CapabilityToken` | | Cross-mesh trust signing | Both meshes' servers | As above | Co-signing `MeshTrustToken` | | Per-file `fileKey` (AEAD) | Drive | Wrapped by partition KEK; lives next to manifest | Encrypting chunks | | Per-partition KEK | `drive-sharing` | Wrapped per-grantee with X25519 sealed-box | Wrapping `fileKey`s | Keys never cross trust boundaries unwrapped. Wrapping is the only mechanism for delegation. ## Reading further - [`architecture.md`](./architecture.md) — `MessageEnvelope` and `NetworkBus`. - [`topology-and-failover.md`](./topology-and-failover.md) — when token issuance is paused. - [`offline-and-reintegration.md`](./offline-and-reintegration.md) — buffered log replay. - [`../drive/encryption.md`](../drive/encryption.md) — the drive layer's use of the per-peer Ed25519 key.