The Stellar/Soroban implementation of the Opaque privacy protocol — DKSAP stealth addresses, on-chain ZK reputation, and a Freighter-powered browser wallet.
Launch the wallet → · GitHub · Solana sibling
Recipient Sender
───────── ──────
Publishes meta-address V ∥ S
Ephemeral key → one-time Stellar account
Pays XLM + announces on Soroban
WASM scanner finds it → sweep to main wallet
Opaque Stellar is the canonical Stellar port of Opaque — the same DKSAP cryptography and Groth16 reputation layer, settled on XLM + Soroban instead of Solana.
| Layer | What it does |
|---|---|
| Stealth payments | Fresh one-time receive accounts per payment — only you can derive the spend key |
| Soroban contracts | Registry, announcer, schemas, attestations, Groth16 + reputation verifiers |
| Browser wallet | Freighter signing · Rust→WASM scanner · snarkjs proofs — all on-device |
| ZK reputation | Prove traits without linking them to your public Stellar address |
Experimental software. Read DISCLAIMER.md before using real funds.
Rust · Stellar CLI · Node 20+ · Freighter · wasm-pack
git clone https://github.com/collinsadi/opaque-stellar.git
cd opaque-stellarContract IDs ship in deployments/v1/testnet.json — no deploy needed to try the UI.
npm run build:scanner # Rust → WASM scanner
npm run fetch:circuits # ZK artifacts (from release when published)
cd frontend
cp .env.example .env # VITE_STELLAR_NETWORK=testnet
npm install
npm run devOpen http://localhost:5173 · connect Freighter on testnet · initialize stealth keys.
cp .env.example .env
stellar keys generate opaque-deployer --network testnet --fund
# Set STELLAR_DEPLOYER=opaque-deployer in .env
npm run deploy:testnet # build WASM + deploy + update manifest
npm run deploy:testnet -- --dry-run # preview onlyEverything has one job. If you only care about the wallet, start with frontend/.
opaque-stellar/
├── frontend/ React wallet (Freighter, send, receive, scan, reputation)
├── contracts/ 6 Soroban smart contracts (Rust workspace)
├── scanner/ DKSAP engine → WASM for the browser
├── circuits/ Circom Groth16 circuits + regression fixtures
├── deployments/ On-chain address book (contract IDs + WASM hashes) ← read this
├── scripts/ TypeScript tooling (deploy, verify, artifacts)
├── artifacts/ Pinned SHA-256 hashes for scanner + circuit builds
├── Cargo.toml Rust workspace root
├── soroban.toml Stellar CLI contract build config
├── deny.toml cargo-deny supply-chain policy
├── package.json Root npm scripts (tsx)
├── .env.example Deployer config for npm run deploy:*
├── SECURITY.md Vulnerability disclosure
└── DISCLAIMER.md Legal / experimental notice
The on-chain address book. After you deploy (or when we publish a release), deployments/v1/testnet.json holds every Soroban contract ID, WASM hash, and RPC URL. The frontend reads it at build time — you don't hardcode C… addresses in source. See deployments/README.md.
Deterministic test vectors for ZK regression. Each folder (v1/, v2/) has valid-input.json, invalid-input.json, and expected-public.json. CI runs npm run test:circuits to prove the Circom circuits still produce the same public outputs — no drift in proof semantics.
| Contract | Role |
|---|---|
stealth-registry |
Wallet → stealth meta-address |
stealth-announcer |
On-chain payment announcements (view tags) |
schema-registry |
Attestation schema definitions |
attestation-engine-v2 |
Issue / revoke credentials |
groth16-verifier |
BN254 proof verification |
reputation-verifier |
Merkle roots, nullifiers, PSR checks |
Build: stellar contract build · Test: cargo test --workspace
All root tooling is TypeScript run via tsx:
| Command | Does |
|---|---|
npm run deploy:testnet |
Build + deploy all contracts + update manifest |
npm run build:scanner |
Compile scanner to frontend/public/pkg/ |
npm run fetch:circuits |
Download pinned ZK artifacts |
npm run verify:deployment |
Validate deployment manifests |
npm run verify:artifacts |
Check scanner/circuit SHA-256 hashes |
npm run test:circuits |
Groth16 regression against fixtures |
| File | Purpose |
|---|---|
.env (root) |
STELLAR_DEPLOYER, STELLAR_NETWORK for deploy scripts |
frontend/.env |
VITE_STELLAR_NETWORK, optional RPC overrides |
Contract IDs default from deployments/v1/<network>.json. Override with VITE_TESTNET_*_CONTRACT only for local dev.
Stealth master keys recover by re-signing with the same Freighter wallet — deterministic derivation, no server.
Manual ghost receives bind ephemeral keys to the browser. Back them up or you lose those funds on device loss.
Session cache (Remember signature) is not a backup — ~30 minutes per tab.
Stealth breaks the link between your public wallet and individual receives. It does not hide that you interacted with Opaque contracts, that you scanned announcements, or network-level metadata.
The in-app privacy threat model maps mitigations to code.
Opaque payment URLs encode amount, asset (XLM), and recipient meta-address for one-click sends. Generated in-app from the Receive tab.
Same DKSAP layout as EIP-5564 / ERC-6538. Meta-addresses are portable; settlement here is Stellar.
| Repo | Chain |
|---|---|
| opaque-stellar (this) | Stellar / Soroban |
| opaque-solana | Solana |
Parts of this codebase were written by contributors at the project’s previous home, collinsadi/opauque-stellar (note the spelling: opauque, not opaque). Much of that work happened during the Stellar wave on Drips. Development continues in this repository because that name cannot be corrected on GitHub right now, and the project needed a cleaner, stricter baseline for open-source work—supply-chain checks, CI gates, security policy, and related hygiene.
Avatars below are generated automatically from Git commit history on the previous repository (contrib.rocks → GitHub Contributors API). New contributions in this repo will appear on its own graph once people land commits here.
Made with contrib.rocks · full contributor graph
See .github/CONTRIBUTING.md. CI is strict: cargo test, clippy -D warnings, frontend lint/typecheck/vitest, circuit regression, manifest verification.
Report vulnerabilities via SECURITY.md.
MIT License · Built by Collins Adi
Every transaction deserves the right to be private.