Skip to content
Snippets Groups Projects

Draft: Doc joss

Closed PERENNOU Tanguy requested to merge doc-joss into main
+ 125
23
@@ -144,6 +144,40 @@ impl<F: PrimeField> Shard<F> {
/// Fr::from(3*0 + 5*3 + 7*5),
/// Fr::from(3*0 + 5*0 + 7*7)]);
/// ```
///
/// # Errors
///
///
/// - The shards must have have the same `k`, `hash` or `size`, otherwise this
/// function will return a [`KomodoError::IncompatibleShards`] indicating the
/// reason. This typically happens when shards from different data are mixed:
/// then at least the hashes are different.
///
/// ```rust
/// # use ark_bls12_381::Fr;
/// # use komodo::fec::{encode, recode_with_coeffs};
/// # use komodo::algebra::linalg::Matrix;
/// # use komodo::error::KomodoError;
/// #
/// // encode 5 shards for data1 and data2 using a 3x5 Vandermonde encoding matrix
/// # let points = [Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3), Fr::from(4)];
/// # let encoding_mat = Matrix::vandermonde(&points, 3).unwrap();
/// let data1 = b"hello world";
/// let shards1 = encode::<Fr>(data1, &encoding_mat).unwrap();
/// let data2 = b"bonjour monde!";
/// let shards2 = encode::<Fr>(data2, &encoding_mat).unwrap();
///
/// // attempt to recode from a subset of shards from both data1 and data2
/// let bad_mix_subset = vec![shards1[0].clone(), shards1[1].clone(), shards2[2].clone()];
/// let coeffs = vec![Fr::from(3), Fr::from(5), Fr::from(7)];
/// let recoded = recode_with_coeffs::<Fr>(&bad_mix_subset, &coeffs);
/// assert_eq!(recoded, None);
/// # // FIXME: incompatible shards should be signalled somehow
/// # // assert!(matches!(recoded, Err(KomodoError::IncompatibleShards(_))));
/// # // let err_string = recoded.unwrap_err().to_string();
/// # // assert!(err_string.starts_with("Shards are incompatible:"));
/// # // assert!(err_string.contains("hash is not the same"));
pub fn recode_with_coeffs<F: PrimeField>(shards: &[Shard<F>], coeffs: &[F]) -> Option<Shard<F>> {
if shards.len() != coeffs.len() {
return None;
@@ -191,7 +225,36 @@ pub fn recode_with_coeffs<F: PrimeField>(shards: &[Shard<F>], coeffs: &[F]) -> O
/// ```
///
/// # Errors
/// - if the shards do not have the same `k`, `hash` or `size`: [`KomodoError::IncompatibleShards`]
///
/// - The shards must have have the same `k`, `hash` or `size`, otherwise this
/// function will return a [`KomodoError::IncompatibleShards`] indicating the
/// reason. This typically happens when shards from different data are mixed:
/// then at least the hashes are different.
///
/// ```rust
/// # use ark_bls12_381::Fr;
/// # use komodo::fec::{encode, recode_random};
/// # use komodo::algebra::linalg::Matrix;
/// # use komodo::error::KomodoError;
/// #
/// // encode 5 shards for data1 and data2 using a 3x5 Vandermonde encoding matrix
/// # let points = [Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3), Fr::from(4)];
/// # let encoding_mat = Matrix::vandermonde(&points, 3).unwrap();
/// let data1 = b"hello world";
/// let shards1 = encode::<Fr>(data1, &encoding_mat).unwrap();
/// let data2 = b"bonjour monde!";
/// let shards2 = encode::<Fr>(data2, &encoding_mat).unwrap();
///
/// // attempt to recode from a subset of shards from both data1 and data2
/// let bad_mix_subset = vec![shards1[0].clone(), shards1[1].clone(), shards2[2].clone()];
/// let rng = &mut ark_std::test_rng();
/// let recoded = recode_random::<Fr>(&bad_mix_subset, rng);
///
/// assert!(matches!(recoded, Err(KomodoError::IncompatibleShards(_))));
/// let err_string = recoded.unwrap_err().to_string();
/// assert!(err_string.starts_with("Shards are incompatible:"));
/// assert!(err_string.contains("hash is not the same"));
/// ```
pub fn recode_random<F: PrimeField>(
shards: &[Shard<F>],
rng: &mut impl RngCore,
@@ -276,7 +339,6 @@ pub fn recode_random<F: PrimeField>(
/// // 0, 1, 4, 9, 16,
///
/// let shards = encode::<Fr>(data, &encoding_mat).unwrap();
/// #
/// # assert_eq!(shards.len(), 5);
/// # for shard in &shards[0..4] {
/// # assert_eq!(shard.k, 3);
@@ -307,6 +369,18 @@ pub fn recode_random<F: PrimeField>(
/// # }
/// ```
///
/// # Errors
///
/// Actually, _[`encode`] cannot return a [`KomodoError`]_. It declares so in
/// its signature because internally, is calls two methods that under certain
/// conditions return [`KomodoError`]:
/// - [`Matrix::from_vec_vec`] returns [`KomodoError::InvalidMatrixElements`] if
/// the vec vec has rows with different lengths; this cannot actually happen
/// in this context because the rows are computed with
/// [`algebra::split_data_into_field_elements`].
/// - [`Matrix::mul`] returns [`KomodoError::IncompatibleMatrixShapes`] if the
/// operands have incompatible shapes; this cannot happen either, because the
/// height of the encoding matrix is used to split the data into vectors.
pub fn encode<F: PrimeField>(
data: &[u8],
encoding_mat: &Matrix<F>,
@@ -338,13 +412,14 @@ pub fn encode<F: PrimeField>(
.collect())
}
/// Reconstruct the original data from a set of encoded, possibly recoded, shards.
/// Reconstruct the original data from a set of encoded, possibly recoded,
/// shards.
///
/// This is the inverse of [`encode`].
///
/// # Example
///
/// ## Succesful decoding
/// When shards originate from the same data, decoding will be successful.
///
/// ```rust
/// use ark_bls12_381::Fr;
@@ -363,7 +438,32 @@ pub fn encode<F: PrimeField>(
/// assert_eq!(data.to_vec(), decoded);
/// ```
///
/// ## Unsuccessful decoding due to insufficient amount of shards
/// # Errors
///
/// - At least 1 shard should be provided, otherwise this function will return a
/// [`KomodoError::TooFewShards`]
///
/// ```rust
/// # use ark_bls12_381::Fr;
/// # use komodo::fec::{encode, decode};
/// # use komodo::algebra::linalg::Matrix;
/// use komodo::error::KomodoError;
///
/// # // encode 5 shards for data using a 3x5 Vandermonde encoding matrix
/// # let data = b"hello world";
/// # let points = [Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3), Fr::from(4)];
/// # let encoding_mat = Matrix::vandermonde(&points, 3).unwrap();
/// # let shards = encode::<Fr>(data, &encoding_mat).unwrap();
/// #
/// // decode from an empty set of shards (3 needed)
/// let empty_set = vec![];
/// let decoded = decode::<Fr>(empty_set);
/// assert_eq!(decoded, Err(KomodoError::TooFewShards(0, 0)));
/// ```
///
/// - At least $k$ shards are needed to decode, otherwise this function will
/// return a [`KomodoError::TooFewShards`] indicating the actual and expected
/// number of shards. $k$ is read from the first passed shard.
///
/// ```rust
/// # use ark_bls12_381::Fr;
@@ -379,11 +479,14 @@ pub fn encode<F: PrimeField>(
/// #
/// // decode from a subset of 2 shards (3 needed)
/// let short_subset = vec![shards[3].clone(), shards[4].clone()];
/// let err = decode::<Fr>(short_subset).unwrap_err();
/// assert!(matches!(err, KomodoError::TooFewShards(2, 3)));
/// let decoded = decode::<Fr>(short_subset);
/// assert_eq!(decoded, Err(KomodoError::TooFewShards(2, 3)));
/// ```
///
/// ## Unsuccessful decoding due to linear dependencies
/// - The shards used for decoding must not be linearly dependent, otherwise
/// this function will return a [`KomodoError::NonInvertibleMatrix`]
/// indicating the actual rank of the computed decoding matrix and the
/// expected rank.
///
/// ```rust
/// # use ark_bls12_381::Fr;
@@ -397,15 +500,18 @@ pub fn encode<F: PrimeField>(
/// # let encoding_mat = Matrix::vandermonde(&points, 3).unwrap();
/// # let shards = encode::<Fr>(data, &encoding_mat).unwrap();
/// #
/// // attempt to decode from a subset of 3 linearly dependent shards (2 identical shards, rank only 2)
/// // attempt to decode from a subset of 3 linearly dependent shards:
/// // 2 shards are identical, so the actual rank of the decoding matrix is 2 instead of 3
/// let dependent_subset = vec![shards[0].clone(), shards[1].clone(), shards[0].clone()];
/// let err = decode::<Fr>(dependent_subset).unwrap_err();
/// assert!(matches!(err, KomodoError::NonInvertibleMatrix(2)));
/// let decoded = decode::<Fr>(dependent_subset);
/// assert_eq!(decoded, Err(KomodoError::NonInvertibleMatrix(2)));
/// ```
///
/// ## Unsuccessful decoding due to bad mix of shards
///
/// When the shards were not generated from the same data, decoding will fail.
/// - The shards must have have the same `k`, `hash` or `size`, otherwise this
/// function will return a [`KomodoError::IncompatibleShards`] indicating the
/// reason. This typically happens when shards from different data are mixed:
/// then at least the hashes are different.
///
/// ```rust
/// # use ark_bls12_381::Fr;
@@ -423,16 +529,12 @@ pub fn encode<F: PrimeField>(
///
/// // attempt to decode from a subset of shards from both data1 and data2
/// let bad_mix_subset = vec![shards1[0].clone(), shards1[1].clone(), shards2[2].clone()];
/// let err = decode::<Fr>(bad_mix_subset).unwrap_err();
/// assert!(matches!(err, KomodoError::IncompatibleShards(_)));
/// let decoded = decode::<Fr>(bad_mix_subset);
/// assert!(matches!(decoded, Err(KomodoError::IncompatibleShards(_))));
/// let err_string = decoded.unwrap_err().to_string();
/// assert!(err_string.starts_with("Shards are incompatible:"));
/// assert!(err_string.contains("hash is not the same"));
/// ```
///
/// # Errors
/// - if there are no shards: [`KomodoError::TooFewShards`]
/// - if the shards do not have the same `k`, `hash` or `size`: [`KomodoError::IncompatibleShards`]
/// - if there are less too few shards, i.e. less than `k` shards, reading `k` from
/// the first shard: [`KomodoError::TooFewShards`]
/// - if there are linear dependencies between shards: [`KomodoError::NonInvertibleMatrix`]
pub fn decode<F: PrimeField>(shards: Vec<Shard<F>>) -> Result<Vec<u8>, KomodoError> {
if shards.is_empty() {
return Err(KomodoError::TooFewShards(0, 0));
Loading