Remove borsh from dkg

It pulls in a lot of bespoke dependencies for little utility directly present.

Moves the necessary code into the processor.
This commit is contained in:
Luke Parker
2025-09-27 02:07:18 -04:00
parent 5b1875dae6
commit ca93c82156
7 changed files with 110 additions and 43 deletions

1
Cargo.lock generated
View File

@@ -2444,7 +2444,6 @@ dependencies = [
name = "dkg"
version = "0.6.1"
dependencies = [
"borsh",
"ciphersuite 0.4.2",
"std-shims 0.1.5",
"thiserror 2.0.17",

View File

@@ -103,7 +103,7 @@ mod _internal_db {
// Tributary transactions to publish from the DKG confirmation task
TributaryTransactionsFromDkgConfirmation: (set: ExternalValidatorSet) -> Transaction,
// Participants to remove
RemoveParticipant: (set: ExternalValidatorSet) -> Participant,
RemoveParticipant: (set: ExternalValidatorSet) -> u16,
}
}
}
@@ -139,10 +139,11 @@ impl RemoveParticipant {
pub(crate) fn send(txn: &mut impl DbTxn, set: ExternalValidatorSet, participant: Participant) {
// If this set has yet to be retired, send this transaction
if RetiredTributary::get(txn, set.network).map(|session| session.0) < Some(set.session.0) {
_internal_db::RemoveParticipant::send(txn, set, &participant);
_internal_db::RemoveParticipant::send(txn, set, &u16::from(participant));
}
}
pub(crate) fn try_recv(txn: &mut impl DbTxn, set: ExternalValidatorSet) -> Option<Participant> {
_internal_db::RemoveParticipant::try_recv(txn, set)
.map(|i| Participant::new(i).expect("sent invalid participant index for removal"))
}
}

View File

@@ -23,19 +23,12 @@ thiserror = { version = "2", default-features = false }
std-shims = { version = "0.1", path = "../../common/std-shims", default-features = false, features = ["alloc"] }
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true }
ciphersuite = { path = "../ciphersuite", version = "^0.4.1", default-features = false, features = ["alloc"] }
[features]
std = [
"thiserror/std",
"std-shims/std",
"borsh?/std",
"ciphersuite/std",
]
borsh = ["dep:borsh"]
default = ["std"]

View File

@@ -22,7 +22,6 @@ use ciphersuite::{
/// The ID of a participant, defined as a non-zero u16.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Zeroize)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize))]
pub struct Participant(u16);
impl Participant {
/// Create a new Participant identifier from a u16.
@@ -129,18 +128,8 @@ pub enum DkgError {
NotParticipating,
}
// Manually implements BorshDeserialize so we can enforce it's a valid index
#[cfg(feature = "borsh")]
impl borsh::BorshDeserialize for Participant {
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
Participant::new(u16::deserialize_reader(reader)?)
.ok_or_else(|| io::Error::other("invalid participant"))
}
}
/// Parameters for a multisig.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize))]
pub struct ThresholdParams {
/// Participants needed to sign on behalf of the group.
t: u16,
@@ -210,16 +199,6 @@ impl ThresholdParams {
}
}
#[cfg(feature = "borsh")]
impl borsh::BorshDeserialize for ThresholdParams {
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
let t = u16::deserialize_reader(reader)?;
let n = u16::deserialize_reader(reader)?;
let i = Participant::deserialize_reader(reader)?;
ThresholdParams::new(t, n, i).map_err(|e| io::Error::other(format!("{e:?}")))
}
}
/// A method of interpolation.
#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
pub enum Interpolation<F: Zeroize + PrimeField> {

View File

@@ -31,7 +31,15 @@ struct RawParams {
#[derive(BorshSerialize, BorshDeserialize)]
pub(crate) struct Participations {
#[borsh(
serialize_with = "messages::borsh_serialize_participant_map",
deserialize_with = "messages::borsh_deserialize_participant_map"
)]
pub(crate) substrate_participations: HashMap<Participant, Vec<u8>>,
#[borsh(
serialize_with = "messages::borsh_serialize_participant_map",
deserialize_with = "messages::borsh_deserialize_participant_map"
)]
pub(crate) network_participations: HashMap<Participant, Vec<u8>>,
}

View File

@@ -23,7 +23,7 @@ hex = { version = "0.4", default-features = false, features = ["std"] }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std", "borsh"] }
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std"] }
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std", "borsh"] }
in-instructions-primitives = { package = "serai-in-instructions-primitives", path = "../../substrate/in-instructions/primitives", default-features = false, features = ["std", "borsh"] }

View File

@@ -21,6 +21,44 @@ pub struct SubstrateContext {
pub network_latest_finalized_block: BlockHash,
}
pub fn borsh_serialize_participant<W: borsh::io::Write>(
value: &Participant,
writer: &mut W,
) -> borsh::io::Result<()> {
u16::from(*value).serialize(writer)
}
pub fn borsh_deserialize_participant<R: borsh::io::Read>(
reader: &mut R,
) -> borsh::io::Result<Participant> {
u16::deserialize_reader(reader).and_then(|p| {
Participant::new(p)
.ok_or_else(|| borsh::io::Error::other("invalid `Participant` despite valid `u16`"))
})
}
pub fn borsh_serialize_participant_map<W: borsh::io::Write>(
value: &HashMap<Participant, Vec<u8>>,
writer: &mut W,
) -> borsh::io::Result<()> {
value
.iter()
.map(|(key, value)| (u16::from(*key), value))
.collect::<HashMap<u16, &Vec<u8>>>()
.serialize(writer)
}
pub fn borsh_deserialize_participant_map<R: borsh::io::Read>(
reader: &mut R,
) -> borsh::io::Result<HashMap<Participant, Vec<u8>>> {
HashMap::<u16, Vec<u8>>::deserialize_reader(reader)?
.into_iter()
.map(|(key, value)| {
Participant::new(key)
.ok_or_else(|| borsh::io::Error::other("invalid `Participant` despite valid `u16` in map"))
.map(|key| (key, value))
})
.collect()
}
pub mod key_gen {
use super::*;
@@ -33,7 +71,15 @@ pub mod key_gen {
/// Received participations for the specified key generation protocol.
///
/// This is sent by the Coordinator's Tributary scanner.
Participation { session: Session, participant: Participant, participation: Vec<u8> },
Participation {
session: Session,
#[borsh(
serialize_with = "borsh_serialize_participant",
deserialize_with = "borsh_deserialize_participant"
)]
participant: Participant,
participation: Vec<u8>,
},
}
impl core::fmt::Debug for CoordinatorMessage {
@@ -58,11 +104,25 @@ pub mod key_gen {
#[derive(Clone, BorshSerialize, BorshDeserialize)]
pub enum ProcessorMessage {
// Participated in the specified key generation protocol.
Participation { session: Session, participation: Vec<u8> },
Participation {
session: Session,
participation: Vec<u8>,
},
// Resulting keys from the specified key generation protocol.
GeneratedKeyPair { session: Session, substrate_key: [u8; 32], network_key: Vec<u8> },
GeneratedKeyPair {
session: Session,
substrate_key: [u8; 32],
network_key: Vec<u8>,
},
// Blame this participant.
Blame { session: Session, participant: Participant },
Blame {
session: Session,
#[borsh(
serialize_with = "borsh_serialize_participant",
deserialize_with = "borsh_deserialize_participant"
)]
participant: Participant,
},
}
impl core::fmt::Debug for ProcessorMessage {
@@ -127,11 +187,25 @@ pub mod sign {
/// Received preprocesses for the specified signing protocol.
///
/// This is sent by the Coordinator's Tributary scanner.
Preprocesses { id: SignId, preprocesses: HashMap<Participant, Vec<u8>> },
Preprocesses {
id: SignId,
#[borsh(
serialize_with = "borsh_serialize_participant_map",
deserialize_with = "borsh_deserialize_participant_map"
)]
preprocesses: HashMap<Participant, Vec<u8>>,
},
// Received shares for the specified signing protocol.
///
/// This is sent by the Coordinator's Tributary scanner.
Shares { id: SignId, shares: HashMap<Participant, Vec<u8>> },
Shares {
id: SignId,
#[borsh(
serialize_with = "borsh_serialize_participant_map",
deserialize_with = "borsh_deserialize_participant_map"
)]
shares: HashMap<Participant, Vec<u8>>,
},
// Re-attempt a signing protocol.
///
/// This is sent by the Coordinator's Tributary re-attempt scheduling logic.
@@ -152,11 +226,24 @@ pub mod sign {
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
pub enum ProcessorMessage {
// Participant sent an invalid message during the sign protocol.
InvalidParticipant { session: Session, participant: Participant },
InvalidParticipant {
session: Session,
#[borsh(
serialize_with = "borsh_serialize_participant",
deserialize_with = "borsh_deserialize_participant"
)]
participant: Participant,
},
// Created preprocesses for the specified signing protocol.
Preprocesses { id: SignId, preprocesses: Vec<Vec<u8>> },
Preprocesses {
id: SignId,
preprocesses: Vec<Vec<u8>>,
},
// Signed shares for the specified signing protocol.
Shares { id: SignId, shares: Vec<Vec<u8>> },
Shares {
id: SignId,
shares: Vec<Vec<u8>>,
},
}
}
@@ -301,7 +388,7 @@ impl CoordinatorMessage {
}
// Unique since one participation per participant per session
key_gen::CoordinatorMessage::Participation { session, participant, .. } => {
(1, borsh::to_vec(&(session, participant)).unwrap())
(1, borsh::to_vec(&(session, u16::from(*participant))).unwrap())
}
};
@@ -372,7 +459,7 @@ impl ProcessorMessage {
}
// Unique since we only blame a participant once (as this is fatal)
key_gen::ProcessorMessage::Blame { session, participant } => {
(2, borsh::to_vec(&(session, participant)).unwrap())
(2, borsh::to_vec(&(session, u16::from(*participant))).unwrap())
}
};