diff --git a/storage-proofs-post/Cargo.toml b/storage-proofs-post/Cargo.toml index 1994647e1..2fee6630d 100644 --- a/storage-proofs-post/Cargo.toml +++ b/storage-proofs-post/Cargo.toml @@ -15,20 +15,16 @@ byteorder = "1" sha2 = "0.10.2" rayon = "1.0.0" serde = { version = "1.0", features = ["derive"]} -blake2b_simd = "1.0.0" ff = "0.13.0" bellperson = "0.26.0" log = "0.4.7" -hex = "0.4.0" generic-array = "0.14.4" anyhow = "1.0.23" -fr32 = { path = "../fr32", version = "~9.1.0", default-features = false } blstrs = "0.7.0" [dev-dependencies] tempfile = "3" pretty_assertions = "1.2.0" -filecoin-hashers = { path = "../filecoin-hashers", version = "~11.1.0", default-features = false, features = ["poseidon", "sha256", "blake2s"]} rand = "0.8" rand_xorshift = "0.3.0" diff --git a/storage-proofs-post/src/election/circuit.rs b/storage-proofs-post/src/election/circuit.rs deleted file mode 100644 index 50dbdccb1..000000000 --- a/storage-proofs-post/src/election/circuit.rs +++ /dev/null @@ -1,167 +0,0 @@ -use std::marker::PhantomData; - -use bellperson::{gadgets::num::AllocatedNum, Circuit, ConstraintSystem, SynthesisError}; -use blstrs::Scalar as Fr; -use ff::Field; -use filecoin_hashers::{poseidon::PoseidonFunction, HashFunction, Hasher, PoseidonMDArity}; -use generic_array::typenum::Unsigned; -use storage_proofs_core::{ - compound_proof::CircuitComponent, - gadgets::{constraint, por::PoRCircuit, variables::Root}, - merkle::MerkleTreeTrait, -}; - -/// This is the `ElectionPoSt` circuit. -pub struct ElectionPoStCircuit { - pub comm_r: Option, - pub comm_c: Option, - pub comm_r_last: Option, - pub leafs: Vec>, - #[allow(clippy::type_complexity)] - pub paths: Vec>, Option)>>, - pub partial_ticket: Option, - pub randomness: Option, - pub prover_id: Option, - pub sector_id: Option, - pub _t: PhantomData, -} - -#[derive(Clone, Default)] -pub struct ComponentPrivateInputs {} - -impl CircuitComponent for ElectionPoStCircuit { - type ComponentPrivateInputs = ComponentPrivateInputs; -} - -impl Circuit for ElectionPoStCircuit { - fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { - let comm_r = self.comm_r; - let comm_c = self.comm_c; - let comm_r_last = self.comm_r_last; - let leafs = self.leafs; - let paths = self.paths; - let partial_ticket = self.partial_ticket; - let randomness = self.randomness; - let prover_id = self.prover_id; - let sector_id = self.sector_id; - - assert_eq!(paths.len(), leafs.len()); - - // 1. Verify comm_r - - let comm_r_last_num = AllocatedNum::alloc(cs.namespace(|| "comm_r_last"), || { - comm_r_last - .map(Into::into) - .ok_or(SynthesisError::AssignmentMissing) - })?; - - let comm_c_num = AllocatedNum::alloc(cs.namespace(|| "comm_c"), || { - comm_c - .map(Into::into) - .ok_or(SynthesisError::AssignmentMissing) - })?; - - let comm_r_num = AllocatedNum::alloc(cs.namespace(|| "comm_r"), || { - comm_r - .map(Into::into) - .ok_or(SynthesisError::AssignmentMissing) - })?; - - comm_r_num.inputize(cs.namespace(|| "comm_r_input"))?; - - // Verify H(Comm_C || comm_r_last) == comm_r - { - let hash_num = ::Function::hash2_circuit( - cs.namespace(|| "H_comm_c_comm_r_last"), - &comm_c_num, - &comm_r_last_num, - )?; - - // Check actual equality - constraint::equal( - cs, - || "enforce_comm_c_comm_r_last_hash_comm_r", - &comm_r_num, - &hash_num, - ); - } - - // 2. Verify Inclusion Paths - for (i, (leaf, path)) in leafs.iter().zip(paths.iter()).enumerate() { - PoRCircuit::::synthesize( - cs.namespace(|| format!("challenge_inclusion{}", i)), - Root::Val(*leaf), - path.clone().into(), - Root::from_allocated::(comm_r_last_num.clone()), - true, - )?; - } - - // 3. Verify partial ticket - - // randomness - let randomness_num = AllocatedNum::alloc(cs.namespace(|| "randomness"), || { - randomness - .map(Into::into) - .ok_or(SynthesisError::AssignmentMissing) - })?; - - // prover_id - let prover_id_num = AllocatedNum::alloc(cs.namespace(|| "prover_id"), || { - prover_id - .map(Into::into) - .ok_or(SynthesisError::AssignmentMissing) - })?; - - // sector_id - let sector_id_num = AllocatedNum::alloc(cs.namespace(|| "sector_id"), || { - sector_id - .map(Into::into) - .ok_or(SynthesisError::AssignmentMissing) - })?; - - let mut partial_ticket_nums = vec![randomness_num, prover_id_num, sector_id_num]; - for (i, leaf) in leafs.iter().enumerate() { - let leaf_num = AllocatedNum::alloc(cs.namespace(|| format!("leaf_{}", i)), || { - leaf.map(Into::into) - .ok_or(SynthesisError::AssignmentMissing) - })?; - partial_ticket_nums.push(leaf_num); - } - - // pad to a multiple of md arity - let arity = PoseidonMDArity::to_usize(); - while partial_ticket_nums.len() % arity != 0 { - partial_ticket_nums.push(AllocatedNum::alloc( - cs.namespace(|| format!("padding_{}", partial_ticket_nums.len())), - || Ok(Fr::ZERO), - )?); - } - - // hash it - let partial_ticket_num = PoseidonFunction::hash_md_circuit::<_>( - &mut cs.namespace(|| "partial_ticket_hash"), - &partial_ticket_nums, - )?; - - // allocate expected input - let expected_partial_ticket_num = - AllocatedNum::alloc(cs.namespace(|| "partial_ticket"), || { - partial_ticket - .map(Into::into) - .ok_or(SynthesisError::AssignmentMissing) - })?; - - expected_partial_ticket_num.inputize(cs.namespace(|| "partial_ticket_input"))?; - - // check equality - constraint::equal( - cs, - || "enforce partial_ticket is correct", - &partial_ticket_num, - &expected_partial_ticket_num, - ); - - Ok(()) - } -} diff --git a/storage-proofs-post/src/election/compound.rs b/storage-proofs-post/src/election/compound.rs deleted file mode 100644 index 328f787aa..000000000 --- a/storage-proofs-post/src/election/compound.rs +++ /dev/null @@ -1,157 +0,0 @@ -use std::marker::PhantomData; - -use bellperson::Circuit; -use blstrs::Scalar as Fr; -use generic_array::typenum::Unsigned; -use storage_proofs_core::{ - compound_proof::{CircuitComponent, CompoundProof}, - drgraph::graph_height, - error::Result, - gadgets::por::PoRCompound, - merkle::MerkleTreeTrait, - parameter_cache::{CacheableParameters, ParameterSetMetadata}, - por, - proof::ProofScheme, - util::NODE_SIZE, -}; - -use crate::election::{generate_leaf_challenge, ElectionPoSt, ElectionPoStCircuit}; - -pub struct ElectionPoStCompound -where - Tree: MerkleTreeTrait, -{ - _t: PhantomData, -} - -impl, P: ParameterSetMetadata, Tree: MerkleTreeTrait> CacheableParameters - for ElectionPoStCompound -{ - fn cache_prefix() -> String { - format!("proof-of-spacetime-election-{}", Tree::display()) - } -} - -impl<'a, Tree> CompoundProof<'a, ElectionPoSt<'a, Tree>, ElectionPoStCircuit> - for ElectionPoStCompound -where - Tree: 'static + MerkleTreeTrait, -{ - fn generate_public_inputs( - pub_inputs: & as ProofScheme<'a>>::PublicInputs, - pub_params: & as ProofScheme<'a>>::PublicParams, - _partition_k: Option, - ) -> Result> { - let mut inputs = Vec::new(); - - let por_pub_params = por::PublicParams { - leaves: (pub_params.sector_size as usize / NODE_SIZE), - private: true, - }; - - // 1. Inputs for verifying comm_r = H(comm_c || comm_r_last) - - inputs.push(pub_inputs.comm_r.into()); - - // 2. Inputs for verifying inclusion paths - - for n in 0..pub_params.challenge_count { - let challenged_leaf_start = generate_leaf_challenge( - pub_params, - pub_inputs.randomness, - pub_inputs.sector_challenge_index, - n as u64, - )?; - for i in 0..pub_params.challenged_nodes { - let por_pub_inputs = por::PublicInputs { - commitment: None, - challenge: challenged_leaf_start as usize + i, - }; - let por_inputs = PoRCompound::::generate_public_inputs( - &por_pub_inputs, - &por_pub_params, - None, - )?; - - inputs.extend(por_inputs); - } - } - - // 3. Inputs for verifying partial_ticket generation - inputs.push(pub_inputs.partial_ticket); - - Ok(inputs) - } - - fn circuit( - pub_in: & as ProofScheme<'a>>::PublicInputs, - _priv_in: as CircuitComponent>::ComponentPrivateInputs, - vanilla_proof: & as ProofScheme<'a>>::Proof, - _pub_params: & as ProofScheme<'a>>::PublicParams, - _partition_k: Option, - ) -> Result> { - let comm_r = pub_in.comm_r.into(); - let comm_c = vanilla_proof.comm_c.into(); - let comm_r_last = vanilla_proof.comm_r_last().into(); - - let leafs: Vec<_> = vanilla_proof - .leafs() - .iter() - .map(|c| Some((*c).into())) - .collect(); - - let paths: Vec> = vanilla_proof - .paths() - .iter() - .map(|v| { - v.iter() - .map(|p| { - ( - p.0.iter().copied().map(Into::into).map(Some).collect(), - Some(p.1), - ) - }) - .collect() - }) - .collect(); - - Ok(ElectionPoStCircuit { - leafs, - comm_r: Some(comm_r), - comm_c: Some(comm_c), - comm_r_last: Some(comm_r_last), - paths, - partial_ticket: Some(pub_in.partial_ticket), - randomness: Some(pub_in.randomness.into()), - prover_id: Some(pub_in.prover_id.into()), - sector_id: Some(pub_in.sector_id.into()), - _t: PhantomData, - }) - } - - fn blank_circuit( - pub_params: & as ProofScheme<'a>>::PublicParams, - ) -> ElectionPoStCircuit { - let challenges_count = pub_params.challenged_nodes * pub_params.challenge_count; - let height = graph_height::(pub_params.sector_size as usize / NODE_SIZE); - - let leafs = vec![None; challenges_count]; - let paths = vec![ - vec![(vec![None; Tree::Arity::to_usize() - 1], None); height - 1]; - challenges_count - ]; - - ElectionPoStCircuit { - comm_r: None, - comm_c: None, - comm_r_last: None, - partial_ticket: None, - leafs, - paths, - randomness: None, - prover_id: None, - sector_id: None, - _t: PhantomData, - } - } -} diff --git a/storage-proofs-post/src/election/mod.rs b/storage-proofs-post/src/election/mod.rs deleted file mode 100644 index c63243f96..000000000 --- a/storage-proofs-post/src/election/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod circuit; -mod compound; -mod vanilla; - -pub use circuit::*; -pub use compound::*; -pub use vanilla::*; diff --git a/storage-proofs-post/src/election/vanilla.rs b/storage-proofs-post/src/election/vanilla.rs deleted file mode 100644 index eb5410f69..000000000 --- a/storage-proofs-post/src/election/vanilla.rs +++ /dev/null @@ -1,453 +0,0 @@ -use std::collections::BTreeMap; -use std::fmt::{self, Debug, Formatter}; -use std::marker::PhantomData; - -use anyhow::{bail, ensure, Context}; -use blstrs::Scalar as Fr; -use byteorder::{ByteOrder, LittleEndian}; -use filecoin_hashers::{ - poseidon::{PoseidonDomain, PoseidonFunction}, - Domain, HashFunction, Hasher, PoseidonMDArity, -}; -use fr32::fr_into_bytes; -use generic_array::typenum::Unsigned; -use log::trace; -use rayon::prelude::{ - IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, ParallelIterator, -}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use sha2::{Digest, Sha256}; -use storage_proofs_core::{ - error::{Error, Result}, - measurements::{measure_op, Operation}, - merkle::{MerkleProof, MerkleProofTrait, MerkleTreeTrait, MerkleTreeWrapper}, - parameter_cache::ParameterSetMetadata, - proof::{NoRequirements, ProofScheme}, - sector::{OrderedSectorSet, SectorId}, - util::NODE_SIZE, -}; - -#[derive(Debug, Clone)] -pub struct SetupParams { - /// Size of the sector in bytes. - pub sector_size: u64, - pub challenge_count: usize, - pub challenged_nodes: usize, -} - -#[derive(Debug, Clone)] -pub struct PublicParams { - /// Size of the sector in bytes. - pub sector_size: u64, - pub challenge_count: usize, - pub challenged_nodes: usize, -} - -impl ParameterSetMetadata for PublicParams { - fn identifier(&self) -> String { - format!( - "ElectionPoSt::PublicParams{{sector_size: {}, count: {}, nodes: {}}}", - self.sector_size(), - self.challenge_count, - self.challenged_nodes, - ) - } - - fn sector_size(&self) -> u64 { - self.sector_size - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PublicInputs { - #[serde(bound = "")] - pub randomness: T, - pub sector_id: SectorId, - #[serde(bound = "")] - pub prover_id: T, - #[serde(bound = "")] - pub comm_r: T, - pub partial_ticket: Fr, - pub sector_challenge_index: u64, -} - -#[derive(Debug)] -pub struct PrivateInputs { - pub tree: MerkleTreeWrapper< - Tree::Hasher, - Tree::Store, - Tree::Arity, - Tree::SubTreeArity, - Tree::TopTreeArity, - >, - pub comm_c: ::Domain, - pub comm_r_last: ::Domain, -} - -/// The candidate data, that is needed for ticket generation. -#[derive(Clone, Serialize, Deserialize)] -pub struct Candidate { - pub sector_id: SectorId, - pub partial_ticket: Fr, - pub ticket: [u8; 32], - pub sector_challenge_index: u64, -} - -impl Debug for Candidate { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Candidate") - .field("sector_id", &self.sector_id) - .field("partial_ticket", &self.partial_ticket) - .field("ticket", &hex::encode(self.ticket)) - .field("sector_challenge_index", &self.sector_challenge_index) - .finish() - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Proof { - #[serde(bound( - serialize = "MerkleProof: Serialize", - deserialize = "MerkleProof: DeserializeOwned" - ))] - inclusion_proofs: Vec>, - pub ticket: [u8; 32], - pub comm_c: ::Domain, -} - -impl Proof

{ - pub fn leafs(&self) -> Vec<::Domain> { - self.inclusion_proofs - .iter() - .map(MerkleProof::leaf) - .collect() - } - - pub fn comm_r_last(&self) -> ::Domain { - self.inclusion_proofs[0].root() - } - - pub fn commitments(&self) -> Vec<::Domain> { - self.inclusion_proofs - .iter() - .map(MerkleProof::root) - .collect() - } - - #[allow(clippy::type_complexity)] - pub fn paths(&self) -> Vec::Domain>, usize)>> { - self.inclusion_proofs - .iter() - .map(MerkleProof::path) - .collect() - } -} - -#[derive(Debug, Clone)] -pub struct ElectionPoSt<'a, Tree> -where - Tree: MerkleTreeTrait, -{ - _t: PhantomData<&'a Tree>, -} - -#[allow(clippy::type_complexity)] -pub fn generate_candidates( - pub_params: &PublicParams, - challenged_sectors: &[SectorId], - trees: &BTreeMap< - SectorId, - MerkleTreeWrapper< - Tree::Hasher, - Tree::Store, - Tree::Arity, - Tree::SubTreeArity, - Tree::TopTreeArity, - >, - >, - prover_id: ::Domain, - randomness: ::Domain, -) -> Result> { - challenged_sectors - .par_iter() - .enumerate() - .map(|(sector_challenge_index, sector_id)| { - let tree = match trees.get(sector_id) { - Some(tree) => tree, - None => bail!(Error::MissingPrivateInput("tree", (*sector_id).into())), - }; - - generate_candidate::( - pub_params, - tree, - prover_id, - *sector_id, - randomness, - sector_challenge_index as u64, - ) - }) - .collect() -} - -fn generate_candidate( - pub_params: &PublicParams, - tree: &MerkleTreeWrapper< - Tree::Hasher, - Tree::Store, - Tree::Arity, - Tree::SubTreeArity, - Tree::TopTreeArity, - >, - prover_id: ::Domain, - sector_id: SectorId, - randomness: ::Domain, - sector_challenge_index: u64, -) -> Result { - let randomness_fr: Fr = randomness.into(); - let prover_id_fr: Fr = prover_id.into(); - let mut data: Vec = vec![ - randomness_fr.into(), - prover_id_fr.into(), - Fr::from(sector_id).into(), - ]; - - for n in 0..pub_params.challenge_count { - let challenge = - generate_leaf_challenge(pub_params, randomness, sector_challenge_index, n as u64)?; - - let val: Fr = measure_op(Operation::PostReadChallengedRange, || { - tree.read_at(challenge as usize) - })? - .into(); - data.push(val.into()); - } - - // pad for md - let arity = PoseidonMDArity::to_usize(); - while data.len() % arity != 0 { - data.push(PoseidonDomain::default()); - } - - let partial_ticket: Fr = measure_op(Operation::PostPartialTicketHash, || { - PoseidonFunction::hash_md(&data) - }) - .into(); - - // ticket = sha256(partial_ticket) - let ticket = finalize_ticket(&partial_ticket); - - Ok(Candidate { - sector_challenge_index, - sector_id, - partial_ticket, - ticket, - }) -} - -pub fn finalize_ticket(partial_ticket: &Fr) -> [u8; 32] { - let bytes = fr_into_bytes(partial_ticket); - let ticket_hash = Sha256::digest(bytes); - let mut ticket = [0u8; 32]; - ticket.copy_from_slice(&ticket_hash[..]); - ticket -} - -pub fn is_valid_sector_challenge_index(challenge_count: u64, index: u64) -> bool { - index < challenge_count -} - -pub fn generate_sector_challenges( - randomness: T, - challenge_count: u64, - sectors: &OrderedSectorSet, -) -> Result> { - (0..challenge_count) - .into_par_iter() - .map(|n| generate_sector_challenge(randomness, n as usize, sectors)) - .collect() -} - -pub fn generate_sector_challenge( - randomness: T, - n: usize, - sectors: &OrderedSectorSet, -) -> Result { - let mut hasher = Sha256::new(); - hasher.update(AsRef::<[u8]>::as_ref(&randomness)); - hasher.update(&n.to_le_bytes()[..]); - let hash = hasher.finalize(); - - let sector_challenge = LittleEndian::read_u64(&hash[..8]); - let sector_index = (sector_challenge % sectors.len() as u64) as usize; - let sector = *sectors - .iter() - .nth(sector_index) - .context("invalid challenge generated")?; - - Ok(sector) -} - -/// Generate all challenged leaf ranges for a single sector, such that the range fits into the sector. -pub fn generate_leaf_challenges( - pub_params: &PublicParams, - randomness: T, - sector_challenge_index: u64, - challenge_count: usize, -) -> Result> { - let mut challenges = Vec::with_capacity(challenge_count); - - for leaf_challenge_index in 0..challenge_count { - let challenge = generate_leaf_challenge( - pub_params, - randomness, - sector_challenge_index, - leaf_challenge_index as u64, - )?; - challenges.push(challenge) - } - - Ok(challenges) -} - -/// Generates challenge, such that the range fits into the sector. -pub fn generate_leaf_challenge( - pub_params: &PublicParams, - randomness: T, - sector_challenge_index: u64, - leaf_challenge_index: u64, -) -> Result { - ensure!( - pub_params.sector_size > pub_params.challenged_nodes as u64 * NODE_SIZE as u64, - "sector size {} is too small", - pub_params.sector_size - ); - - let mut hasher = Sha256::new(); - hasher.update(AsRef::<[u8]>::as_ref(&randomness)); - hasher.update(§or_challenge_index.to_le_bytes()[..]); - hasher.update(&leaf_challenge_index.to_le_bytes()[..]); - let hash = hasher.finalize(); - - let leaf_challenge = LittleEndian::read_u64(&hash[..8]); - - let challenged_range_index = leaf_challenge - % (pub_params.sector_size / (pub_params.challenged_nodes * NODE_SIZE) as u64); - - Ok(challenged_range_index * pub_params.challenged_nodes as u64) -} - -impl<'a, Tree: 'static + MerkleTreeTrait> ProofScheme<'a> for ElectionPoSt<'a, Tree> { - type PublicParams = PublicParams; - type SetupParams = SetupParams; - type PublicInputs = PublicInputs<::Domain>; - type PrivateInputs = PrivateInputs; - type Proof = Proof; - type Requirements = NoRequirements; - - fn setup(sp: &Self::SetupParams) -> Result { - Ok(PublicParams { - sector_size: sp.sector_size, - challenge_count: sp.challenge_count, - challenged_nodes: sp.challenged_nodes, - }) - } - - fn prove<'b>( - pub_params: &'b Self::PublicParams, - pub_inputs: &'b Self::PublicInputs, - priv_inputs: &'b Self::PrivateInputs, - ) -> Result { - // 1. Inclusions proofs of all challenged leafs in all challenged ranges - let tree = &priv_inputs.tree; - let tree_leafs = tree.leafs(); - - trace!( - "Generating proof for tree of len {} with leafs {}", - tree.len(), - tree_leafs, - ); - - let inclusion_proofs = measure_op(Operation::PostInclusionProofs, || { - (0..pub_params.challenge_count) - .into_par_iter() - .flat_map(|n| { - // TODO: replace expect with proper error handling - let challenged_leaf_start = generate_leaf_challenge( - pub_params, - pub_inputs.randomness, - pub_inputs.sector_challenge_index, - n as u64, - ) - .expect("generate leaf challenge failure"); - (0..pub_params.challenged_nodes) - .into_par_iter() - .map(move |i| { - tree.gen_cached_proof(challenged_leaf_start as usize + i, None) - }) - }) - .collect::>>() - })?; - - // 2. correct generation of the ticket from the partial_ticket (add this to the candidate) - let ticket = measure_op(Operation::PostFinalizeTicket, || { - finalize_ticket(&pub_inputs.partial_ticket) - }); - - Ok(Proof { - inclusion_proofs, - ticket, - comm_c: priv_inputs.comm_c, - }) - } - - fn verify( - pub_params: &Self::PublicParams, - pub_inputs: &Self::PublicInputs, - proof: &Self::Proof, - ) -> Result { - // verify that H(Comm_c || Comm_r_last) == Comm_R - // comm_r_last is the root of the proof - let comm_r_last = proof.inclusion_proofs[0].root(); - let comm_c = proof.comm_c; - let comm_r = &pub_inputs.comm_r; - - if AsRef::<[u8]>::as_ref(&::Function::hash2( - &comm_c, - &comm_r_last, - )) != AsRef::<[u8]>::as_ref(comm_r) - { - return Ok(false); - } - - for n in 0..pub_params.challenge_count { - let challenged_leaf_start = generate_leaf_challenge( - pub_params, - pub_inputs.randomness, - pub_inputs.sector_challenge_index, - n as u64, - )?; - for i in 0..pub_params.challenged_nodes { - let merkle_proof = &proof.inclusion_proofs[n * pub_params.challenged_nodes + i]; - - // validate all comm_r_lasts match - if merkle_proof.root() != comm_r_last { - return Ok(false); - } - - // validate the path length - let expected_path_length = - merkle_proof.expected_len(pub_params.sector_size as usize / NODE_SIZE); - - if expected_path_length != merkle_proof.path().len() { - return Ok(false); - } - - if !merkle_proof.validate(challenged_leaf_start as usize + i) { - return Ok(false); - } - } - } - - Ok(true) - } -} diff --git a/storage-proofs-post/src/lib.rs b/storage-proofs-post/src/lib.rs index 35d4fe828..cdda3992a 100644 --- a/storage-proofs-post/src/lib.rs +++ b/storage-proofs-post/src/lib.rs @@ -1,6 +1,4 @@ #![deny(clippy::all, clippy::perf, clippy::correctness, rust_2018_idioms)] #![warn(clippy::unwrap_used)] -pub mod election; pub mod fallback; -pub mod rational; diff --git a/storage-proofs-post/src/rational/circuit.rs b/storage-proofs-post/src/rational/circuit.rs deleted file mode 100644 index e363fa513..000000000 --- a/storage-proofs-post/src/rational/circuit.rs +++ /dev/null @@ -1,98 +0,0 @@ -use std::marker::PhantomData; - -use bellperson::{gadgets::num::AllocatedNum, Circuit, ConstraintSystem, SynthesisError}; -use blstrs::Scalar as Fr; -use filecoin_hashers::{HashFunction, Hasher}; -use storage_proofs_core::{ - compound_proof::CircuitComponent, error::Result, gadgets::constraint, gadgets::por::PoRCircuit, - gadgets::variables::Root, merkle::MerkleTreeTrait, -}; - -/// This is the `RationalPoSt` circuit. -pub struct RationalPoStCircuit { - /// Paramters for the engine. - pub comm_rs: Vec>, - pub comm_cs: Vec>, - pub comm_r_lasts: Vec>, - pub leafs: Vec>, - #[allow(clippy::type_complexity)] - pub paths: Vec>, Option)>>, - pub _t: PhantomData, -} - -#[derive(Clone, Default)] -pub struct ComponentPrivateInputs {} - -impl CircuitComponent for RationalPoStCircuit { - type ComponentPrivateInputs = ComponentPrivateInputs; -} - -impl Circuit for RationalPoStCircuit { - fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { - let comm_rs = self.comm_rs; - let comm_cs = self.comm_cs; - let comm_r_lasts = self.comm_r_lasts; - let leafs = self.leafs; - let paths = self.paths; - - assert_eq!(paths.len(), leafs.len()); - assert_eq!(paths.len(), comm_rs.len()); - assert_eq!(paths.len(), comm_cs.len()); - assert_eq!(paths.len(), comm_r_lasts.len()); - - for (((i, comm_r_last), comm_c), comm_r) in comm_r_lasts - .iter() - .enumerate() - .zip(comm_cs.iter()) - .zip(comm_rs.iter()) - { - let comm_r_last_num = - AllocatedNum::alloc(cs.namespace(|| format!("comm_r_last_{}", i)), || { - comm_r_last - .map(Into::into) - .ok_or(SynthesisError::AssignmentMissing) - })?; - - let comm_c_num = AllocatedNum::alloc(cs.namespace(|| format!("comm_c_{}", i)), || { - comm_c - .map(Into::into) - .ok_or(SynthesisError::AssignmentMissing) - })?; - - let comm_r_num = AllocatedNum::alloc(cs.namespace(|| format!("comm_r_{}", i)), || { - comm_r - .map(Into::into) - .ok_or(SynthesisError::AssignmentMissing) - })?; - - comm_r_num.inputize(cs.namespace(|| format!("comm_r_{}_input", i)))?; - - // Verify H(Comm_C || comm_r_last) == comm_r - { - let hash_num = ::Function::hash2_circuit( - cs.namespace(|| format!("H_comm_c_comm_r_last_{}", i)), - &comm_c_num, - &comm_r_last_num, - )?; - - // Check actual equality - constraint::equal( - cs, - || format!("enforce_comm_c_comm_r_last_hash_comm_r_{}", i), - &comm_r_num, - &hash_num, - ); - } - - PoRCircuit::::synthesize( - cs.namespace(|| format!("challenge_inclusion{}", i)), - Root::Val(leafs[i]), - paths[i].clone().into(), - Root::from_allocated::(comm_r_last_num), - true, - )?; - } - - Ok(()) - } -} diff --git a/storage-proofs-post/src/rational/compound.rs b/storage-proofs-post/src/rational/compound.rs deleted file mode 100644 index 9c84cf06c..000000000 --- a/storage-proofs-post/src/rational/compound.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::marker::PhantomData; - -use anyhow::ensure; -use bellperson::{Circuit, ConstraintSystem, SynthesisError}; -use blstrs::Scalar as Fr; -use generic_array::typenum::U2; -use storage_proofs_core::{ - compound_proof::{CircuitComponent, CompoundProof}, - drgraph::graph_height, - error::Result, - gadgets::por::PoRCompound, - merkle::MerkleTreeTrait, - parameter_cache::{CacheableParameters, ParameterSetMetadata}, - por, - proof::ProofScheme, - util::NODE_SIZE, -}; - -use crate::rational::{RationalPoSt, RationalPoStCircuit}; - -pub struct RationalPoStCompound -where - Tree: MerkleTreeTrait, -{ - _t: PhantomData, -} - -impl, P: ParameterSetMetadata, Tree: MerkleTreeTrait> CacheableParameters - for RationalPoStCompound -{ - fn cache_prefix() -> String { - format!("proof-of-spacetime-rational-{}", Tree::display()) - } -} - -impl<'a, Tree: 'static + MerkleTreeTrait> - CompoundProof<'a, RationalPoSt<'a, Tree>, RationalPoStCircuit> - for RationalPoStCompound -where - Tree: 'static + MerkleTreeTrait, -{ - fn generate_public_inputs( - pub_in: & as ProofScheme<'a>>::PublicInputs, - pub_params: & as ProofScheme<'a>>::PublicParams, - _partition_k: Option, - ) -> Result> { - let mut inputs = Vec::new(); - - let por_pub_params = por::PublicParams { - leaves: (pub_params.sector_size as usize / NODE_SIZE), - private: true, - }; - - ensure!( - pub_in.challenges.len() == pub_in.comm_rs.len(), - "Missmatch in challenges and comm_rs" - ); - - for (challenge, comm_r) in pub_in.challenges.iter().zip(pub_in.comm_rs.iter()) { - inputs.push((*comm_r).into()); - - let por_pub_inputs = por::PublicInputs { - commitment: None, - challenge: challenge.leaf as usize, - }; - let por_inputs = PoRCompound::::generate_public_inputs( - &por_pub_inputs, - &por_pub_params, - None, - )?; - - inputs.extend(por_inputs); - } - - Ok(inputs) - } - - fn circuit( - pub_in: & as ProofScheme<'a>>::PublicInputs, - _priv_in: as CircuitComponent>::ComponentPrivateInputs, - vanilla_proof: & as ProofScheme<'a>>::Proof, - _pub_params: & as ProofScheme<'a>>::PublicParams, - _partition_k: Option, - ) -> Result> { - let comm_rs: Vec<_> = pub_in.comm_rs.iter().map(|c| Some((*c).into())).collect(); - let comm_cs: Vec<_> = vanilla_proof - .comm_cs - .iter() - .map(|c| Some((*c).into())) - .collect(); - - let comm_r_lasts: Vec<_> = vanilla_proof - .commitments() - .into_iter() - .map(|c| Some(c.into())) - .collect(); - - let leafs: Vec<_> = vanilla_proof - .leafs() - .iter() - .map(|c| Some((*c).into())) - .collect(); - - let paths: Vec> = vanilla_proof - .paths() - .iter() - .map(|v| { - v.iter() - .map(|p| { - ( - p.0.iter().copied().map(Into::into).map(Some).collect(), - Some(p.1), - ) - }) - .collect() - }) - .collect(); - - Ok(RationalPoStCircuit { - leafs, - comm_rs, - comm_cs, - comm_r_lasts, - paths, - _t: PhantomData, - }) - } - - fn blank_circuit( - pub_params: & as ProofScheme<'a>>::PublicParams, - ) -> RationalPoStCircuit { - let challenges_count = pub_params.challenges_count; - let height = graph_height::(pub_params.sector_size as usize / NODE_SIZE); - - let comm_rs = vec![None; challenges_count]; - let comm_cs = vec![None; challenges_count]; - let comm_r_lasts = vec![None; challenges_count]; - let leafs = vec![None; challenges_count]; - let paths = vec![vec![(vec![None; 1], None); height - 1]; challenges_count]; - - RationalPoStCircuit { - comm_rs, - comm_cs, - comm_r_lasts, - leafs, - paths, - _t: PhantomData, - } - } -} - -impl RationalPoStCircuit { - #[allow(clippy::type_complexity)] - pub fn synthesize>( - cs: &mut CS, - leafs: Vec>, - comm_rs: Vec>, - comm_cs: Vec>, - comm_r_lasts: Vec>, - paths: Vec>, Option)>>, - ) -> Result<(), SynthesisError> { - Self { - leafs, - comm_rs, - comm_cs, - comm_r_lasts, - paths, - _t: PhantomData, - } - .synthesize(cs) - } -} diff --git a/storage-proofs-post/src/rational/mod.rs b/storage-proofs-post/src/rational/mod.rs deleted file mode 100644 index c63243f96..000000000 --- a/storage-proofs-post/src/rational/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod circuit; -mod compound; -mod vanilla; - -pub use circuit::*; -pub use compound::*; -pub use vanilla::*; diff --git a/storage-proofs-post/src/rational/vanilla.rs b/storage-proofs-post/src/rational/vanilla.rs deleted file mode 100644 index 57c18bbfc..000000000 --- a/storage-proofs-post/src/rational/vanilla.rs +++ /dev/null @@ -1,319 +0,0 @@ -use std::collections::{BTreeMap, HashSet}; -use std::marker::PhantomData; - -use anyhow::{bail, ensure, Context}; -use blake2b_simd::blake2b; -use byteorder::{ByteOrder, LittleEndian}; -use filecoin_hashers::{Domain, HashFunction, Hasher}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use storage_proofs_core::{ - error::{Error, Result}, - merkle::{MerkleProof, MerkleProofTrait, MerkleTreeTrait, MerkleTreeWrapper}, - parameter_cache::ParameterSetMetadata, - proof::{NoRequirements, ProofScheme}, - sector::{OrderedSectorSet, SectorId}, - util::NODE_SIZE, -}; - -#[derive(Debug, Clone)] -pub struct SetupParams { - /// The size of a sector. - pub sector_size: u64, - // TODO: can we drop this? - /// How many challenges there are in total. - pub challenges_count: usize, -} - -#[derive(Debug, Clone)] -pub struct PublicParams { - /// The size of a sector. - pub sector_size: u64, - /// How many challenges there are in total. - pub challenges_count: usize, -} - -impl ParameterSetMetadata for PublicParams { - fn identifier(&self) -> String { - format!( - "RationalPoSt::PublicParams{{sector_size: {} challenges_count: {}}}", - self.sector_size(), - self.challenges_count, - ) - } - - fn sector_size(&self) -> u64 { - self.sector_size - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PublicInputs { - /// The challenges, which leafs to prove. - pub challenges: Vec, - pub faults: OrderedSectorSet, - #[serde(bound = "")] - pub comm_rs: Vec, -} - -#[derive(Debug, Clone)] -#[allow(clippy::type_complexity)] -pub struct PrivateInputs<'a, Tree: 'a + MerkleTreeTrait> { - pub trees: &'a BTreeMap< - SectorId, - &'a MerkleTreeWrapper< - Tree::Hasher, - Tree::Store, - Tree::Arity, - Tree::SubTreeArity, - Tree::TopTreeArity, - >, - >, - pub comm_cs: &'a Vec<::Domain>, - pub comm_r_lasts: &'a Vec<::Domain>, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Proof { - #[serde(bound( - serialize = "MerkleProof: Serialize", - deserialize = "MerkleProof: DeserializeOwned" - ))] - inclusion_proofs: Vec>, - pub comm_cs: Vec<::Domain>, -} - -impl Proof

{ - pub fn leafs(&self) -> Vec<::Domain> { - self.inclusion_proofs - .iter() - .map(MerkleProof::leaf) - .collect() - } - - pub fn commitments(&self) -> Vec<::Domain> { - self.inclusion_proofs - .iter() - .map(MerkleProof::root) - .collect() - } - - #[allow(clippy::type_complexity)] - pub fn paths(&self) -> Vec::Domain>, usize)>> { - self.inclusion_proofs - .iter() - .map(MerkleProof::path) - .collect() - } -} - -#[derive(Debug, Clone)] -pub struct RationalPoSt<'a, Tree> -where - Tree: MerkleTreeTrait, -{ - _t: PhantomData<&'a Tree>, -} - -impl<'a, Tree: 'a + MerkleTreeTrait> ProofScheme<'a> for RationalPoSt<'a, Tree> { - type PublicParams = PublicParams; - type SetupParams = SetupParams; - type PublicInputs = PublicInputs<::Domain>; - type PrivateInputs = PrivateInputs<'a, Tree>; - type Proof = Proof; - type Requirements = NoRequirements; - - fn setup(sp: &Self::SetupParams) -> Result { - Ok(PublicParams { - sector_size: sp.sector_size, - challenges_count: sp.challenges_count, - }) - } - - fn prove<'b>( - _pub_params: &'b Self::PublicParams, - pub_inputs: &'b Self::PublicInputs, - priv_inputs: &'b Self::PrivateInputs, - ) -> Result { - ensure!( - pub_inputs.challenges.len() == pub_inputs.comm_rs.len(), - "mismatched challenges and comm_rs" - ); - ensure!( - pub_inputs.challenges.len() == priv_inputs.comm_cs.len(), - "mismatched challenges and comm_cs" - ); - ensure!( - pub_inputs.challenges.len() == priv_inputs.comm_r_lasts.len(), - "mismatched challenges and comm_r_lasts" - ); - let challenges = &pub_inputs.challenges; - - let proofs = challenges - .iter() - .zip(priv_inputs.comm_r_lasts.iter()) - .map(|(challenge, comm_r_last)| { - let challenged_leaf = challenge.leaf; - - if let Some(tree) = priv_inputs.trees.get(&challenge.sector) { - ensure!(comm_r_last == &tree.root(), Error::InvalidCommitment); - - tree.gen_cached_proof(challenged_leaf as usize, None) - } else { - bail!(Error::MalformedInput); - } - }) - .collect::>>()?; - - Ok(Proof { - inclusion_proofs: proofs, - comm_cs: priv_inputs.comm_cs.to_vec(), - }) - } - - fn verify( - pub_params: &Self::PublicParams, - pub_inputs: &Self::PublicInputs, - proof: &Self::Proof, - ) -> Result { - let challenges = &pub_inputs.challenges; - - ensure!( - challenges.len() == pub_inputs.comm_rs.len(), - Error::MalformedInput - ); - - ensure!( - challenges.len() == proof.inclusion_proofs.len(), - Error::MalformedInput - ); - - // validate each proof - for (((merkle_proof, challenge), comm_r), comm_c) in proof - .inclusion_proofs - .iter() - .zip(challenges.iter()) - .zip(pub_inputs.comm_rs.iter()) - .zip(proof.comm_cs.iter()) - { - let challenged_leaf = challenge.leaf; - - // verify that H(Comm_c || Comm_r_last) == Comm_R - // comm_r_last is the root of the proof - let comm_r_last = merkle_proof.root(); - - if AsRef::<[u8]>::as_ref(&::Function::hash2( - comm_c, - &comm_r_last, - )) != AsRef::<[u8]>::as_ref(&comm_r) - { - return Ok(false); - } - - // validate the path length - let expected_path_length = - merkle_proof.expected_len(pub_params.sector_size as usize / NODE_SIZE); - - if expected_path_length != merkle_proof.path().len() { - return Ok(false); - } - - if !merkle_proof.validate(challenged_leaf as usize) { - return Ok(false); - } - } - - Ok(true) - } -} - -/// A challenge specifying a sector and leaf. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct Challenge { - // The identifier of the challenged sector. - pub sector: SectorId, - // The leaf index this challenge points at. - pub leaf: u64, -} - -/// Rational PoSt specific challenge derivation. -pub fn derive_challenges( - challenge_count: usize, - sector_size: u64, - sectors: &OrderedSectorSet, - seed: &[u8], - faults: &OrderedSectorSet, -) -> Result> { - (0..challenge_count) - .map(|n| { - let mut attempt = 0; - let mut attempted_sectors = HashSet::new(); - loop { - let c = derive_challenge(seed, n as u64, attempt, sector_size, sectors)?; - - // check for faulty sector - if !faults.contains(&c.sector) { - // valid challenge, not found - return Ok(c); - } else { - attempt += 1; - attempted_sectors.insert(c.sector); - - ensure!( - attempted_sectors.len() < sectors.len(), - "all sectors are faulty" - ); - } - } - }) - .collect() -} - -fn derive_challenge( - seed: &[u8], - n: u64, - attempt: u64, - sector_size: u64, - sectors: &OrderedSectorSet, -) -> Result { - let mut data = seed.to_vec(); - data.extend_from_slice(&n.to_le_bytes()[..]); - data.extend_from_slice(&attempt.to_le_bytes()[..]); - - let hash = blake2b(&data); - let challenge_bytes = hash.as_bytes(); - let sector_challenge = LittleEndian::read_u64(&challenge_bytes[..8]); - let leaf_challenge = LittleEndian::read_u64(&challenge_bytes[8..16]); - - let sector_index = (sector_challenge % sectors.len() as u64) as usize; - let sector = *sectors - .iter() - .nth(sector_index) - .context("invalid challenge generated")?; - - Ok(Challenge { - sector, - leaf: leaf_challenge % (sector_size / NODE_SIZE as u64), - }) -} - -#[cfg(test)] -mod tests { - use super::*; - - use std::collections::BTreeSet; - - #[test] - fn test_derive_challenges_fails_on_all_faulty() { - let mut sectors = BTreeSet::new(); - sectors.insert(SectorId::from(1)); - sectors.insert(SectorId::from(2)); - - let mut faults = BTreeSet::new(); - faults.insert(SectorId::from(1)); - faults.insert(SectorId::from(2)); - - let seed = vec![0u8]; - - assert!(derive_challenges(10, 1024, §ors, &seed, &faults).is_err()); - } -} diff --git a/storage-proofs-post/tests/election_circuit.rs b/storage-proofs-post/tests/election_circuit.rs deleted file mode 100644 index 622298e8d..000000000 --- a/storage-proofs-post/tests/election_circuit.rs +++ /dev/null @@ -1,150 +0,0 @@ -use std::collections::BTreeMap; -use std::marker::PhantomData; - -use bellperson::{util_cs::test_cs::TestConstraintSystem, Circuit}; -use blstrs::Scalar as Fr; -use ff::Field; -use filecoin_hashers::{poseidon::PoseidonHasher, Domain, HashFunction, Hasher}; -use generic_array::typenum::{U0, U8}; -use rand::SeedableRng; -use rand_xorshift::XorShiftRng; -use storage_proofs_core::{ - compound_proof::CompoundProof, - merkle::{generate_tree, get_base_tree_count, LCTree, MerkleTreeTrait}, - proof::ProofScheme, - sector::SectorId, - util::NODE_SIZE, - TEST_SEED, -}; -use storage_proofs_post::election::{ - self, generate_candidates, ElectionPoSt, ElectionPoStCircuit, ElectionPoStCompound, -}; -use tempfile::tempdir; - -#[test] -fn test_election_post_circuit_poseidon() { - test_election_post_circuit::>(22_940); -} - -fn test_election_post_circuit(expected_constraints: usize) { - let rng = &mut XorShiftRng::from_seed(TEST_SEED); - - let leaves = 64 * get_base_tree_count::(); - let sector_size = leaves * NODE_SIZE; - - let randomness = ::Domain::random(rng); - let prover_id = ::Domain::random(rng); - - let pub_params = election::PublicParams { - sector_size: sector_size as u64, - challenge_count: 20, - challenged_nodes: 1, - }; - - let mut sectors: Vec = Vec::new(); - let mut trees = BTreeMap::new(); - - let temp_dir = tempdir().unwrap(); - let temp_path = temp_dir.path(); - - for i in 0..5 { - sectors.push(i.into()); - let (_data, tree) = generate_tree::(rng, leaves, Some(temp_path.to_path_buf())); - trees.insert(i.into(), tree); - } - - let candidates = - generate_candidates::(&pub_params, §ors, &trees, prover_id, randomness).unwrap(); - - let candidate = &candidates[0]; - let tree = trees.remove(&candidate.sector_id).unwrap(); - let comm_r_last = tree.root(); - let comm_c = ::Domain::random(rng); - let comm_r = ::Function::hash2(&comm_c, &comm_r_last); - - let pub_inputs = election::PublicInputs { - randomness, - sector_id: candidate.sector_id, - prover_id, - comm_r, - partial_ticket: candidate.partial_ticket, - sector_challenge_index: 0, - }; - - let priv_inputs = election::PrivateInputs:: { - tree, - comm_c, - comm_r_last, - }; - - let proof = ElectionPoSt::::prove(&pub_params, &pub_inputs, &priv_inputs) - .expect("proving failed"); - - let is_valid = ElectionPoSt::::verify(&pub_params, &pub_inputs, &proof) - .expect("verification failed"); - assert!(is_valid); - - // actual circuit test - - let paths = proof - .paths() - .iter() - .map(|p| { - p.iter() - .map(|v| { - ( - v.0.iter().copied().map(Into::into).map(Some).collect(), - Some(v.1), - ) - }) - .collect::>() - }) - .collect(); - let leafs: Vec<_> = proof.leafs().iter().map(|l| Some((*l).into())).collect(); - - let mut cs = TestConstraintSystem::::new(); - - let instance = ElectionPoStCircuit:: { - leafs, - paths, - comm_r: Some(comm_r.into()), - comm_c: Some(comm_c.into()), - comm_r_last: Some(comm_r_last.into()), - partial_ticket: Some(candidate.partial_ticket), - randomness: Some(randomness.into()), - prover_id: Some(prover_id.into()), - sector_id: Some(candidate.sector_id.into()), - _t: PhantomData, - }; - - instance - .synthesize(&mut cs) - .expect("failed to synthesize circuit"); - - assert!(cs.is_satisfied(), "constraints not satisfied"); - - assert_eq!(cs.num_inputs(), 23, "wrong number of inputs"); - assert_eq!( - cs.num_constraints(), - expected_constraints, - "wrong number of constraints" - ); - assert_eq!(cs.get_input(0, "ONE"), Fr::ONE); - - let generated_inputs = - ElectionPoStCompound::::generate_public_inputs(&pub_inputs, &pub_params, None) - .unwrap(); - let expected_inputs = cs.get_inputs(); - - for ((input, label), generated_input) in - expected_inputs.iter().skip(1).zip(generated_inputs.iter()) - { - assert_eq!(input, generated_input, "{}", label); - } - - assert_eq!( - generated_inputs.len(), - expected_inputs.len() - 1, - "inputs are not the same length" - ); -} diff --git a/storage-proofs-post/tests/election_compound.rs b/storage-proofs-post/tests/election_compound.rs deleted file mode 100644 index 413c83aec..000000000 --- a/storage-proofs-post/tests/election_compound.rs +++ /dev/null @@ -1,159 +0,0 @@ -use std::collections::BTreeMap; - -use bellperson::{ - groth16, - util_cs::{metric_cs::MetricCS, test_cs::TestConstraintSystem}, - Circuit, -}; -use filecoin_hashers::{poseidon::PoseidonHasher, Domain, HashFunction, Hasher}; -use generic_array::typenum::{U0, U8}; -use rand::SeedableRng; -use rand_xorshift::XorShiftRng; -use storage_proofs_core::{ - compound_proof::{self, CompoundProof}, - merkle::{generate_tree, get_base_tree_count, LCTree, MerkleTreeTrait}, - multi_proof::MultiProof, - proof::NoRequirements, - sector::SectorId, - util::NODE_SIZE, - TEST_SEED, -}; -use storage_proofs_post::election::{ - generate_candidates, ElectionPoStCompound, PrivateInputs, PublicInputs, SetupParams, -}; -use tempfile::tempdir; - -#[ignore] -#[test] -fn test_election_post_compound_poseidon() { - test_election_post_compound::>(); -} - -fn test_election_post_compound() { - let rng = &mut XorShiftRng::from_seed(TEST_SEED); - - let leaves = 64 * get_base_tree_count::(); - let sector_size = (leaves * NODE_SIZE) as u64; - let randomness = ::Domain::random(rng); - let prover_id = ::Domain::random(rng); - - let setup_params = compound_proof::SetupParams { - vanilla_params: SetupParams { - sector_size, - challenge_count: 20, - challenged_nodes: 1, - }, - partitions: None, - priority: true, - }; - - let mut sectors: Vec = Vec::new(); - let mut trees = BTreeMap::new(); - - let temp_dir = tempdir().unwrap(); - let temp_path = temp_dir.path(); - - for i in 0..5 { - sectors.push(i.into()); - let (_data, tree) = generate_tree::(rng, leaves, Some(temp_path.to_path_buf())); - trees.insert(i.into(), tree); - } - - let pub_params = ElectionPoStCompound::::setup(&setup_params).expect("setup failed"); - - let candidates = generate_candidates::( - &pub_params.vanilla_params, - §ors, - &trees, - prover_id, - randomness, - ) - .unwrap(); - - let candidate = &candidates[0]; - let tree = trees.remove(&candidate.sector_id).unwrap(); - let comm_r_last = tree.root(); - let comm_c = ::Domain::random(rng); - let comm_r = ::Function::hash2(&comm_c, &comm_r_last); - - let pub_inputs = PublicInputs { - randomness, - sector_id: candidate.sector_id, - prover_id, - comm_r, - partial_ticket: candidate.partial_ticket, - sector_challenge_index: 0, - }; - - let priv_inputs = PrivateInputs:: { - tree, - comm_c, - comm_r_last, - }; - - { - let (circuit, inputs) = - ElectionPoStCompound::circuit_for_test(&pub_params, &pub_inputs, &priv_inputs).unwrap(); - - let mut cs = TestConstraintSystem::new(); - - circuit.synthesize(&mut cs).expect("failed to synthesize"); - - if !cs.is_satisfied() { - panic!( - "failed to satisfy: {:?}", - cs.which_is_unsatisfied().unwrap() - ); - } - assert!( - cs.verify(&inputs), - "verification failed with TestContraintSystem and generated inputs" - ); - } - - // Use this to debug differences between blank and regular circuit generation. - { - let (circuit1, _inputs) = - ElectionPoStCompound::circuit_for_test(&pub_params, &pub_inputs, &priv_inputs).unwrap(); - - let blank_circuit = ElectionPoStCompound::::blank_circuit(&pub_params.vanilla_params); - - let mut cs_blank = MetricCS::new(); - blank_circuit - .synthesize(&mut cs_blank) - .expect("failed to synthesize"); - - let a = cs_blank.pretty_print_list(); - - let mut cs1 = TestConstraintSystem::new(); - circuit1.synthesize(&mut cs1).expect("failed to synthesize"); - let b = cs1.pretty_print_list(); - - for (i, (a, b)) in a.chunks(100).zip(b.chunks(100)).enumerate() { - assert_eq!(a, b, "failed at chunk {}", i); - } - } - let blank_groth_params = - ElectionPoStCompound::::groth_params(Some(rng), &pub_params.vanilla_params) - .expect("failed to generate groth params"); - - let proofs = - ElectionPoStCompound::prove(&pub_params, &pub_inputs, &priv_inputs, &blank_groth_params) - .expect("failed while proving"); - - // Don't try to generate the groth parameters, as they should already have been generated by - // the `groth_params()` call above. - let verifying_key = ElectionPoStCompound::::verifying_key::( - None, - &pub_params.vanilla_params, - ) - .expect("failed to get veriyfing key"); - let prepared_verifying_key = groth16::prepare_verifying_key(&verifying_key); - let multi_proof = MultiProof::new(proofs, &prepared_verifying_key); - - let verified = - ElectionPoStCompound::verify(&pub_params, &pub_inputs, &multi_proof, &NoRequirements) - .expect("failed while verifying"); - - assert!(verified); -} diff --git a/storage-proofs-post/tests/election_vanilla.rs b/storage-proofs-post/tests/election_vanilla.rs deleted file mode 100644 index 2b78a2f46..000000000 --- a/storage-proofs-post/tests/election_vanilla.rs +++ /dev/null @@ -1,95 +0,0 @@ -use std::collections::BTreeMap; - -use filecoin_hashers::{poseidon::PoseidonHasher, Domain, HashFunction, Hasher}; -use generic_array::typenum::{U0, U2, U8}; -use rand::SeedableRng; -use rand_xorshift::XorShiftRng; -use storage_proofs_core::{ - merkle::{generate_tree, get_base_tree_count, LCTree, MerkleTreeTrait}, - proof::ProofScheme, - sector::SectorId, - util::NODE_SIZE, - TEST_SEED, -}; -use storage_proofs_post::election::{ - generate_candidates, ElectionPoSt, PrivateInputs, PublicInputs, PublicParams, -}; -use tempfile::tempdir; - -#[test] -fn test_election_post_poseidon_base_8() { - test_election_post::>(); -} - -#[test] -fn test_election_post_poseidon_sub_8_8() { - test_election_post::>(); -} - -#[test] -fn test_election_post_poseidon_top_8_8_2() { - test_election_post::>(); -} - -fn test_election_post() { - let rng = &mut XorShiftRng::from_seed(TEST_SEED); - - let leaves = 64 * get_base_tree_count::(); - let sector_size = leaves * NODE_SIZE; - - let pub_params = PublicParams { - sector_size: sector_size as u64, - challenge_count: 40, - challenged_nodes: 1, - }; - - let randomness = ::Domain::random(rng); - let prover_id = ::Domain::random(rng); - - let mut sectors: Vec = Vec::new(); - let mut trees = BTreeMap::new(); - - let temp_dir = tempdir().expect("tempdir failure"); - let temp_path = temp_dir.path(); - - for i in 0..5 { - sectors.push(i.into()); - let (_data, tree) = generate_tree::(rng, leaves, Some(temp_path.to_path_buf())); - trees.insert(i.into(), tree); - } - - let candidates = - generate_candidates::(&pub_params, §ors, &trees, prover_id, randomness) - .expect("generate candidates failure"); - - let candidate = &candidates[0]; - let tree = trees - .remove(&candidate.sector_id) - .expect("trees.remove failure"); - let comm_r_last = tree.root(); - let comm_c = ::Domain::random(rng); - let comm_r = ::Function::hash2(&comm_c, &comm_r_last); - - let pub_inputs = PublicInputs { - randomness, - sector_id: candidate.sector_id, - prover_id, - comm_r, - partial_ticket: candidate.partial_ticket, - sector_challenge_index: 0, - }; - - let priv_inputs = PrivateInputs:: { - tree, - comm_c, - comm_r_last, - }; - - let proof = ElectionPoSt::::prove(&pub_params, &pub_inputs, &priv_inputs) - .expect("proving failed"); - - let is_valid = ElectionPoSt::::verify(&pub_params, &pub_inputs, &proof) - .expect("verification failed"); - - assert!(is_valid); -} diff --git a/storage-proofs-post/tests/rational_circuit.rs b/storage-proofs-post/tests/rational_circuit.rs deleted file mode 100644 index e028da701..000000000 --- a/storage-proofs-post/tests/rational_circuit.rs +++ /dev/null @@ -1,153 +0,0 @@ -use std::collections::BTreeMap; -use std::marker::PhantomData; - -use bellperson::{util_cs::test_cs::TestConstraintSystem, Circuit}; -use blstrs::Scalar as Fr; -use ff::Field; -use filecoin_hashers::{poseidon::PoseidonHasher, Domain, HashFunction, Hasher}; -use rand::{Rng, SeedableRng}; -use rand_xorshift::XorShiftRng; -use storage_proofs_core::{ - compound_proof::CompoundProof, - merkle::{generate_tree, get_base_tree_count, BinaryMerkleTree, MerkleTreeTrait}, - proof::ProofScheme, - sector::OrderedSectorSet, - util::NODE_SIZE, - TEST_SEED, -}; -use storage_proofs_post::rational::{ - self, derive_challenges, RationalPoSt, RationalPoStCircuit, RationalPoStCompound, -}; -use tempfile::tempdir; - -#[test] -fn test_rational_post_circuit_poseidon() { - test_rational_post_circuit::>(3_770); -} - -fn test_rational_post_circuit(expected_constraints: usize) { - let rng = &mut XorShiftRng::from_seed(TEST_SEED); - - let leaves = 32 * get_base_tree_count::(); - let sector_size = (leaves * NODE_SIZE) as u64; - let challenges_count = 2; - - let pub_params = rational::PublicParams { - sector_size, - challenges_count, - }; - - let temp_dir = tempdir().unwrap(); - let temp_path = temp_dir.path(); - - let (_data1, tree1) = generate_tree::(rng, leaves, Some(temp_path.to_path_buf())); - let (_data2, tree2) = generate_tree::(rng, leaves, Some(temp_path.to_path_buf())); - - let faults = OrderedSectorSet::new(); - let mut sectors = OrderedSectorSet::new(); - sectors.insert(0.into()); - sectors.insert(1.into()); - - let seed = (0..leaves).map(|_| rng.gen()).collect::>(); - let challenges = - derive_challenges(challenges_count, sector_size, §ors, &seed, &faults).unwrap(); - let comm_r_lasts_raw = vec![tree1.root(), tree2.root()]; - let comm_r_lasts: Vec<_> = challenges - .iter() - .map(|c| comm_r_lasts_raw[u64::from(c.sector) as usize]) - .collect(); - - let comm_cs: Vec<::Domain> = challenges - .iter() - .map(|_c| ::Domain::random(rng)) - .collect(); - - let comm_rs: Vec<_> = comm_cs - .iter() - .zip(comm_r_lasts.iter()) - .map(|(comm_c, comm_r_last)| ::Function::hash2(comm_c, comm_r_last)) - .collect(); - - let pub_inputs = rational::PublicInputs { - challenges, - faults, - comm_rs: comm_rs.clone(), - }; - - let mut trees = BTreeMap::new(); - trees.insert(0.into(), &tree1); - trees.insert(1.into(), &tree2); - - let priv_inputs = rational::PrivateInputs:: { - trees: &trees, - comm_cs: &comm_cs, - comm_r_lasts: &comm_r_lasts, - }; - - let proof = RationalPoSt::::prove(&pub_params, &pub_inputs, &priv_inputs) - .expect("proving failed"); - - let is_valid = RationalPoSt::::verify(&pub_params, &pub_inputs, &proof) - .expect("verification failed"); - assert!(is_valid); - - // actual circuit test - - let paths: Vec<_> = proof - .paths() - .iter() - .map(|p| { - p.iter() - .map(|v| { - ( - v.0.iter().copied().map(Into::into).map(Some).collect(), - Some(v.1), - ) - }) - .collect::>() - }) - .collect(); - let leafs: Vec<_> = proof.leafs().iter().map(|l| Some((*l).into())).collect(); - - let mut cs = TestConstraintSystem::::new(); - - let instance = RationalPoStCircuit:: { - leafs, - paths, - comm_rs: comm_rs.iter().copied().map(|c| Some(c.into())).collect(), - comm_cs: comm_cs.into_iter().map(|c| Some(c.into())).collect(), - comm_r_lasts: comm_r_lasts.into_iter().map(|c| Some(c.into())).collect(), - _t: PhantomData, - }; - - instance - .synthesize(&mut cs) - .expect("failed to synthesize circuit"); - - assert!(cs.is_satisfied(), "constraints not satisfied"); - - assert_eq!(cs.num_inputs(), 5, "wrong number of inputs"); - assert_eq!( - cs.num_constraints(), - expected_constraints, - "wrong number of constraints" - ); - assert_eq!(cs.get_input(0, "ONE"), Fr::ONE); - - let generated_inputs = - RationalPoStCompound::::generate_public_inputs(&pub_inputs, &pub_params, None) - .unwrap(); - let expected_inputs = cs.get_inputs(); - - for ((input, label), generated_input) in - expected_inputs.iter().skip(1).zip(generated_inputs.iter()) - { - assert_eq!(input, generated_input, "{}", label); - } - - assert_eq!( - generated_inputs.len(), - expected_inputs.len() - 1, - "inputs are not the same length" - ); -} diff --git a/storage-proofs-post/tests/rational_compound.rs b/storage-proofs-post/tests/rational_compound.rs deleted file mode 100644 index a56a8243e..000000000 --- a/storage-proofs-post/tests/rational_compound.rs +++ /dev/null @@ -1,129 +0,0 @@ -use std::collections::BTreeMap; - -use bellperson::{groth16, util_cs::test_cs::TestConstraintSystem, Circuit}; -use filecoin_hashers::{poseidon::PoseidonHasher, Domain, HashFunction, Hasher}; -use rand::{Rng, SeedableRng}; -use rand_xorshift::XorShiftRng; -use storage_proofs_core::{ - compound_proof::{self, CompoundProof}, - merkle::{generate_tree, get_base_tree_count, BinaryMerkleTree, MerkleTreeTrait}, - multi_proof::MultiProof, - proof::NoRequirements, - sector::OrderedSectorSet, - util::NODE_SIZE, - TEST_SEED, -}; -use storage_proofs_post::rational::{self, derive_challenges, RationalPoStCompound}; -use tempfile::tempdir; - -#[ignore] -#[test] -fn test_rational_post_compound_poseidon() { - test_rational_post_compound::>(); -} - -fn test_rational_post_compound() { - let rng = &mut XorShiftRng::from_seed(TEST_SEED); - - let leaves = 32 * get_base_tree_count::(); - let sector_size = (leaves * NODE_SIZE) as u64; - let challenges_count = 2; - - let setup_params = compound_proof::SetupParams { - vanilla_params: rational::SetupParams { - sector_size, - challenges_count, - }, - partitions: None, - priority: true, - }; - - let pub_params = RationalPoStCompound::::setup(&setup_params).expect("setup failed"); - - let temp_dir = tempdir().unwrap(); - let temp_path = temp_dir.path(); - - let (_data1, tree1) = generate_tree::(rng, leaves, Some(temp_path.to_path_buf())); - let (_data2, tree2) = generate_tree::(rng, leaves, Some(temp_path.to_path_buf())); - - let faults = OrderedSectorSet::new(); - let mut sectors = OrderedSectorSet::new(); - sectors.insert(0.into()); - sectors.insert(1.into()); - - let seed = (0..leaves).map(|_| rng.gen()).collect::>(); - let challenges = - derive_challenges(challenges_count, sector_size, §ors, &seed, &faults).unwrap(); - - let comm_r_lasts_raw = vec![tree1.root(), tree2.root()]; - let comm_r_lasts: Vec<_> = challenges - .iter() - .map(|c| comm_r_lasts_raw[u64::from(c.sector) as usize]) - .collect(); - - let comm_cs: Vec<::Domain> = challenges - .iter() - .map(|_c| ::Domain::random(rng)) - .collect(); - - let comm_rs: Vec<_> = comm_cs - .iter() - .zip(comm_r_lasts.iter()) - .map(|(comm_c, comm_r_last)| ::Function::hash2(comm_c, comm_r_last)) - .collect(); - - let pub_inputs = rational::PublicInputs { - challenges, - faults, - comm_rs, - }; - - let mut trees = BTreeMap::new(); - trees.insert(0.into(), &tree1); - trees.insert(1.into(), &tree2); - - let priv_inputs = rational::PrivateInputs:: { - trees: &trees, - comm_r_lasts: &comm_r_lasts, - comm_cs: &comm_cs, - }; - - let gparams = RationalPoStCompound::::groth_params(Some(rng), &pub_params.vanilla_params) - .expect("failed to create groth params"); - - let proofs = - RationalPoStCompound::::prove(&pub_params, &pub_inputs, &priv_inputs, &gparams) - .expect("proving failed"); - - let (circuit, inputs) = - RationalPoStCompound::::circuit_for_test(&pub_params, &pub_inputs, &priv_inputs) - .unwrap(); - - { - let mut cs = TestConstraintSystem::new(); - - circuit.synthesize(&mut cs).expect("failed to synthesize"); - assert!(cs.is_satisfied()); - assert!(cs.verify(&inputs)); - } - - // Don't try to generate the groth parameters, as they should already have been generated by - // the `groth_params()` call above. - let verifying_key = RationalPoStCompound::::verifying_key::( - None, - &pub_params.vanilla_params, - ) - .expect("failed to get veriyfing key"); - let prepared_verifying_key = groth16::prepare_verifying_key(&verifying_key); - let multi_proof = MultiProof::new(proofs, &prepared_verifying_key); - - let verified = RationalPoStCompound::::verify( - &pub_params, - &pub_inputs, - &multi_proof, - &NoRequirements, - ) - .expect("failed while verifying"); - - assert!(verified); -} diff --git a/storage-proofs-post/tests/rational_vanilla.rs b/storage-proofs-post/tests/rational_vanilla.rs deleted file mode 100644 index f3698ff2b..000000000 --- a/storage-proofs-post/tests/rational_vanilla.rs +++ /dev/null @@ -1,239 +0,0 @@ -use std::collections::BTreeMap; - -use filecoin_hashers::{ - blake2s::Blake2sHasher, poseidon::PoseidonHasher, sha256::Sha256Hasher, Domain, HashFunction, - Hasher, -}; -use generic_array::typenum::{U0, U2, U8}; -use rand::{Rng, SeedableRng}; -use rand_xorshift::XorShiftRng; -use storage_proofs_core::{ - merkle::{generate_tree, get_base_tree_count, LCTree, MerkleTreeTrait}, - proof::ProofScheme, - sector::OrderedSectorSet, - TEST_SEED, -}; -use storage_proofs_post::rational::{self, derive_challenges, RationalPoSt}; -use tempfile::tempdir; - -#[test] -fn test_rational_post_sha256_base_8() { - test_rational_post::>(); -} - -#[test] -fn test_rational_post_blake2s_base_8() { - test_rational_post::>(); -} - -#[test] -fn test_rational_post_poseidon_base_8() { - test_rational_post::>(); -} - -#[test] -fn test_rational_post_poseidon_sub_8_8() { - test_rational_post::>(); -} - -#[test] -fn test_rational_post_poseidon_top_8_8_2() { - test_rational_post::>(); -} - -fn test_rational_post() -where - Tree::Store: 'static, -{ - let rng = &mut XorShiftRng::from_seed(TEST_SEED); - - let leaves = 64 * get_base_tree_count::(); - let sector_size = leaves as u64 * 32; - let challenges_count = 8; - - let pub_params = rational::PublicParams { - sector_size, - challenges_count, - }; - - let temp_dir = tempdir().unwrap(); - let temp_path = temp_dir.path(); - - let (_data1, tree1) = generate_tree::(rng, leaves, Some(temp_path.to_path_buf())); - let (_data2, tree2) = generate_tree::(rng, leaves, Some(temp_path.to_path_buf())); - - let seed = (0..leaves).map(|_| rng.gen()).collect::>(); - let mut faults = OrderedSectorSet::new(); - faults.insert(139.into()); - faults.insert(1.into()); - faults.insert(32.into()); - - let mut sectors = OrderedSectorSet::new(); - sectors.insert(891.into()); - sectors.insert(139.into()); - sectors.insert(32.into()); - sectors.insert(1.into()); - - let mut trees = BTreeMap::new(); - trees.insert(139.into(), &tree1); // faulty with tree - trees.insert(891.into(), &tree2); - // other two faults don't have a tree available - - let challenges = - derive_challenges(challenges_count, sector_size, §ors, &seed, &faults).unwrap(); - - // the only valid sector to challenge is 891 - assert!( - challenges.iter().all(|c| c.sector == 891.into()), - "invalid challenge generated" - ); - - let comm_r_lasts = challenges - .iter() - .map(|c| trees.get(&c.sector).unwrap().root()) - .collect::>(); - - let comm_cs: Vec<::Domain> = challenges - .iter() - .map(|_c| ::Domain::random(rng)) - .collect(); - - let comm_rs: Vec<::Domain> = comm_cs - .iter() - .zip(comm_r_lasts.iter()) - .map(|(comm_c, comm_r_last)| ::Function::hash2(comm_c, comm_r_last)) - .collect(); - - let pub_inputs = rational::PublicInputs { - challenges, - comm_rs, - faults, - }; - - let priv_inputs = rational::PrivateInputs:: { - trees: &trees, - comm_cs: &comm_cs, - comm_r_lasts: &comm_r_lasts, - }; - - let proof = RationalPoSt::::prove(&pub_params, &pub_inputs, &priv_inputs) - .expect("proving failed"); - - let is_valid = RationalPoSt::::verify(&pub_params, &pub_inputs, &proof) - .expect("verification failed"); - - assert!(is_valid); -} - -#[test] -fn test_rational_post_validates_challenge_sha256_base_8() { - test_rational_post_validates_challenge::>(); -} - -#[test] -fn test_rational_post_validates_challenge_blake2s_base_8() { - test_rational_post_validates_challenge::>(); -} - -#[test] -fn test_rational_post_validates_challenge_poseidon_base_8() { - test_rational_post_validates_challenge::>(); -} - -#[test] -fn test_rational_post_validates_challenge_poseidon_sub_8_8() { - test_rational_post_validates_challenge::>(); -} - -#[test] -fn test_rational_post_validates_challenge_poseidon_top_8_8_2() { - test_rational_post_validates_challenge::>(); -} - -fn test_rational_post_validates_challenge() { - let rng = &mut XorShiftRng::from_seed(TEST_SEED); - - let leaves = 64 * get_base_tree_count::(); - let sector_size = leaves as u64 * 32; - let challenges_count = 2; - - let pub_params = rational::PublicParams { - sector_size, - challenges_count, - }; - - let temp_dir = tempdir().unwrap(); - let temp_path = temp_dir.path(); - - let (_data, tree) = generate_tree::(rng, leaves, Some(temp_path.to_path_buf())); - let seed = (0..leaves).map(|_| rng.gen()).collect::>(); - let mut faults = OrderedSectorSet::new(); - faults.insert(1.into()); - let mut sectors = OrderedSectorSet::new(); - sectors.insert(0.into()); - sectors.insert(1.into()); - - let mut trees = BTreeMap::new(); - trees.insert(0.into(), &tree); - - let challenges = - derive_challenges(challenges_count, sector_size, §ors, &seed, &faults).unwrap(); - let comm_r_lasts = challenges - .iter() - .map(|c| trees.get(&c.sector).unwrap().root()) - .collect::>(); - - let comm_cs: Vec<::Domain> = challenges - .iter() - .map(|_c| ::Domain::random(rng)) - .collect(); - - let comm_rs: Vec<::Domain> = comm_cs - .iter() - .zip(comm_r_lasts.iter()) - .map(|(comm_c, comm_r_last)| ::Function::hash2(comm_c, comm_r_last)) - .collect(); - - let pub_inputs = rational::PublicInputs { - challenges, - faults: faults.clone(), - comm_rs, - }; - - let priv_inputs = rational::PrivateInputs:: { - trees: &trees, - comm_cs: &comm_cs, - comm_r_lasts: &comm_r_lasts, - }; - - let proof = RationalPoSt::::prove(&pub_params, &pub_inputs, &priv_inputs) - .expect("proving failed"); - - let seed = (0..leaves).map(|_| rng.gen()).collect::>(); - let challenges = - derive_challenges(challenges_count, sector_size, §ors, &seed, &faults).unwrap(); - let comm_r_lasts = challenges.iter().map(|_c| tree.root()).collect::>(); - - let comm_cs: Vec<::Domain> = challenges - .iter() - .map(|_c| ::Domain::random(rng)) - .collect(); - - let comm_rs: Vec<::Domain> = comm_cs - .iter() - .zip(comm_r_lasts.iter()) - .map(|(comm_c, comm_r_last)| ::Function::hash2(comm_c, comm_r_last)) - .collect(); - - let different_pub_inputs = rational::PublicInputs { - challenges, - faults, - comm_rs, - }; - - let verified = RationalPoSt::::verify(&pub_params, &different_pub_inputs, &proof) - .expect("verification failed"); - - // A proof created with a the wrong challenge not be verified! - assert!(!verified); -}