Private on-chain inventory state with verifiable ZK operations using Sparse Merkle Trees and Groth16 proofs.
This project implements private inventories on Sui where:
- Inventory contents are hidden (only an SMT commitment is stored on-chain)
- Operations are verifiable via Groth16 ZK proofs
- State transitions are proven correct without revealing actual contents
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INVENTORY PRIVACY β
β β
β On-chain: Commitment = Poseidon(root, volume, blinding) β
β Off-chain: Full inventory state + Merkle proofs β
β β
β Proves: β
β - "I have >= N of item X" (membership) β
β - "I can deposit/withdraw X" (valid state transition) β
β - "My inventory is within capacity" (volume check) β
β β
β Reveals: Nothing except the statement is true β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
inventory-privacy/
βββ crates/
β βββ circuits/ # ZK circuits (arkworks + Poseidon)
β βββ prover/ # Proof generation library
β βββ proof-server/ # HTTP API for proof generation
βββ packages/
β βββ inventory/ # Sui Move contracts
βββ web/ # React frontend
βββ scripts/ # Setup and deployment scripts
βββ keys/ # Generated proving/verifying keys
All circuits use the Poseidon hash function optimized for ZK circuits (~240 constraints per hash).
| Circuit | Purpose | Constraints |
|---|---|---|
StateTransition |
Prove valid deposit/withdraw with capacity check | ~8,597 |
ItemExists |
Prove inventory contains >= N of item | ~4,124 |
Capacity |
Prove inventory volume is within capacity | ~724 |
Inventories use a Sparse Merkle Tree (depth 12, supports 4,096 item types):
Commitment = Poseidon(inventory_root, current_volume, blinding)
inventory_root
/ \
... ...
/ \
leaf[slot_i] leaf[slot_j]
| |
Poseidon(id, qty) Poseidon(id, qty)
- Each leaf:
Poseidon(item_id, quantity) - Empty slots use precomputed
Poseidon(0, 0) - Only the commitment is stored on-chain (~32 bytes)
- Volume tracked incrementally for O(1) capacity checks
Sui limits ZK proofs to 8 public inputs. We compress all parameters into one hash:
signal_hash = Poseidon(
old_commitment,
new_commitment,
registry_root,
max_capacity,
item_id,
amount,
op_type,
nonce,
inventory_id
)
- Rust 1.75+
- Sui CLI
- Node.js 18+ (for web frontend)
# Install dependencies
npm install
# Start local Sui network + deploy contracts + start proof server + web
npm run devThis uses mprocs to run all services in parallel.
# Build all Rust crates
cargo build --release
# Build Move contracts
cd packages/inventory && sui move build
# Generate proving/verifying keys
cargo run --release -p inventory-prover --bin export-vks
# Deploy to localnet
npm run deploy
# Start proof server
cargo run --release -p inventory-proof-server
# Start web frontend
cd web && npm run dev# Run all Rust tests (85 tests)
cargo test --release
# Run Move tests
cd packages/inventory && sui move testcurl http://localhost:3001/healthcurl -X POST http://localhost:3001/prove/state-transition \
-H "Content-Type: application/json" \
-d '{
"old_root": "0x...",
"new_root": "0x...",
"item_id": 1,
"old_quantity": 100,
"new_quantity": 70,
"amount": 30,
"op_type": "withdraw",
...
}'curl -X POST http://localhost:3001/inventory/create \
-H "Content-Type: application/json" \
-d '{
"max_capacity": 1000,
"initial_items": [{"item_id": 1, "quantity": 100}]
}'What's hidden:
- Which items are in the inventory
- Quantities of each item
- Total volume used
- Inventory structure and slot assignments
What's revealed:
- Frequency of operations (state transitions)
- That a valid operation occurred
- Max capacity (public parameter)
Attack Prevention:
| Attack | Prevention |
|---|---|
| Replay | Nonce in signal hash, verified on-chain |
| Cross-inventory | Inventory ID in signal hash |
| Underflow | 32-bit range checks on quantities |
| Capacity bypass | Explicit capacity check in circuit |
| Operation | Proofs | Circuit |
|---|---|---|
| Deposit | 1 | StateTransition |
| Withdraw | 1 | StateTransition |
| Transfer | 2 | 2x StateTransition |
| Prove Ownership | 1 | ItemExists |
- Circuit Architecture - Deep dive into circuit design
- StateTransition Circuit - Line-by-line breakdown
- ItemExists Circuit - Membership proof details
- Capacity Circuit - Volume verification
- Supporting Gadgets - Poseidon, SMT, range checks
- Circuits: arkworks (ark-groth16, ark-bn254, ark-r1cs-std)
- Hash Function: Poseidon (ZK-optimized, ~240 constraints)
- Blockchain: Sui (Move contracts with native Groth16 verifier)
- Frontend: React + TypeScript + Vite
- Proof Server: Rust + Axum
This project has been primarily tested on Windows. It may require adjustments for other platforms (Linux, macOS). PRs for cross-platform support are welcome!
MIT



