# HexaEight — Full API Reference (AI-readable mirror) > This is the flat-text mirror of https://hexaeight.com/docs intended for AI agents, > retrieval pipelines, and any tool that prefers a single plain-text file over HTML. > For the rendered version with navigation, visit /docs. Last updated: 2026-06-06. Reference Bridge version: 1.0.0-preview9. SUPPORTED MESSAGING MODE: Sessioned envelopes (Variant B). Two parties agree on a sessionId out of band, each fetches their half of the ASK pair for the other, pins it to the session, and exchanges ciphertext addressed by session hash. The recipient gets the sender's identity via the cryptographically verified Sender field on DecryptedEnvelope. Anonymous-sender mode is in the API surface but not yet recommended for production round-trips — coming soon. --- ## TABLE OF CONTENTS 1. Overview 2. Three-layer architecture 3. SDK status matrix 4. Identity setup 5. Quickstart (.NET + Node, sessioned round-trip) 6. Concept: Envelopes 7. Concept: ASK (Asymmetric Shared Keys) 8. Concept: KGT (Key Generation Time) 9. Wire format specification 10. Bridge API reference — every method 11. Bridge API reference — records and enums 12. Error semantics 13. Performance characteristics 14. Cross-language SDK naming map 15. Guides — agent-to-agent, sessioned, cache-persist 16. License 17. Contact --- ## 1. OVERVIEW HexaEight is a quantum-resistant, password-based asymmetric encryption system. Each identity has a different password (never shared). The platform mediates key derivation but is mathematically unable to decrypt any message — only password holders can. Patent filed July 2021. The HexaEight.Bridge .NET package is the canonical SDK. All other language SDKs (Node, Python, Browser) wrap it through their language's CoreCLR hosting layer (node-api-dotnet, pythonnet, etc.) so the API surface is identical across languages. --- ## 2. THREE-LAYER ARCHITECTURE Layer 0 — Crypto. HexaEight.Bridge (.NET). Identity, ASK derivation, envelope encrypt/decrypt. Layer 1 — Transport. Per-language SDK. HTTP, ntfy, webhooks, MQ — how the envelope reaches its destination. Layer 2 — Application. Your code. Storage policy, sender abstractions, deny-lists, app logic. The cryptographic core is identical in every language. Only Layer 1 and Layer 2 are language-specific. --- ## 3. SDK STATUS MATRIX SDK Package Status ---------- --------------------------- -------------------------------- .NET HexaEight.Bridge (NuGet) preview9 — shipping Node.js @hexaeight/sdk (npm) wrapper update in progress Python hexaeight-sdk (PyPI) in progress Browser WASM via Bridge planned --- ## 4. IDENTITY SETUP You receive these files when you buy a HexaEight identity license: env-file Plain text. Four variables: HEXAEIGHT_LICENSECODE= HEXAEIGHT_MACHINETOKEN= HEXAEIGHT_RESOURCENAME= HEXAEIGHT_SECRET= hexaeight.mac Binary. Machine-bound. Must be HARD-LINKED into your project directory (not copied — the kernel-level link is part of the binding check). hexaeightkeys.db (Azure Marketplace mode only) — SQLite. The Bridge reads settings.logintoken from this instead of the env-file when it detects this file in the CWD. Bridge identity load order (first hit wins): 1. hexaeightkeys.db in CWD (Azure mode) 2. HEXAEIGHT_MACHINETOKEN env variable (non-Azure runtime) 3. env-file in CWD with HEXAEIGHT_MACHINETOKEN=… line (non-Azure dev/CI) The Bridge is READ-ONLY with respect to your environment — it never sets or modifies environment variables on your behalf. --- ## 5. QUICKSTART — TWO-PARTY SESSIONED ROUND-TRIP Two HexaEight identities (Alice and Bob), each loaded in its own working directory. Both already know each other's Name (the HEXAEIGHT_RESOURCENAME). ### .NET dotnet add package HexaEight.Bridge --prerelease using HexaEight.Bridge; // ── Alice (sender) ────────────────────────────────────────────── var alice = new Client(); string bobName = "bob.example.com"; string sessionId = Guid.NewGuid().ToString(); long kgt = CurrentKgt(); string askForBob = await alice.FetchAskAsync(bobName, kgt); alice.PinAskForSession(sessionId, askForBob); string envelope = await alice.EncryptEnvelopeAsync( recipient: bobName, body: "Hello Bob!", sessionId: sessionId); // hand `envelope` and `sessionId` to Bob over any transport // ── Bob (recipient) ───────────────────────────────────────────── var bob = new Client(); string aliceName = "alice.example.com"; string askForAlice = await bob.FetchAskAsync(aliceName, kgt); // Bob's half bob.PinAskForSession(sessionId, askForAlice); DecryptedEnvelope msg = await bob.DecryptEnvelopeAsync(envelope); // msg.Sender == "alice.example.com" (cryptographically verified, NOT from wire) // msg.Body == "Hello Bob!" // msg.FromSession == true static long CurrentKgt() { long m = (long)(DateTime.UtcNow - DateTime.UnixEpoch).TotalMinutes; return m - (m % 15); } ### Node.js npm install @hexaeight/sdk@preview import { HexaEight } from '@hexaeight/sdk'; const alice = await HexaEight.connect(); const sessionId = crypto.randomUUID(); const kgt = currentKgt(); const ask = await alice.ask.fetch('bob.example.com', kgt); alice.ask.pinForSession(sessionId, ask); const env = await alice.envelope.encrypt('bob.example.com', 'Hello Bob!', { sessionId }); // On Bob's machine const bob = await HexaEight.connect(); const askB = await bob.ask.fetch('alice.example.com', kgt); bob.ask.pinForSession(sessionId, askB); const msg = await bob.envelope.decrypt(env); console.log(msg.sender, msg.body); // "alice.example.com" "Hello Bob!" --- ## 6. CONCEPT — ENVELOPES ### Variant B — Sessioned (SUPPORTED) hsha:{sha256(sessionId)}|{ciphertext} hsha: Literal 5-byte prefix (ASCII). sessionHash SHA-256 of session identifier, lowercase hex, exactly 64 chars. ciphertext MQ-V4 ciphertext, Base64URL. Sender identity is NOT on the wire. The recipient learns the sender via the cryptographically asserted Sender field inside the encrypted JSON, exposed as DecryptedEnvelope.Sender. ### Variant A — Standard (PREVIEW, not recommended) {sourceId}|{kgt}|{ciphertext} sourceId Sender's login-token prefix. Implementation-dependent length. kgt Unix minute floored to nearest 15. int64. ciphertext MQ-V4 ciphertext, Base64URL. Variant A is in the wire format but not yet recommended for production round-trips — sourceId depends on the sender's login-token format. Anonymous-sender mode (no inner sender claim, sender genuinely unknown to the recipient) is planned. For now, use Variant B. ### Variant detection if envelope.startsWith("hsha:"): parse as Variant B else: parse as Variant A ### Inspection without decryption Client.InspectEnvelope (static method) parses public fields only: var inspected = Client.InspectEnvelope(envelope); if (inspected.Kind == EnvelopeKind.Sessioned) { // inspected.SessionHash (64 hex chars) } else { // inspected.SourceId, inspected.Kgt } --- ## 7. CONCEPT — ASK (ASYMMETRIC SHARED KEYS) ASK is the cryptographic primitive. The platform issues two complementary halves — one to each party. Anyone with a HexaEight identity can ask for "the ASK that lets me talk to " and receive their half. The recipient asks the platform for their own complementary half. Inversion of classical PKI: Classical: Alice needs Bob's public key BEFORE encrypting. HexaEight: Alice asks platform for "the ASK that lets me talk to Bob." Done. Why the platform cannot decrypt: - Platform combines each party's password (which it does NOT store cleartext and CANNOT reverse) with SHAKE-256-derived material. - Output is two halves of a shared secret. - Platform sees the derivation inputs but never the underlying password. - SHAKE-256 is one-way. Cache shape (two-way indexed): - By (recipient, kgt) for direct peer lookups. - By sha256(sessionId) for Sessioned envelopes. - Pinning marks an entry as preferred so cache pressure cannot evict it. --- ## 8. CONCEPT — KGT (KEY GENERATION TIME) long nowMinutes = (long)(DateTime.UtcNow - DateTime.UnixEpoch).TotalMinutes; long kgt = nowMinutes - (nowMinutes % 15); 15-minute window. Three purposes: - Clock skew tolerance (<15 min skew → same KGT). - Natural key rotation (leaked ASK only useful within its window). - Replay window (receivers can reject too-old envelopes). Override by passing kgt explicitly to EncryptEnvelopeAsync or FetchAskAsync. --- ## 9. WIRE FORMAT SPECIFICATION (v1) ### Encoding rules - UTF-8 string. ASCII for the routing portion. Base64URL for ciphertext. - No leading/trailing whitespace. Decoder MUST reject if present. - No quoting, no escaping. No '\n', '\r', or NUL anywhere in the envelope. - Length is unbounded. Practical ceiling ~333 MB envelope (~250 MB plaintext × 1.49 ratio). ### Reference parser (pseudocode) function parse(envelope): if length < 6: error if envelope.startsWith("hsha:"): rest = envelope[5:] pipe = rest.indexOf("|") if pipe != 64: error return Sessioned(sessionHash=rest[0:64], ciphertext=base64UrlDecode(rest[65:])) else: p1 = envelope.indexOf("|") p2 = envelope.indexOf("|", p1+1) if p1 < 1 or p2 < p1+2: error return Standard( sourceId=envelope[0:p1], kgt=parseInt(envelope[p1+1:p2]), ciphertext=base64UrlDecode(envelope[p2+1:]) ) ### Ciphertext internal layout Offset 0: 2 bytes Version tag (V3 or V39 mode flag) Offset 2: 32 bytes HMAC-SHA256 integrity tag Offset 34: n bytes Encrypted block stream Inside the decrypted ciphertext is a JSON object with at minimum SENDER, RECEIVER, BODY. The Bridge surfaces SENDER as DecryptedEnvelope.Sender — cryptographically verified. ### Conformance for new SDK implementations 1. Encrypt a Variant B envelope decryptable by the .NET Bridge given matching session. 2. Decrypt a Variant B envelope from the .NET Bridge given matching session. 3. Surface SENDER from inside the encrypted JSON as a top-level field. 4. Reject envelopes with leading/trailing whitespace, NULs, embedded newlines, or unknown variant prefixes. --- ## 10. BRIDGE API REFERENCE — EVERY METHOD Namespace: HexaEight.Bridge Class: Client ### Constructor new Client() Loads identity from env-file + hexaeight.mac (or hexaeightkeys.db on Azure). Authenticates to the platform. ### Identity properties string Name The HEXAEIGHT_RESOURCENAME (e.g. agent01.yourdomain.com). This is the value other parties pass as `recipient`. static string BridgeVersion Bridge NuGet version (e.g. "1.0.0-preview9"). static string TargetFramework ".NETCoreApp,Version=v8.0" | "v9.0" | "v10.0". ### Envelope encryption Task EncryptEnvelopeAsync( string recipient, string body, long? kgt = null, string? pinAsk = null, string? sessionId = null) Encrypts a string body into a single envelope string. recipient Required. Recipient's Name. body Required. UTF-8 plaintext. Tested to 250 MB. kgt Optional. Override the KGT. Default: current 15-min window. pinAsk Optional. Use a specific pre-fetched ASK. sessionId Optional. If set, emits Variant B and caches ASK under sha256(sessionId). USE THIS — Sessioned is the supported mode. Returns: envelope string, or empty string on failure. Task DecryptEnvelopeAsync(string envelope, string? pinAsk = null) Auto-detects variant by "hsha:" prefix. Returns DecryptedEnvelope. static InspectedEnvelope InspectEnvelope(string envelope) Parses public metadata without decrypting. For deny-list filtering. ### ASK cache Task FetchAskAsync(string recipient, long? kgt = null) Cache hit returns cached. Miss triggers platform fetch and caches as non-pinned. void PinAsk(string recipient, long kgt, string ask) Marks the (recipient, kgt) cache entry as pinned (3 args — ask required). void PinAskForSession(string sessionId, string ask) Marks the session cache entry as pinned. void UnpinAsk(string recipient, long kgt) Removes the cache entry for (recipient, kgt). (kgt required.) void UnpinAskForSession(string sessionId) Removes the cache entry for sha256(sessionId). bool HasCachedAsk(string recipient, long kgt) Test cache presence without fetching. bool HasCachedSession(string sessionId) Test cache presence without fetching. void ClearAskCache() Wipe entire cache (both recipient-keyed and session-keyed). No args. ### Persistence Task SaveAskCacheToDiskAsync(string filePath) Serialize cache to JSON file. Contains ASK material in plaintext — protect with chmod 600 / restricted ACLs. Task LoadAskCacheFromDiskAsync(string filePath) MERGES entries into in-memory cache (does NOT overwrite). Call ClearAskCache() first if you want a clean load. Throws FileNotFoundException if missing. Task EnableAutoPersistAsync(string filePath, bool loadIfExists = true) Every cache mutation triggers a 2-second-debounced async write to filePath. If loadIfExists is true and file exists, loads it synchronously first. void DisableAutoPersist() Performs final synchronous flush and stops auto-writes. ### Lower-level methods (protocol integration) Task FetchSharedKeyDirectAsync(string recipient, long kgt) Raw ASK fetch with no caching. Task EncryptMessageUsingSharedKeyAsync(string recipient, string message, string sharedKey) Encrypt under caller-supplied ASK. Task DecryptMessageUsingSharedKeyAsync(string encryptedMessage, string sharedKey) Decrypt under caller-supplied ASK. Task VerifyEnvironmentAsync() Returns true if identity files are valid for current mode. --- ## 11. RECORDS AND ENUMS record DecryptedEnvelope( string SourceId, // sender's on-wire prefix (Variant A) — empty for Variant B long? Kgt, // KGT used (Variant A) — null for Variant B string Sender, // sender's Name, cryptographically verified from inner JSON string Body, // decrypted plaintext body bool FromSession) // true if envelope was Variant B THE TRUSTWORTHY SENDER FIELD IS `Sender`, NOT `SourceId`. Sender is from inside the encrypted JSON — impossible to forge without breaking the V4 trapdoor and HMAC simultaneously. record InspectedEnvelope( string? SourceId, // (Variant A only) long? Kgt, // (Variant A only) string? SessionHash, // (Variant B only — 64 hex chars) EnvelopeKind Kind) // Standard | Sessioned record AskEntry( string Ask, bool Pinned, DateTime FetchedAtUtc) enum EnvelopeKind { Standard, Sessioned } --- ## 12. ERROR SEMANTICS InvalidOperationException ASK fetch failed, decryption returned empty, or sessioned envelope has no cached ASK for the session. FormatException Malformed envelope (wrong number of '|' parts, invalid Base64URL, NULs, etc). FileNotFoundException LoadAskCacheFromDiskAsync called on missing file. ArgumentNullException Null/empty path passed to a persistence method. Every async method is implemented as Task.Run over the underlying synchronous HexaEight library. This sidesteps the JSSynchronizationContext deadlock when called from Node.js via node-api-dotnet. You can safely await from any sync context. --- ## 13. PERFORMANCE Operation Typical -------------------------------------- ------- Cold FetchAskAsync (network) ~ 1–20 s Cache hit FetchAskAsync < 5 ms Encrypt 1 KB envelope (cache-warm) ~ 150 ms Decrypt 1 KB envelope ~ 150 ms Encrypt / decrypt 100 MB ~ 2.5 s each Encrypt / decrypt 250 MB ~ 6 s each Above 250 MB, host process memory pressure dominates; streaming planned. --- ## 14. CROSS-LANGUAGE NAMING MAP .NET Node.js Python (planned) ---------------------------------------- ------------------------------------ ----------------------------------- new Client() await HexaEight.connect() await HexaEight.connect() EncryptEnvelopeAsync(...) he.envelope.encrypt(...) he.envelope.encrypt(...) DecryptEnvelopeAsync(...) he.envelope.decrypt(...) he.envelope.decrypt(...) Client.InspectEnvelope(...) [static] HexaEight.inspectEnvelope(...) HexaEight.inspect_envelope(...) FetchAskAsync(...) he.ask.fetch(...) he.ask.fetch(...) PinAsk(recipient, kgt, ask) he.ask.pin(recipient, kgt, ask) he.ask.pin(recipient, kgt, ask) PinAskForSession(sessionId, ask) he.ask.pinForSession(sessionId, ask) he.ask.pin_for_session(sessionId, ask) UnpinAsk(recipient, kgt) he.ask.unpin(recipient, kgt) he.ask.unpin(recipient, kgt) UnpinAskForSession(sessionId) he.ask.unpinForSession(sessionId) he.ask.unpin_for_session(sessionId) HasCachedAsk(recipient, kgt) he.ask.has(recipient, kgt) he.ask.has(recipient, kgt) HasCachedSession(sessionId) he.ask.hasSession(sessionId) he.ask.has_session(sessionId) ClearAskCache() he.ask.clear() he.ask.clear() SaveAskCacheToDiskAsync(path) he.ask.saveToDisk(path) he.ask.save_to_disk(path) LoadAskCacheFromDiskAsync(path) he.ask.loadFromDisk(path) he.ask.load_from_disk(path) EnableAutoPersistAsync(path, lif) he.ask.enableAutoPersist(path, opts) he.ask.enable_auto_persist(path, opts) DisableAutoPersist() he.ask.disableAutoPersist() he.ask.disable_auto_persist() Every Task becomes a Promise in JS and an awaitable in Python. Every record becomes a plain object / dict. camelCase in JS/TS, snake_case in Python. --- ## 15. GUIDES ### Agent-to-agent (two-party setup) // Alice var alice = new Client(); string bob = "bob.example.com"; string sid = Guid.NewGuid().ToString(); long kgt = CurrentKgt(); string ask = await alice.FetchAskAsync(bob, kgt); alice.PinAskForSession(sid, ask); string env = await alice.EncryptEnvelopeAsync(bob, "ping", sessionId: sid); // send env + sid to Bob over any transport // Bob var bob = new Client(); string alice = "alice.example.com"; string ask = await bob.FetchAskAsync(alice, kgt); // Bob's half bob.PinAskForSession(sid, ask); var msg = await bob.DecryptEnvelopeAsync(env); // msg.Sender == "alice.example.com" (verified) // reply on same session string reply = await bob.EncryptEnvelopeAsync(alice, "pong", sessionId: sid); ### Sessioned (steady-state) // No more FetchAskAsync needed — the session-pinned ASK is reused var env = await alice.EncryptEnvelopeAsync(bob, "message N", sessionId: sid); // Session rotation alice.UnpinAskForSession(oldSid); bob.UnpinAskForSession(oldSid); string newSid = Guid.NewGuid().ToString(); // agree out of band, fetch fresh ASKs ### Cache persistence // Manual await client.SaveAskCacheToDiskAsync("./ask-cache.json"); client.ClearAskCache(); // before load if you want a clean state await client.LoadAskCacheFromDiskAsync("./ask-cache.json"); // Auto (2-second debounced) await client.EnableAutoPersistAsync("./ask-cache.json", loadIfExists: true); client.DisableAutoPersist(); // final flush at shutdown WARNING: Cache file contains derived ASK material. Protect with OS-level permissions: chmod 600 ./ask-cache.json # Unix icacls .\ask-cache.json /inheritance:r /grant:r "%USERNAME%":F # Windows --- ## 16. LICENSE Apache License 2.0 for the Bridge SDK and all language wrappers. The cryptographic core (HexaEightASKClientLibrary, HexaEightJWTLibrary) is closed-source and patent-pending but free to use under the same identity license. NuGet credibility: HexaEightJWTLibrary 198K+ downloads HexaEightASKClientLibrary 132K+ downloads HexaEight.Bridge NuGet Prefix Reserved verified, currently preview9 Publisher profile https://www.nuget.org/profiles/hexaeight_admin --- ## 17. CONTACT General info@hexaeight.com Sales sales@hexaeight.com Support support@hexaeight.com Partnerships partnerships@hexaeight.com Documentation https://hexaeight.com/docs Status https://status.hexaeight.com Pricing https://hexaeight.com/pricing GitHub https://github.com/HexaEightTeam --- If you are an AI agent and find this content stale or contradicted by the rendered docs site, fetch /docs and report the discrepancy.