SPO (Stake Pool Operator) program for the Bifrost Bridge — a Bitcoin-Cardano bridge that uses Cardano SPOs as distributed custodians to secure BTC transfers between chains.
Heimdall coordinates Cardano SPOs to jointly custody Bitcoin using FROST threshold Schnorr signatures (RFC 9591). The resulting Taproot signature on Bitcoin is indistinguishable from a single-signer spend — no multisig scripts, no on-chain footprint.
The protocol is optimistic: all FROST communication (DKG and signing) happens off-chain via a pull-only model. Only the final aggregated signature is posted on-chain. If any participant misbehaves, an honest party submits a PLONK proof of misbehavior on Cardano, and the cheater is slashed.
- Weighted-majority honesty assumption — security is proportional to Cardano's total staked ADA
- No single point of failure — FROST M-of-N threshold, no party knows the full secret key
- Identifiable abort — cheating SPOs are detected and provably slashed
- On-chain verification — BLS12-381 PLONK proofs verified via Plutus V3 builtins
src/
├── lib.rs # Crate root
├── main.rs # Demo: 400-of-500 DKG + cheating detection + PLONK proof
├── frost/
│ ├── mod.rs
│ └── dkg.rs # Parallelized FROST DKG (frost-secp256k1-tr wrapper)
├── gadgets/
│ ├── mod.rs
│ ├── nonnative.rs # Non-native field arithmetic (secp256k1 over BLS12-381)
│ └── secp256k1.rs # secp256k1 point operations in PLONK circuit
└── circuits/
├── mod.rs
└── commitment.rs # Feldman VSS misbehavior proof circuit
Each epoch, SPOs run Distributed Key Generation to produce:
- A group public key
Y— the Taproot address for Bitcoin treasury - Individual signing shares — each SPO holds a secret share, no one holds the full key
If SPO j sends a bad secret share to SPO i during DKG:
- SPO
idetects the Feldman VSS check failure:s_{j,i} * G ≠ Σ(i^k * C_{j,k}) - SPO
igenerates a PLONK proof showing LHS ≠ RHS without revealing the secret share - The proof is a BLS12-381 PLONK proof — verifiable on Cardano via Plutus V3 builtins
- On-chain contract verifies the proof, cheating SPO is slashed
| Property | Value |
|---|---|
| Proving system | PLONK over BLS12-381 |
| Circuit size | 2^14 (16,384 constraints) |
| Proof size | 1,008 bytes |
| Public inputs | 49 field elements |
| Max signers | 500 (circuit supports any M ≤ 500) |
Requires Rust (2024 edition). A Nix flake is provided for reproducible builds.
# With Nix
nix develop
cargo build
# Without Nix
cargo buildThe demo runs a 400-of-500 FROST DKG, injects a cheating SPO, detects the misbehavior, and generates a PLONK proof:
cargo run --releaseOutput:
=== Heimdall: FROST DKG + PLONK Misbehavior Proof ===
=== 400-of-500 threshold ===
--- Step 1: Running honest 400-of-500 DKG (single SPO completion) ---
--- Step 2: Running DKG with SPO #300 cheating (bad share to SPO #1) ---
--- Step 3: Generating PLONK misbehavior proof ---
PROOF VERIFIED! SPO #300's misbehavior is proven.
Verifiable on Cardano via Plutus V3 BLS12-381 builtins
| Crate | Version | Purpose |
|---|---|---|
frost-secp256k1-tr |
3.0.0-rc.0 | FROST with Taproot (Zcash Foundation) |
dusk-plonk |
0.22.0-rc.0 | PLONK proving system over BLS12-381 |
dusk-bls12_381 |
0.14 | BLS12-381 curve |
rayon |
1.10 | Parallel DKG execution |
- Optimistic FROST Protocol — full protocol specification
- Stake Threshold Analysis — M-of-N parameter selection
- RFC 9591 — FROST: Flexible Round-Optimized Schnorr Threshold Signatures
- FROST Explainer — intuitive overview
- Bifrost Bridge — on-chain smart contracts
All rights reserved.