1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
//! 
//! [](https://docs.rs/cggmp21)
//! [](https://crates.io/crates/cggmp21)
//!
//! # Threshold ECDSA based on [CGGMP21] paper
//!
//! <!-- TOC -->
#![doc = include_str!("../docs/toc-cggmp21.md")]
//!
//! [CGGMP21] is a state-of-art ECDSA TSS protocol that supports 1-round signing (requires preprocessing),
//! identifiable abort, provides two signing protocols (3+1 and 5+1 rounds with different complexity
//! of abort identification) and key refresh protocol out of the box.
//!
//! This crate implements:
//! * Threshold (i.e., t-out-of-n) and non-threshold (i.e., n-out-of-n) key generation
//! * (3+1)-round general threshold and non-threshold signing
//! * Auxiliary info generation protocol
//! * Key refresh for non-threshold keys
//! * HD-wallets support based on [slip10] standard (compatible with [bip32]) \
//! Requires `hd-wallets` feature
//!
//! A self-contained description of the protocols we implemented is available [here][the spec].
//!
//! We also provide auxiliary tools like:
//! * [Secret key reconstruction](crate::key_share::reconstruct_secret_key) (exporting key from TSS)
//! * [Trusted dealer](crate::trusted_dealer) (importing key into TSS)
//!
//! This crate **does not** (currently) support:
//! * Key refresh for threshold keys (i.e., t-out-of-n)
//! * Identifiable abort
//! * The (5+1)-round signing protocol
//!
//! Our implementation has been audited by Kudelski. Report can be found [here][report].
//!
//! > About notion of threshold and non-threshold keys: originally, CGGMP21 paper does not have support of
//! arbitrary `t` and only works with non-threshold n-out-of-n keys. We have added support of arbitrary
//! threshold $2 \le t \le n$, however, we made it possible to opt out therhsoldness so original CGGMP21
//! protocol can be carried out if needed.
//!
//! ## Running the protocol
//!
//! ### Networking
//! The most essential part of running an interactive protocol is to define how parties can communicate with
//! each other. Our `cggmp21` library is agnostic to the network layer and only requires you to provide two
//! things: a stream of incoming messages and a sink for outgoing messages, i.e.:
//!
//! ```rust,ignore
//! let incoming: impl Stream<Item = Result<Incoming<Msg>>>;
//! let outgoing: impl Sink<Outgoing<Msg>>;
//! ```
//!
//! where:
//! * `Msg` is a protocol message (e.g., [`signing::msg::Msg`])
//! * [`round_based::Incoming`] and [`round_based::Outgoing`] wrap `Msg` and provide additional data (e.g., sender/recepient)
//! * [`futures::Stream`] and [`futures::Sink`] are well-known async primitives.
//!
//! Once you have that, you can construct an [MpcParty][round_based::MpcParty]:
//! ```rust
//! # type Msg = cggmp21::signing::msg::Msg<cggmp21::supported_curves::Secp256k1, sha2::Sha256>;
//! # let incoming = futures::stream::pending::<Result<round_based::Incoming<Msg>, std::convert::Infallible>>();
//! # let outgoing = futures::sink::drain::<round_based::Outgoing<Msg>>();
//! let delivery = (incoming, outgoing);
//! let party = round_based::MpcParty::connected(delivery);
//! ```
//!
//! The concrete networking implementation to use will depend heavily on the specific application.
//! Some applications may use libp2p; others may prefer having a central delivery server or a database
//! (like Redis or Postgres); some specific applications may want to communicate over a public
//! blockchain, and so on.
//!
//! Whatever networking implementation you use, keep in mind that:
//!
//! * All messages must be authenticated \
//! Whenever one party receives a message from another, the receiver should cryptographically
//! verify that the message comes from the claimed sender.
//! * All p2p messages must be encrypted \
//! Only the designated recipient should be able to read the message
//!
//! #### Signer indices
//! Our library uses indices to uniquely refer to particular signers sharing a key. Each index `i`
//! is an unsigned integer `u16` with $0 \le i < n$ where `n` is the total number of parties.
//!
//! All signers should have the same view about each others' indices. For instance, if Signer A
//! holds index 2, then all other signers must agree that i=2 corresponds to Signer A.
//!
//! Assuming some sort of PKI (which would anyway likely be used to ensure secure communication,
//! as described above), each signer has a public key that uniquely identifies that signer.
//! It is then possible to assign unique indices to the signers by lexicographically sorting the
//! signers' public keys, and letting the index of a signer be the position of that signer's public
//! key in the sorted list.
//!
//! ### Execution ID
//! Execution of our protocols requires all participants to agree on unique execution ID (aka
//! session identifier) that is assumed never to repeat. This string provides context separation
//! between different executions of the protocol to ensure that an adversary cannot replay messages
//! from one execution to another.
//!
//! Once signers can talk to each other and share an execution ID, they're ready to do MPC!
//!
//! ### Auxiliary info generation
//! In the usual flow, signers run a protocol for auxiliary-data generation before running distributed
//! key generation. This protocol sets up certain parameters (in particular, Paillier moduli
//! for each of the signers) that will be used during the signing protocols. This protocol can be
//! run as follows:
//!
//! ```rust,no_run
//! # async fn doc() -> Result<(), cggmp21::KeyRefreshError> {
//! # type Msg = cggmp21::key_refresh::msg::aux_only::Msg<sha2::Sha256, cggmp21::security_level::SecurityLevel128>;
//! # let incoming = futures::stream::pending::<Result<round_based::Incoming<Msg>, std::convert::Infallible>>();
//! # let outgoing = futures::sink::drain::<round_based::Outgoing<Msg>>();
//! # let delivery = (incoming, outgoing);
//! # let party = round_based::MpcParty::connected(delivery);
//! #
//! # use rand_core::OsRng;
//! // Prime generation can take a while
//! let pregenerated_primes = cggmp21::PregeneratedPrimes::generate(&mut OsRng);
//!
//! let eid = cggmp21::ExecutionId::new(b"execution id, unique per protocol execution");
//! let i = /* signer index, same as at keygen */
//! # 0;
//! let n = /* number of signers */
//! # 3;
//!
//! let aux_info = cggmp21::aux_info_gen(eid, i, n, pregenerated_primes)
//! .start(&mut OsRng, party)
//! .await?;
//! # Ok(()) }
//! ```
//!
//! The auxiliary-data generation protocol is computationally heavy as it requires the generation
//! of safe primes and involves several zero-knowledge (ZK) proofs.
//!
//! #### On reusability of the auxiliary data
//! The CGGMP21 paper assumes that new auxiliary data is generated for each secret key that is shared.
//! However, examination of the proof shows that this is not necessary, and a fixed group of signers
//! can use the same auxiliary data for the secure sharing/usage of multiple keys.
//!
//! ### Distributed Key Generation (DKG)
//! The DKG protocol involves all signers who will co-share a key. All signers need to agree on
//! some basic parameters including the participants' indices, the execution ID, and the
//! threshold value (i.e., t). The protocol can be executed as
//!
//! ```rust,no_run
//! # async fn doc() -> Result<(), cggmp21::KeygenError> {
//! # type Msg = cggmp21::keygen::msg::threshold::Msg<cggmp21::supported_curves::Secp256k1, cggmp21::security_level::SecurityLevel128, sha2::Sha256>;
//! # let incoming = futures::stream::pending::<Result<round_based::Incoming<Msg>, std::convert::Infallible>>();
//! # let outgoing = futures::sink::drain::<round_based::Outgoing<Msg>>();
//! # let delivery = (incoming, outgoing);
//! # let party = round_based::MpcParty::connected(delivery);
//! #
//! use cggmp21::supported_curves::Secp256k1;
//! # use rand_core::OsRng;
//!
//! let eid = cggmp21::ExecutionId::new(b"execution id, unique per protocol execution");
//! let i = /* signer index (0 <= i < n) */
//! # 0;
//! let n = /* number of signers taking part in key generation */
//! # 3;
//! let t = /* threshold */
//! # 2;
//!
//! let incomplete_key_share = cggmp21::keygen::<Secp256k1>(eid, i, n)
//! .set_threshold(t)
//! .start(&mut OsRng, party)
//! .await?;
//! # Ok(()) }
//! ```
//!
//! The above produces an [`IncompleteKeyShare`]. An incomplete key share can be saved on disk by serializing using
//! [`serde` crate][serde]. Treat this material appropriately as it contains sensitive information.
//!
//! Assuming auxiliary-data generation has already been done (see above), you can "complete" the
//! key share using:
//!
//! ```rust,no_run
//! # let (incomplete_key_share, aux_info): (cggmp21::IncompleteKeyShare<cggmp21::supported_curves::Secp256k1>, cggmp21::key_share::AuxInfo) = unimplemented!();
//! let key_share = cggmp21::KeyShare::from_parts((incomplete_key_share, aux_info))?;
//! # Ok::<_, cggmp21::key_share::InvalidKeyShare>(())
//! ```
//!
//! ### Signing
//! Once signers have a set of "completed" key shares, they can sign or generate presignatures.
//! In either case, exactly the threshold number (i.e., t) of signers must take part in the protocol.
//! As in the DKG protocol, each signer needs to be assigned a unique index, now in the range from 0
//! to t-1. But the signers also need to know which index each signer occupied at the time of keygen.
//!
//! In the example below, we do a full signing:
//! ```rust,no_run
//! # async fn doc() -> Result<(), cggmp21::SigningError> {
//! # type Msg = cggmp21::signing::msg::Msg<cggmp21::supported_curves::Secp256k1, sha2::Sha256>;
//! # let incoming = futures::stream::pending::<Result<round_based::Incoming<Msg>, std::convert::Infallible>>();
//! # let outgoing = futures::sink::drain::<round_based::Outgoing<Msg>>();
//! # let delivery = (incoming, outgoing);
//! # let party = round_based::MpcParty::connected(delivery);
//! #
//! # use rand_core::OsRng; use sha2::Sha256;
//! # const MIN_SIGNERS: usize = 3;
//! #
//! let eid = cggmp21::ExecutionId::new(b"execution id, unique per protocol execution");
//!
//! let i = /* signer index (0 <= i < min_signers) */
//! # 0;
//! let parties_indexes_at_keygen: [u16; MIN_SIGNERS] =
//! /* parties_indexes_at_keygen[i] is the index the i-th party had at keygen */
//! # [0, 1, 2];
//! let key_share = /* completed key share */
//! # {let s: cggmp21::KeyShare<cggmp21::supported_curves::Secp256k1> = unimplemented!(); s};
//!
//! let data_to_sign = cggmp21::DataToSign::digest::<Sha256>(b"data to be signed");
//!
//! let signature = cggmp21::signing(eid, i, &parties_indexes_at_keygen, &key_share)
//! .sign(&mut OsRng, party, data_to_sign)
//! .await?;
//! # Ok(()) }
//! ```
//!
//! Alternatively, you can generate a presignature and later use it to sign:
//! 1. Use [`SigningBuilder::generate_presignature`] to run the presignature generation protocol
//! 2. Later, when a signing request is received, each signer issues a partial signature using
//! [`Presignature::issue_partial_signature`]
//! 3. A threshold number of partial signatures can be combined using [`PartialSignature::combine`] to
//! obtain a full signature
//!
//! **Never reuse presignatures!** If you use the same presignature to sign two different messages,
//! the private key may be leaked.
//!
//! ## Sync API
//! Every protocol is defined as async function. If you need to run a protocol in non-async environment,
//! library provides a wrapper that allows you to execute protocol using sync API only.
//!
//! To use it, you need to enable `state-machine` feature. Then, for every protocol definition, you can
//! find a companion function that returns [`StateMachine`](round_based::state_machine::StateMachine)
//! which can be used to carry out the protocol. For instance, if you do presignature generation, use
//! [`signing::SigningBuilder::generate_presignature_sync`].
//!
//! ## HD wallets support
//! Library supports non-hardened deterministic key derivation based on [slip10] standard (compatible
//! with [bip32]). It allows signers to generate a master key once, and then use it to instantaneously
//! derive as many child keys as needed. Child key derivation takes place within signing protocol
//! practically at no cost.
//!
//! In order to use HD wallets, `hd-wallets` feature must be enabled. Then, a master key needs to be
//! generated by running a regular key generation protocol with [`hd_wallet`](keygen::GenericKeygenBuilder::hd_wallet)
//! set to `true`.
//!
//! When master key is generated, you can issue a signature for child key by setting
//! [derivation path](signing::SigningBuilder::set_derivation_path) in the signing.
//!
//! ## SPOF code: Key Import and Export
//! CGGMP21 protocol is designed to avoid Single Point of Failure by guaranteeing that attacker would
//! need to compromise threshold amount of nodes to obtain a secret key. However, some use-cases may
//! require you to create a SPOF, for instance, importing an existing key into TSS and exporting key
//! from TSS.
//!
//! Such use-cases contradict to nature of MPC so we don't include those primitives by default.
//! However, you may opt for them by enabling `spof` feature, then you can use [`trusted_dealer`]
//! for key import and [`key_share::reconstruct_secret_key`] for key export.
//!
//! ## Differences between the implementation and CGGMP21
//! [CGGMP21] only defines a non-threshold protocol. To support general thresholds,
//! we defined our own CGGMP21-like key generation and threshold signing
//! protocols. However, we keep both
//! threshold and non-threshold versions of the protocols in the crate, so if you opt for the non-threshold
//! protocol, you will be running the original protocol defined in the paper.
//!
//! There are other (small) differences in the implementation compared to the original paper (mostly typo fixes);
//! they are all documented in [the spec].
//!
//! [CGGMP21]: https://ia.cr/2021/060
//! [the spec]: https://dfns.github.io/cggmp21/cggmp21-spec.pdf
//! [security guidelines]: #security-guidelines
//! [slip10]: https://github.com/satoshilabs/slips/blob/master/slip-0010.md
//! [bip32]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
//! [report]: https://github.com/dfns/cggmp21/blob/m/docs/audit_report.pdf
//! [serde]: https://serde.rs/
//!
//! ## Timing attacks
//! Timing attacks are type of side-channel attacks that leak sensitive information through duration of
//! execution. We consider timing attacks out of scope as they are nearly impossible to perform for such
//! complicated protcol as CGGMP21 and impossible to do in our specific deployment. Thus, we intentionally
//! don't do constant-time operations which gives us a significant performance boost.
#![allow(
non_snake_case,
mixed_script_confusables,
uncommon_codepoints,
clippy::too_many_arguments,
clippy::nonminimal_bool
)]
#![forbid(clippy::disallowed_methods, missing_docs, unsafe_code)]
#![cfg_attr(not(test), forbid(unused_crate_dependencies))]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[cfg(feature = "hd-wallets")]
pub use slip_10;
pub use {
generic_ec, paillier_zk,
paillier_zk::{fast_paillier, rug},
round_based,
};
#[doc(inline)]
pub use cggmp21_keygen::{keygen, progress, ExecutionId};
use generic_ec::{coords::HasAffineX, Curve, Point};
use key_share::AnyKeyShare;
use round_based::PartyIndex;
use security_level::SecurityLevel;
use signing::SigningBuilder;
mod errors;
pub mod key_refresh;
pub mod key_share;
pub mod security_level;
pub mod signing;
pub mod supported_curves;
mod utils;
mod zk;
#[cfg(feature = "spof")]
pub mod trusted_dealer;
/// Defines default choice for digest and security level used across the crate
mod default_choice {
pub type Digest = sha2::Sha256;
pub type SecurityLevel = crate::security_level::SecurityLevel128;
}
/// Threshold and non-threshold CGGMP21 DKG
pub mod keygen {
#[doc(inline)]
pub use cggmp21_keygen::{
msg, GenericKeygenBuilder, KeygenBuilder, KeygenError, NonThreshold,
ThresholdKeygenBuilder, WithThreshold,
};
pub use msg::non_threshold::Msg as NonThresholdMsg;
pub use msg::threshold::Msg as ThresholdMsg;
}
pub use self::{
key_refresh::{KeyRefreshError, PregeneratedPrimes},
key_share::{IncompleteKeyShare, KeyShare},
keygen::KeygenError,
signing::{DataToSign, PartialSignature, Presignature, Signature, SigningError},
};
/// Protocol for finalizing the keygen by generating aux info.
///
/// PregeneratedPrimes can be obtained with [`key_refresh::PregeneratedPrimes::generate`]
///
/// Index `i` of party should be the same as index [inside the key share] you are
/// going to use this aux info with. Number of parties `n` should be the same [as number
/// of signers] sharing the key.
///
/// Outputs [`AuxInfo`](key_share::AuxInfo) that can be used to "complete" [`IncompleteKeyShare`]
/// using [`KeyShare::from_parts`].
///
/// [inside the key share]: key_share::DirtyIncompleteKeyShare::i
/// [as number of signers]: IncompleteKeyShare::n
pub fn aux_info_gen<L>(
eid: ExecutionId,
i: u16,
n: u16,
pregenerated: key_refresh::PregeneratedPrimes<L>,
) -> key_refresh::AuxInfoGenerationBuilder<L>
where
L: SecurityLevel,
{
key_refresh::GenericKeyRefreshBuilder::new_aux_gen(eid, i, n, pregenerated)
}
/// Protocol for performing key refresh. Can be used to perform initial refresh
/// with aux info generation, or for a refresh of a complete key share.
///
/// Doesn't work with general-threshold key shares at this point.
///
/// PregeneratedPrimes can be obtained with [`key_refresh::PregeneratedPrimes::generate`]
pub fn key_refresh<'a, E, L>(
eid: ExecutionId<'a>,
key_share: &'a impl AnyKeyShare<E>,
pregenerated: key_refresh::PregeneratedPrimes<L>,
) -> key_refresh::KeyRefreshBuilder<'a, E, L>
where
E: Curve,
L: SecurityLevel,
{
key_refresh::KeyRefreshBuilder::new(eid, key_share, pregenerated)
}
/// Protocol for generating a signature or presignature
pub fn signing<'r, E, L>(
eid: ExecutionId<'r>,
i: PartyIndex,
parties_indexes_at_keygen: &'r [PartyIndex],
key_share: &'r KeyShare<E, L>,
) -> SigningBuilder<'r, E, L>
where
E: Curve,
Point<E>: HasAffineX<E>,
L: SecurityLevel,
{
SigningBuilder::new(eid, i, parties_indexes_at_keygen, key_share)
}
#[cfg(test)]
mod tests {
use digest::Digest;
use generic_ec::Curve;
use serde::{de::DeserializeOwned, Serialize};
use crate::security_level::SecurityLevel;
macro_rules! ensure_certain_types_impl_serde {
($($type:ty),+,) => {
fn impls_serde<T: Serialize + DeserializeOwned>() {}
#[allow(dead_code)]
fn ensure_types_impl_serde<E: Curve, L: SecurityLevel, D: Digest>() {$(
impls_serde::<$type>();
)+}
}
}
ensure_certain_types_impl_serde! {
crate::key_share::KeyShare<E, L>,
crate::key_share::IncompleteKeyShare<E>,
crate::key_share::AuxInfo<L>,
crate::key_share::DirtyKeyShare<E, L>,
crate::key_share::DirtyIncompleteKeyShare<E>,
crate::key_share::DirtyAuxInfo<L>,
crate::keygen::msg::non_threshold::Msg<E, L, D>,
crate::keygen::msg::threshold::Msg<E, L, D>,
crate::key_refresh::msg::aux_only::Msg<D, L>,
crate::key_refresh::msg::non_threshold::Msg<E, D, L>,
crate::signing::msg::Msg<E, D>,
crate::signing::Presignature<E>,
crate::signing::PartialSignature<E>,
crate::signing::Signature<E>,
}
}