Skip to content
ENC Protocol

ENC Wallet Extension

The ENC Wallet Extension is a Chrome (MV3) browser extension that custodies a user's ENC identity and signs on behalf of apps — so an app never touches the private key. It's a BIP-39 seed-phrase HD wallet whose identity is an x-only secp256k1 (ENC Schnorr) key. It injects a window.enc provider any ENC web app connects to through a standard Connect-Wallet flow, and is also NIP-07-compatible (mirrored as window.nostr). No ETH, no EVM — ENC-native crypto only.

Connecting from an app

// the provider is injected on page load; wait for it if it isn't there yet
if (!window.enc) await new Promise(r => window.addEventListener('encReady', r, { once: true }))
 
const { approved, pubKey } = await window.enc.connect()  // first call shows an approval popup
if (approved) console.log('ENC identity:', pubKey)       // x-only 32-byte hex

Once connected, signing and encryption calls run without a popup (the user approved the origin); only connect() prompts.

The window.enc provider

Connection & accounts

MethodReturnsNotes
connect(){ approved, pubKey }approval popup on first use
getPublicKey()stringx-only 32-byte hex (the ENC identity)
isConnected()boolean
getAccounts(){ accounts: [{ index, pubKey }] }HD-derived + imported accounts
switchAccount(index){ pubKey }emits accountChanged
getVersion()string

Signing (no popup)

const sig = await window.enc.signSchnorr(hashHex)   // BIP-340 over a 32-byte hash → signature hex

This is how an app gets a commit signed: build the commit hash, ask the extension to signSchnorr it, and attach the signature. The key never leaves the extension.

Session keys (no popup)

const { session, sessionPriv, expires } = await window.enc.createSession(7200)  // seconds

A short-lived session key for WebSocket auth — see the session model.

ECDH & encryption (no popup)

const shared = await window.enc.ecdh(peerPubHex)                 // 32-byte hex
const key    = await window.enc.deriveKey(shared, 'enc:dm:a-b')  // HKDF → 32-byte hex
const ct     = await window.enc.encrypt(key, 'secret')          // XChaCha20-Poly1305 → base64
const pt     = await window.enc.decrypt(key, ct)

The same primitives as @enc-protocol/core, but computed inside the extension against the custodied key.

Personal (owner-only) encryption (no popup)

const env = await window.enc.encryptPersonal(enclaveId, 'private note')  // → { ciphertext, nonce }
const pt  = await window.enc.decryptPersonal(enclaveId, env)

Owner-only confidentiality keyed by your identity — the spec's identity-aead plugin. The content key is HKDF(identity_priv, "enc-personal-private:" + enclaveId), computed inside the extension: there's no recipient, the key never leaves, and any device with this identity re-derives the same key. Byte-identical to the SDK's identity-aead, so the same data round-trips with a key-holding client (CLI, passkey).

Events

window.enc.on('connect',        ({ pubKey }) => {})
window.enc.on('disconnect',     () => {})
window.enc.on('accountChanged', ({ pubKey, accountIndex }) => {})

The seed phrase and private keys are never exposed to the page — there is no exportSeed or exportPrivKey method. They can only be revealed inside the extension popup after re-entering the wallet password.

Install for development

The extension ships as a built zip. To run it locally:

  1. Build the zip (yarn build) and unzip it somewhere stable.
  2. Open chrome://extensions, enable Developer Mode, click Load unpacked, and select the extracted extension-chrome/ folder.
  3. Reload any open ENC app — the Connect-Wallet row should now show the extension as available.

The content script injects window.enc on every page, so any ENC web app can detect and connect to it.

See also