1use std::collections::BTreeMap;
55
56use rustcrypto_ff::Field;
57use rustcrypto_group::prime::PrimeCurveAffine;
58use rustcrypto_group::Curve as GroupCurve;
59
60use rand::RngExt;
61
62use crate::curve::DklsCurve;
63use crate::protocols::derivation::{ChainCode, DerivData, CHAIN_CODE_LEN};
64use crate::protocols::{
65 Abort, AbortReason, Parameters, PartiesMessage, Party, PartyIndex, PublicKeyPackage,
66};
67
68use crate::utilities::commits;
69use crate::utilities::hashes::HashOutput;
70use crate::utilities::multiplication::{MulReceiver, MulSender};
71use crate::utilities::ot;
72use crate::utilities::proofs::{DLogProof, EncProof};
73use crate::utilities::rng;
74use crate::utilities::zero_shares::{self, ZeroShare};
75
76#[derive(Debug, Clone)]
82#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
83#[cfg_attr(
84 feature = "serde",
85 serde(bound(
86 serialize = "C::AffinePoint: serde::Serialize, C::Scalar: serde::Serialize",
87 deserialize = "C::AffinePoint: serde::Deserialize<'de>, C::Scalar: serde::Deserialize<'de>"
88 ))
89)]
90pub struct ProofCommitment<C: DklsCurve> {
91 pub index: PartyIndex,
92 pub proof: DLogProof<C>,
93 pub commitment: HashOutput,
94}
95
96#[derive(Clone)]
98#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
99pub struct SessionData {
100 pub parameters: Parameters,
101 pub party_index: PartyIndex,
102 pub session_id: Vec<u8>,
103}
104
105#[derive(Clone, Debug)]
111#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
112pub struct TransmitInitZeroSharePhase2to4 {
113 pub parties: PartiesMessage,
114 pub commitment: HashOutput,
115}
116
117#[derive(Clone, Debug)]
121#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
122pub struct TransmitInitZeroSharePhase3to4 {
123 pub parties: PartiesMessage,
124 pub seed: zero_shares::Seed,
125 pub salt: Vec<u8>,
126}
127
128#[derive(Clone, Debug)]
132#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
133pub struct KeepInitZeroSharePhase2to3 {
134 pub seed: zero_shares::Seed,
135 pub salt: Vec<u8>,
136}
137
138#[derive(Clone, Debug)]
142#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
143pub struct KeepInitZeroSharePhase3to4 {
144 pub seed: zero_shares::Seed,
145}
146
147#[derive(Clone, Debug)]
153#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
154#[cfg_attr(
155 feature = "serde",
156 serde(bound(
157 serialize = "C::AffinePoint: serde::Serialize, C::Scalar: serde::Serialize",
158 deserialize = "C::AffinePoint: serde::Deserialize<'de>, C::Scalar: serde::Deserialize<'de>"
159 ))
160)]
161pub struct TransmitInitMulPhase3to4<C: DklsCurve> {
162 pub parties: PartiesMessage,
163
164 pub dlog_proof: DLogProof<C>,
165 pub nonce: C::Scalar,
166
167 pub enc_proofs: Vec<EncProof<C>>,
168 pub seed: ot::base::Seed,
169}
170
171#[derive(Clone, Debug)]
175#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
176#[cfg_attr(
177 feature = "serde",
178 serde(bound(
179 serialize = "C::AffinePoint: serde::Serialize, C::Scalar: serde::Serialize",
180 deserialize = "C::AffinePoint: serde::Deserialize<'de>, C::Scalar: serde::Deserialize<'de>"
181 ))
182)]
183pub struct KeepInitMulPhase3to4<C: DklsCurve> {
184 pub ot_sender: ot::base::OTSender<C>,
185 pub nonce: C::Scalar,
186
187 pub ot_receiver: ot::base::OTReceiver,
188 pub correlation: Vec<bool>,
189 pub vec_r: Vec<C::Scalar>,
190}
191
192#[derive(Clone, Debug)]
198#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
199pub struct BroadcastDerivationPhase2to4 {
200 pub sender_index: PartyIndex,
201 pub cc_commitment: HashOutput,
202}
203
204#[derive(Clone, Debug)]
208#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
209pub struct BroadcastDerivationPhase3to4 {
210 pub sender_index: PartyIndex,
211 pub aux_chain_code: ChainCode,
212 pub cc_salt: Vec<u8>,
213}
214
215#[derive(Clone, Debug)]
219#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
220pub struct UniqueKeepDerivationPhase2to3 {
221 pub aux_chain_code: ChainCode,
222 pub cc_salt: Vec<u8>,
223}
224
225#[cfg(feature = "serde")]
227mod message_tags {
228 use super::*;
229 use crate::protocols::messages::MessageTag;
230
231 impl<C: DklsCurve> MessageTag for ProofCommitment<C>
232 where
233 C::AffinePoint: serde::Serialize + serde::de::DeserializeOwned,
234 C::Scalar: serde::Serialize + serde::de::DeserializeOwned,
235 {
236 const TAG: u8 = 0x01;
237 }
238 impl MessageTag for TransmitInitZeroSharePhase2to4 {
239 const TAG: u8 = 0x02;
240 }
241 impl MessageTag for TransmitInitZeroSharePhase3to4 {
242 const TAG: u8 = 0x03;
243 }
244 impl<C: DklsCurve> MessageTag for TransmitInitMulPhase3to4<C>
245 where
246 C::AffinePoint: serde::Serialize + serde::de::DeserializeOwned,
247 C::Scalar: serde::Serialize + serde::de::DeserializeOwned,
248 {
249 const TAG: u8 = 0x04;
250 }
251 impl MessageTag for BroadcastDerivationPhase2to4 {
252 const TAG: u8 = 0x05;
253 }
254 impl MessageTag for BroadcastDerivationPhase3to4 {
255 const TAG: u8 = 0x06;
256 }
257}
258
259#[must_use]
268pub(crate) fn step1<C: DklsCurve>(parameters: &Parameters) -> Vec<C::Scalar> {
269 let mut rng = rng::get_rng(); let mut polynomial: Vec<C::Scalar> = Vec::with_capacity(parameters.threshold as usize);
272 for _ in 0..parameters.threshold {
273 polynomial.push(<C::Scalar as Field>::random(&mut rng)); }
275 polynomial
276}
277
278#[must_use]
288pub(crate) fn step2<C: DklsCurve>(
289 parameters: &Parameters,
290 polynomial: &[C::Scalar],
291) -> Vec<C::Scalar> {
292 let mut points: Vec<C::Scalar> = Vec::with_capacity(parameters.share_count as usize);
293 let last_index = (parameters.threshold - 1) as usize;
294
295 for j in 1..=parameters.share_count {
296 let j_scalar = C::Scalar::from(u64::from(j));
297
298 let mut evaluation_at_j = polynomial[last_index];
300
301 for &coefficient in polynomial[..last_index].iter().rev() {
302 evaluation_at_j = evaluation_at_j * j_scalar + coefficient;
303 }
304
305 points.push(evaluation_at_j);
306 }
307
308 points
309}
310
311#[must_use]
328pub(crate) fn step3<C: DklsCurve>(
329 party_index: PartyIndex,
330 session_id: &[u8],
331 poly_fragments: &[C::Scalar],
332) -> (C::Scalar, ProofCommitment<C>) {
333 let poly_point: C::Scalar = poly_fragments.iter().copied().sum();
334
335 let (proof, commitment) = DLogProof::<C>::prove_commit(&poly_point, session_id)
336 .expect("Fischlin proof-of-work search exhausted — RNG failure");
337 let proof_commitment = ProofCommitment {
338 index: party_index,
339 proof,
340 commitment,
341 };
342
343 (poly_point, proof_commitment)
344}
345
346pub(crate) fn step5<C: DklsCurve>(
366 parameters: &Parameters,
367 party_index: PartyIndex,
368 session_id: &[u8],
369 proofs_commitments: &[ProofCommitment<C>],
370) -> Result<(C::AffinePoint, BTreeMap<PartyIndex, C::AffinePoint>), Abort> {
371 let mut committed_points: BTreeMap<PartyIndex, C::AffinePoint> = BTreeMap::new(); for party_j in proofs_commitments {
375 if party_j.index != party_index {
376 let verification =
377 DLogProof::<C>::decommit_verify(&party_j.proof, &party_j.commitment, session_id);
378 if !verification {
379 return Err(Abort::recoverable(
380 party_index,
381 AbortReason::ProofVerificationFailed {
382 counterparty: party_j.index,
383 },
384 ));
385 }
386 }
387 committed_points.insert(party_j.index, party_j.proof.point);
388 }
389
390 let identity = <C::AffinePoint as PrimeCurveAffine>::identity();
392 let mut pk = identity;
393
394 for i in 1..=(parameters.share_count - parameters.threshold + 1) {
398 let mut current_pk = identity;
399 for j in i..(i + parameters.threshold) {
400 let j_scalar = C::Scalar::from(u64::from(j));
403 let mut lj_numerator = <C::Scalar as Field>::ONE;
404 let mut lj_denominator = <C::Scalar as Field>::ONE;
405
406 for k in i..(i + parameters.threshold) {
407 if k != j {
408 let k_scalar = C::Scalar::from(u64::from(k));
409 lj_numerator *= k_scalar;
410 lj_denominator *= k_scalar - j_scalar;
411 }
412 }
413
414 let lj = lj_numerator * (lj_denominator.invert().unwrap());
415 let point_j = committed_points
416 .get(&PartyIndex::new(j).unwrap())
417 .ok_or_else(|| {
418 Abort::recoverable(
419 party_index,
420 AbortReason::MissingCommittedPoint {
421 party: PartyIndex::new(j).unwrap(),
422 },
423 )
424 })?;
425 let lj_times_point = *point_j * lj;
426
427 current_pk = (lj_times_point + current_pk).to_affine();
428 }
429
430 if i == 1 {
432 pk = current_pk;
433 } else if pk != current_pk {
434 return Err(Abort::recoverable(
435 party_index,
436 AbortReason::PolynomialInconsistency,
437 ));
438 }
439 }
440 Ok((pk, committed_points))
441}
442
443#[must_use]
460pub fn phase1<C: DklsCurve>(data: &SessionData) -> Vec<C::Scalar> {
461 let secret_polynomial = step1::<C>(&data.parameters);
463
464 step2::<C>(&data.parameters, &secret_polynomial)
465}
466
467#[must_use]
488pub fn phase2<C: DklsCurve>(
489 data: &SessionData,
490 poly_fragments: &[C::Scalar],
491) -> (
492 C::Scalar,
493 ProofCommitment<C>,
494 BTreeMap<PartyIndex, KeepInitZeroSharePhase2to3>,
495 Vec<TransmitInitZeroSharePhase2to4>,
496 UniqueKeepDerivationPhase2to3,
497 BroadcastDerivationPhase2to4,
498) {
499 let (poly_point, proof_commitment) =
501 step3::<C>(data.party_index, &data.session_id, poly_fragments);
502
503 let mut zero_keep = BTreeMap::new();
507 let mut zero_transmit = Vec::with_capacity((data.parameters.share_count - 1) as usize);
508
509 for i in 1..=data.parameters.share_count {
510 let i_idx = PartyIndex::new(i).unwrap();
511 if i_idx == data.party_index {
512 continue;
513 }
514
515 let (seed, commitment, salt) = ZeroShare::generate_seed_with_commitment();
517
518 zero_keep.insert(i_idx, KeepInitZeroSharePhase2to3 { seed, salt });
520 zero_transmit.push(TransmitInitZeroSharePhase2to4 {
521 parties: PartiesMessage {
522 sender: data.party_index,
523 receiver: i_idx,
524 },
525 commitment,
526 });
527 }
528
529 let aux_chain_code: ChainCode = rng::get_rng().random();
533 let (cc_commitment, cc_salt) = commits::commit(&aux_chain_code);
534
535 let bip_keep = UniqueKeepDerivationPhase2to3 {
536 aux_chain_code,
537 cc_salt,
538 };
539
540 let bip_broadcast = BroadcastDerivationPhase2to4 {
542 sender_index: data.party_index,
543 cc_commitment,
544 };
545
546 (
547 poly_point,
548 proof_commitment,
549 zero_keep,
550 zero_transmit,
551 bip_keep,
552 bip_broadcast,
553 )
554}
555
556#[must_use]
573#[allow(clippy::type_complexity)]
574pub fn phase3<C: DklsCurve>(
575 data: &SessionData,
576 zero_kept: &BTreeMap<PartyIndex, KeepInitZeroSharePhase2to3>,
577 bip_kept: &UniqueKeepDerivationPhase2to3,
578) -> (
579 BTreeMap<PartyIndex, KeepInitZeroSharePhase3to4>,
580 Vec<TransmitInitZeroSharePhase3to4>,
581 BTreeMap<PartyIndex, KeepInitMulPhase3to4<C>>,
582 Vec<TransmitInitMulPhase3to4<C>>,
583 BroadcastDerivationPhase3to4,
584) {
585 let share_count = (data.parameters.share_count - 1) as usize;
587 let mut zero_keep = BTreeMap::new();
588 let mut zero_transmit = Vec::with_capacity(share_count);
589
590 for (&target_party, message_kept) in zero_kept.iter() {
591 let keep = KeepInitZeroSharePhase3to4 {
595 seed: message_kept.seed,
596 };
597 let transmit = TransmitInitZeroSharePhase3to4 {
598 parties: PartiesMessage {
599 sender: data.party_index,
600 receiver: target_party,
601 },
602 seed: message_kept.seed,
603 salt: message_kept.salt.clone(),
604 };
605
606 zero_keep.insert(target_party, keep);
607 zero_transmit.push(transmit);
608 }
609
610 let mut mul_keep = BTreeMap::new();
615 let mut mul_transmit = Vec::with_capacity(share_count);
616
617 for i in 1..=data.parameters.share_count {
618 let i_idx = PartyIndex::new(i).unwrap();
619 if i_idx == data.party_index {
620 continue;
621 }
622
623 let mul_sid_receiver = [
629 "Multiplication protocol".as_bytes(),
630 &data.party_index.as_u8().to_be_bytes(),
631 &i.to_be_bytes(),
632 &data.session_id[..],
633 ]
634 .concat();
635
636 let (ot_sender, dlog_proof, nonce) = MulReceiver::<C>::init_phase1(&mul_sid_receiver);
637
638 let mul_sid_sender = [
644 "Multiplication protocol".as_bytes(),
645 &i.to_be_bytes(),
646 &data.party_index.as_u8().to_be_bytes(),
647 &data.session_id[..],
648 ]
649 .concat();
650
651 let (ot_receiver, correlation, vec_r, enc_proofs) =
652 MulSender::<C>::init_phase1(&mul_sid_sender);
653
654 let transmit = TransmitInitMulPhase3to4 {
657 parties: PartiesMessage {
658 sender: data.party_index,
659 receiver: i_idx,
660 },
661
662 dlog_proof,
664 nonce,
665
666 enc_proofs,
668 seed: ot_receiver.seed,
669 };
670 let keep = KeepInitMulPhase3to4 {
671 ot_sender,
673 nonce,
674
675 ot_receiver,
677 correlation,
678 vec_r,
679 };
680
681 mul_keep.insert(i_idx, keep);
682 mul_transmit.push(transmit);
683 }
684
685 let bip_broadcast = BroadcastDerivationPhase3to4 {
690 sender_index: data.party_index,
691 aux_chain_code: bip_kept.aux_chain_code,
692 cc_salt: bip_kept.cc_salt.clone(),
693 };
694
695 (
696 zero_keep,
697 zero_transmit,
698 mul_keep,
699 mul_transmit,
700 bip_broadcast,
701 )
702}
703
704#[allow(clippy::too_many_arguments)]
742pub fn phase4<C: DklsCurve>(
743 data: &SessionData,
744 poly_point: &C::Scalar,
745 proofs_commitments: &[ProofCommitment<C>],
746 zero_kept: &BTreeMap<PartyIndex, KeepInitZeroSharePhase3to4>,
747 zero_received_phase2: &[TransmitInitZeroSharePhase2to4],
748 zero_received_phase3: &[TransmitInitZeroSharePhase3to4],
749 mul_kept: &BTreeMap<PartyIndex, KeepInitMulPhase3to4<C>>,
750 mul_received: &[TransmitInitMulPhase3to4<C>],
751 bip_received_phase2: &BTreeMap<PartyIndex, BroadcastDerivationPhase2to4>,
752 bip_received_phase3: &BTreeMap<PartyIndex, BroadcastDerivationPhase3to4>,
753 address_fn: impl Fn(&C::AffinePoint) -> String,
754) -> Result<(Party<C>, PublicKeyPackage<C>), Abort> {
755 let (pk, verifying_shares) = step5::<C>(
757 &data.parameters,
758 data.party_index,
759 &data.session_id,
760 proofs_commitments,
761 )?;
762
763 let identity = <C::AffinePoint as PrimeCurveAffine>::identity();
768 let generator = <C::AffinePoint as PrimeCurveAffine>::generator();
769 if pk == identity || pk == generator {
770 return Err(Abort::recoverable(
771 data.party_index,
772 AbortReason::TrivialPublicKey,
773 ));
774 }
775
776 if *poly_point == <C::Scalar as Field>::ZERO || *poly_point == <C::Scalar as Field>::ONE {
780 return Err(Abort::recoverable(
781 data.party_index,
782 AbortReason::TrivialKeyShare,
783 ));
784 }
785
786 let mut zero_received_phase2_by_sender: BTreeMap<PartyIndex, &TransmitInitZeroSharePhase2to4> =
788 BTreeMap::new();
789 for message in zero_received_phase2 {
790 if message.parties.receiver != data.party_index {
791 return Err(Abort::recoverable(
792 data.party_index,
793 AbortReason::MisroutedMessage {
794 expected_receiver: data.party_index,
795 actual_receiver: message.parties.receiver,
796 },
797 ));
798 }
799 if !zero_kept.contains_key(&message.parties.sender) {
800 return Err(Abort::recoverable(
801 data.party_index,
802 AbortReason::UnexpectedSender {
803 sender: message.parties.sender,
804 },
805 ));
806 }
807 if zero_received_phase2_by_sender
808 .insert(message.parties.sender, message)
809 .is_some()
810 {
811 return Err(Abort::recoverable(
812 data.party_index,
813 AbortReason::DuplicateSender {
814 sender: message.parties.sender,
815 },
816 ));
817 }
818 }
819 let mut zero_received_phase3_by_sender: BTreeMap<PartyIndex, &TransmitInitZeroSharePhase3to4> =
820 BTreeMap::new();
821 for message in zero_received_phase3 {
822 if message.parties.receiver != data.party_index {
823 return Err(Abort::recoverable(
824 data.party_index,
825 AbortReason::MisroutedMessage {
826 expected_receiver: data.party_index,
827 actual_receiver: message.parties.receiver,
828 },
829 ));
830 }
831 if !zero_kept.contains_key(&message.parties.sender) {
832 return Err(Abort::recoverable(
833 data.party_index,
834 AbortReason::UnexpectedSender {
835 sender: message.parties.sender,
836 },
837 ));
838 }
839 if zero_received_phase3_by_sender
840 .insert(message.parties.sender, message)
841 .is_some()
842 {
843 return Err(Abort::recoverable(
844 data.party_index,
845 AbortReason::DuplicateSender {
846 sender: message.parties.sender,
847 },
848 ));
849 }
850 }
851 if zero_received_phase2_by_sender.len() != zero_kept.len() {
852 return Err(Abort::recoverable(
853 data.party_index,
854 AbortReason::WrongMessageCount {
855 expected: zero_kept.len(),
856 got: zero_received_phase2_by_sender.len(),
857 },
858 ));
859 }
860 if zero_received_phase3_by_sender.len() != zero_kept.len() {
861 return Err(Abort::recoverable(
862 data.party_index,
863 AbortReason::WrongMessageCount {
864 expected: zero_kept.len(),
865 got: zero_received_phase3_by_sender.len(),
866 },
867 ));
868 }
869
870 let mut seeds: Vec<zero_shares::SeedPair> =
871 Vec::with_capacity((data.parameters.share_count - 1) as usize);
872 for (target_party, message_kept) in zero_kept {
873 let message_received_2 = zero_received_phase2_by_sender
874 .get(target_party)
875 .ok_or_else(|| {
876 Abort::recoverable(
877 data.party_index,
878 AbortReason::MissingMessageFromParty {
879 party: *target_party,
880 },
881 )
882 })?;
883 let message_received_3 = zero_received_phase3_by_sender
884 .get(target_party)
885 .ok_or_else(|| {
886 Abort::recoverable(
887 data.party_index,
888 AbortReason::MissingMessageFromParty {
889 party: *target_party,
890 },
891 )
892 })?;
893
894 let verification = ZeroShare::verify_seed(
896 &message_received_3.seed,
897 &message_received_2.commitment,
898 &message_received_3.salt,
899 );
900 if !verification {
901 return Err(Abort::recoverable(
902 data.party_index,
903 AbortReason::ZeroShareDecommitFailed {
904 counterparty: *target_party,
905 },
906 ));
907 }
908
909 seeds.push(ZeroShare::generate_seed_pair(
911 data.party_index,
912 *target_party,
913 &message_kept.seed,
914 &message_received_3.seed,
915 ));
916 }
917
918 let zero_share = ZeroShare::initialize(seeds);
920
921 let mut mul_receivers: BTreeMap<PartyIndex, MulReceiver<C>> = BTreeMap::new();
923 let mut mul_senders: BTreeMap<PartyIndex, MulSender<C>> = BTreeMap::new();
924 let mut mul_received_by_sender: BTreeMap<PartyIndex, &TransmitInitMulPhase3to4<C>> =
925 BTreeMap::new();
926 for message in mul_received {
927 if message.parties.receiver != data.party_index {
928 return Err(Abort::recoverable(
929 data.party_index,
930 AbortReason::MisroutedMessage {
931 expected_receiver: data.party_index,
932 actual_receiver: message.parties.receiver,
933 },
934 ));
935 }
936 if !mul_kept.contains_key(&message.parties.sender) {
937 return Err(Abort::recoverable(
938 data.party_index,
939 AbortReason::UnexpectedSender {
940 sender: message.parties.sender,
941 },
942 ));
943 }
944 if mul_received_by_sender
945 .insert(message.parties.sender, message)
946 .is_some()
947 {
948 return Err(Abort::recoverable(
949 data.party_index,
950 AbortReason::DuplicateSender {
951 sender: message.parties.sender,
952 },
953 ));
954 }
955 }
956 if mul_received_by_sender.len() != mul_kept.len() {
957 return Err(Abort::recoverable(
958 data.party_index,
959 AbortReason::WrongMessageCount {
960 expected: mul_kept.len(),
961 got: mul_received_by_sender.len(),
962 },
963 ));
964 }
965
966 for (target_party, message_kept) in mul_kept {
967 let message_received = mul_received_by_sender.get(target_party).ok_or_else(|| {
968 Abort::recoverable(
969 data.party_index,
970 AbortReason::MissingMessageFromParty {
971 party: *target_party,
972 },
973 )
974 })?;
975
976 let mul_sid_receiver = [
982 "Multiplication protocol".as_bytes(),
983 &data.party_index.as_u8().to_be_bytes(),
984 &target_party.as_u8().to_be_bytes(),
985 &data.session_id[..],
986 ]
987 .concat();
988
989 let receiver_result = MulReceiver::<C>::init_phase2(
990 &message_kept.ot_sender,
991 &mul_sid_receiver,
992 &message_received.seed,
993 &message_received.enc_proofs,
994 &message_kept.nonce,
995 );
996
997 let mul_receiver: MulReceiver<C> = match receiver_result {
998 Ok(r) => r,
999 Err(error) => {
1000 return Err(Abort::recoverable(
1003 data.party_index,
1004 AbortReason::MultiplicationVerificationFailed {
1005 counterparty: *target_party,
1006 detail: error.description.clone(),
1007 },
1008 ));
1009 }
1010 };
1011
1012 let mul_sid_sender = [
1018 "Multiplication protocol".as_bytes(),
1019 &target_party.as_u8().to_be_bytes(),
1020 &data.party_index.as_u8().to_be_bytes(),
1021 &data.session_id[..],
1022 ]
1023 .concat();
1024
1025 let sender_result = MulSender::<C>::init_phase2(
1026 &message_kept.ot_receiver,
1027 &mul_sid_sender,
1028 message_kept.correlation.clone(),
1029 &message_kept.vec_r,
1030 &message_received.dlog_proof,
1031 &message_received.nonce,
1032 );
1033
1034 let mul_sender: MulSender<C> = match sender_result {
1035 Ok(s) => s,
1036 Err(error) => {
1037 return Err(Abort::recoverable(
1040 data.party_index,
1041 AbortReason::MultiplicationVerificationFailed {
1042 counterparty: *target_party,
1043 detail: error.description.clone(),
1044 },
1045 ));
1046 }
1047 };
1048
1049 mul_receivers.insert(*target_party, mul_receiver);
1051 mul_senders.insert(*target_party, mul_sender.clone());
1052 }
1053
1054 let mut chain_code: ChainCode = [0; CHAIN_CODE_LEN];
1058 for i in 1..=data.parameters.share_count {
1059 let i_idx = PartyIndex::new(i).unwrap();
1060 let phase3_msg = bip_received_phase3.get(&i_idx).ok_or_else(|| {
1062 Abort::recoverable(
1063 data.party_index,
1064 AbortReason::MissingMessageFromParty { party: i_idx },
1065 )
1066 })?;
1067 let phase2_msg = bip_received_phase2.get(&i_idx).ok_or_else(|| {
1068 Abort::recoverable(
1069 data.party_index,
1070 AbortReason::MissingMessageFromParty { party: i_idx },
1071 )
1072 })?;
1073 let verification = commits::verify_commitment(
1074 &phase3_msg.aux_chain_code,
1075 &phase2_msg.cc_commitment,
1076 &phase3_msg.cc_salt,
1077 );
1078 if !verification {
1079 return Err(Abort::recoverable(
1080 data.party_index,
1081 AbortReason::ChainCodeCommitmentFailed { party: i_idx },
1082 ));
1083 }
1084
1085 let current_aux_chain_code = phase3_msg.aux_chain_code;
1087 for j in 0..CHAIN_CODE_LEN {
1088 chain_code[j] ^= current_aux_chain_code[j];
1089 }
1090 }
1091
1092 let derivation_data = DerivData {
1095 depth: 0,
1096 child_number: 0, parent_fingerprint: [0; 4],
1098 poly_point: *poly_point,
1099 pk,
1100 chain_code,
1101 };
1102
1103 let address = address_fn(&pk);
1104
1105 let party = Party {
1106 parameters: data.parameters.clone(),
1107 party_index: data.party_index,
1108 session_id: data.session_id.clone(),
1109
1110 poly_point: *poly_point,
1111 pk,
1112
1113 zero_share,
1114
1115 mul_senders,
1116 mul_receivers,
1117
1118 derivation_data,
1119
1120 address,
1121 };
1122
1123 let public_key_package = PublicKeyPackage::new(pk, verifying_shares, data.parameters.clone());
1124
1125 Ok((party, public_key_package))
1126}
1127
1128#[cfg(test)]
1129mod tests {
1130
1131 use super::*;
1132 use elliptic_curve::CurveArithmetic;
1133 use k256::{AffinePoint, Scalar};
1134 use rand::RngExt;
1135
1136 type TestCurve = k256::Secp256k1;
1137
1138 fn no_address(_pk: &<TestCurve as CurveArithmetic>::AffinePoint) -> String {
1139 String::new()
1140 }
1141
1142 struct DkgPhase4Inputs {
1143 all_data: Vec<SessionData>,
1144 poly_points: Vec<Scalar>,
1145 proofs_commitments: Vec<ProofCommitment<TestCurve>>,
1146 zero_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitZeroSharePhase3to4>>,
1147 zero_received_2to4: Vec<Vec<TransmitInitZeroSharePhase2to4>>,
1148 zero_received_3to4: Vec<Vec<TransmitInitZeroSharePhase3to4>>,
1149 mul_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitMulPhase3to4<TestCurve>>>,
1150 mul_received_3to4: Vec<Vec<TransmitInitMulPhase3to4<TestCurve>>>,
1151 bip_broadcast_2to4: BTreeMap<PartyIndex, BroadcastDerivationPhase2to4>,
1152 bip_broadcast_3to4: BTreeMap<PartyIndex, BroadcastDerivationPhase3to4>,
1153 }
1154
1155 fn setup_two_party_dkg_phase4_inputs() -> DkgPhase4Inputs {
1156 let parameters = Parameters {
1157 threshold: 2,
1158 share_count: 2,
1159 };
1160 const SESSION_ID_LEN: usize = 32;
1161 let session_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1162
1163 let mut all_data: Vec<SessionData> = Vec::with_capacity(parameters.share_count as usize);
1165 for i in 0..parameters.share_count {
1166 all_data.push(SessionData {
1167 parameters: parameters.clone(),
1168 party_index: PartyIndex::new(i + 1).unwrap(),
1169 session_id: session_id.to_vec(),
1170 });
1171 }
1172
1173 let mut dkg_1: Vec<Vec<Scalar>> = Vec::with_capacity(parameters.share_count as usize);
1175 for i in 0..parameters.share_count {
1176 let out1 = phase1::<TestCurve>(&all_data[i as usize]);
1177 dkg_1.push(out1);
1178 }
1179
1180 let mut poly_fragments = vec![
1182 Vec::<Scalar>::with_capacity(parameters.share_count as usize);
1183 parameters.share_count as usize
1184 ];
1185 for row_i in dkg_1 {
1186 for j in 0..parameters.share_count {
1187 poly_fragments[j as usize].push(row_i[j as usize]);
1188 }
1189 }
1190
1191 let mut poly_points: Vec<Scalar> = Vec::with_capacity(parameters.share_count as usize);
1193 let mut proofs_commitments: Vec<ProofCommitment<TestCurve>> =
1194 Vec::with_capacity(parameters.share_count as usize);
1195 let mut zero_kept_2to3: Vec<BTreeMap<PartyIndex, KeepInitZeroSharePhase2to3>> =
1196 Vec::with_capacity(parameters.share_count as usize);
1197 let mut zero_transmit_2to4: Vec<Vec<TransmitInitZeroSharePhase2to4>> =
1198 Vec::with_capacity(parameters.share_count as usize);
1199 let mut bip_kept_2to3: Vec<UniqueKeepDerivationPhase2to3> =
1200 Vec::with_capacity(parameters.share_count as usize);
1201 let mut bip_broadcast_2to4: BTreeMap<PartyIndex, BroadcastDerivationPhase2to4> =
1202 BTreeMap::new();
1203 for i in 0..parameters.share_count {
1204 let (out1, out2, out3, out4, out5, out6) =
1205 phase2::<TestCurve>(&all_data[i as usize], &poly_fragments[i as usize]);
1206
1207 poly_points.push(out1);
1208 proofs_commitments.push(out2);
1209 zero_kept_2to3.push(out3);
1210 zero_transmit_2to4.push(out4);
1211 bip_kept_2to3.push(out5);
1212 bip_broadcast_2to4.insert(PartyIndex::new(i + 1).unwrap(), out6);
1213 }
1214
1215 let mut zero_received_2to4: Vec<Vec<TransmitInitZeroSharePhase2to4>> =
1217 Vec::with_capacity(parameters.share_count as usize);
1218 for i in 1..=parameters.share_count {
1219 let i_idx = PartyIndex::new(i).unwrap();
1220 let mut new_row: Vec<TransmitInitZeroSharePhase2to4> =
1221 Vec::with_capacity((parameters.share_count - 1) as usize);
1222 for party in &zero_transmit_2to4 {
1223 for message in party {
1224 if message.parties.receiver == i_idx {
1225 new_row.push(message.clone());
1226 }
1227 }
1228 }
1229 zero_received_2to4.push(new_row);
1230 }
1231
1232 let mut zero_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitZeroSharePhase3to4>> =
1234 Vec::with_capacity(parameters.share_count as usize);
1235 let mut zero_transmit_3to4: Vec<Vec<TransmitInitZeroSharePhase3to4>> =
1236 Vec::with_capacity(parameters.share_count as usize);
1237 let mut mul_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitMulPhase3to4<TestCurve>>> =
1238 Vec::with_capacity(parameters.share_count as usize);
1239 let mut mul_transmit_3to4: Vec<Vec<TransmitInitMulPhase3to4<TestCurve>>> =
1240 Vec::with_capacity(parameters.share_count as usize);
1241 let mut bip_broadcast_3to4: BTreeMap<PartyIndex, BroadcastDerivationPhase3to4> =
1242 BTreeMap::new();
1243 for i in 0..parameters.share_count {
1244 let (out1, out2, out3, out4, out5) = phase3::<TestCurve>(
1245 &all_data[i as usize],
1246 &zero_kept_2to3[i as usize],
1247 &bip_kept_2to3[i as usize],
1248 );
1249
1250 zero_kept_3to4.push(out1);
1251 zero_transmit_3to4.push(out2);
1252 mul_kept_3to4.push(out3);
1253 mul_transmit_3to4.push(out4);
1254 bip_broadcast_3to4.insert(PartyIndex::new(i + 1).unwrap(), out5);
1255 }
1256
1257 let mut zero_received_3to4: Vec<Vec<TransmitInitZeroSharePhase3to4>> =
1259 Vec::with_capacity(parameters.share_count as usize);
1260 let mut mul_received_3to4: Vec<Vec<TransmitInitMulPhase3to4<TestCurve>>> =
1261 Vec::with_capacity(parameters.share_count as usize);
1262 for i in 1..=parameters.share_count {
1263 let i_idx = PartyIndex::new(i).unwrap();
1264 let mut zero_row: Vec<TransmitInitZeroSharePhase3to4> =
1265 Vec::with_capacity((parameters.share_count - 1) as usize);
1266 for party in &zero_transmit_3to4 {
1267 for message in party {
1268 if message.parties.receiver == i_idx {
1269 zero_row.push(message.clone());
1270 }
1271 }
1272 }
1273 zero_received_3to4.push(zero_row);
1274
1275 let mut mul_row: Vec<TransmitInitMulPhase3to4<TestCurve>> =
1276 Vec::with_capacity((parameters.share_count - 1) as usize);
1277 for party in &mul_transmit_3to4 {
1278 for message in party {
1279 if message.parties.receiver == i_idx {
1280 mul_row.push(message.clone());
1281 }
1282 }
1283 }
1284 mul_received_3to4.push(mul_row);
1285 }
1286
1287 DkgPhase4Inputs {
1288 all_data,
1289 poly_points,
1290 proofs_commitments,
1291 zero_kept_3to4,
1292 zero_received_2to4,
1293 zero_received_3to4,
1294 mul_kept_3to4,
1295 mul_received_3to4,
1296 bip_broadcast_2to4,
1297 bip_broadcast_3to4,
1298 }
1299 }
1300
1301 #[test]
1303 fn test_dkg_phase4_rejects_missing_mul_init_messages() {
1304 let mut data = setup_two_party_dkg_phase4_inputs();
1305 data.mul_received_3to4[0].clear();
1306
1307 let result = phase4::<TestCurve>(
1308 &data.all_data[0],
1309 &data.poly_points[0],
1310 &data.proofs_commitments,
1311 &data.zero_kept_3to4[0],
1312 &data.zero_received_2to4[0],
1313 &data.zero_received_3to4[0],
1314 &data.mul_kept_3to4[0],
1315 &data.mul_received_3to4[0],
1316 &data.bip_broadcast_2to4,
1317 &data.bip_broadcast_3to4,
1318 no_address,
1319 );
1320 let abort = result.expect_err("missing multiplication-init message should be rejected");
1321 assert!(matches!(
1322 abort.reason,
1323 AbortReason::WrongMessageCount { .. }
1324 ));
1325 }
1326
1327 #[test]
1337 fn test_dkg_t2_n2() {
1338 let parameters = Parameters {
1339 threshold: 2,
1340 share_count: 2,
1341 };
1342 const SESSION_ID_LEN: usize = 32;
1343 let session_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1344
1345 let p1_phase1 = step2::<TestCurve>(¶meters, &step1::<TestCurve>(¶meters)); let p2_phase1 = step2::<TestCurve>(¶meters, &step1::<TestCurve>(¶meters)); assert_eq!(p1_phase1.len(), 2);
1350 assert_eq!(p2_phase1.len(), 2);
1351
1352 let p1_poly_fragments = vec![p1_phase1[0], p2_phase1[0]];
1354 let p2_poly_fragments = vec![p1_phase1[1], p2_phase1[1]];
1355
1356 let p1_phase2 =
1358 step3::<TestCurve>(PartyIndex::new(1).unwrap(), &session_id, &p1_poly_fragments);
1359 let p2_phase2 =
1360 step3::<TestCurve>(PartyIndex::new(2).unwrap(), &session_id, &p2_poly_fragments);
1361
1362 let (_, p1_proof_commitment) = p1_phase2;
1363 let (_, p2_proof_commitment) = p2_phase2;
1364
1365 let proofs_commitments = vec![p1_proof_commitment, p2_proof_commitment];
1368
1369 let p1_result = step5::<TestCurve>(
1371 ¶meters,
1372 PartyIndex::new(1).unwrap(),
1373 &session_id,
1374 &proofs_commitments,
1375 );
1376 let p2_result = step5::<TestCurve>(
1377 ¶meters,
1378 PartyIndex::new(2).unwrap(),
1379 &session_id,
1380 &proofs_commitments,
1381 );
1382
1383 assert!(p1_result.is_ok());
1384 assert!(p2_result.is_ok());
1385 }
1386
1387 #[test]
1391 fn test_dkg_random() {
1392 let threshold = rng::get_rng().random_range(2..=5); let offset = rng::get_rng().random_range(0..=5);
1394
1395 let parameters = Parameters {
1396 threshold,
1397 share_count: threshold + offset,
1398 }; const SESSION_ID_LEN: usize = 32;
1400 let session_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1401
1402 let mut phase1: Vec<Vec<Scalar>> = Vec::with_capacity(parameters.share_count as usize);
1405 for _ in 0..parameters.share_count {
1406 let party_phase1 = step2::<TestCurve>(¶meters, &step1::<TestCurve>(¶meters));
1407 assert_eq!(party_phase1.len(), parameters.share_count as usize);
1408 phase1.push(party_phase1);
1409 }
1410
1411 let mut poly_fragments = vec![
1414 Vec::<Scalar>::with_capacity(parameters.share_count as usize);
1415 parameters.share_count as usize
1416 ];
1417 for row_i in phase1 {
1418 for j in 0..parameters.share_count {
1419 poly_fragments[j as usize].push(row_i[j as usize]);
1420 }
1421 }
1422
1423 let mut proofs_commitments: Vec<ProofCommitment<TestCurve>> =
1425 Vec::with_capacity(parameters.share_count as usize);
1426 for i in 0..parameters.share_count {
1427 let party_i_phase2 = step3::<TestCurve>(
1428 PartyIndex::new(i + 1).unwrap(),
1429 &session_id,
1430 &poly_fragments[i as usize],
1431 );
1432 let (_, party_i_proof_commitment) = party_i_phase2;
1433 proofs_commitments.push(party_i_proof_commitment);
1434 }
1435
1436 for i in 0..parameters.share_count {
1438 let result = step5::<TestCurve>(
1439 ¶meters,
1440 PartyIndex::new(i + 1).unwrap(),
1441 &session_id,
1442 &proofs_commitments,
1443 );
1444 assert!(result.is_ok());
1445 }
1446 }
1447
1448 #[test]
1456 fn test1_dkg_t2_n2_fixed_polynomials() {
1457 let parameters = Parameters {
1458 threshold: 2,
1459 share_count: 2,
1460 };
1461 const SESSION_ID_LEN: usize = 32;
1462 let session_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1463
1464 let p1_poly_fragments = vec![Scalar::from(1u32), Scalar::from(3u32)];
1466 let p2_poly_fragments = vec![Scalar::from(2u32), Scalar::from(4u32)];
1467
1468 let p1_phase2 =
1474 step3::<TestCurve>(PartyIndex::new(1).unwrap(), &session_id, &p1_poly_fragments);
1475 let p2_phase2 =
1476 step3::<TestCurve>(PartyIndex::new(2).unwrap(), &session_id, &p2_poly_fragments);
1477
1478 let (_, p1_proof_commitment) = p1_phase2;
1479 let (_, p2_proof_commitment) = p2_phase2;
1480
1481 let proofs_commitments = vec![p1_proof_commitment, p2_proof_commitment];
1484
1485 let p1_result = step5::<TestCurve>(
1487 ¶meters,
1488 PartyIndex::new(1).unwrap(),
1489 &session_id,
1490 &proofs_commitments,
1491 );
1492 let p2_result = step5::<TestCurve>(
1493 ¶meters,
1494 PartyIndex::new(2).unwrap(),
1495 &session_id,
1496 &proofs_commitments,
1497 );
1498
1499 assert!(p1_result.is_ok());
1500 assert!(p2_result.is_ok());
1501
1502 let (p1_pk, _) = p1_result.unwrap();
1503 let (p2_pk, _) = p2_result.unwrap();
1504
1505 let expected_pk = (AffinePoint::GENERATOR * Scalar::from(2u32)).to_affine();
1507 assert_eq!(p1_pk, expected_pk);
1508 assert_eq!(p2_pk, expected_pk);
1509 }
1510
1511 #[test]
1513 fn test2_dkg_t2_n2_fixed_polynomials() {
1514 let parameters = Parameters {
1515 threshold: 2,
1516 share_count: 2,
1517 };
1518 const SESSION_ID_LEN: usize = 32;
1519 let session_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1520
1521 let p1_poly_fragments = vec![Scalar::from(12u32), Scalar::from(2u32)];
1523 let p2_poly_fragments = vec![Scalar::from(2u32), Scalar::from(3u32)];
1524
1525 let p1_phase2 =
1531 step3::<TestCurve>(PartyIndex::new(1).unwrap(), &session_id, &p1_poly_fragments);
1532 let p2_phase2 =
1533 step3::<TestCurve>(PartyIndex::new(2).unwrap(), &session_id, &p2_poly_fragments);
1534
1535 let (_, p1_proof_commitment) = p1_phase2;
1536 let (_, p2_proof_commitment) = p2_phase2;
1537
1538 let proofs_commitments = vec![p1_proof_commitment, p2_proof_commitment];
1541
1542 let p1_result = step5::<TestCurve>(
1544 ¶meters,
1545 PartyIndex::new(1).unwrap(),
1546 &session_id,
1547 &proofs_commitments,
1548 );
1549 let p2_result = step5::<TestCurve>(
1550 ¶meters,
1551 PartyIndex::new(2).unwrap(),
1552 &session_id,
1553 &proofs_commitments,
1554 );
1555
1556 assert!(p1_result.is_ok());
1557 assert!(p2_result.is_ok());
1558
1559 let (p1_pk, _) = p1_result.unwrap();
1560 let (p2_pk, _) = p2_result.unwrap();
1561
1562 let expected_pk = (AffinePoint::GENERATOR * Scalar::from(23u32)).to_affine();
1564 assert_eq!(p1_pk, expected_pk);
1565 assert_eq!(p2_pk, expected_pk);
1566 }
1567
1568 #[test]
1571 fn test_dkg_t3_n5_fixed_polynomials() {
1572 let parameters = Parameters {
1573 threshold: 3,
1574 share_count: 5,
1575 };
1576 const SESSION_ID_LEN: usize = 32;
1577 let session_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1578
1579 let poly_fragments = [
1581 vec![
1582 Scalar::from(5u32),
1583 Scalar::from(1u32),
1584 Scalar::from(5u32).negate(),
1585 Scalar::from(2u32).negate(),
1586 Scalar::from(3u32).negate(),
1587 ],
1588 vec![
1589 Scalar::from(9u32),
1590 Scalar::from(3u32),
1591 Scalar::from(4u32).negate(),
1592 Scalar::from(5u32).negate(),
1593 Scalar::from(7u32).negate(),
1594 ],
1595 vec![
1596 Scalar::from(15u32),
1597 Scalar::from(7u32),
1598 Scalar::from(1u32).negate(),
1599 Scalar::from(10u32).negate(),
1600 Scalar::from(13u32).negate(),
1601 ],
1602 vec![
1603 Scalar::from(23u32),
1604 Scalar::from(13u32),
1605 Scalar::from(4u32),
1606 Scalar::from(17u32).negate(),
1607 Scalar::from(21u32).negate(),
1608 ],
1609 vec![
1610 Scalar::from(33u32),
1611 Scalar::from(21u32),
1612 Scalar::from(11u32),
1613 Scalar::from(26u32).negate(),
1614 Scalar::from(31u32).negate(),
1615 ],
1616 ];
1617
1618 let mut proofs_commitments: Vec<ProofCommitment<TestCurve>> =
1626 Vec::with_capacity(parameters.share_count as usize);
1627 for i in 0..parameters.share_count {
1628 let party_i_phase2 = step3::<TestCurve>(
1629 PartyIndex::new(i + 1).unwrap(),
1630 &session_id,
1631 &poly_fragments[i as usize],
1632 );
1633 let (_, party_i_proof_commitment) = party_i_phase2;
1634 proofs_commitments.push(party_i_proof_commitment);
1635 }
1636
1637 let mut public_keys: Vec<AffinePoint> = Vec::with_capacity(parameters.share_count as usize);
1639 for i in 0..parameters.share_count {
1640 let (pk, _) = step5::<TestCurve>(
1641 ¶meters,
1642 PartyIndex::new(i + 1).unwrap(),
1643 &session_id,
1644 &proofs_commitments,
1645 )
1646 .unwrap_or_else(|abort| {
1647 panic!("Party {} aborted: {:?}", abort.index, abort.description());
1648 });
1649 public_keys.push(pk);
1650 }
1651
1652 let expected_pk = (AffinePoint::GENERATOR * Scalar::from(2u32).negate()).to_affine();
1654 for pk in public_keys {
1655 assert_eq!(pk, expected_pk);
1656 }
1657 }
1658
1659 #[test]
1674 fn test_dkg_initialization() {
1675 let threshold = rng::get_rng().random_range(2..=5); let offset = rng::get_rng().random_range(0..=5);
1677
1678 let parameters = Parameters {
1679 threshold,
1680 share_count: threshold + offset,
1681 }; const SESSION_ID_LEN: usize = 32;
1683 let session_id = rng::get_rng().random::<[u8; SESSION_ID_LEN]>();
1684
1685 let mut all_data: Vec<SessionData> = Vec::with_capacity(parameters.share_count as usize);
1687 for i in 0..parameters.share_count {
1688 all_data.push(SessionData {
1689 parameters: parameters.clone(),
1690 party_index: PartyIndex::new(i + 1).unwrap(),
1691 session_id: session_id.to_vec(),
1692 });
1693 }
1694
1695 let mut dkg_1: Vec<Vec<Scalar>> = Vec::with_capacity(parameters.share_count as usize);
1697 for i in 0..parameters.share_count {
1698 let out1 = phase1::<TestCurve>(&all_data[i as usize]);
1699
1700 dkg_1.push(out1);
1701 }
1702
1703 let mut poly_fragments = vec![
1706 Vec::<Scalar>::with_capacity(parameters.share_count as usize);
1707 parameters.share_count as usize
1708 ];
1709 for row_i in dkg_1 {
1710 for j in 0..parameters.share_count {
1711 poly_fragments[j as usize].push(row_i[j as usize]);
1712 }
1713 }
1714
1715 let mut poly_points: Vec<Scalar> = Vec::with_capacity(parameters.share_count as usize);
1717 let mut proofs_commitments: Vec<ProofCommitment<TestCurve>> =
1718 Vec::with_capacity(parameters.share_count as usize);
1719 let mut zero_kept_2to3: Vec<BTreeMap<PartyIndex, KeepInitZeroSharePhase2to3>> =
1720 Vec::with_capacity(parameters.share_count as usize);
1721 let mut zero_transmit_2to4: Vec<Vec<TransmitInitZeroSharePhase2to4>> =
1722 Vec::with_capacity(parameters.share_count as usize);
1723 let mut bip_kept_2to3: Vec<UniqueKeepDerivationPhase2to3> =
1724 Vec::with_capacity(parameters.share_count as usize);
1725 let mut bip_broadcast_2to4: BTreeMap<PartyIndex, BroadcastDerivationPhase2to4> =
1726 BTreeMap::new();
1727 for i in 0..parameters.share_count {
1728 let (out1, out2, out3, out4, out5, out6) =
1729 phase2::<TestCurve>(&all_data[i as usize], &poly_fragments[i as usize]);
1730
1731 poly_points.push(out1);
1732 proofs_commitments.push(out2);
1733 zero_kept_2to3.push(out3);
1734 zero_transmit_2to4.push(out4);
1735 bip_kept_2to3.push(out5);
1736 bip_broadcast_2to4.insert(PartyIndex::new(i + 1).unwrap(), out6); }
1738
1739 let mut zero_received_2to4: Vec<Vec<TransmitInitZeroSharePhase2to4>> =
1741 Vec::with_capacity(parameters.share_count as usize);
1742 for i in 1..=parameters.share_count {
1743 let i_idx = PartyIndex::new(i).unwrap();
1744 let mut new_row: Vec<TransmitInitZeroSharePhase2to4> =
1748 Vec::with_capacity((parameters.share_count - 1) as usize);
1749 for party in &zero_transmit_2to4 {
1750 for message in party {
1751 if message.parties.receiver == i_idx {
1753 new_row.push(message.clone());
1754 }
1755 }
1756 }
1757 zero_received_2to4.push(new_row);
1758 }
1759
1760 let mut zero_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitZeroSharePhase3to4>> =
1765 Vec::with_capacity(parameters.share_count as usize);
1766 let mut zero_transmit_3to4: Vec<Vec<TransmitInitZeroSharePhase3to4>> =
1767 Vec::with_capacity(parameters.share_count as usize);
1768 let mut mul_kept_3to4: Vec<BTreeMap<PartyIndex, KeepInitMulPhase3to4<TestCurve>>> =
1769 Vec::with_capacity(parameters.share_count as usize);
1770 let mut mul_transmit_3to4: Vec<Vec<TransmitInitMulPhase3to4<TestCurve>>> =
1771 Vec::with_capacity(parameters.share_count as usize);
1772 let mut bip_broadcast_3to4: BTreeMap<PartyIndex, BroadcastDerivationPhase3to4> =
1773 BTreeMap::new();
1774 for i in 0..parameters.share_count {
1775 let (out1, out2, out3, out4, out5) = phase3::<TestCurve>(
1776 &all_data[i as usize],
1777 &zero_kept_2to3[i as usize],
1778 &bip_kept_2to3[i as usize],
1779 );
1780
1781 zero_kept_3to4.push(out1);
1782 zero_transmit_3to4.push(out2);
1783 mul_kept_3to4.push(out3);
1784 mul_transmit_3to4.push(out4);
1785 bip_broadcast_3to4.insert(PartyIndex::new(i + 1).unwrap(), out5); }
1787
1788 let mut zero_received_3to4: Vec<Vec<TransmitInitZeroSharePhase3to4>> =
1790 Vec::with_capacity(parameters.share_count as usize);
1791 let mut mul_received_3to4: Vec<Vec<TransmitInitMulPhase3to4<TestCurve>>> =
1792 Vec::with_capacity(parameters.share_count as usize);
1793 for i in 1..=parameters.share_count {
1794 let i_idx = PartyIndex::new(i).unwrap();
1795 let mut new_row: Vec<TransmitInitZeroSharePhase3to4> =
1799 Vec::with_capacity((parameters.share_count - 1) as usize);
1800 for party in &zero_transmit_3to4 {
1801 for message in party {
1802 if message.parties.receiver == i_idx {
1804 new_row.push(message.clone());
1805 }
1806 }
1807 }
1808 zero_received_3to4.push(new_row);
1809
1810 let mut new_row: Vec<TransmitInitMulPhase3to4<TestCurve>> =
1811 Vec::with_capacity((parameters.share_count - 1) as usize);
1812 for party in &mul_transmit_3to4 {
1813 for message in party {
1814 if message.parties.receiver == i_idx {
1816 new_row.push(message.clone());
1817 }
1818 }
1819 }
1820 mul_received_3to4.push(new_row);
1821 }
1822
1823 let mut parties: Vec<Party<TestCurve>> =
1828 Vec::with_capacity((parameters.share_count) as usize);
1829 let mut pkgs: Vec<PublicKeyPackage<TestCurve>> =
1830 Vec::with_capacity(parameters.share_count as usize);
1831 for i in 0..parameters.share_count {
1832 let result = phase4::<TestCurve>(
1833 &all_data[i as usize],
1834 &poly_points[i as usize],
1835 &proofs_commitments,
1836 &zero_kept_3to4[i as usize],
1837 &zero_received_2to4[i as usize],
1838 &zero_received_3to4[i as usize],
1839 &mul_kept_3to4[i as usize],
1840 &mul_received_3to4[i as usize],
1841 &bip_broadcast_2to4,
1842 &bip_broadcast_3to4,
1843 no_address,
1844 );
1845 match result {
1846 Err(abort) => {
1847 panic!("Party {} aborted: {:?}", abort.index, abort.description());
1848 }
1849 Ok((party, pkg)) => {
1850 parties.push(party);
1851 pkgs.push(pkg);
1852 }
1853 }
1854 }
1855
1856 let expected_pk = parties[0].pk;
1858 let expected_chain_code = parties[0].derivation_data.chain_code;
1859 for party in &parties {
1860 assert_eq!(expected_pk, party.pk);
1861 assert_eq!(expected_chain_code, party.derivation_data.chain_code);
1862 }
1863
1864 let pkg0 = &pkgs[0];
1866 assert_eq!(*pkg0.verifying_key(), expected_pk);
1867 assert_eq!(pkg0.threshold(), parameters.threshold);
1868 assert_eq!(pkg0.share_count(), parameters.share_count);
1869 for pkg in &pkgs[1..] {
1870 assert_eq!(pkg.verifying_key(), pkg0.verifying_key());
1871 for i in 1..=parameters.share_count {
1872 let idx = PartyIndex::new(i).unwrap();
1873 assert_eq!(pkg.verifying_share(idx), pkg0.verifying_share(idx));
1874 }
1875 }
1876
1877 for party in &parties {
1879 let expected_share = (AffinePoint::GENERATOR * party.poly_point).to_affine();
1880 assert!(pkg0.verify_share(party.party_index, &expected_share));
1881 }
1882
1883 assert_eq!(parties[0].address, String::new());
1885 }
1886}