storage_proofs_post/fallback/
compound.rs1use 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 inputs.push(sector.comm_r.into());
67
68 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 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 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 §ors[i]
140 } else {
141 §ors[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}