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).

Install: dotnet add package HexaEight.Bridge --prerelease
Namespace: HexaEight.Bridge
Target frameworks: net8.0, net9.0, net10.0
Supported messaging mode in this build: Sessioned envelopes (Variant B). Two parties agree on a 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

MemberTypeDescription
NamestringThe HEXAEIGHT_RESOURCENAME — your fully-qualified identity (e.g. agent01.yourdomain.com). This is the value other parties pass as recipient when talking to you.
BridgeVersionstatic stringThe Bridge NuGet version.
TargetFrameworkstatic stringThe TFM under which Bridge is running.

How identity is loaded

The Bridge looks for credentials in this order, stopping at the first hit:

  1. Azure mode: If hexaeightkeys.db exists in the current working directory, the Bridge reads the login token from the SQLite settings.logintoken row.
  2. Environment variable: If HEXAEIGHT_MACHINETOKEN is set in the process environment.
  3. Env-file: If env-file exists in the current working directory with a HEXAEIGHT_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.

ParamRequiredEffect
recipientyesRecipient's Name (e.g. bob.example.com).
bodyyesUTF-8 plaintext. Tested up to 250 MB.
kgtnoOverride KGT. Default: current 15-min window.
pinAsknoUse a specific pre-fetched ASK. Bypasses cache and platform fetch.
sessionIdnoIf 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

TypeMembers
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.

MethodUse
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

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

OperationTypical
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.

See also