3.6.8 Simplify offset splitting

This wasn't done prior to be 'leaderless', as now the participant with the
lowest ID has an extra step, yet this is still trivial. There's also notable
performance benefits to not taking the previous dividing approach, which
performed an exp.
This commit is contained in:
Luke Parker 2023-03-01 01:06:13 -05:00
parent a42a84e1e8
commit c6284b85a4
No known key found for this signature in database
3 changed files with 23 additions and 21 deletions

View file

@ -401,31 +401,35 @@ impl<C: Ciphersuite> ThresholdKeys<C> {
self.core.serialize() self.core.serialize()
} }
pub fn view(&self, included: &[Participant]) -> Result<ThresholdView<C>, DkgError<()>> { pub fn view(&self, mut included: Vec<Participant>) -> Result<ThresholdView<C>, DkgError<()>> {
if (included.len() < self.params().t.into()) || (usize::from(self.params().n) < included.len()) if (included.len() < self.params().t.into()) || (usize::from(self.params().n) < included.len())
{ {
Err(DkgError::InvalidSigningSet)?; Err(DkgError::InvalidSigningSet)?;
} }
included.sort();
let offset_share = self.offset.unwrap_or_else(C::F::zero) * let mut secret_share =
C::F::from(included.len().try_into().unwrap()).invert().unwrap(); Zeroizing::new(lagrange::<C::F>(self.params().i, &included) * self.secret_share().deref());
let offset_verification_share = C::generator() * offset_share;
let mut verification_shares = self.verification_shares();
for (i, share) in verification_shares.iter_mut() {
*share *= lagrange::<C::F>(*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 { Ok(ThresholdView {
offset: self.offset.unwrap_or_else(C::F::zero), offset,
group_key: self.group_key(), group_key: self.group_key(),
secret_share: Zeroizing::new( secret_share,
(lagrange::<C::F>(self.params().i, included) * self.secret_share().deref()) + offset_share,
),
original_verification_shares: self.verification_shares(), original_verification_shares: self.verification_shares(),
verification_shares: self verification_shares,
.verification_shares() included,
.iter()
.map(|(l, share)| {
(*l, (*share * lagrange::<C::F>(*l, included)) + offset_verification_share)
})
.collect(),
included: included.to_vec(),
}) })
} }
} }

View file

@ -318,7 +318,7 @@ impl<C: Curve, A: Algorithm<C>> SignMachine<A::Signature> 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())?; validate_map(&preprocesses, &included, multisig_params.i())?;
{ {

View file

@ -39,10 +39,8 @@ elements instead of `2n`.
Finally, to support additive offset signing schemes (accounts, stealth Finally, to support additive offset signing schemes (accounts, stealth
addresses, randomization), it's possible to specify a scalar offset for keys. 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 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 process, the offset is explicitly transcripted. Then, the offset is added to the
`p`, the amount of participating signers, and each signer adds it to their participant with the lowest ID.
post-interpolation key share. This maintains a leaderless protocol while still
being correct.
# Caching # Caching