Skip to content

Instantly share code, notes, and snippets.

@SebastienGllmt
Created October 28, 2019 23:46
Show Gist options
  • Save SebastienGllmt/14cd2a892674bd993061c32f771a8f58 to your computer and use it in GitHub Desktop.
Save SebastienGllmt/14cd2a892674bd993061c32f771a8f58 to your computer and use it in GitHub Desktop.
change=3 Proposal

Why this document?

There is an existing proposal for handling Chimeric wallets (which I will call the change=2 proposal) which imposes a limitation of a single staking key per account'. This proposal lifts this restriction.

What is the change=3 proposal?

The restriction to only use account_index=0 in the change=2 problem is fundamentally to solve the following: every staking key should uniquely define the set of payment keys. As long as we only use account_index=0, this holds.

However, this is slightly breaks the design of bip32: child keys should only depend on their parents (its derivation).

To see why this is the case, suppose we want to generate the address for m / 1852' / 1815' / 0' / 0 / 0. The wallet software must do the following:

  1. Derive the public key pay_pub from m / 1852' / 1815' / 0' / 0 / 0
  2. Check if m / 1852' / 1815' / 0' / 2 / 0 (call it stake_pub) exists in the wallet software
  3. If yes, return <pay_pub, stake_pub>, otherwise return just pay_pub.

As you can see, constructing an address required two DIFFERENT bip32 paths. If what we want is that the staking key uniquely defines the payment keys, a more proper solution would be to have the staking key be on the left (in the bip32 path).

How do we reveal the staking key without revealing the payment keys?

It's important that if you ever reveal the staking_key derivation level (which happens when included in a bech32 address), then you SHOULD strip the chaincode first. Otherwise, any external actor would be able to see all child keys (as per the bip32 specification). In general, you should avoid revealing the chaincode for any level (unless it is to interface with wallet software).

The Jormungandr codebase already expects staking keys to be submitted without a chaincode so this is not additional work.

Implementing staking keys as yet another new change type

we use the following derivation path (depending on the value for chain, what comes next changes)

m / purpose' / coin_type' / account' / chain

For chain=0 or chain=1 this is a legacy Icarus wallet

m / purpose' / coin_type' / account' / 0 or 1 / account_index

For chain=2 this is a Chimeric Account

m / purpose' / coin_type' / account' / 2 / account-index

For chain=3 this is a Shelley UTXO

m / purpose' / coin_type' / account' / 3 / staking_key / change / address_index

Now the staking key can uniquely define the payment keys as we want.

We can easily handle legacy wallets either by changing purpose'to something other than 44' OR say that any chain=0 or chain=1 addresses indicates a legacy wallet.

If you only care about the chimeric account, you don’t need to pointlessly create a staking key.

Encoding Single and Group addresses in change=3

The staking key is derived with m / purpose' / coin_type' / account' / 3 / staking_key

The payment key is generated by m / purpose' / coin_type' / account' / 3 / staking_key / change / address_index.

Wallet software can choose to generate an address based just on the payment key OR display a grouped key by showing m / purpose' / coin_type' / account' / 3 / staking_key / change / address_index || m / purpose' / coin_type' / account' / 3 / staking_key. In either case, the address generated depends only on a single BIP32 path (showing the full path down to the address_index uniquely defines what the payment key and staking key. Up to the wallet to decide if a Single or Group address should be shown in the wallet UI)

Summary of change=3 proposal

With this proposal:

  • The staking key now uniquely defines the payment keys
    • Solves the privacy issue of the change=2 proposal
    • Allows you to generate an address knowing only its single bip32 path (change=2 can't do this)
  • We allow users to stake to multiple stake pools from the same account (change=2 proposal doesn't allow for this)
    • This has a strong implication because it means change=2 can NOT know if a new staking key was created on a different machine for your wallet unless you have the private key present. change=3 doesn't need this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment