ES

PDA Derivation

How a Program Derived Address is computed — SHA-256 over seeds, a bump byte, the program id, and a marker string, with the result forced off the ed25519 curve so no private key can exist for it.

Addressing concept

What it is

A Program Derived Address (PDA) is an account address a program controls without holding a private key. It’s deterministically derived from a set of seeds plus the program id, and deliberately chosen to fall off the ed25519 curve — so no keypair could ever sign for it. Instead, the owning program signs on its behalf via invoke_signed.

Why it exists

Programs need accounts they fully control: a per-user vault, a config singleton, a market’s state. If those used normal keypairs, someone would have to hold the private key. PDAs let a program own and sign for accounts using only on-chain logic — the foundation of nearly every Solana program’s account model.

Byte layout

create_program_address hashes a preimage and checks the result is off-curve:

Order Component Bytes Notes
1 seeds variable Each seed concatenated, in order (e.g. b"vault", a Pubkey, a u64).
2 bump 1 A single byte appended as the last seed (added by find_program_address).
3 program_id 32 The owning program’s address.
4 "ProgramDerivedAddress" 21 A fixed ASCII marker domain-separating PDAs from real keys.
hash = sha256(seed_0 || seed_1 || … || [bump] || program_id || "ProgramDerivedAddress")
if hash is a valid ed25519 point: reject (try a smaller bump)
else: hash is the PDA

About half of candidate hashes land on the curve and are rejected; find_program_address decrements the bump until it finds an off-curve result (see canonical bumps).

Where you see it

Every program-owned account: vaults, escrows, config singletons, order books, and Associated Token Accounts. Any time you see an address derived from findProgramAddressSync(seeds, programId), that’s a PDA.

Common gotchas

  • Each seed is capped at 32 bytes, max 16 seeds. Long seeds (like a full string) must be hashed down or split. The runtime enforces these limits.
  • Seed order is part of the identity. [user, mint] and [mint, user] derive different PDAs. Document and fix your seed order.
  • PDAs have no private key by construction. You can’t “sign” with a PDA externally — only the owning program can authorize actions via invoke_signed, passing the seeds + bump.
  • The bump is part of what’s hashed. Two different bumps give two different addresses from the same seeds. This is why canonical-bump discipline matters for security.

Last verified: 2026-05-20