Skip to content

Commit

Permalink
Merge pull request #979 from zcash/account-metadata-keys
Browse files Browse the repository at this point in the history
ZIP 325: Account Metadata Keys
  • Loading branch information
str4d authored Feb 27, 2025
2 parents 0fb1511 + 070c185 commit eda6d41
Show file tree
Hide file tree
Showing 4 changed files with 443 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ written.
<tr> <td><span class="reserved">322</span></td> <td class="left"><a class="reserved" href="zips/zip-0322.rst">Generic Signed Message Format</a></td> <td>Reserved</td>
<tr> <td><span class="reserved">323</span></td> <td class="left"><a class="reserved" href="zips/zip-0323.rst">Specification of getblocktemplate for Zcash</a></td> <td>Reserved</td>
<tr> <td>324</td> <td class="left"><a href="zips/zip-0324.rst">URI-Encapsulated Payments</a></td> <td>Draft</td>
<tr> <td>325</td> <td class="left"><a href="zips/zip-0325.md">Account Metadata Keys</a></td> <td>Draft</td>
<tr> <td><span class="reserved">332</span></td> <td class="left"><a class="reserved" href="zips/zip-0332.rst">Wallet Recovery from zcashd HD Seeds</a></td> <td>Reserved</td>
<tr> <td><span class="reserved">339</span></td> <td class="left"><a class="reserved" href="zips/zip-0339.rst">Wallet Recovery Words</a></td> <td>Reserved</td>
<tr> <td>400</td> <td class="left"><a href="zips/zip-0400.rst">Wallet.dat format</a></td> <td>Draft</td>
Expand Down Expand Up @@ -321,6 +322,7 @@ Index of ZIPs
<tr> <td><span class="reserved">322</span></td> <td class="left"><a class="reserved" href="zips/zip-0322.rst">Generic Signed Message Format</a></td> <td>Reserved</td>
<tr> <td><span class="reserved">323</span></td> <td class="left"><a class="reserved" href="zips/zip-0323.rst">Specification of getblocktemplate for Zcash</a></td> <td>Reserved</td>
<tr> <td>324</td> <td class="left"><a href="zips/zip-0324.rst">URI-Encapsulated Payments</a></td> <td>Draft</td>
<tr> <td>325</td> <td class="left"><a href="zips/zip-0325.md">Account Metadata Keys</a></td> <td>Draft</td>
<tr> <td><span class="reserved">332</span></td> <td class="left"><a class="reserved" href="zips/zip-0332.rst">Wallet Recovery from zcashd HD Seeds</a></td> <td>Reserved</td>
<tr> <td><span class="reserved">339</span></td> <td class="left"><a class="reserved" href="zips/zip-0339.rst">Wallet Recovery Words</a></td> <td>Reserved</td>
<tr> <td>400</td> <td class="left"><a href="zips/zip-0400.rst">Wallet.dat format</a></td> <td>Draft</td>
Expand Down
2 changes: 2 additions & 0 deletions rendered/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
<tr> <td><span class="reserved">322</span></td> <td class="left"><a class="reserved" href="zip-0322">Generic Signed Message Format</a></td> <td>Reserved</td>
<tr> <td><span class="reserved">323</span></td> <td class="left"><a class="reserved" href="zip-0323">Specification of getblocktemplate for Zcash</a></td> <td>Reserved</td>
<tr> <td>324</td> <td class="left"><a href="zip-0324">URI-Encapsulated Payments</a></td> <td>Draft</td>
<tr> <td>325</td> <td class="left"><a href="zip-0325">Account Metadata Keys</a></td> <td>Draft</td>
<tr> <td><span class="reserved">332</span></td> <td class="left"><a class="reserved" href="zip-0332">Wallet Recovery from zcashd HD Seeds</a></td> <td>Reserved</td>
<tr> <td><span class="reserved">339</span></td> <td class="left"><a class="reserved" href="zip-0339">Wallet Recovery Words</a></td> <td>Reserved</td>
<tr> <td>400</td> <td class="left"><a href="zip-0400">Wallet.dat format</a></td> <td>Draft</td>
Expand Down Expand Up @@ -257,6 +258,7 @@
<tr> <td><span class="reserved">322</span></td> <td class="left"><a class="reserved" href="zip-0322">Generic Signed Message Format</a></td> <td>Reserved</td>
<tr> <td><span class="reserved">323</span></td> <td class="left"><a class="reserved" href="zip-0323">Specification of getblocktemplate for Zcash</a></td> <td>Reserved</td>
<tr> <td>324</td> <td class="left"><a href="zip-0324">URI-Encapsulated Payments</a></td> <td>Draft</td>
<tr> <td>325</td> <td class="left"><a href="zip-0325">Account Metadata Keys</a></td> <td>Draft</td>
<tr> <td><span class="reserved">332</span></td> <td class="left"><a class="reserved" href="zip-0332">Wallet Recovery from zcashd HD Seeds</a></td> <td>Reserved</td>
<tr> <td><span class="reserved">339</span></td> <td class="left"><a class="reserved" href="zip-0339">Wallet Recovery Words</a></td> <td>Reserved</td>
<tr> <td>400</td> <td class="left"><a href="zip-0400">Wallet.dat format</a></td> <td>Draft</td>
Expand Down
241 changes: 241 additions & 0 deletions rendered/zip-0325.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
<!DOCTYPE html>
<html>
<head>
<title>ZIP 325: Account Metadata Keys</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-nB0miv6/jRmo5UMMR1wu3Gz6NLsoTkbqJghGIsx//Rlm+ZU03BU6SQNC66uf4l5+" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js" integrity="sha384-7zkQWkzuo3B5mTepMUcHkMB5jZaolc2xDwL6VFqjFALcbeS9Ggm/Yr2r3Dy4lfFg" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous" onload="renderMathInElement(document.body);"></script>
<meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="css/style.css">
</head>
<body>
<pre><code>ZIP: 325
Title: Account Metadata Keys
Owners: Jack Grigg &lt;[email protected]&gt;
Daira-Emma Hopwood &lt;[email protected]&gt;
Kris Nuttycombe &lt;[email protected]&gt;
Status: Draft
Category: Standards / Wallet
Created: 2025-02-18
License: MIT
</code></pre>

<h1 id="terminology"><span class="section-heading">Terminology</span><span class="section-anchor"> <a rel="bookmark" href="#terminology"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h1>

<p>The key words &#8220;MUST NOT&#8221;, &#8220;SHOULD&#8221;, and &#8220;MAY&#8221; in this
document are to be interpreted as described in BCP 14 <a href="#fn:1" id="fnref:1" title="see footnote" class="footnote"><sup>1</sup></a> when, and
only when, they appear in all capitals.</p>

<h1 id="abstract"><span class="section-heading">Abstract</span><span class="section-anchor"> <a rel="bookmark" href="#abstract"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h1>

<p>This ZIP specifies the key tree for Account Metadata Keys. These are derived
from the same seed as a ZIP 32 <a href="#fn:2" id="fnref:2" title="see footnote" class="footnote"><sup>2</sup></a> account, and can be used by wallets
to derive encryption keys for local / off-chain metadata.</p>

<h1 id="motivation"><span class="section-heading">Motivation</span><span class="section-anchor"> <a rel="bookmark" href="#motivation"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h1>

<p>A wallet&#8217;s main data source is the Zcash chain: from this it can detect notes
received by an account, determine whether those notes are spent, build witnesses
for spending, recover on-chain memo data, and so on. However, wallets also
generate significant quantities of off-chain metadata as they are used, such as:</p>

<ul>
<li>Local annotations about transactions in the wallet.</li>
<li>Mappings between Zcash addresses and user-meaningful recipient names.</li>
<li>The exchange rate from ZEC to another currency that was used to determine how
much ZEC to send in a payment.</li>
</ul>

<p>This metadata is valuable to users, and highly desirable to ensure to be backed up.
If the user&#8217;s device is wiped or lost and the user recovers their wallet from a
backed-up mnemonic phrase, they will lose all of this metadata if it is not
stored somewhere.</p>

<p>For other kinds of mobile device data, it is expected by users that their device&#8217;s
normal backup storage will have saved (most of) their data, such that access to
e.g. the associated Apple or Google account will be sufficient for data recovery.
However, metadata such as mappings between Zcash addresses and recipient names can
be particularly sensitive, meaning that users may not want these to be backed up
unencrypted in their device&#8217;s normal backup storage. Similarly, the inability to
alter on-chain data means that permanently storing metadata in transaction memo
fields may also not be an option.</p>

<p>Additionally, it is currently the case that users only need to back up a single
secret (a mnemonic seed phrase), once, in order to recover all information for
accounts derived from that secret. If metadata were encrypted using independent
key material, these keys would also need to be backed up, leading to fragility
of wallet restoration.</p>

<h1 id="requirements"><span class="section-heading">Requirements</span><span class="section-anchor"> <a rel="bookmark" href="#requirements"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h1>

<ul>
<li>The user should not need to update their existing backups of secret material.</li>
<li>It should be possible to store metadata about accounts for which we don&#8217;t
control spend authority (i.e. imported UFVKs).</li>
<li>The key tree must be future-extensible.</li>
</ul>

<h1 id="specification"><span class="section-heading">Specification</span><span class="section-anchor"> <a rel="bookmark" href="#specification"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h1>

<h2 id="metadatakeytree"><span class="section-heading">Metadata key tree</span><span class="section-anchor"> <a rel="bookmark" href="#metadatakeytree"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h2>

<p>This ZIP registers the following ZIP 32 Registered Key Derivation <a href="#fn:3" id="fnref:3" title="see footnote" class="footnote"><sup>3</sup></a>
tree:</p>

<ul>
<li><span class="math">\(\mathsf{ContextString} = \texttt{“MetadataKeys”}\)</span></li>
<li><span class="math">\(\mathsf{ZipNumber} = 325\)</span></li>
</ul>

<p>The tree has the following general structure, specified in more detail below:</p>

<ul>
<li><span class="math">\(m_{\mathsf{metadata}}\)</span>: Metadata Key tree</li>
<li> <span class="math">\(m_{\mathsf{metadata}} / 325' / \mathsf{coinType}' / \mathsf{account}'\)</span> - Account Metadata Key

<ul>
<li><span class="math">\(\ldots / 0'\)</span> - Account-level Inherent Metadata Key</li>
<li> <span class="math">\(\ldots / \ldots\)</span> - (Reserved for future updates to this ZIP)</li>
<li> <span class="math">\(\ldots / (\mathtt{0x7FFFFFFF}', \mathsf{PrivateUseSubject})\)</span> - Private-use Inherent Metadata Key</li>
<li><span class="math">\(\ldots / 1'\)</span> - Account-level External Metadata Key</li>
<li> <span class="math">\(\ldots / (0', \mathsf{FVKTypedItem})\)</span> - Imported UFVK Metadata Key

<ul>
<li><span class="math">\(\ldots / \ldots\)</span> - (Reserved for future updates to this ZIP)</li>
<li><span class="math">\(\ldots / (\mathtt{0x7FFFFFFF}', \mathsf{PrivateUseSubject})\)</span> - Private-use External Metadata Key</li>
</ul></li>
<li> <span class="math">\(\ldots / \ldots\)</span> - (Reserved for future updates to this ZIP)</li>
<li><span class="math">\(\ldots / \ldots\)</span> - (Reserved for future updates to this ZIP)</li>
</ul></li>
</ul>

<p>Non-leaf keys in the key tree MUST NOT be used directly to encrypt metadata.
Encryption keys are leaves in this key tree. The sole exception to this is
private-use keys (for which part of their key derivation is outside the scope of
this specification): encryption keys MAY be derived from the private-use key
leaves.</p>

<h3 id="accountmetadatakey"><span class="section-heading">Account Metadata Key</span><span class="section-anchor"> <a rel="bookmark" href="#accountmetadatakey"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h3>

<p>The Account Metadata Key is the root of a subtree that corresponds to a ZIP 32
account represented elsewhere in the overall tree. It is derived from the seed
<span class="math">\(\mathsf{S}\)</span> as:</p>

<p><span class="math">\(\mathsf{AccountMetadataKey} = \mathsf{CKDreg}(\mathsf{CKDreg}(\mathsf{RegKD}(\texttt{“MetadataKeys”}, \mathsf{S}, 325), \mathsf{coinType}, [\,]), \mathsf{account}, [\,])\)</span></p>

<p>or, in path notation:</p>

<pre><code>m_metadata / 325' / coin_type' / account'
</code></pre>

<h3 id="inherentmetadatakeys"><span class="section-heading">Inherent metadata keys</span><span class="section-anchor"> <a rel="bookmark" href="#inherentmetadatakeys"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h3>

<p>The Account-level Inherent Metadata Key&#8217;s subtree contains keys used for
metadata associated with the Account Metadata Key&#8217;s corresponding account. The
key is derived as:</p>

<p><span class="math">\(\mathsf{CKDreg}(\mathsf{AccountMetadataKey}, 0, [\,])\)</span></p>

<h3 id="externalmetadatakeys"><span class="section-heading">External metadata keys</span><span class="section-anchor"> <a rel="bookmark" href="#externalmetadatakeys"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h3>

<p>The Account-level External Metadata Key&#8217;s subtree contains keys used for
metadata associated with imported UFVKs. Unlike the inherent metadata keys which
can leverage the inherent domain separation provided by the account index, here
domain separation between metadata keys is provided by the UFVKs themselves.</p>

<p>As UFVKs may in general change over time (due to the inclusion of new
higher-preference FVK items, or removal of older deprecated FVK items), there is
no guarantee that the exact same set of FVK items will be present at both backup
creation time and recovery time. Instead, the most preferred FVK item within a
UFVK is used as the domain in which keys can be generated, and the Imported
UFVK Metadata Key is derived as:</p>

<p><span class="math">\(\mathsf{CKDreg}(\mathsf{CKDreg}(\mathsf{AccountMetadataKey}, 1, [\,]), 0, \mathsf{FVKTypedItem})\)</span></p>

<p>where <span class="math">\(\mathsf{FVKTypedItem}\)</span> is the encoding of the most preferred FVK
item within the ZIP 316 raw encoding of a UFVK. <a href="#fn:4" id="fnref:4" title="see footnote" class="footnote"><sup>4</sup></a></p>

<p>Usage of the Imported UFVK Metadata Key trees SHOULD follow ZIP 316 preference
order: <a href="#fn:4" title="see footnote" class="footnote"><sup>4</sup></a></p>

<ul>
<li>For encryption-like usage, the key tree corresponding to the most preferred
FVK item within a UFVK SHOULD be used.</li>
<li>For decryption-like usage, each key tree SHOULD be tried in preference order
until metadata can be recovered. If metadata is recovered via an FVK item that
is not the most preferred, wallets SHOULD update their metadata backups by
re-encrypting the metadata using the key tree corresponding to the most
preferred FVK item.</li>
</ul>

<h2 id="standardisedmetadataprotocols"><span class="section-heading">Standardised metadata protocols</span><span class="section-anchor"> <a rel="bookmark" href="#standardisedmetadataprotocols"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h2>

<p>The following metadata protocols have been standardised:</p>

<ul>
<li>None at time of writing.</li>
</ul>

<p>The remaining range of child indices from 0 to <span class="math">\(\texttt{0x7FFFFFFE}\)</span> inclusive
are reserved for future updates to this ZIP. Wallet developers can propose new
standardised metadata protocols by writing a 2000-series ZIP that specifies the
protocol as an update to this ZIP.</p>

<h2 id="private-usemetadatakeys"><span class="section-heading">Private-use metadata keys</span><span class="section-anchor"> <a rel="bookmark" href="#private-usemetadatakeys"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h2>

<p>In some contexts there is a need for deriving ad-hoc key trees for private use
by wallets, without ecosystem coordination and without any kind of compatibility
guarantees. This ZIP reserves child index <span class="math">\(\mathtt{0x7FFFFFFF}\)</span> (the maximum
valid hardened child index) within its key tree for this purpose.</p>

<ul>
<li>Let <span class="math">\(K\)</span> be either the Account-level Inherent Metadata Key, or an Imported UFVK
Metadata Key.</li>
<li>Let <span class="math">\(\mathsf{PrivateUseSubject}\)</span> be a globally unique non-empty sequence of at
most 252 bytes that identifies the desired private-use context.</li>
<li>Return <span class="math">\(\mathsf{CKDreg}(K, \mathtt{0x7FFFFFFF}, \mathsf{PrivateUseSubject})\)</span></li>
</ul>

<p>:::warning
It is the responsibility of wallet developers to ensure that they do not use
colliding <span class="math">\(\mathsf{PrivateUseSubject}\)</span> values, and to analyse their private use for
any security risks related to potential cross-protocol attacks (in the event that
two wallet developers happen to select a colliding <span class="math">\(\mathsf{PrivateUseSubject}\)</span>).
Wallet developers that are unwilling to accept these risks SHOULD propose new
standardised metadata protocols instead, to benefit from ecosystem coordination
and review.
:::
</p>

<h1 id="referenceimplementation"><span class="section-heading">Reference implementation</span><span class="section-anchor"> <a rel="bookmark" href="#referenceimplementation"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h1>

<ul>
<li>https://github.com/Electric-Coin-Company/zcash-android-wallet-sdk/pull/1686</li>
</ul>

<h1 id="references"><span class="section-heading">References</span><span class="section-anchor"> <a rel="bookmark" href="#references"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h1>

<div class="footnotes">
<hr />
<ol>

<li id="fn:1">
<p><a href="https://www.rfc-editor.org/info/bcp14">Information on BCP 14 — &#8220;RFC 2119: Key words for use in RFCs to Indicate Requirement Levels&#8221; and &#8220;RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&#8221;</a> <a href="#fnref:1" title="return to body" class="reversefootnote">&#160;&#8617;&#xfe0e;</a></p>
</li>

<li id="fn:2">
<p><a href="zip-0032">ZIP 32: Shielded Hierarchical Deterministic Wallets</a> <a href="#fnref:2" title="return to body" class="reversefootnote">&#160;&#8617;&#xfe0e;</a></p>
</li>

<li id="fn:3">
<p><a href="zip-0032#specification-registered-key-derivation">ZIP 32: Shielded Hierarchical Deterministic Wallets, Section: Registered key derivation</a> <a href="#fnref:3" title="return to body" class="reversefootnote">&#160;&#8617;&#xfe0e;</a></p>
</li>

<li id="fn:4">
<p><a href="zip-0316">ZIP 316: Unified Addresses and Unified Viewing Keys</a> <a href="#fnref:4" title="return to body" class="reversefootnote">&#160;&#8617;&#xfe0e;</a></p>
</li>

</ol>
</div>
</body>
</html>
Loading

0 comments on commit eda6d41

Please sign in to comment.