jf_vid/
lib.rs

1// Copyright (c) 2022 Espresso Systems (espressosys.com)
2// This file is part of the Jellyfish library.
3
4// You should have received a copy of the MIT License
5// along with the Jellyfish library. If not, see <https://mit-license.org/>.
6
7//! Trait and implementation for a Verifiable Information Retrieval (VID).
8//! See <https://arxiv.org/abs/2111.12323> section 1.3--1.4 for intro to VID semantics.
9
10#![cfg_attr(not(feature = "std"), no_std)]
11// Temporarily allow warning for nightly compilation with [`displaydoc`].
12#![allow(warnings)]
13#![deny(missing_docs)]
14#[cfg(test)]
15extern crate std;
16
17#[macro_use]
18extern crate derivative;
19
20#[cfg(any(not(feature = "std"), target_has_atomic = "ptr"))]
21#[doc(hidden)]
22extern crate alloc;
23
24use ark_std::{
25    error::Error,
26    fmt::{Debug, Display},
27    hash::Hash,
28    string::String,
29    vec::Vec,
30};
31use displaydoc::Display;
32use serde::{de::DeserializeOwned, Deserialize, Serialize};
33use tagged_base64::TaggedBase64;
34
35/// VID: Verifiable Information Dispersal
36pub trait VidScheme {
37    /// Payload commitment.
38    type Commit: Clone
39        + Debug
40        + Display
41        + DeserializeOwned
42        + Eq
43        + PartialEq
44        + Hash
45        + Serialize
46        + Sync
47        + for<'a> TryFrom<&'a TaggedBase64>
48        + Into<TaggedBase64>; // TODO https://github.com/EspressoSystems/jellyfish/issues/253
49
50    /// Share-specific data sent to a storage node.
51    type Share: Clone + Debug + DeserializeOwned + Eq + PartialEq + Hash + Serialize + Sync; // TODO https://github.com/EspressoSystems/jellyfish/issues/253
52
53    /// Common data sent to all storage nodes.
54    type Common: Clone + Debug + DeserializeOwned + Eq + PartialEq + Hash + Serialize + Sync; // TODO https://github.com/EspressoSystems/jellyfish/issues/253
55
56    /// Compute a payload commitment
57    fn commit_only<B>(&mut self, payload: B) -> VidResult<Self::Commit>
58    where
59        B: AsRef<[u8]>;
60
61    /// Compute shares to send to the storage nodes
62    fn disperse<B>(&mut self, payload: B) -> VidResult<VidDisperse<Self>>
63    where
64        B: AsRef<[u8]>;
65
66    /// Verify a share. Used by both storage node and retrieval client.
67    /// Why is return type a nested `Result`? See <https://sled.rs/errors>
68    /// Returns:
69    /// - VidResult::Err in case of actual error
70    /// - VidResult::Ok(Result::Err) if verification fails
71    /// - VidResult::Ok(Result::Ok) if verification succeeds
72    fn verify_share(
73        &self,
74        share: &Self::Share,
75        common: &Self::Common,
76        commit: &Self::Commit,
77    ) -> VidResult<Result<(), ()>>;
78
79    /// Recover payload from shares.
80    /// Do not verify shares or check recovered payload against anything.
81    fn recover_payload(&self, shares: &[Self::Share], common: &Self::Common) -> VidResult<Vec<u8>>;
82
83    /// Check that a [`VidScheme::Common`] is consistent with a
84    /// [`VidScheme::Commit`].
85    ///
86    /// TODO conform to nested result pattern like [`VidScheme::verify_share`].
87    /// Unfortunately, `VidResult<()>` is more user-friently.
88    fn is_consistent(commit: &Self::Commit, common: &Self::Common) -> VidResult<()>;
89
90    /// Extract the payload byte length data from a [`VidScheme::Common`].
91    fn get_payload_byte_len(common: &Self::Common) -> u32;
92
93    /// Extract the number of storage nodes from a [`VidScheme::Common`].
94    fn get_num_storage_nodes(common: &Self::Common) -> u32;
95
96    /// Extract the number of poly evals per share [`VidScheme::Common`].
97    fn get_multiplicity(common: &Self::Common) -> u32;
98}
99
100/// Convenience struct to aggregate disperse data.
101///
102/// Return type for [`VidScheme::disperse`].
103///
104/// # Why the `?Sized` bound?
105/// Rust hates you: <https://stackoverflow.com/a/54465962>
106#[derive(Derivative, Deserialize, Serialize)]
107#[serde(bound = "V::Share: Serialize + for<'a> Deserialize<'a>,
108     V::Common: Serialize + for<'a> Deserialize<'a>,
109     V::Commit: Serialize + for<'a> Deserialize<'a>,")]
110// Somehow these bizarre bounds suffice for downstream derivations
111#[derivative(
112    Clone(bound = ""),
113    Debug(bound = "V::Share: Debug, V::Common: Debug, V::Commit: Debug"),
114    Eq(bound = ""),
115    Hash(bound = "V::Share: Hash, V::Common: Hash, V::Commit: Hash"),
116    PartialEq(bound = "")
117)]
118pub struct VidDisperse<V: VidScheme + ?Sized> {
119    /// VID disperse shares to send to the storage nodes.
120    pub shares: Vec<V::Share>,
121    /// VID common data to send to all storage nodes.
122    pub common: V::Common,
123    /// VID payload commitment.
124    pub commit: V::Commit,
125}
126pub mod precomputable;
127
128pub mod payload_prover;
129
130pub mod advz; // instantiation of `VidScheme`
131
132// BOILERPLATE: error handling
133
134/// The error type for `VidScheme` methods.
135#[derive(Display, Debug)]
136pub enum VidError {
137    /// invalid args: {0}
138    Argument(String),
139    /// internal error: {0}
140    Internal(anyhow::Error),
141}
142
143impl Error for VidError {}
144
145/// Convenience wrapper to convert any error into a [`VidError`].
146///
147/// Private fn so as not to expose error conversion API outside this crate
148/// as per [stackoverflow](https://stackoverflow.com/a/70057677).
149///
150/// # No-std support
151/// `no_std` mode requires `.map_err(vid)` to convert from a non-`anyhow` error
152/// as per [`anyhow` docs](https://docs.rs/anyhow/latest/anyhow/index.html#no-std-support),
153fn vid<E>(e: E) -> VidError
154where
155    E: ark_std::fmt::Display + Debug + Send + Sync + 'static,
156{
157    VidError::Internal(anyhow::anyhow!(e))
158}
159
160/// Convenience [`Result`] wrapper for [`VidError`].
161pub type VidResult<T> = Result<T, VidError>;