Reference · HexaEight.Bridge · 1.0.0-preview9
.NET Bridge API Reference
Every HexaEight SDK — Node, Python, Browser — wraps this .NET package. The surface documented here is the canonical one; language wrappers expose the same names with idiomatic adjustments (camelCase in JS/TS, snake_case in Python).
dotnet add package HexaEight.Bridge --prereleaseNamespace:
HexaEight.BridgeTarget frameworks: net8.0, net9.0, net10.0
sessionId out of band, each fetches
their half of the ASK for the other, and they exchange ciphertext addressed by
session hash. The recipient gets the sender's identity via the cryptographically
verified Sender field on DecryptedEnvelope.
Anonymous-sender mode (Variant A — Standard envelopes with on-wire sender prefix but no inner sender claim) is in the API but not yet recommended for production round-trips. Coming soon.
Class Client
Single entry point. Constructing it loads your identity and authenticates to the platform.
using HexaEight.Bridge;
var client = new Client();
// Identity is now loaded. All subsequent calls are scoped to this identity. Identity properties
| Member | Type | Description |
|---|---|---|
Name | string | The HEXAEIGHT_RESOURCENAME — your fully-qualified identity (e.g. agent01.yourdomain.com). This is the value other parties pass as recipient when talking to you. |
BridgeVersion | static string | The Bridge NuGet version. |
TargetFramework | static string | The TFM under which Bridge is running. |
How identity is loaded
The Bridge looks for credentials in this order, stopping at the first hit:
- Azure mode: If
hexaeightkeys.dbexists in the current working directory, the Bridge reads the login token from the SQLitesettings.logintokenrow. - Environment variable: If
HEXAEIGHT_MACHINETOKENis set in the process environment. - Env-file: If
env-fileexists in the current working directory with aHEXAEIGHT_MACHINETOKEN=…line.
The Bridge is read-only with respect to your environment — it never sets or modifies environment variables on your behalf.
Sessioned envelope round-trip
The supported two-party flow. Alice and Bob each fetch their half of the ASK pair,
pin it under a shared sessionId, and exchange ciphertext.
// ── Alice (sender) ──────────────────────────────────────────
var alice = new Client();
string bobName = "bob.example.com";
string sessionId = Guid.NewGuid().ToString(); // share with Bob out-of-band
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);
// send envelope 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 kgt is the current 15-minute window — see KGT.
Envelope methods
EncryptEnvelopeAsync
Task<string> EncryptEnvelopeAsync(
string recipient,
string body,
long? kgt = null,
string? pinAsk = null,
string? sessionId = null) Encrypts a string body into a single envelope string.
| Param | Required | Effect |
|---|---|---|
recipient | yes | Recipient's Name (e.g. bob.example.com). |
body | yes | UTF-8 plaintext. Tested up to 250 MB. |
kgt | no | Override KGT. Default: current 15-min window. |
pinAsk | no | Use a specific pre-fetched ASK. Bypasses cache and platform fetch. |
sessionId | no | If set, emits Variant B (Sessioned) and caches the ASK under sha256(sessionId). Use this. |
Returns: envelope string (Variant B when sessionId is set),
or empty string on failure.
DecryptEnvelopeAsync
Task<DecryptedEnvelope> DecryptEnvelopeAsync(
string envelope,
string? pinAsk = null) Auto-detects the envelope variant by the hsha: prefix.
InspectEnvelope (static)
static InspectedEnvelope InspectEnvelope(string envelope) Parses the wire format only — no decryption, no platform call. Use it for cheap deny-list filtering before paying the decryption cost.
ASK cache
FetchAskAsync
Task<string> FetchAskAsync(string recipient, long? kgt = null)
Returns the cached ASK if present, otherwise fetches from the platform and caches as
non-pinned. kgt defaults to the current 15-min window.
PinAsk / PinAskForSession
void PinAsk(string recipient, long kgt, string ask)
void PinAskForSession(string sessionId, string ask)
Marks an ASK entry as pinned so it survives auto-eviction. PinAskForSession
stores it under sha256(sessionId) so subsequent
EncryptEnvelopeAsync/DecryptEnvelopeAsync calls with the same
sessionId reuse it.
UnpinAsk / UnpinAskForSession
void UnpinAsk(string recipient, long kgt)
void UnpinAskForSession(string sessionId) Removes a cache entry.
HasCachedAsk / HasCachedSession
bool HasCachedAsk(string recipient, long kgt)
bool HasCachedSession(string sessionId) Test cache presence without triggering a fetch.
ClearAskCache
void ClearAskCache() Wipes the entire ASK cache, both recipient-keyed and session-keyed entries.
Persistence
SaveAskCacheToDiskAsync / LoadAskCacheFromDiskAsync
Task SaveAskCacheToDiskAsync(string filePath)
Task LoadAskCacheFromDiskAsync(string filePath)
Serialize/deserialize the cache as JSON. The file contains ASK material in plaintext —
protect it with OS-level permissions (chmod 600, restricted ACL on Windows).
Load merges entries into the in-memory cache without overwriting; call
ClearAskCache() first if you want a clean load.
EnableAutoPersistAsync / DisableAutoPersist
Task EnableAutoPersistAsync(string filePath, bool loadIfExists = true)
void DisableAutoPersist()
Every cache mutation triggers a 2-second-debounced async write to
filePath. If loadIfExists is true and the file
exists, it's loaded synchronously first. DisableAutoPersist performs a
final synchronous flush.
Records and enums
| Type | Members |
|---|---|
record DecryptedEnvelope | string SourceId, long? Kgt,
string Sender, string Body, bool FromSession.
Sender is the cryptographically verified identity from
inside the encrypted JSON envelope — trust this, not SourceId.FromSession is true when the envelope was
Variant B (Sessioned).
|
record InspectedEnvelope | string? SourceId, long? Kgt, string? SessionHash, EnvelopeKind Kind. |
record AskEntry | string Ask, bool Pinned, DateTime FetchedAtUtc. |
enum EnvelopeKind | Standard, Sessioned. |
Lower-level methods
For protocol-level integration. Most apps should use the envelope methods above.
| Method | Use |
|---|---|
FetchSharedKeyDirectAsync(recipient, kgt) | Raw ASK fetch with no caching. |
EncryptMessageUsingSharedKeyAsync(recipient, message, sharedKey) | Encrypt under a caller-supplied ASK. |
DecryptMessageUsingSharedKeyAsync(encryptedMessage, sharedKey) | Decrypt under a caller-supplied ASK. |
VerifyEnvironmentAsync() | Returns true if identity files are valid for current mode. |
Error handling
InvalidOperationException— ASK fetch failed, decryption returned empty, or sessioned envelope has no cached ASK for the session.FormatException— malformed envelope.FileNotFoundException—LoadAskCacheFromDiskAsynccalled on a missing file.ArgumentNullException— null/empty path passed to a persistence method.
Threading and async
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.
Performance characteristics
| Operation | Typical |
|---|---|
Cold FetchAskAsync (network round-trip) | ~ 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 plaintext, host process memory pressure dominates; streaming support is planned.