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>;