A prototype implementing BIP-352-style silent payments for the Chia blockchain. Recipients publish a single static address; senders use ECDH to derive unique, unlinkable one-time addresses per payment. No interaction is required, and the resulting transactions are indistinguishable from normal Chia spends.
See the draft proposal CHIP-0057.
This is a prototype for testnet use only. Do not use with real funds.
- Python 3.10+
- coinset CLI (for on-chain lookups)
- Sage wallet (optional, for sending transactions via RPC)
coinset is a command-line tool for querying the Chia blockchain. Install it following the instructions at https://github.com/coinset-org/cli. It must be available in your PATH.
python -m venv venv
source venv/bin/activate
pip install -r requirements.txtThe Python dependencies are:
| Package | Purpose |
|---|---|
chia_rs |
BLS12-381 cryptography, CLVM program handling |
chia-puzzles-py |
Compiled Chia puzzle bytecode (standard transaction, CAT, NFT, singleton) |
mnemonic |
BIP-39 mnemonic word list |
requests |
HTTPS client for Sage wallet RPC (only needed with --sage) |
python generate_address.py -f mnemonic.txt
python generate_address.py -f mnemonic.txt --label 1The mnemonic file should contain a BIP-39 mnemonic (12 or 24 words). If -f is not provided, the mnemonic is prompted interactively. The --label flag generates a labeled sub-address for distinguishing payment streams.
# Derive the one-time address (no send)
python send_payment.py <silent_payment_address> -f mnemonic.txt
# Send via Sage wallet RPC
python send_payment.py <silent_payment_address> --sage --amount 1000
python send_payment.py <silent_payment_address> --sage --amount 1000 --fee 50When using --sage, the script connects to a local Sage wallet via RPC, selects coins, builds a spend bundle, and submits the transaction. Multi-input sends (spending multiple coins) are supported automatically.
Without --sage, the script uses the first derivation index (m/12381/8444/2/0) to derive the sender key and looks up the coin via coinset. The one-time address is printed for manual sending from any wallet.
python scanner.py -s <start_height> -f mnemonic.txt
python scanner.py -s <start_height> -e <end_height> -f mnemonic.txt
python scanner.py -s <start_height> -f mnemonic.txt --labels 1,2,3The scanner examines every coin spend from start_height to the chain tip (or end_height), extracts sender public keys from puzzle reveals, and checks for silent payments using ECDH. Multi-input payments are detected via puzzle-hash grouping and announcement linkage.
python spend_coin.py <coin_id> -f mnemonic.txt
python spend_coin.py <coin_id> -f mnemonic.txt --sageDetects whether the coin belongs to the recipient (trying both single-input and multi-input), derives the one-time secret key, and submits a spend bundle sending the funds to the recipient's standard wallet address.
python scan_coin.py <coin_id> -f mnemonic.txtChecks whether a specific coin is a silent payment to the recipient without spending it.
python -m pytest tests/ -vThe test suite includes:
test_vectors.py-- CHIP test vectors with all intermediate cryptographic valuestest_protocol.py-- Protocol mechanism tests (labels, multi-input, edge cases)test_scanner.py-- Scanner integration teststest_feasibility.py-- CAT2/NFT1 puzzle extraction tests
| File | Description |
|---|---|
shared.py |
Core library: key derivation, ECDH, puzzle construction, scanning |
generate_address.py |
Generate a silent payment address from a mnemonic |
send_payment.py |
Derive one-time address and optionally send via Sage |
scanner.py |
Scan testnet11 blocks for incoming silent payments |
scan_coin.py |
Check if a single coin is a silent payment |
spend_coin.py |
Spend a detected silent payment coin |
sage_rpc.py |
Sage wallet HTTPS RPC client |
chip-silent-payments.md |
Protocol specification (CHIP) |