Introducing a Stealth Address Lock Script + Wallet Demo for CKB

(Looking for feedback from CKB developers!)

Hi everyone,

I’ve been experimenting with privacy features on CKB and recently finished building a Stealth Address Lock Script along with a small Wallet Demo that implements it.

I’m sharing it here to get feedback, suggestions, and ideas from other developers who are interested in privacy, scripting, or building advanced wallet features.

What Is Stealth Address Support?

This implementation follows the “stealth address” pattern known from early Bitcoin proposals:

  • The receiver publishes two public keys (P, Q')
  • The sender generates an ephemeral key R
  • A one-time derived public key is computed using ECDH
  • The payment is locked to this unique derived key
  • The receiver computes the matching private key locally and spends the output

This allows:

  • Unlinkable payment addresses
  • No on-chain exposure of the receiver’s real public keys
  • No interaction needed between sender and receiver

The lock script uses CKB’s standard secp256k1 verification (via ckb-auth), so everything stays compatible with existing tooling.

Wallet Demo

I also built a small demo wallet that:

  • Generates stealth key pairs
  • Creates stealth payment addresses
  • Constructs transactions that send funds to one-time derived keys
  • Scans the blockchain for outputs that belong to the user (stealth cells)
  • Automatically derives the matching private key to unlock those cells

This wallet works as a proof-of-concept showing how stealth addresses can be integrated into a real user workflow:
send → detect → derive → spend.

It is not a production wallet — just a prototype to test the contract logic and validate the privacy flow on CKB.

Confidential Transactions (CT)

Planned CT features include:

  • Amount-hiding via Pedersen commitments
  • Balance conservation enforced by Type Script
  • Sender → receiver encrypted amount recovery
  • Proof-based validation (Bulletproofs, SNARKs, or hybrid approaches)

This will enable:

  • Private balances
  • Private transfers
  • Unlinkable transaction outputs

Why I’m Sharing

I’m planning to continue building a full Confidential Token (CT) system on top of CKB (Pedersen commitments, encrypted amounts, type scripts for validation, etc.), and the stealth lock is the first essential piece.

Before moving on, I want:

  • Feedback on the stealth lock script
  • Ideas for combining stealth address + CT in a clean way
  • Discussion on potential standardization if the community is interested

Looking for Developers!

If you are working on:

  • CKB scripting
  • Privacy primitives (stealth, commitments, proofs)
  • Wallet development
  • Layer 1 crypto experiments
  • Or just curious about privacy on CKB

Your input would be super valuable.


Let’s Discuss

github-repo: Rea-Don-Lycn/obscell and Rea-Don-Lycn/obscell-wallet (sorry, I cannot post link directly since I’m new user here)

Feel free to reply here or open issues/PRs on the repos.
Happy to answer any technical questions or walk through the design.

Thanks!

25 Likes

Your stealth lock implementation looks clean and minimal — the contract simply loads Q’ from the args and relies on ckb-auth for signature verification. The documentation is clear, and the wallet demo ran successfully on Windows and MacOS with `cargo run`, which makes testing very convenient.

Below are a few suggestions as you continue development:

1. You mentioned plans to add Confidential Transactions, possibly using Bulletproofs or SNARKs.

It would help the community if you could outline the intended approach, especially since CKB-VM cycle limits may constrain proof verification. A rough design or feasibility note would already be useful.

2. The scanning issue of wallet demo: sometimes the wallet balance updates only after pressing `rescan` button, it may be worth checking the view-key scanning loop or error handling during block iteration.

3. Theh demo currently uses raw P || Q’ hex as the address, aligning the format with the standard CKB address scheme could improve interoperability and future integration.

Gotta say, this is genuinely impressive — even without CT, your stealth lock design already provides real, practical privacy benefits for everyday CKB transfers. It’s a direction the community should definitely pay more attention to.

11 Likes

Just dropping a small tech note here.

Each CT token cell stores exactly 64 bytes in output.data:

  1. commitment: a 32 bytes compressed Ristretto commitment that hides the token amount C = v·H + r·G, where v - amount, r - blinding, H, G - fixed generators

  2. encrypted_value_and_blinding: a 32-byte encrypted payload containing v (8 bytes) || r (24 bytes) enabling receiver recovery, encrypted using a symmetric key derived from cell’s stealth lock script args.

Receiver (Wallet) to recover balance metadata:

  1. Compute DH shared secret from the lock script args. (DONE in stealth script wallet demo)
  2. Decrypt: key = H(shared), plaintext = encrypted_value_and_blinding XOR key, v = plaintext[0..8), r = plaintext[8..32)

On-Chain Verification (CT Token Type Script):

  1. Sum check is trivial, because commitments are homomorphic, just validates Σ inputs.commitment == Σ outputs.commitment
  2. Actual bulletproof goes into the witness, even with batching, bulletproof verification is not trivial,
    this might hit the cycle cap depending on range size and batch size. I’ll put some priority on benchmarking this part, thanks to the @quake pointed this out in the thread.
7 Likes

Just finished running test on the CT script, and I’ve got a couple of data points that probably need confirmation from developers who have done more heavy cryptography inside CKB-VM.


1. Cycle cost for a 2-in / 2-out CT transaction

My current benchmark for:

  • 2 inputs
  • 2 outputs
  • range proof verification
  • commitment sum check

is landing around 125,000,000 cycles.

Not entirely sure where this sits in the “practical or too expensive” spectrum for real mainnet usage.
If anyone has experience with crypto-heavy on-chain workloads on CKB, I’d appreciate some context, is ~125M cycles considered borderline, acceptable, or already too high?


2. Bulletproof verification RNG

The Bulletproof verifier requires a RNG source.
Obviously there’s no real entropy inside CKB-VM, so I built a deterministic RNG seeded from the transaction hash.

From what I understand of Bulletproof verification, this should be fine, because the RNG is only used to generate Fiat–Shamir challenge values, and does not need unpredictability, only determinism and collision resistance.

Still, I’d really like to confirm this with anyone who’s worked on similar systems on CKB or has deeper experience with Bulletproof internals.
If tx-hash–based RNG is not sufficient for some reason, I’d love to hear why.

If anyone wants to reproduce the numbers, test code is here: Rea-Don-Lycn/obscell/blob/9d388c68513436c2dd0ff5a0e99f9a7d3b271156/tests/src/tests.rs#L151

4 Likes

A quick question: what is the size of proof?

The most suitable ZKP approach on ckb‑vm is likely zkSNARK, which offers a small proof size and strong performance. We’ve already run zk‑VM on ckb‑vm; the cycles can be reduced to roughly the cost of 2 pairing, about 130M cycles.

the batch proof size of two commitments is 672 bytes.

I only took a quick look at the repo, so thanks again for sharing the link. I might be misunderstanding parts of it. But from what I can see, the ckb_bf_verifier contract doesn’t really explain how the witness layout is supposed to be structured, and there isn’t any unit test that shows how a developer is meant to call the contract with an actual proof. Right now the only reference seems to be the verifier implementation itself, which means anyone trying to build a circuit has to reverse-engineer how params, vk, proof, and inputs are supposed to be packed into the witness. That’s a bit hard to rely on.

It would help a lot if the repo included a very small demo circuit that performs something basic like range checking and a sum constraint, together with a test that shows how to generate the params, build the vk, create a proof, pack everything into witnesses, and then verify it on-chain. That kind of example would make it much easier for me to understand how to interact with the contract correctly.

2 Likes

you can follow what is CI doing here: ckb-bf-zkvm/Makefile at 623d10af1b3880a372759cd27be997136ba941e7 · cryptape/ckb-bf-zkvm · GitHub

The ckb-debugger is actually verifying a transaction.

not sure if this helps https://blog.cryptape.com/building-a-zero-knowledge-virtual-machine-on-ckb-vm-for-privacy-preserving-and-secure-computing

This proof size is acceptable for CKB transactions. If the cycle cost does not increase significantly across different scenarios, this solution is feasible.

1 Like