pub trait PhasedScheme:
Debug
+ Clone
+ Send
+ Sync
+ 'static {
type Commitment: Digest;
type StrongShard: Clone + Debug + Eq + Codec<Cfg = CodecConfig> + Send + Sync + 'static;
type WeakShard: Clone + Debug + Eq + Codec<Cfg = CodecConfig> + Send + Sync + 'static;
type CheckingData: Clone + Eq + Send + Sync;
type CheckedShard: Clone + Send + Sync;
type Error: Debug + Send;
// Required methods
fn encode(
config: &Config,
data: impl Buf,
strategy: &impl Strategy,
) -> Result<(Self::Commitment, Vec<Self::StrongShard>), Self::Error>;
fn weaken(
config: &Config,
commitment: &Self::Commitment,
index: u16,
shard: Self::StrongShard,
) -> Result<(Self::CheckingData, Self::CheckedShard, Self::WeakShard), Self::Error>;
fn check(
config: &Config,
commitment: &Self::Commitment,
checking_data: &Self::CheckingData,
index: u16,
weak_shard: Self::WeakShard,
) -> Result<Self::CheckedShard, Self::Error>;
fn decode<'a>(
config: &Config,
commitment: &Self::Commitment,
checking_data: Self::CheckingData,
shards: impl Iterator<Item = &'a Self::CheckedShard>,
strategy: &impl Strategy,
) -> Result<Vec<u8>, Self::Error>;
}Expand description
A phased coding interface with separate local and forwarded shard handling.
This trait models schemes where the initial distributor attaches extra verification material to each participant’s strong shard. Participants derive checking data from that strong shard, then use it to validate weaker forwarded shards received from others before reconstruction.
The tradeoff compared to Scheme is that weak shards cannot be
verified independently. A participant must first derive
PhasedScheme::CheckingData from a strong shard via
PhasedScheme::weaken.
§Example
use commonware_coding::{Config, PhasedScheme as _, Zoda};
use commonware_cryptography::Sha256;
use commonware_parallel::Sequential;
use commonware_utils::NZU16;
const STRATEGY: Sequential = Sequential;
type Z = Zoda<Sha256>;
let config = Config {
minimum_shards: NZU16!(2),
extra_shards: NZU16!(1),
};
let data = b"Hello!";
let (commitment, mut shards) = Z::encode(&config, data.as_slice(), &STRATEGY).unwrap();
let (checking_data, checked_0, _) =
Z::weaken(&config, &commitment, 0, shards.remove(0)).unwrap();
let (_, _, weak_1) = Z::weaken(&config, &commitment, 1, shards.remove(0)).unwrap();
let checked_1 = Z::check(&config, &commitment, &checking_data, 1, weak_1).unwrap();
let data2 = Z::decode(
&config,
&commitment,
checking_data,
[checked_0, checked_1].iter(),
&STRATEGY,
)
.unwrap();
assert_eq!(&data[..], &data2[..]);§Guarantees
Here are additional properties that implementors of this trait need to consider, and that users of this trait can rely on.
§Weaken vs Check
PhasedScheme::weaken and PhasedScheme::check should agree, even for malicious encoders.
It should not be possible for parties A and B to call weaken successfully,
but then have either of them fail on the other’s shard when calling check.
In other words, if an honest party considers their shard to be correctly formed, then other honest parties which have successfully constructed their checking data will also agree with the shard being correct.
A violation of this property would be, for example, if a malicious payload could convince two parties that they both have valid shards, but then the checking data they produce from the malicious payload reports issues with those shards.
Required Associated Types§
Sourcetype Commitment: Digest
type Commitment: Digest
A commitment attesting to the shards of data.
Sourcetype StrongShard: Clone + Debug + Eq + Codec<Cfg = CodecConfig> + Send + Sync + 'static
type StrongShard: Clone + Debug + Eq + Codec<Cfg = CodecConfig> + Send + Sync + 'static
A strong shard of data, to be received by a participant.
Sourcetype WeakShard: Clone + Debug + Eq + Codec<Cfg = CodecConfig> + Send + Sync + 'static
type WeakShard: Clone + Debug + Eq + Codec<Cfg = CodecConfig> + Send + Sync + 'static
A weak shard shared with other participants, to aid them in reconstruction.
In most cases, this will be the same as StrongShard, but some schemes might
have extra information in StrongShard that may not be necessary to reconstruct
the data.
Sourcetype CheckedShard: Clone + Send + Sync
type CheckedShard: Clone + Send + Sync
A shard that has been checked for inclusion in the commitment.
This allows excluding PhasedScheme::WeakShards which are invalid, and shouldn’t
be considered as progress towards meeting the minimum number of shards.
Required Methods§
Sourcefn encode(
config: &Config,
data: impl Buf,
strategy: &impl Strategy,
) -> Result<(Self::Commitment, Vec<Self::StrongShard>), Self::Error>
fn encode( config: &Config, data: impl Buf, strategy: &impl Strategy, ) -> Result<(Self::Commitment, Vec<Self::StrongShard>), Self::Error>
Encode a piece of data, returning a commitment, along with shards, and proofs.
Each shard and proof is intended for exactly one participant. The number of shards returned
should equal config.minimum_shards + config.extra_shards.
Sourcefn weaken(
config: &Config,
commitment: &Self::Commitment,
index: u16,
shard: Self::StrongShard,
) -> Result<(Self::CheckingData, Self::CheckedShard, Self::WeakShard), Self::Error>
fn weaken( config: &Config, commitment: &Self::Commitment, index: u16, shard: Self::StrongShard, ) -> Result<(Self::CheckingData, Self::CheckedShard, Self::WeakShard), Self::Error>
Take your own shard, check it, and produce a PhasedScheme::WeakShard to forward to others.
This takes in an index, which is the index you expect the shard to be.
This will produce a PhasedScheme::CheckedShard which counts towards the minimum
number of shards you need to reconstruct the data, in PhasedScheme::decode.
You also get PhasedScheme::CheckingData, which has information you can use to check
the shards you receive from others.
Sourcefn check(
config: &Config,
commitment: &Self::Commitment,
checking_data: &Self::CheckingData,
index: u16,
weak_shard: Self::WeakShard,
) -> Result<Self::CheckedShard, Self::Error>
fn check( config: &Config, commitment: &Self::Commitment, checking_data: &Self::CheckingData, index: u16, weak_shard: Self::WeakShard, ) -> Result<Self::CheckedShard, Self::Error>
Check the integrity of a weak shard, producing a checked shard.
This requires the PhasedScheme::CheckingData produced by PhasedScheme::weaken.
This takes in an index, to make sure that the weak shard you’re checking is associated with the participant you expect it to be.
Sourcefn decode<'a>(
config: &Config,
commitment: &Self::Commitment,
checking_data: Self::CheckingData,
shards: impl Iterator<Item = &'a Self::CheckedShard>,
strategy: &impl Strategy,
) -> Result<Vec<u8>, Self::Error>
fn decode<'a>( config: &Config, commitment: &Self::Commitment, checking_data: Self::CheckingData, shards: impl Iterator<Item = &'a Self::CheckedShard>, strategy: &impl Strategy, ) -> Result<Vec<u8>, Self::Error>
Decode the data from shards received from other participants.
The data must be decodeable with as few as config.minimum_shards,
including your own shard.
Calls to this function with the same commitment, but with different shards, or shards in a different should also result in the same output data, or in failure. In other words, when using the decoding function in a broader system, you get a guarantee that every participant decoding will see the same final data, even if they receive different shards, or receive them in a different order.
§Commitment Binding
Implementations must reject shards that were checked against a different
commitment than the one passed to decode. Mixing checked shards from
separate encode calls (and thus different commitments) must return an
error.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.