Privacy-Preserving Payment Streaming & Escrow Protocol on Stellar (Soroban)
Powered by Groth16 Zero-Knowledge Proofs & Soroban Protocol 25 BN254 Host Functions
stellar-zkstream is a privacy-preserving payment streaming protocol constructed natively on Soroban, Stellar's smart contract platform. It enables organizations, DAOs, and individuals to stream XLM or any SEP-41 compliant token to recipients continuously over time (for payroll, subscriptions, grants, and vesting) without disclosing exact payment amounts or revealing recipient transaction links on-chain.
By leveraging Groth16 Zero-Knowledge Proofs (BN254 curve) verified on-chain via Soroban Protocol 25 native pairing host functions, stellar-zkstream solves the core transparency trade-off of public blockchains: achieving verifiable, trustless financial execution while maintaining strict commercial and personal privacy.
- π Zero-Knowledge Amount Privacy: Senders prove via ZK Range Proofs (
$min \le \text{amount} \le max$ ) that payment streams are non-zero and fully funded without ever publishing the raw numerical value to the public ledger. - π« Anti Double-Withdrawal Nullifiers: Withdrawals use Poseidon cryptographic nullifier proofs ($N = \text{Poseidon}(s, \text{stream_id})$). Once a nullifier is published and stored on-chain, it cannot be reused, preventing double-claiming.
- β±οΈ Linear Continuous Vesting: Tokens vest per-second based on ledger timestamps. Recipients can withdraw vested portions at any frequency without waiting for stream completion.
- π Soroban Protocol 25 BN254 Native Host Integration: Proof verification delegates cryptographic pairing calculations to Soroban's native
crypto().bn254_pairing_check()host functions, reducing WASM execution footprint and gas costs by over 90%. - βοΈ Revocable & Non-Revocable Streams: Stream creators configure cancellation permissions at creation time. Cancelled streams automatically calculate vested funds owed to the recipient and return unvested remainders to the sender.
- π§© SEP-41 Token Composability: Native support for XLM and any standard Soroban token asset.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CLIENT SIDE β
β β
β Sender Input: (Amount, Duration, Salt) β
β β β
β βΌ β
β [range_proof.circom] βββΊ snarkjs (WASM) βββΊ Groth16 Proof (BN254) β
β β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββΌβββββββββββββββββββββ
β
ββββββββββββββββββΌβββββββββββββββββββββ
β SOROBAN ON-CHAIN LAYER β
β βΌ β
β stream::create_stream() β
β β β
β βΌ β
β zk_verifier::vrfy_prf() β
β β β
β β Native Host Functions β
β βΌ β
β crypto().bn254_pairing_check() β
β β β
β βΌ (Valid) β
β SEP-41 Token Escrow Transfer β
βββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β RECIPIENT CLAIM β
β β
β Recipient Secret (s) + Stream ID β
β β β
β βΌ β
β [nullifier.circom] βββΊ Nullifier Proof βββΊ stream::withdraw() β
β β β
β βΌ β
β Nullifier Registry Check β
β (Persistent Storage) β
β β β
β βΌ β
β Vested Amount Transferred β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The protocol operates over the BN254 pairing-friendly elliptic curve defined by
The zk_verifier contract evaluates the Groth16 zero-knowledge pairing equation:
Where:
-
$A \in \mathbb{G}_1$ (64 bytes),$B \in \mathbb{G}_2$ (128 bytes),$C \in \mathbb{G}_1$ (64 bytes) represent the proof. -
$\alpha, \beta, \gamma, \delta$ are the verification key parameters. - $vk_x = \text{IC}0 + \sum{i=1}^{n} w_i \cdot \text{IC}_i$ is the public input linear combination.
stellar-zkstream utilizes the ZK-friendly Poseidon Hash for commitments and nullifiers:
- State width
$t = 3$ , Full rounds$R_F = 8$ , Partial rounds$R_P = 57$ .
At any ledger timestamp
Initializes contract state with administrator address and the target zk_verifier contract address.
create_stream(env: Env, sender: Address, recipient: Address, token: Address, total_amount: i128, start_time: u64, end_time: u64, proof: Bytes, public_inputs: Vec<BytesN<32>>) -> u64
Creates a payment stream, verifies the Groth16 ZK range proof, and escrows tokens.
withdraw(env: Env, stream_id: u64, caller: Address, nullifier_hash: BytesN<32>, nullifier_proof: Bytes, public_inputs: Vec<BytesN<32>>) -> i128
Withdraws currently vested tokens for the recipient using a ZK nullifier proof.
Cancels an active stream (sender only). Pays recipient vested portion and returns unvested remainder to sender.
View function returning current withdrawable tokens for a stream ID without modifying state.
| Storage Tier | Data Key | Content | Purpose |
|---|---|---|---|
instance() |
DataKey::Admin |
Address |
Admin governance address |
instance() |
DataKey::VerifierContract |
Address |
Deployed zk_verifier contract ID |
instance() |
DataKey::StreamCount |
u64 |
Total stream counter |
persistent() |
DataKey::Stream(id) |
StreamData |
Stream state, balances, timestamps |
persistent() |
DataKey::Nullifier(bytes32) |
bool |
Anti double-withdrawal nullifier index |
persistent() |
DataKey::StreamsBySender(address) |
Vec<u64> |
Sender stream index map |
persistent() |
DataKey::StreamsByRecipient(address) |
Vec<u64> |
Recipient stream index map |
stellar-zkstream/
βββ contracts/
β βββ stream/ # Core payment streaming & escrow contract
β βββ zk_verifier/ # Groth16 BN254 verifier contract
β βββ token_wrapper/ # SEP-41 token wrapper utilities
βββ circuits/
β βββ range_proof/ # Circom ZK range proof circuit
β βββ stream_nullifier/ # Circom ZK nullifier circuit
βββ sdk/ # TypeScript SDK
βββ frontend/ # React application UI
βββ tools/ # CLI tooling (circom2soroban converter)
βββ docs/ # Architecture, ZK specs, deployment guides
βββ scripts/
βββ deploy.sh # Testnet deployment script
git clone https://github.com/stellar-zklab/stellar-zkstream.git
cd stellar-zkstream
# Run unit tests
cargo test --all --features testutils
# Build release WASM binaries
cargo build --release --target wasm32v1-none| Threat Vector | Mitigation Strategy | Status |
|---|---|---|
| Double Withdrawal Attack | Nullifier hash checked against persistent() storage before withdrawal |
β Enforced on-chain |
| Front-Running Claims | Nullifiers bound to specific stream_id via Poseidon hash |
β Cryptographically Bound |
| Proof Replay Attack | Verification keys stored per contract instance & validated against inputs | β Enforced |
| Overflow / Precision Loss | Fixed-point multiplication ordered to prevent overflow | β Verified |
stellar-zkstream is an open-source protocol built for the Stellar ecosystem. We welcome contributions from developers, security researchers, and financial protocol builders!
- Explore Issues: Check out open tasks tagged
good-first-issueorhelp-wanted. - Fork & Branch: Create a feature branch (
git checkout -b feat/your-feature). - Test Your Changes: Ensure all unit tests pass (
cargo test --all --features testutils). - Submit a Pull Request: Open a PR with a clear summary of your changes.
Licensed under the Apache License 2.0. See LICENSE for details.