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) → payloadRecovers 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)
→ handoffSeals 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) | nullReturns 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) | nullSee also
- Normative: ecdh-envelope
- Plugin SDKs ·
@enc-protocol/core