2024-08-16 17:01:45 -04:00
|
|
|
use core::marker::PhantomData;
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
|
|
use zeroize::Zeroizing;
|
|
|
|
|
|
Smash the singular `Ciphersuite` trait into multiple
This helps identify where the various functionalities are used, or rather, not
used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating
the entire FCMP++ tree, only requires the markers _and_ canonical point
decoding. I've opened a PR to upstream such a trait into `group`
(https://github.com/zkcrypto/group/pull/68).
`WrappedGroup` is still justified for as long as `Group::generator` exists.
Moving `::generator()` to its own trait, on an independent structure (upstream)
would be massively appreciated. @tarcieri also wanted to update from
`fn generator()` to `const GENERATOR`, which would encourage further discussion
on https://github.com/zkcrypto/group/issues/32 and
https://github.com/zkcrypto/group/issues/45, which have been stagnant.
The `Id` trait is occasionally used yet really should be first off the chopping
block.
Finally, `WithPreferredHash` is only actually used around a third of the time,
which more than justifies it being a separate trait.
---
Updates `dalek_ff_group::Scalar` to directly re-export
`curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint`
also could be replaced with an export of `curve25519_dalek::RistrettoPoint`,
yet the coordinator relies on how we implemented `Hash` on it for the hell of
it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be
replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't
implement `zeroize`, `subtle` traits within a released, non-yanked version.
Relevance to https://github.com/serai-dex/serai/issues/201 and
https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746.
Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over
`SHA2-512`. In order to maintain compliance with FROST's IETF standard,
`modular-frost` defines its own ciphersuite for Ristretto which still uses
`SHA2-512`.
2025-09-03 12:25:37 -04:00
|
|
|
use ciphersuite::{group::GroupEncoding, *};
|
2025-08-25 09:17:29 -04:00
|
|
|
use dkg::*;
|
2024-08-16 17:01:45 -04:00
|
|
|
|
2025-09-02 02:16:21 -04:00
|
|
|
use serai_primitives::validator_sets::Session;
|
2024-08-16 17:01:45 -04:00
|
|
|
|
|
|
|
|
use borsh::{BorshSerialize, BorshDeserialize};
|
2024-09-11 03:23:00 -04:00
|
|
|
use serai_db::{Get, DbTxn};
|
2024-08-16 17:01:45 -04:00
|
|
|
|
Smash the singular `Ciphersuite` trait into multiple
This helps identify where the various functionalities are used, or rather, not
used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating
the entire FCMP++ tree, only requires the markers _and_ canonical point
decoding. I've opened a PR to upstream such a trait into `group`
(https://github.com/zkcrypto/group/pull/68).
`WrappedGroup` is still justified for as long as `Group::generator` exists.
Moving `::generator()` to its own trait, on an independent structure (upstream)
would be massively appreciated. @tarcieri also wanted to update from
`fn generator()` to `const GENERATOR`, which would encourage further discussion
on https://github.com/zkcrypto/group/issues/32 and
https://github.com/zkcrypto/group/issues/45, which have been stagnant.
The `Id` trait is occasionally used yet really should be first off the chopping
block.
Finally, `WithPreferredHash` is only actually used around a third of the time,
which more than justifies it being a separate trait.
---
Updates `dalek_ff_group::Scalar` to directly re-export
`curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint`
also could be replaced with an export of `curve25519_dalek::RistrettoPoint`,
yet the coordinator relies on how we implemented `Hash` on it for the hell of
it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be
replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't
implement `zeroize`, `subtle` traits within a released, non-yanked version.
Relevance to https://github.com/serai-dex/serai/issues/201 and
https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746.
Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over
`SHA2-512`. In order to maintain compliance with FROST's IETF standard,
`modular-frost` defines its own ciphersuite for Ristretto which still uses
`SHA2-512`.
2025-09-03 12:25:37 -04:00
|
|
|
use crate::{Ristretto, KeyGenParams};
|
2024-08-16 17:01:45 -04:00
|
|
|
|
|
|
|
|
pub(crate) struct Params<P: KeyGenParams> {
|
|
|
|
|
pub(crate) t: u16,
|
|
|
|
|
pub(crate) n: u16,
|
|
|
|
|
pub(crate) substrate_evrf_public_keys:
|
Smash the singular `Ciphersuite` trait into multiple
This helps identify where the various functionalities are used, or rather, not
used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating
the entire FCMP++ tree, only requires the markers _and_ canonical point
decoding. I've opened a PR to upstream such a trait into `group`
(https://github.com/zkcrypto/group/pull/68).
`WrappedGroup` is still justified for as long as `Group::generator` exists.
Moving `::generator()` to its own trait, on an independent structure (upstream)
would be massively appreciated. @tarcieri also wanted to update from
`fn generator()` to `const GENERATOR`, which would encourage further discussion
on https://github.com/zkcrypto/group/issues/32 and
https://github.com/zkcrypto/group/issues/45, which have been stagnant.
The `Id` trait is occasionally used yet really should be first off the chopping
block.
Finally, `WithPreferredHash` is only actually used around a third of the time,
which more than justifies it being a separate trait.
---
Updates `dalek_ff_group::Scalar` to directly re-export
`curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint`
also could be replaced with an export of `curve25519_dalek::RistrettoPoint`,
yet the coordinator relies on how we implemented `Hash` on it for the hell of
it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be
replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't
implement `zeroize`, `subtle` traits within a released, non-yanked version.
Relevance to https://github.com/serai-dex/serai/issues/201 and
https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746.
Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over
`SHA2-512`. In order to maintain compliance with FROST's IETF standard,
`modular-frost` defines its own ciphersuite for Ristretto which still uses
`SHA2-512`.
2025-09-03 12:25:37 -04:00
|
|
|
Vec<<<Ristretto as Curves>::EmbeddedCurve as WrappedGroup>::G>,
|
2024-08-16 17:01:45 -04:00
|
|
|
pub(crate) network_evrf_public_keys:
|
Smash the singular `Ciphersuite` trait into multiple
This helps identify where the various functionalities are used, or rather, not
used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating
the entire FCMP++ tree, only requires the markers _and_ canonical point
decoding. I've opened a PR to upstream such a trait into `group`
(https://github.com/zkcrypto/group/pull/68).
`WrappedGroup` is still justified for as long as `Group::generator` exists.
Moving `::generator()` to its own trait, on an independent structure (upstream)
would be massively appreciated. @tarcieri also wanted to update from
`fn generator()` to `const GENERATOR`, which would encourage further discussion
on https://github.com/zkcrypto/group/issues/32 and
https://github.com/zkcrypto/group/issues/45, which have been stagnant.
The `Id` trait is occasionally used yet really should be first off the chopping
block.
Finally, `WithPreferredHash` is only actually used around a third of the time,
which more than justifies it being a separate trait.
---
Updates `dalek_ff_group::Scalar` to directly re-export
`curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint`
also could be replaced with an export of `curve25519_dalek::RistrettoPoint`,
yet the coordinator relies on how we implemented `Hash` on it for the hell of
it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be
replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't
implement `zeroize`, `subtle` traits within a released, non-yanked version.
Relevance to https://github.com/serai-dex/serai/issues/201 and
https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746.
Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over
`SHA2-512`. In order to maintain compliance with FROST's IETF standard,
`modular-frost` defines its own ciphersuite for Ristretto which still uses
`SHA2-512`.
2025-09-03 12:25:37 -04:00
|
|
|
Vec<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as WrappedGroup>::G>,
|
2024-08-16 17:01:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(BorshSerialize, BorshDeserialize)]
|
|
|
|
|
struct RawParams {
|
|
|
|
|
t: u16,
|
|
|
|
|
substrate_evrf_public_keys: Vec<[u8; 32]>,
|
|
|
|
|
network_evrf_public_keys: Vec<Vec<u8>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(BorshSerialize, BorshDeserialize)]
|
|
|
|
|
pub(crate) struct Participations {
|
2025-09-27 02:07:18 -04:00
|
|
|
#[borsh(
|
|
|
|
|
serialize_with = "messages::borsh_serialize_participant_map",
|
|
|
|
|
deserialize_with = "messages::borsh_deserialize_participant_map"
|
|
|
|
|
)]
|
2024-08-16 17:01:45 -04:00
|
|
|
pub(crate) substrate_participations: HashMap<Participant, Vec<u8>>,
|
2025-09-27 02:07:18 -04:00
|
|
|
#[borsh(
|
|
|
|
|
serialize_with = "messages::borsh_serialize_participant_map",
|
|
|
|
|
deserialize_with = "messages::borsh_deserialize_participant_map"
|
|
|
|
|
)]
|
2024-08-16 17:01:45 -04:00
|
|
|
pub(crate) network_participations: HashMap<Participant, Vec<u8>>,
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-11 03:23:00 -04:00
|
|
|
mod _db {
|
2025-09-02 02:16:21 -04:00
|
|
|
use serai_primitives::validator_sets::Session;
|
2024-09-11 03:23:00 -04:00
|
|
|
|
|
|
|
|
use serai_db::{Get, DbTxn, create_db};
|
|
|
|
|
|
|
|
|
|
create_db!(
|
|
|
|
|
KeyGen {
|
|
|
|
|
Params: (session: &Session) -> super::RawParams,
|
|
|
|
|
Participations: (session: &Session) -> super::Participations,
|
|
|
|
|
KeyShares: (session: &Session) -> Vec<u8>,
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-08-16 17:01:45 -04:00
|
|
|
|
|
|
|
|
pub(crate) struct KeyGenDb<P: KeyGenParams>(PhantomData<P>);
|
|
|
|
|
impl<P: KeyGenParams> KeyGenDb<P> {
|
|
|
|
|
pub(crate) fn set_params(txn: &mut impl DbTxn, session: Session, params: Params<P>) {
|
|
|
|
|
assert_eq!(params.substrate_evrf_public_keys.len(), params.network_evrf_public_keys.len());
|
|
|
|
|
|
2024-09-11 03:23:00 -04:00
|
|
|
_db::Params::set(
|
2024-08-16 17:01:45 -04:00
|
|
|
txn,
|
|
|
|
|
&session,
|
|
|
|
|
&RawParams {
|
|
|
|
|
t: params.t,
|
|
|
|
|
substrate_evrf_public_keys: params
|
|
|
|
|
.substrate_evrf_public_keys
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|key| key.to_bytes())
|
|
|
|
|
.collect(),
|
|
|
|
|
network_evrf_public_keys: params
|
|
|
|
|
.network_evrf_public_keys
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|key| key.to_bytes().as_ref().to_vec())
|
|
|
|
|
.collect(),
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn params(getter: &impl Get, session: Session) -> Option<Params<P>> {
|
2024-09-11 03:23:00 -04:00
|
|
|
_db::Params::get(getter, &session).map(|params| Params {
|
2024-08-16 17:01:45 -04:00
|
|
|
t: params.t,
|
|
|
|
|
n: params
|
|
|
|
|
.network_evrf_public_keys
|
|
|
|
|
.len()
|
|
|
|
|
.try_into()
|
|
|
|
|
.expect("amount of keys exceeded the amount allowed during a DKG"),
|
|
|
|
|
substrate_evrf_public_keys: params
|
|
|
|
|
.substrate_evrf_public_keys
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|key| {
|
Smash the singular `Ciphersuite` trait into multiple
This helps identify where the various functionalities are used, or rather, not
used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating
the entire FCMP++ tree, only requires the markers _and_ canonical point
decoding. I've opened a PR to upstream such a trait into `group`
(https://github.com/zkcrypto/group/pull/68).
`WrappedGroup` is still justified for as long as `Group::generator` exists.
Moving `::generator()` to its own trait, on an independent structure (upstream)
would be massively appreciated. @tarcieri also wanted to update from
`fn generator()` to `const GENERATOR`, which would encourage further discussion
on https://github.com/zkcrypto/group/issues/32 and
https://github.com/zkcrypto/group/issues/45, which have been stagnant.
The `Id` trait is occasionally used yet really should be first off the chopping
block.
Finally, `WithPreferredHash` is only actually used around a third of the time,
which more than justifies it being a separate trait.
---
Updates `dalek_ff_group::Scalar` to directly re-export
`curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint`
also could be replaced with an export of `curve25519_dalek::RistrettoPoint`,
yet the coordinator relies on how we implemented `Hash` on it for the hell of
it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be
replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't
implement `zeroize`, `subtle` traits within a released, non-yanked version.
Relevance to https://github.com/serai-dex/serai/issues/201 and
https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746.
Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over
`SHA2-512`. In order to maintain compliance with FROST's IETF standard,
`modular-frost` defines its own ciphersuite for Ristretto which still uses
`SHA2-512`.
2025-09-03 12:25:37 -04:00
|
|
|
<<Ristretto as Curves>::EmbeddedCurve as GroupIo>::read_G(&mut key.as_slice()).unwrap()
|
2024-08-16 17:01:45 -04:00
|
|
|
})
|
|
|
|
|
.collect(),
|
|
|
|
|
network_evrf_public_keys: params
|
|
|
|
|
.network_evrf_public_keys
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|key| {
|
Smash the singular `Ciphersuite` trait into multiple
This helps identify where the various functionalities are used, or rather, not
used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating
the entire FCMP++ tree, only requires the markers _and_ canonical point
decoding. I've opened a PR to upstream such a trait into `group`
(https://github.com/zkcrypto/group/pull/68).
`WrappedGroup` is still justified for as long as `Group::generator` exists.
Moving `::generator()` to its own trait, on an independent structure (upstream)
would be massively appreciated. @tarcieri also wanted to update from
`fn generator()` to `const GENERATOR`, which would encourage further discussion
on https://github.com/zkcrypto/group/issues/32 and
https://github.com/zkcrypto/group/issues/45, which have been stagnant.
The `Id` trait is occasionally used yet really should be first off the chopping
block.
Finally, `WithPreferredHash` is only actually used around a third of the time,
which more than justifies it being a separate trait.
---
Updates `dalek_ff_group::Scalar` to directly re-export
`curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint`
also could be replaced with an export of `curve25519_dalek::RistrettoPoint`,
yet the coordinator relies on how we implemented `Hash` on it for the hell of
it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be
replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't
implement `zeroize`, `subtle` traits within a released, non-yanked version.
Relevance to https://github.com/serai-dex/serai/issues/201 and
https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746.
Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over
`SHA2-512`. In order to maintain compliance with FROST's IETF standard,
`modular-frost` defines its own ciphersuite for Ristretto which still uses
`SHA2-512`.
2025-09-03 12:25:37 -04:00
|
|
|
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as GroupIo>::read_G::<&[u8]>(
|
|
|
|
|
&mut key.as_ref(),
|
|
|
|
|
)
|
2024-08-16 17:01:45 -04:00
|
|
|
.unwrap()
|
|
|
|
|
})
|
|
|
|
|
.collect(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn set_participations(
|
|
|
|
|
txn: &mut impl DbTxn,
|
|
|
|
|
session: Session,
|
|
|
|
|
participations: &Participations,
|
|
|
|
|
) {
|
2024-09-11 03:23:00 -04:00
|
|
|
_db::Participations::set(txn, &session, participations)
|
2024-08-16 17:01:45 -04:00
|
|
|
}
|
|
|
|
|
pub(crate) fn participations(getter: &impl Get, session: Session) -> Option<Participations> {
|
2024-09-11 03:23:00 -04:00
|
|
|
_db::Participations::get(getter, &session)
|
2024-08-16 17:01:45 -04:00
|
|
|
}
|
|
|
|
|
|
2024-08-19 00:41:18 -04:00
|
|
|
// Set the key shares for a session.
|
2024-08-16 17:01:45 -04:00
|
|
|
pub(crate) fn set_key_shares(
|
|
|
|
|
txn: &mut impl DbTxn,
|
|
|
|
|
session: Session,
|
2025-08-25 09:17:29 -04:00
|
|
|
substrate_keys: &[ThresholdKeys<<Ristretto as Curves>::ToweringCurve>],
|
|
|
|
|
network_keys: &[ThresholdKeys<<P::ExternalNetworkCiphersuite as Curves>::ToweringCurve>],
|
2024-08-16 17:01:45 -04:00
|
|
|
) {
|
|
|
|
|
assert_eq!(substrate_keys.len(), network_keys.len());
|
|
|
|
|
|
|
|
|
|
let mut keys = Zeroizing::new(vec![]);
|
|
|
|
|
for (substrate_keys, network_keys) in substrate_keys.iter().zip(network_keys) {
|
|
|
|
|
keys.extend(substrate_keys.serialize().as_slice());
|
|
|
|
|
keys.extend(network_keys.serialize().as_slice());
|
|
|
|
|
}
|
2024-09-11 03:23:00 -04:00
|
|
|
_db::KeyShares::set(txn, &session, &keys);
|
2024-08-16 17:01:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(clippy::type_complexity)]
|
|
|
|
|
pub(crate) fn key_shares(
|
|
|
|
|
getter: &impl Get,
|
|
|
|
|
session: Session,
|
2025-08-25 09:17:29 -04:00
|
|
|
) -> Option<(
|
|
|
|
|
Vec<ThresholdKeys<<Ristretto as Curves>::ToweringCurve>>,
|
|
|
|
|
Vec<ThresholdKeys<<P::ExternalNetworkCiphersuite as Curves>::ToweringCurve>>,
|
|
|
|
|
)> {
|
2024-09-11 03:23:00 -04:00
|
|
|
let keys = _db::KeyShares::get(getter, &session)?;
|
2024-08-16 17:01:45 -04:00
|
|
|
let mut keys: &[u8] = keys.as_ref();
|
|
|
|
|
|
|
|
|
|
let mut substrate_keys = vec![];
|
|
|
|
|
let mut network_keys = vec![];
|
|
|
|
|
while !keys.is_empty() {
|
2025-08-25 09:17:29 -04:00
|
|
|
substrate_keys.push(ThresholdKeys::read(&mut keys).unwrap());
|
|
|
|
|
let mut these_network_keys = ThresholdKeys::read(&mut keys).unwrap();
|
2024-08-16 17:01:45 -04:00
|
|
|
P::tweak_keys(&mut these_network_keys);
|
|
|
|
|
network_keys.push(these_network_keys);
|
|
|
|
|
}
|
|
|
|
|
Some((substrate_keys, network_keys))
|
|
|
|
|
}
|
|
|
|
|
}
|