Skip to content

Identity & Key Derivation

The Core Idea

Your identity in Relay is not a username and password. It is a 12-word seed phrase — a BIP39 mnemonic that generates all the cryptographic keys you need.

From that single seed, two independent keypairs are derived using different paths in a hierarchical key tree. One controls your money. The other proves who you are. They share a common root but are mathematically independent — knowing one reveals nothing about the other.

In plain English: When you create an account, Relay generates 12 random English words. From those words, it mathematically derives two separate keys — one for your wallet and one for logging in. Both private keys stay locked inside your phone's secure hardware. The server only ever receives the login public key — which is like giving someone your mailing address without giving them your house key.


Seed Generation

The seed phrase is generated using the BIP-39 mnemonic standard:

  • Entropy: 128 bits of cryptographically secure randomness
  • Word count: 12 words from the standard English wordlist (2048 words)
  • Checksum: Last 4 bits are a SHA-256 checksum of the entropy
  • Library: @scure/bip39 — audited, pure JavaScript implementation

The mnemonic is converted to a 512-bit seed using PBKDF2-SHA512 (2048 iterations). This seed is the input to the HD key derivation.

A note on "BIP" standards in a Solana wallet

BIP-39 (mnemonic phrases) and BIP-44 (derivation path format) originated as Bitcoin Improvement Proposals but have become universal standards adopted across every major blockchain ecosystem. Phantom, Solflare, Backpack, and virtually every Solana wallet uses them. The same 12-word phrase format, the same wordlist, the same path conventions.

What Relay does not use is BIP-32 — the Bitcoin-specific HD key derivation algorithm, which only supports the secp256k1 curve. Solana uses Ed25519, so Relay uses SLIP-0010, which is the Ed25519-compatible equivalent of hierarchical key derivation. Same concept, different curve math.


HD Key Derivation (SLIP-0010)

Relay uses SLIP-0010 for Ed25519 hierarchical deterministic key derivation — the standard adopted by the Solana ecosystem for deriving Ed25519 keys from a master seed.

How it works:

  1. The 512-bit seed is passed through HMAC-SHA512 with the key "ed25519 seed" to produce a 256-bit master secret key and a 256-bit chain code.
  2. Each segment of the derivation path applies another HMAC-SHA512 step, using the chain code as the HMAC key and the parent key + index as input.
  3. All derivation is hardened (indices use the 0x80000000 offset), which means each child key is cryptographically independent — you cannot derive a child public key from a parent public key.

The two paths:

PathPurposeLeaves the device?
m/44'/501'/0'/0'Wallet keypair — controls Solana fundsNever. Private key stays in device secure hardware.
m/44'/501'/1'/0'Auth keypair — proves identity to serverPublic key only. Private key stays in device secure hardware.

The path structure follows the BIP-44 convention (universally adopted, not Bitcoin-specific):

  • 44' — purpose code (standard across all chains)
  • 501' — Solana's registered coin type (SLIP-44 registry)
  • 0' or 1' — account index (wallet vs. auth)
  • 0' — address index

Key Storage

Private keys are stored in the device's hardware-backed secure enclave:

Wallet Keys (react-native-keychain)

SettingValue
Access controlBIOMETRY_ANY_OR_DEVICE_PASSCODE
AccessibilityWHEN_UNLOCKED_THIS_DEVICE_ONLY
Security levelSECURE_HARDWARE

Three items stored:

  • Wallet private key (base58-encoded Solana keypair)
  • Auth private key (base58-encoded Solana keypair)
  • Mnemonic (the 12-word phrase itself)

All three require biometric authentication or device passcode to access.

Public Key Cache

Public keys are stored separately in a non-biometric-gated keychain entry. This allows the app to read your wallet address and auth public key without triggering a biometric prompt on every screen load.


Key Zeroing

After any operation that uses a private key — signing a transaction, signing an auth challenge, deriving keys during import — the secret key bytes are explicitly overwritten with zeros:

typescript
function zeroOut(arr: Uint8Array): void {
  for (let i = 0; i < arr.length; i++) {
    arr[i] = 0;
  }
}

This reduces the window during which key material exists in application memory.


Recovery

Account recovery is deterministic. Given the same 12-word seed phrase:

  1. The wallet keypair is re-derived at m/44'/501'/0'/0' — same address, same funds.
  2. The auth keypair is re-derived at m/44'/501'/1'/0' — same public key the server has on file.
  3. The app performs a signature-based login with the re-derived auth key.
  4. The account is restored. Messages stored locally on the previous device are not recoverable unless an encrypted backup was made.

In plain English: If you get a new phone, you type in your 12 words and everything comes back — your wallet with all your funds, and your account with your username. The math is deterministic: same words, same keys, every time. The only thing you might lose is old messages, unless you made a backup.

Built with conviction.