jf_vid/advz/
precomputable.rs

1// Copyright (c) 2024 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//! Implementations of [`Precomputable`] for `Advz`.
8
9use crate::{
10    advz::{
11        polynomial_eval, AdvzInternal, Common, HasherDigest, KzgCommit, KzgEvalsMerkleTree,
12        MaybeGPU, Pairing, PolynomialMultiplier, UnivariateKzgPCS,
13    },
14    precomputable::Precomputable,
15    vid, VidDisperse, VidResult,
16};
17use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
18use ark_std::{end_timer, start_timer, vec::Vec};
19use jf_merkle_tree::{MerkleCommitment, MerkleTreeScheme};
20use jf_pcs::{prelude::Commitment, PolynomialCommitmentScheme, UnivariatePCS};
21
22use jf_utils::canonical;
23use serde::{Deserialize, Serialize};
24
25impl<E, H, T> Precomputable for AdvzInternal<E, H, T>
26where
27    E: Pairing,
28    H: HasherDigest,
29    T: Sync,
30    AdvzInternal<E, H, T>: MaybeGPU<E>,
31{
32    type PrecomputeData = PrecomputeData<E>;
33
34    fn commit_only_precompute<B>(
35        &self,
36        payload: B,
37    ) -> VidResult<(Self::Commit, Self::PrecomputeData)>
38    where
39        B: AsRef<[u8]>,
40    {
41        let payload = payload.as_ref();
42        let multiplicity = self.min_multiplicity(payload.len());
43        let polys = self.bytes_to_polys(payload)?;
44        let poly_commits: Vec<Commitment<E>> =
45            UnivariateKzgPCS::batch_commit(&self.ck, &polys).map_err(vid)?;
46        Ok((
47            Self::derive_commit(&poly_commits, payload.len(), self.num_storage_nodes)?,
48            PrecomputeData { poly_commits },
49        ))
50    }
51
52    fn disperse_precompute<B>(
53        &self,
54        payload: B,
55        data: &Self::PrecomputeData,
56    ) -> VidResult<VidDisperse<Self>>
57    where
58        B: AsRef<[u8]>,
59    {
60        let payload = payload.as_ref();
61        let polys = self.bytes_to_polys(payload)?;
62        let poly_commits = data.poly_commits.clone();
63
64        self.disperse_with_polys_and_commits(payload, polys, poly_commits)
65    }
66}
67
68#[derive(
69    Debug,
70    Clone,
71    CanonicalSerialize,
72    CanonicalDeserialize,
73    Derivative,
74    Deserialize,
75    Serialize,
76    PartialEq,
77    Eq,
78)]
79#[derivative(Hash(bound = ""))]
80/// Data that can be precomputed as used in dispersal
81pub struct PrecomputeData<E>
82where
83    E: Pairing,
84{
85    #[serde(with = "canonical")]
86    poly_commits: Vec<KzgCommit<E>>,
87}
88
89#[cfg(test)]
90mod tests {
91    use crate::{
92        advz::{
93            test::{advz_init, init_random_payload, init_srs},
94            Advz,
95        },
96        precomputable::Precomputable,
97        VidScheme,
98    };
99    use ark_bls12_381::Bls12_381;
100    use sha2::Sha256;
101
102    #[ignore]
103    #[test]
104    fn commit_only_with_data_timer() {
105        // run with 'print-trace' feature to see timer output
106        let (recovery_threshold, num_storage_nodes) = (256, 512);
107        let mut rng = jf_utils::test_rng();
108        let multiplicity = 1;
109        let srs = init_srs((recovery_threshold * multiplicity) as usize, &mut rng);
110        let advz = Advz::<Bls12_381, Sha256>::with_multiplicity(
111            num_storage_nodes,
112            recovery_threshold,
113            multiplicity,
114            srs,
115        )
116        .unwrap();
117        let payload_random = init_random_payload(1 << 20, &mut rng);
118
119        let (_commit, _data) = advz.commit_only_precompute(payload_random).unwrap();
120    }
121
122    #[ignore]
123    #[test]
124    fn disperse_with_data_timer() {
125        // run with 'print-trace' feature to see timer output
126        let (recovery_threshold, num_storage_nodes) = (64, 128);
127        let multiplicity = 4;
128        let mut rng = jf_utils::test_rng();
129        let srs = init_srs((recovery_threshold * multiplicity) as usize, &mut rng);
130        let advz = Advz::<Bls12_381, Sha256>::with_multiplicity(
131            num_storage_nodes,
132            recovery_threshold,
133            multiplicity,
134            srs,
135        )
136        .unwrap();
137        let payload_random = init_random_payload(1 << 20, &mut rng);
138        let (_commit, data) = advz.commit_only_precompute(&payload_random).unwrap();
139        let _ = advz.disperse_precompute(payload_random, &data);
140    }
141
142    #[test]
143    fn commit_disperse_recover_with_precomputed_data() {
144        let (advz, bytes_random) = advz_init();
145        let (commit, data) = advz.commit_only_precompute(&bytes_random).unwrap();
146        let disperse = advz.disperse_precompute(&bytes_random, &data).unwrap();
147        let (shares, common) = (disperse.shares, disperse.common);
148        for share in &shares {
149            let v = advz.verify_share(share, &common, &commit);
150            assert!(v.is_ok(), "share verification should succeed");
151        }
152
153        let bytes_recovered = advz
154            .recover_payload(&shares, &common)
155            .expect("recover_payload should succeed");
156        assert_eq!(bytes_recovered, bytes_random);
157    }
158}