Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

33 Commits

Folders and files

Repository files navigation

darkfi-lightwalletd

Privacy-preserving light wallet server for the DarkFi network. The default binary serves compact blocks for trial decryption. Experimental UnifOMR is a separate build (--features fhe-omr).

0.3.4. Same trial-decrypt default as 0.3.2; version bump aligned with Moonshine 3.1.7 / Nighthawk 3.01.08 light-wallet clients. Build pin 44ec78b6e (nighthawk-testnet, includes upstream tx-local fees and net hosts/refinery fixes).

0.3.2. Default build is trial decrypt: GetCompactOutputBodies, GetNullifiers, GetCompactDaoCalls, and auth-token history. GetLightInfo.omr_supported is false unless the binary is built with fhe-omr. DarkFi pin e47d3f5f2 (Arti 0.48). Proto 2.1.0.

0.3.1. Clue registration accepts monotonic key_version values, including the wallet constant 1. A lower version is rejected, and the same version is accepted only for the same clue key.

0.3.0. DarkFi pin 8af61b3f0 (nighthawk-testnet), the same checkout as the 3.00.026 wallets. That pin pays a fee from tx-local change when the change output covers it. Proto 2.0.0, with no 1.x compatibility path: historical tree snapshots for checkpoints, padded-range enforcement on GetNoteCommitments, GetNullifiers, and GetCompactOutputBodies (a power-of-two bucket of at least 1024, or one cut short within 64 blocks of the tip), a UnifOMR detection-key pool (RegisterDetectionKey, GetUnifOmrDigestFromPool; 24 h handles, 4096 handles and 8 GiB total), a SubscribeBlocks ChainTip stream, and GetCompactOutputBodies.

0.2.4. SendTransaction accepts extra_omr_clues, one UniFOMR clue per sender output (transfer change and fee change) in addition to the recipient clue. Each clue is stored against its output index. A repeat registration for an index that already has a clue is left as first-writer-wins.

Contents


Architecture

┌─────────────┐     gRPC (port 9067)     ┌─────────────────────┐     JSON-RPC     ┌──────────┐
│  Mobile /    │ ◄────────────────────► │ darkfi-lightwalletd  │ ◄──────────────► │ darkfid  │
│  Moonshine   │    Compact Blocks       │  (cache + detector)  │    Full Blocks   │ (node)   │
│  Wallet      │    OMR Digests          │  sled cache          │                  │          │
└─────────────┘                          └─────────────────────┘                  └──────────┘

The server:

  1. Subscribes to new blocks from darkfid via JSON-RPC
  2. Strips ZK proofs, signatures, and PoW data into compact blocks
  3. Caches compact blocks in a local sled database
  4. Serves them to wallets over gRPC
  5. Serves those compact records for wallet trial decryption. Experimental UnifOMR detection runs only when the binary is built with fhe-omr.

Production clients use the default binary (no fhe-omr). See docs/verification-checklist.md and docs/connectivity-triage.md. UnifOMR limits stay in docs/unifomr_mvp_limits.md.


Prerequisites

Requirement Notes
Rust stable (edition 2021) rustup
protoc On PATH (tonic-build in build.rs)
darkfi-nighthawk-testnet Sibling directory literally named ../darkfi-nighthawk-testnet at pin 44ec78b6e (nighthawk24 nighthawk-testnet). Upstream DarkFi is git.dark.fi/darkrenaissance/darkfi, not the GitHub mirror. That pin is not on git.dark.fi, so a master checkout is not enough. Reuse Android nighthawk-android-wallet/third_party/darkfi with ln -sfn.
Running darkfid JSON-RPC endpoint for full blocks

Recommended layout after ./scripts/build.sh:

~/GitHub/
  darkfi-nighthawk-testnet/   # pin 44ec78b6e — or symlink to Android third_party/darkfi
  darkfi-lightwalletd/        # this repo
  moonshine/
  nighthawk-android-wallet/
  nighthawk-ios-wallet/
# Reuse the Android pin instead of a second clone:
ln -sfn nighthawk-android-wallet/third_party/darkfi darkfi-nighthawk-testnet
brew install protobuf                # macOS
sudo apt install protobuf-compiler   # Debian/Ubuntu

Build

Independent clone (pulls darkfi-nighthawk-testnet next to this repo, then builds):

./scripts/build.sh
# Binary: ./target/release/darkfi-lightwalletd

scripts/fetch-darkfi.sh clones/updates the sibling checkout pinned by scripts/darkfi.rev (44ec78b6efbf1d3e797f99bffe95195994b2488d). Overrides:

DARKFI_DIR=/path/to/darkfi-nighthawk-testnet DARKFI_GIT_REF=<commit> ./scripts/fetch-darkfi.sh
./scripts/build.sh --features fhe-omr      # experimental UnifOMR / FHE

If ../darkfi-nighthawk-testnet already exists (symlink to Android third_party/darkfi is OK):

cargo build --release --all-features
# Unit tests do not need compiled contract *.zk.bin (no test-harness dep).
cargo test --release --lib

Run

Configure

Copy lightwalletd.toml.example and set network to testnet or mainnet explicitly. Invalid TOML, missing files, or a chain_name that disagrees with network exits the process (no silent fallback to defaults).

darkfid_endpoint = "tcp://127.0.0.1:18345"   # testnet; mainnet often 8345
# SECURITY: cleartext ONLY on loopback. Public binds REQUIRE TLS.
grpc_listen = "127.0.0.1:9067"
cache_path = "~/.local/share/darkfi/lightwalletd_cache"
poll_interval = 10
chain_name = "darkfi-testnet"
network = "testnet"                          # or "mainnet"

# Public / non-loopback example:
# grpc_listen = "0.0.0.0:9067"
# tls_cert_path = "~/.config/darkfi/lightwalletd.crt"
# tls_key_path = "~/.config/darkfi/lightwalletd.key"

Ops notes:

  • ~ in cache_path / TLS paths is expanded via $HOME
  • Default cache root is scoped by network: …/lightwalletd_cache/testnet or …/lightwalletd_cache/mainnet so compact blocks for the two networks never share a sled DB
  • Chain poller stores compact blocks from darkfid into that cache and serves them over gRPC
  • UnifOMR detection keys must carry the matching network byte (0x00 mainnet / 0x01 testnet)

TLS (required off-loopback)

Cleartext on non-loopback hosts is refused at startup.

# Self-signed (LAN / Mac Studio) or Let's Encrypt (public DNS):
./scripts/generate_tls_cert.sh self-signed --domain studio.local
# ./scripts/generate_tls_cert.sh letsencrypt --domain lw.example.com --email ops@example.com

# Emits certs + LIGHTWALLET_TLS_PIN_SHA256 (leaf DER SHA-256) under scripts/certs/

Full pin guide: docs/TLS_PINNING.md.

Start

# Ensure darkfid is up on darkfid_endpoint (same network as config.network)
cargo run --release -- --config lightwalletd.toml
# or: ./target/release/darkfi-lightwalletd --config lightwalletd.toml

Point clients

Client How
Moonshine server_url = "http://127.0.0.1:9067" (or https://… behind a trusted path)
Android App settings / -PLIGHTWALLET_TLS_PIN_SHA256=<64hex> for remote HTTPS
iOS LIGHTWALLET_TLS_PIN_SHA256 build setting / UserDefaults override

Clients must use the same network / chain_name family as this server.


gRPC API

Defined in proto/lightwallet.proto.

RPC Purpose
GetLightInfo Version, tip, omr_supported
GetBlock / GetBlockRange Compact blocks
GetCompactBlocksAtHeights Sparse compact blocks
GetChainTip Tip height + hash
SendTransaction Broadcast + optional omr_clue → clue_accepted
RegisterOmrClue Transitional clue register (peer-bound)
GetUnifOmrDigest UnifOMR Round 1 (scheme 0x05)
FetchPirBatch UnifOMR Round 2
RegisterCluePublicKey / GetCluePublicKey UnifOMR send-path registry
GetOmrCapabilities Disabled in the default build. unifomr only with --features fhe-omr
GetNullifiers / GetNoteCommitments Spend / commitment sync

OmrDigestRequest:

  • detection_key — legacy single key
  • detection_keys — multi-address (preferred when N > 1)
  • Multi-key response framing: repeated [u32 LE len][digest bytes]

Wire constants

Field Values
Network Mainnet 0x00 · Testnet 0x01
Scheme UnifOMR 0x05 (only)
Multi-address Cap 16 keys; SIMD slots = block heights

Features

Transport & access control

Feature Status Notes
TLS off-loopback (S6) ✅ Cleartext only on 127.0.0.1 / ::1 / localhost
Optional PEM TLS ✅ tls_cert_path + tls_key_path
OMR rate limit ✅ omr_rate_limit_per_min
Clue rate limit ✅ Tighter on RegisterOmrClue
Detection key size cap ✅ Reject oversized UnifOMR keys (~48 MiB)
Max block range ✅ Caps range RPCs (DoS)

Compact blocks & cache

Feature Status Notes
Proof/signature stripping ✅ Compact blocks only
Empty-height FHE slots (S19) ✅ Every height in range occupies a SIMD slot
Skip note clone when clue present (P2) ✅ Detector uses omr_clue when set
Clue hint TTL (S21) ✅ Orphan hints expire (24h)
First-empty / indexed clue apply (S20) ✅ One clue → first empty output or explicit index
No per-hint sled.flush (P8) ✅ Flush with block insert / shutdown

OMR detection

Feature Status Notes
Trial decrypt compact blocks (default) ✅ GetCompactOutputBodies, nullifiers, DAO calls
FetchPirBatch ✅ Length-prefixed SealPIR-style limbs
RegisterCluePublicKey / GetCluePublicKey ✅ Decoy directory; 250 ms timing pad
FHE any-match (S1) ✅ Per-clue layers, client OR
Multi-key digest (S17) ✅ Cap 16
spawn_blocking OMR (P1) ✅ Off the async gRPC worker
Timing pad ✅ Min response time on UnifOMR + clue-dir
UnifOMR clue validate ✅ Size + parse + noise bound

Transaction / clue path

Feature Status Notes
SendTransaction + omr_clue ✅ Hint keyed by tx hash and output index (24h TTL). extra_omr_clues covers the sender's other outputs
clue_accepted (S22) ✅ Tx may succeed while clue is rejected
RegisterOmrClue peer bind (S12) ✅ Prior SendTransaction from same peer within 24h
Envelope parse ✅ Wire OMR envelope can supply FHE clue

UnifOMR (scheme 0x05)

  • Experimental. Build with --features fhe-omr. The default binary does not serve it.
  • Cross-client crypto parity: RLWE n=1024, signed AHE, CLUE_ERROR_BOUND=2, length-prefixed SealPIR limbs
  • Flow: RegisterCluePublicKey → GetClue → SendTransaction(omr_clue) → GetUnifOmrDigest → FetchPirBatch
  • Empty OMR → clients may supplemental trial-decrypt (decoy directory ≠ failure)
  • Clients default to http://127.0.0.1:9067; network / chain_name must match wallets
  • Clue hints from SendTransaction live 24h until the confirming block is indexed
  • Limits: docs/unifomr_mvp_limits.md
  • Sync speed (snapshots, padded ranges, detection-key pool, tip subscribe): docs/wallet-sync-speed-plan.md
Item Status
Crypto parity LWD ↔ moonshine ↔ iOS ↔ Android (n=1024) ✅
Registration matrix + digest round-trip ✅
PIR assemble / CompactBlock reassembly ✅
Clue noise bound vs R_PRIME ✅
Clue hint 24h TTL · GetClue 250ms pad ✅
Decoy directory found channel ✅
Funded broadcast → confirm → PIR e2e ⏳ needs live darkfid
Paper Param2 structural params (n,q,h,r,D,ℓ) ✅ active — see docs/unifomr_mvp_limits.md; archived MVP in docs/unifomr_mvp_archive.md
Paper FP/FN rates ❌ not claimed until digest mod-switch + measured FP

Privacy invariants

Invariant Status
No wallet accounts / session identity ✅
Do not log detection keys or match heights ✅
Sanitize darkfid errors to clients ✅

Infrastructure sizing

Resource 1k users 10k 100k
CPU 2 8 32+ (detector pool)
RAM 4 GB 16 GB 64+ GB
Storage 50 GB SSD 200 GB 1 TB NVMe
Bandwidth ~50 Mbps ~500 Mbps ~5 Gbps

Related projects

Project Role
moonshine CLI light wallet
nighthawk-android-wallet Android
nighthawk-ios-wallet iOS

License

Copyright (C) 2026 Nighthawk Apps — AGPL-3.0-or-later (see LICENSE and COPYRIGHT).

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages