A Cosmos SDK privacy pool: a shielded UTXO set of Poseidon2 note commitments with nullifier-based spends, verifying Noir/UltraHonk proofs natively in Go. Drops into any Cosmos SDK chain, with optional auditor compliance data enforced once an auditor key is configured.
This is the Cosmos implementation of nixpool. For the account-model approach —
balances as ElGamal ciphertexts rather than a UTXO set — see
confidential-module.
go get github.com/nixprotocol/cosmos-nixpool@v0.1.4Use v0.1.2 or later on Go 1.26. Earlier versions pinned the required
bytedance/sonicfix with areplacedirective, which Go honours only in the main module and ignores for imported packages — so consumers resolved the broken version and failed to compile.
- 5 messages: Register, Deposit, Transact, UpdateParams, SetVerificationKey
- 3 circuits: deposit, registration, transact (2-in/2-out)
- Multi-tree forest: Auto-expanding note trees (2^20 leaves per tree)
- Withdrawal via Transact: Set
withdraw_amount > 0(no separate claim message) - UltraHonk verification: Noir-compatible proof system over BN254
- Auditor compliance: ECIES-encrypted data, required on every transaction
once
auditor_pub_keyis set (unset by default, in which case none is required) - Relayer support: Built-in relayer fee mechanism
Wire into your app.go:
import (
nixmodule "github.com/nixprotocol/cosmos-nixpool/module"
nixkeeper "github.com/nixprotocol/cosmos-nixpool/keeper"
nixtypes "github.com/nixprotocol/cosmos-nixpool/types"
)
// In NewApp:
app.NixpoolKeeper = nixkeeper.NewKeeper(
runtime.NewKVStoreService(keys[nixtypes.StoreKey]),
appCodec,
app.AccountKeeper.AddressCodec(),
authtypes.NewModuleAddress(govtypes.ModuleName), // authority, as []byte
app.BankKeeper,
)
app.ModuleManager.Modules[nixtypes.ModuleName] = nixmodule.NewAppModule(
appCodec, app.NixpoolKeeper, app.BankKeeper,
)| Parameter | Default | Description |
|---|---|---|
tree_depth |
20 | Depth of note Merkle trees (2^20 leaves per tree) |
reg_tree_depth |
20 | Depth of registration tree |
auditor_pub_key |
nil | Grumpkin public key for auditor (64 bytes) |
supported_denoms |
["anix"] | Whitelisted token denominations |
chain_binding |
nil | Poseidon2 hash of chainId for replay protection |
| Message | Description |
|---|---|
MsgRegister |
Register identity with ZK proof |
MsgDeposit |
Shield tokens into the pool |
MsgTransact |
2-in/2-out private transfer (optionally with withdrawal) |
MsgUpdateParams |
Governance-only parameter updates |
MsgSetVerificationKey |
Governance-only VK updates |
| Query | Description |
|---|---|
Root |
Current active tree Merkle root |
NullifierStatus |
Check if nullifier is spent |
TreeInfo |
Forest metadata (tree count, active tree, next index) |
Params |
Module parameters |
RegistrationRoot |
Registration tree root |
AuditorKey |
Current auditor public key |
SupportedDenoms |
List of supported denominations |
- No ZK-level denom binding (enforced at handler level for v1)
- No chainId binding in circuits (enforced at handler level via ChainBinding param)
- No verification key is embedded in the binary. All three circuits load their
VK from state, so every one must be supplied via genesis or a
MsgSetVerificationKeygovernance proposal before that message type works. chain_bindingmust be set before the pool is usable. Register and Transact fail closed without it, and Deposit now does too — otherwise a pool could escrow coins it had no way to release.- Client-side proof generation requires JS/WASM SDK (not included)