mirror of
https://github.com/serai-dex/serai.git
synced 2024-11-16 17:07:35 +00:00
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:
parent
a42a84e1e8
commit
c6284b85a4
3 changed files with 23 additions and 21 deletions
|
@ -401,31 +401,35 @@ impl<C: Ciphersuite> ThresholdKeys<C> {
|
|||
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())
|
||||
{
|
||||
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::<C::F>(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::<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 {
|
||||
offset: self.offset.unwrap_or_else(C::F::zero),
|
||||
offset,
|
||||
group_key: self.group_key(),
|
||||
secret_share: Zeroizing::new(
|
||||
(lagrange::<C::F>(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::<C::F>(*l, included)) + offset_verification_share)
|
||||
})
|
||||
.collect(),
|
||||
included: included.to_vec(),
|
||||
verification_shares,
|
||||
included,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())?;
|
||||
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue