1use digest::Digest;
4use futures::SinkExt;
5use generic_ec::{coords::AlwaysHasAffineX, Curve, NonZero, Point, Scalar, SecretScalar};
6use generic_ec_zkp::polynomial::lagrange_coefficient_at_zero;
7use paillier_zk::{backend::Integer, fast_paillier};
8use paillier_zk::{
9 dlog_with_el_gamal_commitment as pi_elog, paillier_affine_operation_in_range as pi_aff,
10 paillier_encryption_in_range_with_el_gamal as pi_enc_elg, IntegerExt,
11};
12use rand_core::{CryptoRng, RngCore};
13use round_based::{
14 rounds_router::{simple_store::RoundInput, RoundsRouter},
15 runtime::AsyncRuntime,
16 Delivery, Mpc, MpcParty, Outgoing, PartyIndex,
17};
18use serde::{Deserialize, Serialize};
19use thiserror::Error;
20
21use crate::errors::IoError;
22use crate::key_share::{InvalidKeyShare, KeyShare, PedersenParams, VssSetup};
23use crate::progress::Tracer;
24use crate::{security_level::SecurityLevel, utils, ExecutionId};
25
26use self::msg::*;
27
28#[derive(Debug, Clone, Copy)]
44pub struct DataToSign<E: Curve>(Scalar<E>);
45
46impl<E: Curve> DataToSign<E> {
47 pub fn digest<D: Digest>(data: &[u8]) -> Self {
49 DataToSign(Scalar::from_be_bytes_mod_order(D::digest(data)))
50 }
51
52 pub fn from_digest<D: Digest>(hash: D) -> Self {
54 DataToSign(Scalar::from_be_bytes_mod_order(hash.finalize()))
55 }
56
57 pub fn to_scalar(self) -> Scalar<E> {
59 self.0
60 }
61}
62
63#[derive(Clone, Copy, Debug)]
120pub struct PrehashedDataToSign<E: Curve>(Scalar<E>);
121
122impl<E: Curve> PrehashedDataToSign<E> {
123 pub fn from_scalar(scalar: Scalar<E>) -> Self {
127 Self(scalar)
128 }
129
130 pub fn to_scalar(self) -> Scalar<E> {
132 self.0
133 }
134
135 #[cfg(feature = "insecure-assume-preimage-known")]
147 pub fn insecure_assume_preimage_known(self) -> DataToSign<E> {
148 DataToSign(self.0)
149 }
150}
151
152mod internal {
153 pub trait Sealed {}
154}
155
156pub trait AnyDataToSign<E: Curve>: Send + Sync + internal::Sealed {
161 fn to_scalar(&self) -> Scalar<E>;
163}
164impl<E: Curve> internal::Sealed for DataToSign<E> {}
165impl<E: Curve> internal::Sealed for PrehashedDataToSign<E> {}
166
167impl<E: Curve> AnyDataToSign<E> for DataToSign<E> {
168 fn to_scalar(&self) -> Scalar<E> {
169 self.0
170 }
171}
172impl<E: Curve> AnyDataToSign<E> for PrehashedDataToSign<E> {
173 fn to_scalar(&self) -> Scalar<E> {
174 self.0
175 }
176}
177
178#[derive(Clone, Serialize, Deserialize)]
182#[serde(bound = "")]
183pub struct Presignature<E: Curve> {
184 pub Gamma: NonZero<Point<E>>,
186 pub tilde_k: SecretScalar<E>,
188 pub tilde_chi: SecretScalar<E>,
190}
191
192#[derive(Clone, Debug, PartialEq, Eq)]
196pub struct PresignaturePublicData<E: Curve> {
197 pub Gamma: NonZero<Point<E>>,
199 pub commitments: Vec<PresignatureCommitment<E>>,
201}
202
203#[derive(Clone, Debug, PartialEq, Eq)]
205pub struct PresignatureCommitment<E: Curve> {
206 pub tilde_Delta: Point<E>,
208 pub tilde_S: Point<E>,
210}
211
212#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
218#[serde(bound = "")]
219pub struct PartialSignature<E: Curve> {
220 pub sigma: Scalar<E>,
222}
223
224#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug)]
226#[serde(bound = "")]
227pub struct Signature<E: Curve> {
228 pub r: NonZero<Scalar<E>>,
230 pub s: NonZero<Scalar<E>>,
232}
233
234macro_rules! prefixed {
235 ($name:tt) => {
236 concat!("dfns.cggmp24.signing.", $name)
237 };
238}
239
240#[doc = include_str!("../docs/mpc_message.md")]
241pub mod msg {
242 use digest::Digest;
243 use generic_ec::Curve;
244 use generic_ec::{Point, Scalar};
245
246 use paillier_zk::fast_paillier;
247 use paillier_zk::{
248 dlog_with_el_gamal_commitment as pi_elog, paillier_affine_operation_in_range as pi_aff,
249 paillier_encryption_in_range_with_el_gamal as pi_enc_elg,
250 };
251 use round_based::ProtocolMessage;
252 use serde::{Deserialize, Serialize};
253
254 use crate::utils;
255
256 use super::PartialSignature;
257
258 #[derive(Clone, ProtocolMessage, Serialize, Deserialize)]
262 #[serde(bound = "")]
263 #[allow(clippy::large_enum_variant)]
264 pub enum Msg<E: Curve, D: Digest> {
265 Round1a(MsgRound1a<E>),
267 Round1b(MsgRound1b<E>),
269 Round2(MsgRound2<E>),
271 Round3(MsgRound3<E>),
273 Round4(MsgRound4<E>),
275 ReliabilityCheck(MsgReliabilityCheck<D>),
277 }
278
279 #[derive(Clone, Serialize, Deserialize, udigest::Digestable)]
281 #[serde(bound = "")]
282 #[udigest(tag = prefixed!("round1"))]
283 #[udigest(bound = "")]
284 pub struct MsgRound1a<E: Curve> {
285 #[udigest(as = utils::encoding::Integer)]
287 pub K: fast_paillier::Ciphertext,
288 #[udigest(as = utils::encoding::Integer)]
290 pub G: fast_paillier::Ciphertext,
291 pub Y: Point<E>,
293 pub A1: Point<E>,
295 pub A2: Point<E>,
297 pub B1: Point<E>,
299 pub B2: Point<E>,
301 }
302
303 #[derive(Clone, Serialize, Deserialize)]
305 #[serde(bound = "")]
306 pub struct MsgRound1b<E: Curve> {
307 pub psi0: pi_enc_elg::NiProof<E>,
309 pub psi1: pi_enc_elg::NiProof<E>,
311 }
312
313 #[derive(Clone, Serialize, Deserialize)]
315 #[serde(bound = "")]
316 pub struct MsgRound2<E: Curve> {
317 pub Gamma: Point<E>,
319 pub D: fast_paillier::Ciphertext,
321 pub F: fast_paillier::Ciphertext,
323 pub hat_D: fast_paillier::Ciphertext,
325 pub hat_F: fast_paillier::Ciphertext,
327 pub tilde_psi: pi_elog::NiProof<E>,
329 pub psi_j: pi_aff::NiProof<E>,
331 pub hat_psi_j: pi_aff::NiProof<E>,
333 }
334
335 #[derive(Clone, Serialize, Deserialize)]
337 #[serde(bound = "")]
338 pub struct MsgRound3<E: Curve> {
339 pub delta: Scalar<E>,
341 pub S: Point<E>,
343 pub Delta: Point<E>,
345 pub psi_prime: pi_elog::NiProof<E>,
347 }
348
349 #[derive(Clone, Serialize, Deserialize)]
351 #[serde(bound = "")]
352 pub struct MsgRound4<E: Curve> {
353 pub partial_sig: PartialSignature<E>,
355 }
356
357 #[derive(Clone, Serialize, Deserialize)]
359 #[serde(bound = "")]
360 pub struct MsgReliabilityCheck<D: Digest>(pub digest::Output<D>);
361}
362
363mod unambiguous {
364 use crate::ExecutionId;
365
366 #[derive(udigest::Digestable)]
367 #[udigest(tag = prefixed!("proof_enc"))]
368 pub struct ProofEnc<'a> {
369 pub sid: ExecutionId<'a>,
370 pub prover: u16,
371 pub num: u8,
373 }
374
375 #[derive(udigest::Digestable)]
376 #[udigest(tag = prefixed!("proof_psi"))]
377 pub struct ProofPsi<'a> {
378 pub sid: ExecutionId<'a>,
379 pub prover: u16,
380 pub hat: bool,
381 }
382
383 #[derive(udigest::Digestable)]
384 #[udigest(tag = prefixed!("proof_elog"))]
385 pub struct ProofElog<'a> {
386 pub sid: ExecutionId<'a>,
387 pub prover: u16,
388 pub prime: bool,
389 }
390
391 #[derive(udigest::Digestable)]
392 #[udigest(tag = prefixed!("echo_round"))]
393 #[udigest(bound = "")]
394 pub struct Echo<'a, E: generic_ec::Curve> {
395 pub sid: ExecutionId<'a>,
396 pub ciphertexts: &'a super::MsgRound1a<E>,
397 }
398}
399
400pub struct SigningBuilder<
402 'r,
403 E,
404 L = crate::default_choice::SecurityLevel,
405 D = crate::default_choice::Digest,
406> where
407 E: Curve,
408 L: SecurityLevel,
409 D: Digest,
410{
411 i: PartyIndex,
412 parties_indexes_at_keygen: &'r [PartyIndex],
413 key_share: &'r KeyShare<E, L>,
414 execution_id: ExecutionId<'r>,
415 tracer: Option<&'r mut dyn Tracer>,
416 enforce_reliable_broadcast: bool,
417 _digest: std::marker::PhantomData<D>,
418
419 #[cfg(feature = "hd-wallet")]
420 additive_shift: Option<Scalar<E>>,
421}
422
423impl<'r, E, L, D> SigningBuilder<'r, E, L, D>
424where
425 E: Curve,
426 NonZero<Point<E>>: AlwaysHasAffineX<E>,
427 L: SecurityLevel,
428 D: Digest + Clone + 'static,
429{
430 pub fn new(
432 eid: ExecutionId<'r>,
433 i: PartyIndex,
434 parties_indexes_at_keygen: &'r [PartyIndex],
435 secret_key_share: &'r KeyShare<E, L>,
436 ) -> Self {
437 Self {
438 i,
439 parties_indexes_at_keygen,
440 key_share: secret_key_share,
441 execution_id: eid,
442 tracer: None,
443 enforce_reliable_broadcast: true,
444 _digest: std::marker::PhantomData,
445 #[cfg(feature = "hd-wallet")]
446 additive_shift: None,
447 }
448 }
449
450 pub fn set_digest<D2>(self) -> SigningBuilder<'r, E, L, D2>
452 where
453 D2: Digest,
454 {
455 SigningBuilder {
456 i: self.i,
457 parties_indexes_at_keygen: self.parties_indexes_at_keygen,
458 key_share: self.key_share,
459 tracer: self.tracer,
460 enforce_reliable_broadcast: self.enforce_reliable_broadcast,
461 execution_id: self.execution_id,
462 _digest: std::marker::PhantomData,
463 #[cfg(feature = "hd-wallet")]
464 additive_shift: self.additive_shift,
465 }
466 }
467
468 pub fn set_progress_tracer(mut self, tracer: &'r mut dyn Tracer) -> Self {
470 self.tracer = Some(tracer);
471 self
472 }
473
474 #[doc = include_str!("../docs/enforce_reliable_broadcast.md")]
475 pub fn enforce_reliable_broadcast(self, v: bool) -> Self {
476 Self {
477 enforce_reliable_broadcast: v,
478 ..self
479 }
480 }
481
482 #[cfg(all(feature = "hd-wallet", feature = "hd-slip10"))]
501 pub fn set_derivation_path<Index>(
502 self,
503 path: impl IntoIterator<Item = Index>,
504 ) -> Result<
505 Self,
506 crate::key_share::HdError<<Index as TryInto<hd_wallet::NonHardenedIndex>>::Error>,
507 >
508 where
509 hd_wallet::Slip10: hd_wallet::HdWallet<E>,
510 hd_wallet::NonHardenedIndex: TryFrom<Index>,
511 {
512 self.set_derivation_path_with_algo::<hd_wallet::Slip10, _>(path)
513 }
514
515 #[cfg(feature = "hd-wallet")]
517 pub fn set_derivation_path_with_algo<Hd: hd_wallet::HdWallet<E>, Index>(
518 mut self,
519 path: impl IntoIterator<Item = Index>,
520 ) -> Result<
521 Self,
522 crate::key_share::HdError<<Index as TryInto<hd_wallet::NonHardenedIndex>>::Error>,
523 >
524 where
525 hd_wallet::NonHardenedIndex: TryFrom<Index>,
526 {
527 use crate::key_share::HdError;
528 let public_key = self
529 .key_share
530 .extended_public_key()
531 .ok_or(HdError::DisabledHd)?;
532 self.additive_shift = Some(
533 derive_additive_shift::<E, Hd, _>(public_key, path).map_err(HdError::InvalidPath)?,
534 );
535 Ok(self)
536 }
537
538 pub async fn generate_presignature<R, M>(
540 self,
541 rng: &mut R,
542 party: M,
543 ) -> Result<(Presignature<E>, PresignaturePublicData<E>), SigningError>
544 where
545 R: RngCore + CryptoRng,
546 M: Mpc<ProtocolMessage = Msg<E, D>>,
547 {
548 match signing_t_out_of_n(
549 self.tracer,
550 rng,
551 party,
552 self.execution_id,
553 self.i,
554 self.key_share,
555 self.parties_indexes_at_keygen,
556 None,
557 self.enforce_reliable_broadcast,
558 #[cfg(feature = "hd-wallet")]
559 self.additive_shift,
560 #[cfg(not(feature = "hd-wallet"))]
561 None,
562 )
563 .await?
564 {
565 ProtocolOutput::Presignature(presig) => Ok(presig),
566 ProtocolOutput::Signature(_) => Err(Bug::UnexpectedProtocolOutput.into()),
567 }
568 }
569
570 #[cfg(feature = "state-machine")]
574 pub fn generate_presignature_sync<R>(
575 self,
576 rng: &'r mut R,
577 ) -> impl round_based::state_machine::StateMachine<
578 Output = Result<(Presignature<E>, PresignaturePublicData<E>), SigningError>,
579 Msg = Msg<E, D>,
580 > + 'r
581 where
582 R: RngCore + CryptoRng,
583 {
584 round_based::state_machine::wrap_protocol(|party| self.generate_presignature(rng, party))
585 }
586
587 pub async fn sign<R, M>(
593 self,
594 rng: &mut R,
595 party: M,
596 message_to_sign: &dyn AnyDataToSign<E>,
597 ) -> Result<Signature<E>, SigningError>
598 where
599 R: RngCore + CryptoRng,
600 M: Mpc<ProtocolMessage = Msg<E, D>>,
601 {
602 match signing_t_out_of_n(
603 self.tracer,
604 rng,
605 party,
606 self.execution_id,
607 self.i,
608 self.key_share,
609 self.parties_indexes_at_keygen,
610 Some(message_to_sign.to_scalar()),
611 self.enforce_reliable_broadcast,
612 #[cfg(feature = "hd-wallet")]
613 self.additive_shift,
614 #[cfg(not(feature = "hd-wallet"))]
615 None,
616 )
617 .await?
618 {
619 ProtocolOutput::Signature(sig) => Ok(sig),
620 ProtocolOutput::Presignature(_) => Err(Bug::UnexpectedProtocolOutput.into()),
621 }
622 }
623
624 #[cfg(feature = "state-machine")]
632 pub fn sign_sync<R>(
633 self,
634 rng: &'r mut R,
635 message_to_sign: &'r dyn AnyDataToSign<E>,
636 ) -> impl round_based::state_machine::StateMachine<
637 Output = Result<Signature<E>, SigningError>,
638 Msg = Msg<E, D>,
639 > + 'r
640 where
641 R: RngCore + CryptoRng,
642 {
643 round_based::state_machine::wrap_protocol(move |party| {
644 self.sign(rng, party, message_to_sign)
645 })
646 }
647}
648
649async fn signing_t_out_of_n<M, E, L, D, R>(
656 mut tracer: Option<&mut dyn Tracer>,
657 rng: &mut R,
658 party: M,
659 sid: ExecutionId<'_>,
660 i: PartyIndex,
661 key_share: &KeyShare<E, L>,
662 S: &[PartyIndex],
663 message_to_sign: Option<Scalar<E>>,
664 enforce_reliable_broadcast: bool,
665 additive_shift: Option<Scalar<E>>,
666) -> Result<ProtocolOutput<E>, SigningError>
667where
668 M: Mpc<ProtocolMessage = Msg<E, D>>,
669 E: Curve,
670 L: SecurityLevel,
671 D: Digest + Clone + 'static,
672 R: RngCore + CryptoRng,
673 NonZero<Point<E>>: AlwaysHasAffineX<E>,
674{
675 tracer.protocol_begins();
676 tracer.stage("Map t-out-of-n protocol to t-out-of-t");
677
678 let n: u16 = key_share
680 .aux
681 .pedersen_params
682 .len()
683 .try_into()
684 .map_err(|_| Bug::PartiesNumberExceedsU16)?;
685 let t = key_share
686 .core
687 .vss_setup
688 .as_ref()
689 .map(|s| s.min_signers)
690 .unwrap_or(n);
691 if S.len() != usize::from(t) {
692 return Err(InvalidArgs::MismatchedAmountOfParties.into());
693 }
694 if !(i < t) {
695 return Err(InvalidArgs::SignerIndexOutOfBounds.into());
696 }
697 if S.iter().any(|&S_j| S_j >= n) {
698 return Err(InvalidArgs::InvalidS.into());
699 }
700
701 let (mut x_i, mut X) = if let Some(VssSetup { I, .. }) = &key_share.core.vss_setup {
703 let I = utils::subset(S, I).ok_or(Bug::Subset)?;
705 let X = utils::subset(S, &key_share.core.public_shares).ok_or(Bug::Subset)?;
706
707 let lambda_i = lagrange_coefficient_at_zero(usize::from(i), &I).ok_or(Bug::LagrangeCoef)?;
708 let x_i = (lambda_i * &key_share.core.x).into_secret();
709
710 let lambda = (0..t).map(|j| lagrange_coefficient_at_zero(usize::from(j), &I));
711 let X = lambda
712 .zip(&X)
713 .map(|(lambda_j, X_j)| Some(lambda_j? * X_j))
714 .collect::<Option<Vec<_>>>()
715 .ok_or(Bug::LagrangeCoef)?;
716
717 (x_i, X)
718 } else {
719 let X = utils::subset(S, &key_share.core.public_shares).ok_or(Bug::Subset)?;
721 (key_share.core.x.clone(), X)
722 };
723 debug_assert_eq!(key_share.core.shared_public_key, X.iter().sum::<Point<E>>());
724
725 let shift = additive_shift.unwrap_or(Scalar::zero());
727 let Shift = Point::generator() * shift;
728
729 X[0] = NonZero::from_point(X[0] + Shift).ok_or(Bug::DerivedChildKeyZero)?;
730 if i == 0 {
731 x_i = NonZero::from_scalar(x_i + shift)
732 .ok_or(Bug::DerivedChildShareZero)?
733 .into_secret();
734 }
735 debug_assert_eq!(
736 key_share.core.shared_public_key + Shift,
737 X.iter().sum::<Point<E>>()
738 );
739
740 let (p_i, q_i) = (&key_share.aux.p, &key_share.aux.q);
742 let N = utils::subset(S, &key_share.aux.N)
743 .ok_or(Bug::Subset)?
744 .into_iter()
745 .map(fast_paillier::EncryptionKey::from_n)
746 .collect::<Vec<_>>();
747 let R = utils::subset(S, &key_share.aux.pedersen_params).ok_or(Bug::Subset)?;
748
749 signing_n_out_of_n::<_, _, L, _, _>(
751 tracer,
752 rng,
753 party,
754 sid,
755 i,
756 t,
757 &x_i,
758 &X,
759 key_share.core.shared_public_key + Shift,
760 p_i,
761 q_i,
762 &N,
763 &R,
764 message_to_sign,
765 enforce_reliable_broadcast,
766 )
767 .await
768}
769
770async fn signing_n_out_of_n<M, E, L, D, R>(
775 mut tracer: Option<&mut dyn Tracer>,
776 rng: &mut R,
777 party: M,
778 sid: ExecutionId<'_>,
779 i: PartyIndex,
780 n: u16,
781 x_i: &NonZero<SecretScalar<E>>,
782 X: &[NonZero<Point<E>>],
783 pk: Point<E>,
784 p_i: &Integer,
785 q_i: &Integer,
786 N: &[fast_paillier::EncryptionKey],
787 R: &[PedersenParams],
788 message_to_sign: Option<Scalar<E>>,
789 enforce_reliable_broadcast: bool,
790) -> Result<ProtocolOutput<E>, SigningError>
791where
792 M: Mpc<ProtocolMessage = Msg<E, D>>,
793 E: Curve,
794 L: SecurityLevel,
795 D: Digest + Clone + 'static,
796 R: RngCore + CryptoRng,
797 NonZero<Point<E>>: AlwaysHasAffineX<E>,
798{
799 let MpcParty {
800 delivery, runtime, ..
801 } = party.into_party();
802 let (incomings, mut outgoings) = delivery.split();
803
804 tracer.stage("Retrieve auxiliary data");
805 let R_i = &R[usize::from(i)];
806
807 let dec_i: fast_paillier::DecryptionKey =
808 fast_paillier::DecryptionKey::from_primes(p_i.clone(), q_i.clone())
809 .map_err(|_| Bug::InvalidOwnPaillierKey)?;
810
811 tracer.stage("Precompute execution id and security params");
812 let security_params = crate::utils::SecurityParams::new::<L>();
813
814 tracer.stage("Setup networking");
815 let mut rounds = RoundsRouter::<Msg<E, D>>::builder();
816 let round1a = rounds.add_round(RoundInput::<MsgRound1a<E>>::broadcast(i, n));
817 let round1b = rounds.add_round(RoundInput::<MsgRound1b<E>>::p2p(i, n));
818 let round1a_sync = rounds.add_round(RoundInput::<MsgReliabilityCheck<D>>::broadcast(i, n));
819 let round2 = rounds.add_round(RoundInput::<MsgRound2<E>>::p2p(i, n));
820 let round3 = rounds.add_round(RoundInput::<MsgRound3<E>>::broadcast(i, n));
821 let round4 = rounds.add_round(RoundInput::<MsgRound4<E>>::broadcast(i, n));
822 let mut rounds = rounds.listen(incomings);
823
824 tracer.round_begins();
826
827 tracer.stage("Generate local ephemeral secrets (k_i, y_i, p_i, v_i)");
828 let gamma_i = SecretScalar::<E>::random(rng);
829 let k_i = SecretScalar::<E>::random(rng);
830
831 let v_i = Integer::sample_in_mult_group_of(rng, dec_i.n());
832 let rho_i = Integer::sample_in_mult_group_of(rng, dec_i.n());
833
834 tracer.stage("Encrypt G_i and K_i");
835 let G_i = dec_i
836 .encrypt_with(&utils::scalar_to_pm_bignumber(&gamma_i), &v_i)
837 .map_err(|_| Bug::PaillierEnc(BugSource::G_i))?;
838 let K_i = dec_i
839 .encrypt_with(&utils::scalar_to_pm_bignumber(&k_i), &rho_i)
840 .map_err(|_| Bug::PaillierEnc(BugSource::K_i))?;
841
842 tracer.stage("Generate a_i, b_i, A_i1, A_i2, B_i1, B_i2");
843 let Y_i = {
844 let y_i = SecretScalar::<E>::random(rng);
845 Point::generator() * y_i
846 };
847 let a_i = SecretScalar::<E>::random(rng);
848 let b_i = SecretScalar::<E>::random(rng);
849
850 let A_i1 = &a_i * Point::generator();
851 let A_i2 = &a_i * Y_i + &k_i * Point::generator();
852
853 let B_i1 = &b_i * Point::generator();
854 let B_i2 = &b_i * Y_i + &gamma_i * Point::generator();
855
856 tracer.send_msg();
857 outgoings
858 .feed(Outgoing::broadcast(Msg::Round1a(MsgRound1a {
859 K: K_i.clone(),
860 G: G_i.clone(),
861 Y: Y_i,
862 A1: A_i1,
863 A2: A_i2,
864 B1: B_i1,
865 B2: B_i2,
866 })))
867 .await
868 .map_err(IoError::send_message)?;
869 tracer.msg_sent();
870
871 for j in utils::iter_peers(i, n) {
872 tracer.stage("Prove psi0_ji, psi1_ji");
873 let R_j = &R[usize::from(j)];
874
875 let psi0_ji = pi_enc_elg::non_interactive::prove::<E, D>(
876 &unambiguous::ProofEnc {
877 sid,
878 prover: i,
879 num: 0,
880 },
881 &R_j.into(),
882 pi_enc_elg::Data {
883 key: &dec_i,
884 ciphertext: &K_i,
885 a: &Y_i,
886 b: &A_i1,
887 x: &A_i2,
888 },
889 pi_enc_elg::PrivateData {
890 plaintext: &utils::scalar_to_pm_bignumber(&k_i),
891 nonce: &rho_i,
892 b: a_i.as_ref(),
893 },
894 &security_params.pi_enc_elg,
895 rng,
896 )
897 .map_err(|e| Bug::PiEncElg(BugSource::psi0, e))?;
898
899 let psi1_ji = pi_enc_elg::non_interactive::prove::<E, D>(
900 &unambiguous::ProofEnc {
901 sid,
902 prover: i,
903 num: 1,
904 },
905 &R_j.into(),
906 pi_enc_elg::Data {
907 key: &dec_i,
908 ciphertext: &G_i,
909 a: &Y_i,
910 b: &B_i1,
911 x: &B_i2,
912 },
913 pi_enc_elg::PrivateData {
914 plaintext: &utils::scalar_to_pm_bignumber(&gamma_i),
915 nonce: &v_i,
916 b: b_i.as_ref(),
917 },
918 &security_params.pi_enc_elg,
919 rng,
920 )
921 .map_err(|e| Bug::PiEncElg(BugSource::psi1, e))?;
922
923 tracer.send_msg();
924 outgoings
925 .feed(Outgoing::p2p(
926 j,
927 Msg::Round1b(MsgRound1b {
928 psi0: psi0_ji,
929 psi1: psi1_ji,
930 }),
931 ))
932 .await
933 .map_err(IoError::send_message)?;
934 tracer.msg_sent();
935 }
936 tracer.send_msg();
937 outgoings.flush().await.map_err(IoError::send_message)?;
938 tracer.msg_sent();
939
940 tracer.round_begins();
942
943 tracer.receive_msgs();
944 let ciphertexts = rounds
946 .complete(round1a)
947 .await
948 .map_err(IoError::receive_message)?;
949 let psi_proofs = rounds
950 .complete(round1b)
951 .await
952 .map_err(IoError::receive_message)?;
953 tracer.msgs_received();
954
955 if enforce_reliable_broadcast {
957 tracer.stage("Hash received msgs (reliability check)");
958 let h_i = udigest::hash_iter::<D>(
959 ciphertexts
960 .iter_including_me(&MsgRound1a {
961 K: K_i.clone(),
962 G: G_i.clone(),
963 Y: Y_i,
964 A1: A_i1,
965 A2: A_i2,
966 B1: B_i1,
967 B2: B_i2,
968 })
969 .map(|ciphertexts| unambiguous::Echo { sid, ciphertexts }),
970 );
971
972 tracer.send_msg();
973 outgoings
974 .send(Outgoing::broadcast(Msg::ReliabilityCheck(
975 MsgReliabilityCheck(h_i.clone()),
976 )))
977 .await
978 .map_err(IoError::send_message)?;
979 tracer.msg_sent();
980
981 tracer.round_begins();
982
983 tracer.receive_msgs();
984 let round1a_hashes = rounds
985 .complete(round1a_sync)
986 .await
987 .map_err(IoError::receive_message)?;
988 tracer.msgs_received();
989 tracer.stage("Assert other parties hashed messages (reliability check)");
990 let parties_have_different_hashes =
991 utils::collect_simple_blame(&round1a_hashes, |hash| hash.0 != h_i);
992 if !parties_have_different_hashes.is_empty() {
993 return Err(SigningAborted::Round1aNotReliable(parties_have_different_hashes).into());
994 }
995 }
996
997 tracer.stage("Verify psi0, psi1 proofs");
999 let faulty_parties =
1000 utils::collect_blame_with_data(&ciphertexts, &psi_proofs, |j, ciphertexts, proof| {
1001 let N_j = &N[usize::from(j)];
1002 pi_enc_elg::non_interactive::verify::<E, D>(
1003 &unambiguous::ProofEnc {
1004 sid,
1005 prover: j,
1006 num: 0,
1007 },
1008 &R_i.into(),
1009 pi_enc_elg::Data {
1010 key: N_j,
1011 ciphertext: &ciphertexts.K,
1012 a: &ciphertexts.Y,
1013 b: &ciphertexts.A1,
1014 x: &ciphertexts.A2,
1015 },
1016 &proof.psi0,
1017 &security_params.pi_enc_elg,
1018 )
1019 .err()?;
1020 pi_enc_elg::non_interactive::verify::<E, D>(
1021 &unambiguous::ProofEnc {
1022 sid,
1023 prover: j,
1024 num: 1,
1025 },
1026 &R_i.into(),
1027 pi_enc_elg::Data {
1028 key: N_j,
1029 ciphertext: &ciphertexts.G,
1030 a: &ciphertexts.Y,
1031 b: &ciphertexts.B1,
1032 x: &ciphertexts.B2,
1033 },
1034 &proof.psi1,
1035 &security_params.pi_enc_elg,
1036 )
1037 .err()
1038 });
1039
1040 if !faulty_parties.is_empty() {
1041 return Err(SigningAborted::EncProofOfK(faulty_parties).into());
1042 }
1043 runtime.yield_now().await;
1044
1045 let Gamma_i = Point::generator() * &gamma_i;
1047
1048 tracer.stage("Prove tilde_psi_i");
1049 let tilde_psi_i = pi_elog::non_interactive::prove::<E, D>(
1050 &unambiguous::ProofElog {
1051 sid,
1052 prover: i,
1053 prime: false,
1054 },
1055 pi_elog::Data {
1056 l: &B_i1,
1057 m: &B_i2,
1058 x: &Y_i,
1059 y: &Gamma_i,
1060 h: &Point::generator().to_point(),
1061 },
1062 pi_elog::PrivateData {
1063 y: gamma_i.as_ref(),
1064 lambda: b_i.as_ref(),
1065 },
1066 rng,
1067 )
1068 .map_err(|e| Bug::PiElog(BugSource::psi, e))?;
1069 runtime.yield_now().await;
1070
1071 let J = Integer::one() << L::ELL_PRIME;
1072
1073 let mut beta_sum = Scalar::zero();
1074 let mut hat_beta_sum = Scalar::zero();
1075 for (j, _, ciphertext_j) in ciphertexts.iter_indexed() {
1076 tracer.stage("Sample random r, hat_r, s, hat_s, beta, hat_beta");
1077 let R_j = &R[usize::from(j)];
1078 let enc_j = &N[usize::from(j)];
1079
1080 let r_ij = dec_i.n().random_below_ref(rng);
1081 let hat_r_ij = dec_i.n().random_below_ref(rng);
1082 let s_ij = enc_j.n().random_below_ref(rng);
1083 let hat_s_ij = enc_j.n().random_below_ref(rng);
1084
1085 let beta_ij = Integer::from_rng_half_pm(rng, &J);
1086 let hat_beta_ij = Integer::from_rng_half_pm(rng, &J);
1087
1088 beta_sum += beta_ij.to_scalar();
1089 hat_beta_sum += hat_beta_ij.to_scalar();
1090
1091 tracer.stage("Encrypt D_ji");
1092 let D_ji = {
1094 let gamma_i_times_K_j = enc_j
1095 .omul(&utils::scalar_to_pm_bignumber(&gamma_i), &ciphertext_j.K)
1096 .map_err(|_| Bug::PaillierOp(BugSource::gamma_i_times_K_j))?;
1097 let neg_beta_ij_enc = enc_j
1098 .encrypt_with(&-&beta_ij, &s_ij)
1099 .map_err(|_| Bug::PaillierEnc(BugSource::neg_beta_ij_enc))?;
1100 enc_j
1101 .oadd(&gamma_i_times_K_j, &neg_beta_ij_enc)
1102 .map_err(|_| Bug::PaillierOp(BugSource::D_ji))?
1103 };
1104
1105 tracer.stage("Encrypt F_ji");
1106 let F_ji = dec_i
1107 .encrypt_with(&-&beta_ij, &r_ij)
1108 .map_err(|_| Bug::PaillierEnc(BugSource::F_ji))?;
1109
1110 tracer.stage("Encrypt hat_D_ji");
1111 let hat_D_ji = {
1113 let x_i_times_K_j = enc_j
1114 .omul(&utils::scalar_to_pm_bignumber(x_i), &ciphertext_j.K)
1115 .map_err(|_| Bug::PaillierOp(BugSource::x_i_times_K_j))?;
1116 let neg_hat_beta_ij_enc = enc_j
1117 .encrypt_with(&-&hat_beta_ij, &hat_s_ij)
1118 .map_err(|_| Bug::PaillierEnc(BugSource::hat_beta_ij_enc))?;
1119 enc_j
1120 .oadd(&x_i_times_K_j, &neg_hat_beta_ij_enc)
1121 .map_err(|_| Bug::PaillierOp(BugSource::hat_D))?
1122 };
1123 runtime.yield_now().await;
1124
1125 tracer.stage("Encrypt hat_F_ji");
1126 let hat_F_ji = dec_i
1127 .encrypt_with(&-&hat_beta_ij, &hat_r_ij)
1128 .map_err(|_| Bug::PaillierEnc(BugSource::hat_F))?;
1129
1130 tracer.stage("Prove psi_ji");
1131 let psi_ji = pi_aff::non_interactive::prove::<E, D>(
1132 &unambiguous::ProofPsi {
1133 sid,
1134 prover: i,
1135 hat: false,
1136 },
1137 &R_j.into(),
1138 pi_aff::Data {
1139 key_j: enc_j,
1140 key_i: &dec_i,
1141 c: &ciphertext_j.K,
1142 d: &D_ji,
1143 y: &F_ji,
1144 x: &Gamma_i,
1145 },
1146 pi_aff::PrivateData {
1147 x: &utils::scalar_to_pm_bignumber(&gamma_i),
1148 y: &-&beta_ij,
1149 nonce: &s_ij,
1150 nonce_y: &r_ij,
1151 },
1152 &security_params.pi_aff,
1153 &mut *rng,
1154 )
1155 .map_err(|e| Bug::PiAffG(BugSource::psi, e))?;
1156 runtime.yield_now().await;
1157
1158 tracer.stage("Prove psiˆ_ji");
1159 let hat_psi_ji = pi_aff::non_interactive::prove::<E, D>(
1160 &unambiguous::ProofPsi {
1161 sid,
1162 prover: i,
1163 hat: true,
1164 },
1165 &R_j.into(),
1166 pi_aff::Data {
1167 key_j: enc_j,
1168 key_i: &dec_i,
1169 c: &ciphertext_j.K,
1170 d: &hat_D_ji,
1171 y: &hat_F_ji,
1172 x: &(Point::generator() * x_i),
1173 },
1174 pi_aff::PrivateData {
1175 x: &utils::scalar_to_pm_bignumber(x_i),
1176 y: &-&hat_beta_ij,
1177 nonce: &hat_s_ij,
1178 nonce_y: &hat_r_ij,
1179 },
1180 &security_params.pi_aff,
1181 &mut *rng,
1182 )
1183 .map_err(|e| Bug::PiAffG(BugSource::hat_psi, e))?;
1184 runtime.yield_now().await;
1185
1186 tracer.send_msg();
1187 outgoings
1188 .feed(Outgoing::p2p(
1189 j,
1190 Msg::Round2(MsgRound2 {
1191 Gamma: Gamma_i,
1192 D: D_ji,
1193 F: F_ji,
1194 hat_D: hat_D_ji,
1195 hat_F: hat_F_ji,
1196 tilde_psi: tilde_psi_i.clone(),
1197 psi_j: psi_ji,
1198 hat_psi_j: hat_psi_ji,
1199 }),
1200 ))
1201 .await
1202 .map_err(IoError::send_message)?;
1203 tracer.msg_sent();
1204 }
1205 tracer.send_msg();
1206 outgoings.flush().await.map_err(IoError::send_message)?;
1207 tracer.msg_sent();
1208
1209 tracer.round_begins();
1211
1212 tracer.receive_msgs();
1214 let round2_msgs = rounds
1215 .complete(round2)
1216 .await
1217 .map_err(IoError::receive_message)?;
1218 tracer.msgs_received();
1219
1220 let faulty_parties =
1221 utils::collect_blame_with_data(&round2_msgs, &ciphertexts, |j, msg, ciphertexts| {
1222 tracer.stage("Retrieve auxiliary data");
1223 let X_j = X[usize::from(j)];
1224 let enc_j = &N[usize::from(j)];
1225
1226 tracer.stage("Validate tilde_psi_j");
1227 let tilde_psi_invalid = pi_elog::non_interactive::verify::<E, D>(
1228 &unambiguous::ProofElog {
1229 sid,
1230 prover: j,
1231 prime: false,
1232 },
1233 pi_elog::Data {
1234 l: &ciphertexts.B1,
1235 m: &ciphertexts.B2,
1236 x: &ciphertexts.Y,
1237 y: &msg.Gamma,
1238 h: &Point::generator().to_point(),
1239 },
1240 &msg.tilde_psi,
1241 )
1242 .err();
1243
1244 tracer.stage("Validate psi_i,j");
1245 let psi_j_invalid = pi_aff::non_interactive::verify::<E, D>(
1246 &unambiguous::ProofPsi {
1247 sid,
1248 prover: j,
1249 hat: false,
1250 },
1251 &R_i.into(),
1252 pi_aff::Data {
1253 key_j: &dec_i,
1254 key_i: enc_j,
1255 c: &K_i,
1256 d: &msg.D,
1257 y: &msg.F,
1258 x: &msg.Gamma,
1259 },
1260 &security_params.pi_aff,
1261 &msg.psi_j,
1262 )
1263 .err();
1264
1265 tracer.stage("Validate hat_psi_i,j");
1266 let hat_psi_j_invalid = pi_aff::non_interactive::verify::<E, D>(
1267 &unambiguous::ProofPsi {
1268 sid,
1269 prover: j,
1270 hat: true,
1271 },
1272 &R_i.into(),
1273 pi_aff::Data {
1274 key_j: &dec_i,
1275 key_i: enc_j,
1276 c: &K_i,
1277 d: &msg.hat_D,
1278 y: &msg.hat_F,
1279 x: &X_j,
1280 },
1281 &security_params.pi_aff,
1282 &msg.hat_psi_j,
1283 )
1284 .err();
1285
1286 if tilde_psi_invalid.is_some() || psi_j_invalid.is_some() || hat_psi_j_invalid.is_some()
1287 {
1288 Some((tilde_psi_invalid, psi_j_invalid, hat_psi_j_invalid))
1289 } else {
1290 None
1291 }
1292 });
1293 if !faulty_parties.is_empty() {
1294 return Err(SigningAborted::InvalidPsi(faulty_parties).into());
1295 }
1296 runtime.yield_now().await;
1297
1298 tracer.stage("Compute Gamma, Delta_i, delta_i, chi_i");
1300 let Gamma = Gamma_i + round2_msgs.iter().map(|msg| msg.Gamma).sum::<Point<E>>();
1301 let Delta_i = Gamma * &k_i;
1302
1303 let alpha_sum =
1304 round2_msgs
1305 .iter()
1306 .map(|msg| &msg.D)
1307 .try_fold(Scalar::<E>::zero(), |sum, D_ij| {
1308 let alpha_ij = dec_i
1309 .decrypt(D_ij)
1310 .map_err(|_| Bug::PaillierDec(BugSource::alpha))?;
1311 Ok::<_, Bug>(sum + alpha_ij.to_scalar())
1312 })?;
1313 let hat_alpha_sum =
1314 round2_msgs
1315 .iter()
1316 .map(|msg| &msg.hat_D)
1317 .try_fold(Scalar::zero(), |sum, hat_D_ij| {
1318 let hat_alpha_ij = dec_i
1319 .decrypt(hat_D_ij)
1320 .map_err(|_| Bug::PaillierDec(BugSource::hat_alpha))?;
1321 Ok::<_, Bug>(sum + hat_alpha_ij.to_scalar())
1322 })?;
1323
1324 let delta_i = gamma_i.as_ref() * k_i.as_ref() + alpha_sum + beta_sum;
1325 let chi_i = x_i * k_i.as_ref() + hat_alpha_sum + hat_beta_sum;
1326 let S_i = chi_i * Gamma;
1327 runtime.yield_now().await;
1328
1329 tracer.stage("Prove psi_prime");
1330 let psi_prime_i = pi_elog::non_interactive::prove::<E, D>(
1331 &unambiguous::ProofElog {
1332 sid,
1333 prover: i,
1334 prime: true,
1335 },
1336 pi_elog::Data {
1337 l: &A_i1,
1338 m: &A_i2,
1339 x: &Y_i,
1340 y: &Delta_i,
1341 h: &Gamma,
1342 },
1343 pi_elog::PrivateData {
1344 y: k_i.as_ref(),
1345 lambda: a_i.as_ref(),
1346 },
1347 rng,
1348 )
1349 .map_err(|e| Bug::PiLog(BugSource::psi_prime, e))?;
1350
1351 tracer.send_msg();
1352 let my_round3_msg = MsgRound3 {
1353 delta: delta_i,
1354 S: S_i,
1355 Delta: Delta_i,
1356 psi_prime: psi_prime_i,
1357 };
1358 outgoings
1359 .send(Outgoing::broadcast(Msg::Round3(my_round3_msg.clone())))
1360 .await
1361 .map_err(IoError::send_message)?;
1362 tracer.msg_sent();
1363
1364 tracer.named_round_begins("Presig output");
1366
1367 tracer.receive_msgs();
1369 let round3_msgs = rounds
1370 .complete(round3)
1371 .await
1372 .map_err(IoError::receive_message)?;
1373 tracer.msgs_received();
1374
1375 tracer.stage("Validate psi_prime_prime");
1376 let faulty_parties =
1377 utils::collect_blame_with_data(&round3_msgs, &ciphertexts, |j, msg_j, ciphertext_j| {
1378 pi_elog::non_interactive::verify::<E, D>(
1379 &unambiguous::ProofElog {
1380 sid,
1381 prover: j,
1382 prime: true,
1383 },
1384 pi_elog::Data {
1385 l: &ciphertext_j.A1,
1386 m: &ciphertext_j.A2,
1387 x: &ciphertext_j.Y,
1388 y: &msg_j.Delta,
1389 h: &Gamma,
1390 },
1391 &msg_j.psi_prime,
1392 )
1393 .err()
1394 });
1395 if !faulty_parties.is_empty() {
1396 return Err(SigningAborted::InvalidPsiPrimePrime(faulty_parties).into());
1397 }
1398 runtime.yield_now().await;
1399
1400 tracer.stage("Calculate presignature");
1402 let delta = delta_i + round3_msgs.iter().map(|m| m.delta).sum::<Scalar<E>>();
1403 let Delta = Delta_i + round3_msgs.iter().map(|m| m.Delta).sum::<Point<E>>();
1404 let S = S_i + round3_msgs.iter().map(|m| m.S).sum::<Point<E>>();
1405
1406 if Point::generator() * delta != Delta || pk * delta != S {
1407 return Err(SigningAborted::MismatchedDelta.into());
1411 }
1412
1413 let delta_inv = delta.invert().ok_or(Bug::Zero(BugSource::delta))?;
1414
1415 let tilde_k_i = SecretScalar::new(&mut (k_i * delta_inv));
1416 let tilde_chi_i = SecretScalar::new(&mut (chi_i * delta_inv));
1417
1418 let Gamma = NonZero::from_point(Gamma).ok_or(Bug::Zero(BugSource::Gamma))?;
1419
1420 let commitments = round3_msgs
1421 .iter_including_me(&my_round3_msg)
1422 .map(|m| PresignatureCommitment {
1423 tilde_Delta: delta_inv * m.Delta,
1424 tilde_S: delta_inv * m.S,
1425 })
1426 .collect::<Vec<_>>();
1427 let commitments = PresignaturePublicData { Gamma, commitments };
1428
1429 let presig = Presignature {
1430 Gamma,
1431 tilde_k: tilde_k_i,
1432 tilde_chi: tilde_chi_i,
1433 };
1434
1435 let Some(message_to_sign) = message_to_sign else {
1438 tracer.protocol_ends();
1439 return Ok(ProtocolOutput::Presignature((presig, commitments)));
1440 };
1441
1442 tracer.named_round_begins("Partial signing");
1444
1445 let message_to_sign = DataToSign(message_to_sign);
1452
1453 let partial_sig = presig.issue_partial_signature(message_to_sign);
1454
1455 tracer.send_msg();
1456 outgoings
1457 .send(Outgoing::broadcast(Msg::Round4(MsgRound4 { partial_sig })))
1458 .await
1459 .map_err(IoError::send_message)?;
1460 tracer.msg_sent();
1461
1462 tracer.named_round_begins("Signature reconstruction");
1464
1465 tracer.receive_msgs();
1466 let partial_sigs = rounds
1467 .complete(round4)
1468 .await
1469 .map_err(IoError::receive_message)?;
1470 tracer.msgs_received();
1471
1472 let partial_sigs = partial_sigs
1473 .into_vec_including_me(MsgRound4 { partial_sig })
1474 .into_iter()
1475 .map(|m| m.partial_sig)
1476 .collect::<Vec<_>>();
1477
1478 let sig = PartialSignature::combine(&partial_sigs, &commitments, message_to_sign)
1482 .ok_or(SigningAborted::SignatureInvalid)?;
1483
1484 tracer.protocol_ends();
1485 Ok(ProtocolOutput::Signature(sig))
1486}
1487
1488impl<E> Presignature<E>
1489where
1490 E: Curve,
1491 NonZero<Point<E>>: AlwaysHasAffineX<E>,
1492{
1493 pub fn issue_partial_signature(self, message_to_sign: DataToSign<E>) -> PartialSignature<E> {
1504 let r = self.Gamma.x().to_scalar();
1505 let m = message_to_sign.to_scalar();
1506 let sigma_i = self.tilde_k.as_ref() * m + r * self.tilde_chi.as_ref();
1507 PartialSignature { sigma: sigma_i }
1508 }
1509}
1510
1511#[cfg(feature = "hd-wallet")]
1512fn derive_additive_shift<E: Curve, Hd: hd_wallet::HdWallet<E>, Index>(
1513 mut epub: hd_wallet::ExtendedPublicKey<E>,
1514 path: impl IntoIterator<Item = Index>,
1515) -> Result<Scalar<E>, <Index as TryInto<hd_wallet::NonHardenedIndex>>::Error>
1516where
1517 hd_wallet::NonHardenedIndex: TryFrom<Index>,
1518{
1519 let mut additive_shift = Scalar::<E>::zero();
1520
1521 for child_index in path {
1522 let child_index: hd_wallet::NonHardenedIndex = child_index.try_into()?;
1523 let shift = Hd::derive_public_shift(&epub, child_index);
1524
1525 additive_shift += shift.shift;
1526 epub = shift.child_public_key;
1527 }
1528
1529 Ok(additive_shift)
1530}
1531
1532impl<E: Curve> PartialSignature<E>
1533where
1534 NonZero<Point<E>>: AlwaysHasAffineX<E>,
1535{
1536 pub fn combine(
1544 partial_signatures: &[PartialSignature<E>],
1545 commitments: &PresignaturePublicData<E>,
1546 m: DataToSign<E>,
1547 ) -> Option<Signature<E>> {
1548 if partial_signatures.is_empty()
1549 || partial_signatures.len() != commitments.commitments.len()
1550 {
1551 None
1552 } else {
1553 let r = commitments.Gamma.x().to_scalar();
1554 let r = NonZero::from_scalar(r)?;
1555 let m = m.to_scalar();
1556 for (partial_sig, commitment) in partial_signatures.iter().zip(&commitments.commitments)
1557 {
1558 if partial_sig.sigma * commitments.Gamma
1559 != m * commitment.tilde_Delta + r * commitment.tilde_S
1560 {
1561 return None;
1562 }
1563 }
1564 let sigma = partial_signatures.iter().map(|s| &s.sigma).sum();
1565 let sigma = NonZero::from_scalar(sigma)?;
1566 Some(Signature { r, s: sigma }.normalize_s())
1567 }
1568 }
1569}
1570
1571impl<E: Curve> Signature<E>
1572where
1573 NonZero<Point<E>>: AlwaysHasAffineX<E>,
1574{
1575 pub fn verify(
1577 &self,
1578 public_key: &Point<E>,
1579 message: &dyn AnyDataToSign<E>,
1580 ) -> Result<(), InvalidSignature> {
1581 let r = (Point::generator() * message.to_scalar() + public_key * self.r) * self.s.invert();
1582 let r = NonZero::from_point(r).ok_or(InvalidSignature)?;
1583
1584 if *self.r == r.x().to_scalar() {
1585 Ok(())
1586 } else {
1587 Err(InvalidSignature)
1588 }
1589 }
1590}
1591
1592impl<E: Curve> Signature<E> {
1593 pub fn from_raw_parts(r: NonZero<Scalar<E>>, s: NonZero<Scalar<E>>) -> Self {
1595 Self { r, s }
1596 }
1597 pub fn normalize_s(self) -> Self {
1605 let neg_s = -self.s;
1606 if neg_s < self.s {
1607 Signature { s: neg_s, ..self }
1608 } else {
1609 self
1610 }
1611 }
1612
1613 pub fn write_to_slice(&self, out: &mut [u8]) {
1618 if out.len() < Self::serialized_len() {
1619 return;
1620 }
1621 let scalar_size = Scalar::<E>::serialized_len();
1622 out[0..scalar_size].copy_from_slice(&self.r.to_be_bytes());
1623 out[scalar_size..2 * scalar_size].copy_from_slice(&self.s.to_be_bytes());
1624 }
1625
1626 pub fn read_from_slice(inp: &[u8]) -> Option<Self> {
1632 if inp.len() != Self::serialized_len() {
1633 return None;
1634 }
1635 let r_bytes = &inp[0..inp.len() / 2];
1636 let s_bytes = &inp[inp.len() / 2..];
1637 let r = generic_ec::Scalar::from_be_bytes(r_bytes)
1638 .ok()?
1639 .try_into()
1640 .ok()?;
1641 let s = generic_ec::Scalar::from_be_bytes(s_bytes)
1642 .ok()?
1643 .try_into()
1644 .ok()?;
1645 Some(Self::from_raw_parts(r, s))
1646 }
1647
1648 pub fn serialized_len() -> usize {
1650 2 * Scalar::<E>::serialized_len()
1651 }
1652}
1653
1654enum ProtocolOutput<E: Curve> {
1655 Presignature((Presignature<E>, PresignaturePublicData<E>)),
1656 Signature(Signature<E>),
1657}
1658
1659#[derive(Debug, Error)]
1661#[error("signing protocol failed")]
1662pub struct SigningError(#[source] Reason);
1663
1664crate::errors::impl_from! {
1665 impl From for SigningError {
1666 err: InvalidArgs => SigningError(Reason::InvalidArgs(err)),
1667 err: InvalidKeyShare => SigningError(Reason::InvalidKeyShare(err)),
1668 err: SigningAborted => SigningError(Reason::Aborted(err)),
1669 err: IoError => SigningError(Reason::IoError(err)),
1670 err: Bug => SigningError(Reason::Bug(err)),
1671 }
1672}
1673
1674#[derive(Debug, Error)]
1676enum Reason {
1677 #[error("invalid arguments")]
1678 InvalidArgs(
1679 #[from]
1680 #[source]
1681 InvalidArgs,
1682 ),
1683 #[error("provided key share is not valid")]
1684 InvalidKeyShare(
1685 #[from]
1686 #[source]
1687 InvalidKeyShare,
1688 ),
1689 #[error("protocol was maliciously aborted by another party")]
1691 Aborted(
1692 #[source]
1693 #[from]
1694 SigningAborted,
1695 ),
1696 #[error("i/o error")]
1697 IoError(#[source] IoError),
1698 #[error("bug occurred")]
1700 Bug(Bug),
1701}
1702
1703#[allow(clippy::type_complexity)]
1707#[derive(Debug, Error)]
1708enum SigningAborted {
1709 #[error("pi_enc::verify(K) failed")]
1710 EncProofOfK(Vec<(utils::AbortBlame, paillier_zk::InvalidProof)>),
1711 #[error("ψ_j, ψ_j,i or ψˆ_ji proofs are invalid: {0:?}")]
1712 InvalidPsi(
1713 Vec<(
1714 utils::AbortBlame,
1715 (
1716 Option<paillier_zk::InvalidProof>,
1717 Option<paillier_zk::InvalidProof>,
1718 Option<paillier_zk::InvalidProof>,
1719 ),
1720 )>,
1721 ),
1722 #[error("ψ'' proof is invalid")]
1723 InvalidPsiPrimePrime(Vec<(utils::AbortBlame, paillier_zk::InvalidProof)>),
1724 #[error("Delta != G * delta")]
1725 MismatchedDelta,
1726 #[error("resulting signature is not valid")]
1727 SignatureInvalid,
1728 #[error("other parties received different broadcast messages at round1a")]
1729 Round1aNotReliable(Vec<utils::AbortBlame>),
1730}
1731
1732#[derive(Debug, Error)]
1733enum InvalidArgs {
1734 #[error("exactly `threshold` amount of parties should take part in signing")]
1735 MismatchedAmountOfParties,
1736 #[error("signer index `i` is out of bounds (must be < n)")]
1737 SignerIndexOutOfBounds,
1738 #[error("party index in S is out of bounds (must be < n)")]
1739 InvalidS,
1740}
1741
1742#[derive(Debug, Error)]
1743enum Bug {
1744 #[error("own paillier decryption key is not valid")]
1745 InvalidOwnPaillierKey,
1746 #[error("invalid key share: number of parties exceeds u16")]
1747 PartiesNumberExceedsU16,
1748 #[error("couldn't encrypt a scalar with paillier encryption key: {0:?}")]
1749 PaillierEnc(BugSource),
1750 #[error("paillier addition/multiplication failed: {0:?}")]
1751 PaillierOp(BugSource),
1752 #[error("π enc elg failed to prove statement {0:?}")]
1753 PiEncElg(BugSource, paillier_zk::Error),
1754 #[error("π elog failed to prove statement {0:?}")]
1755 PiElog(BugSource, #[source] paillier_zk::Error),
1756 #[error("π aff-g failed to prove statement {0:?}")]
1757 PiAffG(BugSource, #[source] paillier_zk::Error),
1758 #[error("π log* failed to prove statement: {0:?}")]
1759 PiLog(BugSource, #[source] paillier_zk::Error),
1760 #[error("couldn't decrypt a message: {0:?}")]
1761 PaillierDec(BugSource),
1762 #[error("{0:?} is zero")]
1763 Zero(BugSource),
1764 #[error("unexpected protocol output")]
1765 UnexpectedProtocolOutput,
1766 #[error("derive lagrange coef")]
1767 LagrangeCoef,
1768 #[error("subset function returned error")]
1769 Subset,
1770 #[error("derived child key is zero - probability of that is negligible")]
1771 DerivedChildKeyZero,
1772 #[error("derived child share is zero - probability of that is negligible")]
1773 DerivedChildShareZero,
1774}
1775
1776#[derive(Debug)]
1777#[allow(non_camel_case_types)]
1778enum BugSource {
1779 G_i,
1780 K_i,
1781 gamma_i_times_K_j,
1782 neg_beta_ij_enc,
1783 D_ji,
1784 F_ji,
1785 x_i_times_K_j,
1786 hat_beta_ij_enc,
1787 hat_D,
1788 hat_F,
1789 psi0,
1790 psi1,
1791 psi,
1792 hat_psi,
1793 alpha,
1794 hat_alpha,
1795 psi_prime,
1796
1797 delta,
1798 Gamma,
1799}
1800
1801#[derive(Debug, Error)]
1803#[error("signature is not valid")]
1804pub struct InvalidSignature;
1805
1806#[cfg(test)]
1807mod test {
1808 fn read_write_signature<E: generic_ec::Curve>() {
1809 let mut rng = rand_dev::DevRng::new();
1810 for _ in 0..10 {
1811 let r = generic_ec::NonZero::<generic_ec::Scalar<E>>::random(&mut rng);
1812 let s = generic_ec::NonZero::<generic_ec::Scalar<E>>::random(&mut rng);
1813 let signature = super::Signature::from_raw_parts(r, s);
1814 let mut bytes = vec![0; super::Signature::<E>::serialized_len()];
1815 signature.write_to_slice(&mut bytes);
1816 let signature2 = super::Signature::read_from_slice(&bytes).unwrap();
1817 assert!(signature == signature2, "signatures equal");
1818 }
1819 }
1820
1821 #[test]
1822 fn read_write_signature_secp256k1() {
1823 read_write_signature::<crate::supported_curves::Secp256k1>()
1824 }
1825 #[test]
1826 fn read_write_signature_secp256r1() {
1827 read_write_signature::<crate::supported_curves::Secp256r1>()
1828 }
1829 #[test]
1830 fn read_write_signature_stark() {
1831 read_write_signature::<crate::supported_curves::Stark>()
1832 }
1833}