A privacy-preserving BIP-352 Silent Payments indexing service. Light clients detect Taproot-based silent payments without revealing scan keys to the server.
- Privacy-Preserving β 4-byte prefix filtering, 2Β³Β² anonymity set per query
- Efficient β 99.9% bandwidth reduction vs full block download
- Real-time β ZMQ-based block ingestion from Bitcoin Core
- Scalable β PostgreSQL with optimized B-tree indexes
- Dashboard β Built-in dark-themed admin UI at
http://localhost:3000
ββββββββββββββββββββββββ
β Client (Rust/FFI) β Local ECDH verification
β Prefix Generation β Server never sees secrets
ββββββββββββ¬ββββββββββββ
β HTTPS
ββββββββββββΌββββββββββββ
β Whisper Server β Axum REST API
β PostgreSQL Index β Prefix-based queries
ββββββββββββ¬ββββββββββββ
β ZMQ
ββββββββββββΌββββββββββββ
β Bitcoin Core β Raw block notifications
β + txindex + ZMQ β Taproot output extraction
ββββββββββββββββββββββββ
cp .env.example .env
docker-compose up -d
open http://localhost:3000 # Dashboard
curl http://localhost:3000/api/v1/statusPrerequisites: Rust 1.75+, PostgreSQL 15+, Bitcoin Core 26.0+ with ZMQ
# Database
createdb whisper
export DATABASE_URL=postgres://user:pass@localhost/whisper
# Bitcoin Core (bitcoin.conf)
# regtest=1, server=1, txindex=1
# zmqpubrawblock=tcp://127.0.0.1:28332
# Build & Run
cargo build --release
cd whisper-server && cargo run --releaseQuery blocks for Silent Payment candidates by prefix.
// Request
{
"scan_pubkey": "02a1b2c3...",
"start_height": 100,
"end_height": 200,
"prefixes": ["a1b2c3d4", "e5f6a7b8"]
}
// Response
{
"candidates": [{
"txid": "abc123...",
"vout": 0,
"amount": 100000,
"script_pubkey": "5120...",
"block_height": 150,
"block_hash": "000000...",
"timestamp": 1234567890
}],
"scanned_blocks": [100, 101, ...],
"server_time_ms": 45
}{
"status": "ok",
"version": "0.1.0",
"tip_height": 12345,
"total_outputs": 98765,
"total_blocks": 12345,
"network": "regtest",
"uptime_seconds": 3600
}use whisper_client::SilentPaymentClient;
use whisper_core::{ScanKey, InputData};
let scan_key = ScanKey::from_slice(&secret_bytes)?;
let client = SilentPaymentClient::new(
"http://localhost:3000".into(),
scan_key, spend_pubkey, 10,
);
let results = client.scan_range(100, 200, &inputs).await?;
for r in results {
println!("Payment: {} sats (label: {:?})", r.amount, r.label);
}whisper/
βββ whisper-core/ # BIP-352 cryptographic library
β βββ src/lib.rs # ECDH, tagged hashes, output derivation
βββ whisper-server/ # Indexer & REST API
β βββ src/
β β βββ main.rs # Server entry, static file serving
β β βββ api.rs # REST endpoints with validation
β β βββ indexer.rs # ZMQ block ingestion with reconnect
β β βββ config.rs # Environment configuration
β βββ migrations/ # PostgreSQL schema
β βββ static/ # Dashboard UI
βββ whisper-client/ # Async client library
βββ examples/ # Usage example
| Layer | Protection |
|---|---|
| Crypto | BIP-352 tagged hashes, proper ECDH (mul_tweak) |
| Privacy | 4-byte prefix = 2Β³Β² anonymity set, no key leakage |
| API | Input validation, block range limits, prefix count limits |
| Database | Parameterized queries (sqlx), FK constraints, CHECK constraints |
| Server | Configurable CORS, security headers, graceful shutdown |
make build # Build all crates
make test # Run all tests
make run # Start server
make check # Format + Clippy + Test- Tagged hashes:
BIP0352/SharedSecret,BIP0352/Outputs - ECDH using secp256k1 scalar multiplication
- X-only public keys (BIP-340, even-Y assumption)
- Label support (m = 1..255)
- Core BIP-352 implementation
- PostgreSQL schema & indexing
- REST API with validation
- Client library with local verification
- Dashboard UI
- FFI bindings (UniFFI for iOS/Android)
- Automatic reorg handling
- Production monitoring (Prometheus)
MIT β See LICENSE for details.
β οΈ Cryptographic Warning: This software handles private keys and Bitcoin transactions. Audit thoroughly before production use.