zips/zip-0304.html

436 lines
30 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<title>ZIP 304: Sapling Address Signatures</title>
<meta charset="utf-8" />
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js?config=TeX-AMS-MML_HTMLorMML"></script>
<meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="css/style.css"></head>
<body>
<section>
<pre>ZIP: 304
Title: Sapling Address Signatures
Owners: Jack Grigg &lt;jack@electriccoin.co&gt;
Credits: Daira Hopwood &lt;daira@electriccoin.co&gt;
Sean Bowe &lt;sean@electriccoin.co&gt;
Status: Draft
Category: Standards / RPC / Wallet
Created: 2020-06-01
License: MIT
Discussions-To: &lt;<a href="https://github.com/zcash/zips/issues/345">https://github.com/zcash/zips/issues/345</a>&gt;
Pull-Request: &lt;<a href="https://github.com/zcash/zips/pull/376">https://github.com/zcash/zips/pull/376</a>&gt;</pre>
<section id="terminology"><h2><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></h2>
<p>The key words "MUST" and "SHOULD" in this document is to be interpreted as described in RFC 2119. <a id="id1" class="footnote_reference" href="#rfc2119">1</a></p>
</section>
<section id="abstract"><h2><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></h2>
<p>This proposal describes a mechanism for creating signatures with Sapling addresses, suitable for use by the <code>signmessage</code> and <code>verifymessage</code> RPC methods in <code>zcashd</code>.</p>
</section>
<section id="motivation"><h2><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></h2>
<p>There are a variety of situations where it is useful for a user to be able to prove that they control a given payment address. For example, before a high-value transfer of funds, the sender may want to verify that the recipient will definitely be able to spend them, to ensure that the funds won't be stuck in an invalid or unusable address.</p>
<p>A payment address is analogous (in some cases, identical) to a public key in a signature scheme. A transaction that spends funds received by the address, is authorized by making (the equivalent of) a signature with the corresponding spending key. This authorization protocol can be repurposed to instead sign a message provided by a third party.</p>
<p>Bitcoin Core's <code>bitcoind</code> provides a <code>signmessage</code> RPC method that implements message signing for Bitcoin addresses, leveraging the fact that a Bitcoin private key is just a <code>secp256k</code> private key, and a Bitcoin transaction authorizes spends with a signature. <code>zcashd</code> inherited this RPC method, and it can be used to make signatures for transparent Zcash addresses.</p>
<p>However, support for signing messages with shielded addresses was not possible when Zcash launched, because of the design of the Sprout protocol (and the state of zero-knowledge proof R&amp;D at the time). Shielded transactions, by design, do not expose the payment address of the sender when creating a transaction; in Sprout, this meant that the spending key was a private input to the zero-knowledge proof, and not a key that could be used to create a signature.</p>
<p>One of the R&amp;D achievements behind the Sapling protocol was the ability to use elliptic curves inside a circuit. With this primitive available, Sapling keys and payment addresses could be designed such that transaction authorization involved a signature. While this was designed to enable hardware wallets (which lack the power to create zero-knowledge proofs, but can easily create signatures), it also enables the creation of a mechanism for signing arbitrary messages. That mechanism is the subject of this ZIP.</p>
</section>
<section id="conventions"><h2><span class="section-heading">Conventions</span><span class="section-anchor"> <a rel="bookmark" href="#conventions"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h2>
<p>The following constants and functions used in this ZIP are defined in the Zcash protocol specification: <a id="id2" class="footnote_reference" href="#protocol">3</a></p>
<ul>
<li>
<span class="math">\(\mathsf{MerkleDepth}^\mathsf{Sapling}\)</span>
and
<span class="math">\(\mathsf{Uncommitted}^\mathsf{Sapling}\)</span>
<a id="id3" class="footnote_reference" href="#protocol-constants">6</a></li>
<li>
<span class="math">\(\mathsf{MerkleCRH}^\mathsf{Sapling}\)</span>
<a id="id4" class="footnote_reference" href="#protocol-saplingmerklecrh">7</a></li>
<li>
<span class="math">\(\mathsf{DiversifyHash}(\mathsf{d})\)</span>
<a id="id5" class="footnote_reference" href="#protocol-concretediversifyhash">8</a></li>
<li>
<span class="math">\(\mathsf{MixingPedersenHash}(\mathsf{cm}, position)\)</span>
<a id="id6" class="footnote_reference" href="#protocol-concretemixinghash">9</a></li>
<li>
<span class="math">\(\mathsf{PRF}^\mathsf{nfSapling}_\mathsf{nk}(ρ)\)</span>
<a id="id7" class="footnote_reference" href="#protocol-concreteprfs">10</a></li>
<li>
<span class="math">\(\mathsf{SpendAuthSig.RandomizePrivate}(α, \mathsf{sk})\)</span>
,
<span class="math">\(\mathsf{SpendAuthSig.RandomizePublic}(α, \mathsf{vk})\)</span>
,
<span class="math">\(\mathsf{SpendAuthSig.Sign}(\mathsf{sk}, m)\)</span>
, and
<span class="math">\(\mathsf{SpendAuthSig.Verify}(\mathsf{vk}, m, σ)\)</span>
<a id="id8" class="footnote_reference" href="#protocol-concretespendauthsig">11</a></li>
<li>
<span class="math">\(\mathsf{NoteCommit}^\mathsf{Sapling}_\mathsf{rcm}(\mathsf{g_d}, \mathsf{pk_d}, value)\)</span>
<a id="id9" class="footnote_reference" href="#protocol-concretewindowedcommit">12</a></li>
<li>
<span class="math">\(\mathsf{ValueCommit}_\mathsf{rcv}(value)\)</span>
<a id="id10" class="footnote_reference" href="#protocol-concretehomomorphiccommit">13</a></li>
</ul>
<p>We also reproduce some notation and functions here for convenience:</p>
<ul>
<li>
<span class="math">\(a\,||\,b\)</span>
means the concatenation of sequences
<span class="math">\(a\)</span>
then
<span class="math">\(b\)</span>
.</li>
<li>
<span class="math">\(\mathsf{repr}_\mathbb{J}(P)\)</span>
is the representation of the Jubjub elliptic curve point
<span class="math">\(P\)</span>
as a bit sequence, defined in <a id="id11" class="footnote_reference" href="#protocol-jubjub">14</a>.</li>
<li>
<span class="math">\(\mathsf{BLAKE2b}\text{-}\mathsf{256}(p, x)\)</span>
refers to unkeyed BLAKE2b-256 in sequential mode, with an output digest length of 32 bytes, 16-byte personalization string
<span class="math">\(p\)</span>
, and input
<span class="math">\(x\)</span>
.</li>
</ul>
</section>
<section id="requirements"><h2><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></h2>
<p>Given a payment address, a message, and a valid signature, the following properties should hold:</p>
<ul>
<li><strong>Authentication:</strong> the signature will not verify with any other payment address.</li>
<li><strong>Binding:</strong> the signature will not verify with any modification, extension, or truncation of the message.</li>
<li><strong>Non-malleability:</strong> it should not be possible to obtain a second valid signature (with a different encoding) for the same payment address and message without access to the spending key for that payment address.</li>
</ul>
</section>
<section id="non-requirements"><h2><span class="section-heading">Non-requirements</span><span class="section-anchor"> <a rel="bookmark" href="#non-requirements"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h2>
<p>Multiple signatures by a single payment addresses are not required to be unlinkable.</p>
</section>
<section id="specification"><h2><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></h2>
<p>A Sapling address signature is created by taking the process for creating a Sapling Spend description, and running it with fixed inputs:</p>
<ul>
<li>A fake Sapling note with a value of
<span class="math">\(1\)</span>
zatoshi and
<span class="math">\(\mathsf{rcm} = 0\)</span>
.</li>
<li>A Sapling commitment tree that is empty except for the commitment for the fake note.</li>
</ul>
<section id="signature-algorithm"><h3><span class="section-heading">Signature algorithm</span><span class="section-anchor"> <a rel="bookmark" href="#signature-algorithm"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h3>
<p>The inputs to the signature algorithm are:</p>
<ul>
<li>The payment address
<span class="math">\((\mathsf{d}, \mathsf{pk_d})\)</span>
,</li>
<li>Its corresponding expanded spending key
<span class="math">\((\mathsf{ask}, \mathsf{nsk}, \mathsf{ovk})\)</span>
,</li>
<li>The SLIP-44 <a id="id12" class="footnote_reference" href="#slip-0044">15</a> coin type, and</li>
<li>The message
<span class="math">\(msg\)</span>
to be signed.</li>
</ul>
<p>The signature is created as follows:</p>
<ul>
<li>Derive the full viewing key
<span class="math">\((\mathsf{ak}, \mathsf{nk}, \mathsf{ovk})\)</span>
from the expanded spending key.</li>
<li>Let
<span class="math">\(\mathsf{g_d} = \mathsf{DiversifyHash}(\mathsf{d})\)</span>
.</li>
<li>Let
<span class="math">\(\mathsf{cm} = \mathsf{NoteCommit}^\mathsf{Sapling}_0(\mathsf{repr}_\mathbb{J}(\mathsf{g_d}), \mathsf{repr}_\mathbb{J}(\mathsf{pk_d}), 1)\)</span>
.</li>
<li>Let
<span class="math">\(\mathsf{rt}\)</span>
be the root of a Merkle tree with depth
<span class="math">\(\mathsf{MerkleDepth}^\mathsf{Sapling}\)</span>
and hashing function
<span class="math">\(\mathsf{MerkleCRH}^\mathsf{Sapling}\)</span>
, containing
<span class="math">\(\mathsf{cm}\)</span>
at position 0, and
<span class="math">\(\mathsf{Uncommitted}^\mathsf{Sapling}\)</span>
at all other positions.</li>
<li>Let
<span class="math">\(path\)</span>
be the Merkle path from position 0 to
<span class="math">\(\mathsf{rt}\)</span>
. <a id="id13" class="footnote_reference" href="#protocol-merklepath">4</a></li>
<li>Let
<span class="math">\(\mathsf{cv} = \mathsf{ValueCommit}_0(1)\)</span>
.
<ul>
<li>This is a constant and may be pre-computed.</li>
</ul>
</li>
<li>Let
<span class="math">\(\mathsf{nf} = \mathsf{PRF}^\mathsf{nfSapling}_{\mathsf{repr}_\mathbb{J}(\mathsf{nk})}(\mathsf{repr}_\mathbb{J}(\mathsf{MixingPedersenHash}(\mathsf{cm}, 0)))\)</span>
.</li>
<li>Select a random
<span class="math">\(α\)</span>
.</li>
<li>Let
<span class="math">\(\mathsf{rk} = \mathsf{SpendAuthSig.RandomizePublic}(α, \mathsf{ak})\)</span>
.</li>
<li>Let
<span class="math">\(zkproof\)</span>
be the byte sequence representation of a Sapling spend proof with primary input
<span class="math">\((\mathsf{rt}, \mathsf{cv}, \mathsf{nf}, \mathsf{rk})\)</span>
and auxiliary input
<span class="math">\((path, 0, \mathsf{g_d}, \mathsf{pk_d}, 1, 0, \mathsf{cm}, 0, α, \mathsf{ak}, \mathsf{nsk})\)</span>
. <a id="id14" class="footnote_reference" href="#protocol-spendstatement">5</a></li>
<li>Let
<span class="math">\(\mathsf{rsk} = \mathsf{SpendAuthSig.RandomizePrivate}(α, \mathsf{ask})\)</span>
.</li>
<li>Let
<span class="math">\(coinType\)</span>
be the 4-byte little-endian encoding of the coin type in its index form, not its hardened form (i.e. 133 for mainnet Zcash).</li>
<li>Let
<span class="math">\(digest = \mathsf{BLAKE2b}\text{-}\mathsf{256}(\texttt{"ZIP304Signed"}\,||\,coinType, zkproof\,||\,msg)\)</span>
.</li>
<li>Let
<span class="math">\(spendAuthSig = \mathsf{SpendAuthSig.Sign}(\mathsf{rsk}, digest)\)</span>
.</li>
<li>Return
<span class="math">\((\mathsf{nf}, \mathsf{rk}, zkproof, spendAuthSig)\)</span>
.</li>
</ul>
</section>
<section id="verification-algorithm"><h3><span class="section-heading">Verification algorithm</span><span class="section-anchor"> <a rel="bookmark" href="#verification-algorithm"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h3>
<p>The inputs to the verification algorithm are:</p>
<ul>
<li>The payment address
<span class="math">\((\mathsf{d}, \mathsf{pk_d})\)</span>
,</li>
<li>The SLIP-44 <a id="id15" class="footnote_reference" href="#slip-0044">15</a> coin type,</li>
<li>The message
<span class="math">\(msg\)</span>
that is claimed to be signed, and</li>
<li>The ZIP 304 signature
<span class="math">\((\mathsf{nf}, \mathsf{rk}, zkproof, spendAuthSig)\)</span>
.</li>
</ul>
<p>The signature MUST be verified as follows:</p>
<ul>
<li>Let
<span class="math">\(coinType\)</span>
be the 4-byte little-endian encoding of the coin type in its index form, not its hardened form (i.e. 133 for mainnet Zcash).</li>
<li>Let
<span class="math">\(digest = \mathsf{BLAKE2b}\text{-}\mathsf{256}(\texttt{"ZIP304Signed"}\,||\,coinType, zkproof\,||\,msg)\)</span>
.</li>
<li>If
<span class="math">\(\mathsf{SpendAuthSig.Verify}(\mathsf{rk}, digest, spendAuthSig) = 0\)</span>
, return false.</li>
<li>Let
<span class="math">\(\mathsf{cm} = \mathsf{NoteCommit}^\mathsf{Sapling}_0(\mathsf{repr}_\mathbb{J}(\mathsf{DiversifyHash}(\mathsf{d})), \mathsf{repr}_\mathbb{J}(\mathsf{pk_d}), 1)\)</span>
.</li>
<li>Let
<span class="math">\(\mathsf{rt}\)</span>
be the root of a Merkle tree with depth
<span class="math">\(\mathsf{MerkleDepth}^\mathsf{Sapling}\)</span>
and hashing function
<span class="math">\(\mathsf{MerkleCRH}^\mathsf{Sapling}\)</span>
, containing
<span class="math">\(\mathsf{cm}\)</span>
at position 0, and
<span class="math">\(\mathsf{Uncommitted}^\mathsf{Sapling}\)</span>
at all other positions.</li>
<li>Let
<span class="math">\(path\)</span>
be the Merkle path from position 0 to
<span class="math">\(\mathsf{rt}\)</span>
. <a id="id16" class="footnote_reference" href="#protocol-merklepath">4</a></li>
<li>Let
<span class="math">\(\mathsf{cv} = \mathsf{ValueCommit}_0(1)\)</span>
.
<ul>
<li>This is a constant and may be pre-computed.</li>
</ul>
</li>
<li>Decode and verify
<span class="math">\(zkproof\)</span>
as a Sapling spend proof with primary input
<span class="math">\((\mathsf{rt}, \mathsf{cv}, \mathsf{nf}, \mathsf{rk})\)</span>
. <a id="id17" class="footnote_reference" href="#protocol-spendstatement">5</a> If verification fails, return false.</li>
<li>Return true.</li>
</ul>
</section>
<section id="signature-encoding"><h3><span class="section-heading">Signature encoding</span><span class="section-anchor"> <a rel="bookmark" href="#signature-encoding"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h3>
<p>The raw form of a ZIP 304 signature is
<span class="math">\(\mathsf{nf}\,||\,\mathsf{LEBS2OSP}_{256}(\mathsf{repr}_{\mathbb{J}}(\mathsf{rk}))\,||\,zkproof\,||\,spendAuthSig\)</span>
, for a total size of 320 bytes.</p>
<p>When encoding a ZIP 304 signature in a human-readable format, implementations <strong>SHOULD</strong> use standard Base64 for compatibility with the <code>signmessage</code> and <code>verifymessage</code> RPC methods in <code>zcashd</code>. ZIP 304 signatures in this form are 428 bytes. The encoded form is the string
<span class="math">\(\texttt{"zip304:"}\)</span>
followed by the result of Base64-encoding <a id="id18" class="footnote_reference" href="#rfc4648">2</a> the raw form of the signature.</p>
</section>
</section>
<section id="rationale"><h2><span class="section-heading">Rationale</span><span class="section-anchor"> <a rel="bookmark" href="#rationale"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h2>
<p>We use a fake note within the signature scheme in order to reuse the Sapling Spend circuit and its parameters. It is possible to construct a signature scheme with a smaller encoded signature, but this would require a new circuit and another parameter-generation ceremony (if Groth16 were used).</p>
<p>We use a note value of
<span class="math">\(1\)</span>
zatoshi instead of zero to ensure that the payment address is fully bound to
<span class="math">\(zkproof\)</span>
. Notes with zero value have certain constraints disabled inside the circuit.</p>
<p>We set
<span class="math">\(\mathsf{rcm}\)</span>
and
<span class="math">\(\mathsf{rcv}\)</span>
to zero because we do not need the hiding properties of the note commitment or value commitment schemes (as we are using a fixed-value fake note), and can thus omit both
<span class="math">\(\mathsf{rcm}\)</span>
and
<span class="math">\(\mathsf{rcv}\)</span>
from the signature.</p>
</section>
<section id="security-and-privacy-considerations"><h2><span class="section-heading">Security and Privacy Considerations</span><span class="section-anchor"> <a rel="bookmark" href="#security-and-privacy-considerations"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h2>
<p>A normal (and desired) property of signature schemes is that all signatures for a specific public key are linkable if the public key is known. ZIP 304 signatures have the additional property that all signatures for a specific payment address are linkable without knowing the payment address, as the first 32 bytes of each signature will be identical.</p>
<p>A signature is bound to a specific diversified address of the spending key. Signatures for different diversified addresses of the same spending key are unlinkable, as long as
<span class="math">\(α\)</span>
is never re-used across signatures.</p>
<p>Most of the data within a ZIP 304 signature is inherently non-malleable:</p>
<ul>
<li>
<span class="math">\(\mathsf{nf}\)</span>
is a binary public input to
<span class="math">\(zkproof\)</span>
.</li>
<li>
<span class="math">\(\mathsf{rk}\)</span>
is internally bound to
<span class="math">\(spendAuthSig\)</span>
by the design of RedJubjub.</li>
<li>RedJubjub signatures are themselves non-malleable.</li>
</ul>
<p>The one component that is inherently malleable is
<span class="math">\(zkproof\)</span>
. The zero-knowledge property of a Groth16 proof implies that anyone can take a valid proof, and re-randomize it to obtain another valid proof with a different encoding. We prevent this by binding the encoding of
<span class="math">\(zkproof\)</span>
to
<span class="math">\(spendAuthSig\)</span>
, by including
<span class="math">\(zkproof\)</span>
in the message digest.</p>
</section>
<section id="reference-implementation"><h2><span class="section-heading">Reference implementation</span><span class="section-anchor"> <a rel="bookmark" href="#reference-implementation"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h2>
<p><a href="https://github.com/zcash/librustzcash/pull/210">https://github.com/zcash/librustzcash/pull/210</a></p>
</section>
<section id="references"><h2><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></h2>
<table id="rfc2119" class="footnote">
<tbody>
<tr>
<th>1</th>
<td><a href="https://www.rfc-editor.org/rfc/rfc2119.html">RFC 2119: Key words for use in RFCs to Indicate Requirement Levels</a></td>
</tr>
</tbody>
</table>
<table id="rfc4648" class="footnote">
<tbody>
<tr>
<th>2</th>
<td><a href="https://www.rfc-editor.org/rfc/rfc4648">RFC 4648: The Base16, Base32, and Base64 Data Encodings</a></td>
</tr>
</tbody>
</table>
<table id="protocol" class="footnote">
<tbody>
<tr>
<th>3</th>
<td><a href="protocol/protocol.pdf">Zcash Protocol Specification, Version 2020.1.15 or later</a></td>
</tr>
</tbody>
</table>
<table id="protocol-merklepath" class="footnote">
<tbody>
<tr>
<th>4</th>
<td><a href="protocol/protocol.pdf#merklepath">Zcash Protocol Specification, Version 2020.1.15. Section 4.8: Merkle path validity</a></td>
</tr>
</tbody>
</table>
<table id="protocol-spendstatement" class="footnote">
<tbody>
<tr>
<th>5</th>
<td><a href="protocol/protocol.pdf#spendstatement">Zcash Protocol Specification, Version 2020.1.15. Section 4.15.2: Spend Statement (Sapling)</a></td>
</tr>
</tbody>
</table>
<table id="protocol-constants" class="footnote">
<tbody>
<tr>
<th>6</th>
<td><a href="protocol/protocol.pdf#constants">Zcash Protocol Specification, Version 2020.1.15. Section 5.3: Constants</a></td>
</tr>
</tbody>
</table>
<table id="protocol-saplingmerklecrh" class="footnote">
<tbody>
<tr>
<th>7</th>
<td><a href="protocol/protocol.pdf#saplingmerklecrh">Zcash Protocol Specification, Version 2020.1.15. Section 5.4.1.3: Merkle Tree Hash Function</a></td>
</tr>
</tbody>
</table>
<table id="protocol-concretediversifyhash" class="footnote">
<tbody>
<tr>
<th>8</th>
<td><a href="protocol/protocol.pdf#concretediversifyhash">Zcash Protocol Specification, Version 2020.1.15. Section 5.4.1.6: DiversifyHash Hash Function</a></td>
</tr>
</tbody>
</table>
<table id="protocol-concretemixinghash" class="footnote">
<tbody>
<tr>
<th>9</th>
<td><a href="protocol/protocol.pdf#concretemixinghash">Zcash Protocol Specification, Version 2020.1.15. Section 5.4.1.8: Mixing Pedersen Hash Function</a></td>
</tr>
</tbody>
</table>
<table id="protocol-concreteprfs" class="footnote">
<tbody>
<tr>
<th>10</th>
<td><a href="protocol/protocol.pdf#concreteprfs">Zcash Protocol Specification, Version 2020.1.15. Section 5.4.2: Pseudo Random Functions</a></td>
</tr>
</tbody>
</table>
<table id="protocol-concretespendauthsig" class="footnote">
<tbody>
<tr>
<th>11</th>
<td><a href="protocol/protocol.pdf#concretespendauthsig">Zcash Protocol Specification, Version 2020.1.15. Section 5.4.6.1: Spend Authorization Signature</a></td>
</tr>
</tbody>
</table>
<table id="protocol-concretewindowedcommit" class="footnote">
<tbody>
<tr>
<th>12</th>
<td><a href="protocol/protocol.pdf#concretewindowedcommit">Zcash Protocol Specification, Version 2020.1.15. Section 5.4.7.2: Windowed Pedersen commitments</a></td>
</tr>
</tbody>
</table>
<table id="protocol-concretehomomorphiccommit" class="footnote">
<tbody>
<tr>
<th>13</th>
<td><a href="protocol/protocol.pdf#concretehomomorphiccommit">Zcash Protocol Specification, Version 2020.1.15. Section 5.4.7.3: Homomorphic Pedersen commitments</a></td>
</tr>
</tbody>
</table>
<table id="protocol-jubjub" class="footnote">
<tbody>
<tr>
<th>14</th>
<td><a href="protocol/protocol.pdf#jubjub">Zcash Protocol Specification, Version 2020.1.15. Section 5.4.8.3: Jubjub</a></td>
</tr>
</tbody>
</table>
<table id="slip-0044" class="footnote">
<tbody>
<tr>
<th>15</th>
<td><a href="https://github.com/satoshilabs/slips/blob/master/slip-0044.md">SLIP-0044 : Registered coin types for BIP-0044</a></td>
</tr>
</tbody>
</table>
</section>
</section>
</body>
</html>