hotshot_types/vid/
advz.rs

1// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
2// This file is part of the HotShot repository.
3
4// You should have received a copy of the MIT License
5// along with the HotShot repository. If not, see <https://mit-license.org/>.
6
7//! Provides the implementation for ADVZ VID scheme
8
9use std::{fmt::Debug, ops::Range};
10
11use ark_bn254::Bn254;
12use jf_pcs::{
13    prelude::{UnivariateKzgPCS, UnivariateUniversalParams},
14    PolynomialCommitmentScheme,
15};
16use jf_vid::{
17    advz::{
18        self,
19        payload_prover::{LargeRangeProof, SmallRangeProof},
20    },
21    payload_prover::{PayloadProver, Statement},
22    VidDisperse, VidResult, VidScheme,
23};
24use lazy_static::lazy_static;
25use serde::{Deserialize, Serialize};
26use sha2::Sha256;
27
28use crate::constants::SRS_DEGREE;
29
30/// VID scheme constructor.
31///
32/// Returns an opaque type that impls jellyfish traits:
33/// [`VidScheme`], [`PayloadProver`], [`Precomputable`].
34///
35/// # Rust forbids naming impl Trait in return types
36///
37/// Due to Rust limitations the return type of [`vid_scheme`] is a newtype
38/// wrapper [`VidSchemeType`] that impls the above traits.
39///
40/// We prefer that the return type of [`vid_scheme`] be `impl Trait` for the
41/// above traits. But the ability to name an impl Trait return type is
42/// currently missing from Rust:
43/// - [Naming impl trait in return types - Impl trait initiative](https://rust-lang.github.io/impl-trait-initiative/explainer/rpit_names.html)
44/// - [RFC: Type alias impl trait (TAIT)](https://github.com/rust-lang/rfcs/blob/master/text/2515-type_alias_impl_trait.md)
45///
46/// # Panics
47/// When the construction fails for the underlying VID scheme.
48#[must_use]
49#[memoize::memoize(SharedCache, Capacity: 10)]
50pub fn advz_scheme(num_storage_nodes: usize) -> ADVZScheme {
51    // recovery_threshold is currently num_storage_nodes rounded down to a power of two
52    // TODO recovery_threshold should be a function of the desired erasure code rate
53    // https://github.com/EspressoSystems/HotShot/issues/2152
54    let recovery_threshold = 1 << num_storage_nodes.ilog2();
55
56    #[allow(clippy::panic)]
57    let num_storage_nodes = u32::try_from(num_storage_nodes).unwrap_or_else(|err| {
58        panic!(
59            "num_storage_nodes {num_storage_nodes} should fit into u32; \
60                error: {err}"
61        )
62    });
63
64    // TODO panic, return `Result`, or make `new` infallible upstream (eg. by panicking)?
65    #[allow(clippy::panic)]
66    ADVZScheme(
67        Advz::new(num_storage_nodes, recovery_threshold, &*KZG_SRS).unwrap_or_else(|err| {
68              panic!("advz construction failure: (num_storage nodes,recovery_threshold)=({num_storage_nodes},{recovery_threshold}); \
69                      error: {err}")
70        })
71    )
72}
73
74/// VID commitment type
75pub type ADVZCommitment = <ADVZScheme as VidScheme>::Commit;
76/// VID common type
77pub type ADVZCommon = <ADVZScheme as VidScheme>::Common;
78/// VID share type
79pub type ADVZShare = <ADVZScheme as VidScheme>::Share;
80
81#[cfg(not(feature = "gpu-vid"))]
82/// Internal Jellyfish VID scheme
83type Advz = advz::Advz<E, H>;
84#[cfg(feature = "gpu-vid")]
85/// Internal Jellyfish VID scheme
86type Advz = advz::AdvzGPU<'static, E, H>;
87
88/// Newtype wrapper for a VID scheme type that impls
89/// [`VidScheme`], [`PayloadProver`], [`Precomputable`].
90#[derive(Clone)]
91pub struct ADVZScheme(Advz);
92
93/// Newtype wrapper for a large payload range proof.
94///
95/// Useful for namespace proofs.
96#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
97pub struct LargeRangeProofType(
98    // # Type complexity
99    //
100    // Jellyfish's `LargeRangeProof` type has a prime field generic parameter `F`.
101    // This `F` is determined by the type parameter `E` for `Advz`.
102    // Jellyfish needs a more ergonomic way for downstream users to refer to this type.
103    //
104    // There is a `KzgEval` type alias in jellyfish that helps a little, but it's currently private:
105    // <https://github.com/EspressoSystems/jellyfish/issues/423>
106    // If it were public then we could instead use
107    // `LargeRangeProof<KzgEval<E>>`
108    // but that's still pretty crufty.
109    LargeRangeProof<<UnivariateKzgPCS<E> as PolynomialCommitmentScheme>::Evaluation>,
110);
111
112/// Newtype wrapper for a small payload range proof.
113///
114/// Useful for transaction proofs.
115#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
116pub struct SmallRangeProofType(
117    // # Type complexity
118    //
119    // Similar to the comments in `LargeRangeProofType`.
120    SmallRangeProof<<UnivariateKzgPCS<E> as PolynomialCommitmentScheme>::Proof>,
121);
122
123// By default, use SRS from Aztec's ceremony
124lazy_static! {
125    /// SRS comment
126    static ref KZG_SRS: UnivariateUniversalParams<E> = {
127        let srs = ark_srs::kzg10::aztec20::setup(SRS_DEGREE)
128            .expect("Aztec SRS failed to load");
129        UnivariateUniversalParams {
130            powers_of_g: srs.powers_of_g,
131            h: srs.h,
132            beta_h: srs.beta_h,
133            powers_of_h: vec![srs.h, srs.beta_h],
134        }
135    };
136}
137
138/// Private type alias for the EC pairing type parameter for [`Advz`].
139type E = Bn254;
140/// Private type alias for the hash type parameter for [`Advz`].
141type H = Sha256;
142
143// THE REST OF THIS FILE IS BOILERPLATE
144//
145// All this boilerplate can be deleted when we finally get
146// type alias impl trait (TAIT):
147// [rfcs/text/2515-type_alias_impl_trait.md at master ยท rust-lang/rfcs](https://github.com/rust-lang/rfcs/blob/master/text/2515-type_alias_impl_trait.md)
148impl VidScheme for ADVZScheme {
149    type Commit = <Advz as VidScheme>::Commit;
150    type Share = <Advz as VidScheme>::Share;
151    type Common = <Advz as VidScheme>::Common;
152
153    fn commit_only<B>(&mut self, payload: B) -> VidResult<Self::Commit>
154    where
155        B: AsRef<[u8]>,
156    {
157        self.0.commit_only(payload)
158    }
159
160    fn disperse<B>(&mut self, payload: B) -> VidResult<VidDisperse<Self>>
161    where
162        B: AsRef<[u8]>,
163    {
164        self.0.disperse(payload).map(vid_disperse_conversion)
165    }
166
167    fn verify_share(
168        &self,
169        share: &Self::Share,
170        common: &Self::Common,
171        commit: &Self::Commit,
172    ) -> VidResult<Result<(), ()>> {
173        self.0.verify_share(share, common, commit)
174    }
175
176    fn recover_payload(&self, shares: &[Self::Share], common: &Self::Common) -> VidResult<Vec<u8>> {
177        self.0.recover_payload(shares, common)
178    }
179
180    fn is_consistent(commit: &Self::Commit, common: &Self::Common) -> VidResult<()> {
181        <Advz as VidScheme>::is_consistent(commit, common)
182    }
183
184    fn get_payload_byte_len(common: &Self::Common) -> u32 {
185        <Advz as VidScheme>::get_payload_byte_len(common)
186    }
187
188    fn get_num_storage_nodes(common: &Self::Common) -> u32 {
189        <Advz as VidScheme>::get_num_storage_nodes(common)
190    }
191
192    fn get_multiplicity(common: &Self::Common) -> u32 {
193        <Advz as VidScheme>::get_multiplicity(common)
194    }
195}
196
197impl PayloadProver<LargeRangeProofType> for ADVZScheme {
198    fn payload_proof<B>(&self, payload: B, range: Range<usize>) -> VidResult<LargeRangeProofType>
199    where
200        B: AsRef<[u8]>,
201    {
202        self.0
203            .payload_proof(payload, range)
204            .map(LargeRangeProofType)
205    }
206
207    fn payload_verify(
208        &self,
209        stmt: Statement<'_, Self>,
210        proof: &LargeRangeProofType,
211    ) -> VidResult<Result<(), ()>> {
212        self.0.payload_verify(stmt_conversion(stmt), &proof.0)
213    }
214}
215
216impl PayloadProver<SmallRangeProofType> for ADVZScheme {
217    fn payload_proof<B>(&self, payload: B, range: Range<usize>) -> VidResult<SmallRangeProofType>
218    where
219        B: AsRef<[u8]>,
220    {
221        self.0
222            .payload_proof(payload, range)
223            .map(SmallRangeProofType)
224    }
225
226    fn payload_verify(
227        &self,
228        stmt: Statement<'_, Self>,
229        proof: &SmallRangeProofType,
230    ) -> VidResult<Result<(), ()>> {
231        self.0.payload_verify(stmt_conversion(stmt), &proof.0)
232    }
233}
234
235/// Convert a [`VidDisperse<Advz>`] to a [`VidDisperse<VidSchemeType>`].
236///
237/// Foreign type rules prevent us from doing:
238/// - `impl From<VidDisperse<VidSchemeType>> for VidDisperse<Advz>`
239/// - `impl VidDisperse<VidSchemeType> {...}`
240///
241/// and similarly for `Statement`.
242/// Thus, we accomplish type conversion via functions.
243fn vid_disperse_conversion(vid_disperse: VidDisperse<Advz>) -> VidDisperse<ADVZScheme> {
244    VidDisperse {
245        shares: vid_disperse.shares,
246        common: vid_disperse.common,
247        commit: vid_disperse.commit,
248    }
249}
250
251/// Convert a [`Statement<'_, VidSchemeType>`] to a [`Statement<'_, Advz>`].
252fn stmt_conversion(stmt: Statement<'_, ADVZScheme>) -> Statement<'_, Advz> {
253    Statement {
254        payload_subslice: stmt.payload_subslice,
255        range: stmt.range,
256        commit: stmt.commit,
257        common: stmt.common,
258    }
259}