Skip to content
SAYaghoubnejad edited this page Feb 11, 2024 · 5 revisions

PyFrost

PyFrost is a Python-based implementation of the FROST (Flexible Round-Optimized Schnorr Threshold Signatures) protocol. This protocol stands out in the field of threshold signature protocols due to its efficient approach that allows signing in a single round. PyFrost follows the standard FROST protocol for these single-round signing operations.

In addition, PyFrost integrates features from the Identifiable Cheating Entity FROST Signature Protocol within its distributed key generation (DKG) framework. This enhancement helps identify and address malicious activities. For instance, it can detect scenarios where dishonest participants might selectively share secrets during the DKG process, aiming to unfairly exclude honest participants.

For those new to these concepts, this tutorial offers a beginner-friendly introduction. It covers essential cryptographic concepts integral to PyFrost, such as Threshold Signatures, Distributed Key Generation, Cheating Identification, Standard Schnorr Signatures, and Single-Round Schnorr Threshold Signatures.

The PyFrost package not only implements the cryptographic functionalities of the FROST protocol but also includes a networking package. This package features libp2p clients, which are essential for nodes, signature aggregators, and distributed key generators, facilitating and secure network communications.

Frost Implementation

We have implemented the FROST algorithm based on the Identifiable Cheating Entity FROST Signature Protocol. This implementation assigns a unique set of private-public keys to each node per DKG. It uses the private key of the $i$th node and the public key of the $j$th node to secure data exchange between nodes $i$ and $j$. The data exchange, including the broadcast of round1 data and the secret sharing in round2, is facilitated through a broadcast channel (i.e., DKG Initiator found in pyfrost/network/dkg.py). In the event of dishonesty, a complaining node can reveal its private key. This enables decryption and verification of the message sent to the complainant to ascertain the accused node's guilt or innocence.

The cryptographic functions of this implementation are summarized as follows:

  1. pyfrost.KeyGen.round1(): Initiates key generation.
  2. pyfrost.KeyGen.round2(): Processes data from the first round and prepares data to exchange between each set of nodes.
  3. pyfrost.KeyGen.round3(): Finalizes key generation and handles complaints.
  4. pyfrost.Key.sign(): Generates a partial signature.
  5. pyfrost.create_nonces(): Creates nonces for signature issuance.
  6. pyfrost.aggregate_nonce(): Aggregates nonces for signature verification.
  7. pyfrost.aggregate_signatures(): Combines individual signatures into a single, verifiable signature.
  8. pyfrost.verify_single_signature(): Verifies each node's signature share.
  9. pyfrost.verify_group_signature(): Validates the aggregated group signature.

Detailed information about each function, including their input and output formats, can be found in the PyFrost Documentation.

Network

As illustrated in Figure 1, our PyFrost implementation employs a peer-to-peer (P2P) architecture as the foundation for Multi-Party Communication (MPC). Communication is facilitated using py-libp2p or the HTTP protocol as the network protocol. This setup is vital for both Distributed Key Generation (DKG) and the signature issuance processes. Within our network architecture, nodes serve as servers, awaiting instructions from either the DKG initiator or the Signature Aggregator (SA). Upon receiving calls from the DKG initiator or SA, these nodes execute the corresponding functions (handlers). In this architecture, the DKG initiator and SA take the roles of clients within our system.

PyFrost System Components

Figure 1: This figure depicts the different components of the PyFrost network and their interconnections.

Node

Nodes are the fundamental units of the PyFrost network, participating actively in the Multi-Party Communication (MPC) process. Each node effectively functions as a py-libp2p or HTTP server, handling incoming requests (e.g., round1 of DKG or sign), processing these requests, and invoking PyFrost's corresponding functions to fulfill them. Nodes are also tasked with maintaining data (utilizing a database when necessary) and ensuring the authenticity and authorization of request callers. Moreover, nodes offer a feature enabling developers to validate data before signing, using a decorator. The code examples are accessible at pyfrost/examples/libp2p/node.py and pyfrost/examples/http/node.py.

Distributed Key Generation (DKG) Initiator

The DKG Initiator, operating as a py-libp2p or HTTP client, is charged with initiating the DKG process and managing the generated keys upon response reception. Specifically, the DKG Initiator calls round1 on selected nodes from a group of $n$ nodes designated for participation in the DKG process. It then receives data for broadcasting to all nodes in the party, along with a request to initiate round2. Following round2 completion, the DKG initiator collects encrypted data from each node, which is then unpacked, aggregated, and dispatched to respective nodes for round3. Upon successful completion of round3 (assuming no complaints), the DKG Initiator acquires the distributed key and each node's public share.

PyFrost DKG

Figure 2 illustrates the distributed key generation procedure.

Signature Aggregator (SA)

The Signature Aggregator (SA) operates similarly as a py-libp2p or HTTP client, tasked with requesting signature issuances. As shown in Figure 3, establishing a random nonce between each Node and the SA is critical (the nonce concept is detailed in the PyFrost TSS protocol documentation). To establish these nonces, the SA sends a call request indicating the desired batch size of nonces to the Node. The Node then generates a batch of random numbers, each representing a set of public-private keys, stores them, and sends the public keys back to the SA.

For signature issuance, the SA creates another call and sends it to the Nodes, along with a list of nonces, each comprising a public nonce generated by the respective Nodes. Each Node then validates the data to be signed, retrieves its share from the distributed key and its private part of the nonce it generated, signs the data and nonces with its share, and sends the signed data along with the signature back to the SA for aggregation with other signatures. This process is depicted in Figure 4.

PyFrost Nonces

Figure 3 highlights the nonce exchange between Nodes and the SA.

PyFrost Sign

Figure 4 demonstrates the signature issuance process in PyFrost.

How to Build a Network Using PyFrost?

To implement a P2P network for issuing Frost signatures, specific steps must be followed. This involves implementing several abstract methods within our system, which we will discuss in the following section. Then, by running Nodes (as demonstrated in pyfrost/examples/http/node.py and pyfrost/examples/libp2p/node.py) along with the SA and DKG Initiator (as shown in pyfrost/examples/http/example.py and pyfrost/examples/libp2p/example.py), you can establish your own network.

Abstract Methods

To inherit from the pyfrost/network_http or pyfrost/network_libp2p module, certain functions need to be implemented. These are detailed in pyfrost/network_http/abstract.py or pyfrost/network_libp2p/abstract.py, respectively. These files consist of three abstract classes:

  1. DataManager: This class is responsible for maintaining the data source of nonces and keys. By implementing the six methods: get_nonce, set_nonce, remove_nonce, get_key, set_key, and remove_key, developers can utilize any desired databases or data structures they wish to store the data regarding nonces and keys.

  2. NodesInfo: This class is used to retrieve data regarding nodes from a data source through lookup_node and get_all_nodes functions.

  3. Validators: This class checks if a caller of a method has the authority to call that method, which is done in caller_validator. Additionally, this class has a data_validator method that checks the validity of data that is going to be signed.

For more information on these abstract classes and methods, feel free to explore the source code available at pyfrost/network_http/abstract.py or pyfrost/network_libp2p/abstract.py. You can also review our example implementations at pyfrost/examples/http/abstracts.py and pyfrost/examples/libp2p/abstracts.py.