Encryption
Encryption
Section titled “Encryption”The @contextvm/sdk
supports optional end-to-end encryption for all communication, providing enhanced privacy and security. This section explains the encryption mechanism, how to enable it, and the underlying principles.
Overview
Section titled “Overview”ContextVM’s encryption leverages a simplified version of NIP-17 to ensure:
- Message Content Privacy: All MCP message content is encrypted using NIP-44.
- Metadata Protection: The gift wrap pattern conceals participant identities and other metadata.
- Selective Encryption: Clients and servers can negotiate encryption on a per-session basis.
When encryption is enabled, all ephemeral messages (kind 25910) are wrapped in a kind 1059 gift wrap event. Server announcements and capability lists remain unencrypted for public discoverability.
How It Works
Section titled “How It Works”The encryption flow is designed to be secure and efficient:
- Content Preparation: The original MCP message is serialized into a standard Nostr event.
- Gift Wrapping: The entire event is then encrypted using
nip44.v2
and wrapped inside a “gift wrap” event (kind 1059). A new, random keypair is generated for each gift wrap. - Transmission: The encrypted gift wrap event is published to the Nostr network.
The recipient then unwraps the gift using their private key to decrypt the original message.
Why a Simplified NIP-17/NIP-59 Pattern?
Section titled “Why a Simplified NIP-17/NIP-59 Pattern?”The standard implementation of NIP-17 is designed for persistent private messages and includes a “rumor” and “seal” mechanism to prevent message leakage. Since ContextVM messages are ephemeral and not intended to be stored by relays, this complexity is unnecessary. The SDK uses a more direct gift-wrapping approach that provides strong encryption and metadata protection without the overhead of the full NIP-17 standard.
Enabling Encryption
Section titled “Enabling Encryption”Encryption is configured at the transport level using the EncryptionMode
enum. You can set the desired mode when creating a NostrClientTransport
or NostrServerTransport
.
import { NostrClientTransport } from "@ctxvm/sdk/transport";import { EncryptionMode } from "@ctxvm/sdk/core";
const transport = new NostrClientTransport({ // ... other options encryptionMode: EncryptionMode.OPTIONAL, // or REQUIRED, DISABLED});
EncryptionMode
Section titled “EncryptionMode”REQUIRED
: The transport will only communicate with peers that support encryption. If the other party does not support it, the connection will fail.OPTIONAL
: (Default) The transport will attempt to use encryption if the peer supports it. If not, it will fall back to unencrypted communication.DISABLED
: The transport will not use encryption, even if the peer supports it.
Encryption Support Discovery
Section titled “Encryption Support Discovery”Clients and servers can discover if a peer supports encryption in two ways:
- Server Announcements: Public server announcements (kind 11316) include a
support_encryption
tag to indicate that the server is capable of encrypted communication. - Initialization Handshake: During the MCP initialization process, both the client and server can signal their support for encryption.
API Reference
Section titled “API Reference”The core encryption functions are exposed in the core
module:
encryptMessage(message: string, recipientPublicKey: string): NostrEvent
decryptMessage(event: NostrEvent, signer: NostrSigner): Promise<string>
These functions handle the low-level details of gift wrapping and unwrapping, but in most cases, you will interact with encryption through the transport’s encryptionMode
setting.
Next Steps
Section titled “Next Steps”Now that you understand how encryption works, let’s look at the Constants used throughout the SDK.