Skip to main content

storage_proofs_post/fallback/
compound.rs

1use std::marker::PhantomData;
2
3use anyhow::{anyhow, ensure};
4use bellperson::Circuit;
5use blstrs::Scalar as Fr;
6use filecoin_hashers::Hasher;
7use sha2::{Digest, Sha256};
8use storage_proofs_core::{
9    compound_proof::{CircuitComponent, CompoundProof},
10    error::Result,
11    gadgets::por::PoRCompound,
12    merkle::MerkleTreeTrait,
13    parameter_cache::{CacheableParameters, ParameterSetMetadata},
14    por,
15    proof::ProofScheme,
16    util::NODE_SIZE,
17};
18
19use crate::fallback::{
20    generate_leaf_challenge_inner, get_challenge_index, FallbackPoSt, FallbackPoStCircuit, Sector,
21};
22
23pub struct FallbackPoStCompound<Tree>
24where
25    Tree: MerkleTreeTrait,
26{
27    _t: PhantomData<Tree>,
28}
29
30impl<C: Circuit<Fr>, P: ParameterSetMetadata, Tree: MerkleTreeTrait> CacheableParameters<C, P>
31    for FallbackPoStCompound<Tree>
32{
33    fn cache_prefix() -> String {
34        format!("proof-of-spacetime-fallback-{}", Tree::display())
35    }
36}
37
38impl<'a, Tree: 'static + MerkleTreeTrait>
39    CompoundProof<'a, FallbackPoSt<'a, Tree>, FallbackPoStCircuit<Tree>>
40    for FallbackPoStCompound<Tree>
41{
42    fn generate_public_inputs(
43        pub_inputs: &<FallbackPoSt<'a, Tree> as ProofScheme<'a>>::PublicInputs,
44        pub_params: &<FallbackPoSt<'a, Tree> as ProofScheme<'a>>::PublicParams,
45        partition_k: Option<usize>,
46    ) -> Result<Vec<Fr>> {
47        let mut inputs = Vec::new();
48
49        let por_pub_params = por::PublicParams {
50            leaves: (pub_params.sector_size as usize / NODE_SIZE),
51            private: true,
52        };
53
54        let num_sectors_per_chunk = pub_params.sector_count;
55
56        let partition_index = partition_k.unwrap_or(0);
57
58        let sectors = pub_inputs
59            .sectors
60            .chunks(num_sectors_per_chunk)
61            .nth(partition_index)
62            .ok_or_else(|| anyhow!("invalid number of sectors/partition index"))?;
63
64        for (i, sector) in sectors.iter().enumerate() {
65            // 1. Inputs for verifying comm_r = H(comm_c || comm_r_last)
66            inputs.push(sector.comm_r.into());
67
68            // avoid rehashing fixed inputs
69            let mut challenge_hasher = Sha256::new();
70            challenge_hasher.update(AsRef::<[u8]>::as_ref(&pub_inputs.randomness));
71            challenge_hasher.update(&u64::from(sector.id).to_le_bytes()[..]);
72
73            // 2. Inputs for verifying inclusion paths
74            for n in 0..pub_params.challenge_count {
75                let sector_index = partition_index * pub_params.sector_count + i;
76                let challenge_index = get_challenge_index(
77                    pub_params.api_version,
78                    sector_index,
79                    pub_params.challenge_count,
80                    n,
81                );
82                let challenged_leaf = generate_leaf_challenge_inner::<
83                    <Tree::Hasher as Hasher>::Domain,
84                >(
85                    challenge_hasher.clone(), pub_params, challenge_index
86                );
87
88                let por_pub_inputs = por::PublicInputs {
89                    commitment: None,
90                    challenge: challenged_leaf as usize,
91                };
92                let por_inputs = PoRCompound::<Tree>::generate_public_inputs(
93                    &por_pub_inputs,
94                    &por_pub_params,
95                    partition_k,
96                )?;
97
98                inputs.extend(por_inputs);
99            }
100        }
101        let num_inputs_per_sector = inputs.len() / sectors.len();
102
103        // duplicate last one if too little sectors available
104        while inputs.len() / num_inputs_per_sector < num_sectors_per_chunk {
105            let s = inputs[inputs.len() - num_inputs_per_sector..].to_vec();
106            inputs.extend_from_slice(&s);
107        }
108        assert_eq!(inputs.len(), num_inputs_per_sector * num_sectors_per_chunk);
109
110        Ok(inputs)
111    }
112
113    fn circuit(
114        pub_in: &<FallbackPoSt<'a, Tree> as ProofScheme<'a>>::PublicInputs,
115        _priv_in: <FallbackPoStCircuit<Tree> as CircuitComponent>::ComponentPrivateInputs,
116        vanilla_proof: &<FallbackPoSt<'a, Tree> as ProofScheme<'a>>::Proof,
117        pub_params: &<FallbackPoSt<'a, Tree> as ProofScheme<'a>>::PublicParams,
118        partition_k: Option<usize>,
119    ) -> Result<FallbackPoStCircuit<Tree>> {
120        let num_sectors_per_chunk = pub_params.sector_count;
121        ensure!(
122            pub_params.sector_count == vanilla_proof.sectors.len(),
123            "vanilla proofs must equal sector_count: {} != {}",
124            num_sectors_per_chunk,
125            vanilla_proof.sectors.len(),
126        );
127
128        let partition_index = partition_k.unwrap_or(0);
129        let sectors = pub_in
130            .sectors
131            .chunks(num_sectors_per_chunk)
132            .nth(partition_index)
133            .ok_or_else(|| anyhow!("invalid number of sectors/partition index"))?;
134
135        let mut res_sectors = Vec::with_capacity(vanilla_proof.sectors.len());
136
137        for (i, vanilla_proof) in vanilla_proof.sectors.iter().enumerate() {
138            let pub_sector = if i < sectors.len() {
139                &sectors[i]
140            } else {
141                // Repeat the last sector, iff there are too little inputs to fill the circuit.
142                &sectors[sectors.len() - 1]
143            };
144
145            res_sectors.push(Sector::circuit(pub_sector, vanilla_proof)?);
146        }
147
148        assert_eq!(res_sectors.len(), num_sectors_per_chunk);
149
150        Ok(FallbackPoStCircuit {
151            prover_id: Some(pub_in.prover_id.into()),
152            sectors: res_sectors,
153        })
154    }
155
156    fn blank_circuit(
157        pub_params: &<FallbackPoSt<'a, Tree> as ProofScheme<'a>>::PublicParams,
158    ) -> FallbackPoStCircuit<Tree> {
159        let sectors = (0..pub_params.sector_count)
160            .map(|_| Sector::blank_circuit(pub_params))
161            .collect();
162
163        FallbackPoStCircuit {
164            prover_id: None,
165            sectors,
166        }
167    }
168}