Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update wsts dependency to get malicious DkgPrivateShares handling #4326

Merged
merged 1 commit into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ members = [

# Dependencies we want to keep the same between workspace members
[workspace.dependencies]
wsts = "7.0"
wsts = "8.0"
rand_core = "0.6"
rand = "0.8"

Expand Down
130 changes: 121 additions & 9 deletions libsigner/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use blockstack_lib::net::api::postblock_proposal::{
use blockstack_lib::util_lib::boot::boot_code_id;
use clarity::vm::types::serialization::SerializationError;
use clarity::vm::types::QualifiedContractIdentifier;
use hashbrown::HashMap;
use hashbrown::{HashMap, HashSet};
use serde::{Deserialize, Serialize};
use stacks_common::codec::{
read_next, read_next_at_most, read_next_exact, write_next, Error as CodecError,
Expand All @@ -40,12 +40,13 @@ use stacks_common::util::hash::Sha512Trunc256Sum;
use tiny_http::{
Method as HttpMethod, Request as HttpRequest, Response as HttpResponse, Server as HttpServer,
};
use wsts::common::{PolyCommitment, PublicNonce, Signature, SignatureShare};
use wsts::common::{PolyCommitment, PublicNonce, Signature, SignatureShare, TupleProof};
use wsts::curve::point::{Compressed, Point};
use wsts::curve::scalar::Scalar;
use wsts::net::{
DkgBegin, DkgEnd, DkgEndBegin, DkgPrivateBegin, DkgPrivateShares, DkgPublicShares, DkgStatus,
Message, NonceRequest, NonceResponse, Packet, SignatureShareRequest, SignatureShareResponse,
BadPrivateShare, DkgBegin, DkgEnd, DkgEndBegin, DkgFailure, DkgPrivateBegin, DkgPrivateShares,
DkgPublicShares, DkgStatus, Message, NonceRequest, NonceResponse, Packet,
SignatureShareRequest, SignatureShareResponse,
};
use wsts::schnorr::ID;
use wsts::state_machine::signer;
Expand Down Expand Up @@ -247,6 +248,119 @@ impl StacksMessageCodecExtensions for Point {
}
}

#[allow(non_snake_case)]
impl StacksMessageCodecExtensions for TupleProof {
fn inner_consensus_serialize<W: Write>(&self, fd: &mut W) -> Result<(), CodecError> {
self.R.inner_consensus_serialize(fd)?;
self.rB.inner_consensus_serialize(fd)?;
self.z.inner_consensus_serialize(fd)
}
fn inner_consensus_deserialize<R: Read>(fd: &mut R) -> Result<Self, CodecError> {
let R = Point::inner_consensus_deserialize(fd)?;
let rB = Point::inner_consensus_deserialize(fd)?;
let z = Scalar::inner_consensus_deserialize(fd)?;
Ok(Self { R, rB, z })
}
}

impl StacksMessageCodecExtensions for BadPrivateShare {
fn inner_consensus_serialize<W: Write>(&self, fd: &mut W) -> Result<(), CodecError> {
self.shared_key.inner_consensus_serialize(fd)?;
self.tuple_proof.inner_consensus_serialize(fd)
}
fn inner_consensus_deserialize<R: Read>(fd: &mut R) -> Result<Self, CodecError> {
let shared_key = Point::inner_consensus_deserialize(fd)?;
let tuple_proof = TupleProof::inner_consensus_deserialize(fd)?;
Ok(Self {
shared_key,
tuple_proof,
})
}
}

impl StacksMessageCodecExtensions for HashSet<u32> {
fn inner_consensus_serialize<W: Write>(&self, fd: &mut W) -> Result<(), CodecError> {
write_next(fd, &(self.len() as u32))?;
for i in self {
write_next(fd, i)?;
}
Ok(())
}
fn inner_consensus_deserialize<R: Read>(fd: &mut R) -> Result<Self, CodecError> {
let mut set = Self::new();
let len = read_next::<u32, _>(fd)?;
for _ in 0..len {
let i = read_next::<u32, _>(fd)?;
set.insert(i);
}
Ok(set)
}
}

impl StacksMessageCodecExtensions for DkgFailure {
fn inner_consensus_serialize<W: Write>(&self, fd: &mut W) -> Result<(), CodecError> {
match self {
DkgFailure::BadState => write_next(fd, &0u8),
DkgFailure::MissingPublicShares(shares) => {
write_next(fd, &1u8)?;
shares.inner_consensus_serialize(fd)
}
DkgFailure::BadPublicShares(shares) => {
write_next(fd, &2u8)?;
shares.inner_consensus_serialize(fd)
}
DkgFailure::MissingPrivateShares(shares) => {
write_next(fd, &3u8)?;
shares.inner_consensus_serialize(fd)
}
DkgFailure::BadPrivateShares(shares) => {
write_next(fd, &4u8)?;
write_next(fd, &(shares.len() as u32))?;
for (id, share) in shares {
write_next(fd, id)?;
share.inner_consensus_serialize(fd)?;
}
Ok(())
}
}
}
fn inner_consensus_deserialize<R: Read>(fd: &mut R) -> Result<Self, CodecError> {
let failure_type_prefix = read_next::<u8, _>(fd)?;
let failure_type = match failure_type_prefix {
0 => DkgFailure::BadState,
1 => {
let set = HashSet::<u32>::inner_consensus_deserialize(fd)?;
DkgFailure::MissingPublicShares(set)
}
2 => {
let set = HashSet::<u32>::inner_consensus_deserialize(fd)?;
DkgFailure::BadPublicShares(set)
}
3 => {
let set = HashSet::<u32>::inner_consensus_deserialize(fd)?;
DkgFailure::MissingPrivateShares(set)
}
4 => {
let mut map = HashMap::new();
let len = read_next::<u32, _>(fd)?;
for _ in 0..len {
let i = read_next::<u32, _>(fd)?;
let bad_share = BadPrivateShare::inner_consensus_deserialize(fd)?;
map.insert(i, bad_share);
}
DkgFailure::BadPrivateShares(map)
}
_ => {
return Err(CodecError::DeserializeError(format!(
"Unknown DkgFailure type prefix: {}",
failure_type_prefix
)))
}
};
Ok(failure_type)
}
}

impl StacksMessageCodecExtensions for DkgBegin {
fn inner_consensus_serialize<W: Write>(&self, fd: &mut W) -> Result<(), CodecError> {
write_next(fd, &self.dkg_id)
Expand Down Expand Up @@ -301,7 +415,7 @@ impl StacksMessageCodecExtensions for DkgEnd {
DkgStatus::Success => write_next(fd, &0u8),
DkgStatus::Failure(failure) => {
write_next(fd, &1u8)?;
write_next(fd, &failure.as_bytes().to_vec())
failure.inner_consensus_serialize(fd)
}
}
}
Expand All @@ -312,9 +426,7 @@ impl StacksMessageCodecExtensions for DkgEnd {
let status = match status_type_prefix {
0 => DkgStatus::Success,
1 => {
let failure_bytes: Vec<u8> = read_next(fd)?;
let failure = String::from_utf8(failure_bytes)
.map_err(|e| CodecError::DeserializeError(e.to_string()))?;
let failure = DkgFailure::inner_consensus_deserialize(fd)?;
DkgStatus::Failure(failure)
}
_ => {
Expand Down Expand Up @@ -1122,7 +1234,7 @@ mod test {
test_fixture_packet(Message::DkgEnd(DkgEnd {
dkg_id,
signer_id,
status: DkgStatus::Failure("failure".to_string()),
status: DkgStatus::Failure(DkgFailure::BadState),
}));

// Test DKG public shares Packet
Expand Down
13 changes: 13 additions & 0 deletions stacks-signer/src/runloop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use stacks_common::{debug, error, info, warn};
use wsts::common::{MerkleRoot, Signature};
use wsts::curve::ecdsa;
use wsts::curve::keys::PublicKey;
use wsts::curve::point::{Compressed, Point};
use wsts::net::{Message, NonceRequest, Packet, SignatureShareRequest};
use wsts::state_machine::coordinator::fire::Coordinator as FireCoordinator;
use wsts::state_machine::coordinator::{Config as CoordinatorConfig, Coordinator};
Expand Down Expand Up @@ -833,6 +834,17 @@ impl From<&Config> for RunLoop<FireCoordinator<v2::Aggregator>> {
.iter()
.map(|(i, ids)| (*i, ids.iter().copied().collect::<HashSet<u32>>()))
.collect::<HashMap<u32, HashSet<u32>>>();
let signer_public_keys = config
.signer_ids_public_keys
.signers
.iter()
.map(|(i, ecdsa_key)| {
(
*i,
Point::try_from(&Compressed::from(ecdsa_key.to_bytes())).unwrap(),
)
})
.collect::<HashMap<u32, Point>>();

let coordinator_config = CoordinatorConfig {
threshold,
Expand All @@ -846,6 +858,7 @@ impl From<&Config> for RunLoop<FireCoordinator<v2::Aggregator>> {
nonce_timeout: config.nonce_timeout,
sign_timeout: config.sign_timeout,
signer_key_ids,
signer_public_keys,
};
let coordinator = FireCoordinator::new(coordinator_config);
let signing_round = Signer::new(
Expand Down