diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 9829d60f..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,27 +0,0 @@ -# 0.8.0 - -- Added an extra requirement to Curve API for constant-time scalar sampling - -# 0.7.0 - -- Remove triple setup interface, always doing a fresh setup, for security reasons. -- Fix various security bugs. -- Update dependencies. - -# 0.6.0 - -- Modify specification to use a single threshold (turns out the code accidentally enforced this already) -- Modify code to match simplified presigning protocol because of this threshold. -- Modify specification to pre-commit to C polynomial in triple generation. -- Modify code accordingly. - -# 0.5.0 - -- Modify specification & implementation to use perfectly hiding commitments. -- Update dependencies to recent Rust-Crypto ECDSA versions. -- Support arbitrary curves and message hashes. -- Add curve description (name) to transcript in keysharing and triple generation. - -# 0.4.0 - -- Added key refresh and resharing protocols. diff --git a/LICENSE b/LICENSE index cf935f97..d86cec2c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,7 @@ +MIT + Copyright (c) 2023 Lúcás C. Meier +Copyright (c) 2025 NEAR One Limited Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 1f180d9e..2fbcdc8d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,70 @@ -# MPC Threshold Signatures -This repo contains implementations of Cait-Sith and FROST, used by the [MPC node](https://github.com/near/mpc) to compute threshold signatures. +# Threshold Signatures +This repository offers cryptographic implementations of **threshold ECDSA** and **threshold EdDSA**. Prior to [PR#15](https://github.com/near/threshold-signatures/pull/15), the implementation had undergone professional audit. + +The ECDSA code implements an OT-based threshold protocol and a Secret-Sharing based one. The former +is originally imported from the [Cait-Sith](https://github.com/cronokirby/cait-sith) library and amended to meet our industrial needs. This includes modifying parts of the code to improve the performance, augment the security, and generalize functions' syntax. The latter however is implemented from scratch and follows \[[DJNPØ](https://eprint.iacr.org/2020/501)\] + +The EdDSA implementation is mainly a wrapper of the [Frost](https://github.com/ZcashFoundation/frost) signing functions instantiated with Curve25519. + +# Code organization + +The repository provides implementations for both ECDSA and EdDSA. +Each signature scheme has its own repository that implements it, namely, `src/ecdsa` and `src/eddsa`. +Additionally `src/crypto` implements generic mathematical and cryptographic tools used for both schemes such as polynomial manipulations, randomness generation, commitment schemes, etc... `src/crypto/proofs` implements \[[Mau09](https://crypto.ethz.ch/publications/files/Maurer09.pdf)\] proofs for discrete logarithms, and `src/protocol` allows defining participants, communication channels, asynchronous functions that run and test the protocol and reliable broadcast channel. +Some additional files are found in `src`. `src/participants.rs` provides complex structures related to participants mainly based on hash maps and `src/generic_dkg.rs` implements a distributed key generation (DKG) that is agnostic of the curve. + +# Important Technical Details +## Threshold ECDSA Functionalities +The threshold ECDSA scheme is implemented over curve Secp256k1. +The following functionalities are provided: +1) **Distributed Key Generation (DKG)**: allows multiple parties to each generate its own secret key shares and a corresponding master public key. +2) **Key Resharing**: allows multiple parties to reshare their keys adding new members or kicking old members. If the sets of new/old participants is the same, then we talk about *key refreshing*. +3) **Beaver Triple Generation (offline)**: Allows the distributive generation of multiplicative (Beaver) triples $(a,b,c)$ and their commitments $(A, B, C)$ where +$c = a\cdot b$ and where $(A,B,C) = (g^a, g^b, g^c)$. These triples are essential for creating the presignatures. +4) **Presigning (offline)**: Allows generating some presignatures during an offline signing phase that will be consumed during the online signing phase when the message to be signed is known to the signers. +5) **Signing (online)**: Corresponds to the online signing phase in which the signing parties produce a valid signature + +## Threshold EdDSA Functionalities +The threshold EdDSA scheme is implemented over curve +Curve25519. We refer to such scheme as Ed25519. +The following functionalities are provided: +1) **Distributed Key Generation (DKG)**: Same as in ECDSA. +2) **Key Resharing**: Same as in ECDSA. +3) **Signing (online)**: Threshold EdDSA is generally more efficient than threshold ECDSA due to the mathematical formula behind the signature computation. Our Ed25519 implementation does not necessitate an offline phase of computation. + +## Comments + +* We do not implement any verification algorithm. In fact, a party possessing the message-signature pair can simply run the verification algorithm of the corresponding classic, non-distributed scheme using the master verification key. + +* Both implemented ECDSA and EdDSA schemes do not currently provide **Robustness** i.e. recovery in case a participants drops out during presigning/signing. + +* Our ECDSA signing scheme outsources the message hash to the function caller (i.e. expects a hashed message as input and does not internally hash the input). However, our EdDSA implementation does not outsource the message hashing instead internally performs the message hash. This distinction is an artifact of the multiple different verifiers implemented in the wild where some might perform a "double hashing" and others not. +(See \[[PoeRas24](https://link.springer.com/chapter/10.1007/978-3-031-57718-5_10)\] for an in-depth security study of ECDSA with outsourced hashing). + +* This implementation allows arbitrary number of parties and thresholds as long as the latter verifies some basic requirements (see the [documentation](docs/ecdsa/orchestration.md)). However, it is worth mentioning that the ECDSA scheme scales non-efficiently with the number of participants (Benchmarks to be added soon). + +* **🚨 Important 🚨:** Our DKG/Resharing protocol is the same for both ECDSA and EdDSA except the underlying elliptic curve instantiation. Internally, this DKG makes use of a reliable broadcast channel implemented for asynchronous peer-to-peer communication. Due to a fundamental impossibility theorem for asynchronous broadcast channel, our DKG/Resharing protocol can only tolerate $n/3$ malicious parties where $n$ is the total number of parties. + +# Build and Test +Building the crate is fairly simple using +``cargo build``. + +Run ``cargo test`` to run all the built-in test cases. Some of the tests might take some time to run as they require running complex protocols with multiple participants at once. + +# Benchmarks +* Benchmarks with 8 nodes -- TODO: https://github.com/near/threshold-signatures/issues/8 + +# Acknowledgements +This implementation relies on +[Cait-Sith](https://github.com/cronokirby/cait-sith) and +[Frost](https://github.com/ZcashFoundation/frost) and was possible thanks to contributors that actively put this together: +
+ Mårten Blankfors
+ Robin Cheng
+ Reynaldo Gil Pons
+ Chelsea Komlo
+ George Kuska
+ Matej Pavlovic
+ Simon Rastikian
+ Bowen Wang
+
diff --git a/docs/images/dark/dependencies.svg b/docs/ecdsa/images/dark/dependencies.svg similarity index 100% rename from docs/images/dark/dependencies.svg rename to docs/ecdsa/images/dark/dependencies.svg diff --git a/docs/images/light/dependencies.svg b/docs/ecdsa/images/light/dependencies.svg similarity index 100% rename from docs/images/light/dependencies.svg rename to docs/ecdsa/images/light/dependencies.svg diff --git a/docs/intro.md b/docs/ecdsa/intro.md similarity index 100% rename from docs/intro.md rename to docs/ecdsa/intro.md diff --git a/docs/orchestration.md b/docs/ecdsa/orchestration.md similarity index 100% rename from docs/orchestration.md rename to docs/ecdsa/orchestration.md diff --git a/docs/proofs.md b/docs/ecdsa/proofs.md similarity index 100% rename from docs/proofs.md rename to docs/ecdsa/proofs.md diff --git a/docs/signing.md b/docs/ecdsa/signing.md similarity index 100% rename from docs/signing.md rename to docs/ecdsa/signing.md diff --git a/docs/triples.md b/docs/ecdsa/triples.md similarity index 100% rename from docs/triples.md rename to docs/ecdsa/triples.md diff --git a/docs/key-generation.md b/docs/key-generation.md deleted file mode 100644 index c3c2ba9e..00000000 --- a/docs/key-generation.md +++ /dev/null @@ -1,96 +0,0 @@ -In this document, we describe a generalized version of key generation, -allowing for key refresh and resharing, and then apply that to -create two specific protocols: -1. A protocol for generating a fresh key. -2. A protocol for changing the threshold and set of participants but with the same key. - - -Given a set of players $\mathcal{P} = \{P_1, \ldots, P_N\}$, -and a desired threshold $t$, define -the following protocol: - -## KeyShare - -We assume that each participant in $\mathcal{P} := \\\{P_1, \ldots, P_n\\\}$ -has a secret share $s_i$ (which can possibly be $0$), which sum to $s := \sum_i s_i$ and that they share a public value $S$, -which is either $\bot$ (meaning no value), -or should equal $s \cdot G$. - -The goal of this protocol is for each particapant to obtain a fresh -threshold $t$ sharing of $s$, such that any $t$ participants -can reconstruct the value, along with the value $s \cdot G$, -if $S = \bot$. - -**Round 1:** - -1. $\blacktriangle$ Each $P_i$ *asserts* that $|\mathcal{P}| \geq t$. -2. $T.\text{Add}(\mathbb{G}, \mathcal{P}, t)$ -3. Each $P_i$ samples $f \xleftarrow{\\\$} \mathbb{F}_ q[X]_ {\leq t - 1}$, -subject to the constraint that $f(0) = s_i$. -4. Each $P_i$ sets $F_ i \gets f \cdot G$. -5. Each $P_i$ sets $(\text{Com}_i, r_i) \gets \text{Commit}(F_i)$. -6. $\star$ Each $P_i$ sends $\text{Com}_i$ to every other party. - -**Round 2:** - -1. $\bullet$ Each $P_i$ waits to receive $\text{Com}_j$ from each other $P_j$. -2. Each $P_i$ sets $\text{Confirm}_i \gets H(\text{Com}_1, \ldots, \text{Com}_N)$. -3. $T.\text{Add}(\text{Confirm}_i)$ -4. $\star$ Each $P_i$ sends $\text{Confirm}_i$ to every other party. -5. Each $P_i$ generates the proof $\pi_i \gets \text{Prove}(T.\text{Cloned}(\texttt{dlog0}, i), \text{Mau}(- \cdot G, F_{i}(0); f(0)))$. -6. $\star$ Each $P_i$ sends $(F_i, r_i, \pi_i)$ to every other party. -7. $\textcolor{red}{\star}$ Each $P_i$ *privately* sends $x_i^j := f(j)$ to each other party $P_j$, and saves $x_i^i$ for itself. - -**Round 3:** - -1. $\bullet$ Each $P_i$ waits to receive $\text{Confirm}_j$ from each other $P_j$. -2. $\blacktriangle$ Each $P_i$ *asserts* that $\forall j \in [N].\ \text{Confirm}_j = \text{Confirm}_i$, aborting otherwise. -3. $\bullet$ Each $P_i$ waits to receive $(F_j, r_j, \pi_j)$ from each other $P_j$. -4. $\blacktriangle$ Each $P_i$ *asserts* that $\forall j \in [N].\ \text{deg}(F_ j) = t -1 \land \text{CheckCommit}(\text{Com}_j, F_j, r_j) \land \text{Verify}(T.\text{Cloned}(\texttt{dlog0}, j), \pi_j, \text{Mau}({- \cdot G}, F_j(0)))$. -5. $\bullet$ Each $P_i$ waits to receive $x_j^i$ from each other $P_j$. -6. Each $P_i$ sets $x_i \gets \sum_j x^i_j$ and $X \gets \sum_j F_j(0)$. -7. $\blacktriangle$ Each $P_i$ asserts that $x_i \cdot G = (\sum_j F_j)(i)$. -8. (If $S \neq \bot$) $\blacktriangle$ Each $P_i$ asserts that $X = S$. -9. Each $P_i$ outputs $x_i$ and $X$. - -**Output** - -The value $x_i$ is $P_i$'s private share of the secret key $s$. - -$X$ is the public key shared by the group, which should be equal -to the previous value $S$, if it was provided. - -## Key Generation - -The key sharing protocol can be used for a standard key generation -protocol, by having each party sample $s_i$ randomly, -and setting $S = \bot$ (no expected public key). - -## Key Refresh - -A key refresh protocol can be performed by first linearizing the -shares $x_1, \ldots, x_n$, -setting $s_i \gets \lambda(\mathcal{P})_i \cdot x_i$, -and then using $S = X$, to check that the public key doesn't -change. - -## Key Resharing - -A key resharing protocol can be performed as well. -This involves transitioning from $(\mathcal{P}, t)$ -to $(\mathcal{P}', t')$, and can be performed as long -as $|\mathcal{P} \cap \mathcal{P}'| \geq t$, -i.e. there are enough old parties with a share. -The end result is that the new set of parties -hold threshold $t'$ shares of the same private key. - -This works by having each party in $\mathcal{P} \cap \mathcal{P}'$ linearize their share, -setting $s_i \gets \lambda(\mathcal{P})_i \cdot x_i$. -Each party in $\mathcal{P}' / \mathcal{P}$ (the new members), -simply set $s_i \gets 0$. -We also set $S = X$, to check that the same public key -is generated. - -Key refresh can be seen as a natural case of -key resharing, with $\mathcal{P} = \mathcal{P}'$, -and $t = t'$. diff --git a/logo.png b/logo.png deleted file mode 100644 index 33b8c3b3..00000000 Binary files a/logo.png and /dev/null differ