Silent Reusable Payment Addresses (SRPA)

I would like to discuss the possibility of implementing a feature similar to a stealth identity for wallets, where payments can be received using the same QR code, address, or URIs. For this proposal, we could refer to this feature as the “Silent RPA” mode that’s compatible with CashFusion for Bitcoin Cash wallets that:

  1. Receives all payments on one-time addresses derived via ECDH from a static SRPA public key (stealth-address logic similar to BIP352, but using BCH’s existing P2PKH/P2PKT scripts rather than Taproot).

  2. Feeds those UTXOs into CashFusion, with all fusion outputs (including change) sent to fresh SRPA-derived addresses.

  3. Sends to third parties using the same ECDH derivation against the recipient’s SRPA public key.

The result is a wallet living entirely in “SRPA space” infinite receive → fuse → send cycles, with full compatibility with existing CashFusion rounds and HD-wallet participants.

Motivation

  • Maintain CashFusion interoperability: fusion transactions byte-for-byte identical, regardless of participant type.

  • Silent Payments enhance stealth addresses by eliminating all on-chain hints or metadata linking sender and receiver upfront, preventing the creation of identifiable trails to begin with.

  • Bring Monero-style privacy to BCH without adding confidential-amount layers where our chain arithmetic calculation of the supply remains fully auditable.

Specification

  1. SRPA Keypair
  • Wallet holds a static keypair (sk, PK = sk·G).
  • Backup: sk plus last-scanned block height.
  1. One-Time Address Derivation (BIP352-style)

For any chosen input UTXO with ephemeral pubkey P_in:

shared = ECDH(P_in, sk)                   # = P_in · sk  
addr_bytes = HASH(shared ∥ “srpa”)        # domain separation  
one_time_script = standard_P2PKH(addr_bytes)  
  1. Receive Flow
  • Sender uses the above derivation (analogous to BIP352) to compute your one-time address.
  • Wallet scans every new block’s inputs, computes shared for each P_in, and detects UTXOs to its one-time scripts.
  1. CashFusion Integration
  • Fusion rounds include SRPA and HD participants interchangeably.
  • All fusion outputs (including change) are generated via the ECDH derivation above.
  • On-chain txs remain standard CashFusion format (identical scripts and values).
  1. Send Flow
  • To pay another SRPA user, pick any fused UTXO’s input P_in, derive the recipient’s one-time address via the same function, and build the tx.

Backward Compatibility

  • No protocol changes: CashFusion tx format and script templates unchanged.
  • Standard wallets ignore SRPA outputs.
  • SRPA wallets track both SRPA and HD outputs, mixing seamlessly with non-SRPA users.

Deployment

  • Opt-in “Full Silent RPA Mode” in Electron Cash (or other wallets).
  • No consensus upgrade required wallet-level only.
  • Testnet rollout first; use compact Neutrino-style filters for faster input scanning. Scanning performance via Bloom or Golomb filters (e.g., Neutrino).

Disadvantages

  • Wallet recovery: if you lose sk, re-scan from the genesis block.

Mitigation and improvement for better UX

  • Optional Prefix & Suffix Filtering for light client as defined in the RPA spec by im_imaginaryusername, wallets may optionally support the prefix_size field (0, 4, 8, 12, or 16 bits) encoded in the paycode: string to embed that many bits of the shared-secret hash in each output allowing receivers to scan only 2^prefix_size × fewer inputs (e.g. ~256× fewer with an 8-bit prefix) at the cost of a proportionally smaller anonymity set. Wallets should also parse any URI suffix parameters to configure off-chain relay methods. Implementations must ignore unknown or reserved fields for forward compatibility. Both features should be exposed as advanced, opt-in toggles in the UI (e.g. “Fast Scan (prefix filter)” and “Off-chain Relay Settings”) with clear disclosure of the privacy vs usability trade-offs.

Reference

  1. RPA Proposal Draft
  2. BIP352 - Silent Payment
3 Likes

For Wallets implementing merge avoidance they should strictly disable it when both SRPA and CashFusion are active. inspired by Ryan X. Charles.

[Receive logic] - HD or SRPA derivation
[UTXO pool] - all outputs, labeled (e.g. SRPA, HD)
[Spend logic] - context-aware merge avoidance toggle

In this design:

  • SRPA outputs are tracked and labeled distinctly from HD outputs.
  • Merge avoidance is an important privacy layer that prevents UTXO merging during normal spending, preserving unlinkability. However, because CashFusion requires merging UTXOs to create strong anonymity sets, merge avoidance must be disabled when both SRPA and CashFusion are active, allowing SRPA outputs to participate fully in fusion.
  • Once CashFusion is off, merge avoidance should be re-enabled to protect privacy during normal spends.

The wallet toggle logic can be summarized as:

if SRPA_enabled and CashFusion_enabled:
    merge_avoidance = False  # Disable merge avoidance to allow fusion merging
elif SRPA_enabled or standard_HD:
    merge_avoidance = True   # Enable merge avoidance to protect unlinkability
else:
    merge_avoidance = False  # Default off when neither applies

Where SRPA privacy is preserved outside fusion rounds while CashFusion mixing is fully effective by allowing necessary merges. Wallet behavior remains clear, simple, without degrading privacy.

1 Like

Hi @ABLA,

I’ve been working on a Phase-1 prototype that implements the core of what you describe as “Silent RPA mode” on Bitcoin Cash, using only standard BCH transactions (P2PKH / P2SH + CashTokens).

I wrote up the design and demo here:
:point_right: Blog post:
Silent Reusable Payment Addresses on Bitcoin Cash — Phase-1 Working Demo
`

Very briefly, the current demo on chipnet does:

  • Static SRPA identity
    Each wallet has a long-lived keypair exposed as a paycode (static SRPA public key).
  • One-time ECDH-derived addresses
    All payments are sent to fresh P2PKH addresses derived via ECDH from the paycode and an ephemeral key (BIP352-style). On-chain they look like ordinary BCH outputs.
  • **SRPA change **
    Both receiver and sender change are routed to SRPA-derived self-stealth addresses , so funds can live entirely in “SRPA space”.
  • Covenant-enforced correctness
    A CashTokens-backed covenant binds a Pedersen commitment, a proof hash, and a stealth pubkey hash so only the intended party can redeem the covenant UTXO for the correct amount.
  • Standard transaction format
    No new opcodes, no consensus changes. All scripts are P2PKH / P2SH + CashTokens; non-SRPA wallets just see normal transactions.

What’s intentionally not in Phase-1 yet:

  • Full SRPA discovery / chain scanning .
    For the demo, Alice and Bob share txid s out-of-band. That’s enough to validate the math, the covenant behavior, and the “live in SRPA space” flow. A later phase will address wallet-level discovery (either via SRPA scanning or a more ZKP-driven approach).

CashFusion compatibility is part of the design: because everything is standard P2PKH/P2SH, SRPA UTXOs can sit in the same fusion rounds as HD wallets. The next step is to wire SRPA derivation into the fusion UTXO pool so fusion outputs and change all land on SRPA addresses, as you outlined.

I’m currently preparing to open-source the Phase-1 repo and have a FundMe campaign to support that and the follow-on work (discovery, fusion integration, and later amount-hiding):

:point_right: Funding: Phase 1 https://fundme.cash/campaign/79
:point_right: Funding: Phase 2 https://fundme.cash/campaign/80

Phase 2 will focus on 100% shielded identity and amount on public blockchain and hopefully also eliminate the need for scanning by leveraging zkps for a more p2p transaction style.

Happy to answer questions or adjust details to better align with your SRPA spec. Just wanted to signal to the community that this is not purely theoretical—we have a working SRPA + covenant demo running on chipnet today.

— BC

8 Likes

I still need to review this in detail, but this is incredibly exciting research and prototyping to see and I think everyone should pay close attention!

There has been massive user demand for this kind of privacy tooling (people are always asking about it in BCH Telegram groups and Twitter), so I’m thrilled to see action towards advancing BCH state of the art and making it available to users!!

3 Likes

Absolutely fantastic. I’ve donated to the phase 1 flipstarter. Looking forward to having this in BCH!

3 Likes

Thanks all for the Telegram feedback. There has been some confusion around the term SRPA, and I’ve updated the demo code to remove any of those references for clarity.

In one sense, I do think this work is on the way to achieving SRPA as @ABLA describes.

For the purpose of this discussion, I’m tentatively classifying SRPA as an evolution of the existing RPA implementation in Electron Cash, based on the original spec @im_uname
https://github.com/imaginaryusername/Reusable_specs/blob/master/reusable_addresses.md

Right now, RPA uses a paycode plus specific math to generate child addresses that are unlinkable to the underlying wallet pubkey. This allows you to hand out a static paycode (business-card style) without directly exposing your on-chain identity, since each payment actually lands on a fresh child address.

The current RPA implementation in EC is still beta and relies on wallet-side tracking/indexing to associate those child outputs with the user’s wallet.

SRPA’s intention, as I’m using the term here, is to go a step further: remove the need for extra “beacons” or external tracking, and implement the same effect on-chain using plain Bitcoin Cash transactions, covenants, NFTs, and zero-knowledge proofs.

Phase 1 of this work (confidential asset scaffolding) is aimed at that direction. It’s also being designed to extend the EC implementation, so that—if other wallets follow a similar pattern—we can standardize confidential asset transfers on Bitcoin Cash without extra protocol-specific prefixes or explicit on-chain beacons. You can think of this as moving toward “beaconless” confidential asset transactions.

Please keep the feedback coming so I can refine the story and make it more understandable and relatable.

Here is the latest run log from the current Phase 1 demo:

=== Phase 1: Paycode → Covenant → RPA Return Demo (PZ-SQH) ===

[0] Base wallets and paycodes
  Alice base wallet:  bchtest:qpdmgn6p67s4vezh8rzy0t4dqwte7kc3x53ls5pxfe
  Alice paycode:      PM8TJQi7puENNvL87PcG...
  Bob base wallet:    bchtest:qps6dfu8mhmtpj9p8uusay5xxh2mc6k9ugarzuhldj
  Bob paycode:        PM8TJLg64Hzye5Y6YM9A...

  (Paycodes are static identifiers derived from each wallet’s pubkey.
   They are never used directly on-chain; each payment uses a fresh child address.)

[1] Alice → covenant: lock NFT + amount under Bob-only guard
  - Input[0]: from Alice base wallet (this UTXO could come from CashFusion).
  - Output[0]: small marker → Bob base wallet (optional, for explorer UX).
  - Output[1]: NFT + 100000 sats → covenant lock
      • Guard key: one-time child derived from Bob’s paycode (RPA receiver side).
  - Output[2]: change → Alice base wallet (no paycode-change yet in Phase 1).

  Funding txid:
    fdd8f62cc671d107d1f64c2f52056d7c47f7f034ceb206ec02e63e50b7d8d354

[2] Bob → Alice: return NFT + amount to a paycode-derived one-time address
  - Bob decrypts encrypted amount from Alice: 100000 sats.
  - Bob reconstructs the covenant guard key using:
      • his paycode secrets (scan/spend),
      • Alice’s funding pubkey,
      • the funding input outpoint,
      • index = 0.

  - Inputs:
      input[0]: covenant P2SH (unlocked by Bob’s one-time child key)
      input[1]: Bob fee UTXO from his base wallet: bchtest:qps6dfu8mhmtpj9p8uusay5xxh2mc6k9ugarzuhldj

  - Outputs:
      output[0]: NFT + 100000 sats → one-time address from Alice’s paycode
                 bchtest:qpw2e5zh9uhqqrs6z8afrnnemg8s2gfq3u5pqypst7
      output[1]: change → Bob base wallet: bchtest:qps6dfu8mhmtpj9p8uusay5xxh2mc6k9ugarzuhldj

  Return txid:
    dbb44b08c1ea697d7550e7fa23a29e121cf14c674d3159516b75d537dd04d29e

  Note:
    The address Alice receives is not her base wallet address and not her paycode.
    It’s a fresh child address derived from:
      - Bob’s sender key (fee input),
      - Alice’s paycode pubkey,
      - Bob’s fee outpoint,
      - index = 0.
    To an outside observer, it looks like a random P2PKH token address.

[3] Alice → Alice: spend the RPA-derived output back to her source wallet
  - Alice recognizes Bob’s payment as hers by scanning with her paycode keys.
  - She derives the matching one-time private key and spends that UTXO.

  - Input[0]: one-time P2PKH child from Alice paycode
              (same address as TX [2] output[0])
  - Output[0]: Alice base wallet:
               bchtest:qpdmgn6p67s4vezh8rzy0t4dqwte7kc3x53ls5pxfe

  RPA spend txid:
    d1be520ddef05313c44fa9292740f54beab70095b65e08314cc2d9c091b49161

[4] UTXO consolidation (internal)
  - Along the way, the demo may consolidate Alice or Bob’s UTXOs into
    a single input to simplify the flow.
  - This is an internal wallet hygiene step; it does not affect the paycode logic.

Explorer links:
  [1] Alice → covenant:
      https://chipnet.chaingraph.cash/tx/fdd8f62cc671d107d1f64c2f52056d7c47f7f034ceb206ec02e63e50b7d8d354
  [2] Bob → Alice (paycode-derived child address):
      https://chipnet.chaingraph.cash/tx/dbb44b08c1ea697d7550e7fa23a29e121cf14c674d3159516b75d537dd04d29e
  [3] Alice (RPA child) → Alice (base wallet):
      https://chipnet.chaingraph.cash/tx/d1be520ddef05313c44fa9292740f54beab70095b65e08314cc2d9c091b49161
4 Likes

Thanks for clarifying the terminology in the article below

SRPA’s intention, as I’m using the term here, is to go a step further than RPA by: Removing the need for extra “beacons” or protocol‑specific tracking infrastructure, and Implementing the same “static identity → one‑time address” effect entirely on‑chain using:

Plain P2PKH/P2SH Bitcoin Cash transactions, covenants, CashTokens NFTs, and zero‑knowledge proofs.

I think you did a great job explaining this, and it’s necessary to understand that we’ll use a different approach than BIP352. As you all know, BTC uses P2TR for its silent addresses. While we aim for the same stealth-address outcome on Bitcoin Cash we’ll use a different approach for beaconless RPA since BCH doesn’t have or need Taproot, as Bastian showed in his design.

2 Likes