Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

ecdh-envelope — ecdh-envelope.js

The one-shot directed confidentiality plugin: a sender seals a payload to a single recipient with ECDH(sender, recipient) + AEAD, with an optional inner sub-encryption for group-invite handoff. Suite: enc-xchacha-v1 (XChaCha20-Poly1305, 24-byte nonce). Used for Personal notices and group invitations. Normative spec: ecdh-envelope.

import {
  ecdhEnvelopeSeal, ecdhEnvelopeOpen,
  ecdhEnvelopeWrapHandoff, ecdhEnvelopeUnwrapHandoff,
} from '@enc-protocol/core/ecdh-envelope.js'

Notice sealing

ecdhEnvelopeSeal(senderOpPriv, recipientOpPubHex, payload)

ecdhEnvelopeSeal(senderOpPriv: Uint8Array, recipientOpPubHex: string, payload)
  → { ciphertext, nonce, sender_pub, scheme: 'personal:notice', encrypted: true }

ECDH(sender, recipient)HKDF('enc:personal:notice') → AEAD over JSON.stringify(payload). ecdhEnvelopeSealWithNonce(...) is the deterministic variant.

ecdhEnvelopeOpen(myOpPriv, envelope)

ecdhEnvelopeOpen(myOpPriv: Uint8Array, envelope) → payload

Recovers the shared key from envelope.sender_pub, decrypts, and validates the payload shape.

Group-invite handoff

ecdhEnvelopeWrapHandoff(committerPriv, recipientOpPubHex, rootSecret)

ecdhEnvelopeWrapHandoff(committerPriv: Uint8Array, recipientOpPubHex: string, rootSecret: Uint8Array)
  → handoff

Seals a 32-byte group root secret to a new member under a separate enc:personal:notice:epoch key — the bridge that lets a one-shot invite hand off an ongoing group epoch.

ecdhEnvelopeUnwrapHandoff(myOpPriv, myOpPubHex, handoff)

ecdhEnvelopeUnwrapHandoff(myOpPriv: Uint8Array, myOpPubHex: string, handoff) → Uint8Array(32) | null

Returns the 32-byte secret, or null if the handoff isn't addressed to this key.

The guards ecdhEnvelopeIsEnvelope(content) and ecdhEnvelopeValidatePayload(payload) are also exported.

Example

import {
  ecdhEnvelopeSeal, ecdhEnvelopeOpen,
  ecdhEnvelopeWrapHandoff, ecdhEnvelopeUnwrapHandoff,
} from '@enc-protocol/core/ecdh-envelope.js'
 
// sender seals a group invite to the recipient's operator key
const envelope = ecdhEnvelopeSeal(senderOpPriv, recipientOpPub, {
  kind: 'group_invite', enclave_id, enclave_kind: 'Group', inviter, epoch_n: 0,
})
const payload = ecdhEnvelopeOpen(recipientOpPriv, envelope)
console.log(payload.kind) // 'group_invite'
 
// hand the live group root secret off to the new member
const handoff = ecdhEnvelopeWrapHandoff(committerPriv, recipientOpPub, groupRootSecret)
const secret = ecdhEnvelopeUnwrapHandoff(recipientOpPriv, recipientOpPub, handoff) // Uint8Array(32) | null

See also