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/plugin-ecdh-envelope'Notice sealing
ecdhEnvelopeSeal(senderOpPriv, recipientOpPubHex, payload)
ts
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)
ts
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)
ts
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)
ts
ecdhEnvelopeUnwrapHandoff(myOpPriv: Uint8Array, myOpPubHex: string, handoff) → Uint8Array(32) | nullReturns the 32-byte secret, or null if the handoff isn't addressed to this key.
Example
import {
ecdhEnvelopeSeal, ecdhEnvelopeOpen,
ecdhEnvelopeWrapHandoff, ecdhEnvelopeUnwrapHandoff,
} from '@enc-protocol/plugin-ecdh-envelope'
// 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
- Package:
@enc-protocol/plugin-ecdh-envelope - Plugin SDKs