mirror of https://github.com/zcash/zips.git
452 lines
23 KiB
ReStructuredText
452 lines
23 KiB
ReStructuredText
::
|
|
|
|
ZIP: 312
|
|
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>`_
|