New CHIP: 2026-paths (the derivation type)

The backup can be publicly stored on a server, under the address resulting from the zero.

As such, the publishing of the address for the same wallet, for instance for RPA, binds it to an encrypted backup file. I don’t specifically forsee that being a huge deal, but there is no reason to take any risk when addresses are practically free.

Maybe the word ‘identify’ is not clear. As the technical wallet already uses the path you pasted. It appends things like the change chain etc.
This is not the identity I was referring to.

The wallet identity is one bitcoin address that can be used to refer to the wallet. As opposed to referring to reddit.com (as in, a login key) or another public key that is the login for this site, bccr com.
The choice of 2/0 (appended to that pasted path of yours) is simply to pick an address that is unused by any payments or other things. So thigns stay private and nobody will be able to find that comment-backup file and tie it to you.

It is a simple avoidance of reusing an address.

I mean, my point of view is to not see it as “moving it up one index”. The point I’m trying to support is that the /2/* chain is for a lot of keys. And you want to avoid reusing of keys.
So it becomes needed to reserve keys in your wallet. If you implement the feature to do logins on websites then you reserve keys for that. And if the user just happens to create an RPA at a later date, it just uses the first free one.

So no different than main or change addresses where you avoid reuse.

And I agree, please use /2/*
It falls in the concept of the CHIP, I have no problem with it.

Just the basic request to consider the /2/0 key pre-reserved. If you don’t, then I won’t lose any sleep over it. Some users may complain and if you want to do backups in your wallet at a later time you’ll be forced to do is incompatible with mine, which is why I’m writing here.

So use /2/*, by all means.

1 Like

If I am reading this correctly this would mean that it would be hard to move a seed between wallets with different functionality. Wallet A (that supports “identity” but not RPA) could use m'/44'/145'/0'/2/0 as a login to a specific website. If a user enters the seed into Wallet B (that supports RPA but not “identity”) a paycode would expose the pubkeys m'/44'/145'/0'/2/0 and m'/44'/145'/0'/2/1 and anyone with knowledge of the identity and paycode would be able to link the two to the same user.
Therefor RPA should not be derived on a path that is known to be used for anything else so any RPA capable wallet could recover funds from the known path.

@kzKallisti So “up 1 index” and use m'/44'/145'/0'/3/x for RPA seems appropriate.

1 Like

works for me too.

To tie it al into a nice ribbon; the /2/0 key is used to do the comments-backup I mentioned? This can naturally also be used to backup your other details, like which identity matches which key. So restoring from seed also restores all this info from a (cloud based) backup.

1 Like

You are the only one that has claimed any usage of the m'/44'/145'/0'/2/0 key so I do not know who you are asking this.

My interest in this is to only have a path for RPA keys and I do not have any opinion on any key below m'/44'/145'/0'/2/... currently.

1 Like

Why keep RPA under 44' at all? Even in this thread it’s slid from /2 to /3, and identity/backup and logins also sit on /2. Giving RPA its own purpose like m'/47'/145'/0' or m'/X'/145' reserves it by namespace instead of a child index everyone has to remember to keep clear, so it stays isolated whatever else gets added under 44' later. 47' is already the reusable-payment slot and 145' keeps it BCH. I might be missing why 44' is the better home though.

RPA is not the same as BIP-47 so using 47 would not be ideal.

The reason it makes sense is that the RPA keys at m/44'/145'/0'/3/[0,1] “belongs” to the wallet m/44'/145'/0'.

If a new wallet for the same seed would be needed it would naturally be m/44'/145'/1' and it’s RPA keys would be below the same path: m/44'/145'/1'/3/[0,1]

It’s a logical grouping of what belongs to a specific wallet and you can recover all the RPA funds given one xpriv.

You can treat 47' just as the nearest existing label, not me proposing BIP47. The idea is a dedicated purpose m'/X'/145', so “RPA isn’t BIP47” isn’t the issue you can choose any arbitrary number its just that BIP47 is famous for payment code and the implementation is BCH native.

On grouping though, “recover everything from one xpriv” is the same property as “link everything from one xpub.” With RPA at m'/44'/145'/0'/3/[0,1], anyone you hand the account xpub to (watch-only, a backup service, a third party) can derive /3/0 and /3/1 to rebuild your paycode and /2/x for what Tom mentioned about login/identity, and tie them to one wallet. That’s the linkage again, just at xpub level instead of a reused address.

A separate purpose puts RPA in a tree the 44' account xpub can’t reach, so handing out that xpub doesn’t rebuild your paycode. You lose single-account-xpriv recovery for it, but the seed still recovers everything either way.

So it’s a real tradeoff, not a clear win for 44': grouping is convenient if you only ever restore from seed, but it’s the same key that ties RPA to your logins the moment an account xpub leaves the wallet. Wallet implementation can follow both 47' and 44'and with clear labeling for the end user just like the picture shown below

Why would you handle a third party a xpub for an entire account and not expect that party to link everything that belongs to it? At that point it would make more sense if paycodes and identities was revealed then not. You are giving away almost all privacy (Fused coins? Nope! All fusing history is there…)

To me it seems more consistent to have a use-case: “I have one seed, here is xpriv for wallet 0, 1 and 2 with its own identity and paycode”

Electron Cash has for years been handling RPA as its own wallet and the response has been clear that a paycode should be “linked” to a normal wallet.

What is it you are showing with the picture?

A minor side note: if you are only given a xpub where you can derive the scan and spend pubkeys you will not be able to find the transactions that corresponds to it, the private keys are needed for that.

The picture is from an experimental implementation @0pen and I did in 00wallet, a BIP352 silent payments variant for BCH, where two separate m'/X'/145' branches are derived from the same seed and tracked by the wallet. 44' for normal BCH and 352' for stealth. It was experimental, but it worked.

To add to that, Cauldron is using the /7 path for LP pools. If you give anyone the full account xpub the third party will also be fully aware of any pools that belongs to the wallet account and those pools will also be recoverable from account xpriv.

From an UI perspective: if you from your wallet create pools, paycodes and use identity services it should be expected that those resources is coupled with the account. Hence it would make sense that if you provide a “watch-only” key for the account to a service all the resources would be “watchable” by that service.

There will always be need for watch-only wallet this is why the user should have an easy solution to do that in isolation. Therefore user can have two different accounts for RPA one for watch only wallet and one for normal RPA payments. This is one of worries i was always thinking about and one of the reasons i thought harden gate for the derivation was needed.

I do not fully understand what you are proposing. Why should there be 2 accounts for RPA? How would you distinguish between them in a wallet UI?

What is the need exactly for a watch only wallet? I don’t know where an account level xpub is shared to an untrusted third party and it should be heavily discouraged. The CHIP in OP proposes sharing of xpubs on specific subpaths (not for the whole account) and the WizardConnect protocol is strict about which xpubs are shared (never for the whole account).

Watch-only here is special for RPA. Detecting incoming payments needs the private scan key, not an xpub. So a watch-only RPA wallet means handing over a scan key that can see every payment to that paycode but can’t spend like a merchant terminal, a second device, or an accounting view that should detect incoming RPA but never spend it. For RPA an xpub detects nothing, so the watch case necessarily means sharing a private scan key, not a pubkey.

And because that scan key covers everything it can derive, the best way i can think of to delegate it is to keep the RPA you expose in its own account, separate from your private RPA. The shared key is then scoped to that account and reaches nothing else. In the UI that’s just two accounts like 0’ and 1’, one labeled receive/watch, the other normal.

don’t do that.

Don’t delute the term “watch only” to mean something different than it means. It actually means that the wallet is incapable of doing anything but watching. It is a security thing where you are comfortable giving this watch only wallet to people you lack the trust in them to not spend it.

If you can’t have the ‘watch only’ security on RPA, then just be clear about that. A UI option means they can extract the private key from disk and spend your money.

@tom @robchank I’m working on an account/identity implementation for Selene-related services. With some experimentation, and taking this discussion into consideration, here’s what I think we should settle on:


For purposes of discussion, a wallet is a collection of a user’s keys, and a wallet app is a software app that manages wallets. These two terms can be used nearly-interchangeably.

Wallet apps derive wallet keys deterministically according to the widely-adopted BIP-44 standard, which defines derivation paths with grammar as such:

m'/<purpose>'/<coin_id>'/<account_id>'/<change>/<address_index>

Where ' denotes a hardened derivation path as defined in BIP-32.


A typical BCH wallet app will create its initial wallet using the m'/44'/145'/0' derivation path, which I will call the root derivation path.

For BCH wallets, we should generally consider the purpose and coin_id to be constant. Per BIP-44, purpose set to 44' indicates that we are adhering to the BIP-44 path grammar, and coin_id set to 145' indicates that we are deriving addresses for Bitcoin Cash and not some other blockchain.

We will note the account_id set to 0'. We will consider this path to be not only the root derivation path, but also the wallet’s default account path.

From the default account path, the wallet can derive receive and change addresses by setting change to 0 and 1, respectively. To prevent address reuse, we can increment the address_index for each change path. So the very first user-facing (receive) address would be derived from the path m'/44'/145'/0'/0/0, and the wallet will internally manage change addresses starting from m'/44'/145'/0'/1/0.


Earlier we noted the account_id. We must disambiguate the words account and identity.

For this discussion, an account will refer to a high-level concept similar to “user account” or a “bank account.” The funds and payment histories for each account are all isolated from each other.

A wallet app could present options to manage multiple accounts, each with their own name, but derived from a single seed. Where the default account has the account_id set to 0, we could create any arbitrary number of accounts by setting the account_id to any 0...n.

By these definitions, a single wallet created from root derivation path can contain multiple accounts, where each account derives addresses on multiple change paths.


For identity purposes, we will set the change path to 2. Thus we define the account identity path as m'/44'/145'/<account_id>/2/<identity_index>.

We will define the path at m'/44'/145'/0'/2/0 to be the default wallet identity.

The CashID authentication protocol is a simple challenge-response protocol that enables authentication to a service by signing a challenge message using a private key managed by a user’s wallet.

For privacy, each CashID address should be unique to the service it authenticates to, much like we discourage reuse of payment addresses. Thus, we consider each key derived from the account identity path to represent a single identity.

Two Ways to Handle Identity Derivation
  1. We could simply increment identity_index for each service, and track the metadata of which index corresponds to a service inside the wallet app. For wallet backups, the metadata must be stored, else the only way to recover this metadata is to brute force unlinked addresses against each known service until we learn the correspondence of each.

  2. We could derive the identity_index deterministically based on some canonical service_id, perhaps a hash of the authenticated CashID origin. I am currently leaning in this direction, but am open to discussion on the matter.


With the identity path clearly defined, we then maintain rationale for moving the RPA derivation path to m'/44'/145'/<account_id>'/3/0 for the scan key and m'/44'/145'/<account_id>'/3/1 for the spend key. If the user wishes to derive more reusable paycodes, the wallet should reserve adjacent pairs (2+3, 4+5, etc).

Hopefully this clarifies things for everyone involved, and hopefully what I wrote here aligns with everyone’s existing understanding. Please let me know if there’s anything here that should be ironed out further. :slight_smile:

3 Likes

Also for consideration: if we are able to deterministically know an identity_index for each service, then on the service’s subpaths we could derive things service-specific paycodes, or refund xpubs

This aligns perfectly with my view on this matter. Thank you for doing the write-up.

1 Like

Thanks @kzKallisti this is very comprehensive. I really like ECDH based addresses and discussions like this is the thing that move privacy forward on bitcoin cash i really wish these discussions happened long time ago. I have one question regarding Wizardconnect which can use a template for wallets handshake via extensions to define the workflow of RPA. So, i wonder here how do you think the workflow should be for BCH dapps that use RPA through WizardConnect?

RPA is separate from WizardConnect. In this design, I plan on using WizardConnect as a transport for CashID, and I plan on linking RPA with CashAccount.

So, CashAccount lookup will give you the user’s RPA for payments. The CashAccount is associated with the account as defined above. We are never logging in via CashID using the RPA or the default account path directly. We instead will always furnish a unique address for each service using the identity path for CashID purposes. The wallet app will communicate with the third-party app via WizardConnect in order to negotiate the login using the CashID spec.

I checked Gem Wallet’s current BCH implementation.

Gem uses the standard default path m/44'/145'/0'/0/0 , and derives/stores the account xpub at m/44'/145'/0' . So the current structure is compatible with the proposal’s default BCH account and first receive address.

However, Gem currently operates as a single-address BCH wallet. It does not increment receive-address indexes, use a separate .../1/<index> change branch, or derive additional account IDs. Change is returned to the same .../0/0 address, and the signer currently expects all UTXOs to belong to that one sender key.

Gem also does not currently use the proposed /2/* identity or /3/* RPA branches, so there is no path conflict with those reservations.

Supporting the fuller proposal would require path-aware key derivation and signing, address/index state, separate change addresses, and recovery discovery with an appropriate gap limit. Existing Gem BCH wallets at m/44'/145'/0'/0/0 would remain compatible because that is already the proposed default account’s first receive address.

From an implementation perspective, having a community registry for /2 , /3 , /7 , and other specialized branches would be useful before wallets start allocating these paths independently.