use std::{
fmt,
io::{self, Read, Write},
};
use crate::{
address::{Address, Error as AddressError, Stream, Version as AddressVersion},
crypto::{self, PublicKey, Signature, VerifyError},
encoding::Encoding,
error::TooLongError,
feature::Features,
identity::Private as PrivateIdentity,
io::{ReadFrom, SizedReadFrom, WriteTo},
message,
pow::{NonceTrialsPerByte, PayloadLengthExtraBytes},
var_type::VarInt,
};
use crate::crypto::SignError;
#[derive(Clone, Debug)]
pub enum BroadcastError {
SignError(SignError),
}
impl fmt::Display for BroadcastError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::SignError(err) => err.fmt(f),
}
}
}
impl std::error::Error for BroadcastError {}
impl From<SignError> for BroadcastError {
fn from(err: SignError) -> Self {
Self::SignError(err)
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Broadcast {
address_version: AddressVersion,
stream_number: Stream,
behavior_bitfield: Features,
public_signing_key: PublicKey,
public_encryption_key: PublicKey,
nonce_trials_per_byte: NonceTrialsPerByte,
extra_bytes: PayloadLengthExtraBytes,
encoding: Encoding,
message: Vec<u8>,
signature: Signature,
}
impl Broadcast {
pub fn new(
header: impl AsRef<[u8]>,
identity: &PrivateIdentity,
encoding: Encoding,
message: Vec<u8>,
) -> Result<Self, BroadcastError> {
let address_version = identity.version();
let stream_number = identity.stream();
let behavior_bitfield = identity.features();
let public_signing_key = identity.public_signing_key();
let public_encryption_key = identity.public_encryption_key();
let nonce_trials_per_byte = identity.nonce_trials_per_byte();
let extra_bytes = identity.payload_length_extra_bytes();
let mut data = header.as_ref().to_vec();
address_version.write_to(&mut data).unwrap();
stream_number.write_to(&mut data).unwrap();
behavior_bitfield.write_to(&mut data).unwrap();
public_signing_key.write_to(&mut data).unwrap();
public_encryption_key.write_to(&mut data).unwrap();
if address_version.as_u64() >= 3 {
nonce_trials_per_byte.write_to(&mut data).unwrap();
extra_bytes.write_to(&mut data).unwrap();
}
encoding.write_to(&mut data).unwrap();
let len = VarInt::from(message.len());
len.write_to(&mut data).unwrap();
message.write_to(&mut data).unwrap();
let signature = crypto::sign(&data, identity.private_signing_key())?;
Ok(Self {
address_version,
stream_number,
behavior_bitfield,
public_signing_key,
public_encryption_key,
nonce_trials_per_byte,
extra_bytes,
encoding,
message,
signature,
})
}
pub fn stream_number(&self) -> Stream {
self.stream_number
}
pub fn encoding(&self) -> Encoding {
self.encoding
}
pub fn message(&self) -> &[u8] {
&self.message
}
pub fn verify(&self, signed_header: impl AsRef<[u8]>) -> Result<(), VerifyError> {
let mut data = signed_header.as_ref().to_vec();
self.address_version.write_to(&mut data).unwrap();
self.stream_number.write_to(&mut data).unwrap();
self.behavior_bitfield.write_to(&mut data).unwrap();
self.public_signing_key.write_to(&mut data).unwrap();
self.public_encryption_key.write_to(&mut data).unwrap();
if self.address_version.as_u64() >= 3 {
self.nonce_trials_per_byte.write_to(&mut data).unwrap();
self.extra_bytes.write_to(&mut data).unwrap();
}
self.encoding.write_to(&mut data).unwrap();
let len = VarInt::from(self.message.len());
len.write_to(&mut data).unwrap();
self.message.write_to(&mut data).unwrap();
crypto::verify(&data, &self.signature, &self.public_signing_key)
}
pub fn address(&self) -> Result<Address, AddressError> {
Ok(Address::from_public_keys(
self.address_version,
self.stream_number,
&self.public_signing_key,
&self.public_encryption_key,
)?)
}
}
impl WriteTo for Broadcast {
fn write_to(&self, w: &mut dyn Write) -> io::Result<()> {
self.address_version.write_to(w)?;
self.stream_number.write_to(w)?;
self.behavior_bitfield.write_to(w)?;
self.public_signing_key.write_to(w)?;
self.public_encryption_key.write_to(w)?;
if self.address_version.as_u64() >= 3 {
self.nonce_trials_per_byte.write_to(w)?;
self.extra_bytes.write_to(w)?;
}
self.encoding.write_to(w)?;
let len = VarInt::from(self.message.len());
len.write_to(w)?;
self.message.write_to(w)?;
self.signature.write_to(w)?;
Ok(())
}
}
#[allow(clippy::useless_let_if_seq)]
impl ReadFrom for Broadcast {
fn read_from(r: &mut dyn Read) -> io::Result<Self>
where
Self: Sized,
{
let address_version = AddressVersion::read_from(r)?;
let stream_number = Stream::read_from(r)?;
let behavior_bitfield = Features::read_from(r)?;
let public_signing_key = PublicKey::read_from(r)?;
let public_encryption_key = PublicKey::read_from(r)?;
let nonce_trials_per_byte;
let extra_bytes;
if address_version.as_u64() >= 3 {
nonce_trials_per_byte = NonceTrialsPerByte::read_from(r)?;
extra_bytes = PayloadLengthExtraBytes::read_from(r)?;
} else {
nonce_trials_per_byte = 1000.into();
extra_bytes = 1000.into();
}
let encoding = Encoding::read_from(r)?;
let len = VarInt::read_from(r)?;
if len.as_u64() > message::Object::MAX_OBJECT_PAYLOAD_LENGTH as u64 {
return Err(io::Error::new(
io::ErrorKind::Other,
TooLongError::new(
message::Object::MAX_OBJECT_PAYLOAD_LENGTH,
len.as_u64() as usize,
),
));
}
let message = Vec::<u8>::sized_read_from(r, len.as_u64() as usize)?;
let signature = Signature::read_from(r)?;
Ok(Self {
address_version,
stream_number,
behavior_bitfield,
public_signing_key,
public_encryption_key,
nonce_trials_per_byte,
extra_bytes,
encoding,
message,
signature,
})
}
}