diff --git a/static/css/style.css b/static/css/style.css index 51d038e5..a1a7a307 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -204,7 +204,7 @@ pre:has(.mermaid) { aside { display: flex; flex-direction: column; - gap: 1em; + gap: 0; padding-top: 0.15rem; padding-left: 0.15rem; padding-right: 0.15rem; diff --git a/zips/zip-0000.rst b/zips/zip-0000.rst index 355df761..90c6e8d7 100644 --- a/zips/zip-0000.rst +++ b/zips/zip-0000.rst @@ -652,17 +652,13 @@ If there are multiple Owners, each should be on a separate line. Credits: and Original-Authors: fields SHOULD NOT include email addresses. -The "Owners", "Credits", and "Original-Authors" headers always use -these plural spellings even there is only one Owner, one person to be -credited, or one original author. - While a ZIP is in public discussions (usually during the initial Draft phase), a Discussions-To header will indicate the URL where the ZIP is being discussed. No Discussions-To header is necessary if the ZIP is being discussed privately with the Owner. -The Pull-Request header, if present, gives an URL to a Pull Request for -the ZIP. +The Pull-Request header, if present, gives one or more URLs to +Pull Requests for the ZIP. The Category header specifies the type of ZIP, as described in `ZIP categories`_. Multiple categories MAY be specified, separated by @@ -674,6 +670,11 @@ Dates should be in yyyy-mm-dd format, e.g. 2001-08-14. For ZIPs written in reStructuredText, URLs in header fields SHOULD be surrounded by ``<`` ``>``; this ensures that the link is rendered correctly. +The "Owners", "Credits", and "Original-Authors" headers always use +these plural spellings even if there is only one Owner, one person to +be credited, or one original author. The "Pull-Request" header always +uses this singular spelling even there are multiple Pull Requests. + Auxiliary Files ^^^^^^^^^^^^^^^ diff --git a/zips/zip-0312.rst b/zips/zip-0312.rst index 05c4619f..c45e9125 100644 --- a/zips/zip-0312.rst +++ b/zips/zip-0312.rst @@ -3,24 +3,29 @@ ZIP: 312 Title: FROST for Spend Authorization Multisignatures Owners: Conrado Gouvea - Chelsea Komlo - Deirdre Connolly + Daira-Emma Hopwood + Original-Authors: Chelsea Komlo + Deirdre Connolly Status: Draft Category: Wallet - Created: 2022-08-dd + Created: 2022-08-01 License: MIT Discussions-To: Pull-Request: + 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 key words "MUST", "SHOULD", "RECOMMENDED", "NOT RECOMMENDED", and "MAY" in +this document are to be interpreted as described in BCP 14 [#BCP14]_ when, and +only when, they appear in all capitals. -The terms below are to be interpreted as follows: +The term "Recovery Protocol" in this document is to be interpreted as described +in [#zip-2005]_. + +The term below is to be interpreted as follows: Unlinkability The property of statistical independence of signatures from the @@ -33,28 +38,29 @@ Unlinkability 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. +This proposal adapts FROST [#FROST]_, a threshold signature scheme, to make it +support key re-randomization as described in [#protocol-abstractsigrerand]_. +This is a requirement in order for it to be used to implement unlinkable spend +authorization signatures in the Orchard and Sapling 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. +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. +possibility is to ensure that authorization from multiple parties is needed in +order for 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 such 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 @@ -73,6 +79,8 @@ Requirements 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. +- The key generation must be compatible with Quantum Recoverability + [#zip-2005]_. Threat Model ------------ @@ -87,9 +95,9 @@ shielded transaction: 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 $\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 +split the spend authorization private key $\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. @@ -101,10 +109,15 @@ 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. + 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. + thus a rogue key share holder will be able to break its privacy and + unlinkability. + +Caveats concerning the security model for use of FROST keys in a Quantum +Recovery protocol are covered in [#zip-2005-usage-with-frost]_. Non-requirements @@ -112,10 +125,10 @@ 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. +- 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 require a particular + key generation procedure, although it does suggest one. - Network privacy is not in scope for this ZIP, and must be obtained with other tools if desired. @@ -126,131 +139,366 @@ 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 $[k] P$ with the group -implied by $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. +We define the following as in [#FROST]_ for a specific FROST ciphersuite: + +* Let $G$ be a group of prime order $p$ as described in [#frost-primeordergroup]_, + with element type $\mathtt{Element}$, identity $I \;{\small ⦂}\; \mathtt{Element}$, + base element $B \;{\small ⦂}\; \mathtt{Element}$ where $B \neq I$, and scalar type + $\mathtt{Scalar} = \mathbb{F}_p$. +* Let $\mathtt{Ne}$ and $\mathtt{Ns}$ be the sizes in bytes of a serialized Element + representation and Scalar representation, respectively. +* Let functions $\mathsf{Scalar} \;{\small ⦂}\; \{ 0 .. p-1 \} \rightarrow \mathtt{Scalar}$, + $\mathsf{RandomScalar} \;{\small ⦂}\; () \stackrel{\tiny\mathrm{R}}{\rightarrow} \mathtt{Scalar}$, + $\mathsf{ScalarMult} \;{\small ⦂}\; \mathtt{Element} \times \mathtt{Scalar} \rightarrow \mathtt{Element}$, + $\mathsf{ScalarBaseMult} \;{\small ⦂}\; \mathtt{Scalar} \rightarrow \mathtt{Element}$, + $\mathsf{SerializeElement} \;{\small ⦂}\; \mathtt{Element} \rightarrow \mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[\mathtt{Ne}]}$, + $\mathsf{DeserializeElement} \;{\small ⦂}\; \mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[\mathtt{Ne}]} \rightarrow \mathtt{Element} \cup \{ \bot \}$, + $\mathsf{SerializeScalar} \;{\small ⦂}\; \mathtt{Scalar} \rightarrow \mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[\mathtt{Ns}]}$, + $\mathsf{DeserializeScalar} \;{\small ⦂}\; \mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[\mathtt{Ns}]} \rightarrow \mathtt{Scalar} \cup \{ \bot \}$ + also be as described in [#frost-primeordergroup]_ (where "raising an error" + corresponds to returning $\bot$). + +Note that the notation for elliptic-curve scalar multiplication, +$\mathsf{G.ScalarMult}(P, k)$, differs from that used in the Zcash Protocol +Specification, which would use $[k]\, P$ with the group implied by $P$ +[#protocol-abstractgroup]_. 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 $\mathsf{ask}$ [#protocol-spendauthsig]_ is the -particular key that must be used in the context of this ZIP. Note that the -$\mathsf{ask}$ is usually derived from the spending key -$\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 $\mathsf{ask}$ from $\mathsf{sk}$ prevents -using seed phrases to recover the original secret (which may be something -desirable in the context of FROST). +FROST key generation with a trusted dealer is described in [#frost-tdkg]_. That +description does not support key re-randomization but can be adapted to do so, +as described in section 5 of [#frost-rerandomized]_. + +.. warning:: + Trusted dealer key generation has the severe disadvantage that it requires + absolutely trustworthy hardware and software to be used by the dealer in + order to reliably avoid exposing the private key material. That is, it is + not sufficient simply to have an individual or organization that is trusted + by all participants; their entire hardware and software stack also needs to + be trusted by all participants. + + Since this will often be an unrealistic assumption that partly defeats the + point of using a threshold signature scheme, trusted dealer key generation + SHOULD NOT be used. + +Instead, it is RECOMMENDED to instead use Distributed Key Generation. + +A suitable DKG protocol is COCKTAIL-DKG [#cocktail-dkg]_, which is supported by +the Zcash Foundation's reference implementation of FROST [#zf-frost-dkg]_. +COCKTAIL-DKG assumes that each participant has a static public key known to all +other participants. As noted in its documentation, the reference implementation +also requires participants to broadcast the commitment values honestly (i.e. +participants do not provide different commitment values to a subset of +participants), over a secure broadcast channel [#frost-term-broadcast-channel]_. + +Other Distributed Key Generation protocols MAY be used. + +To define a spending or viewing key that uses FROST, the Orchard and Sapling key +trees [#protocol-orchardkeycomponents]_ [#protocol-saplingkeycomponents]_ are +adjusted as follows: + +- The Spend validating key $\mathsf{ak}$ is replaced by the FROST group + public key `PK` [#frost-protocol]_ when deriving other key components. +- The Spend authorizing key $\mathsf{ask}$ [#protocol-spendauthsig]_ is + replaced by the logical signing key that corresponds to the group public key + `PK`. By design, this key is never explicitly constructed (unless trusted + dealer key generation was used), and instead is represented by any sufficient + subset of the participant FROST signing key shares `sk_i`. + +For both Orchard and Sapling, use of Distributed Key Generation precludes +generating $\mathsf{ask}$ from a spending key $\mathsf{sk}$. Instead the +Distributed Key Generation protocol will output the FROST group public key `PK`. + +When generating FROST key components for the Orchard shielded protocol, the +remaining parts of the Orchard key tree apart from $\mathsf{ask}$ and +$\mathsf{ak}$ SHOULD be generated as described in [#zip-2005-usage-with-frost]_. +The specification there is normative, and is only summarized here. It requires +the participants to privately agree on a value $\mathsf{sk}$ (which is no longer +sufficient by itself for spend authorization), and then use it to obtain the +nullifier deriving key $\mathsf{nk}$, the quantum spending key $\mathsf{qsk}$, +the quantum intermediate key $\mathsf{qk}$, and (using the FROST group public +key in place of $\mathsf{ak}$) $\mathsf{rivk\_ext}$. This process is specified +in § 4.2.3 ‘Orchard Key Components’ [#protocol-orchardkeycomponents]_ as +modified by [#zip-2005-usage-with-frost]_. + +Similarly, when generating a FROST key for the Sapling shielded protocol, the +remaining parts of the Sapling key tree apart from $\mathsf{ask}$ and +$\mathsf{ak}$ (that is, $\mathsf{nk}$, $\mathsf{rivk\_ext}$, and further values +derived from them and $\mathsf{ak}$) SHOULD be generated from a common value +$\mathsf{sk}$ (again, not sufficient by itself for spend authorization) as +described in [#protocol-saplingkeycomponents]_. + +If trusted dealer key generation is used contrary to recommendation, then +$\mathsf{ask}$ MAY in that case be derived from an $\mathsf{sk}$ known only to +the trusted dealer. This allows backing up the unsplit key, but any benefit of +being able to do so does not outweigh the disadvantages of requiring a trusted +dealer under normal circumstances. + +Regardless of how the Orchard or Sapling key components are generated, the +participants MUST ensure that they have obtained the same values for +$\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk\_ext}$. + +Since Sapling will not be modified to support Quantum Recoverability +[#zip-2005]_, Orchard is RECOMMENDED for new FROST keys. + +In order for all participants to agree on the value of $\mathsf{sk}$, one +of the following options SHOULD be used: + +- One participant generates a random $\mathsf{sk}$ and sends it to the + others via an encrypted and authenticated channel. This option SHOULD be used + if trusted dealer key generation was used, and the $\mathsf{sk}$ value + can be sent along with the FROST shares during key generation. This option MAY + be used if Distributed Key Generation was employed, if participants find it + acceptable to trust one participant to correctly generate $\mathsf{sk}$. +- Participants generate a $\mathsf{sk}$ in a contributory manner, for example + using the method defined in `Contributory Generation of sk`_. This approach + SHOULD be used to generate $\mathsf{sk}$ if Distributed Key Generation was + employed. + + +Contributory Randomness Generation +---------------------------------- + +The following procedure allows generating randomness with inputs from all +participants, such that each participant can verify that its contribution +was included and that other honest participants will obtain the same value. + +This is used to generate FROST randomizers, and can also be used for the +initial generation of $\mathsf{sk}$. + +Two functions are provided for this purpose: $\mathtt{randomness\_generate}()$ +and $\mathtt{randomness\_regenerate}()$. Both use helper functions defined as +follows: + +- The $\mathtt{encode\_contributions}()$ function returns a byte serialization + of a contribution list as defined below. +- $\mathtt{random\_bytes}(n)$ is defined in [#frost-conventions]_. It returns a + sequence of $n$ bytes sampled uniformly at random. + +A contribution list is a value of the form $[(i, \mathtt{contribution}_{\,i}),\, \ldots]$. +Each element in the list indicates a NonZeroScalar identifier $i$ and a byte +sequence $\mathtt{contribution}_{\,i}$. This list MUST be sorted in ascending +order by identifier. +:: -Re-randomizable FROST ---------------------- + encode_contributions(): -To add re-randomization to FROST, follow the specification [#FROST]_ with the -following modifications. + Input: a contribution list. + Output: a byte array. -Randomizer Generation -''''''''''''''''''''' + def encode_contributions(contribution_list): + return the concatenation of (G.SerializeScalar(i) || contribution_i) for each i -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. + randomness_generate(): + + Inputs: + - contribution_list, a contribution list. + - N, a seed length in bytes. + - H', a hash function (in practice this is either H2 or Hs from the + ciphersuite). + + Outputs: (randomness_seed, randomness), a byte sequence of length N + and an output of H'. + + def randomness_generate(contribution_list, N, H'): + randomness_seed = random_bytes(N) + randomness_input = randomness_seed || encode_contribution_list(contribution_list) + return (randomness_seed, H'(randomness_input)) :: - randomizer_generate(): + randomness_regenerate(): 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. + - randomness_seed, a byte sequence. + - contribution_list, a contribution list. + - H', a hash function (in practice this is either H2 or Hs from the + ciphersuite). + + Outputs: randomness, a Scalar + + def randomness_regenerate(randomness_seed, contribution_list, H'): + randomness_input = randomness_seed || encode_contribution_list(contribution_list) + return H'(randomness_input) + + +Contributory Generation of sk +----------------------------- + +This section describes a method of generating $\mathsf{sk}$ based on randomness +contributed by each participant, as well as the Coordinator. This avoids +entirely depending on the Coordinator's random number generator for security of +this key. This method depends on an encrypted, authenticated channel between the +Coordinator and each participant. + +We make use of the following ciphersuite-generic parameters defined in the +`Ciphersuites`_ section: + +- $\mathtt{Nh}$, the output size of the ciphersuite hash $\mathtt{H}$. +- $\mathtt{Hs}(m)$, a hash function. + +Define:: + + def sk_generate(contribution_list): + return randomness_generate(contribution_list, Nh, Hs) + + def sk_regenerate(sk_seed, contribution_list): + return randomness_regenerate(sk_seed, contribution_list, Hs) + +The parties agree on $\mathsf{sk}$ as follows: + +1. The Coordinator chooses a random seed + $\mathtt{sk\_seed} = \mathtt{random\_bytes}(\mathtt{Nh})$. +2. Each participant $i$ generates + $\mathtt{contribution}_{\,i} = \mathtt{random\_bytes}(\mathtt{Nh})$, and sends + its contribution to the Coordinator over an encrypted, authenticated channel. +3. The Coordinator calls $\mathtt{sk\_generate}(\mathtt{contribution\_list})$, + and sends the resulting $\mathtt{sk\_seed}$ to each participant over an + encrypted, authenticated channel. +4. All parties regenerate $\mathsf{sk}$ using + $\mathtt{sk\_regenerate}(\mathtt{sk\_seed}, \mathtt{contribution\_list})$, + and they include a Pedersen commitment to it in the transcript. + + +Randomizer Generation +--------------------- + +Re-Randomized FROST uses randomizers. This section specifies how they are +generated; this will be required for the Signature Share Generation +specification below. + +We make use of the following ciphersuite-generic parameters defined in the +`Ciphersuites`_ section: + +- $\mathtt{Ns}$, the size of a serialized scalar. +- $\mathtt{H2}(m)$, a hash function defined in [#frost-hash]_. + +The contribution to randomness generation from each participant, +$\mathtt{contribution}_{\,i}$, is the serialization of the hiding and binding +commitment Element values generated in Round One of the signing protocol, i.e. +$\mathsf{G.SerializeElement}(\mathtt{hiding\_nonce\_commitment}_i) \,||$ $\mathsf{G.SerializeElement}(\mathtt{binding\_nonce\_commitment}_i)$. + +Note that $\mathtt{encode\_contributions}$ defined in `Contributory Randomness Generation`_, +applied to a list of commitments of this form, is equivalent to +$\mathtt{encode\_group\_commitment\_list}$ defined in [#frost-listoperations]_. - Outputs: randomizer, a Scalar +Define:: - 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) + def randomizer_generate(commitment_list): + return randomness_generate(commitment_list, Ns, H2) + + def randomizer_regenerate(randomizer_seed, commitment_list): + return randomness_regenerate(randomizer_seed, commitment_list, H2) + + +Re-Randomized FROST +------------------- + +To add re-randomization to FROST, the signers MUST follow the specification +[#FROST]_ with the following modifications. Round One - Commitment '''''''''''''''''''''' -Roune One is exactly the same as specified [#FROST]_. But for context, it +Round 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. +- Each signer generates nonces and their corresponding public commitments. A + nonce is a pair of $\mathtt{Scalar}$ values, and a commitment is a pair of + $\mathtt{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)`` +In Round Two of regular FROST, the Coordinator picks a message and sends it to +each signer along with the commitments received in Round One. In Re-Randomized +FROST, the Coordinator MUST additionally call $\mathtt{randomizer\_generate}()$ +and send the $\mathtt{randomizer\_seed}$ along with the message and the +commitments. Each participant, upon receiving those values, MUST compute +$\mathtt{randomizer}$ by calling $\mathtt{randomizer\_regenerate}()$ with the +received $\mathtt{randomizer\_seed}$ and commitments. + +In Zcash, the message that needs to be signed is the SIGHASH transaction hash. +This by itself does not convey enough information for the signers to decide +whether they want to authorize the transaction or not. Therefore, in addition +to the serialized transaction, more data (such as openings of value commitments, +decryption of note ciphertexts, etc.) needs to be sent from the Coordinator to +the signers. This SHOULD be done by sending a Partially Constructed Zcash Transaction +[#draft-zip-0374]_ over the same encrypted, authenticated channel. In order to sign, +each signer MUST be satisfied that the transaction should be authorized, using +the additional information provided in the PCZT where necessary. That information +MUST be checked for consistency with the transaction and not trusted simply +because the Coordinator is providing it. + +The details of this checking, and of what needs to be included in the PCZT in +order for the signers to be satisfied that the transaction should be authorized, +are to be specified in [#draft-zip-0374]_. + +Let $\textsf{FROST.sign}$ be the regular FROST signing function with arguments +``(identifier, sk_i, group_public_key, nonce_i, msg, commitment_list)``, +as defined in [#frost-sign]_. + +The $\textsf{Rerandomized-FROST.sign}$ function takes an additional input +$\mathtt{randomizer\_seed}$, and adjusts the inputs relative to the +$\mathtt{randomizer}$ computed by $\mathtt{randomizer\_regenerate}()$:: + + def Rerandomized-FROST.sign(identifier, sk_i, group_public_key, nonce_i, msg, + commitment_list, randomizer_seed): + randomizer = randomizer_regenerate(randomizer_seed, commitment_list) + randomized_sk_i = sk_i + randomizer + randomized_group_public_key = group_public_key + G.ScalarBaseMult(randomizer) + return FROST.sign(identifier, randomized_sk_i, randomized_group_public_key, + nonce_i, msg, commitment_list) + +The signer MAY cache $\mathtt{randomizer}$ and +$\mathsf{G.ScalarBaseMult}(\mathtt{randomizer})$ for use in the +$\textsf{Rerandomized-FROST.}$ {aggregate, verify_signature_share} +functions defined below. 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: +Let $\textsf{FROST.aggregate}$ be the regular FROST aggregation function with +arguments ``(commitment_list, msg, group_public_key, sig_shares)``, as defined +in [#frost-aggregate]_. + +The $\textsf{Rerandomized-FROST.aggregate} function takes an additional input +$\mathtt{randomizer}$ computed as above, and adjusts the inputs relative to this +randomizer:: + + def Rerandomized-FROST.aggregate(commitment_list, msg, group_public_key, sig_shares, + randomizer): + randomized_group_public_key = group_public_key + G.ScalarBaseMult(randomizer) + return FROST.aggregate(commitment_list, msg, randomized_group_public_key, sig_shares) -- ``group_public_key = group_public_key + G.ScalarBaseMult(randomizer)`` +Similarly, let $\textsf{FROST.verify\_signature\_share}$ be the regular FROST signature +share verification function with arguments +``(identifier, PK_i, comm_i, sig_share_i, commitment_list, group_public_key, msg)``, +as defined also in [#frost-aggregate]_. -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: +The $\textsf{Rerandomized-FROST.verify\_signature\_share}$ function takes an +additional input $\mathtt{randomizer}$ computed as above, and adjusts the inputs +relative to this randomizer:: -- ``PK_i = PK_i + G.ScalarBaseMult(randomizer)`` -- ``group_public_key = group_public_key + G.ScalarBaseMult(randomizer)`` + def Rerandomized-FROST.verify_signature_share(identifier, PK_i, comm_i, sig_share_i, + commitment_list, group_public_key, msg): + group_offset = G.ScalarBaseMult(randomizer) + randomized_PK_i = PK_i + group_offset + randomized_group_public_key = group_public_key + group_offset + return FROST.verify_signature_share(identifier, randomized_PK_i, comm_i, sig_share_i, + commitment_list, randomized_group_public_key, msg) Ciphersuites @@ -259,47 +507,49 @@ 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]_. +This ciphersuite uses Jubjub for the Group and BLAKE2b-512 for the Hash function +$\mathtt{H}$ meant to produce signatures indistinguishable from RedJubjub +Sapling Spend Authorization Signatures as specified in [#protocol-concretespendauthsig]_. - Group: Jubjub [#protocol-jubjub]_ with base point $\mathcal{G}^{\mathsf{Sapling}}$ as defined in [#protocol-concretespendauthsig]_. - - Order: $r_\mathbb{J}$ as defined in [#protocol-jubjub]_. + - Order: $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 $\mathsf{repr}_\mathbb{J}(P)$ as defined in [#protocol-jubjub]_ - - DeserializeElement(P): Implemented as $\mathsf{abst}_\mathbb{J}(P)$ as defined in [#protocol-jubjub]_, - returning an error if $\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. + - $\mathsf{RandomScalar}()$: Implemented by returning a uniformly random + $\mathtt{Scalar}$ in the range $[0, \mathsf{G.Order}() - 1]$. Refer to + [#frost-randomscalar]_ for implementation guidance. + - $\mathsf{SerializeElement}(P)$: Implemented as + $\mathsf{repr}_{\mathbb{J}}(P)$ as defined in [#protocol-jubjub]_. + - $\mathsf{DeserializeElement}(P)$: Implemented as + $\mathsf{abst}_{\mathbb{J}}(P)$ as defined in [#protocol-jubjub]_, returning + an error if $\bot$ is returned. Additionally, this function validates that + the resulting element is not the group identity element, returning an error + if the check fails. + - $\mathsf{SerializeScalar}$: Implemented by outputting the little-endian + 32-byte encoding of the $\mathtt{Scalar}$ value. + - $\mathsf{DeserializeScalar}$: Implemented by attempting to deserialize a + $\mathtt{Scalar}$ from a little-endian 32-byte string. This function can + fail if the input does not represent a $\mathtt{Scalar}$ in the range + $[0, \mathsf{G.Order}() - 1]$. + +- Hash ($\mathtt{H}$): BLAKE2b-512 [#BLAKE]_ (BLAKE2b with 512-bit output and + 16-byte personalization string), and $\mathtt{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()``. + modulo $\mathsf{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()``. + modulo $\mathsf{G.Order}()$. (This is equivalent to $\mathsf{H}^\circledast(m)$, as defined by the $\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()``. + modulo $\mathsf{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()``. + - Hs(m): Implemented by taking the first 32 bytes of BLAKE2b-512("FROST_RedJubjubs", m). Signature verification is as specified in [#protocol-concretespendauthsig]_ for RedJubjub. @@ -317,37 +567,39 @@ Authorization Signatures as specified in [#protocol-concretespendauthsig]_. - Order: $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 $\mathsf{repr}_\mathbb{P}(P)$ as defined in [#protocol-pallasandvesta]_. - - DeserializeElement(P): Implemented as $\mathsf{abst}_\mathbb{P}(P)$ as defined in [#protocol-pallasandvesta]_, - failing if $\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. + - $\mathsf{RandomScalar}()$: Implemented by returning a uniformly random + $\mathtt{Scalar}$ in the range $[0, \mathsf{G.Order}() - 1]$. Refer to + [#frost-randomscalar]_ for implementation guidance. + - $\mathsf{SerializeElement}(P)$: Implemented as $\mathsf{repr}_\mathbb{P}(P)$ + as defined in [#protocol-pallasandvesta]_. + - $\mathsf{DeserializeElement}(P)$: Implemented as $\mathsf{abst}_\mathbb{P}(P)$ + as defined in [#protocol-pallasandvesta]_, failing if $\bot$ is returned. + Additionally, this function validates that the resulting element is not the + group identity element, returning an error if the check fails. + - $\mathsf{SerializeScalar}$: Implemented by outputting the little-endian + 32-byte encoding of the $\mathtt{Scalar}$ value. + - $\mathsf{DeserializeScalar}$: Implemented by attempting to deserialize a + $\mathtt{Scalar}$ from a little-endian 32-byte string. This function can + fail if the input does not represent a $\mathtt{Scalar}$ in the range + $[0, \mathsf{G.Order}() - 1]$. + +- Hash ($\mathtt{H}$): BLAKE2b-512 [#BLAKE]_ (BLAKE2b with 512-bit output and + 16-byte personalization string), and $\mathtt{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()``. + modulo $\mathsf{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()``. + modulo $\mathsf{G.Order}()$. (This is equivalent to $\mathsf{H}^\circledast(m)$, as defined by the $\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()``. + modulo $\mathsf{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()``. + - Hs(m): Implemented by taking the first 32 bytes of BLAKE2b-512("FROST_RedPallass", m). Signature verification is as specified in [#protocol-concretespendauthsig]_ for RedPallas. @@ -364,25 +616,26 @@ practice this entails making sure that the generated signature can be verified by the $\mathsf{RedDSA.Validate}$ function specified in [#protocol-concretereddsa]_: -- The FROST signature, when split into R and S in the first step of +- The FROST signature, when split into $R$ and $S$ in the first step of $\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. + function. This is ensured by defining $\mathsf{SerializeElement}$ and + $\mathsf{SerializeScalar}$ in each ciphersuite to yield those values. -- The challenge c used during FROST signing must be equal to the challenge c - computed during $\mathsf{RedDSA.Validate}$. This requires defining the +- The challenge $c$ used during FROST signing must be equal to the challenge + $c$ computed during $\mathsf{RedDSA.Validate}$. This requires defining the ciphersuite H2 function as the $\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 - $\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. + Fortunately FROST and Zcash use the same input order ($R$, public key, message) + so we just need to make sure that $\mathsf{SerializeElement}$ (used to compute + the encoded public key before passing to the hash function) matches what + $\mathsf{RedDSA.Validate}$ expects; which is possible since both $R$ and + $\mathsf{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 + $\mathsf{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 a uniformly distributed random element, which is true for + FROST. - The above will ensure that the verification equation in $\mathsf{RedDSA.Validate}$ will pass, since FROST ensures the exact same @@ -395,59 +648,79 @@ signing generates a re-randomized signature: 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 - $\mathsf{RedDSA.RandomizedPrivate}$, which refers to the randomizer as - $\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. + randomized public key. This is shown to be true in [#frost-rerandomized]_. - 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 $\mathsf{RedDSA.GenRandom}$; and signature generation is compatible - with $\mathsf{RedDSA.RandomizedPrivate}$, - $\mathsf{RedDSA.RandomizedPublic}$, $\mathsf{RedDSA.Sign}$ and - $\mathsf{RedDSA.Validate}$ as explained in the previous item. + $\mathtt{randomizer\_generate} generates randomizer uniformly at random as + required by $\mathsf{RedDSA.GenRandom}$; and signature generation is compatible + with $\mathsf{RedDSA.RandomizePrivate}$, $\mathsf{RedDSA.RandomizePublic}$, + $\mathsf{RedDSA.Sign}$ and $\mathsf{RedDSA.Validate}$ as explained in the + previous item. The security of Re-Randomized FROST with respect to the security assumptions of regular FROST is shown in [#frost-rerandomized]_. +Regarding randomizer handling, in Zcash, the $\mathtt{randomizer}$ is called +$\alpha$ and is usually generated using the $\mathsf{RedDSA.GenRandom}$ function +as defined in the Zcash specification [#protocol-spendauthsig]_. Note that the +choice of $\alpha$ influences the SIGHASH computation, so it is impossible to +compute the $\mathtt{randomizer}$ based on the message (SIGHASH), as suggested +in [#frost-rerandomized]_. This is not an issue as long as the +$\mathtt{randomizer}$ is generated with the same security properties as +$\mathsf{RedDSA.GenRandom}$. We ensure that by using a very similar approach; +while the original $\mathsf{RedDSA.GenRandom}$ uses $\mathsf{H}^\circledast(T)$ +where $T$ is a random byte sequence with a certain size, in this ZIP we +effectively use $\mathsf{H}^\circledast(T || \mathsf{signing\_commitments\_enc})$, +i.e. we concatenate the random bytes with the encoding of the signing +commitments. This preserves the security assumptions and also hedges against +issues in the Coordinator random byte generator and prevents the Coordinator +from fully influencing the randomizer, reducing its trust assumptions. + Reference implementation ======================== -The `reddsa` crate [#crate-reddsa]_ contains a re-randomized FROST implementation of -both ciphersuites. +The `reddsa` crate [#crate-reddsa]_ contains a re-randomized FROST implementation +of both ciphersuites. References ========== +.. [#BCP14] `Information on BCP 14 — "RFC 2119: Key words for use in RFCs to Indicate Requirement Levels" and "RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words" `_ .. [#BLAKE] `BLAKE2: simpler, smaller, fast as MD5 `_ -.. [#RFC2119] `RFC 2119: Key words for use in RFCs to Indicate Requirement Levels `_ .. [#FROST] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures `_ -.. [#frost-rerandomized] `Re-Randomized FROST `_ -.. [#frost-protocol] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Section 5: Two-Round FROST Signing Protocol `_ -.. [#frost-removingcoordinator] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Section 7.3: Removing the Coordinator Role `_ +.. [#frost-rerandomized] `Re-Randomized FROST (ePrint 2024/436) `_ +.. [#frost-serialization] `The ZF FROST Book, Serialization Format `_ +.. [#frost-term-broadcast-channel] `The ZF FROST Book, Terminology — Broadcast Channel `_ +.. [#frost-conventions] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Section 2: Conventions and Definitions `_ .. [#frost-primeordergroup] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Section 3.1: Prime-Order Group `_ +.. [#frost-hash] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Section 3.2: Cryptographic Hash Function `_ +.. [#frost-listoperations] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Section 4.3: List Operations `_ +.. [#frost-protocol] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Section 5: Two-Round FROST Signing Protocol `_ +.. [#frost-sign] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Section 5.2: Round Two - Signature Share Generation `_ +.. [#frost-aggregate] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Section 5.3: Signature Share Aggregation `_ +.. [#frost-removingcoordinator] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Section 7.5: Removing the Coordinator Role `_ .. [#frost-primeorderverify] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Appendix B: Schnorr Signature Generation and Verification for Prime-Order Groups `_ -.. [#frost-tdkg] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Appendix B: Trusted Dealer Key Generation `_ -.. [#frost-randomscalar] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Appendix C: Random Scalar Generation `_ -.. [#frost-serialization] `The ZF FROST Book, Serialization Format `_ -.. [#protocol-concretereddsa] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.7: RedDSA, RedJubjub, and RedPallas `_ -.. [#protocol-concretespendauthsig] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.7.1: Spend Authorization Signature (Sapling and Orchard) `_ -.. [#protocol-spendauthsig] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 4.15: Spend Authorization Signature (Sapling and Orchard) `_ -.. [#protocol-jubjub] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.9.3: Jubjub `_ -.. [#protocol-pallasandvesta] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.9.6: Pallas and Vesta `_ -.. [#crate-reddsa] `reddsa `_ +.. [#frost-tdkg] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Appendix C: Trusted Dealer Key Generation `_ +.. [#frost-randomscalar] `RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures. Appendix D: Random Scalar Generation `_ +.. [#protocol-addressesandkeys] `Zcash Protocol Specification, Version 2025.6.1 [NU6.1]. Section 3.1: Payment Addresses and Keys `_ +.. [#protocol-abstractsigrerand] `Zcash Protocol Specification, Version 2025.6.1 [NU6.1]. Section 4.1.7.1: Signature with Re-Randomizable Keys `_ +.. [#protocol-abstractgroup] `Zcash Protocol Specification, Version 2025.6.1 [NU6.1]. Section 4.1.9: Represented Group `_ +.. [#protocol-saplingkeycomponents] `Zcash Protocol Specification, Version 2025.6.1 [NU6.1]. Section 4.2.2: Sapling Key Components `_ +.. [#protocol-orchardkeycomponents] `Zcash Protocol Specification, Version 2025.6.1 [NU6.1]. Section 4.2.3: Orchard Key Components `_ +.. [#protocol-spendauthsig] `Zcash Protocol Specification, Version 2025.6.1 [NU6.1]. Section 4.15: Spend Authorization Signature (Sapling and Orchard) `_ +.. [#protocol-concretereddsa] `Zcash Protocol Specification, Version 2025.6.1 [NU6.1]. Section 5.4.7: RedDSA, RedJubjub, and RedPallas `_ +.. [#protocol-concretespendauthsig] `Zcash Protocol Specification, Version 2025.6.1 [NU6.1]. Section 5.4.7.1: Spend Authorization Signature (Sapling and Orchard) `_ +.. [#protocol-jubjub] `Zcash Protocol Specification, Version 2025.6.1 [NU6.1]. Section 5.4.9.3: Jubjub `_ +.. [#protocol-pallasandvesta] `Zcash Protocol Specification, Version 2025.6.1 [NU6.1]. Section 5.4.9.6: Pallas and Vesta `_ +.. [#crate-reddsa] `reddsa Rust crate `_ .. [#sum-lambda-proof] `Prove that the sum of the Lagrange (interpolation) coefficients is equal to 1 `_ +.. [#zf-frost-dkg] `FROST reference implementation (ZcashFoundation/frost) — Distributed Key Generation `_ +.. [#cocktail-dkg] `COCKTAIL-DKG: Distributed Key Generation protocol for FROST `_ (draft at [#cocktail-dkg-draft]_) +.. [#cocktail-dkg-draft] `C2SP Pull Request 164 — new spec: COCKTAIL-DKG `_ +.. [#draft-zip-0374] `Draft ZIP 374 (zcash/zips PR 1063): Partially Created Zcash Transaction Format `_ +.. [#zip-2005] `ZIP 2005: Quantum recoverability `_ +.. [#zip-2005-usage-with-frost] `ZIP 2005: Quantum recoverability - Usage with FROST `_ diff --git a/zips/zip-guide-markdown.md b/zips/zip-guide-markdown.md index 8a8a425e..21c420b7 100644 --- a/zips/zip-guide-markdown.md +++ b/zips/zip-guide-markdown.md @@ -158,19 +158,20 @@ ZIP editors will catch any inconsistencies in review.
-"`.. note::`" in reStructuredText or "`
`" in Markdown -(followed by a blank line in either case), can be used for an aside from the main -text. The rendering of notes is colourful and may be distracting, so they should -only be used for important points. +"`.. note::`" (followed by a block indented 4 spaces) in reStructuredText, or +"`
`" (with a blank line before the following paragraph) +in Markdown, can be used for an aside from the main text. The rendering of notes +is colourful and may be distracting, so they should only be used for important +points.
-"`.. warning::`" in reStructuredText or "`
`" in -Markdown (followed by a blank line in either case), can be used for warnings. -Warnings should be used very sparingly — for example to signal that a -entire specification, or part of it, may be inapplicable or could cause -significant interoperability or security problems. In most cases, a "MUST" -or "SHOULD" conformance requirement is more appropriate. +"`.. warning::`" (followed by a block indented 4 spaces) in reStructuredText, or +"`
`" (with a blank line before the following paragraph) +in Markdown, can be used for warnings. Warnings should be used very sparingly — +for example to signal that an entire specification, or part of it, may be +inapplicable or could cause significant interoperability or security problems. +In most cases, a "MUST" or "SHOULD" conformance requirement is more appropriate. In Markdown, notes and warnings can currently only be a single paragraph. diff --git a/zips/zip-guide.rst b/zips/zip-guide.rst index 43df1676..525cc6f0 100644 --- a/zips/zip-guide.rst +++ b/zips/zip-guide.rst @@ -167,18 +167,19 @@ Notes and warnings ------------------ .. note:: - "``.. note::``" in reStructuredText or "``
``" in - Markdown (followed by a blank line in either case), can be used for an aside - from the main text. + "``.. note::``" (followed by a block indented 4 spaces) in reStructuredText, + or "``
``" (with a blank line before the following + paragraph) in Markdown, can be used for an aside from the main text. The rendering of notes is colourful and may be distracting, so they should only be used for important points. .. warning:: - "``.. warning::``" in reStructuredText, or "``
``" - in Markdown (followed by a blank line in either case), can be used for warnings. + "``.. warning::``" (followed by a block indented 4 spaces) in reStructuredText, + or "``
``" (with a blank line before the following + paragraph) in Markdown, can be used for warnings. - Warnings should be used very sparingly — for example to signal that a + Warnings should be used very sparingly — for example to signal that an entire specification, or part of it, may be inapplicable or could cause significant interoperability or security problems. In most cases, a "MUST" or "SHOULD" conformance requirement is more appropriate.