# Derive your protocol keys

> One EIP-712 signature yields four keys: nullifying, revocable, viewing private, and viewing public. They are wallet-deterministic and recoverable.

## What this lets you do

Produce the four protocol keys from one wallet signature. There is no server, no storage, and no enrollment ceremony, because the keys are a deterministic function of your wallet signature over a fixed message. If you lose the cache, you simply re-derive identical keys.

## The four keys

privateNullifyingKey Used to derive [nullifiers](/concepts/commitments-and-nullifiers) when spending. Highly sensitive: an attacker who obtains it can link your spends to known commitments, but cannot spend a [note](/concepts/notes) without also holding that note's secret and your revocable-key authorization.
privateRevocableKey Auth-policy material, rotatable via [key rotation](rotate-revocable-key).
viewingPrivateKey Decrypts incoming note payloads. An attacker who obtains it can see your incoming receive history, but spending is unaffected.
viewingPublicKey The X25519 public key derived from viewingPrivateKey. It is safe to publish on-chain (see [register viewing key](register-viewing-key)).

## Constraints & limits

-   You must sign the exact EIP-712 payload the SDK's `deriveKeysFromSignature` expects. The canonical reference is `buildSecretDerivationPayload` in `v2-monorepo/apps/sample/src/keystore/secretDerivationPayload.ts`, which is kept outside the SDK by design.
-   The keys are wallet-bound: the same wallet always produces the same keys, while a different wallet produces a different identity with different notes and a different viewing scope.
-   Keep the derived keys on the client. Caching them in `sessionStorage` spares a browser session from re-prompting the wallet, and you can always drop the cache and re-derive, since the same signature reproduces the same keys. Don't send them to a remote server.

## What it unlocks next

-   [Register your viewing key](register-viewing-key) so others can send you discoverable notes.
-   All spending, transfer, withdraw, and [discover](/operations/manage-notes) operations require these keys.

## How to use it

```ts

// Reference payload builder lives in the sample app, not the SDK (see above):

const payload   = buildSecretDerivationPayload(ownerAddress);
const signature = await walletClient.signTypedData({
    account: ownerAddress,
    domain: payload.domain,
    types: { SecretDerivation: payload.types.SecretDerivation },
    primaryType: payload.primaryType,
    message: payload.message,
});

const keystoreManager = KeystoreManager.fromSignature(
    {
        signature,
        signerAddress: ownerAddress,
        addressHash: payload.message.addressHash,
        revocableKeyIndex: "0x0",
    },
    { cryptoService: new CryptoService() },
);

const privateNullifyingKey = keystoreManager.getPrivateNullifyingKey();
const privateRevocableKey  = keystoreManager.getPrivateRevocableKey();
const { privateKey: viewingPrivateKey, publicKey: viewingPublicKey } =
    keystoreManager.getViewingKeyPair();
```

## Recover on a new device

Because the keys come only from your wallet signature, recovering an account on a new device (or after a `sessionStorage` wipe) is just running this derivation again. There is no extra state to back up. Two things differ from a first-time derivation:

-   **Rotation index:** if the account ever [rotated its revocable key](rotate-revocable-key), re-derive at its current `revocableKeyIndex` rather than `0x0`. Reuse the index your app persisted, or recover it on-chain with `session.discoverRevocableKeyIndex(...)`, which scans candidate indices against the stored auth digest.
-   **Notes:** the keys alone don't carry your [note](/concepts/notes) history. After rebuilding the session, call [`discoverNotes()`](discover-notes) to repopulate it from chain.

The same wallet on a phone and a laptop derives the same keys and sees the same notes, so multi-device access needs no syncing beyond that re-discovery.

## Behind the scenes

Primitives EIP-712 typed-data signing, two-stage HKDF-SHA256 derivation, and X25519 ECDH public-key derivation
SDK source `v2-monorepo/packages/sdk/src/services/CryptoService.ts` (`deriveKeysFromSignature`)
Where Fully client-side. The wallet signature happens via your provider; the SDK requires a standard 65-byte ECDSA signature
