DEV Community

TokenVet
TokenVet

Posted on

Beyond the Compiler: How OPEQ Handcrafted an sBPF Toolchain to Bring Post-Quantum Security to Solana

When standard compilers make post-quantum verification too expensive for Solana's constraints, one project chose to write the entire toolchain from scratch. This article examines the engineering approach and the trade-offs behind it.

1. The problem: fitting hash-based signatures into Solana

Most public blockchains rely on elliptic-curve cryptography. Shor's algorithm, run on a sufficiently large quantum computer, could derive a private key from its public key. Solana's case is especially direct: an account address is its Ed25519 public key, so the key material needed for an attack is visible on-chain from the moment an address is used.

Hash-based signature schemes, whose security rests only on the collision resistance of hash functions rather than on discrete-log assumptions, are a natural defense. But deploying them on Solana runs into two hard constraints.

  • Transaction size. A serialized Solana transaction is capped at 1,232 bytes. Lattice-based schemes such as ML-DSA produce multi-kilobyte signatures that do not fit. Hash-based schemes are more compact, but they must share that envelope with account metadata, instructions, and other fields.
  • Compute budget. Hash-based verification requires executing many hash chains. Each step costs compute units (CU), and the verifier must leave enough budget for the actual business logic — a token transfer, a swap, or another cross-program invocation — in the same transaction.

OPEQ, currently deployed on Solana devnet, is a wallet that addresses both constraints through a custom toolchain and a compact WOTS+ design. The rest of this article uses it as a worked example.

2. Why bypass the standard toolchain

The standard path for writing a Solana program is Rust, often with the Anchor framework, compiled through LLVM to sBPF bytecode. This works well for general-purpose programs, but the OPEQ team found it problematic for a verifier whose hot loop is a long sequence of hash-chain evaluations. Their reasoning:

  • LLVM's optimizer is general-purpose. It does not know that the program's inner loop will execute hundreds of SHA-256 truncations in sequence, and it cannot eliminate the register spills and boilerplate that accumulate across those iterations.
  • For a program that must stay under roughly 200,000 CU while verifying 18 hash chains and a Merkle path, every unnecessary instruction counts.

Rather than fighting the compiler, the team chose to write directly in sBPF assembly, controlling register allocation, memory layout, and loop structure by hand.

3. The toolchain

The entire stack is plain Python 3 — no Rust, no LLVM, no Solana CLI.

Component Role
asm.py A custom sBPF v3 assembler and strict ELF writer that produces the deployable binary
program.py The on-chain verifier, authored directly in assembly through the assembler
emu.py An sBPF interpreter modeling Solana syscalls, CPI checks, and compute-unit accounting
refmodel.py A reference model of the program's logic, used as a test oracle
test_emu.py Program tests and differential fuzzing against the reference model
test_client.py Client tests against a simulated chain running the real program in the emulator

The emulator's compute-unit counts matched devnet execution within 0.05%, giving the team a fast offline feedback loop during development.

4. How the cryptography fits

4.1 Signature scheme

Component Parameter Size
One-time signature WOTS+ with n = 16 bytes, w = 256 (16 message + 2 checksum chains) 288 bytes
Merkle authentication path Height-10 tree (10 × 16-byte siblings) 160 bytes
Total signature material 448 bytes
Hash function SHA-256 truncated to 16 bytes, tweaked with a per-account public seed and address field, following the SPHINCS+ / SLH-DSA style
Security target About 128-bit classical / 64-bit quantum per one-time key, same category as SLH-DSA-128

The signed message binds program ID, account ID, epoch, leaf index, an expiry slot (capped at 300 slots ahead), and every inner instruction's full content.

4.2 Salt grinding

The client searches a 32-bit salt before submitting a transaction. A good salt produces a message digest whose WOTS+ chains are short, reducing the number of hash steps the on-chain verifier must execute. The project reports that this brings verification down to about 1,275 hash steps — roughly 160,000 CU for a standard transfer and 200,000 CU for a Raydium swap.

4.3 Key management

Each Merkle tree has 1,024 leaves. The last 16 are reserved for rekeying, leaving 1,008 usable signatures per tree. When a tree is nearly exhausted, a rekey transaction mounts a fresh tree while the wallet address and balances stay the same. All trees derive from a single 256-bit master seed displayed as a standard 24-word BIP39 phrase.

4.4 Wallet architecture

The wallet is a Program-Derived Address (PDA) with no Ed25519 private key behind it. The program signs for it via invoke_signed only after verification succeeds. Network fees are paid by a separate Ed25519 fee key derived from the same recovery words; breaking that key costs only its fee balance, never the main vault.

5. Verification and testing

The team uses two complementary strategies.

  • Differential fuzzing. The assembly program and the Python reference model are run on generated inputs. Any divergence is treated as a bug. This catches logic errors that code review might miss.
  • Emulator validation. The emulator replicates the Solana runtime closely enough that compute-unit counts match devnet within 0.05%, allowing rapid iteration without deploying each change.

The program has also been tested against SOL transfers, SPL Token, Token-2022, Memo, associated token account creation, and Raydium CPMM swaps on devnet.

6. Current status and roadmap

The project is transparent about where it stands.

  • Devnet only. The program is deployed on devnet and has been through internal adversarial reviews and a full test suite. It has not yet undergone a published external audit.
  • Upgrade authority. The program's upgrade authority is itself an OPEQ quantum-safe wallet, so a broken Ed25519 key cannot alter the code. On devnet, this authority is a single admin wallet. The team lists mainnet governance — either an immutable program or a quantum-safe multisig with a timelock — as an open design decision.
  • Browser extension. A Chrome extension (source in the repository) is available for devnet use.

7. Trade-offs

Every engineering choice involves trade-offs. The ones most relevant here:

  • Assembly vs. high-level code. Hand-written sBPF gives maximum control over compute cost, but it is harder to read, maintain, and audit than Rust. Few auditors specialize in raw sBPF, which may affect audit timelines.
  • 16-byte hash output. Truncating SHA-256 to 16 bytes keeps signatures at 448 bytes, but it gives a smaller quantum security margin (64 bits) than a 32-byte parameter set would. This is a deliberate trade-off between size and security depth.
  • Stateful key management. WOTS+ keys are one-time use. The wallet enforces a single active device and an on-chain counter to prevent key reuse, but the risk is inherent to the design and demands careful operational discipline.
  • Signature budget. 1,008 signatures per tree means periodic rekeying, which adds a transaction and a small cost.
  • Fee key exposure. The separate Ed25519 fee key remains classically vulnerable, though the damage from its compromise is limited to the fee balance.

8. Context: other approaches

OPEQ is not the only project exploring post-quantum protection on Solana.

  • Solana Winternitz Vault (early 2025): An optional add-on using WOTS with a fresh vault per spend. It works well for cold storage but is impractical for frequent transactions.
  • Protocol-level migration: The Solana Foundation has discussed adding post-quantum signature schemes natively, which would be the most complete solution but requires network-wide coordination and a migration path for existing wallets.

OPEQ's approach sits between these two: it offers active-wallet usability without requiring a protocol change, at the cost of trusting an on-chain program rather than the protocol itself.

9. Conclusion

Building a post-quantum signature verifier on a chain designed around 64-byte Ed25519 signatures is a genuine engineering challenge. OPEQ's approach — discarding the standard compiler toolchain and writing directly in sBPF assembly — is an unusual but coherent response to the tight compute and size constraints. Whether a well-optimized Rust implementation could achieve similar results is an open and interesting question.

For the project, the natural next steps are an external audit, a mainnet governance decision, and continued testing under adversarial conditions. For the broader ecosystem, the work is a useful data point in the ongoing discussion about how blockchains should prepare for the post-quantum era.

Sources

Top comments (0)