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}