Route blame between Processor and Coordinator (#427)

* Have processor report errors during the DKG to the coordinator

* Add RemoveParticipant, InvalidDkgShare to coordinator

* Route DKG blame around coordinator

* Allow public construction of AdditionalBlameMachine

Necessary for upcoming work on handling DKG blame in the processor and
coordinator.

Additionally fixes a publicly reachable panic when commitments parsed with one
ThresholdParams are used in a machine using another set of ThresholdParams.

Renames InvalidProofOfKnowledge to InvalidCommitments.

* Remove unused error from dleq

* Implement support for VerifyBlame in the processor

* Have coordinator send the processor share message relevant to Blame

* Remove desync between processors reporting InvalidShare and ones reporting GeneratedKeyPair

* Route blame on sign between processor and coordinator

Doesn't yet act on it in coordinator.

* Move txn usage as needed for stable Rust to build

* Correct InvalidDkgShare serialization
This commit is contained in:
Luke Parker
2023-11-12 07:24:41 -05:00
committed by GitHub
parent d015ee96a3
commit 54f1929078
18 changed files with 931 additions and 281 deletions

View File

@@ -233,6 +233,8 @@ impl<const N: usize> ReadWrite for SignData<N> {
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Transaction {
RemoveParticipant(Participant),
// Once this completes successfully, no more instances should be created.
DkgCommitments(u32, Vec<Vec<u8>>, Signed),
DkgShares {
@@ -242,6 +244,13 @@ pub enum Transaction {
confirmation_nonces: [u8; 64],
signed: Signed,
},
InvalidDkgShare {
attempt: u32,
accuser: Participant,
faulty: Participant,
blame: Option<Vec<u8>>,
signed: Signed,
},
DkgConfirmed(u32, [u8; 32], Signed),
// When we have synchrony on a batch, we can allow signing it
@@ -279,7 +288,15 @@ impl ReadWrite for Transaction {
reader.read_exact(&mut kind)?;
match kind[0] {
0 => {
0 => Ok(Transaction::RemoveParticipant({
let mut participant = [0; 2];
reader.read_exact(&mut participant)?;
Participant::new(u16::from_le_bytes(participant)).ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "invalid participant in RemoveParticipant")
})?
})),
1 => {
let mut attempt = [0; 4];
reader.read_exact(&mut attempt)?;
let attempt = u32::from_le_bytes(attempt);
@@ -314,7 +331,7 @@ impl ReadWrite for Transaction {
Ok(Transaction::DkgCommitments(attempt, commitments, signed))
}
1 => {
2 => {
let mut attempt = [0; 4];
reader.read_exact(&mut attempt)?;
let attempt = u32::from_le_bytes(attempt);
@@ -351,7 +368,40 @@ impl ReadWrite for Transaction {
Ok(Transaction::DkgShares { attempt, shares, confirmation_nonces, signed })
}
2 => {
3 => {
let mut attempt = [0; 4];
reader.read_exact(&mut attempt)?;
let attempt = u32::from_le_bytes(attempt);
let mut accuser = [0; 2];
reader.read_exact(&mut accuser)?;
let accuser = Participant::new(u16::from_le_bytes(accuser)).ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "invalid participant in InvalidDkgShare")
})?;
let mut faulty = [0; 2];
reader.read_exact(&mut faulty)?;
let faulty = Participant::new(u16::from_le_bytes(faulty)).ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "invalid participant in InvalidDkgShare")
})?;
let mut blame_len = [0; 2];
reader.read_exact(&mut blame_len)?;
let mut blame = vec![0; u16::from_le_bytes(blame_len).into()];
reader.read_exact(&mut blame)?;
let signed = Signed::read(reader)?;
Ok(Transaction::InvalidDkgShare {
attempt,
accuser,
faulty,
blame: Some(blame).filter(|blame| !blame.is_empty()),
signed,
})
}
4 => {
let mut attempt = [0; 4];
reader.read_exact(&mut attempt)?;
let attempt = u32::from_le_bytes(attempt);
@@ -364,7 +414,7 @@ impl ReadWrite for Transaction {
Ok(Transaction::DkgConfirmed(attempt, confirmation_share, signed))
}
3 => {
5 => {
let mut block = [0; 32];
reader.read_exact(&mut block)?;
let mut batch = [0; 5];
@@ -372,19 +422,19 @@ impl ReadWrite for Transaction {
Ok(Transaction::Batch(block, batch))
}
4 => {
6 => {
let mut block = [0; 8];
reader.read_exact(&mut block)?;
Ok(Transaction::SubstrateBlock(u64::from_le_bytes(block)))
}
5 => SignData::read(reader).map(Transaction::BatchPreprocess),
6 => SignData::read(reader).map(Transaction::BatchShare),
7 => SignData::read(reader).map(Transaction::BatchPreprocess),
8 => SignData::read(reader).map(Transaction::BatchShare),
7 => SignData::read(reader).map(Transaction::SignPreprocess),
8 => SignData::read(reader).map(Transaction::SignShare),
9 => SignData::read(reader).map(Transaction::SignPreprocess),
10 => SignData::read(reader).map(Transaction::SignShare),
9 => {
11 => {
let mut plan = [0; 32];
reader.read_exact(&mut plan)?;
@@ -405,8 +455,13 @@ impl ReadWrite for Transaction {
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
match self {
Transaction::DkgCommitments(attempt, commitments, signed) => {
Transaction::RemoveParticipant(i) => {
writer.write_all(&[0])?;
writer.write_all(&u16::from(*i).to_le_bytes())
}
Transaction::DkgCommitments(attempt, commitments, signed) => {
writer.write_all(&[1])?;
writer.write_all(&attempt.to_le_bytes())?;
if commitments.is_empty() {
Err(io::Error::new(io::ErrorKind::Other, "zero commitments in DkgCommitments"))?
@@ -428,7 +483,7 @@ impl ReadWrite for Transaction {
}
Transaction::DkgShares { attempt, shares, confirmation_nonces, signed } => {
writer.write_all(&[1])?;
writer.write_all(&[2])?;
writer.write_all(&attempt.to_le_bytes())?;
// `shares` is a Vec which is supposed to map to a HashMap<Pariticpant, Vec<u8>>. Since we
@@ -456,43 +511,59 @@ impl ReadWrite for Transaction {
signed.write(writer)
}
Transaction::InvalidDkgShare { attempt, accuser, faulty, blame, signed } => {
writer.write_all(&[3])?;
writer.write_all(&attempt.to_le_bytes())?;
writer.write_all(&u16::from(*accuser).to_le_bytes())?;
writer.write_all(&u16::from(*faulty).to_le_bytes())?;
// Flattens Some(vec![]) to None on the expectation no actual blame will be 0-length
assert!(blame.as_ref().map(|blame| blame.len()).unwrap_or(1) != 0);
let blame_len =
u16::try_from(blame.as_ref().unwrap_or(&vec![]).len()).expect("blame exceeded 64 KB");
writer.write_all(&blame_len.to_le_bytes())?;
writer.write_all(blame.as_ref().unwrap_or(&vec![]))?;
signed.write(writer)
}
Transaction::DkgConfirmed(attempt, share, signed) => {
writer.write_all(&[2])?;
writer.write_all(&[4])?;
writer.write_all(&attempt.to_le_bytes())?;
writer.write_all(share)?;
signed.write(writer)
}
Transaction::Batch(block, batch) => {
writer.write_all(&[3])?;
writer.write_all(&[5])?;
writer.write_all(block)?;
writer.write_all(batch)
}
Transaction::SubstrateBlock(block) => {
writer.write_all(&[4])?;
writer.write_all(&[6])?;
writer.write_all(&block.to_le_bytes())
}
Transaction::BatchPreprocess(data) => {
writer.write_all(&[5])?;
writer.write_all(&[7])?;
data.write(writer)
}
Transaction::BatchShare(data) => {
writer.write_all(&[6])?;
writer.write_all(&[8])?;
data.write(writer)
}
Transaction::SignPreprocess(data) => {
writer.write_all(&[7])?;
writer.write_all(&[9])?;
data.write(writer)
}
Transaction::SignShare(data) => {
writer.write_all(&[8])?;
writer.write_all(&[10])?;
data.write(writer)
}
Transaction::SignCompleted { plan, tx_hash, first_signer, signature } => {
writer.write_all(&[9])?;
writer.write_all(&[11])?;
writer.write_all(plan)?;
writer
.write_all(&[u8::try_from(tx_hash.len()).expect("tx hash length exceed 255 bytes")])?;
@@ -507,8 +578,11 @@ impl ReadWrite for Transaction {
impl TransactionTrait for Transaction {
fn kind(&self) -> TransactionKind<'_> {
match self {
Transaction::RemoveParticipant(_) => TransactionKind::Provided("remove"),
Transaction::DkgCommitments(_, _, signed) => TransactionKind::Signed(signed),
Transaction::DkgShares { signed, .. } => TransactionKind::Signed(signed),
Transaction::InvalidDkgShare { signed, .. } => TransactionKind::Signed(signed),
Transaction::DkgConfirmed(_, _, signed) => TransactionKind::Signed(signed),
Transaction::Batch(_, _) => TransactionKind::Provided("batch"),
@@ -574,8 +648,11 @@ impl Transaction {
) {
fn signed(tx: &mut Transaction) -> &mut Signed {
match tx {
Transaction::RemoveParticipant(_) => panic!("signing RemoveParticipant"),
Transaction::DkgCommitments(_, _, ref mut signed) => signed,
Transaction::DkgShares { ref mut signed, .. } => signed,
Transaction::InvalidDkgShare { ref mut signed, .. } => signed,
Transaction::DkgConfirmed(_, _, ref mut signed) => signed,
Transaction::Batch(_, _) => panic!("signing Batch"),