Arcium: MPC for Solana — compute over encrypted data, on-chain
Arcium runs Multi-Party Computation networks that compute over encrypted inputs without ever revealing them. Here's the integration model with Solana programs.
Arcium is a Multi-Party Computation (MPC) network that integrates with Solana programs. Where ZK rollups prove a computation happened correctly, MPC lets a network of nodes jointly perform a computation over inputs none of them can see individually. For Solana, this means on-chain primitives where the data stays private from everyone — including the Arcium nodes themselves.
The model
Three actors:
- Users / programs. Submit encrypted inputs to a computation.
- Arcium nodes (cluster). Hold pieces of every encrypted input. None of them can reconstruct the input alone (the encryption uses MPC secret-sharing). They jointly evaluate the agreed circuit and publish a result.
- Arcium Solana program. Mediates the request, stores the encrypted inputs as on-chain accounts, accepts the jointly-signed result, and forwards it to your program via callback CPI.
The lifecycle of a computation
1. Your program submits a computation request to Arcium
(computation_id + encrypted inputs as ciphertext accounts)
↓
2. Arcium nodes pick up the request, each holds shares of every input
↓
3. Nodes jointly run the circuit defined by computation_id
(the circuit is registered ahead of time as bytecode)
↓
4. Nodes publish the encrypted output and a threshold signature
proving they ran the right circuit on the right inputs
↓
5. The Arcium Solana program verifies the signature, decrypts the
output (or hands the still-encrypted result back to a specific
recipient who holds the decryption key)
↓
6. Arcium CPIs into your program's callback with the resultThe circuit definition
Computations are written in a DSL called Arcis (Rust-flavoured). The compiler turns them into MPC circuits the node network can execute.
// Arcis circuit — runs in the MPC network, inputs stay encrypted
#[mpc_circuit]
pub fn sealed_auction(
bids: Vec<EncryptedU64>, // each node has a share of each bid
bidders: Vec<EncryptedPubkey>,
) -> (EncryptedPubkey, EncryptedU64) {
let (winner_idx, winner_bid) = max_by_value(&bids)?;
(bidders[winner_idx], winner_bid)
}The bids are never visible to any node — the network jointly evaluates the max function over the secret-shared values. Only the winner's identity + winning bid amount is revealed (and even those can be returned encrypted if the design calls for it).
Use cases on Solana
- Sealed-bid auctions. NFT mints, governance token launches. Bidders submit encrypted bids; the auction-clearing happens in MPC; only the winners are revealed.
- Dark pools. Order matching over hidden orders — your buy/sell intent is never visible to other participants or to the protocol operators.
- Private DAO voting. Vote secrecy with on-chain verifiability — only the tally is revealed, never who voted which way.
- Private credit scoring. A lender can decide whether to extend credit based on a borrower's aggregated on-chain history without ever seeing the raw transactions.
- AI inference over private inputs. Run a model on a user's data without the model operator ever seeing the data.
MPC vs ZK — when to pick each
MPC (Arcium) ZK proofs
─────────────────────────────────────────────────────────────────────
Who learns what? Nothing — output encrypted Verifier learns the
to recipient statement, not witness
Trust model Threshold of MPC nodes Math (trustless)
Compute cost Distributed; cheap inputs Expensive proving step
expensive interaction
Setup ceremony Per-circuit precomputation Per-circuit setup
(sometimes trusted)
Best for Multi-party shared inputs Single-prover statementsMPC wins when multiple parties contribute private inputs to a shared computation. ZK wins when one party wants to prove something about their own private data without revealing it.
The callback pattern from your program
use arcium_anchor::queue_computation;
#[program]
pub mod my_auction {
use super::*;
pub fn submit_bid(ctx: Context<SubmitBid>, encrypted_bid: Vec<u8>) -> Result<()> {
queue_computation(
ctx.accounts.arcium_pool,
"sealed_auction", // pre-registered circuit id
vec![encrypted_bid],
CALLBACK_DISCRIMINATOR,
)?;
Ok(())
}
// Arcium calls back when the computation finishes
pub fn handle_auction_result(
ctx: Context<HandleResult>,
winner: Pubkey,
winning_bid: u64,
) -> Result<()> {
ctx.accounts.auction.winner = winner;
ctx.accounts.auction.final_price = winning_bid;
Ok(())
}
}References
Arcium fills the gap between "all data public on-chain" (default Solana) and "all computation off-chain" (just run a server). It's the right primitive when a computation needs to be on-chain-verifiable but its inputs need to stay private — and it's one of the few production-grade MPC networks integrated with any L1.