mithril_stm/
lib.rs

1#![doc = include_str!("../README.md")]
2//! Implementation of Stake-based Threshold Multisignatures
3//! Top-level API for Mithril Stake-based Threshold Multisignature scheme.
4//! See figure 6 of [the paper](https://eprint.iacr.org/2021/916) for most of the
5//! protocol.
6//!
7//! What follows is a simple example showing the usage of STM.
8//!
9//! ```rust
10//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
11//! use blake2::{Blake2b, digest::consts::U32};
12//! use rand_chacha::ChaCha20Rng;
13//! use rand_core::{RngCore, SeedableRng};
14//! use rayon::prelude::*; // We use par_iter to speed things up
15//!
16//! use mithril_stm::{
17//!    AggregateSignatureType, AggregationError, Clerk, Initializer, KeyRegistration, Parameters,
18//!    RegistrationEntry, Signer, SingleSignature, MithrilMembershipDigest,
19//! };
20//!
21//! let nparties = 4; // Use a small number of parties for this example
22//! type D = MithrilMembershipDigest; // Setting the hash function for convenience
23//!
24//! let mut rng = ChaCha20Rng::from_seed([0u8; 32]); // create and initialize rng
25//! let mut msg = [0u8; 16]; // setting an arbitrary message
26//! rng.fill_bytes(&mut msg);
27//!
28//! // In the following, we will have 4 parties try to sign `msg`, then aggregate and
29//! // verify those signatures.
30//!
31//! //////////////////////////
32//! // initialization phase //
33//! //////////////////////////
34//!
35//! // Set low parameters for testing
36//! // XXX: not for production
37//! let params = Parameters {
38//!     m: 100, // Security parameter XXX: not for production
39//!     k: 2, // Quorum parameter XXX: not for production
40//!     phi_f: 0.2, // Lottery parameter XXX: not for production
41//! };
42//!
43//! // Generate some arbitrary stake for each party
44//! // Stake is an integer.
45//! // Total stake of all parties is total stake in the system.
46//! let stakes = (0..nparties)
47//!     .into_iter()
48//!     .map(|_| 1 + (rng.next_u64() % 9999))
49//!     .collect::<Vec<_>>();
50//!
51//! // Create a new key registry from the parties and their stake
52//! let mut key_reg = KeyRegistration::initialize();
53//!
54//! // For each party, crate a Initializer.
55//! // This struct can create keys for the party.
56//! let mut ps: Vec<Initializer> = Vec::with_capacity(nparties);
57//! for stake in stakes {
58//!     // Create keys for this party
59//!     let p = Initializer::new(params, stake, &mut rng);
60//!     // Register keys with the KeyRegistration service
61//!     let entry = RegistrationEntry::new(
62//!         p.get_verification_key_proof_of_possession_for_concatenation(),
63//!         p.stake,
64//!        #[cfg(feature = "future_snark")] p.schnorr_verification_key,
65//!     )
66//!     .unwrap();
67//!     key_reg.register_by_entry(&entry).unwrap();
68//!     ps.push(p);
69//! }
70//!
71//! // Close the key registration.
72//! let closed_reg = key_reg.close_registration();
73//!
74//! // Finalize the Initializer and turn it into a Signer, which can execute the
75//! // rest of the protocol.
76//! let ps = ps
77//!     .into_par_iter()
78//!     .map(|p| p.try_create_signer(&closed_reg).unwrap())
79//!     .collect::<Vec<Signer<D>>>();
80//!
81//! /////////////////////
82//! // operation phase //
83//! /////////////////////
84//!
85//! // Next, each party tries to sign the message for each index available.
86//! // We collect the successful signatures into a vec.
87//! let sigs = ps
88//!     .par_iter()
89//!     .filter_map(|p| p.create_single_signature(&msg).ok())
90//!     .collect::<Vec<SingleSignature>>();
91//!
92//! // Clerk can aggregate and verify signatures.
93//! let clerk = Clerk::new_clerk_from_signer(&ps[0]);
94//!
95//! // Aggregate and verify the signatures
96//! let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, AggregateSignatureType::Concatenation);
97//! match msig {
98//!     Ok(aggr) => {
99//!         println!("Aggregate ok");
100//!         assert!(aggr
101//!             .verify(&msg, &clerk.compute_aggregate_verification_key(), &params)
102//!             .is_ok());
103//!     }
104//!     Err(error) => assert!(
105//!         matches!(
106//!             error.downcast_ref::<AggregationError>(),
107//!             Some(AggregationError::NotEnoughSignatures { .. })
108//!         ),
109//!         "Unexpected error: {error}"
110//!     ),
111//! }
112//! # Ok(())
113//! # }
114//! ```
115
116#[cfg(feature = "future_snark")]
117pub mod circuits;
118#[cfg(feature = "future_snark")]
119mod hash;
120mod membership_commitment;
121mod proof_system;
122mod protocol;
123mod signature_scheme;
124
125pub use proof_system::AggregateVerificationKeyForConcatenation;
126pub use protocol::{
127    AggregateSignature, AggregateSignatureError, AggregateSignatureType, AggregateVerificationKey,
128    AggregationError, Clerk, ClosedKeyRegistration, ClosedRegistrationEntry, Initializer,
129    KeyRegistration, Parameters, RegisterError, RegistrationEntry,
130    RegistrationEntryForConcatenation, SignatureError, Signer, SingleSignature,
131    SingleSignatureWithRegisteredParty, VerificationKeyForConcatenation,
132    VerificationKeyProofOfPossessionForConcatenation,
133};
134pub use signature_scheme::BlsSignatureError;
135
136use blake2::{Blake2b, digest::consts::U32};
137use digest::{Digest, FixedOutput};
138use std::fmt::Debug;
139
140#[cfg(feature = "benchmark-internals")]
141pub use signature_scheme::{
142    BlsProofOfPossession, BlsSignature, BlsSigningKey, BlsVerificationKey,
143    BlsVerificationKeyProofOfPossession,
144};
145
146#[cfg(feature = "future_snark")]
147pub use signature_scheme::{
148    BaseFieldElement, SchnorrSigningKey, SchnorrVerificationKey, UniqueSchnorrSignature,
149};
150
151#[cfg(feature = "future_snark")]
152use hash::poseidon::MidnightPoseidonDigest;
153
154#[cfg(feature = "future_snark")]
155pub use protocol::VerificationKeyForSnark;
156
157/// The quantity of stake held by a party, represented as a `u64`.
158pub type Stake = u64;
159
160/// Quorum index for signatures.
161/// An aggregate signature (`StmMultiSig`) must have at least `k` unique indices.
162pub type LotteryIndex = u64;
163
164/// Index of the signer in the key registration
165pub type SignerIndex = u64;
166
167/// Mithril-stm error type
168pub type StmError = anyhow::Error;
169
170/// Mithril-stm result type
171pub type StmResult<T> = anyhow::Result<T, StmError>;
172
173#[cfg(feature = "future_snark")]
174// TODO: remove this allow dead_code directive when function is called or future_snark is activated
175#[allow(dead_code)]
176/// Target value type used in the lottery for snark proof system
177pub type LotteryTargetValue = crate::signature_scheme::BaseFieldElement;
178
179/// Trait defining the different hash types for different proof systems.
180pub trait MembershipDigest: Clone {
181    type ConcatenationHash: Digest + FixedOutput + Clone + Debug + Send + Sync;
182    #[cfg(feature = "future_snark")]
183    type SnarkHash: Digest + FixedOutput + Clone + Debug + Send + Sync;
184}
185
186/// Default Mithril Membership Digest
187#[derive(Clone, Debug, Default)]
188pub struct MithrilMembershipDigest {}
189
190/// Default implementation of MembershipDigest for Mithril
191/// TODO: `SnarkHash` will be changed with Poseidon. For now, we use `Blake2b<U64>` (`U64` is set
192/// for having something different than the `ConcatenationHash`) as a placeholder.
193impl MembershipDigest for MithrilMembershipDigest {
194    type ConcatenationHash = Blake2b<U32>;
195    #[cfg(feature = "future_snark")]
196    type SnarkHash = MidnightPoseidonDigest;
197}