frost/frost-redjubjub/src/messages/validate.rs

144 lines
5.1 KiB
Rust
Raw Normal View History

Implement the messages spec (#114) * start messages and validation * add missing docs to constants * change validation to matches, fix constant doc Co-authored-by: teor <teor@riseup.net> * fix the build * validate share_commitment * add new constants and validations * fix validation * derive serde Serialize and Deserialize in all messages structs * update created structs Co-authored-by: teor <teor@riseup.net> * fix build * define and use a new MAX_SIGNERS constant * change group_public type * add some test cases * add validation and serialization tests for SigningCommitments * add validation and serialization test to SigningPackage * change some fields order matching the spec * fix field order in tests according to last updates to the spec * implement serialize and deserialize for ParticipantId * move serde-json to dev-dependencies section * change to pub(crate) * fix serialize of VerificationKey * add assert to serialize * add note, fix typo * improve some code in tests * test serialization of individual fields * start messages and validation * add missing docs to constants * change validation to matches, fix constant doc Co-authored-by: teor <teor@riseup.net> * fix the build * validate share_commitment * add new constants and validations * fix validation * define and use a new MAX_SIGNERS constant * change group_public type * change some fields order matching the spec * change message fields to new spec * remove some non needed conversions * use a BTreeMap to guarantee the order * remove some calls to `clone()` by implementing `Copy` * change message type in frost and add validate_signatureshare test * change `share_commitment` to BTreeMap * add `serialize_signatureshare` test * add aggregatesignature tests * add some test header messages utility functions * add a setup utility * move the general serialization checks into an utility function * fi some typos * add and use a `generate_share_commitment` utility * add create_signing_commitments utility function * improve the serialization tests * make room for prop tests * add arbitrary tests for serialization * remove allow dead code from messages * fix some imports * make signature module public only to the crate * simplify a bit the frost tests * improve the generated docs * add a `prop_filter` to Header arbitrary * (ab)use proptest_derive * improve validation for Message * improve some utility functions * change frost to serialization id conversion * add a quick btreemap test * change the `MsgType` to `u32` * add no leftover bytes checks * add a full_setup utility * add map len checks Co-authored-by: teor <teor@riseup.net>
2021-06-16 12:13:23 -07:00
//! Validation rules specified in [RFC-001#rules]
//!
//! [RFC-001#rules]: https://github.com/ZcashFoundation/redjubjub/blob/main/rfcs/0001-messages.md#rules
use super::constants::{
BASIC_FROST_SERIALIZATION, MAX_SIGNERS, MIN_SIGNERS, MIN_THRESHOLD,
ZCASH_MAX_PROTOCOL_MESSAGE_LEN,
};
use super::*;
use thiserror::Error;
pub trait Validate {
fn validate(&self) -> Result<&Self, MsgErr>;
}
impl Validate for Message {
fn validate(&self) -> Result<&Self, MsgErr> {
match self.payload {
Payload::SharePackage(_) => {
if self.header.sender != ParticipantId::Dealer {
return Err(MsgErr::SenderMustBeDealer);
}
if !matches!(self.header.receiver, ParticipantId::Signer(_)) {
return Err(MsgErr::ReceiverMustBeSigner);
}
}
Payload::SigningCommitments(_) => {
if !matches!(self.header.sender, ParticipantId::Signer(_)) {
return Err(MsgErr::SenderMustBeSigner);
}
if self.header.receiver != ParticipantId::Aggregator {
return Err(MsgErr::ReceiverMustBeAggregator);
}
}
Payload::SigningPackage(_) => {
if self.header.sender != ParticipantId::Aggregator {
return Err(MsgErr::SenderMustBeAggregator);
}
if !matches!(self.header.receiver, ParticipantId::Signer(_)) {
return Err(MsgErr::ReceiverMustBeSigner);
}
}
Payload::SignatureShare(_) => {
if !matches!(self.header.sender, ParticipantId::Signer(_)) {
return Err(MsgErr::SenderMustBeSigner);
}
if self.header.receiver != ParticipantId::Aggregator {
return Err(MsgErr::ReceiverMustBeAggregator);
}
}
Payload::AggregateSignature(_) => {
if self.header.sender != ParticipantId::Aggregator {
return Err(MsgErr::SenderMustBeAggregator);
}
if !matches!(self.header.receiver, ParticipantId::Signer(_)) {
return Err(MsgErr::ReceiverMustBeSigner);
}
}
}
self.header.validate()?;
self.payload.validate()?;
Ok(self)
}
}
impl Validate for Header {
fn validate(&self) -> Result<&Self, MsgErr> {
// Validate the message version.
// By now we only have 1 valid version so we compare against that.
if self.version != BASIC_FROST_SERIALIZATION {
return Err(MsgErr::WrongVersion);
}
// Make sure the sender and the receiver are not the same.
if self.sender == self.receiver {
return Err(MsgErr::SameSenderAndReceiver);
}
Ok(self)
}
}
impl Validate for Payload {
fn validate(&self) -> Result<&Self, MsgErr> {
match self {
Payload::SharePackage(share_package) => {
if share_package.share_commitment.len() < MIN_SIGNERS {
return Err(MsgErr::NotEnoughCommitments(MIN_SIGNERS));
}
if share_package.share_commitment.len() > MAX_SIGNERS.into() {
return Err(MsgErr::TooManyCommitments);
}
}
Payload::SigningCommitments(_) => {}
Payload::SigningPackage(signing_package) => {
if signing_package.message.len() > ZCASH_MAX_PROTOCOL_MESSAGE_LEN {
return Err(MsgErr::MsgTooBig);
}
if signing_package.signing_commitments.len() < MIN_THRESHOLD {
return Err(MsgErr::NotEnoughCommitments(MIN_THRESHOLD));
}
if signing_package.signing_commitments.len() > MAX_SIGNERS.into() {
return Err(MsgErr::TooManyCommitments);
}
}
Payload::SignatureShare(_) => {}
Payload::AggregateSignature(_) => {}
}
Ok(self)
}
}
/// The error a message can produce if it fails validation.
#[derive(Error, Debug, PartialEq)]
pub enum MsgErr {
#[error("wrong version number")]
WrongVersion,
#[error("sender and receiver are the same")]
SameSenderAndReceiver,
#[error("the sender of this message must be the dealer")]
SenderMustBeDealer,
#[error("the receiver of this message must be a signer")]
ReceiverMustBeSigner,
#[error("the sender of this message must be a signer")]
SenderMustBeSigner,
#[error("the receiver of this message must be the aggregator")]
ReceiverMustBeAggregator,
#[error("the sender of this message must be the aggregator")]
SenderMustBeAggregator,
#[error("the number of signers must be at least {0}")]
NotEnoughCommitments(usize),
#[error("the number of signers can't be more than {}", MAX_SIGNERS)]
TooManyCommitments,
#[error(
"the message field can't be bigger than {}",
ZCASH_MAX_PROTOCOL_MESSAGE_LEN
)]
MsgTooBig,
}