frost/book/src/tutorial/signing.md

4.5 KiB

Signing

The diagram below shows the signing process. Dashed lines represent data being sent through an authenticated communication channel.

Diagram of Signing, illustrating what is explained in the text

Coordinator, Round 1

To sign, the Coordinator must select which participants are going to generate the signature, and must signal to start the process. This needs to be implemented by users of the ZF FROST library and will depend on the communication channel being used.

Participants, Round 1

Each selected participant will then generate the nonces (a SigningNonces) and their commitments (a SigningCommitments) by calling round1::commit():

{{#include ../../../frost-ristretto255/README.md:round1_commit}}

The SigningNonces must be kept by the participant to use in Round 2, while the SigningCommitments must be sent to the Coordinator using an authenticated channel.

Coordinator, Round 2

The Coordinator will get all SigningCommitments from the participants and the message to be signed, and then build a SigningPackage by calling SigningPackage::new().

{{#include ../../../frost-ristretto255/README.md:round2_package}}

The SigningPackage must then be sent to all the participants using an authenticated channel. (Of course, if the message is confidential, then the channel must also be confidential.)

In all of the main FROST ciphersuites, the entire message must
be sent to participants. In some cases, where the message is too big, it may be
necessary to send a hash of the message instead. We strongly suggest creating a
specific ciphersuite for this, and not just sending the hash as if it were the
message. For reference, see [how RFC 8032 handles
"pre-hashing"](https://datatracker.ietf.org/doc/html/rfc8032).

Participants, Round 2

Upon receiving the SigningPackage, each participant will then produce their signature share using their KeyPackage from the key generation process and their SigningNonces from Round 1, by calling round2::sign():

{{#include ../../../frost-ristretto255/README.md:round2_sign}}

The resulting SignatureShare must then be sent back to the Coordinator using an authenticated channel.

In most applications, it is important that the participant must be aware of what
they are signing. Thus the application should show the message to the
participant and obtain their consent to proceed before producing the signature
share.

Coordinator, Aggregate

Upon receiving the SignatureShares from the participants, the Coordinator can finally produce the final signature by calling aggregate() with the same SigningPackage sent to the participants and the PublicKeyPackage from the key generation (which is used to validate each SignatureShare).

{{#include ../../../frost-ristretto255/README.md:aggregate}}

The returned signature, a Signature, will be a valid signature for the message in the SigningPackage in Round 2 for the group verifying key in the PublicKeyPackage.

FROST supports identifiable abort: if a participant misbehaves and produces an
invalid signature share, then aggregation will fail and the returned error
will have the identifier of the misbehaving participant. (If multiple participants
misbehave, only the first one detected will be returned.)

What should be done in that case is up to the application. The misbehaving participant
could be excluded from future signing sessions, for example.

Verifying signatures

The Coordinator could verify the signature with:

{{#include ../../../frost-ristretto255/README.md:verify}}

(There is no need for the Coordinator to verify the signature since that already happens inside aggregate(). This just shows how the signature can be verified.)