diff --git a/crypto/dkg/src/lib.rs b/crypto/dkg/src/lib.rs index e513665d..ce0ce400 100644 --- a/crypto/dkg/src/lib.rs +++ b/crypto/dkg/src/lib.rs @@ -401,31 +401,35 @@ impl ThresholdKeys { self.core.serialize() } - pub fn view(&self, included: &[Participant]) -> Result, DkgError<()>> { + pub fn view(&self, mut included: Vec) -> Result, DkgError<()>> { if (included.len() < self.params().t.into()) || (usize::from(self.params().n) < included.len()) { Err(DkgError::InvalidSigningSet)?; } + included.sort(); - let offset_share = self.offset.unwrap_or_else(C::F::zero) * - C::F::from(included.len().try_into().unwrap()).invert().unwrap(); - let offset_verification_share = C::generator() * offset_share; + let mut secret_share = + Zeroizing::new(lagrange::(self.params().i, &included) * self.secret_share().deref()); + + let mut verification_shares = self.verification_shares(); + for (i, share) in verification_shares.iter_mut() { + *share *= lagrange::(*i, &included); + } + + // The offset is included by adding it to the participant with the lowest ID + let offset = self.offset.unwrap_or_else(C::F::zero); + if included[0] == self.params().i() { + *secret_share += offset; + } + *verification_shares.get_mut(&included[0]).unwrap() += C::generator() * offset; Ok(ThresholdView { - offset: self.offset.unwrap_or_else(C::F::zero), + offset, group_key: self.group_key(), - secret_share: Zeroizing::new( - (lagrange::(self.params().i, included) * self.secret_share().deref()) + offset_share, - ), + secret_share, original_verification_shares: self.verification_shares(), - verification_shares: self - .verification_shares() - .iter() - .map(|(l, share)| { - (*l, (*share * lagrange::(*l, included)) + offset_verification_share) - }) - .collect(), - included: included.to_vec(), + verification_shares, + included, }) } } diff --git a/crypto/frost/src/sign.rs b/crypto/frost/src/sign.rs index b869e610..9634b161 100644 --- a/crypto/frost/src/sign.rs +++ b/crypto/frost/src/sign.rs @@ -318,7 +318,7 @@ impl> SignMachine for AlgorithmSignMachi } } - let view = self.params.keys.view(&included).unwrap(); + let view = self.params.keys.view(included.clone()).unwrap(); validate_map(&preprocesses, &included, multisig_params.i())?; { diff --git a/docs/cryptography/FROST.md b/docs/cryptography/FROST.md index 9f6b3378..464052e2 100644 --- a/docs/cryptography/FROST.md +++ b/docs/cryptography/FROST.md @@ -39,10 +39,8 @@ elements instead of `2n`. Finally, to support additive offset signing schemes (accounts, stealth addresses, randomization), it's possible to specify a scalar offset for keys. The public key signed for is also offset by this value. During the signing -process, the offset is explicitly transcripted. Then, the offset is divided by -`p`, the amount of participating signers, and each signer adds it to their -post-interpolation key share. This maintains a leaderless protocol while still -being correct. +process, the offset is explicitly transcripted. Then, the offset is added to the +participant with the lowest ID. # Caching