Skip to main content

cggmp24/
key_refresh.rs

1//! Key refresh & aux info generation protocols
2
3/// Auxiliary info (re)generation protocol specific types
4mod aux_only;
5
6use digest::Digest;
7use rand_core::{CryptoRng, RngCore};
8use round_based::Mpc;
9use thiserror::Error;
10
11use crate::backend::Integer;
12use crate::utils;
13use crate::{
14    errors::IoError, key_share::AuxInfo, progress::Tracer, security_level::SecurityLevel,
15    utils::AbortBlame, ExecutionId,
16};
17
18#[doc(no_inline)]
19pub use self::msg::Msg;
20
21#[doc = include_str!("../docs/mpc_message.md")]
22pub mod msg {
23    pub use crate::key_refresh::aux_only::{
24        Msg, MsgReliabilityCheck, MsgRound1, MsgRound2, MsgRound3,
25    };
26}
27
28/// To speed up computations, it's possible to supply data to the algorithm
29/// generated ahead of time
30#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
31pub struct PregeneratedPrimes<L = crate::default_choice::SecurityLevel> {
32    primes: [Integer; 4],
33    _phantom: std::marker::PhantomData<L>,
34}
35
36impl<L: SecurityLevel> TryFrom<[Integer; 4]> for PregeneratedPrimes<L> {
37    type Error = [Integer; 4];
38
39    /// Constructs pregenerated primes from 4 big numbers
40    ///
41    /// Returns `None` if big numbers are smaller than required by security level
42    ///
43    /// Function doesn't validate that provided numbers are primes. If they're not,
44    /// key refresh protocol should fail with some ZK proof error.
45    fn try_from(primes: [Integer; 4]) -> Result<Self, Self::Error> {
46        if primes
47            .iter()
48            .any(|p| !crate::security_level::validate_secret_paillier_prime_size::<L>(p))
49        {
50            Err(primes)
51        } else {
52            Ok(Self {
53                primes,
54                _phantom: std::marker::PhantomData,
55            })
56        }
57    }
58}
59
60impl<L: SecurityLevel> PregeneratedPrimes<L> {
61    /// Returns stored primes
62    pub fn into_primes(self) -> [Integer; 4] {
63        self.primes
64    }
65
66    /// Returns a reference to stored primes
67    pub fn primes_ref(&self) -> &[Integer; 4] {
68        &self.primes
69    }
70
71    /// Generates primes. Takes some time.
72    pub fn generate<R: RngCore>(rng: &mut R) -> Self {
73        Self {
74            primes: [(); 4].map(|_| Integer::generate_safe_prime(rng, L::RSA_PRIME_BITLEN)),
75            _phantom: std::marker::PhantomData,
76        }
77    }
78}
79
80/// Entry point for key refresh and auxiliary info generation.
81pub struct AuxInfoBuilder<'a, L, D = crate::default_choice::Digest>
82where
83    L: SecurityLevel,
84    D: Digest,
85{
86    i: u16,
87    n: u16,
88    execution_id: ExecutionId<'a>,
89    pregenerated: PregeneratedPrimes<L>,
90    tracer: Option<&'a mut dyn Tracer>,
91    enforce_reliable_broadcast: bool,
92    precompute_multiexp_tables: bool,
93    _digest: std::marker::PhantomData<D>,
94}
95
96impl<'a, L, D> AuxInfoBuilder<'a, L, D>
97where
98    L: SecurityLevel,
99    D: Digest,
100{
101    /// Build key aux info generation operation. Start it with [`start`](Self::start).
102    ///
103    /// PregeneratedPrimes can be obtained with [`PregeneratedPrimes::generate`]
104    pub fn new_aux_gen(
105        eid: ExecutionId<'a>,
106        i: u16,
107        n: u16,
108        pregenerated: PregeneratedPrimes<L>,
109    ) -> Self {
110        Self {
111            i,
112            n,
113            execution_id: eid,
114            pregenerated,
115            tracer: None,
116            enforce_reliable_broadcast: true,
117            precompute_multiexp_tables: false,
118            _digest: std::marker::PhantomData,
119        }
120    }
121
122    /// Carry out the aux info generation procedure. Takes a lot of time
123    pub async fn start<R, M>(self, rng: &mut R, party: M) -> Result<AuxInfo<L>, KeyRefreshError>
124    where
125        R: RngCore + CryptoRng,
126        M: Mpc<ProtocolMessage = aux_only::Msg<D, L>>,
127        L: SecurityLevel,
128        D: Digest + Clone + 'static,
129    {
130        aux_only::run_aux_gen(
131            self.i,
132            self.n,
133            rng,
134            party,
135            self.execution_id,
136            self.pregenerated,
137            self.tracer,
138            self.enforce_reliable_broadcast,
139            self.precompute_multiexp_tables,
140        )
141        .await
142    }
143
144    /// Returns a state machine that can be used to carry out the aux info generation protocol
145    ///
146    /// See [`round_based::state_machine`] for details on how that can be done.
147    #[cfg(feature = "state-machine")]
148    pub fn into_state_machine<R>(
149        self,
150        rng: &'a mut R,
151    ) -> impl round_based::state_machine::StateMachine<
152        Output = Result<AuxInfo<L>, KeyRefreshError>,
153        Msg = aux_only::Msg<D, L>,
154    > + 'a
155    where
156        R: RngCore + CryptoRng,
157        L: SecurityLevel,
158        D: Digest<OutputSize = digest::typenum::U32> + Clone + 'static,
159    {
160        round_based::state_machine::wrap_protocol(|party| self.start(rng, party))
161    }
162}
163
164impl<'a, L, D> AuxInfoBuilder<'a, L, D>
165where
166    L: SecurityLevel,
167    D: Digest,
168{
169    /// Specifies another hash function to use
170    pub fn set_digest<D2: Digest>(self) -> AuxInfoBuilder<'a, L, D2> {
171        AuxInfoBuilder {
172            i: self.i,
173            n: self.n,
174            execution_id: self.execution_id,
175            pregenerated: self.pregenerated,
176            tracer: self.tracer,
177            enforce_reliable_broadcast: self.enforce_reliable_broadcast,
178            precompute_multiexp_tables: self.precompute_multiexp_tables,
179            _digest: std::marker::PhantomData,
180        }
181    }
182
183    /// Sets a tracer that tracks progress of protocol execution
184    pub fn set_progress_tracer(mut self, tracer: &'a mut dyn Tracer) -> Self {
185        self.tracer = Some(tracer);
186        self
187    }
188
189    #[doc = include_str!("../docs/enforce_reliable_broadcast.md")]
190    pub fn enforce_reliable_broadcast(self, v: bool) -> Self {
191        Self {
192            enforce_reliable_broadcast: v,
193            ..self
194        }
195    }
196
197    /// Precomputes multiexponentiation tables for output aux data
198    ///
199    /// Enables optimization that makes signing and presigning faster. Precomputation takes a
200    /// while and makes protocol a bit longer. It noticebly increases size of aux data both
201    /// in RAM and on disk (after serialization).
202    pub fn precompute_multiexp_tables(mut self, v: bool) -> Self {
203        self.precompute_multiexp_tables = v;
204        self
205    }
206}
207
208/// Error of key refresh and aux info generation protocols
209#[derive(Debug, Error)]
210#[error("key refresh protocol failed to complete")]
211pub struct KeyRefreshError(#[source] Reason);
212
213crate::errors::impl_from! {
214    impl From for KeyRefreshError {
215        err: ProtocolAborted => KeyRefreshError(Reason::Aborted(err)),
216        err: IoError => KeyRefreshError(Reason::IoError(err)),
217        err: Bug => KeyRefreshError(Reason::InternalError(err)),
218        err: utils::GenPedersenError => Bug::GenPedersen(err).into(),
219    }
220}
221
222#[derive(Debug, Error)]
223enum Reason {
224    /// Protocol was maliciously aborted by another party
225    #[error("protocol was aborted by malicious party")]
226    Aborted(#[source] ProtocolAborted),
227    #[error("i/o error")]
228    IoError(#[source] IoError),
229    #[error("internal error")]
230    InternalError(#[from] Bug),
231}
232
233/// Unexpected error in operation not caused by other parties
234#[derive(Debug, Error)]
235enum Bug {
236    #[error("Invalid key share geenrated")]
237    InvalidShareGenerated(#[source] crate::key_share::InvalidKeyShare),
238    #[error("couldn't prove a pi mod statement")]
239    PiMod(#[source] paillier_zk::Error),
240    #[error("couldn't prove a pi fac statement")]
241    PiFac(#[source] paillier_zk::Error),
242    #[error("couldn't prove prm statement")]
243    PiPrm(#[source] crate::zk::ring_pedersen_parameters::ZkError),
244    #[error("couldn't build multiexp tables")]
245    BuildMultiexpTables(#[source] crate::key_share::InvalidKeyShare),
246    #[error("generate pedersen params")]
247    GenPedersen(#[source] utils::GenPedersenError),
248    #[error("own modulus N is not positive")]
249    NegativeModulus,
250}
251
252/// Error indicating that protocol was aborted by malicious party
253///
254/// It _can be_ cryptographically proven, but we do not support it yet.
255#[derive(Debug, Error)]
256#[error("Protocol aborted; malicious parties: {parties:?}; reason: {reason}")]
257struct ProtocolAborted {
258    pub reason: ProtocolAbortReason,
259    pub parties: Vec<AbortBlame>,
260}
261
262/// Reason for protocol abort: which exact check has failed
263#[derive(Debug, Error)]
264enum ProtocolAbortReason {
265    #[error("decommitment doesn't match commitment")]
266    InvalidDecommitment,
267    #[error("provided invalid proof for Rmod")]
268    InvalidModProof,
269    #[error("provided invalid proof for Rfac")]
270    InvalidFacProof,
271    #[error("N, s and t parameters are invalid")]
272    InvalidRingPedersenParameters,
273    #[error("round 1 was not reliable")]
274    Round1NotReliable,
275}
276
277macro_rules! make_factory {
278    ($function:ident, $reason:ident) => {
279        fn $function(parties: Vec<AbortBlame>) -> Self {
280            Self {
281                reason: ProtocolAbortReason::$reason,
282                parties,
283            }
284        }
285    };
286}
287impl ProtocolAborted {
288    make_factory!(invalid_decommitment, InvalidDecommitment);
289    make_factory!(invalid_mod_proof, InvalidModProof);
290    make_factory!(invalid_fac_proof, InvalidFacProof);
291    make_factory!(
292        invalid_ring_pedersen_parameters,
293        InvalidRingPedersenParameters
294    );
295    make_factory!(round1_not_reliable, Round1NotReliable);
296}