dkls23/setup/
quorum_change.rs

1// Copyright (c) Silence Laboratories Pte. Ltd. All Rights Reserved.
2// This software is licensed under the Silence Laboratories License Agreement.
3
4#![allow(missing_docs)]
5
6use std::{marker::PhantomData, sync::Arc, time::Duration};
7
8use crate::{
9    keygen::Keyshare,
10    setup::{
11        keys::{NoSignature, NoSigningKey, NoVerifyingKey},
12        *,
13    },
14};
15
16/// Default Time-To-Live (TTL) value for messages in seconds
17const DEFAULT_TTL: u64 = 100; // smaller timeout might fail tests
18
19/// A message used for setting up quorum changes in a multi-party computation protocol.
20///
21/// This struct encapsulates all necessary information for changing the quorum of participants,
22/// including old and new participant information, cryptographic keys, and protocol parameters.
23///
24/// # Type Parameters
25/// * `SK` - The type of signing key used for message signatures
26/// * `VK` - The type of verifying key used to verify message signatures
27/// * `MS` - The type of message signature
28/// * `KS` - The type of keyshare used in the protocol
29/// * `PK` - The type of public key used in the protocol
30pub struct SetupMessage<
31    SK = NoSigningKey,
32    VK = NoVerifyingKey,
33    MS = NoSignature,
34    KS = Keyshare,
35    PK = ProjectivePoint,
36> {
37    /// ID of the current party
38    this_party: usize,
39    /// Signing key for the current party
40    sk: SK,
41    /// Verifying keys for all participants
42    vk: Vec<VK>,
43    /// Optional reference to the current keyshare
44    keyshare: Option<Arc<KS>>,
45    /// Public key for the protocol
46    public_key: PK,
47    /// New threshold value for the protocol
48    new_t: usize,
49    /// New ranks for all participants
50    new_ranks: Vec<u8>,
51    /// Indices of new participants
52    new_parties: Vec<usize>,
53    /// Indices of old participants
54    old_parties: Vec<usize>,
55    /// Instance identifier for the protocol
56    instance: InstanceId,
57    /// Time-to-live duration for messages
58    ttl: Duration,
59    /// Phantom data to hold the message signature type
60    marker: PhantomData<MS>,
61}
62
63impl<SK, VK, MS, KS, PK> SetupMessage<SK, VK, MS, KS, PK> {
64    /// Creates a new setup message for quorum changes.
65    ///
66    /// # Arguments
67    /// * `instance` - Instance identifier for the protocol
68    /// * `this_party` - ID of the current party
69    /// * `old_parties` - Indices of old participants
70    /// * `new_parties` - Pairs of (index, rank) for new participants
71    /// * `new_t` - New threshold value
72    /// * `sk` - Signing key for the current party
73    /// * `vk` - Vector of verifying keys for all participants
74    /// * `public_key` - Public key for the protocol
75    ///
76    /// # Panics
77    /// Panics if:
78    /// * `this_party` is not less than the total number of parties
79    /// * Any old party index is not less than the total number of parties
80    /// * Any new party index is not less than the total number of parties
81    /// * `new_t` is greater than the number of new parties
82    #[allow(clippy::too_many_arguments)]
83    pub fn new(
84        instance: InstanceId,
85        this_party: usize,
86        old_parties: &[usize],
87        new_parties: &[(usize, u8)],
88        new_t: usize,
89        sk: SK,
90        vk: Vec<VK>,
91        public_key: PK,
92    ) -> Self {
93        let total_parties = vk.len();
94
95        assert!(this_party < total_parties);
96
97        assert!(
98            old_parties.iter().max().unwrap_or(&usize::MAX) < &total_parties
99        );
100
101        assert!(
102            new_parties
103                .iter()
104                .map(|&(i, _)| i)
105                .max()
106                .unwrap_or(usize::MAX)
107                < total_parties
108        );
109
110        assert!(new_t <= new_parties.len());
111
112        Self {
113            this_party,
114            sk,
115            vk,
116            public_key,
117            new_t,
118            new_ranks: new_parties.iter().map(|p| p.1).collect(),
119            new_parties: new_parties.iter().map(|p| p.0).collect(),
120            old_parties: old_parties.to_vec(),
121            instance,
122            ttl: Duration::from_secs(DEFAULT_TTL),
123            keyshare: None,
124            marker: PhantomData,
125        }
126    }
127
128    /// Sets a custom time-to-live duration for messages.
129    ///
130    /// # Arguments
131    /// * `ttl` - The new time-to-live duration
132    ///
133    /// # Returns
134    /// The modified `SetupMessage` instance
135    pub fn with_ttl(mut self, ttl: Duration) -> Self {
136        self.ttl = ttl;
137        self
138    }
139
140    /// Sets an optional keyshare for the protocol.
141    ///
142    /// # Arguments
143    /// * `keyshare` - Optional reference to the keyshare
144    ///
145    /// # Returns
146    /// The modified `SetupMessage` instance
147    pub fn with_keyshare_opt(mut self, keyshare: Option<Arc<KS>>) -> Self {
148        self.keyshare = keyshare;
149        self
150    }
151
152    /// Sets a keyshare for the protocol.
153    ///
154    /// # Arguments
155    /// * `keyshare` - Reference to the keyshare
156    ///
157    /// # Returns
158    /// The modified `SetupMessage` instance
159    pub fn with_keyshare(self, keyshare: Arc<KS>) -> Self {
160        self.with_keyshare_opt(Some(keyshare))
161    }
162}
163
164impl<SK, VK, MS, KS, PK> ProtocolParticipant
165    for SetupMessage<SK, VK, MS, KS, PK>
166where
167    SK: Signer<MS>,
168    MS: SignatureEncoding,
169    VK: AsRef<[u8]> + Verifier<MS>,
170{
171    type MessageSignature = MS;
172    type MessageSigner = SK;
173    type MessageVerifier = VK;
174
175    /// Returns the signing key for the current participant.
176    fn signer(&self) -> &Self::MessageSigner {
177        &self.sk
178    }
179
180    /// Returns the verifying key for a specific participant.
181    ///
182    /// # Arguments
183    /// * `index` - The index of the participant
184    ///
185    /// # Returns
186    /// A reference to the verifying key
187    fn verifier(&self, index: usize) -> &Self::MessageVerifier {
188        &self.vk[index]
189    }
190
191    /// Returns the instance identifier for the protocol.
192    fn instance_id(&self) -> &InstanceId {
193        &self.instance
194    }
195
196    /// Returns the time-to-live duration for messages.
197    fn message_ttl(&self) -> Duration {
198        self.ttl
199    }
200
201    /// Returns the index of the current participant.
202    fn participant_index(&self) -> usize {
203        self.this_party
204    }
205
206    /// Returns the total number of participants in the protocol.
207    fn total_participants(&self) -> usize {
208        self.vk.len()
209    }
210}
211
212impl<SK, VK, MS, KS, PK> QuorumChangeSetupMessage<KS, PK>
213    for SetupMessage<SK, VK, MS, KS, PK>
214where
215    SK: Signer<MS>,
216    MS: SignatureEncoding,
217    VK: AsRef<[u8]> + Verifier<MS>,
218{
219    /// Returns a reference to the old keyshare if it exists.
220    fn old_keyshare(&self) -> Option<&KS> {
221        self.keyshare.as_deref()
222    }
223
224    /// Returns the new threshold value for the protocol.
225    fn new_threshold(&self) -> u8 {
226        self.new_t as u8
227    }
228
229    /// Returns the rank of a specific participant in the new quorum.
230    ///
231    /// # Arguments
232    /// * `party_id` - The ID of the participant
233    ///
234    /// # Returns
235    /// The rank of the participant
236    fn new_participant_rank(&self, party_id: u8) -> u8 {
237        self.new_ranks[party_id as usize]
238    }
239
240    /// Returns the expected public key for the protocol.
241    fn expected_public_key(&self) -> &PK {
242        &self.public_key
243    }
244
245    /// Returns the indices of the old participants.
246    fn old_party_indices(&self) -> &[usize] {
247        &self.old_parties
248    }
249
250    /// Returns the indices of the new participants.
251    fn new_party_indices(&self) -> &[usize] {
252        &self.new_parties
253    }
254
255    /// Derives a key identifier from a public key.
256    ///
257    /// This is a trivial implementation that takes the first 32 bytes of the public key.
258    ///
259    /// # Arguments
260    /// * `public_key` - The public key to derive the identifier from
261    ///
262    /// # Returns
263    /// A 32-byte key identifier
264    fn derive_key_id(&self, public_key: &[u8]) -> [u8; 32] {
265        let mut bytes = [0; 32];
266
267        let size = bytes.len().min(public_key.len());
268
269        bytes[..size].copy_from_slice(&public_key[..size]);
270
271        bytes
272    }
273}