1use k256::{NonZeroScalar, ProjectivePoint, Scalar};
5use rand::prelude::*;
6use x25519_dalek::{PublicKey, ReusableSecret};
7use zeroize::Zeroizing;
8
9use sl_mpc_mate::{
10 coord::*,
11 math::birkhoff_coeffs,
12 message::{MessageTag, MsgId, MESSAGE_HEADER_SIZE},
13};
14
15pub const KEYSHARE_EXPORT_TAG: MessageTag = MessageTag::tag(1);
17
18const EXPORTED_KEYSHARE_RECEIVER: usize = 0;
20
21use crate::{
22 keygen::Keyshare,
23 pairs::Pairs,
24 proto::{
25 check_abort, decode_scalar, tags::*, EncryptedMessage,
26 EncryptionScheme, ScalarBytes,
27 },
28 setup::{
29 KeyExportReceiverSetupMessage, KeyExporterSetupMessage,
30 ProtocolParticipant, ABORT_MESSAGE_TAG,
31 },
32 sign::get_lagrange_coeff_list,
33};
34
35#[derive(Debug, thiserror::Error)]
36#[allow(missing_docs)]
37pub enum KeyExportError {
39 #[error(
40 "Error while deserializing message or invalid message data length"
41 )]
42 InvalidMessage,
43
44 #[error("Public key mismatch after combining keyshares")]
45 PublicKeyMismatch,
46
47 #[error("Missing message")]
49 MissingMessage,
50
51 #[error("Send message")]
53 SendMessage,
54
55 #[error("Abort protocol by party {0}")]
57 AbortProtocol(usize),
58}
59
60impl From<MessageSendError> for KeyExportError {
61 fn from(_err: MessageSendError) -> Self {
62 KeyExportError::SendMessage
63 }
64}
65
66impl From<Error> for KeyExportError {
67 fn from(err: Error) -> Self {
68 match err {
69 Error::Abort(p) => KeyExportError::AbortProtocol(p as _),
70 Error::Recv => KeyExportError::MissingMessage,
71 Error::Send => KeyExportError::SendMessage,
72 Error::InvalidMessage => KeyExportError::InvalidMessage,
73 }
74 }
75}
76
77pub fn combine_shares(
88 x_i_list: &[(NonZeroScalar, usize)],
89 s_i_list: &[Scalar],
90 public_key: &ProjectivePoint,
91) -> Option<Scalar> {
92 if s_i_list.len() != x_i_list.len() {
93 return None;
94 }
95
96 let is_lagrange = x_i_list.iter().all(|&(_, rank)| rank == 0);
97
98 let s = if is_lagrange {
99 get_lagrange_coeff_list(x_i_list, |(x, _)| x)
100 .zip(s_i_list)
101 .map(|(c, s_i)| c * s_i)
102 .sum()
103 } else {
104 birkhoff_coeffs(x_i_list)
105 .into_iter()
106 .zip(s_i_list)
107 .map(|(c, s_i)| c * s_i)
108 .sum()
109 };
110
111 let calculated_public_key = ProjectivePoint::GENERATOR * s;
112
113 (public_key == &calculated_public_key).then_some(s)
114}
115
116pub fn export_keyshare<S, R>(mut rng: R, setup: &S) -> Option<Vec<u8>>
121where
122 S: KeyExporterSetupMessage<PublicKey, Keyshare>,
123 R: RngCore + CryptoRng,
124{
125 let mut scheme = crate::proto::Scheme::new(&mut rng);
126
127 scheme
128 .receiver_public_key(0, setup.receiver_public_key().as_bytes())
129 .ok()?;
130
131 let pub_key = scheme.public_key();
132
133 let mut msg = EncryptedMessage::<ScalarBytes>::new_with_ad(
134 &setup.msg_id(Some(EXPORTED_KEYSHARE_RECEIVER), KEYSHARE_EXPORT_TAG),
135 setup.message_ttl().as_secs() as u32,
136 0,
137 pub_key.len(),
138 1,
139 &scheme,
140 );
141
142 let (payload, trailer, ad) = msg.payload_with_ad(&scheme);
143
144 payload.copy_from_slice(&setup.keyshare().s_i);
145 trailer[0] = setup.keyshare().party_id;
146 ad.copy_from_slice(pub_key);
147
148 msg.encrypt(&mut scheme, 0)
149}
150
151pub fn decrypt_share(
153 mut msg: Zeroizing<Vec<u8>>,
154 enc_key: &ReusableSecret,
155) -> Option<(Scalar, u8)> {
156 let mut scheme = crate::proto::Scheme::from_secret(enc_key.clone());
157
158 let enc_pub_key = msg
159 .get(MESSAGE_HEADER_SIZE..)
160 .and_then(|msg| msg.get(0..32))?;
161
162 scheme.receiver_public_key(0, enc_pub_key).ok()?;
163
164 let (s_i, pid, _) = EncryptedMessage::<[u8; 32]>::decrypt_with_ad(
165 &mut msg, 32, 1, &scheme, 0,
166 )?;
167
168 let party_id = pid[0];
169
170 let s_i = decode_scalar(s_i)?;
171
172 Some((s_i, party_id))
173}
174
175pub async fn receive_keyshares<S, R>(
177 setup: S,
178 relay: R,
179) -> Result<Scalar, KeyExportError>
180where
181 S: KeyExportReceiverSetupMessage<ReusableSecret>,
182 R: Relay,
183{
184 let share = setup.keyshare();
185
186 let mut relay = FilteredMsgRelay::new(relay);
187
188 relay.ask_messages(&setup, ABORT_MESSAGE_TAG, false).await?;
189
190 relay
191 .ask_messages(&setup, KEYSHARE_EXPORT_TAG, true)
192 .await?;
193
194 let pk = setup.keyshare().public_key();
195
196 let rank_list = setup.keyshare().rank_list();
197 let x_i_list = setup.keyshare().x_i_list();
198
199 let mut x_i_list_2 = Pairs::new_with_item(
200 share.party_id as usize,
201 (
202 x_i_list[share.party_id as usize],
203 rank_list[share.party_id as usize] as usize,
204 ),
205 );
206 let mut s_i_list =
207 Pairs::new_with_item(share.party_id as usize, share.s_i());
208
209 let mut round = Round::new(
210 setup.total_participants() - 1,
211 KEYSHARE_EXPORT_TAG,
212 &mut relay,
213 );
214
215 while let Some((msg, party_idx, is_abort)) = round.recv().await? {
216 if is_abort {
217 check_abort(
218 &setup,
219 &msg,
220 party_idx,
221 KeyExportError::AbortProtocol,
222 )?;
223 round.put_back(&msg, ABORT_MESSAGE_TAG, party_idx);
224 continue;
225 }
226
227 let msg = Zeroizing::new(msg);
228
229 let (s_i, party_id) =
230 decrypt_share(msg, setup.receiver_private_key())
231 .ok_or(KeyExportError::InvalidMessage)?;
232
233 let x_j = x_i_list
234 .get(party_id as usize)
235 .ok_or(KeyExportError::InvalidMessage)?;
236 let rank_j = rank_list
237 .get(party_id as usize)
238 .ok_or(KeyExportError::InvalidMessage)?;
239 x_i_list_2.push(party_id as usize, (*x_j, *rank_j as usize));
240 s_i_list.push(party_id as usize, s_i);
241 }
242
243 let private_key =
244 combine_shares(&x_i_list_2.remove_ids(), &s_i_list.remove_ids(), &pk)
245 .ok_or(KeyExportError::PublicKeyMismatch)?;
246
247 Ok(private_key)
248}
249
250pub fn message_receivers<S, F>(setup: &S, mut msg_receiver: F)
255where
256 S: ProtocolParticipant,
257 F: FnMut(MsgId, &S::MessageVerifier),
258{
259 setup.all_other_parties().for_each(|p| {
260 let vk = setup.verifier(p);
261
262 msg_receiver(setup.msg_id(None, ABORT_MESSAGE_TAG), vk);
263 msg_receiver(setup.msg_id(Some(p), KEYSHARE_EXPORT_TAG), vk);
264 })
265}
266
267#[cfg(test)]
268mod tests {
269 use k256::{NonZeroScalar, ProjectivePoint};
270 use rand::seq::SliceRandom;
271 use x25519_dalek::ReusableSecret;
272
273 use sl_mpc_mate::{coord::SimpleMessageRelay, message::InstanceId};
274
275 use crate::{
276 key_import::ecdsa_secret_shares,
277 keygen::utils::gen_keyshares,
278 setup::{
279 key_export::{
280 exporter::KeyExporter, receiver::KeyExportReceiver,
281 },
282 NoSigningKey, NoVerifyingKey,
283 },
284 };
285
286 use super::{
287 combine_shares, export_keyshare, receive_keyshares, PublicKey,
288 };
289
290 #[test]
291 fn test_combine() {
292 const T: u8 = 5;
293 const N: usize = 9;
294
295 let mut rng = rand::thread_rng();
296
297 let private_key = NonZeroScalar::random(&mut rng);
298 let public_key = ProjectivePoint::GENERATOR * *private_key;
299
300 let root_chain_code = [1u8; 32];
301
302 let shares = ecdsa_secret_shares(
303 T,
304 vec![0; N],
305 &private_key,
306 root_chain_code,
307 None,
308 &mut rng,
309 );
310
311 let s_i_list =
312 shares.iter().map(|s| s.s_i.unwrap()).collect::<Vec<_>>();
313
314 let x_i_list = shares[0]
315 .x_i_list
316 .clone()
317 .unwrap()
318 .into_iter()
319 .map(|x_i| (x_i, 0))
320 .collect::<Vec<_>>();
321
322 for t in T as usize..=N {
323 let recovered_private_key =
324 combine_shares(&x_i_list[..t], &s_i_list[..t], &public_key)
325 .unwrap();
326
327 assert_eq!(recovered_private_key, *private_key);
328 }
329 }
330
331 #[tokio::test(flavor = "multi_thread")]
332 async fn parties() {
333 let mut rng = rand::thread_rng();
334
335 const T: u8 = 3;
336 const N: u8 = 5;
337
338 let mut shares = gen_keyshares(T, N, None).await;
339 let pk = shares[0].public_key();
340
341 let inst = rand::random();
342
343 let vk: Vec<NoVerifyingKey> =
344 (0..N as usize).map(NoVerifyingKey::new).collect();
345
346 for _ in 0..10 {
347 shares.shuffle(&mut rng);
352
353 for t in T..=N {
354 let enc_key = ReusableSecret::random_from_rng(&mut rng);
355 let enc_pub_key = PublicKey::from(&enc_key);
356
357 let msgs = (1..t)
358 .map(|party_id| {
359 let setup = KeyExporter::new(
360 InstanceId::new(inst),
361 NoSigningKey,
362 party_id as _,
363 vk[..t as usize].to_vec(),
364 shares[party_id as usize].clone(),
365 enc_pub_key,
366 );
367
368 export_keyshare(&mut rng, &setup).unwrap()
369 })
370 .collect::<Vec<_>>();
371
372 let relay = SimpleMessageRelay::new();
373
374 for msg in msgs {
375 relay.send(msg);
376 }
377
378 let recv = <KeyExportReceiver>::new(
379 InstanceId::new(inst),
380 NoSigningKey,
381 0,
382 vk[..t as usize].to_vec(),
383 shares[0].clone(),
384 enc_key,
385 );
386
387 let sk =
388 receive_keyshares(recv, relay.connect()).await.unwrap();
389
390 assert_eq!(ProjectivePoint::GENERATOR * sk, pk);
391 }
392 }
393 }
394}