zips/zip-0315.rst

501 lines
19 KiB
ReStructuredText
Raw Normal View History

::
ZIP: 315
Title: Best Practices for Wallet Handling of Multiple Pools
Owners: Daira Emma Hopwood <daira@electriccoin.co>
Jack Grigg <jack@electriccoin.co>
Status: Proposed
Category: Wallet
Discussions-To: <https://github.com/zcash/zips/issues/447>
Pull-Request: <https://github.com/zcash/zips/issues/>
Terminology
===========
The key words "MUST", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be
interpreted as described in RFC 2119. [#RFC2119]_
The terms below are to be interpreted as follows:
Auto-shielding
The process of automatically transferring transparent funds to the most recent
shielded pool on receipt.
Opportunistic shielding
The process of transferring previously received transparent funds to the most
recent shielded pool as part of a user-initiated transaction.
Auto-migration
The process of automatically transferring shielded funds from older pools to the
most preferred (usually the most recent) pool on receipt.
Opportunistic migration
The process of transferring previously received shielded funds from older pools
to the most preferred (usually the most recent) pool as part of a user-initiated
transaction.
Transaction output (TXO)
An output (transparent TXO or note) of a transaction on the consensus block chain
or in the mempool visible to a wallet.
Motivation
==========
Zcash wallets have to serve two purposes as a user agent:
* to manage the economic actions dictated by the user;
* to manage the privacy implications of these actions.
The goal of this ZIP is to document security and privacy best practices when handling
funds and transactions as the user's agent. These best practices are intended to
provide as much privacy as is feasible by default, while still enabling the user's
desired transactions to occur, and exposing any privacy implications to the user so
that they have enough information to assess the consequences of their economic actions.
This ZIP covers best practices for:
* what information to display to the user about transactions and balances;
* how to handle interactions between the ZIP 32 key tree and Unified Addresses;
* when to use external or internal keys/addresses;
* sharing addresses and viewing keys;
* sending and receiving funds;
* migrating funds between pools.
Requirements
============
User consent
------------
A wallet typically reveals some information in the process of creating a transaction.
Which information is revealed depends on the configured wallet privacy policy.
The guiding principle of these requirements is that users must explicitly consent
to each instance of information being revealed by the wallet in a transaction.
A user may give blanket consent to reveal a particular kind of information, and
must also be able to change the configured wallet privacy policy to avoid the
wallet creating new information leaks of a given type.
The specifications below describe some situations in which blanket consent may be
inappropriate.
Some varieties of consent may not be revocable, for example if a user chooses to
share some of their keys.
Prompt accessibility of funds
-----------------------------
Wallets need to take account of two concerns:
* enabling funds to be spent as quickly as possible to reduce latency;
* waiting for long enough before spending TXOs to ensure that the
confirmed-spendable balance is not overestimated, and so can be trusted
by the user.
To enable this we define two kinds of TXOs:
* An untrusted TXO is a TXO received from a party that may try to double-spend.
* A trusted TXO is a TXO received from a party where the wallet trusts a
double-spend not to occur, e.g. TXOs created by the wallet's internal TXO
handling.
Wallets can then require that untrusted TXOs need more confirmations before
they become spendable than trusted TXOs. This provides an improved trade-off
between latency on the one hand, and reliability and safety on the other.
Specification
=============
Long-term storage of funds
--------------------------
It is RECOMMENDED that wallets only hold funds as shielded in the long-term;
that is, if a wallet supports receiving transparent funds (or supports
importing a seed from another wallet that may have done so), then it SHOULD
either auto-shield or opportunistically shield such funds by default.
Following this recommendation improves both collective privacy and the user's
individual privacy, by maximizing the size of the note anonymity set over time.
The remainder of this specification assumes a wallet that follows the above
recommendation, except where explicitly noted.
A wallet MAY allow users to disable auto-shielding.
Trusted and untrusted TXOs
--------------------------
A wallet SHOULD treat received TXOs that are outputs of transactions created
by the same wallet, as trusted TXOs. Wallets MAY enable users to mark specific
external transactions as trusted, allowing their received TXOs also to be
classified as trusted TXOs.
A wallet SHOULD have a policy that is clearly communicated to the user for
the number of confirmations needed to spend untrusted and trusted TXOs
respectively. The following confirmation policy is RECOMMENDED:
* 10 confirmations, for untrusted TXOs;
* 3 confirmations, for trusted TXOs.
Rationale for the given numbers of confirmations
''''''''''''''''''''''''''''''''''''''''''''''''
The rationale for choosing three confirmations for trusted TXOs is that
empirically, reorgs are usually less than three blocks.
The consequences of attempting to spend an untrusted note in the case of a
rollback may be less severe than attempting to spend a trusted note. The value
received from a trusted note should always be recoverable, whereas recovering
value received from an untrusted note may require the user to request that
funds are re-sent.
Categories of TXOs according to spendability
--------------------------------------------
A TXO is *spendable*, relative to a given block chain and wallet state,
if and only if all of the following are true in that state:
* the TXO is unspent;
* the TXO is not committed to be spent in another transaction created
by this wallet; and
* the wallet has the TXO's spending key.
A TXO is *confirmed-spendable*, relative to a given block chain and
wallet state, if and only if all of the following are true in that state:
* the wallet is synchronized; and
* the TXO is spendable; and
* either auto-shielding is disabled or the TXO is shielded; and
* the TXO is trusted and has at least the required confirmations for
trusted TXOs, or it is untrusted and has at least the required
confirmations for untrusted TXOs.
A TXO is *unconfirmed-spendable*, relative to a given block chain and
wallet state, if and only if the TXO is spendable but is not
confirmed-spendable in that state.
A TXO is *watch-only* if and only if the wallet has its full viewing key
(or address in the case of a transparent TXO) but not its spending key.
A wallet MUST NOT attempt to spend a TXO that is not confirmed-spendable.
Note: the definition of a TXO includes outputs in mempool transactions
that are unconflicted from the perspective of the wallet.
Reporting of balances
---------------------
Wallets SHOULD report:
* Confirmed-spendable balance.
* Pending balance, *or* total balance.
These are calculated as follows:
* The confirmed-spendable balance is the sum of values of
confirmed-spendable TXOs.
* The pending balance is the sum of values of unconfirmed-spendable TXOs.
* The total balance is the confirmed-spendable balance plus the pending
balance.
Note: the definition of "confirmed-spendable" above ensures that:
* if auto-shielding is enabled, transparent funds will be reported in
the pending or total balance, but not in the confirmed-spendable
balance;
* if the wallet is not synchronized, the confirmed-spendable balance
will be zero.
If auto-shielding is disabled, the wallet MAY report shielded and
transparent balances separately. If it does so, it MUST make clear
whether each reported balance corresponds to a confirmed-spendable,
pending, or total subset of funds.
Rationale for reporting of balances
'''''''''''''''''''''''''''''''''''
If auto-shielding is disabled, then separate shielded and transparent
balances (and potentially, for expert users, separate shielded balances
per pool) can constitute useful information. If auto-shielding is enabled
then the wallet can and will automatically spend transparent TXOs in
order to shield them, and so transparent TXOs need to be presented as
pending, not as part of the balance spendable by the user.
TODO: The specification of balance reporting is intended to give the user
visibility into the operation of auto-shielding, opportunistic shielding,
and pool migration/usage. (Does the spec satisfy this?)
Reporting of transactions
-------------------------
If a transaction contains both spendable and watch-only TXOs, its spendable
and watch-only incoming balances MUST be reported separately.
Incoming transactions
'''''''''''''''''''''
A transaction is incoming if it contains unconfirmed-spendable TXOs.
Incoming transactions SHOULD be reported with their number of confirmations
and their balances as described in `Reporting of balances`_.
Sent transactions
'''''''''''''''''
A transaction is sent if it was either:
* created by the wallet, or
* detected using the wallet's outgoing viewing keys, or
* detected as having been sent from one of the wallet's watch-only addresses.
Sent transactions SHOULD be reported with their number of confirmations,
how long until they expire, and their balances as described in
`Reporting of balances`_.
Transaction creation
--------------------
Anchor selection
''''''''''''''''
A wallet SHOULD choose an anchor a number of blocks back from the head of the
chain equal to the trusted confirmation depth. That is, if the current block
is at height H, the anchor SHOULD reflect the final treestate of the block at
height H-3.
Rationale for anchor selection
''''''''''''''''''''''''''''''
* If the chain rolls back past the block at which the anchor is chosen, then
the anchor and the transaction will be invalidated. This is undesirable both
for reliability, and because the nullifiers of spent notes will have been
revealed, linking this transaction to any future transactions that spend those
notes.
* On the other hand, it is undesirable to choose an anchor too many blocks back,
because that prevents more recently received notes from being spent.
* Using a fixed anchor depth (as opposed to a different depth depending on whether
or not we are spending trusted notes) avoids leaking information about whether
or not we spent trusted notes.
Note selection
''''''''''''''
TODO: consider what we should do when nullifiers are revealed in a transaction
that is then invalidated. Should those notes be prioritized to be spent soon,
or should they be used in a note management tx?
Expiration height
'''''''''''''''''
A wallet SHOULD create transactions using the default expiration height of 40 blocks
from the current height, as specified in [#zip-0203]_.
Linkability of transactions or addresses
----------------------------------------
TODO: dusting attack mitigation
Network-layer privacy
---------------------
Viewing keys
------------
What they are supposed to reveal; see ZIP 310 for Sapling (needs updating for
Orchard). https://github.com/zcash/zips/issues/606
Allowed transfers
-----------------
* Sprout -> transparent or Sapling
* Sapling -> transparent or Sapling or Orchard
* Orchard -> transparent or Sapling or Orchard
* if auto-shielding is off:
* transparent -> transparent or Sapling or Orchard
* if auto-shielding is on:
* transparent -> internal Orchard or Sapling
Note: wallets MAY further restrict the set of transfers they perform.
Auto-shielding
--------------
Wallets SHOULD NOT spend funds from a transparent address to an external address,
unless the user gives explicit consent for this on a per-transaction basis.
In order to support this policy, wallets SHOULD implement a system of auto-shielding
with the following characteristics.
If auto-shielding functionality is available in a wallet, then users MUST be able
to explicitly consent to one of the following possibilities:
* auto-shielding is always on;
* auto-shielding is always off;
* the user specifies a policy...
Auto-shielding MUST be one of:
* "must opt in or out" (zcashd will do this -- i.e. refuse to start unless the option
is configured), or
* always on.
Auto-migration
--------------
Information leakage for transfers between pools
-----------------------------------------------
If no auto-migration, if you can satisfy a transfer request to Sapling from your
Sapling funds, do so.
The user's consent is needed to reveal amounts. Therefore, there should be
per-transaction opt-in for any amount-revealing transfer.
* there may be a compatibility issue for amount-revealing cross-pool txns that were
previously allowed without opt-in
Don't automatically combine funds across pools to satisfy a transfer (since that
could reveal the total funds in some pool).
In order to maintain the integrity of IVK guarantees, wallets should not generate
unified addresses that contain internal receivers, nor expose internal receivers
(such as those used for auto-shielding and change outputs) in any way.
Open questions:
* should there be an auto-migration option from Sapling to Orchard?
# str4d notes
If we want to have both automatic and opportunistic shielding, and keep the two
indistinguishable, then we can't auto-shield when the transparent balance reaches
some threshold (otherwise opportunistic would either never be used, or would be
identifiable when it uses the balance below the threshold).
Instead, a proposition: we define a distribution of "time since last payment to the
address" from which we sample the time at which the auto-shielding transaction will
be created. This distribution is weighted by the balance in the address, so as more
funds accrue, the auto-shielding transaction is more likely to be created.
- It ensures that all funds will eventually be auto-shielded, while preventing
fee-dusting attacks (where dust is sent in order to repeatedly consume fees from
the wallet), as the auto-shielding transaction is not directly triggered by payment
receipt.
- If the user makes a shielding transaction in the meantime, we opportunistically
shield, without it being clearly not an auto-shielding transaction.
- If a wallet is offline for a long time, then it would likely auto-shield as soon as
it finishes syncing. This maybe isn't enough to reveal that the wallet came online,
except that it _might_ result in auto-shielding transactions for multiple
transparent addresses being created at the same time. So we might want to
special-case this?
Properties we want from auto-shielding:
- Auto-shielding transactions MUST NOT shield from multiple transparent receivers in
the same transaction.
- Doing so would trivially link diversified UAs containing transparent receivers.
Properties we want from auto-migration:
- Receipt of a shielded payment MUST NOT trigger any on-chain behaviour (as that
reveals transaction linkability).
Both auto-shielding and auto-migration are time-triggered actions, not
receipt-triggered actions. An auto-shielding or auto-migration transaction MUST NOT
be created as a direct result of a payment being received.
Both of these are opportunistic: if the user's wallet is making a transaction in
which one of these actions would occur anyway, then the wallet takes the opportunity
to migrate as much as it would do if it were generating an autoshielding transaction.
This both saves on a transaction, and removes the need for any kind of transparent
change address within UAs.
TODO: what pool should change go to?
* Proposal: the most recent pool already involved in the transaction.
Wallet Recovery
---------------
In the case where we are recovering a wallet from a backed-up mnemonic phrase,
and not from a wallet.dat, we don't have enough information to figure out what
receiver types the user originally used when deriving each UA under an account.
We have a similar issue if someone exports a UFVK, derives an address from it,
and has a payment sent to the address: zcashd will detect the payment, but has
no way to figure out what address it should display in the UI. A wallet could
store this information in the memo field of change outputs, but that adds a
bunch of coordination to the problem, and assumes ongoing on-chain state
storage.
- If the receiver matches an address that the wallet knows was derived via
``z_getaddressforaccount``, show that UA as expected (matching the receiver
types the user selected).
- If the receiver matches a UFVK in the wallet, and we are looking it up
because we detected a received note in some block, show the UA with the
default receiver types that zcashd was using as of that block height
(ideally the earliest block height we detect), and cache this for future
usage.
- For zcashd's current policy of "best and second-best shielded pools, plus
transparent pool", that would mean Orchard, Sapling, and transparent for
current block heights.
- For each release of a wallet, the wallet should specify a set of receiver
types and an associated range of block heights during which the wallet
will, by default, generate unified addresses using that set of receiver
types.
- For zcashd we know how the policy evolves because each zcashd release has
an approximate release height and End-of-Service height that defines the window.
- Subsequent releases of a wallet SHOULD NOT retroactively change their
policies for previously defined block height ranges.
- If the receiver type for a note received at a given time is not a member
of the set of receiver types expected for the range of block heights, the
policy corresponding to the nearest block height range that includes that
receiver type SHOULD be used.
- If the receiver matches a UFVK in the wallet, and we have no information
about when this receiver may have been first used, show the UA
corresponding to the most recent receiver types policy that includes the
receiver's type.
- As part of this, we're also going to change the "Sapling receiver to
UfvkId" logic to trial-decrypt after trying internal map, so that we will
detect all receivers linked to UFVKs in the wallet, not just receivers in
addresses generated via z_getaddressforaccount. The internal map lookup
is then just an optimisation (and a future refactor to have Orchard do
the same is possible, but for now we will only trial-decrypt so we don't
need to refactor to access the Rust wallet). TODO: express this in a less
zcashd-specific way.
TODO: Mention recommendations (not requirements) of receiver types based on
settled ('accepted') network upgrades, as defined in §3.3 of the
Zcash Protocol Specification, at the time of the release of the wallet.
TODO: Rationale subsection explaining why earliest block height at detection
and the rules/recommendations in place at that block height are preferred
over showing different UAs at different heights
References
==========
.. [#RFC2119] `RFC 2119: Key words for use in RFCs to Indicate Requirement Levels <https://www.rfc-editor.org/rfc/rfc2119.html>`_
.. [#zip-0203] `ZIP 203: Transaction Expiry <zip-0203.rst>`_