storage_proofs_post/fallback/
circuit.rs1use bellperson::{gadgets::num::AllocatedNum, Circuit, ConstraintSystem, SynthesisError};
2use blstrs::Scalar as Fr;
3use ff::Field;
4use filecoin_hashers::{HashFunction, Hasher};
5use rayon::prelude::{ParallelIterator, ParallelSlice};
6use storage_proofs_core::{
7 compound_proof::CircuitComponent,
8 error::Result,
9 gadgets::{
10 constraint,
11 por::{AuthPath, PoRCircuit},
12 variables::Root,
13 },
14 merkle::MerkleTreeTrait,
15 por,
16 settings::SETTINGS,
17 util::NODE_SIZE,
18};
19
20use crate::fallback::{PublicParams, PublicSector, SectorProof};
21
22pub struct FallbackPoStCircuit<Tree: MerkleTreeTrait> {
24 pub prover_id: Option<Fr>,
25 pub sectors: Vec<Sector<Tree>>,
26}
27
28impl<Tree: 'static + MerkleTreeTrait> Clone for FallbackPoStCircuit<Tree> {
33 fn clone(&self) -> Self {
34 FallbackPoStCircuit {
35 prover_id: self.prover_id,
36 sectors: self.sectors.clone(),
37 }
38 }
39}
40
41pub struct Sector<Tree: MerkleTreeTrait> {
42 pub comm_r: Option<Fr>,
43 pub comm_c: Option<Fr>,
44 pub comm_r_last: Option<Fr>,
45 pub leafs: Vec<Option<Fr>>,
46 pub paths: Vec<AuthPath<Tree::Hasher, Tree::Arity, Tree::SubTreeArity, Tree::TopTreeArity>>,
47 pub id: Option<Fr>,
48}
49
50impl<Tree: MerkleTreeTrait> Clone for Sector<Tree> {
53 fn clone(&self) -> Self {
54 Sector {
55 comm_r: self.comm_r,
56 comm_c: self.comm_c,
57 comm_r_last: self.comm_r_last,
58 leafs: self.leafs.clone(),
59 paths: self.paths.clone(),
60 id: self.id,
61 }
62 }
63}
64
65impl<Tree: 'static + MerkleTreeTrait> Sector<Tree> {
66 pub fn circuit(
67 sector: &PublicSector<<Tree::Hasher as Hasher>::Domain>,
68 vanilla_proof: &SectorProof<Tree::Proof>,
69 ) -> Result<Self> {
70 let leafs = vanilla_proof
71 .leafs()
72 .iter()
73 .map(|l| Some((*l).into()))
74 .collect();
75
76 let paths = vanilla_proof
77 .as_options()
78 .into_iter()
79 .map(Into::into)
80 .collect();
81
82 Ok(Sector {
83 leafs,
84 id: Some(sector.id.into()),
85 comm_r: Some(sector.comm_r.into()),
86 comm_c: Some(vanilla_proof.comm_c.into()),
87 comm_r_last: Some(vanilla_proof.comm_r_last.into()),
88 paths,
89 })
90 }
91
92 pub fn blank_circuit(pub_params: &PublicParams) -> Self {
93 let challenges_count = pub_params.challenge_count;
94 let leaves = pub_params.sector_size as usize / NODE_SIZE;
95
96 let por_params = por::PublicParams {
97 leaves,
98 private: true,
99 };
100 let leafs = vec![None; challenges_count];
101 let paths = vec![AuthPath::blank(por_params.leaves); challenges_count];
102
103 Sector {
104 id: None,
105 comm_r: None,
106 comm_c: None,
107 comm_r_last: None,
108 leafs,
109 paths,
110 }
111 }
112}
113
114impl<Tree: 'static + MerkleTreeTrait> Circuit<Fr> for &Sector<Tree> {
115 fn synthesize<CS: ConstraintSystem<Fr>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
116 let Sector {
117 comm_r,
118 comm_c,
119 comm_r_last,
120 leafs,
121 paths,
122 ..
123 } = self;
124
125 assert_eq!(paths.len(), leafs.len());
126
127 let comm_r_last_num = AllocatedNum::alloc(cs.namespace(|| "comm_r_last"), || {
129 comm_r_last
130 .map(Into::into)
131 .ok_or(SynthesisError::AssignmentMissing)
132 })?;
133
134 let comm_c_num = AllocatedNum::alloc(cs.namespace(|| "comm_c"), || {
135 comm_c
136 .map(Into::into)
137 .ok_or(SynthesisError::AssignmentMissing)
138 })?;
139
140 let comm_r_num = AllocatedNum::alloc(cs.namespace(|| "comm_r"), || {
141 comm_r
142 .map(Into::into)
143 .ok_or(SynthesisError::AssignmentMissing)
144 })?;
145
146 comm_r_num.inputize(cs.namespace(|| "comm_r_input"))?;
147
148 {
150 let hash_num = <Tree::Hasher as Hasher>::Function::hash2_circuit(
151 cs.namespace(|| "H_comm_c_comm_r_last"),
152 &comm_c_num,
153 &comm_r_last_num,
154 )?;
155
156 constraint::equal(
158 cs,
159 || "enforce_comm_c_comm_r_last_hash_comm_r",
160 &comm_r_num,
161 &hash_num,
162 );
163 }
164
165 for (i, (leaf, path)) in leafs.iter().zip(paths.iter()).enumerate() {
167 PoRCircuit::<Tree>::synthesize(
168 cs.namespace(|| format!("challenge_inclusion_{}", i)),
169 Root::Val(*leaf),
170 path.clone(),
171 Root::from_allocated::<CS>(comm_r_last_num.clone()),
172 true,
173 )?;
174 }
175
176 Ok(())
177 }
178}
179
180#[derive(Clone, Default)]
181pub struct ComponentPrivateInputs {}
182
183impl<Tree: MerkleTreeTrait> CircuitComponent for FallbackPoStCircuit<Tree> {
184 type ComponentPrivateInputs = ComponentPrivateInputs;
185}
186
187impl<Tree: 'static + MerkleTreeTrait> Circuit<Fr> for FallbackPoStCircuit<Tree> {
188 fn synthesize<CS: ConstraintSystem<Fr>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
189 if CS::is_extensible() {
190 return self.synthesize_extendable(cs);
191 }
192
193 self.synthesize_default(cs)
194 }
195}
196
197impl<Tree: 'static + MerkleTreeTrait> FallbackPoStCircuit<Tree> {
198 fn synthesize_default<CS: ConstraintSystem<Fr>>(
199 self,
200 cs: &mut CS,
201 ) -> Result<(), SynthesisError> {
202 let cs = &mut cs.namespace(|| "outer namespace".to_string());
203
204 for (i, sector) in self.sectors.iter().enumerate() {
205 let cs = &mut cs.namespace(|| format!("sector_{}", i));
206 sector.synthesize(cs)?;
207 }
208 Ok(())
209 }
210
211 fn synthesize_extendable<CS: ConstraintSystem<Fr>>(
212 self,
213 cs: &mut CS,
214 ) -> Result<(), SynthesisError> {
215 let FallbackPoStCircuit { sectors, .. } = self;
216
217 let num_chunks = SETTINGS.window_post_synthesis_num_cpus as usize;
218
219 let chunk_size = (sectors.len() / num_chunks).max(1);
220 let css = sectors
221 .par_chunks(chunk_size)
222 .map(|sector_group| {
223 let mut cs = CS::new();
224 cs.alloc_input(|| "temp ONE", || Ok(Fr::ONE))?;
225
226 for (i, sector) in sector_group.iter().enumerate() {
227 let mut cs = cs.namespace(|| format!("sector_{}", i));
228
229 sector.synthesize(&mut cs)?;
230 }
231 Ok(cs)
232 })
233 .collect::<Result<Vec<_>, SynthesisError>>()?;
234
235 for sector_cs in css.into_iter() {
236 cs.extend(§or_cs);
237 }
238
239 Ok(())
240 }
241}