Version: v0.2.0-draft (Work in Progress)
Note
This document represents the official technical specification of the Handshake protocol. It defines message schemas, cryptographic identity, sovereign storage models, and wire protocols to ensure interoperability across heterogeneous clients (web frontends, native daemons, and mobile implementations). For core conceptual principles and non-negotiable architectural pillars, see Architectural Invariants.
The protocol does not implement "user accounts", "registrations", or "profiles". Identity in Handshake is purely cryptographic, decentralized, and message-signature oriented:
- Ed25519 Keypairs: Every node or author uses an Ed25519 asymmetric keypair:
- Private Key (SK): Local secret to digitally sign published messages. Stored strictly in client storage.
- Public Key (PK): Author identifier (
author_pk) used by the P2P swarm to verify message integrity and authenticity, ensuring it was not tampered with during transport.
- Optional Pseudonymity: Users can reuse keypairs for author consistency or generate ephemeral keys for isolated messages. The protocol does not link names, emails, or personal data to any key.
To enable sovereign import and export of keys between clients without server dependency:
{
"public_key": "hexadecimal_public_key_64_characters",
"private_key": "hexadecimal_private_seed_64_characters"
}Standardized on a 32-byte private seed (64 hexadecimal characters).
All messages on the network are public, open, and immutable. They are serialized and transmitted using strict JSON formatting. The schema consists of three primary blocks: header (cryptographic identity and thread graph), anchor (constitutive space-time anchor), and content (payload).
{
"version": "1.0",
"header": {
"author_pk": "hex_public_key_32_bytes",
"parent_signature": "hex_parent_signature_64_bytes_optional",
"signature": "hex_signature_64_bytes"
},
"anchor": {
"timestamp": 1712345678,
"geohash": "dr5reg6",
"coordinates": {
"lat": 40.712776,
"lon": -74.005974
},
"proof": {
"type": "GPS",
"data": "40.712776,-74.005974"
}
},
"content": {
"text": "Space-time anchored graffiti content text",
"attachments": [
{
"url": "https://example.com/audio.ogg",
"sha256": "sha256_hex_hash_64_characters",
"mime_type": "audio/ogg"
}
]
}
}header.author_pk(String, Required): 64-character hexadecimal representation of the author's 32-byte Ed25519 public key. Nodes MUST verify that it decodes to exactly 32 bytes and represents a valid Ed25519 curve point.header.parent_signature(String | null, Optional): 128-character hexadecimal string representing the Ed25519 signature of the parent message being replied to (nullif initiating a new root conversation). Nodes use this field to construct conversation trees without enforcing that author or location match the parent message.header.signature(String, Required): 128-character hexadecimal Ed25519 signature computed over the canonical serialized JSON payload (RFC 8785) excluding this field itself.anchor.timestamp(Integer, Required): 64-bit signed integer UNIX timestamp (seconds). Validation Rule: Nodes and trackers MUST NOT reject messages based on clock skew or future/past offsets (declarative time). Validity is governed solely by cryptographic signature integrity over the canonical payload.anchor.geohash(String, Required): Canonical Geohash string (precision 6 or 7) derived from coordinates. Nodes MUST verify thatanchor.geohashmatches the geographic bounds ofanchor.coordinates.anchor.coordinates(Object, Required): High-precision geographical coordinates containinglat(Float between-90.0and+90.0) andlon(Float between-180.0and+180.0). In both root messages and conversation replies, coordinates are sovereign and declarative (replies are not required to share the parent's coordinates).anchor.proof(Object, Optional): Cryptographic co-presence or spatial proof (type:"GPS","WITNESS_SWARM", or"NONE").content.text(String, Required): UTF-8 message text content (plain text or lightweight markdown).content.attachments(Array of Objects, Optional): List of linked multimedia attachments. Each item MUST containurl(String),sha256(64-character hex hash for cryptographic integrity verification), andmime_type(String).
To generate or verify the Ed25519 signature:
- Take the message JSON object excluding the
header.signaturefield. - Recursively sort all object keys in lexicographical (Unicode code point) order following the JSON Canonicalization Scheme (RFC 8785).
- Compactify the normalized JSON string without superfluous whitespace, encode as UTF-8, and sign/verify with the Ed25519 keypair.
- Strict Closed Schema (Zero Smuggling): To prevent payload smuggling, trojan data carriers, tracking tokens, and botnet command injection, nodes enforce strict closed-schema validation under
version: "1.0". Any message containing unrecognized fields at the root or within sub-objects is malformed and must be immediately rejected and discarded. - Hard Message Size Limit: The maximum allowable size for a serialized canonical message is 64 KB. Messages exceeding this threshold are dropped at the transport boundary before signature parsing or cryptographic verification, preventing denial-of-service (DoS) and local storage bloat attacks.
- Signature Immutability: Modifying, omitting, or reordering any field invalidates the original Ed25519 signature.
- Protocol Evolution: Future extensions and additions require an explicit protocol version increment (e.g.
version: "1.1"or"2.0").
The Space-Time Tracker serves exclusively as an ephemeral matchmaking and signaling coordinator. It maintains no centralized persistence of messages or user accounts; it connects peers exploring the same spatial swarm cell (Geohash precision 5, approx. 4.9 km × 4.9 km) to negotiate direct peer-to-peer transport.
Endpoint: ws://<host>:<port>/ws/tracker/
Sent by the client upon connecting or moving to a new spatial cell. Requires cryptographic authentication using the client's Ed25519 private key to prove key ownership and prevent peer impersonation, spoofing, and MITM signaling hijacking:
{
"type": "register",
"peer_id": "7b8a1c...64_hex_author_pubkey",
"geohash": "69y7pg3",
"timestamp": 1712345678,
"signature": "3f9c4a...128_hex_signature"
}To prove ownership of peer_id, the client signs the following deterministic ASCII string with its Ed25519 private key:
REGISTER:<peer_id>:<geohash>:<timestamp>
The tracker server verifies:
-
peer_idis a 32-byte Ed25519 public key in hexadecimal format (64 characters). -
timestampis within an acceptable skew window ($\pm 120$ seconds) of server time to prevent replay attacks. -
signatureis a valid detached Ed25519 signature of the challenge string for thatpeer_id.
If authentication succeeds, the tracker registers or updates the peer in its active peer registry. If authentication fails or fields are missing/expired, the tracker returns an error payload and discards the registration:
{
"type": "error",
"code": "AUTH_FAILED",
"message": "Invalid registration signature or expired timestamp"
}Sent by the Tracker back to the registering client containing all active peers in the matching spatial swarm cell (Geohash precision 5):
{
"type": "peer_list",
"peers": [
{ "peer_id": "peer_abc123", "geohash": "69y7pba" },
{ "peer_id": "peer_xyz789", "geohash": "69y7pff" }
]
}Broadcast by the Tracker to all active peers in the same spatial room when a peer enters or leaves:
// Peer entered
{
"type": "peer_joined",
"peer_id": "peer_abc123",
"geohash": "69y7pba"
}
// Peer departed
{
"type": "peer_left",
"peer_id": "peer_abc123"
}Relayed transparently as an opaque payload through the Tracker to negotiate direct P2P transport between peers (using standard WebRTC SDP offer/answer and ICE candidate schemas as the reference standard for browser swarms):
// SDP Offer / Answer
{
"type": "signal",
"target": "target_peer_id",
"signal": {
"sdp": {
"type": "offer", // or "answer"
"sdp": "v=0\r\no=- ..."
}
}
}
// ICE Candidate
{
"type": "signal",
"target": "target_peer_id",
"signal": {
"candidate": {
"candidate": "candidate:1 1 UDP ...",
"sdpMid": "0",
"sdpMLineIndex": 0
}
}
}Once a direct peer connection is established (e.g. over a WebRTC RTCDataChannel labeled "handshake-sync" in browser swarms, or local transport in proximity encounters), data exchange is demand-driven and governed by inventory negotiation.
Upon channel opening (onopen) or when a peer's viewport changes, the initiating client sends an inventory of known message signatures for its current spatial cell:
{
"type": "inventory",
"geohash": "69y7p",
"signatures": [
"3f9c4a...signature1",
"a1b2c3...signature2"
]
}The receiving peer compares the inventory against its local storage and requests only signatures it does not possess:
{
"type": "request_missing",
"signatures": [
"3f9c4a...signature1"
]
}Sent in response to request_missing (delivering only requested messages), or broadcast across active peers when a new message is published locally:
{
"type": "sync_response",
"messages": [
{
"version": "1.0",
"header": {
"author_pk": "7b8a1c...",
"parent_signature": null,
"signature": "3f9c4a..."
},
"anchor": {
"timestamp": 1787928000,
"geohash": "69y7pg3",
"coordinates": { "lat": -34.6037, "lon": -58.3816 }
},
"content": {
"text": "Meeting at the obelisk next Sunday at 18:00!"
}
}
]
}When a peer receives a sync_response:
- Size Boundary Check: Discards immediately any message payload exceeding the hard limit of 64 KB before parsing.
- Strict Schema Check: Verifies that the JSON strictly contains the core triad (
header,anchor,content) without unauthorized fields. - Canonical Reconstruction: Reconstructs the canonical JSON payload (excluding
header.signature) according to RFC 8785. - Signature Verification: Verifies the detached Ed25519 signature against
header.author_pk. - Storage Ingestion: If valid, ingests the message into sovereign local storage and updates visual views. Untrusted, malformed, or tampered messages are immediately discarded.
Messages are grouped into spatial cells and temporal epochs:
- Spatial Resolution: Territory is partitioned into spatial cells using Geohash precision 6 or 7 (approx. ~1.2 km to ~150 meters).
-
Temporal Resolution: Time is partitioned into monthly epochs in
YYYY-MMformat. -
InfoHash Generation: A deterministic SHA-1 identifier is computed for the swarm:
$$\text{InfoHash} = \text{SHA1}(\text{geohash} + ":" + \text{epoch})$$ -
Collective Seeding: Peer connections exchange messages belonging to the given
InfoHash, persisting them in local sovereign storage. - Historical Custody: Nodes can seed both current, past, and future epochs stored locally, acting as custodians of spatial-temporal memory.
Clients maintain sovereign local-first storage. The protocol is strictly agnostic of concrete storage engines (whether implemented via IndexedDB, SQLite, DuckDB, or key-value stores), but mandates the essential logical data model, query capabilities, and local metabolism (eviction) rules.
Every compliant client implementation MUST locally persist messages with the following logical properties:
- Unique Message Identifier: The Ed25519
header.signatureserves as the primary unique key. - Author Identity: The author's public key (
header.author_pk). - Thread Link: The optional parent message signature (
header.parent_signature). - Space-Time Anchor:
- Geohash spatial index (
anchor.geohash). - High-precision spatial coordinates (
anchor.coordinates.lat,anchor.coordinates.lon). - Temporal coordinate UNIX epoch (
anchor.timestamp).
- Geohash spatial index (
- Payload Content:
- Textual payload (
content.text). - Optional multimedia attachments.
- Textual payload (
- Canonical Wire Payload: Preserved verbatim for zero-trust relaying and P2P re-seeding without re-encoding.
- Storage Custody Flags:
- User pin flag (
is_pinned), set explicitly by the sovereign user.
- User pin flag (
Clients maintain a sovereign local store of trusted public keys to grant storage immunity:
public_key: Ed25519 public key of the trusted contact.alias: Locally assigned nickname.added_at: UNIX timestamp when trust was established (e.g. via direct in-person QR exchange or BLE proximity).
To participate in spatial discovery and conversation threads, client storage engines MUST support:
- Spatial-Temporal Range Queries: Efficient filtering of messages within a spatial cell (matching geohash prefix) and a time interval (
start_timestamptoend_timestamp). - Genealogical Traversal: Direct lookup by
header.signatureand child lookup byheader.parent_signatureto assemble conversational trees.
Nodes operate within finite local storage budgets. When storage thresholds are exceeded, the client executes an automated metabolism policy:
- Eviction Precedence: Messages are evicted in order of oldest
anchor.timestampfirst (FIFO). - Storage Immunity: Messages are strictly IMMUNE to automated eviction if:
- The message is explicitly pinned by the user (
is_pinned = true), OR - The message author's public key exists in the client's local
trusted_handshakesstore.
- The message is explicitly pinned by the user (
- Parent Linking (
parent_signature): Replying to a message includes the parent message's Ed25519 signature in the header. - Sovereign & Itinerant Replies: Every reply is a sovereign space-time trace carrying its own declarative coordinates. An author may anchor a reply at the exact same location as the parent message, at their own physical location (tracing an itinerant physical path across the map), or at any arbitrary coordinates chosen across space.
- Decentralized Tree Reconstruction: The client connects messages and reconstructs the thread tree locally using cryptographic signatures. If a node lacks a parent message, it can request it with priority from swarm peers.