1use k256::{
9 elliptic_curve::{group::GroupEncoding, subtle::ConstantTimeEq, Group},
10 NonZeroScalar, ProjectivePoint, Scalar,
11};
12use rand::prelude::*;
13use rand_chacha::ChaCha20Rng;
14use sha2::{Digest, Sha256};
15
16use sl_mpc_mate::{
17 coord::*,
18 math::{
19 feldman_verify, polynomial_coeff_multipliers, GroupPolynomial,
20 Polynomial,
21 },
22 message::MsgId,
23 SessionId,
24};
25use sl_oblivious::{
26 endemic_ot::{EndemicOTMsg1, EndemicOTReceiver, EndemicOTSender},
27 soft_spoken::{build_pprf, eval_pprf},
28};
29
30use crate::{
31 keygen::{
32 broadcast_4,
33 constants::*,
34 get_all_but_one_session_id, get_base_ot_session_id,
35 messages::*,
36 utils::{
37 check_secret_recovery, get_birkhoff_coefficients,
38 get_lagrange_coeff,
39 },
40 KeygenError, Keyshare,
41 },
42 pairs::Pairs,
43 proto::{tags::*, *},
44 setup::{QuorumChangeSetupMessage, ABORT_MESSAGE_TAG},
45 Seed,
46};
47
48#[cfg(feature = "multi-thread")]
49use tokio::task::block_in_place;
50
51#[cfg(not(feature = "multi-thread"))]
52fn block_in_place<F, R>(f: F) -> R
53where
54 F: FnOnce() -> R,
55{
56 f()
57}
58
59pub async fn run<T, R>(
91 setup: T,
92 seed: Seed,
93 relay: R,
94) -> Result<Option<Keyshare>, KeygenError>
95where
96 T: QuorumChangeSetupMessage<Keyshare, ProjectivePoint>,
97 R: Relay,
98{
99 let abort_msg = create_abort_message(&setup);
100 let mut relay = FilteredMsgRelay::new(relay);
101
102 let result = match run_inner(setup, seed, &mut relay).await {
103 Ok(share) => Ok(share),
104 Err(KeygenError::AbortProtocol(p)) => {
105 Err(KeygenError::AbortProtocol(p))
106 }
107 Err(KeygenError::SendMessage) => Err(KeygenError::SendMessage),
108 Err(err) => {
109 let _ = relay.send(abort_msg).await;
111 Err(err)
112 }
113 };
114
115 let _ = relay.close().await;
116
117 result
118}
119
120#[allow(non_snake_case)]
142pub(crate) async fn run_inner<T, R>(
143 setup: T,
144 seed: Seed,
145 relay: &mut FilteredMsgRelay<R>,
146) -> Result<Option<Keyshare>, KeygenError>
147where
148 T: QuorumChangeSetupMessage<Keyshare, ProjectivePoint>,
149 R: Relay,
150{
151 let mut rng = ChaCha20Rng::from_seed(seed);
152
153 let mut scheme = crate::proto::Scheme::new(&mut rng);
154
155 let expected_public_key = setup.expected_public_key();
156 assert!(expected_public_key != &ProjectivePoint::IDENTITY);
157
158 let NEW_T = setup.new_threshold() as usize;
159 let NEW_N = setup.new_party_indices().len();
160
161 let new_x_i_list: Vec<NonZeroScalar> = (1..=NEW_N as u32)
162 .map(Scalar::from)
163 .map(|s| NonZeroScalar::new(s).unwrap())
164 .collect();
165
166 let my_party_index = setup.participant_index();
167 let my_old_party_id = setup.old_keyshare().map(|k| k.party_id);
168 let my_party_is_old = my_old_party_id.is_some();
169 let my_new_party_id = setup.new_party_id(my_party_index);
170 let my_party_is_new = my_new_party_id.is_some();
171
172 relay.ask_messages(&setup, ABORT_MESSAGE_TAG, false).await?;
173
174 let _r0 = relay
175 .ask_messages_from_slice(
176 &setup,
177 QC_MSG_R0,
178 setup.old_party_indices(),
179 false,
180 )
181 .await?;
182
183 relay.ask_messages(&setup, QC_MSG_R1, false).await?;
184
185 let _p2p_1 = if my_party_is_new {
186 relay
187 .ask_messages_from_slice(
188 &setup,
189 QC_MSG_P2P_1,
190 setup.old_party_indices(),
191 true,
192 )
193 .await?
194 } else {
195 0
196 };
197
198 let _p2p_2 = if my_party_is_new {
199 relay
200 .ask_messages_from_slice(
201 &setup,
202 QC_MSG_P2P_2,
203 setup.old_party_indices(),
204 true,
205 )
206 .await?
207 } else {
208 0
209 };
210
211 let _r2 = relay
212 .ask_messages_from_slice(
213 &setup,
214 QC_MSG_R2,
215 setup.old_party_indices(),
216 false,
217 )
218 .await?;
219
220 let sid_i = SessionId::new(rng.gen());
221
222 let mut old_party_ids = Pairs::new();
223
224 if let Some(party_id) = my_old_party_id {
225 relay
227 .send(SignedMessage::build(
228 &setup.msg_id(None, QC_MSG_R0),
229 setup.message_ttl().as_secs() as _,
230 0,
231 setup.signer(),
232 |msg: &mut u8, _| {
233 *msg = party_id;
234 },
235 ))
236 .await?;
237 old_party_ids.push(my_party_index, party_id);
238 }
239
240 Round::new(_r0, QC_MSG_R0, relay)
241 .of_signed_messages(
242 &setup,
243 KeygenError::AbortProtocol,
244 |&party_id: &u8, index| {
245 old_party_ids.push(index, party_id);
246 Ok(())
247 },
248 )
249 .await?;
250
251 let s_i_0 = setup
255 .old_keyshare()
256 .map(|keyshare| {
257 let my_old_party_id = keyshare.party_id as usize;
258
259 let s_i = keyshare.s_i();
260 let old_rank_list = keyshare.rank_list();
261 let old_x_i_list = keyshare.x_i_list();
262 let x_i = old_x_i_list[my_old_party_id];
263
264 assert!(
265 setup.old_party_indices().len()
266 >= keyshare.threshold as usize
267 );
268
269 let old_party_id_list = old_party_ids.remove_ids();
270
271 let all_ranks_zero = old_rank_list.iter().all(|&r| r == 0);
272
273 let lambda = if all_ranks_zero {
274 get_lagrange_coeff(&x_i, &old_x_i_list, &old_party_id_list)
275 } else {
276 get_birkhoff_coefficients(
277 &old_rank_list,
278 &old_x_i_list,
279 &old_party_id_list,
280 )
281 .get(&my_old_party_id)
282 .copied()
283 .unwrap_or_default()
284 };
285
286 lambda * s_i
287 })
288 .unwrap_or_default();
289
290 let mut polynomial = Polynomial::random(&mut rng, NEW_T - 1);
292 polynomial.set_constant(s_i_0);
293
294 let big_p_i_poly = polynomial.commit();
295 let r1_i = rng.gen();
296
297 let commitment1_i = if my_party_is_old {
298 hash_commitment_1(&sid_i, my_party_index, &big_p_i_poly, &r1_i)
299 } else {
300 [0u8; 32]
301 };
302
303 let (sid_i_list, enc_pub_keys, commitment1_list, _) = broadcast_4(
305 &setup,
306 relay,
307 QC_MSG_R1,
308 (sid_i, scheme.public_key().to_vec(), commitment1_i, ()),
309 )
310 .await?;
311
312 for (receiver, pub_key) in enc_pub_keys.into_iter().enumerate() {
313 if receiver != setup.participant_index() {
314 scheme
315 .receiver_public_key(receiver, &pub_key)
316 .map_err(|_| KeygenError::InvalidMessage)?;
317 }
318 }
319
320 let final_session_id: [u8; 32] = sid_i_list
321 .iter()
322 .fold(Sha256::new(), |hash, sid| hash.chain_update(sid))
323 .finalize()
324 .into();
325
326 let mut p_i_list: Pairs<Scalar, u8> = Pairs::new();
328 if my_party_is_old && my_party_is_new {
329 let my_old_party_id = my_old_party_id.unwrap();
330 let my_new_party_id = my_new_party_id.unwrap();
331 let my_new_rank = setup.new_participant_rank(my_new_party_id);
332 let x_i = new_x_i_list[my_new_party_id as usize];
333 let p_i_i = block_in_place(|| {
334 polynomial.derivative_at(my_new_rank as usize, &x_i)
335 });
336 p_i_list.push(my_old_party_id, p_i_i);
337 }
338
339 let mut r2_j_list: Pairs<[u8; 32], u8> = Pairs::new();
341 let mut p_i_j_list: Pairs<Scalar, u8> = Pairs::new();
342 if my_party_is_old {
343 for &receiver_index in setup.new_party_indices() {
344 if receiver_index == my_party_index {
345 continue;
346 }
347 let receiver_id = setup.new_party_id(receiver_index).unwrap();
348
349 let r2_j: [u8; 32] = rng.gen();
350 r2_j_list.push(receiver_id, r2_j);
351
352 let party_j_rank = setup.new_participant_rank(receiver_id);
353 let x_j = new_x_i_list[receiver_id as usize];
354 let p_i_j = block_in_place(|| {
355 polynomial.derivative_at(party_j_rank as usize, &x_j)
356 });
357 p_i_j_list.push(receiver_id, p_i_j);
358
359 let commitment_2_i = hash_commitment_2(
360 &final_session_id,
361 my_party_index,
362 receiver_index,
363 &p_i_j,
364 &r2_j,
365 );
366
367 let mut enc_msg1 = EncryptedMessage::<QCP2PMsg1>::new(
368 &setup.msg_id(Some(receiver_index), QC_MSG_P2P_1),
369 setup.message_ttl().as_secs() as u32,
370 0,
371 0,
372 &scheme,
373 );
374
375 let (msg1, _) = enc_msg1.payload(&scheme);
376 msg1.commitment_2_i = commitment_2_i;
377
378 relay
382 .feed(
383 enc_msg1
384 .encrypt(&mut scheme, receiver_index)
385 .ok_or(KeygenError::SendMessage)?,
386 )
387 .await
388 .map_err(|_| KeygenError::SendMessage)?;
389 }
390 }
391
392 let mut commitment2_list: Pairs<[u8; 32], u8> = Pairs::new();
394
395 Round::new(_p2p_1, QC_MSG_P2P_1, relay)
396 .of_encrypted_messages(
397 &setup,
398 &mut scheme,
399 0,
400 KeygenError::AbortProtocol,
401 |p2p_msg1: &QCP2PMsg1, from_party_index, _, _| {
402 let from_party_id =
403 *old_party_ids.find_pair(from_party_index);
404
405 commitment2_list.push(from_party_id, p2p_msg1.commitment_2_i);
406
407 Ok(None)
408 },
409 )
410 .await?;
411
412 let decommit_data = if let Some(keyshare) = setup.old_keyshare() {
415 for &receiver_index in setup.new_party_indices() {
416 if receiver_index == my_party_index {
417 continue;
418 }
419 let receiver_id = setup.new_party_id(receiver_index).unwrap();
420
421 let p_i_j = p_i_j_list.find_pair(receiver_id);
422 let r2_j = r2_j_list.find_pair(receiver_id);
423
424 let mut enc_msg2 = EncryptedMessage::<QCP2PMsg2>::new(
425 &setup.msg_id(Some(receiver_index), QC_MSG_P2P_2),
426 setup.message_ttl().as_secs() as u32,
427 0,
428 0,
429 &scheme,
430 );
431
432 let (msg2, _) = enc_msg2.payload(&scheme);
433 msg2.p_i = encode_scalar(p_i_j);
434 msg2.r_2_i = *r2_j;
435 msg2.root_chain_code = keyshare.root_chain_code;
436
437 relay
441 .feed(
442 enc_msg2
443 .encrypt(&mut scheme, receiver_index)
444 .ok_or(KeygenError::SendMessage)?,
445 )
446 .await
447 .map_err(|_| KeygenError::SendMessage)?;
448 }
449
450 let (big_p_j_poly_list, r1_j_list, _, _) =
452 Round::new(_r2, QC_MSG_R2, relay)
453 .broadcast_4(&setup, (big_p_i_poly.clone(), r1_i, (), ()))
454 .await?;
455
456 for &old_party_index in setup.old_party_indices() {
458 let r1_j = r1_j_list.find_pair(old_party_index);
459 let sid_j = &sid_i_list[old_party_index];
460 let commitment1 = &commitment1_list[old_party_index];
461 let big_p_i_poly = big_p_j_poly_list.find_pair(old_party_index);
462
463 if big_p_i_poly.coeffs.len() != NEW_T {
464 return Err(KeygenError::InvalidMessage);
465 }
466
467 if big_p_i_poly.points().any(|p| p.is_identity().into()) {
468 return Err(KeygenError::InvalidPolynomialPoint);
469 }
470
471 let commit_hash1 =
472 hash_commitment_1(sid_j, old_party_index, big_p_i_poly, r1_j);
473 if commit_hash1.ct_ne(commitment1).into() {
474 return Err(KeygenError::InvalidCommitmentHash);
475 }
476 }
477
478 let mut big_p_vec = GroupPolynomial::identity(NEW_T);
479 for (_, v) in &big_p_j_poly_list {
480 big_p_vec.add_mut(v); }
482
483 if &big_p_vec.get_constant() != expected_public_key {
484 return Err(KeygenError::PublicKeyMismatch);
485 }
486
487 if !my_party_is_new {
489 return Ok(None);
490 }
491
492 Some(big_p_j_poly_list)
493 } else {
494 None
495 };
496
497 let mut root_chain_code_list = setup
498 .old_keyshare()
499 .map(|share| {
500 Pairs::new_with_item(share.party_id, share.root_chain_code)
501 })
502 .unwrap_or_default();
503
504 Round::new(_p2p_2, QC_MSG_P2P_2, relay)
507 .of_encrypted_messages(
508 &setup,
509 &mut scheme,
510 0,
511 KeygenError::AbortProtocol,
512 |p2p_msg2: &QCP2PMsg2, from_party_index, _, _| {
513 let from_party_id =
514 *old_party_ids.find_pair(from_party_index);
515
516 let p_j_i = decode_scalar(&p2p_msg2.p_i)
517 .ok_or(KeygenError::InvalidMessage)?;
518
519 let commitment2 = commitment2_list.find_pair(from_party_id);
520
521 let commit_hash_2 = hash_commitment_2(
522 &final_session_id,
523 from_party_index,
524 my_party_index,
525 &p_j_i,
526 &p2p_msg2.r_2_i,
527 );
528
529 if commit_hash_2.ct_ne(commitment2).into() {
530 return Err(KeygenError::InvalidCommitmentHash);
531 }
532
533 p_i_list.push(from_party_id, p_j_i);
534
535 root_chain_code_list
536 .push(from_party_id, p2p_msg2.root_chain_code);
537
538 Ok(None)
539 },
540 )
541 .await?;
542
543 let root_chain_code_list = root_chain_code_list.remove_ids();
545 let root_chain_code = root_chain_code_list[0];
546 if !root_chain_code_list
547 .iter()
548 .all(|&item| item == root_chain_code)
549 {
550 return Err(KeygenError::InvalidQuorumChange);
551 };
552
553 let big_p_j_poly_list = if let Some(decommit_data) = decommit_data {
554 decommit_data
555 } else {
556 let (big_p_j_poly_list, r1_j_list, _, _) =
559 Round::new(_r2, QC_MSG_R2, relay)
560 .recv_broadcast_4::<_, _, _, (), ()>(
561 &setup,
562 &[big_p_i_poly.external_size(), 32, 0, 0],
563 )
564 .await?;
565
566 for &old_party_index in setup.old_party_indices() {
568 let r1_j = r1_j_list.find_pair(old_party_index);
569 let sid_j = &sid_i_list[old_party_index];
570 let commitment1 = &commitment1_list[old_party_index];
571 let big_p_i_vec: &GroupPolynomial<ProjectivePoint> =
572 big_p_j_poly_list.find_pair(old_party_index);
573
574 if big_p_i_vec.coeffs.len() != NEW_T {
575 return Err(KeygenError::InvalidMessage);
576 }
577
578 if big_p_i_vec.points().any(|p| p.is_identity().into()) {
579 return Err(KeygenError::InvalidPolynomialPoint);
580 }
581
582 let commit_hash1 =
583 hash_commitment_1(sid_j, old_party_index, big_p_i_vec, r1_j);
584 if commit_hash1.ct_ne(commitment1).into() {
585 return Err(KeygenError::InvalidCommitmentHash);
586 }
587 }
588
589 big_p_j_poly_list
590 };
591
592 let mut big_p_poly = GroupPolynomial::identity(NEW_T);
593
594 let mut big_p_j_poly_list_sorted_by_old_id = Pairs::new();
596 for &old_party_index in setup.old_party_indices() {
597 let old_party_id = old_party_ids.find_pair(old_party_index);
598 big_p_j_poly_list_sorted_by_old_id.push(
599 *old_party_id,
600 big_p_j_poly_list.find_pair(old_party_index).clone(),
601 );
602 }
603
604 let big_p_j_poly_list = big_p_j_poly_list_sorted_by_old_id.remove_ids();
605 let p_i_list = p_i_list.remove_ids();
606 for v in &big_p_j_poly_list {
607 big_p_poly.add_mut(v); }
609
610 if big_p_j_poly_list.len() != p_i_list.len() {
611 return Err(KeygenError::FailedFelmanVerify);
612 }
613
614 let my_party_id = my_new_party_id.unwrap();
615 let my_rank = setup.new_participant_rank(my_party_id);
616
617 for (big_p_j, p_j_i) in big_p_j_poly_list.iter().zip(&p_i_list) {
619 let coeffs =
620 block_in_place(|| big_p_j.derivative_coeffs(my_rank as usize));
621 let valid = feldman_verify(
622 coeffs,
623 &new_x_i_list[my_party_id as usize],
624 p_j_i,
625 &ProjectivePoint::GENERATOR,
626 );
627 if !valid {
628 return Err(KeygenError::FailedFelmanVerify);
629 }
630 }
631
632 let p_i = p_i_list.iter().sum();
633
634 let big_p_i = ProjectivePoint::GENERATOR * p_i;
636 let x_i = new_x_i_list[my_party_id as usize];
637 let coeff_multipliers =
638 polynomial_coeff_multipliers(&x_i, my_rank as usize, NEW_T);
639
640 let expected_point: ProjectivePoint = big_p_poly
641 .points()
642 .zip(coeff_multipliers)
643 .map(|(point, coeff)| point * &coeff)
644 .sum();
645
646 if expected_point != big_p_i {
647 return Err(KeygenError::BigSMismatch);
648 }
649
650 let public_key = big_p_poly.get_constant();
651
652 if &public_key != expected_public_key {
653 return Err(KeygenError::PublicKeyMismatch);
654 }
655
656 let big_s_list: Vec<ProjectivePoint> = new_x_i_list
657 .iter()
658 .enumerate()
659 .map(|(party_id, x_i)| {
660 let party_rank = setup.new_participant_rank(party_id as u8);
661
662 let coeff_multipliers =
663 polynomial_coeff_multipliers(x_i, party_rank as usize, NEW_T);
664
665 big_p_poly
666 .points()
667 .zip(coeff_multipliers)
668 .map(|(point, coeff)| point * &coeff)
669 .sum()
670 })
671 .collect();
672
673 let mut rank_list = vec![];
674 for &party_index in setup.new_party_indices() {
675 let party_id = setup.new_party_id(party_index).unwrap();
676 rank_list.push(setup.new_participant_rank(party_id));
677 }
678
679 if !rank_list.iter().all(|&r| r == 0) {
680 check_secret_recovery(
682 &new_x_i_list,
683 &rank_list,
684 &big_s_list,
685 &public_key,
686 )?;
687 }
688
689 let mut new_keyshare = Keyshare::new(
690 NEW_N as u8,
691 NEW_T as u8,
692 my_party_id,
693 setup.keyshare_extra(),
694 );
695
696 new_keyshare.info_mut().final_session_id = final_session_id;
697 new_keyshare.info_mut().root_chain_code = root_chain_code;
698 new_keyshare.info_mut().public_key = encode_point(&public_key);
699 new_keyshare.info_mut().s_i = encode_scalar(&p_i);
700 new_keyshare.info_mut().key_id =
701 setup.derive_key_id(&public_key.to_bytes());
702
703 for p in 0..NEW_N {
704 let each = new_keyshare.each_mut(p as u8);
705
706 each.x_i = encode_scalar(&new_x_i_list[p]);
707 each.big_s = encode_point(&big_s_list[p]);
708 each.rank = rank_list[p];
709 }
710
711 let _ot1 = relay
715 .ask_messages_from_slice(
716 &setup,
717 QC_MSG_OT1,
718 setup.new_party_indices(),
719 true,
720 )
721 .await?;
722
723 let _ot2 = relay
724 .ask_messages_from_slice(
725 &setup,
726 QC_MSG_OT2,
727 setup.new_party_indices(),
728 true,
729 )
730 .await?;
731
732 let mut base_ot_receivers: Pairs<EndemicOTReceiver> = Pairs::new();
733 for &receiver_index in setup.new_party_indices() {
734 if receiver_index == my_party_index {
735 continue;
736 }
737
738 let receiver_id = setup.new_party_id(receiver_index).unwrap();
739
740 let sid = get_base_ot_session_id(
741 my_party_id,
742 receiver_id,
743 &new_keyshare.final_session_id,
744 );
745
746 let mut enc_ot_msg1 = EncryptedMessage::<EndemicOTMsg1>::new(
747 &setup.msg_id(Some(receiver_index), QC_MSG_OT1),
748 setup.message_ttl().as_secs() as u32,
749 0,
750 0,
751 &scheme,
752 );
753 let (msg1, _) = enc_ot_msg1.payload(&scheme);
754
755 let receiver = EndemicOTReceiver::new(&sid, msg1, &mut rng);
756 base_ot_receivers.push(receiver_id, receiver);
757
758 relay
762 .feed(
763 enc_ot_msg1
764 .encrypt(&mut scheme, receiver_index)
765 .ok_or(KeygenError::SendMessage)?,
766 )
767 .await
768 .map_err(|_| KeygenError::SendMessage)?;
769 }
770
771 Round::new(_ot1, QC_MSG_OT1, relay)
772 .of_encrypted_messages(
773 &setup,
774 &mut scheme,
775 0,
776 KeygenError::AbortProtocol,
777 |base_ot_msg1: &EndemicOTMsg1, receiver_index, _, scheme| {
778 let receiver_id = setup.new_party_id(receiver_index).unwrap();
779
780 let mut enc_buf = EncryptedMessage::<QCOTMsg2>::new(
781 &setup.msg_id(Some(receiver_index), QC_MSG_OT2),
782 setup.message_ttl().as_secs() as _,
783 0,
784 0,
785 scheme,
786 );
787
788 let (msg3, _trailer) = enc_buf.payload(scheme);
789
790 let sender_ot_seed = {
791 let sid = get_base_ot_session_id(
792 receiver_id,
793 my_party_id,
794 &new_keyshare.final_session_id,
795 );
796
797 block_in_place(|| {
798 EndemicOTSender::process(
799 &sid,
800 base_ot_msg1,
801 &mut msg3.base_ot_msg2,
802 &mut rng,
803 )
804 })
805 .map_err(|_| KeygenError::InvalidMessage)?
806 };
807
808 let all_but_one_session_id = get_all_but_one_session_id(
809 my_party_id as usize,
810 receiver_id as usize,
811 &new_keyshare.final_session_id,
812 );
813
814 build_pprf(
815 &all_but_one_session_id,
816 &sender_ot_seed,
817 &mut new_keyshare.other_mut(receiver_id).send_ot_seed,
818 &mut msg3.pprf_output,
819 );
820
821 if receiver_id > my_party_id {
822 rng.fill_bytes(&mut msg3.seed_i_j);
823 new_keyshare.each_mut(receiver_id - 1).zeta_seed =
824 msg3.seed_i_j;
825 };
826
827 Ok(Some(
828 enc_buf
829 .encrypt(scheme, receiver_index)
830 .ok_or(KeygenError::SendMessage)?,
831 ))
832 },
833 )
834 .await?;
835
836 Round::new(_ot2, QC_MSG_OT2, relay)
837 .of_encrypted_messages(
838 &setup,
839 &mut scheme,
840 0,
841 KeygenError::AbortProtocol,
842 |msg3: &QCOTMsg2, party_index, _, _| {
843 let party_id = setup.new_party_id(party_index).unwrap();
844
845 let receiver = base_ot_receivers.pop_pair(party_id);
846 let receiver_output =
847 block_in_place(|| receiver.process(&msg3.base_ot_msg2))
848 .map_err(|_| KeygenError::InvalidMessage)?;
849 let all_but_one_session_id = get_all_but_one_session_id(
850 party_id as usize,
851 my_party_id as usize,
852 &new_keyshare.final_session_id,
853 );
854
855 block_in_place(|| {
856 eval_pprf(
857 &all_but_one_session_id,
858 &receiver_output,
859 &msg3.pprf_output,
860 &mut new_keyshare.other_mut(party_id).recv_ot_seed,
861 )
862 })
863 .map_err(KeygenError::PPRFError)?;
864
865 if party_id < my_party_id {
866 new_keyshare.each_mut(party_id).zeta_seed = msg3.seed_i_j;
867 }
868
869 Ok(None)
870 },
871 )
872 .await?;
873
874 Ok(Some(new_keyshare))
875}
876
877fn hash_commitment_1(
893 session_id: &[u8],
894 party_index: usize,
895 big_f_i_vec: &GroupPolynomial<ProjectivePoint>,
896 r1_i: &[u8; 32],
897) -> [u8; 32] {
898 let mut hasher = Sha256::new();
899 hasher.update(QC_LABEL);
900 hasher.update(session_id);
901 hasher.update((party_index as u64).to_be_bytes());
902 for point in big_f_i_vec.points() {
903 hasher.update(point.to_bytes());
904 }
905 hasher.update(r1_i);
906 hasher.update(QC_COMMITMENT_1_LABEL);
907
908 hasher.finalize().into()
909}
910
911fn hash_commitment_2(
928 session_id: &[u8],
929 from_party_i_index: usize,
930 to_party_j_index: usize,
931 p_i_j: &Scalar,
932 r2_i: &[u8; 32],
933) -> [u8; 32] {
934 let mut hasher = Sha256::new();
935 hasher.update(QC_LABEL);
936 hasher.update(session_id);
937 hasher.update((from_party_i_index as u64).to_be_bytes());
938 hasher.update((to_party_j_index as u64).to_be_bytes());
939 hasher.update(p_i_j.to_bytes());
940 hasher.update(r2_i);
941 hasher.update(QC_COMMITMENT_2_LABEL);
942
943 hasher.finalize().into()
944}
945
946pub fn message_receivers<S, F>(setup: &S, mut msg_receiver: F)
961where
962 S: QuorumChangeSetupMessage<Keyshare, ProjectivePoint>,
963 F: FnMut(MsgId, &S::MessageVerifier),
964{
965 let my_party_index = setup.participant_index();
966 let my_party_is_old = setup.old_keyshare().is_some();
967 let my_new_party_id = setup.new_party_id(my_party_index);
968 let my_party_is_new = my_new_party_id.is_some();
969
970 let _old = setup.old_party_indices();
971 let new = setup.new_party_indices();
972
973 setup.all_other_parties().for_each(|receiver_idx| {
974 let receiver = setup.verifier(receiver_idx);
975
976 msg_receiver(setup.msg_id(None, ABORT_MESSAGE_TAG), receiver);
977
978 if my_party_is_old {
979 msg_receiver(setup.msg_id(None, QC_MSG_R0), receiver);
980 }
981
982 msg_receiver(setup.msg_id(None, QC_MSG_R1), receiver);
983
984 if my_party_is_old && new.contains(&receiver_idx) {
985 msg_receiver(
986 setup.msg_id(Some(receiver_idx), QC_MSG_P2P_1),
987 receiver,
988 );
989 }
990
991 if my_party_is_old && new.contains(&receiver_idx) {
992 msg_receiver(
993 setup.msg_id(Some(receiver_idx), QC_MSG_P2P_2),
994 receiver,
995 );
996 }
997
998 if my_party_is_old {
999 msg_receiver(setup.msg_id(None, QC_MSG_R2), receiver);
1000 }
1001
1002 if my_party_is_new && new.contains(&receiver_idx) {
1003 msg_receiver(
1004 setup.msg_id(Some(receiver_idx), QC_MSG_OT1),
1005 receiver,
1006 );
1007 }
1008
1009 if my_party_is_new && new.contains(&receiver_idx) {
1010 msg_receiver(
1011 setup.msg_id(Some(receiver_idx), QC_MSG_OT2),
1012 receiver,
1013 );
1014 }
1015 })
1016}
1017
1018#[cfg(test)]
1019mod tests {
1020 use super::*;
1021 use std::sync::Arc;
1022
1023 use tokio::task::JoinSet;
1024
1025 use sl_mpc_mate::{
1026 coord::{
1027 adversary::{EvilMessageRelay, EvilPlay},
1028 MessageRelayService, SimpleMessageRelay,
1029 },
1030 message::MsgId,
1031 };
1032
1033 use crate::{
1034 keygen::utils::{
1035 gen_keyshares, setup_quorum_change,
1036 setup_quorum_change_extend_parties,
1037 setup_quorum_change_threshold,
1038 },
1039 setup::quorum_change::SetupMessage as QuorumChangeSetupMessage,
1040 sign::{run as run_dsg, setup_dsg},
1041 };
1042
1043 async fn sim<S, R>(
1044 old_keyshares: &[Arc<Keyshare>],
1045 new_threshold: u8,
1046 new_ranks: Vec<u8>,
1047 coord: S,
1048 ) -> Vec<Option<Arc<Keyshare>>>
1049 where
1050 S: MessageRelayService<MessageRelay = R>,
1051 R: Relay + Send + 'static,
1052 {
1053 let parties =
1054 setup_quorum_change(old_keyshares, new_threshold, &new_ranks);
1055
1056 sim_parties(parties, coord).await
1057 }
1058
1059 async fn sim_extend<S, R>(
1060 old_keyshares: &[Arc<Keyshare>],
1061 new_threshold: u8,
1062 new_parties_len: u8,
1063 new_ranks: Vec<u8>,
1064 coord: S,
1065 ) -> Vec<Option<Arc<Keyshare>>>
1066 where
1067 S: MessageRelayService<MessageRelay = R>,
1068 R: Relay + Send + 'static,
1069 {
1070 let parties = setup_quorum_change_extend_parties(
1071 old_keyshares,
1072 new_threshold,
1073 new_parties_len,
1074 &new_ranks,
1075 );
1076 sim_parties(parties, coord).await
1077 }
1078
1079 async fn sim_only_change_threshold<S, R>(
1080 old_keyshares: &[Arc<Keyshare>],
1081 new_threshold: u8,
1082 new_ranks: Vec<u8>,
1083 coord: S,
1084 ) -> Vec<Option<Arc<Keyshare>>>
1085 where
1086 S: MessageRelayService<MessageRelay = R>,
1087 R: Relay + Send + 'static,
1088 {
1089 let parties = setup_quorum_change_threshold(
1090 old_keyshares,
1091 new_threshold,
1092 &new_ranks,
1093 );
1094 sim_parties(parties, coord).await
1095 }
1096
1097 async fn sim_parties<S, R>(
1098 parties: Vec<(QuorumChangeSetupMessage, [u8; 32])>,
1099 coord: S,
1100 ) -> Vec<Option<Arc<Keyshare>>>
1101 where
1102 S: MessageRelayService<MessageRelay = R>,
1103 R: Send + Relay + 'static,
1104 {
1105 let mut jset = JoinSet::new();
1106 for (setup, seed) in parties {
1107 let relay = coord.connect().await.unwrap();
1108
1109 jset.spawn(run(setup, seed, relay));
1110 }
1111
1112 let mut shares = vec![];
1113
1114 while let Some(fini) = jset.join_next().await {
1115 let fini = fini.unwrap();
1116
1117 if let Err(ref err) = fini {
1118 println!("error {}", err);
1119 }
1120
1121 let share = fini.unwrap();
1122 match share {
1123 None => shares.push(None),
1124 Some(v) => shares.push(Some(Arc::new(v))),
1125 }
1126 }
1127
1128 shares
1129 }
1130
1131 #[tokio::test(flavor = "multi_thread")]
1132 async fn quorum_change_all_new_parties() {
1133 let old_threshold = 2;
1134 let old_n = 3;
1135 let ranks = [0, 0, 0];
1136 let shares = gen_keyshares(old_threshold, old_n, Some(&ranks)).await;
1137 let expected_public_key = shares[0].public_key;
1138
1139 let shares =
1140 [shares[1].clone(), shares[0].clone(), shares[2].clone()];
1141
1142 let new_threshold = 3;
1143 let new_n = 4;
1144 let new_ranks = vec![0, 0, 1, 1];
1145 let result = sim(
1146 &shares[..old_threshold as usize],
1147 new_threshold,
1148 new_ranks,
1149 SimpleMessageRelay::new(),
1150 )
1151 .await;
1152
1153 let mut new_shares: Vec<Arc<Keyshare>> =
1154 result.iter().flatten().cloned().collect();
1155 assert_eq!(new_shares.len(), new_n as usize);
1156 assert_eq!(expected_public_key, new_shares[0].public_key);
1157
1158 let coord = SimpleMessageRelay::new();
1160
1161 new_shares.sort_by_key(|share| share.party_id);
1162 let subset = &new_shares[0..new_threshold as usize];
1163
1164 let mut parties: JoinSet<Result<_, _>> = JoinSet::new();
1165 for (setup, seed) in setup_dsg(None, subset, "m") {
1166 parties.spawn(run_dsg(setup, seed, coord.connect()));
1167 }
1168
1169 while let Some(fini) = parties.join_next().await {
1170 let fini = fini.unwrap();
1171
1172 if let Err(ref err) = fini {
1173 println!("error {err:?}");
1174 }
1175 let _fini = fini.unwrap();
1176 }
1177 }
1178
1179 #[tokio::test(flavor = "multi_thread")]
1180 async fn quorum_change_extend_parties() {
1181 let old_threshold = 2;
1182 let old_n = 3;
1183 let ranks = [0, 0, 0];
1184 let shares = gen_keyshares(old_threshold, old_n, Some(&ranks)).await;
1185 let expected_public_key = shares[0].public_key;
1186
1187 let shares =
1188 [shares[1].clone(), shares[0].clone(), shares[2].clone()];
1189
1190 let new_threshold = 2;
1191 let new_parties_len = 2;
1192 let new_n = old_n + new_parties_len;
1193 let new_ranks = vec![0, 0, 0, 1, 1];
1194 let result = sim_extend(
1195 &shares,
1196 new_threshold,
1197 new_parties_len,
1198 new_ranks,
1199 SimpleMessageRelay::new(),
1200 )
1201 .await;
1202
1203 let mut new_shares: Vec<Arc<Keyshare>> =
1204 result.iter().flatten().cloned().collect();
1205 assert_eq!(new_shares.len(), new_n as usize);
1206 assert_eq!(expected_public_key, new_shares[0].public_key);
1207
1208 let coord = SimpleMessageRelay::new();
1210
1211 new_shares.sort_by_key(|share| share.party_id);
1212 let subset = &new_shares[0..new_threshold as usize];
1213
1214 let mut parties: JoinSet<Result<_, _>> = JoinSet::new();
1215 for (setup, seed) in setup_dsg(None, subset, "m") {
1216 parties.spawn(run_dsg(setup, seed, coord.connect()));
1217 }
1218
1219 while let Some(fini) = parties.join_next().await {
1220 let fini = fini.unwrap();
1221
1222 if let Err(ref err) = fini {
1223 println!("error {err:?}");
1224 }
1225 let _fini = fini.unwrap();
1226 }
1227 }
1228
1229 #[tokio::test(flavor = "multi_thread")]
1230 async fn quorum_change_only_change_threshold() {
1231 let old_threshold = 2;
1232 let old_n = 4;
1233 let ranks = [0, 0, 0, 0];
1234 let mut shares =
1235 gen_keyshares(old_threshold, old_n, Some(&ranks)).await;
1236 let expected_public_key = shares[0].public_key;
1237
1238 shares.shuffle(&mut thread_rng());
1239
1240 let new_threshold = 3;
1241 let new_n = old_n;
1242 let new_ranks = vec![0, 0, 0, 0];
1243 let result = sim_only_change_threshold(
1244 &shares,
1245 new_threshold,
1246 new_ranks,
1247 SimpleMessageRelay::new(),
1248 )
1249 .await;
1250
1251 let mut new_shares: Vec<Arc<Keyshare>> =
1252 result.iter().flatten().cloned().collect();
1253 assert_eq!(new_shares.len(), new_n as usize);
1254 assert_eq!(expected_public_key, new_shares[0].public_key);
1255
1256 let coord = SimpleMessageRelay::new();
1258
1259 new_shares.sort_by_key(|share| share.party_id);
1260 let subset = &new_shares[0..new_threshold as usize];
1261
1262 let mut parties: JoinSet<Result<_, _>> = JoinSet::new();
1263 for (setup, seed) in setup_dsg(None, subset, "m") {
1264 parties.spawn(run_dsg(setup, seed, coord.connect()));
1265 }
1266
1267 while let Some(fini) = parties.join_next().await {
1268 let fini = fini.unwrap();
1269
1270 if let Err(ref err) = fini {
1271 println!("error {err:?}");
1272 }
1273 let _fini = fini.unwrap();
1274 }
1275 }
1276
1277 #[tokio::test(flavor = "multi_thread")]
1278 async fn n1() {
1279 let old_threshold = 2;
1280 let old_n = 3;
1281 let ranks = [0, 0, 0];
1282 let shares = gen_keyshares(old_threshold, old_n, Some(&ranks)).await;
1283
1284 let play = EvilPlay::new().drop_message(MsgId::ZERO_ID, None);
1285
1286 let new_threshold = 2;
1287 let new_ranks = vec![0, 0, 1, 1];
1288 sim(
1289 &shares[..old_threshold as usize],
1290 new_threshold,
1291 new_ranks,
1292 EvilMessageRelay::new(play),
1293 )
1294 .await;
1295 }
1296}