Skip to main content
Sovran uses NIP-06 hierarchical deterministic key derivation to generate Nostr keypairs from your BIP-39 mnemonic. This provides a single backup phrase that controls both your Bitcoin wallet and Nostr identity.

Key Derivation (NIP-06)

Derivation Path

Nostr keys follow the path: m/44'/1237'/<accountIndex>'/0/0
  • Purpose: 44' (BIP-44)
  • Coin Type: 1237' (Nostr)
  • Account: 0' (default), 1', 2', etc.
  • Change: 0 (external)
  • Index: 0 (first key)

Example Usage

Never expose or log the nsec or privateKey in production. These grant full control over the Nostr identity.

NostrKeysProvider

The NostrKeysProvider manages key derivation, caching, and account switching.

Provider Features

  • Automatic key derivation from mnemonic on app startup
  • SecureStore caching to avoid expensive re-derivation
  • Multi-account support with getKeysForAccount(index)
  • Mnemonic hash validation to detect mnemonic changes
  • Integration with CocoManager for Cashu wallet sync

Implementation

Context API

Secure Storage

Key Caching Strategy

To avoid re-deriving keys on every app launch (which is expensive), Sovran caches derived keys in Expo SecureStore:

Cache Validation

Cached keys are only used if the mnemonic hasn’t changed:

Multi-Account Support

Account Switching

Sovran supports multiple Nostr identities derived from the same mnemonic:

Profile Store Integration

The profileStore tracks which accounts have been created:

Use Case: Testing

Multi-account support is useful for:
  • Testing: Create separate accounts for testing without affecting your main identity
  • Privacy: Use different identities for different contexts
  • Business/Personal: Separate professional and personal Nostr activity

Initialization Flow

Here’s how Sovran initializes Nostr keys on app startup:
1

Check SecureStore for mnemonic

Try to load the mnemonic from Expo SecureStore. If it doesn’t exist, check Redux as a fallback migration path.
2

Generate mnemonic if needed

If no mnemonic exists anywhere, generate a new 12-word BIP-39 mnemonic and store it in SecureStore.
3

Hash mnemonic for cache validation

Compute SHA-256 hash of the mnemonic to validate cached keys.
4

Check cache for derived keys

Look for cached Nostr keys and Cashu mnemonic in SecureStore for the current account index.
5

Derive keys if cache miss

If cache is invalid or missing, derive fresh keys using NIP-06 and BIP-32. This is the slow path.
6

Update cache in background

Store the newly derived keys in SecureStore for next time. This happens asynchronously.
7

Set keys in context

Expose the keys via NostrKeysContext so components can access keys, cashuMnemonic, etc.
8

Initialize CocoManager

Configure the Cashu wallet manager with the account index and Cashu mnemonic.
9

Register with profileStore

Add the pubkey to the profile store so it appears in account switcher.

Cashu Key Derivation

Sovran also derives a separate Cashu wallet mnemonic from the root mnemonic:
This allows both Nostr and Cashu identities to be recovered from a single backup phrase.

Security Best Practices

While JavaScript doesn’t provide explicit memory management, avoid storing private keys in long-lived variables:

Migration from Redux

Older versions of Sovran stored mnemonics in Redux. The NostrKeysProvider automatically migrates:
On first launch after upgrading, the provider:
  1. Detects no mnemonic in SecureStore
  2. Checks Redux for a fallback
  3. Migrates the mnemonic to SecureStore
  4. Derives and caches keys as normal

Testing

Test Vectors

Use known test mnemonics to verify correct derivation:

Mock Provider

For component tests, mock the NostrKeysProvider:

Direct Messages

Use derived keys to send encrypted NIP-17 messages

User Profiles

Publish profile metadata for your Nostr identity

Lightning Address

Claim a Lightning address for your npub

Secure Storage

Learn about Expo SecureStore and encryption