@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
-
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.
-
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. 