Compare commits

...

45 Commits

Author SHA1 Message Date
Conrado Gouvea 8b800d1ba2
Merge 51dd721dd8 into 5273fc9c99 2024-04-23 01:10:28 -07:00
Daira-Emma Hopwood 5273fc9c99
Merge pull request #796 from zcash/dependabot/github_actions/actions/checkout-4.1.2
Bump actions/checkout from 4.1.1 to 4.1.2
2024-04-14 17:18:22 +01:00
dependabot[bot] bf6c166940
Bump actions/checkout from 4.1.1 to 4.1.2
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.1 to 4.1.2.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4.1.1...v4.1.2)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-14 16:17:28 +00:00
Daira-Emma Hopwood 2e9272e850
Merge pull request #711 from AArnott/workflow
Fix and rename GitHub Action workflow
2024-04-14 15:47:30 +01:00
Conrado Gouvea 51dd721dd8
Apply suggestions from code review
Co-authored-by: Daira-Emma Hopwood <daira@jacaranda.org>
2024-02-09 14:19:42 -03:00
Conrado Gouvea 28fd4209a1 rephrase abstract 2024-01-15 12:10:32 -03:00
github-actions 6a0a93c020 Commit from GitHub Actions (Build tex and rst) 2024-01-06 20:57:42 +00:00
Andrew Arnott 250425e54a
Drop PR trigger
The git push at the end didn't have permission to push back to the source repo, even if the PR author granted permission for contributors to push to the source branch.
2024-01-06 13:48:56 -07:00
Andrew Arnott b8ba2282c2
Fix and rename GitHub Action workflow
This gets the Dockerfile behind the render workflow to build again.

I also renamed the workflow because it described only building the PDF, but it also builds all the .html files.
2024-01-06 13:35:22 -07:00
Conrado Gouvea c9e2a854d3 update HTML 2023-12-20 18:16:42 -03:00
Conrado Gouvea 201857978d generate a random buffer instead of serializing a random scalar 2023-12-20 18:13:37 -03:00
Conrado Gouvea eecee7c9d9
Apply suggestions from code review
Co-authored-by: Daira Emma Hopwood <daira@jacaranda.org>
2023-12-07 19:03:51 -03:00
Conrado Gouvea b441df0745 hash signing package in randomizer generator; overall adjustments 2023-09-18 18:47:17 -03:00
Conrado Gouvea c0c16432a4 update with simplified design 2023-08-21 18:22:26 -03:00
Conrado Gouvea e2c611d2cb Merge remote-tracking branch 'upstream/main' into zip-frost 2023-08-21 18:21:40 -03:00
Conrado Gouvea 7bffa045d6 rename randomizer_point to randomizer_commitment 2023-02-09 19:57:00 -03:00
Deirdre Connolly 1c837a2450
Update zip-0312.rst 2023-02-07 12:34:17 -05:00
Deirdre Connolly 91573df230
Update zip-0312.rst 2023-02-07 12:31:45 -05:00
Deirdre Connolly 9512ead14c
Update zip-0312.rst 2023-02-07 12:30:05 -05:00
Conrado Gouvea 8836e22610 add initial Rationale section 2023-01-16 19:20:31 -03:00
Conrado Gouvea 8fa30b0f44
Apply suggestions from code review
Co-authored-by: Daira Hopwood <daira@jacaranda.org>
2023-01-16 19:03:20 -03:00
Conrado Gouvea bc16e533af add lines about signature verification in each ciphersuite 2023-01-13 17:54:29 -03:00
Conrado Gouvea f72d8cdb5d address multiple comments 2023-01-13 17:07:41 -03:00
Conrado Gouvea 564642f1ff
Apply suggestions from code review
Co-authored-by: Daira Hopwood <daira@jacaranda.org>
2023-01-13 11:07:56 -03:00
Conrado Gouvea 115f2caac8
Apply suggestions from code review
Co-authored-by: Daira Hopwood <daira@jacaranda.org>
2023-01-12 14:12:36 -03:00
Conrado Gouvea 48f8c2c80e rename to zip-312.rst 2023-01-12 11:42:26 -03:00
Conrado Gouvea bf9edbd0ef Clean up header 2023-01-12 11:37:57 -03:00
Conrado Gouvea a7fd12c00d
Apply suggestions from code review
Co-authored-by: Daira Hopwood <daira@jacaranda.org>
2023-01-11 19:25:08 -03:00
Conrado Gouvea 5183e06b2f update to last RFC version 2023-01-10 18:39:53 -03:00
Conrado Gouvea b2e5634248 small fixes 2022-10-21 16:28:43 -03:00
Conrado Gouvea 8740dce550 update to v11 2022-10-13 17:07:27 -03:00
Conrado Gouvea d2d315f012 send randomizer point instead of randomizer 2022-08-29 15:06:21 -03:00
Conrado Gouvea f1058ccfa9 update to spec V8 2022-08-25 20:10:09 -03:00
Conrado Gouvea 1342ead71a make explicit that key share holders can break unlinkability 2022-07-22 14:45:20 -03:00
Conrado Gouvea 80a22f4010 addressed comments from ZIP sync 2022-07-21 22:00:23 -03:00
Conrado Gouvea 665acefc63
Apply suggestions from code review
Co-authored-by: teor <teor@riseup.net>
2022-07-21 19:24:47 -03:00
Deirdre Connolly 8ba6cfb314
RedPallas s/Sapling/Orchard/ 2022-07-20 18:16:16 -04:00
Deirdre Connolly fe882e9c27
Update zip-frost.rst
Co-authored-by: teor <teor@riseup.net>
2022-07-20 17:48:59 -04:00
Conrado Gouvea d420223db8 fix formula in verify_signature_share(), to match sign() 2022-07-18 15:03:44 -03:00
Conrado Gouvea 3a96a2f75b Fixed threat model; cleaning up; added references 2022-07-15 18:38:08 -03:00
Conrado Gouvea 54dbd57d76 fix randomized_group_public_key computation 2022-07-11 11:55:21 -03:00
Conrado Gouvea cf19f23f4f fix formulas; address comments 2022-07-08 18:28:26 -03:00
Conrado Gouvea 8cbfddaba5
Apply suggestions from code review
Co-authored-by: Deirdre Connolly <durumcrustulum@gmail.com>
2022-07-08 12:20:27 -03:00
Conrado Gouvea 30f9a09904 make context string the right length 2022-07-06 14:04:12 -03:00
Conrado Gouvea 7d2b7940e9 WIP 2022-07-05 19:11:42 -03:00
13 changed files with 876 additions and 26 deletions

View File

@ -1 +0,0 @@
../../../Dockerfile

View File

@ -1,7 +0,0 @@
name: Render Zcash Protocol Specification
description: GitHub Action to compile Zcash Protocol Specification LaTeX documents
author: Deirdre Connolly
runs:
using: docker
# Runs `make all` or something like it
image: Dockerfile

7
.github/actions/render/action.yml vendored Normal file
View File

@ -0,0 +1,7 @@
name: Render ZIPs and Zcash Protocol Specification
description: GitHub Action to compile ZIPs and Zcash Protocol Specification LaTeX documents
author: Deirdre Connolly
runs:
using: docker
# Runs `make all` or something like it
image: ../../../Dockerfile

View File

@ -1,19 +1,23 @@
name: Render pdfs
name: Build tex and rst
on: workflow_dispatch
on:
workflow_dispatch:
push:
branches:
- main
jobs:
render:
runs-on: ubuntu-latest
steps:
- name: Set up Git repository
uses: actions/checkout@v4.1.1
- name: Checkout repository
uses: actions/checkout@v4.1.2
- name: Compile Zcash Protocol Specification
uses: ./.github/actions/render-protocol-pdf
- name: Compile ZIPs and Zcash Protocol Specification
uses: ./.github/actions/render
- uses: EndBug/add-and-commit@v9.1.3
with:
add: '**/*.pdf'
add: 'protocol/*.pdf *.html'
default_author: github_actions

View File

@ -1,7 +1,7 @@
FROM debian:latest
RUN apt-get update \
&& apt-get install -y \
RUN apt-get update
RUN apt-get install -y \
gawk \
perl \
sed \
@ -17,7 +17,10 @@ RUN apt-get update \
texlive-plain-generic \
texlive-bibtex-extra
RUN pip3 install rst2html5
RUN rm /usr/lib/python3.11/EXTERNALLY-MANAGED
RUN pip install rst2html5
ENV PATH=${PATH}:/root/.local/bin
WORKDIR "/zips"
ENTRYPOINT ["make", "all"]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,16 +1,416 @@
<!DOCTYPE html>
<html>
<head>
<title>ZIP 312: Shielded Multisignatures using FROST</title>
<title>ZIP 312: FROST for Spend Authorization Multisignatures</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: 312
Title: Shielded Multisignatures using FROST
Status: Reserved
Category: Standards / RPC / Wallet
Discussions-To: &lt;<a href="https://github.com/zcash/zips/issues/382">https://github.com/zcash/zips/issues/382</a>&gt;</pre>
Title: FROST for Spend Authorization Multisignatures
Owners: Conrado Gouvea &lt;conrado@zfnd.org&gt;
Chelsea Komlo &lt;ckomlo@uwaterloo.ca&gt;
Deirdre Connolly &lt;deirdre@zfnd.org&gt;
Status: Draft
Category: Wallet
Created: 2022-08-dd
License: MIT
Discussions-To: &lt;<a href="https://github.com/zcash/zips/issues/382">https://github.com/zcash/zips/issues/382</a>&gt;
Pull-Request: &lt;<a href="https://github.com/zcash/zips/pull/662">https://github.com/zcash/zips/pull/662</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>{Edit this to reflect the key words that are actually used.} The key words "MUST", "MUST NOT", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119. <a id="id1" class="footnote_reference" href="#rfc2119">2</a></p>
<p>The terms below are to be interpreted as follows:</p>
<dl>
<dt>Unlinkability</dt>
<dd>The property of statistical independence of signatures from the signers' long-term keys, ensuring that (for perfectly uniform generation of Randomizers and no leakage of metadata) it is impossible to determine whether two transactions were generated by the same party.</dd>
</dl>
</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 adapts FROST <a id="id2" class="footnote_reference" href="#frost">3</a>, a threshold signature scheme, to make it unlinkable, which is a requirement for its use in the Zcash protocol. The adapted scheme generates signatures compatible with spend authorization signatures in the Zcash protocol, for the Sapling and Orchard shielded pools.</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>In the Zcash protocol, Spend Authorization Signatures are employed to authorize a transaction. The ability to generate these signatures with the user's private key is what effectively allows the user to spend funds.</p>
<p>This is a security-critical step, since anyone who obtains access to the private key will be able to spend the user's funds. For this reason, one interesting possibility is to require multiple parties to allow the transaction to go through. This can be accomplished with threshold signatures, where the private key is split between parties (or generated already split using a distributed protocol) in a way that a threshold (e.g. 2 out of 3) of them must sign the transaction in order to create the final signature. This enables scenarios such as users and third-party services sharing custody of a wallet, or a group of people managing shared funds, for example.</p>
<p>FROST is one of such threshold signature protocols. However, it can't be used as-is since the Zcash protocol also requires re-randomizing public and private keys to ensure unlinkability between transactions. This ZIP specifies a variant of FROST with re-randomization support.</p>
</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>
<ul>
<li>All signatures generated by following this ZIP must be verified successfully as Sapling or Orchard spend authorization signatures using the appropriate validating key.</li>
<li>The signatures generated by following this ZIP should meet the security criteria for Signature with Re-Randomizable Keys as specified in the Zcash protocol <a id="id3" class="footnote_reference" href="#protocol-concretereddsa">11</a>.</li>
<li>The threat model described below must be taken into account.</li>
</ul>
<section id="threat-model"><h3><span class="section-heading">Threat Model</span><span class="section-anchor"> <a rel="bookmark" href="#threat-model"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h3>
<p>In normal usage, a Zcash user follows multiple steps in order to generate a shielded transaction:</p>
<ul>
<li>The transaction is created.</li>
<li>The transaction is signed with a re-randomized version of the user's spend authorization private key.</li>
<li>The zero-knowledge proof for the transaction is created with the randomizer as an auxiliary (secret) input, among others.</li>
</ul>
<p>When employing re-randomizable FROST as specified in this ZIP, the goal is to split the spend authorization private key
<span class="math">\(\mathsf{ask}\)</span>
among multiple possible signers. This means that the proof generation will still be performed by a single participant, likely the one that created the transaction in the first place. Note that this user already controls the privacy of the transaction since they are responsible for creating the proof.</p>
<p>This fits well into the "Coordinator" role from the FROST specification <a id="id4" class="footnote_reference" href="#frost-protocol">4</a>. The Coordinator is responsible for sending the message to be signed to all participants, and to aggregate the signature shares.</p>
<p>With those considerations in mind, the threat model considered in this ZIP is:</p>
<ul>
<li>The Coordinator is trusted with the privacy of the transaction (which includes the unlinkability property). A rogue Coordinator will be able to break unlinkability and privacy, but should not be able to create signed transactions without the approval of <code>MIN_PARTICIPANTS</code> participants, as specified in FROST.</li>
<li>All key share holders are also trusted with the privacy of the transaction, thus a rogue key share holder will be able to break its privacy and unlinkability.</li>
</ul>
</section>
</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>
<ul>
<li>This ZIP does not support removing the Coordinator role, as described in <a id="id5" class="footnote_reference" href="#frost-removingcoordinator">5</a>.</li>
<li>This ZIP does not prevent key share holders from linking the signing operation to a transaction in the blockchain.</li>
<li>Like the FROST specification <a id="id6" class="footnote_reference" href="#frost">3</a>, this ZIP does not specify a key generation procedure; but refer to that specification for guidelines.</li>
<li>Network privacy is not in scope for this ZIP, and must be obtained with other tools if desired.</li>
</ul>
</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>Algorithms in this section are specified using Python pseudo-code, in the same fashion as the FROST specification <a id="id7" class="footnote_reference" href="#frost">3</a>.</p>
<p>The types Scalar, Element, and G are defined in <a id="id8" class="footnote_reference" href="#frost-primeordergroup">6</a>, as well as the notation for elliptic-curve arithmetic, which uses the additive notation. Note that this notation differs from that used in the Zcash Protocol Specification. For example, <code>G.ScalarMult(P, k)</code> is used for scalar multiplication, where the protocol spec would use
<span class="math">\([k] P\)</span>
with the group implied by
<span class="math">\(P\)</span>
.</p>
<p>An additional per-ciphersuite hash function is used, denote <code>HR(m)</code>, which receives an arbitrary-sized byte string and returns a Scalar. It is defined concretely in the Ciphersuites section.</p>
<section id="re-randomizable-frost"><h3><span class="section-heading">Re-randomizable FROST</span><span class="section-anchor"> <a rel="bookmark" href="#re-randomizable-frost"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h3>
<p>To add re-randomization to FROST, follow the specification <a id="id9" class="footnote_reference" href="#frost">3</a> with the following modifications.</p>
<section id="key-generation"><h4><span class="section-heading">Key Generation</span><span class="section-anchor"> <a rel="bookmark" href="#key-generation"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h4>
<p>While key generation is out of scope for this ZIP and the FROST spec <a id="id10" class="footnote_reference" href="#frost">3</a>, it needs to be consistent with FROST, see <a id="id11" class="footnote_reference" href="#frost-tdkg">8</a> for guidance. The spend authorization private key
<span class="math">\(\mathsf{ask}\)</span>
<a id="id12" class="footnote_reference" href="#protocol-spendauthsig">13</a> is the particular key that must be used in the context of this ZIP. Note that the
<span class="math">\(\mathsf{ask}\)</span>
is usually derived from the spending key
<span class="math">\(\mathsf{sk}\)</span>
, though that is not required. Not doing so allows using distributed key generation, since the key it generates is unpredictable. Note however that not deriving
<span class="math">\(\mathsf{ask}\)</span>
from
<span class="math">\(\mathsf{sk}\)</span>
prevents using seed phrases to recover the original secret (which may be something desirable in the context of FROST).</p>
</section>
<section id="randomizer-generation"><h4><span class="section-heading">Randomizer Generation</span><span class="section-anchor"> <a rel="bookmark" href="#randomizer-generation"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h4>
<p>A new helper function is defined, which generates a randomizer. The <cite>encode_signing_package</cite> is defined as the byte serialization of the <cite>msg</cite>, <cite>commitment_list</cite> values as described in <a id="id13" class="footnote_reference" href="#frost-serialization">10</a>. Implementations MAY choose another encoding as long as all values (the message, and the identifier, binding nonce and hiding nonce for each participant) are unambiguously encoded.</p>
<p>The function <cite>random_bytes(n)</cite> is defined in <a id="id14" class="footnote_reference" href="#frost">3</a> and it returns a buffer with <cite>n</cite> bytes sampled uniformly at random. The constant <cite>Ns</cite> is also specified in <a id="id15" class="footnote_reference" href="#frost">3</a> and is the size of a serialized scalar.</p>
<pre>randomizer_generate():
Inputs:
- msg, the message being signed in the current FROST signing run
- commitment_list = [(i, hiding_nonce_commitment_i,
binding_nonce_commitment_i), ...], a list of commitments issued by
each participant, where each element in the list indicates a
NonZeroScalar identifier i and two commitment Element values
(hiding_nonce_commitment_i, binding_nonce_commitment_i). This list
MUST be sorted in ascending order by identifier.
Outputs: randomizer, a Scalar
def randomizer_generate(msg, commitment_list):
# Generate a random byte buffer with the size of a serialized scalar
rng_randomizer = random_bytes(Ns)
signing_package_enc = encode_signing_package(commitment_list, msg)
randomizer_input = rng_randomizer || signing_package_enc
return HR(randomizer_input)</pre>
</section>
<section id="round-one-commitment"><h4><span class="section-heading">Round One - Commitment</span><span class="section-anchor"> <a rel="bookmark" href="#round-one-commitment"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h4>
<p>Roune One is exactly the same as specified <a id="id16" class="footnote_reference" href="#frost">3</a>. But for context, it involves these steps:</p>
<ul>
<li>Each signer generates nonces and their corresponding public commitments. A nonce is a pair of Scalar values, and a commitment is a pair of Element values.</li>
<li>The nonces are stored locally by the signer and kept private for use in the second round.</li>
<li>The commitments are sent to the Coordinator.</li>
</ul>
</section>
<section id="round-two-signature-share-generation"><h4><span class="section-heading">Round Two - Signature Share Generation</span><span class="section-anchor"> <a rel="bookmark" href="#round-two-signature-share-generation"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h4>
<p>In Round Two, the Coordinator generates a random scalar <code>randomizer</code> by calling <code>randomizer_generate</code> and sends it to each signer, over a confidential and authenticated channel, along with the message and the set of signing commitments. (Note that this differs from regular FROST which just requires an authenticated channel.)</p>
<p>In Zcash, the message that needs to be signed is actually the SIGHASH transaction hash, which does not convey enough information for the signers to decide if they want to authorize the transaction or not. Therefore, in practice, more data is needed to be sent (over the same encrypted, authenticated channel) from the Coordinator to the signers, possibly the transaction itself, openings of value commitments, decryption of note ciphertexts, etc.; and the signers MUST check that the given SIGHASH matches the data sent from the Coordinator, or compute the SIGHASH themselves from that data. However, the specific mechanism for that process is outside the scope of this ZIP.</p>
<p>The randomized <code>sign</code> function is defined as the regular FROST <code>sign</code> function, but with its inputs modified relative to the <code>randomizer</code> as following:</p>
<ul>
<li><code>sk_i = sk_i + randomizer</code></li>
<li><code>group_public_key = group_public_key + G.ScalarBaseMult(randomizer)</code></li>
</ul>
</section>
<section id="signature-share-verification-and-aggregation"><h4><span class="section-heading">Signature Share Verification and Aggregation</span><span class="section-anchor"> <a rel="bookmark" href="#signature-share-verification-and-aggregation"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h4>
<p>The randomized <code>aggregate</code> function is defined as the regular FROST <code>aggregate</code> function, but with its inputs modified relative to the <code>randomizer</code> as following:</p>
<ul>
<li><code>group_public_key = group_public_key + G.ScalarBaseMult(randomizer)</code></li>
</ul>
<p>The randomized <code>verify_signature_share</code> function is defined as the regular FROST <code>verify_signature_share</code> function, but with its inputs modified relative to the <code>randomizer</code> as following:</p>
<ul>
<li><code>PK_i = PK_i + G.ScalarBaseMult(randomizer)</code></li>
<li><code>group_public_key = group_public_key + G.ScalarBaseMult(randomizer)</code></li>
</ul>
</section>
</section>
<section id="ciphersuites"><h3><span class="section-heading">Ciphersuites</span><span class="section-anchor"> <a rel="bookmark" href="#ciphersuites"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h3>
<section id="frost-jubjub-blake2b-512"><h4><span class="section-heading">FROST(Jubjub, BLAKE2b-512)</span><span class="section-anchor"> <a rel="bookmark" href="#frost-jubjub-blake2b-512"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h4>
<p>This ciphersuite uses Jubjub for the Group and BLAKE2b-512 for the Hash function <code>H</code> meant to produce signatures indistinguishable from RedJubjub Sapling Spend Authorization Signatures as specified in <a id="id17" class="footnote_reference" href="#protocol-concretespendauthsig">12</a>.</p>
<ul>
<li>Group: Jubjub <a id="id18" class="footnote_reference" href="#protocol-jubjub">14</a> with base point
<span class="math">\(\mathcal{G}^{\mathsf{Sapling}}\)</span>
as defined in <a id="id19" class="footnote_reference" href="#protocol-concretespendauthsig">12</a>.
<ul>
<li>Order:
<span class="math">\(r_\mathbb{J}\)</span>
as defined in <a id="id20" class="footnote_reference" href="#protocol-jubjub">14</a>.</li>
<li>Identity: as defined in <a id="id21" class="footnote_reference" href="#protocol-jubjub">14</a>.</li>
<li>RandomScalar(): Implemented by returning a uniformly random Scalar in the range [0, <code>G.Order()</code> - 1]. Refer to {{frost-randomscalar}} for implementation guidance.</li>
<li>SerializeElement(P): Implemented as
<span class="math">\(\mathsf{repr}_\mathbb{J}(P)\)</span>
as defined in <a id="id22" class="footnote_reference" href="#protocol-jubjub">14</a></li>
<li>DeserializeElement(P): Implemented as
<span class="math">\(\mathsf{abst}_\mathbb{J}(P)\)</span>
as defined in <a id="id23" class="footnote_reference" href="#protocol-jubjub">14</a>, returning an error if
<span class="math">\(\bot\)</span>
is returned. Additionally, this function validates that the resulting element is not the group identity element, returning an error if the check fails.</li>
<li>SerializeScalar: Implemented by outputting the little-endian 32-byte encoding of the Scalar value.</li>
<li>DeserializeScalar: Implemented by attempting to deserialize a Scalar from a little-endian 32-byte string. This function can fail if the input does not represent a Scalar in the range [0, <code>G.Order()</code> - 1].</li>
</ul>
</li>
<li>Hash (<code>H</code>): BLAKE2b-512 <a id="id24" class="footnote_reference" href="#blake">1</a> (BLAKE2b with 512-bit output and 16-byte personalization string), and Nh = 64.
<ul>
<li>H1(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubR", m), interpreting the 64 bytes as a little-endian integer, and reducing the resulting integer modulo <code>G.Order()</code>.</li>
<li>H2(m): Implemented by computing BLAKE2b-512("Zcash_RedJubjubH", m), interpreting the 64 bytes as a little-endian integer, and reducing the resulting integer modulo <code>G.Order()</code>. (This is equivalent to
<span class="math">\(\mathsf{H}^\circledast(m)\)</span>
, as defined by the
<span class="math">\(\mathsf{RedJubjub}\)</span>
scheme instantiated in <a id="id25" class="footnote_reference" href="#protocol-concretereddsa">11</a>.)</li>
<li>H3(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubN", m), interpreting the 64 bytes as a little-endian integer, and reducing the resulting integer modulo <code>G.Order()</code>.</li>
<li>H4(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubM", m).</li>
<li>H5(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubC", m).</li>
<li>HR(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubA", m), interpreting the 64 bytes as a little-endian integer, and reducing the resulting integer modulo <code>G.Order()</code>.</li>
</ul>
</li>
</ul>
<p>Signature verification is as specified in <a id="id26" class="footnote_reference" href="#protocol-concretespendauthsig">12</a> for RedJubjub.</p>
</section>
<section id="frost-pallas-blake2b-512"><h4><span class="section-heading">FROST(Pallas, BLAKE2b-512)</span><span class="section-anchor"> <a rel="bookmark" href="#frost-pallas-blake2b-512"><img width="24" height="24" class="section-anchor" src="assets/images/section-anchor.png" alt=""></a></span></h4>
<p>This ciphersuite uses Pallas for the Group and BLAKE2b-512 for the Hash function <code>H</code> meant to produce signatures indistinguishable from RedPallas Orchard Spend Authorization Signatures as specified in <a id="id27" class="footnote_reference" href="#protocol-concretespendauthsig">12</a>.</p>
<ul>
<li>Group: Pallas <a id="id28" class="footnote_reference" href="#protocol-pallasandvesta">15</a> with base point
<span class="math">\(\mathcal{G}^{\mathsf{Orchard}}\)</span>
as defined in <a id="id29" class="footnote_reference" href="#protocol-concretespendauthsig">12</a>.
<ul>
<li>Order:
<span class="math">\(r_\mathbb{P}\)</span>
as defined in <a id="id30" class="footnote_reference" href="#protocol-pallasandvesta">15</a>.</li>
<li>Identity: as defined in <a id="id31" class="footnote_reference" href="#protocol-pallasandvesta">15</a>.</li>
<li>RandomScalar(): Implemented by returning a uniformly random Scalar in the range [0, <code>G.Order()</code> - 1]. Refer to {{frost-randomscalar}} for implementation guidance.</li>
<li>SerializeElement(P): Implemented as
<span class="math">\(\mathsf{repr}_\mathbb{P}(P)\)</span>
as defined in <a id="id32" class="footnote_reference" href="#protocol-pallasandvesta">15</a>.</li>
<li>DeserializeElement(P): Implemented as
<span class="math">\(\mathsf{abst}_\mathbb{P}(P)\)</span>
as defined in <a id="id33" class="footnote_reference" href="#protocol-pallasandvesta">15</a>, failing if
<span class="math">\(\bot\)</span>
is returned. Additionally, this function validates that the resulting element is not the group identity element, returning an error if the check fails.</li>
<li>SerializeScalar: Implemented by outputting the little-endian 32-byte encoding of the Scalar value.</li>
<li>DeserializeScalar: Implemented by attempting to deserialize a Scalar from a little-endian 32-byte string. This function can fail if the input does not represent a Scalar in the range [0, <code>G.Order()</code> - 1].</li>
</ul>
</li>
<li>Hash (<code>H</code>): BLAKE2b-512 <a id="id34" class="footnote_reference" href="#blake">1</a> (BLAKE2b with 512-bit output and 16-byte personalization string), and Nh = 64.
<ul>
<li>H1(m): Implemented by computing BLAKE2b-512("FROST_RedPallasR", m), interpreting the 64 bytes as a little-endian integer, and reducing the resulting integer modulo <code>G.Order()</code>.</li>
<li>H2(m): Implemented by computing BLAKE2b-512("Zcash_RedPallasH", m), interpreting the 64 bytes as a little-endian integer, and reducing the resulting integer modulo <code>G.Order()</code>. (This is equivalent to
<span class="math">\(\mathsf{H}^\circledast(m)\)</span>
, as defined by the
<span class="math">\(\mathsf{RedPallas}\)</span>
scheme instantiated in <a id="id35" class="footnote_reference" href="#protocol-concretereddsa">11</a>.)</li>
<li>H3(m): Implemented by computing BLAKE2b-512("FROST_RedPallasN", m), interpreting the 64 bytes as a little-endian integer, and reducing the resulting integer modulo <code>G.Order()</code>.</li>
<li>H4(m): Implemented by computing BLAKE2b-512("FROST_RedPallasM", m).</li>
<li>H5(m): Implemented by computing BLAKE2b-512("FROST_RedPallasC", m).</li>
<li>HR(m): Implemented by computing BLAKE2b-512("FROST_RedPallasA", m), interpreting the 64 bytes as a little-endian integer, and reducing the resulting integer modulo <code>G.Order()</code>.</li>
</ul>
</li>
</ul>
<p>Signature verification is as specified in <a id="id36" class="footnote_reference" href="#protocol-concretespendauthsig">12</a> for RedPallas.</p>
</section>
</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>FROST is a threshold Schnorr signature scheme, and Zcash Spend Authorization are also Schnorr signatures, which allows the usage of FROST with Zcash. However, since there is no widespread standard for Schnorr signatures, it must be ensured that the signatures generated by the FROST variant specified in this ZIP can be verified successfully by a Zcash implementation following its specification. In practice this entails making sure that the generated signature can be verified by the
<span class="math">\(\mathsf{RedDSA.Validate}\)</span>
function specified in <a id="id37" class="footnote_reference" href="#protocol-concretereddsa">11</a>:</p>
<ul>
<li>The FROST signature, when split into R and S in the first step of
<span class="math">\(\mathsf{RedDSA.Validate}\)</span>
, must yield the values expected by the function. This is ensured by defining SerializeElement and SerializeScalar in each ciphersuite to yield those values.</li>
<li>The challenge c used during FROST signing must be equal to the challenge c computed during
<span class="math">\(\mathsf{RedDSA.Validate}\)</span>
. This requires defining the ciphersuite H2 function as the
<span class="math">\(\mathsf{H}^\circledast(m)\)</span>
Zcash function in the ciphersuites, and making sure its input will be the same. Fortunately FROST and Zcash use the same input order (R, public key, message) so we just need to make sure that SerializeElement (used to compute the encoded public key before passing to the hash function) matches what
<span class="math">\(\mathsf{RedDSA.Validate}\)</span>
expects; which is possible since both <cite>R</cite> and <cite>vk</cite> (the public key) are encoded in the same way as in Zcash.</li>
<li>Note that <code>r</code> (and thus <code>R</code>) will not be generated as specified in RedDSA.Sign. This is not an issue however, since with Schnorr signatures it does not matter for the verifier how the <code>r</code> value was chosen, it just needs to be generated uniformly at random, which is true for FROST.</li>
<li>The above will ensure that the verification equation in
<span class="math">\(\mathsf{RedDSA.Validate}\)</span>
will pass, since FROST ensures the exact same equation will be valid as described in <a id="id38" class="footnote_reference" href="#frost-primeorderverify">7</a>.</li>
</ul>
<p>The second step is adding the re-randomization functionality so that each FROST signing generates a re-randomized signature:</p>
<ul>
<li>Anywhere the public key is used, the randomized public key must be used instead. This is exactly what is done in the functions defined above.</li>
<li>The re-randomization must be done in each signature share generation, such that the aggregated signature must be valid under verification with the randomized public key. The <code>R</code> value from the signature is not influenced by the randomizer so we just need to focus on the <code>z</code> value (using FROST notation). Recall that <code>z</code> must equal to <code>r + (c * sk)</code>, and that each signature share is <code>z_i = (hiding_nonce + (binding_nonce * binding_factor)) +
(lambda_i * c * sk_i)</code>. The first terms are not influenced by the randomizer so we can only look into the second term of each top-level addition, i.e. <code>c
* sk</code> must be equal to <code>sum(lambda_i * c * sk_i)</code> for each participant <code>i</code>. Under re-randomization these become <code>c * (sk + randomizer)</code> (see
<span class="math">\(\mathsf{RedDSA.RandomizedPrivate}\)</span>
, which refers to the randomizer as
<span class="math">\(\alpha\)</span>
) and <code>sum(lambda_i * c * (sk_i + randomizer))</code>. The latter can be rewritten as <code>c * (sum(lambda_i * sk_i) + randomizer *
sum(lambda_i)</code>. Since <code>sum(lambda_i * sk_i) == sk</code> per the Shamir secret sharing mechanism used by FROST, and since <code>sum(lambda_i) == 1</code> <a id="id39" class="footnote_reference" href="#sum-lambda-proof">17</a>, we arrive at <code>c * (sk + randomizer)</code> as required.</li>
<li>The re-randomization procedure must be exactly the same as in <a id="id40" class="footnote_reference" href="#protocol-concretereddsa">11</a> to ensure that re-randomized keys are uniformly distributed and signatures are unlinkable. This is also true; observe that <code>randomizer_generate</code> generates randomizer uniformly at random as required by
<span class="math">\(\mathsf{RedDSA.GenRandom}\)</span>
; and signature generation is compatible with
<span class="math">\(\mathsf{RedDSA.RandomizedPrivate}\)</span>
,
<span class="math">\(\mathsf{RedDSA.RandomizedPublic}\)</span>
,
<span class="math">\(\mathsf{RedDSA.Sign}\)</span>
and
<span class="math">\(\mathsf{RedDSA.Validate}\)</span>
as explained in the previous item.</li>
</ul>
</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>The <cite>reddsa</cite> crate <a id="id41" class="footnote_reference" href="#crate-reddsa">16</a> contains a re-randomized FROST implementation of both ciphersuites.</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="blake" class="footnote">
<tbody>
<tr>
<th>1</th>
<td><a href="https://blake2.net/#sp">BLAKE2: simpler, smaller, fast as MD5</a></td>
</tr>
</tbody>
</table>
<table id="rfc2119" class="footnote">
<tbody>
<tr>
<th>2</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="frost" class="footnote">
<tbody>
<tr>
<th>3</th>
<td><a href="https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html">Draft RFC: Two-Round Threshold Schnorr Signatures with FROST</a></td>
</tr>
</tbody>
</table>
<table id="frost-protocol" class="footnote">
<tbody>
<tr>
<th>4</th>
<td><a href="https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#name-two-round-frost-signing-pro">Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 5: Two-Round FROST Signing Protocol</a></td>
</tr>
</tbody>
</table>
<table id="frost-removingcoordinator" class="footnote">
<tbody>
<tr>
<th>5</th>
<td><a href="https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#name-removing-the-coordinator-ro">Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 7.3: Removing the Coordinator Role</a></td>
</tr>
</tbody>
</table>
<table id="frost-primeordergroup" class="footnote">
<tbody>
<tr>
<th>6</th>
<td><a href="https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#name-prime-order-group">Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 3.1: Prime-Order Group</a></td>
</tr>
</tbody>
</table>
<table id="frost-primeorderverify" class="footnote">
<tbody>
<tr>
<th>7</th>
<td><a href="https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-schnorr-signature-generatio">Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Appendix B: Schnorr Signature Generation and Verification for Prime-Order Groups</a></td>
</tr>
</tbody>
</table>
<table id="frost-tdkg" class="footnote">
<tbody>
<tr>
<th>8</th>
<td><a href="https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#name-trusted-dealer-key-generati">Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Appendix B: Trusted Dealer Key Generation</a></td>
</tr>
</tbody>
</table>
<table id="frost-randomscalar" class="footnote">
<tbody>
<tr>
<th>9</th>
<td><a href="https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#name-random-scalar-generation">Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Appendix C: Random Scalar Generation</a></td>
</tr>
</tbody>
</table>
<table id="frost-serialization" class="footnote">
<tbody>
<tr>
<th>10</th>
<td><a href="https://frost.zfnd.org/user/serialization.html">The ZF FROST Book, Serialization Format</a></td>
</tr>
</tbody>
</table>
<table id="protocol-concretereddsa" class="footnote">
<tbody>
<tr>
<th>11</th>
<td><a href="protocol/protocol.pdf#concretereddsa">Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.7: RedDSA, RedJubjub, and RedPallas</a></td>
</tr>
</tbody>
</table>
<table id="protocol-concretespendauthsig" class="footnote">
<tbody>
<tr>
<th>12</th>
<td><a href="protocol/protocol.pdf#concretespendauthsig">Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.7.1: Spend Authorization Signature (Sapling and Orchard)</a></td>
</tr>
</tbody>
</table>
<table id="protocol-spendauthsig" class="footnote">
<tbody>
<tr>
<th>13</th>
<td><a href="protocol/protocol.pdf#spendauthsig">Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 4.15: Spend Authorization Signature (Sapling and Orchard)</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 2022.3.4 [NU5]. Section 5.4.9.3: Jubjub</a></td>
</tr>
</tbody>
</table>
<table id="protocol-pallasandvesta" class="footnote">
<tbody>
<tr>
<th>15</th>
<td><a href="protocol/protocol.pdf#pallasandvesta">Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.9.6: Pallas and Vesta</a></td>
</tr>
</tbody>
</table>
<table id="crate-reddsa" class="footnote">
<tbody>
<tr>
<th>16</th>
<td><a href="https://github.com/ZcashFoundation/reddsa">reddsa</a></td>
</tr>
</tbody>
</table>
<table id="sum-lambda-proof" class="footnote">
<tbody>
<tr>
<th>17</th>
<td><a href="https://math.stackexchange.com/questions/1325292/prove-that-the-sum-of-the-lagrange-interpolation-coefficients-is-equal-to-1/1325342#1325342">Prove that the sum of the Lagrange (interpolation) coefficients is equal to 1</a></td>
</tr>
</tbody>
</table>
</section>
</section>
</body>
</html>

View File

@ -1,7 +1,451 @@
::
ZIP: 312
Title: Shielded Multisignatures using FROST
Status: Reserved
Category: Standards / RPC / Wallet
Title: FROST for Spend Authorization Multisignatures
Owners: Conrado Gouvea <conrado@zfnd.org>
Chelsea Komlo <ckomlo@uwaterloo.ca>
Deirdre Connolly <deirdre@zfnd.org>
Status: Draft
Category: Wallet
Created: 2022-08-dd
License: MIT
Discussions-To: <https://github.com/zcash/zips/issues/382>
Pull-Request: <https://github.com/zcash/zips/pull/662>
Terminology
===========
{Edit this to reflect the key words that are actually used.}
The key words "MUST", "MUST NOT", "SHOULD", and "MAY" in this document are to
be interpreted as described in RFC 2119. [#RFC2119]_
The terms below are to be interpreted as follows:
Unlinkability
The property of statistical independence of signatures from the
signers' long-term keys, ensuring that (for perfectly uniform
generation of Randomizers and no leakage of metadata) it is
impossible to determine whether two transactions were generated
by the same party.
Abstract
========
This proposal adapts FROST [#FROST]_, a threshold signature scheme,
to make it unlinkable, which is a requirement for its use in the Zcash protocol.
The adapted scheme generates signatures compatible with spend authorization
signatures in the Sapling and Orchard shielded protocols as deployed in Zcash.
Motivation
==========
In the Zcash protocol, Spend Authorization Signatures are employed to authorize
a transaction. The ability to generate these signatures with the user's
private key is what effectively allows the user to spend funds.
This is a security-critical step, since anyone who obtains access to the private
key will be able to spend the user's funds. For this reason, one interesting
possibility is to require multiple parties to allow the transaction to go
through. This can be accomplished with threshold signatures, where the private
key is split between parties (or generated already split using a distributed
protocol) in a way that a threshold (e.g. 2 out of 3) of them must sign the
transaction in order to create the final signature. This enables scenarios such
as users and third-party services sharing custody of a wallet, or a group of
people managing shared funds, for example.
FROST is one of such threshold signature protocols. However, it can't be used
as-is since the Zcash protocol also requires re-randomizing public and private
keys to ensure unlinkability between transactions. This ZIP specifies a variant
of FROST with re-randomization support.
Requirements
============
- All signatures generated by following this ZIP must be verified successfully
as Sapling or Orchard spend authorization signatures using the appropriate
validating key.
- The signatures generated by following this ZIP should meet the security
criteria for Signature with Re-Randomizable Keys as specified in the Zcash
protocol [#protocol-concretereddsa]_.
- The threat model described below must be taken into account.
Threat Model
------------
In normal usage, a Zcash user follows multiple steps in order to generate a
shielded transaction:
- The transaction is created.
- The transaction is signed with a re-randomized version of the user's spend
authorization private key.
- The zero-knowledge proof for the transaction is created with the randomizer
as an auxiliary (secret) input, among others.
When employing re-randomizable FROST as specified in this ZIP, the goal is to
split the spend authorization private key :math:`\mathsf{ask}` among multiple
possible signers. This means that the proof generation will still be performed
by a single participant, likely the one that created the transaction in the first
place. Note that this user already controls the privacy of the transaction since
they are responsible for creating the proof.
This fits well into the "Coordinator" role from the FROST specification
[#frost-protocol]_. The Coordinator is responsible for sending the message to be
signed to all participants, and to aggregate the signature shares.
With those considerations in mind, the threat model considered in this ZIP is:
- The Coordinator is trusted with the privacy of the transaction (which includes
the unlinkability property). A rogue Coordinator will be able to break
unlinkability and privacy, but should not be able to create signed transactions
without the approval of ``MIN_PARTICIPANTS`` participants, as specified in FROST.
- All key share holders are also trusted with the privacy of the transaction,
thus a rogue key share holder will be able to break its privacy and unlinkability.
Non-requirements
================
- This ZIP does not support removing the Coordinator role, as described in
[#frost-removingcoordinator]_.
- This ZIP does not prevent key share holders from linking the signing operation to a
transaction in the blockchain.
- Like the FROST specification [#FROST]_, this ZIP does not specify a key generation
procedure; but refer to that specification for guidelines.
- Network privacy is not in scope for this ZIP, and must be obtained with other
tools if desired.
Specification
=============
Algorithms in this section are specified using Python pseudo-code, in the same
fashion as the FROST specification [#FROST]_.
The types Scalar, Element, and G are defined in [#frost-primeordergroup]_, as
well as the notation for elliptic-curve arithmetic, which uses the additive
notation. Note that this notation differs from that used in the Zcash Protocol
Specification. For example, ``G.ScalarMult(P, k)`` is used for scalar
multiplication, where the protocol spec would use :math:`[k] P` with the group
implied by :math:`P`.
An additional per-ciphersuite hash function is used, denote ``HR(m)``, which
receives an arbitrary-sized byte string and returns a Scalar. It is defined
concretely in the Ciphersuites section.
Re-randomizable FROST
---------------------
To add re-randomization to FROST, follow the specification [#FROST]_ with the
following modifications.
Key Generation
''''''''''''''
While key generation is out of scope for this ZIP and the FROST spec [#FROST]_,
it needs to be consistent with FROST, see [#frost-tdkg]_ for guidance. The spend
authorization private key :math:`\mathsf{ask}` [#protocol-spendauthsig]_ is the
particular key that must be used in the context of this ZIP. Note that the
:math:`\mathsf{ask}` is usually derived from the spending key
:math:`\mathsf{sk}`, though that is not required. Not doing so allows using
distributed key generation, since the key it generates is unpredictable. Note
however that not deriving :math:`\mathsf{ask}` from :math:`\mathsf{sk}` prevents
using seed phrases to recover the original secret (which may be something
desirable in the context of FROST).
Randomizer Generation
'''''''''''''''''''''
A new helper function is defined, which generates a randomizer. The
`encode_signing_package` is defined as the byte serialization of the `msg`,
`commitment_list` values as described in [#frost-serialization]_.
Implementations MAY choose another encoding as long as all values (the message,
and the identifier, binding nonce and hiding nonce for each participant) are
unambiguously encoded.
The function `random_bytes(n)` is defined in [#FROST]_ and it returns a buffer
with `n` bytes sampled uniformly at random. The constant `Ns` is also specified
in [#FROST]_ and is the size of a serialized scalar.
::
randomizer_generate():
Inputs:
- msg, the message being signed in the current FROST signing run
- commitment_list = [(i, hiding_nonce_commitment_i,
binding_nonce_commitment_i), ...], a list of commitments issued by
each participant, where each element in the list indicates a
NonZeroScalar identifier i and two commitment Element values
(hiding_nonce_commitment_i, binding_nonce_commitment_i). This list
MUST be sorted in ascending order by identifier.
Outputs: randomizer, a Scalar
def randomizer_generate(msg, commitment_list):
# Generate a random byte buffer with the size of a serialized scalar
rng_randomizer = random_bytes(Ns)
signing_package_enc = encode_signing_package(commitment_list, msg)
randomizer_input = rng_randomizer || signing_package_enc
return HR(randomizer_input)
Round One - Commitment
''''''''''''''''''''''
Roune One is exactly the same as specified [#FROST]_. But for context, it
involves these steps:
- Each signer generates nonces and their corresponding public commitments.
A nonce is a pair of Scalar values, and a commitment is a pair of Element values.
- The nonces are stored locally by the signer and kept private for use in the second round.
- The commitments are sent to the Coordinator.
Round Two - Signature Share Generation
''''''''''''''''''''''''''''''''''''''
In Round Two, the Coordinator generates a random scalar ``randomizer`` by calling
``randomizer_generate`` and sends it to each signer, over a confidential and
authenticated channel, along with the message and the set of signing
commitments. (Note that this differs from regular FROST which just requires an
authenticated channel.)
In Zcash, the message that needs to be signed is actually the SIGHASH
transaction hash, which does not convey enough information for the signers to
decide if they want to authorize the transaction or not. Therefore, in practice,
more data is needed to be sent (over the same encrypted, authenticated channel)
from the Coordinator to the signers, possibly the transaction itself, openings of
value commitments, decryption of note ciphertexts, etc.; and the signers MUST check
that the given SIGHASH matches the data sent from the Coordinator, or compute the
SIGHASH themselves from that data. However, the specific mechanism for that process
is outside the scope of this ZIP.
The randomized ``sign`` function is defined as the regular FROST ``sign``
function, but with its inputs modified relative to the ``randomizer`` as
following:
- ``sk_i = sk_i + randomizer``
- ``group_public_key = group_public_key + G.ScalarBaseMult(randomizer)``
Signature Share Verification and Aggregation
''''''''''''''''''''''''''''''''''''''''''''
The randomized ``aggregate`` function is defined as the regular FROST
``aggregate`` function, but with its inputs modified relative to the
``randomizer`` as following:
- ``group_public_key = group_public_key + G.ScalarBaseMult(randomizer)``
The randomized ``verify_signature_share`` function is defined as the regular
FROST ``verify_signature_share`` function, but with its inputs modified relative
to the ``randomizer`` as following:
- ``PK_i = PK_i + G.ScalarBaseMult(randomizer)``
- ``group_public_key = group_public_key + G.ScalarBaseMult(randomizer)``
Ciphersuites
------------
FROST(Jubjub, BLAKE2b-512)
''''''''''''''''''''''''''
This ciphersuite uses Jubjub for the Group and BLAKE2b-512 for the Hash function ``H``
meant to produce signatures indistinguishable from RedJubjub Sapling Spend
Authorization Signatures as specified in [#protocol-concretespendauthsig]_.
- Group: Jubjub [#protocol-jubjub]_ with base point :math:`\mathcal{G}^{\mathsf{Sapling}}`
as defined in [#protocol-concretespendauthsig]_.
- Order: :math:`r_\mathbb{J}` as defined in [#protocol-jubjub]_.
- Identity: as defined in [#protocol-jubjub]_.
- RandomScalar(): Implemented by returning a uniformly random Scalar in the range
\[0, ``G.Order()`` - 1\]. Refer to {{frost-randomscalar}} for implementation guidance.
- SerializeElement(P): Implemented as :math:`\mathsf{repr}_\mathbb{J}(P)` as defined in [#protocol-jubjub]_
- DeserializeElement(P): Implemented as :math:`\mathsf{abst}_\mathbb{J}(P)` as defined in [#protocol-jubjub]_,
returning an error if :math:`\bot` is returned. Additionally, this function
validates that the resulting element is not the group identity element,
returning an error if the check fails.
- SerializeScalar: Implemented by outputting the little-endian 32-byte encoding
of the Scalar value.
- DeserializeScalar: Implemented by attempting to deserialize a Scalar from a
little-endian 32-byte string. This function can fail if the input does not
represent a Scalar in the range \[0, ``G.Order()`` - 1\].
- Hash (``H``): BLAKE2b-512 [#BLAKE]_ (BLAKE2b with 512-bit output and 16-byte personalization string),
and Nh = 64.
- H1(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubR", m), interpreting
the 64 bytes as a little-endian integer, and reducing the resulting integer
modulo ``G.Order()``.
- H2(m): Implemented by computing BLAKE2b-512("Zcash_RedJubjubH", m), interpreting
the 64 bytes as a little-endian integer, and reducing the resulting integer
modulo ``G.Order()``.
(This is equivalent to :math:`\mathsf{H}^\circledast(m)`, as defined by
the :math:`\mathsf{RedJubjub}` scheme instantiated in [#protocol-concretereddsa]_.)
- H3(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubN", m), interpreting
the 64 bytes as a little-endian integer, and reducing the resulting integer
modulo ``G.Order()``.
- H4(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubM", m).
- H5(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubC", m).
- HR(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubA", m), interpreting
the 64 bytes as a little-endian integer, and reducing the resulting integer
modulo ``G.Order()``.
Signature verification is as specified in [#protocol-concretespendauthsig]_
for RedJubjub.
FROST(Pallas, BLAKE2b-512)
''''''''''''''''''''''''''
This ciphersuite uses Pallas for the Group and BLAKE2b-512 for the Hash function ``H``
meant to produce signatures indistinguishable from RedPallas Orchard Spend
Authorization Signatures as specified in [#protocol-concretespendauthsig]_.
- Group: Pallas [#protocol-pallasandvesta]_ with base point :math:`\mathcal{G}^{\mathsf{Orchard}}`
as defined in [#protocol-concretespendauthsig]_.
- Order: :math:`r_\mathbb{P}` as defined in [#protocol-pallasandvesta]_.
- Identity: as defined in [#protocol-pallasandvesta]_.
- RandomScalar(): Implemented by returning a uniformly random Scalar in the range
\[0, ``G.Order()`` - 1\]. Refer to {{frost-randomscalar}} for implementation guidance.
- SerializeElement(P): Implemented as :math:`\mathsf{repr}_\mathbb{P}(P)` as defined in [#protocol-pallasandvesta]_.
- DeserializeElement(P): Implemented as :math:`\mathsf{abst}_\mathbb{P}(P)` as defined in [#protocol-pallasandvesta]_,
failing if :math:`\bot` is returned. Additionally, this function validates that the resulting
element is not the group identity element, returning an error if the check fails.
- SerializeScalar: Implemented by outputting the little-endian 32-byte encoding
of the Scalar value.
- DeserializeScalar: Implemented by attempting to deserialize a Scalar from a
little-endian 32-byte string. This function can fail if the input does not
represent a Scalar in the range \[0, ``G.Order()`` - 1\].
- Hash (``H``): BLAKE2b-512 [#BLAKE]_ (BLAKE2b with 512-bit output and 16-byte personalization string),
and Nh = 64.
- H1(m): Implemented by computing BLAKE2b-512("FROST_RedPallasR", m), interpreting
the 64 bytes as a little-endian integer, and reducing the resulting integer
modulo ``G.Order()``.
- H2(m): Implemented by computing BLAKE2b-512("Zcash_RedPallasH", m), interpreting
the 64 bytes as a little-endian integer, and reducing the resulting integer
modulo ``G.Order()``.
(This is equivalent to :math:`\mathsf{H}^\circledast(m)`, as defined by
the :math:`\mathsf{RedPallas}` scheme instantiated in [#protocol-concretereddsa]_.)
- H3(m): Implemented by computing BLAKE2b-512("FROST_RedPallasN", m), interpreting
the 64 bytes as a little-endian integer, and reducing the resulting integer
modulo ``G.Order()``.
- H4(m): Implemented by computing BLAKE2b-512("FROST_RedPallasM", m).
- H5(m): Implemented by computing BLAKE2b-512("FROST_RedPallasC", m).
- HR(m): Implemented by computing BLAKE2b-512("FROST_RedPallasA", m), interpreting
the 64 bytes as a little-endian integer, and reducing the resulting integer
modulo ``G.Order()``.
Signature verification is as specified in [#protocol-concretespendauthsig]_
for RedPallas.
Rationale
=========
FROST is a threshold Schnorr signature scheme, and Zcash Spend Authorization are
also Schnorr signatures, which allows the usage of FROST with Zcash. However,
since there is no widespread standard for Schnorr signatures, it must be ensured
that the signatures generated by the FROST variant specified in this ZIP can be
verified successfully by a Zcash implementation following its specification. In
practice this entails making sure that the generated signature can be verified
by the :math:`\mathsf{RedDSA.Validate}` function specified in
[#protocol-concretereddsa]_:
- The FROST signature, when split into R and S in the first step of
:math:`\mathsf{RedDSA.Validate}`, must yield the values expected by the
function. This is ensured by defining SerializeElement and SerializeScalar in
each ciphersuite to yield those values.
- The challenge c used during FROST signing must be equal to the challenge c
computed during :math:`\mathsf{RedDSA.Validate}`. This requires defining the
ciphersuite H2 function as the :math:`\mathsf{H}^\circledast(m)` Zcash
function in the ciphersuites, and making sure its input will be the same.
Fortunately FROST and Zcash use the same input order (R, public key, message)
so we just need to make sure that SerializeElement (used to compute the
encoded public key before passing to the hash function) matches what
:math:`\mathsf{RedDSA.Validate}` expects; which is possible since both `R` and
`vk` (the public key) are encoded in the same way as in Zcash.
- Note that ``r`` (and thus ``R``) will not be generated as specified in RedDSA.Sign.
This is not an issue however, since with Schnorr signatures it does not matter
for the verifier how the ``r`` value was chosen, it just needs to be generated
uniformly at random, which is true for FROST.
- The above will ensure that the verification equation in
:math:`\mathsf{RedDSA.Validate}` will pass, since FROST ensures the exact same
equation will be valid as described in [#frost-primeorderverify]_.
The second step is adding the re-randomization functionality so that each FROST
signing generates a re-randomized signature:
- Anywhere the public key is used, the randomized public key must be used instead.
This is exactly what is done in the functions defined above.
- The re-randomization must be done in each signature share generation, such
that the aggregated signature must be valid under verification with the
randomized public key. The ``R`` value from the signature is not influenced by
the randomizer so we just need to focus on the ``z`` value (using FROST
notation). Recall that ``z`` must equal to ``r + (c * sk)``, and that each
signature share is ``z_i = (hiding_nonce + (binding_nonce * binding_factor)) +
(lambda_i * c * sk_i)``. The first terms are not influenced by the randomizer
so we can only look into the second term of each top-level addition, i.e. ``c
* sk`` must be equal to ``sum(lambda_i * c * sk_i)`` for each participant
``i``. Under re-randomization these become ``c * (sk + randomizer)`` (see
:math:`\mathsf{RedDSA.RandomizedPrivate}`, which refers to the randomizer as
:math:`\alpha`) and ``sum(lambda_i * c * (sk_i + randomizer))``. The latter
can be rewritten as ``c * (sum(lambda_i * sk_i) + randomizer *
sum(lambda_i)``. Since ``sum(lambda_i * sk_i) == sk`` per the Shamir secret
sharing mechanism used by FROST, and since ``sum(lambda_i) == 1``
[#sum-lambda-proof]_, we arrive at ``c * (sk + randomizer)`` as required.
- The re-randomization procedure must be exactly the same as in
[#protocol-concretereddsa]_ to ensure that re-randomized keys are uniformly
distributed and signatures are unlinkable. This is also true; observe that
``randomizer_generate`` generates randomizer uniformly at random as required
by :math:`\mathsf{RedDSA.GenRandom}`; and signature generation is compatible
with :math:`\mathsf{RedDSA.RandomizedPrivate}`,
:math:`\mathsf{RedDSA.RandomizedPublic}`, :math:`\mathsf{RedDSA.Sign}` and
:math:`\mathsf{RedDSA.Validate}` as explained in the previous item.
Reference implementation
========================
The `reddsa` crate [#crate-reddsa]_ contains a re-randomized FROST implementation of
both ciphersuites.
References
==========
.. [#BLAKE] `BLAKE2: simpler, smaller, fast as MD5 <https://blake2.net/#sp>`_
.. [#RFC2119] `RFC 2119: Key words for use in RFCs to Indicate Requirement Levels <https://www.rfc-editor.org/rfc/rfc2119.html>`_
.. [#FROST] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html>`_
.. [#frost-protocol] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 5: Two-Round FROST Signing Protocol <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#name-two-round-frost-signing-pro>`_
.. [#frost-removingcoordinator] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 7.3: Removing the Coordinator Role <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#name-removing-the-coordinator-ro>`_
.. [#frost-primeordergroup] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 3.1: Prime-Order Group <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#name-prime-order-group>`_
.. [#frost-primeorderverify] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Appendix B: Schnorr Signature Generation and Verification for Prime-Order Groups <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-schnorr-signature-generatio>`_
.. [#frost-tdkg] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Appendix B: Trusted Dealer Key Generation <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#name-trusted-dealer-key-generati>`_
.. [#frost-randomscalar] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Appendix C: Random Scalar Generation <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#name-random-scalar-generation>`_
.. [#frost-serialization] `The ZF FROST Book, Serialization Format <https://frost.zfnd.org/user/serialization.html>`_
.. [#protocol-concretereddsa] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.7: RedDSA, RedJubjub, and RedPallas <protocol/protocol.pdf#concretereddsa>`_
.. [#protocol-concretespendauthsig] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.7.1: Spend Authorization Signature (Sapling and Orchard) <protocol/protocol.pdf#concretespendauthsig>`_
.. [#protocol-spendauthsig] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 4.15: Spend Authorization Signature (Sapling and Orchard) <protocol/protocol.pdf#spendauthsig>`_
.. [#protocol-jubjub] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.9.3: Jubjub <protocol/protocol.pdf#jubjub>`_
.. [#protocol-pallasandvesta] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.9.6: Pallas and Vesta <protocol/protocol.pdf#pallasandvesta>`_
.. [#crate-reddsa] `reddsa <https://github.com/ZcashFoundation/reddsa>`_
.. [#sum-lambda-proof] `Prove that the sum of the Lagrange (interpolation) coefficients is equal to 1 <https://math.stackexchange.com/questions/1325292/prove-that-the-sum-of-the-lagrange-interpolation-coefficients-is-equal-to-1/1325342#1325342>`_