1use core::fmt::{self, Debug};
4
5use crate as frost;
6use crate::{
7 Challenge, Ciphersuite, Error, Field, Group, {round1, *},
8};
9
10#[derive(Clone, Copy, Eq, PartialEq, Getters)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
15#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
16pub struct SignatureShare<C: Ciphersuite> {
17 #[getter(skip)]
19 pub(crate) header: Header<C>,
20 pub(crate) share: SerializableScalar<C>,
22}
23
24impl<C> SignatureShare<C>
25where
26 C: Ciphersuite,
27{
28 pub(crate) fn new(
29 scalar: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar,
30 ) -> Self {
31 Self {
32 header: Header::default(),
33 share: SerializableScalar(scalar),
34 }
35 }
36
37 pub(crate) fn to_scalar(
38 self,
39 ) -> <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar {
40 self.share.0
41 }
42
43 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
45 Ok(Self {
46 header: Header::default(),
47 share: SerializableScalar::deserialize(bytes)?,
48 })
49 }
50
51 pub fn serialize(&self) -> Vec<u8> {
53 self.share.serialize()
54 }
55
56 #[cfg_attr(feature = "internals", visibility::make(pub))]
63 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
64 pub(crate) fn verify(
65 &self,
66 identifier: Identifier<C>,
67 group_commitment_share: &round1::GroupCommitmentShare<C>,
68 verifying_share: &frost::keys::VerifyingShare<C>,
69 lambda_i: Scalar<C>,
70 challenge: &Challenge<C>,
71 ) -> Result<(), Error<C>> {
72 if (<C::Group>::generator() * self.to_scalar())
73 != (group_commitment_share.to_element()
74 + (verifying_share.to_element() * challenge.0 * lambda_i))
75 {
76 return Err(Error::InvalidSignatureShare {
77 culprit: identifier,
78 });
79 }
80
81 Ok(())
82 }
83}
84
85impl<C> Debug for SignatureShare<C>
86where
87 C: Ciphersuite,
88{
89 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90 f.debug_struct("SignatureShare")
91 .field("share", &hex::encode(self.serialize()))
92 .finish()
93 }
94}
95
96#[cfg_attr(feature = "internals", visibility::make(pub))]
98#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
99pub(super) fn compute_signature_share<C: Ciphersuite>(
100 signer_nonces: &round1::SigningNonces<C>,
101 binding_factor: BindingFactor<C>,
102 lambda_i: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar,
103 key_package: &keys::KeyPackage<C>,
104 challenge: Challenge<C>,
105) -> SignatureShare<C> {
106 let z_share: <<C::Group as Group>::Field as Field>::Scalar = signer_nonces.hiding.to_scalar()
107 + (signer_nonces.binding.to_scalar() * binding_factor.0)
108 + (lambda_i * key_package.signing_share.to_scalar() * challenge.to_scalar());
109
110 SignatureShare::<C>::new(z_share)
111}
112
113pub fn sign<C: Ciphersuite>(
126 signing_package: &SigningPackage<C>,
127 signer_nonces: &round1::SigningNonces<C>,
128 key_package: &frost::keys::KeyPackage<C>,
129) -> Result<SignatureShare<C>, Error<C>> {
130 if signing_package.signing_commitments().len() < key_package.min_signers as usize {
131 return Err(Error::IncorrectNumberOfCommitments);
132 }
133
134 let commitment = signing_package
136 .signing_commitments
137 .get(&key_package.identifier)
138 .ok_or(Error::MissingCommitment)?;
139
140 if &signer_nonces.commitments != commitment {
142 return Err(Error::IncorrectCommitment);
143 }
144
145 let (signing_package, signer_nonces, key_package) =
146 <C>::pre_sign(signing_package, signer_nonces, key_package)?;
147
148 let binding_factor_list: BindingFactorList<C> =
151 compute_binding_factor_list(&signing_package, &key_package.verifying_key, &[])?;
152 let binding_factor: frost::BindingFactor<C> = binding_factor_list
153 .get(&key_package.identifier)
154 .ok_or(Error::UnknownIdentifier)?
155 .clone();
156
157 let group_commitment = compute_group_commitment(&signing_package, &binding_factor_list)?;
159
160 let lambda_i = frost::derive_interpolating_value(key_package.identifier(), &signing_package)?;
162
163 let challenge = <C>::challenge(
165 &group_commitment.0,
166 &key_package.verifying_key,
167 signing_package.message(),
168 )?;
169
170 let signature_share = <C>::compute_signature_share(
172 &group_commitment,
173 &signer_nonces,
174 binding_factor,
175 lambda_i,
176 &key_package,
177 challenge,
178 );
179
180 Ok(signature_share)
181}