use crate::Config; use commonware_codec::{EncodeSize, RangeCfg, Read, Write}; use commonware_cryptography::Hasher; use std::marker::PhantomData; use thiserror::Error; #[derive(Error, Debug)] pub enum Error { #[error("data does not match commitment")] BadData, } /// A trivial scheme which performs no coding at all. /// /// Instead, each shard contains all of the data. /// /// The commitment is simply a hash of that data. This struct is generic /// over the choice of [commonware_cryptography::Hasher]. #[derive(Clone, Copy)] pub struct NoCoding { _marker: PhantomData, } impl std::fmt::Debug for NoCoding { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("NoCoding").finish() } } #[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub struct Shard(Vec); impl EncodeSize for Shard { fn encode_size(&self) -> usize { self.0.encode_size() } } impl Write for Shard { fn write(&self, buf: &mut impl bytes::BufMut) { self.0.write(buf) } } impl Read for Shard { type Cfg = crate::CodecConfig; fn read_cfg( buf: &mut impl bytes::Buf, cfg: &Self::Cfg, ) -> Result { Vec::read_cfg(buf, &(RangeCfg::new(0..=cfg.maximum_shard_size), ())).map(Self) } } #[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub struct ReShard(()); impl EncodeSize for ReShard { fn encode_size(&self) -> usize { 0 } } impl Write for ReShard { fn write(&self, _buf: &mut impl bytes::BufMut) {} } impl Read for ReShard { type Cfg = crate::CodecConfig; fn read_cfg( _buf: &mut impl bytes::Buf, _cfg: &Self::Cfg, ) -> Result { Ok(Self(())) } } impl crate::Scheme for NoCoding { type Commitment = H::Digest; type Shard = Shard; type ReShard = ReShard; type CheckedShard = (); type CheckingData = Vec; type Error = Error; fn encode( config: &crate::Config, mut data: impl bytes::Buf, _concurrency: usize, ) -> Result<(Self::Commitment, Vec), Self::Error> { let data: Vec = data.copy_to_bytes(data.remaining()).to_vec(); let commitment = H::new().update(&data).finalize(); let shards = (0..config.total_shards()) .map(|_| Shard(data.clone())) .collect(); Ok((commitment, shards)) } fn reshard( _config: &Config, commitment: &Self::Commitment, _index: u16, shard: Self::Shard, ) -> Result<(Self::CheckingData, Self::CheckedShard, Self::ReShard), Self::Error> { let my_commitment = H::new().update(shard.0.as_slice()).finalize(); if &my_commitment != commitment { return Err(Error::BadData); } Ok((shard.0, (), ReShard(()))) } fn check( _config: &Config, _commitment: &Self::Commitment, _checking_data: &Self::CheckingData, _index: u16, _reshard: Self::ReShard, ) -> Result { Ok(()) } fn decode( _config: &Config, _commitment: &Self::Commitment, checking_data: Self::CheckingData, _shards: &[Self::CheckedShard], _concurrency: usize, ) -> Result, Self::Error> { Ok(checking_data) } } impl crate::ValidatingScheme for NoCoding {} #[cfg(all(test, feature = "arbitrary"))] mod conformance { use super::*; use commonware_codec::conformance::CodecConformance; commonware_conformance::conformance_tests! { CodecConformance, CodecConformance } }