diff --git a/storage-proofs/src/circuit/kdf.rs b/storage-proofs/src/circuit/create_label.rs similarity index 88% rename from storage-proofs/src/circuit/kdf.rs rename to storage-proofs/src/circuit/create_label.rs index 840d71bd7..6bc20a394 100644 --- a/storage-proofs/src/circuit/kdf.rs +++ b/storage-proofs/src/circuit/create_label.rs @@ -8,7 +8,7 @@ use fil_sapling_crypto::jubjub::JubjubEngine; use crate::circuit::uint64; /// Key derivation function. -pub fn kdf( +pub fn create_label( mut cs: CS, id: &[Boolean], parents: Vec>, @@ -18,7 +18,7 @@ where E: JubjubEngine, CS: ConstraintSystem, { - trace!("circuit: kdf"); + trace!("circuit: create_label"); // ciphertexts will become a buffer of the layout // id | node | encodedParentNode1 | encodedParentNode1 | ... @@ -32,7 +32,7 @@ where ciphertexts.extend_from_slice(&parent); } - trace!("circuit: kdf: sha256"); + trace!("circuit: create_label: sha256"); let alloc_bits = sha256_circuit(cs.namespace(|| "hash"), &ciphertexts[..])?; let fr = if alloc_bits[0].get_value().is_some() { let be_bits = alloc_bits @@ -68,7 +68,7 @@ mod tests { use rand::{Rng, SeedableRng, XorShiftRng}; #[test] - fn kdf_circuit_no_node() { + fn create_label_circuit_no_node() { let mut cs = TestConstraintSystem::::new(); let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); @@ -90,8 +90,13 @@ mod tests { bytes_into_boolean_vec_be(&mut cs, Some(p.as_slice()), p.len()).unwrap() }) .collect(); - let out = kdf(cs.namespace(|| "kdf"), &id_bits, parents_bits.clone(), None) - .expect("key derivation function failed"); + let out = create_label( + cs.namespace(|| "create_label"), + &id_bits, + parents_bits.clone(), + None, + ) + .expect("key derivation function failed"); assert!(cs.is_satisfied(), "constraints not satisfied"); assert_eq!(cs.num_constraints(), 292540); @@ -101,7 +106,7 @@ mod tests { acc }); - let expected = crypto::kdf::kdf(input_bytes.as_slice(), m); + let expected = crypto::create_label::create_label(input_bytes.as_slice(), m); assert_eq!( expected, @@ -110,7 +115,7 @@ mod tests { ); } #[test] - fn kdf_circuit_with_node() { + fn create_label_circuit_with_node() { let mut cs = TestConstraintSystem::::new(); let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); @@ -136,8 +141,8 @@ mod tests { let node_raw = 123456789u64; let node = uint64::UInt64::constant(node_raw); - let out = kdf( - cs.namespace(|| "kdf"), + let out = create_label( + cs.namespace(|| "create_label"), &id_bits, parents_bits.clone(), Some(node), @@ -154,7 +159,7 @@ mod tests { input_bytes.extend_from_slice(parent); } - let expected = crypto::kdf::kdf(input_bytes.as_slice(), m); + let expected = crypto::create_label::create_label(input_bytes.as_slice(), m); assert_eq!( expected, diff --git a/storage-proofs/src/circuit/drgporep.rs b/storage-proofs/src/circuit/drgporep.rs index e26e5c70e..d679eca78 100644 --- a/storage-proofs/src/circuit/drgporep.rs +++ b/storage-proofs/src/circuit/drgporep.rs @@ -7,8 +7,8 @@ use fil_sapling_crypto::jubjub::JubjubEngine; use paired::bls12_381::{Bls12, Fr}; use crate::circuit::constraint; +use crate::circuit::create_label::create_label as kdf; use crate::circuit::encode; -use crate::circuit::kdf::kdf; use crate::circuit::por::{PoRCircuit, PoRCompound}; use crate::circuit::variables::Root; use crate::compound_proof::{CircuitComponent, CompoundProof}; diff --git a/storage-proofs/src/circuit/mod.rs b/storage-proofs/src/circuit/mod.rs index fe7f6be3f..93426b9de 100644 --- a/storage-proofs/src/circuit/mod.rs +++ b/storage-proofs/src/circuit/mod.rs @@ -1,8 +1,8 @@ mod constraint; +pub mod create_label; pub mod drgporep; pub mod encode; -pub mod kdf; pub mod multi_proof; pub mod pedersen; pub mod por; diff --git a/storage-proofs/src/circuit/stacked/encoding_proof.rs b/storage-proofs/src/circuit/stacked/encoding_proof.rs index c94b19f18..6b85719c1 100644 --- a/storage-proofs/src/circuit/stacked/encoding_proof.rs +++ b/storage-proofs/src/circuit/stacked/encoding_proof.rs @@ -3,7 +3,7 @@ use fil_sapling_crypto::circuit::{boolean::Boolean, num}; use fil_sapling_crypto::jubjub::JubjubEngine; use paired::bls12_381::{Bls12, Fr}; -use crate::circuit::{constraint, encode::encode, kdf::kdf, uint64}; +use crate::circuit::{constraint, create_label::create_label as kdf, encode::encode, uint64}; use crate::drgraph::Graph; use crate::fr32::fr_into_bytes; use crate::hasher::Hasher; @@ -18,15 +18,10 @@ pub struct EncodingProof { impl EncodingProof { /// Create an empty proof, used in `blank_circuit`s. - pub fn empty(params: &PublicParams, layer: usize) -> Self { - let degree = if layer == 1 { - params.graph.base_graph().degree() - } else { - params.graph.degree() - }; + pub fn empty(params: &PublicParams) -> Self { EncodingProof { node: None, - parents: vec![None; degree], + parents: vec![None; params.graph.degree()], } } @@ -68,30 +63,7 @@ impl EncodingProof { ) } - pub fn synthesize_key>( - self, - mut cs: CS, - params: &::Params, - replica_id: &[Boolean], - exp_encoded_node: &num::AllocatedNum, - ) -> Result<(), SynthesisError> { - let EncodingProof { node, parents } = self; - - let key = Self::create_key( - cs.namespace(|| "create_key"), - params, - replica_id, - node, - parents, - )?; - - // enforce equality - constraint::equal(&mut cs, || "equality_key", &exp_encoded_node, &key); - - Ok(()) - } - - pub fn synthesize_decoded>( + pub fn synthesize>( self, mut cs: CS, params: &::Params, diff --git a/storage-proofs/src/circuit/stacked/labeling_proof.rs b/storage-proofs/src/circuit/stacked/labeling_proof.rs new file mode 100644 index 000000000..711984528 --- /dev/null +++ b/storage-proofs/src/circuit/stacked/labeling_proof.rs @@ -0,0 +1,104 @@ +use bellperson::{ConstraintSystem, SynthesisError}; +use fil_sapling_crypto::circuit::{boolean::Boolean, num}; +use fil_sapling_crypto::jubjub::JubjubEngine; +use paired::bls12_381::{Bls12, Fr}; + +use crate::circuit::{constraint, create_label::create_label, uint64}; +use crate::drgraph::Graph; +use crate::fr32::fr_into_bytes; +use crate::hasher::Hasher; +use crate::stacked::{LabelingProof as VanillaLabelingProof, PublicParams}; +use crate::util::bytes_into_boolean_vec_be; + +#[derive(Debug, Clone)] +pub struct LabelingProof { + node: Option, + parents: Vec>, +} + +impl LabelingProof { + /// Create an empty proof, used in `blank_circuit`s. + pub fn empty(params: &PublicParams, layer: usize) -> Self { + let degree = if layer == 1 { + params.graph.base_graph().degree() + } else { + params.graph.degree() + }; + LabelingProof { + node: None, + parents: vec![None; degree], + } + } + + fn create_label>( + mut cs: CS, + _params: &::Params, + replica_id: &[Boolean], + node: Option, + parents: Vec>, + ) -> Result, SynthesisError> { + // get the parents into bits + let parents_bits: Vec> = parents + .iter() + .enumerate() + .map(|(i, val)| match val { + Some(val) => { + let bytes = fr_into_bytes::(val); + bytes_into_boolean_vec_be( + cs.namespace(|| format!("parents_{}_bits", i)), + Some(&bytes), + 256, + ) + } + None => bytes_into_boolean_vec_be( + cs.namespace(|| format!("parents_{}_bits", i)), + None, + 256, + ), + }) + .collect::>, SynthesisError>>()?; + + let node_num = uint64::UInt64::alloc(cs.namespace(|| "node"), node)?; + + create_label( + cs.namespace(|| "create_label"), + replica_id, + parents_bits, + Some(node_num), + ) + } + + pub fn synthesize>( + self, + mut cs: CS, + params: &::Params, + replica_id: &[Boolean], + exp_encoded_node: &num::AllocatedNum, + ) -> Result<(), SynthesisError> { + let LabelingProof { node, parents } = self; + + let key = Self::create_label( + cs.namespace(|| "create_label"), + params, + replica_id, + node, + parents, + )?; + + // enforce equality + constraint::equal(&mut cs, || "equality_key", &exp_encoded_node, &key); + + Ok(()) + } +} + +impl From> for LabelingProof { + fn from(vanilla_proof: VanillaLabelingProof) -> Self { + let VanillaLabelingProof { parents, node, .. } = vanilla_proof; + + LabelingProof { + node: Some(node), + parents: parents.into_iter().map(|p| Some(p.into())).collect(), + } + } +} diff --git a/storage-proofs/src/circuit/stacked/mod.rs b/storage-proofs/src/circuit/stacked/mod.rs index 7bd72fe8b..dea4a20b8 100644 --- a/storage-proofs/src/circuit/stacked/mod.rs +++ b/storage-proofs/src/circuit/stacked/mod.rs @@ -2,6 +2,7 @@ mod column; mod column_proof; mod encoding_proof; pub(crate) mod hash; +mod labeling_proof; mod params; mod proof; diff --git a/storage-proofs/src/circuit/stacked/params.rs b/storage-proofs/src/circuit/stacked/params.rs index 57810f5e3..5d1896e90 100644 --- a/storage-proofs/src/circuit/stacked/params.rs +++ b/storage-proofs/src/circuit/stacked/params.rs @@ -5,7 +5,9 @@ use fil_sapling_crypto::circuit::{boolean::Boolean, num}; use fil_sapling_crypto::jubjub::JubjubEngine; use paired::bls12_381::{Bls12, Fr}; -use crate::circuit::stacked::{column_proof::ColumnProof, encoding_proof::EncodingProof}; +use crate::circuit::stacked::{ + column_proof::ColumnProof, encoding_proof::EncodingProof, labeling_proof::LabelingProof, +}; use crate::circuit::{por::PoRCircuit, variables::Root}; use crate::drgraph::Graph; use crate::hasher::Hasher; @@ -19,7 +21,8 @@ pub struct Proof { pub comm_d_proof: InclusionPath, pub comm_r_last_proof: InclusionPath, pub replica_column_proof: ReplicaColumnProof, - pub encoding_proofs: Vec, + pub labeling_proofs: Vec<(usize, LabelingProof)>, + pub encoding_proof: EncodingProof, } impl Proof { @@ -27,22 +30,25 @@ impl Proof { pub fn empty(params: &PublicParams, challenge_index: usize) -> Self { let layers = params.layer_challenges.layers(); - let mut encoding_proofs = Vec::with_capacity(layers); + let mut labeling_proofs = Vec::with_capacity(layers); for layer in 1..=layers { - if !params + let include_challenge = params .layer_challenges - .include_challenge_at_layer(layer, challenge_index) - { + .include_challenge_at_layer(layer, challenge_index); + + if !include_challenge { continue; } - encoding_proofs.push(EncodingProof::empty(params, layer)); + labeling_proofs.push((layer, LabelingProof::empty(params, layer))); } + Proof { comm_d_proof: InclusionPath::empty(¶ms.graph), comm_r_last_proof: InclusionPath::empty(¶ms.graph), replica_column_proof: ReplicaColumnProof::empty(params), - encoding_proofs, + labeling_proofs, + encoding_proof: EncodingProof::empty(params), } } @@ -62,7 +68,8 @@ impl Proof { comm_d_proof, comm_r_last_proof, replica_column_proof, - encoding_proofs, + labeling_proofs, + encoding_proof, } = self; // verify initial data layer @@ -78,36 +85,30 @@ impl Proof { comm_r_last_proof.alloc_value(cs.namespace(|| "comm_r_last_data_leaf"))?; // verify encodings - for (i, proof) in encoding_proofs.into_iter().enumerate() { - let layer = i + 1; - - if layer == layers { - proof.synthesize_decoded( - cs.namespace(|| format!("encoding_proof_{}", layer)), - params, - replica_id, - &comm_r_last_data_leaf, - &comm_d_leaf, - )?; - } else { - let raw = replica_column_proof.c_x.get_node_at_layer(layer); - let encoded_node = num::AllocatedNum::alloc( - cs.namespace(|| format!("enc_node_{}", layer)), - || { - raw.map(Into::into) - .ok_or_else(|| SynthesisError::AssignmentMissing) - }, - )?; - - proof.synthesize_key( - cs.namespace(|| format!("encoding_proof_{}", layer)), - params, - replica_id, - &encoded_node, - )?; - } + for (layer, proof) in labeling_proofs.into_iter() { + let raw = replica_column_proof.c_x.get_node_at_layer(layer); + let labeled_node = + num::AllocatedNum::alloc(cs.namespace(|| format!("label_node_{}", layer)), || { + raw.map(Into::into) + .ok_or_else(|| SynthesisError::AssignmentMissing) + })?; + + proof.synthesize( + cs.namespace(|| format!("labeling_proof_{}", layer)), + params, + replica_id, + &labeled_node, + )?; } + encoding_proof.synthesize( + cs.namespace(|| format!("encoding_proof_{}", layers)), + params, + replica_id, + &comm_r_last_data_leaf, + &comm_d_leaf, + )?; + // verify replica column openings replica_column_proof.synthesize(cs.namespace(|| "replica_column_proof"), params, comm_c)?; @@ -129,14 +130,23 @@ impl From> for Proof { comm_d_proofs, comm_r_last_proof, replica_column_proofs, - encoding_proofs, + labeling_proofs, + encoding_proof, } = vanilla_proof; + let mut labeling_proofs: Vec<_> = labeling_proofs + .into_iter() + .map(|(layer, p)| (layer, p.into())) + .collect(); + + labeling_proofs.sort_by_cached_key(|(k, _)| *k); + Proof { comm_d_proof: comm_d_proofs.into(), comm_r_last_proof: comm_r_last_proof.into(), replica_column_proof: replica_column_proofs.into(), - encoding_proofs: encoding_proofs.into_iter().map(|p| p.into()).collect(), + labeling_proofs, + encoding_proof: encoding_proof.into(), } } } diff --git a/storage-proofs/src/circuit/stacked/proof.rs b/storage-proofs/src/circuit/stacked/proof.rs index c6f42d931..647727e1f 100644 --- a/storage-proofs/src/circuit/stacked/proof.rs +++ b/storage-proofs/src/circuit/stacked/proof.rs @@ -401,7 +401,7 @@ mod tests { assert!(proofs_are_valid); let expected_inputs = 20; - let expected_constraints = 329_930; + let expected_constraints = 649_106; { // Verify that MetricCS returns the same metrics as TestConstraintSystem. diff --git a/storage-proofs/src/crypto/kdf.rs b/storage-proofs/src/crypto/create_label.rs similarity index 82% rename from storage-proofs/src/crypto/kdf.rs rename to storage-proofs/src/crypto/create_label.rs index 9e555de22..ade89a469 100644 --- a/storage-proofs/src/crypto/kdf.rs +++ b/storage-proofs/src/crypto/create_label.rs @@ -5,19 +5,19 @@ use sha2::{Digest, Sha256}; use crate::fr32::bytes_into_fr_repr_safe; /// Key derivation function, based on pedersen hashing. -pub fn kdf(data: &[u8], _m: usize) -> Fr { +pub fn create_label(data: &[u8], _m: usize) -> Fr { let hash = Sha256::digest(data); Fr::from_repr(bytes_into_fr_repr_safe(hash.as_ref())).unwrap() } #[cfg(test)] mod tests { - use super::kdf; + use super::create_label; use ff::PrimeField; use paired::bls12_381::{Fr, FrRepr}; #[test] - fn kdf_valid_block_len() { + fn create_label_valid_block_len() { let m = 1; let size = 32 * (1 + m); @@ -30,7 +30,7 @@ mod tests { ]; let expected = Fr::from_repr(FrRepr(repr)).unwrap(); - let res = kdf(&data, m); + let res = create_label(&data, m); assert_eq!(res, expected); } } diff --git a/storage-proofs/src/crypto/mod.rs b/storage-proofs/src/crypto/mod.rs index df63d60da..10a334626 100644 --- a/storage-proofs/src/crypto/mod.rs +++ b/storage-proofs/src/crypto/mod.rs @@ -1,6 +1,6 @@ pub mod aes; +pub mod create_label; pub mod feistel; -pub mod kdf; pub mod pedersen; pub mod sloth; pub mod xor; diff --git a/storage-proofs/src/hasher/blake2s.rs b/storage-proofs/src/hasher/blake2s.rs index f8902305d..9ae30b108 100644 --- a/storage-proofs/src/hasher/blake2s.rs +++ b/storage-proofs/src/hasher/blake2s.rs @@ -26,7 +26,7 @@ impl Hasher for Blake2sHasher { "Blake2sHasher".into() } - fn kdf(data: &[u8], m: usize) -> Self::Domain { + fn create_label(data: &[u8], m: usize) -> Self::Domain { assert_eq!( data.len(), 32 * (1 + m), diff --git a/storage-proofs/src/hasher/pedersen.rs b/storage-proofs/src/hasher/pedersen.rs index 420713092..7580e2fc8 100644 --- a/storage-proofs/src/hasher/pedersen.rs +++ b/storage-proofs/src/hasher/pedersen.rs @@ -11,7 +11,7 @@ use paired::bls12_381::{Bls12, Fr, FrRepr}; use rand::{Rand, Rng}; use crate::circuit::pedersen::pedersen_md_no_padding; -use crate::crypto::{kdf, pedersen, sloth}; +use crate::crypto::{create_label, pedersen, sloth}; use crate::error::{Error, Result}; use crate::hasher::{Domain, HashFunction, Hasher}; @@ -26,8 +26,8 @@ impl Hasher for PedersenHasher { "PedersenHasher".into() } - fn kdf(data: &[u8], m: usize) -> Self::Domain { - kdf::kdf(data, m).into() + fn create_label(data: &[u8], m: usize) -> Self::Domain { + create_label::create_label(data, m).into() } #[inline] diff --git a/storage-proofs/src/hasher/sha256.rs b/storage-proofs/src/hasher/sha256.rs index a49458e65..109b89d9f 100644 --- a/storage-proofs/src/hasher/sha256.rs +++ b/storage-proofs/src/hasher/sha256.rs @@ -26,15 +26,7 @@ impl Hasher for Sha256Hasher { "Sha256Hasher".into() } - fn kdf(data: &[u8], m: usize) -> Self::Domain { - assert_eq!( - data.len(), - 32 * (1 + m), - "invalid input length: data.len(): {} m: {}", - data.len(), - m - ); - + fn create_label(data: &[u8], _m: usize) -> Self::Domain { >::hash(data) } diff --git a/storage-proofs/src/hasher/types.rs b/storage-proofs/src/hasher/types.rs index 42e1291f5..1d9ca871a 100644 --- a/storage-proofs/src/hasher/types.rs +++ b/storage-proofs/src/hasher/types.rs @@ -73,7 +73,7 @@ pub trait Hasher: Clone + ::std::fmt::Debug + Eq + Default + Send + Sync { type Domain: Domain + LightHashable + AsRef; type Function: HashFunction; - fn kdf(data: &[u8], m: usize) -> Self::Domain; + fn create_label(data: &[u8], m: usize) -> Self::Domain; fn sloth_encode(key: &Self::Domain, ciphertext: &Self::Domain) -> Self::Domain; fn sloth_decode(key: &Self::Domain, ciphertext: &Self::Domain) -> Self::Domain; diff --git a/storage-proofs/src/stacked/challenges.rs b/storage-proofs/src/stacked/challenges.rs index c119ec0f7..71a6e3d83 100644 --- a/storage-proofs/src/stacked/challenges.rs +++ b/storage-proofs/src/stacked/challenges.rs @@ -29,7 +29,7 @@ impl LayerChallenges { assert!(layer <= self.layers, "Layer too large"); // TODO: proper tapering - if layer == 1 { + if layer == self.layers { self.max_count } else { self.max_count / 2 diff --git a/storage-proofs/src/stacked/column_proof.rs b/storage-proofs/src/stacked/column_proof.rs index fe9541cef..ce3bec1a0 100644 --- a/storage-proofs/src/stacked/column_proof.rs +++ b/storage-proofs/src/stacked/column_proof.rs @@ -22,13 +22,10 @@ pub struct ColumnProof { impl ColumnProof { pub fn from_column(column: Column, inclusion_proof: MerkleProof) -> Self { - let res = ColumnProof { + ColumnProof { column, inclusion_proof, - }; - debug_assert!(res.verify()); - - res + } } pub fn root(&self) -> &H::Domain { @@ -52,10 +49,12 @@ impl ColumnProof { self.column.hash() } - pub fn verify(&self) -> bool { + pub fn verify(&self, challenge: u32, expected_root: &H::Domain) -> bool { let c_i = self.column_hash(); + check_eq!(self.inclusion_proof.root(), expected_root); check!(self.inclusion_proof.validate_data(c_i.as_ref())); + check!(self.inclusion_proof.validate(challenge as usize)); true } diff --git a/storage-proofs/src/stacked/encoding_proof.rs b/storage-proofs/src/stacked/encoding_proof.rs index fefff4b4e..664f2b719 100644 --- a/storage-proofs/src/stacked/encoding_proof.rs +++ b/storage-proofs/src/stacked/encoding_proof.rs @@ -44,16 +44,12 @@ impl EncodingProof { &self, replica_id: &H::Domain, exp_encoded_node: &H::Domain, - decoded_node: Option<&G::Domain>, + decoded_node: &G::Domain, ) -> bool { let key = self.create_key(replica_id); - let encoded_node = if let Some(decoded_node) = decoded_node { - let fr: Fr = (*decoded_node).into(); - encode(key, fr.into()) - } else { - key - }; + let fr: Fr = (*decoded_node).into(); + let encoded_node = encode(key, fr.into()); check_eq!(exp_encoded_node, &encoded_node); diff --git a/storage-proofs/src/stacked/labeling_proof.rs b/storage-proofs/src/stacked/labeling_proof.rs new file mode 100644 index 000000000..e07f6105f --- /dev/null +++ b/storage-proofs/src/stacked/labeling_proof.rs @@ -0,0 +1,47 @@ +use std::marker::PhantomData; + +use sha2::{Digest, Sha256}; + +use crate::fr32::bytes_into_fr_repr_safe; +use crate::hasher::Hasher; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LabelingProof { + pub(crate) parents: Vec, + pub(crate) node: u64, + #[serde(skip)] + _h: PhantomData, +} + +impl LabelingProof { + pub fn new(node: u64, parents: Vec) -> Self { + LabelingProof { + node, + parents, + _h: PhantomData, + } + } + + fn create_label(&self, replica_id: &H::Domain) -> H::Domain { + let mut hasher = Sha256::new(); + + // replica_id + hasher.input(AsRef::<[u8]>::as_ref(replica_id)); + + // node id + hasher.input(&(self.node as u64).to_be_bytes()); + + for parent in &self.parents { + hasher.input(AsRef::<[u8]>::as_ref(parent)); + } + + bytes_into_fr_repr_safe(hasher.result().as_ref()).into() + } + + pub fn verify(&self, replica_id: &H::Domain, expected_label: &H::Domain) -> bool { + let label = self.create_label(replica_id); + check_eq!(expected_label, &label); + + true + } +} diff --git a/storage-proofs/src/stacked/mod.rs b/storage-proofs/src/stacked/mod.rs index 4d508c7c4..51792e925 100644 --- a/storage-proofs/src/stacked/mod.rs +++ b/storage-proofs/src/stacked/mod.rs @@ -7,6 +7,7 @@ mod column_proof; mod encoding_proof; mod graph; pub(crate) mod hash; +mod labeling_proof; mod params; mod porep; mod proof; @@ -22,3 +23,4 @@ pub use self::params::{ ReplicaColumnProof, SetupParams, Tau, TemporaryAux, }; pub use self::proof::StackedDrg; +pub use labeling_proof::LabelingProof; diff --git a/storage-proofs/src/stacked/params.rs b/storage-proofs/src/stacked/params.rs index 158e787f6..fc6444dfe 100644 --- a/storage-proofs/src/stacked/params.rs +++ b/storage-proofs/src/stacked/params.rs @@ -1,8 +1,8 @@ +use std::collections::HashMap; use std::marker::PhantomData; use merkletree::store::DiskStore; use merkletree::store::Store; -use paired::bls12_381::Fr; use serde::{Deserialize, Serialize}; use crate::drgraph::Graph; @@ -12,8 +12,8 @@ use crate::hasher::{Domain, Hasher}; use crate::merkle::{MerkleProof, MerkleTree}; use crate::parameter_cache::ParameterSetMetadata; use crate::stacked::{ - column::Column, column_proof::ColumnProof, encoding_proof::EncodingProof, - graph::StackedBucketGraph, hash::hash2, LayerChallenges, + column::Column, column_proof::ColumnProof, graph::StackedBucketGraph, EncodingProof, + LabelingProof, LayerChallenges, }; use crate::util::data_at_node; @@ -140,12 +140,17 @@ pub struct Proof { deserialize = "ReplicaColumnProof: Deserialize<'de>" ))] pub replica_column_proofs: ReplicaColumnProof, + #[serde(bound( + serialize = "LabelingProof: Serialize", + deserialize = "LabelingProof: Deserialize<'de>" + ))] + /// Indexed by layer in 1..layers. + pub labeling_proofs: HashMap>, #[serde(bound( serialize = "EncodingProof: Serialize", deserialize = "EncodingProof: Deserialize<'de>" ))] - /// Indexed by layer in 1..layers. - pub encoding_proofs: Vec>, + pub encoding_proof: EncodingProof, } impl Proof { @@ -157,10 +162,6 @@ impl Proof { self.replica_column_proofs.c_x.root() } - fn comm_r(&self) -> H::Domain { - Fr::from(hash2(self.comm_c(), self.comm_r_last())).into() - } - /// Verify the full proof. pub fn verify( &self, @@ -175,20 +176,11 @@ impl Proof { check!(challenge < graph.size()); check!(pub_inputs.tau.is_some()); - // just grabbing the first one - let actual_comm_r = self.comm_r(); - let expected_comm_r = if let Some(ref tau) = pub_inputs.tau { - &tau.comm_r - } else { - return false; - }; - - check_eq!(expected_comm_r, &actual_comm_r); - // Verify initial data layer trace!("verify initial data layer"); check!(self.comm_d_proofs.proves_challenge(challenge)); + if let Some(ref tau) = pub_inputs.tau { check_eq!(self.comm_d_proofs.root(), &tau.comm_d); } else { @@ -197,50 +189,48 @@ impl Proof { // Verify replica column openings trace!("verify replica column openings"); - check!(self.replica_column_proofs.verify()); + let mut parents = vec![0; graph.degree()]; + graph.parents(challenge, &mut parents); + check!(self.replica_column_proofs.verify(challenge, &parents)); check!(self.verify_final_replica_layer(challenge)); - check!(self.verify_encodings(replica_id, &pub_params.layer_challenges, challenge_index)); + check!(self.verify_labels(replica_id, &pub_params.layer_challenges, challenge_index)); + + trace!("verify encoding"); + check!(self.encoding_proof.verify::( + replica_id, + self.comm_r_last_proof.leaf(), + self.comm_d_proofs.leaf() + )); true } /// Verify all encodings. - fn verify_encodings( + fn verify_labels( &self, replica_id: &H::Domain, layer_challenges: &LayerChallenges, challenge_index: usize, ) -> bool { - // Verify Encoding Layer 1..layers + // Verify Labels Layer 1..layers for layer in 1..=layer_challenges.layers() { let expect_challenge = layer_challenges.include_challenge_at_layer(layer, challenge_index); trace!( - "verify encoding (layer: {} - expect_challenge: {})", + "verify labeling (layer: {} - expect_challenge: {})", layer, expect_challenge ); - let (encoded_node, decoded_node) = if layer == layer_challenges.layers() { - ( - self.comm_r_last_proof.leaf(), - Some(self.comm_d_proofs.leaf()), - ) - } else { - ( - self.replica_column_proofs.c_x.get_node_at_layer(layer), - None, - ) - }; - if expect_challenge { - check!(self.encoding_proofs.get(layer - 1).is_some()); - let encoding_proof = &self.encoding_proofs[layer - 1]; - check!(encoding_proof.verify::(replica_id, encoded_node, decoded_node)); + check!(self.labeling_proofs.contains_key(&layer)); + let labeling_proof = &self.labeling_proofs.get(&layer).unwrap(); + let labeled_node = self.replica_column_proofs.c_x.get_node_at_layer(layer); + check!(labeling_proof.verify(replica_id, labeled_node)); } else { - check!(self.encoding_proofs.get(layer - 1).is_none()); + check!(self.labeling_proofs.get(&layer).is_none()); } } @@ -276,22 +266,24 @@ pub struct ReplicaColumnProof { } impl ReplicaColumnProof { - pub fn verify(&self) -> bool { + pub fn verify(&self, challenge: usize, parents: &[u32]) -> bool { let expected_comm_c = self.c_x.root(); trace!(" verify c_x"); - check!(self.c_x.verify()); + check!(self.c_x.verify(challenge as u32, &expected_comm_c)); trace!(" verify drg_parents"); - for proof in &self.drg_parents { - check!(proof.verify()); - check_eq!(expected_comm_c, proof.root()); + for (proof, parent) in self.drg_parents.iter().zip(parents.iter()) { + check!(proof.verify(*parent, &expected_comm_c)); } trace!(" verify exp_parents"); - for proof in &self.exp_parents { - check!(proof.verify()); - check_eq!(expected_comm_c, proof.root()); + for (proof, parent) in self + .exp_parents + .iter() + .zip(parents.iter().skip(self.drg_parents.len())) + { + check!(proof.verify(*parent, &expected_comm_c)); } true @@ -327,49 +319,49 @@ pub struct PersistentAux { #[derive(Debug)] pub struct TemporaryAux { /// The encoded nodes for 1..layers. - pub encodings: Encodings, + pub labels: Labels, pub tree_d: Tree, pub tree_r_last: Tree, pub tree_c: Tree, } impl TemporaryAux { - pub fn encoding_at_layer(&self, layer: usize) -> &DiskStore { - self.encodings.encoding_at_layer(layer) + pub fn labels_for_layer(&self, layer: usize) -> &DiskStore { + self.labels.labels_for_layer(layer) } - pub fn domain_node_at_layer(&self, layer: usize, node_index: u32) -> Result { - Ok(self.encoding_at_layer(layer).read_at(node_index as usize)) + pub fn domain_node_at_layer(&self, layer: usize, node_index: u32) -> H::Domain { + self.labels_for_layer(layer).read_at(node_index as usize) } pub fn column(&self, column_index: u32) -> Result> { - self.encodings.column(column_index) + self.labels.column(column_index) } } #[derive(Debug)] -pub struct Encodings { - encodings: Vec>, +pub struct Labels { + labels: Vec>, _h: PhantomData, } -impl Encodings { - pub fn new(encodings: Vec>) -> Self { - Encodings { - encodings, +impl Labels { + pub fn new(labels: Vec>) -> Self { + Labels { + labels, _h: PhantomData, } } pub fn len(&self) -> usize { - self.encodings.len() + self.labels.len() } pub fn is_empty(&self) -> bool { - self.encodings.is_empty() + self.labels.is_empty() } - pub fn encoding_at_layer(&self, layer: usize) -> &DiskStore { + pub fn labels_for_layer(&self, layer: usize) -> &DiskStore { assert!(layer != 0, "Layer cannot be 0"); assert!( layer <= self.layers(), @@ -379,25 +371,25 @@ impl Encodings { ); let row_index = layer - 1; - &self.encodings[row_index] + &self.labels[row_index] } - /// Returns encoding on the last layer. - pub fn encoding_at_last_layer(&self) -> &DiskStore { - &self.encodings[self.encodings.len() - 1] + /// Returns the labels on the last layer. + pub fn labels_for_last_layer(&self) -> &DiskStore { + &self.labels[self.labels.len() - 1] } /// How many layers are available. fn layers(&self) -> usize { - self.encodings.len() + self.labels.len() } /// Build the column for the given node. pub fn column(&self, node: u32) -> Result> { let rows = self - .encodings + .labels .iter() - .map(|encoding| encoding.read_at(node as usize)) + .map(|labels| labels.read_at(node as usize)) .collect(); Ok(Column::new(node, rows)) diff --git a/storage-proofs/src/stacked/proof.rs b/storage-proofs/src/stacked/proof.rs index f8176b9bc..e05ff33c3 100644 --- a/storage-proofs/src/stacked/proof.rs +++ b/storage-proofs/src/stacked/proof.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::marker::PhantomData; use merkletree::merkle::FromIndexedParallelIterator; @@ -14,13 +15,13 @@ use crate::merkle::{MerkleProof, MerkleTree, Store}; use crate::stacked::{ challenges::LayerChallenges, column::Column, - encoding_proof::EncodingProof, graph::StackedBucketGraph, hash::hash2, params::{ - get_node, Encodings, PersistentAux, Proof, PublicInputs, ReplicaColumnProof, Tau, + get_node, Labels, PersistentAux, Proof, PublicInputs, ReplicaColumnProof, Tau, TemporaryAux, TransformedLayers, Tree, }, + EncodingProof, LabelingProof, }; use crate::util::{data_at_node, data_at_node_offset, NODE_SIZE}; @@ -43,7 +44,7 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { partition_count: usize, ) -> Result>>> { assert!(layers > 0); - assert_eq!(t_aux.encodings.len(), layers); + assert_eq!(t_aux.labels.len(), layers); let graph_size = graph.size(); @@ -123,8 +124,9 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { let comm_r_last_proof = MerkleProof::new_from_proof(&t_aux.tree_r_last.gen_proof(challenge)); - // Encoding Proof Layer 1..l - let mut encoding_proofs = Vec::with_capacity(layers); + // Labeling Proofs Layer 1..l + let mut labeling_proofs = HashMap::with_capacity(layers); + let mut encoding_proof = None; for layer in 1..=layers { let include_challenge = @@ -140,14 +142,14 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { continue; } - let parents_data = if layer == 1 { + let parents_data: Vec = if layer == 1 { let mut parents = vec![0; graph.base_graph().degree()]; graph.base_parents(challenge, &mut parents); parents .into_iter() .map(|parent| t_aux.domain_node_at_layer(layer, parent)) - .collect::>()? + .collect() } else { let mut parents = vec![0; graph.degree()]; graph.parents(challenge, &mut parents); @@ -165,36 +167,34 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { t_aux.domain_node_at_layer(layer - 1, parent) } }) - .collect::>()? + .collect() }; - let proof = EncodingProof::::new(challenge as u64, parents_data); + let proof = + LabelingProof::::new(challenge as u64, parents_data.clone()); { - let (encoded_node, decoded_node) = if layer == layers { - (comm_r_last_proof.leaf(), Some(comm_d_proof.leaf())) - } else { - (rpc.c_x.get_node_at_layer(layer), None) - }; - + let labeled_node = rpc.c_x.get_node_at_layer(layer); assert!( - proof.verify::( - &pub_inputs.replica_id, - &encoded_node, - decoded_node - ), + proof.verify(&pub_inputs.replica_id, &labeled_node), "Invalid encoding proof generated" ); } - encoding_proofs.push(proof); + labeling_proofs.insert(layer, proof); + + if layer == layers { + encoding_proof = + Some(EncodingProof::new(challenge as u64, parents_data)); + } } Ok(Proof { comm_d_proofs: comm_d_proof, replica_column_proofs: rpc, comm_r_last_proof, - encoding_proofs, + labeling_proofs, + encoding_proof: encoding_proof.expect("invalid tapering"), }) }) .collect() @@ -213,13 +213,13 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { let layers = layer_challenges.layers(); assert!(layers > 0); - // generate encodings - let (encodings, _) = Self::generate_layers(graph, layer_challenges, replica_id, false)?; + // generate labels + let (labels, _) = Self::generate_labels(graph, layer_challenges, replica_id, false)?; - let size = encodings.encoding_at_last_layer().len(); + let size = labels.labels_for_last_layer().len(); - for (key, encoded_node_bytes) in encodings - .encoding_at_last_layer() + for (key, encoded_node_bytes) in labels + .labels_for_last_layer() .read_range(0..size) .into_iter() .zip(data.chunks_mut(NODE_SIZE)) @@ -235,19 +235,19 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { } #[allow(clippy::type_complexity)] - fn generate_layers( + fn generate_labels( graph: &StackedBucketGraph, layer_challenges: &LayerChallenges, replica_id: &::Domain, with_hashing: bool, - ) -> Result<(Encodings, Option>)> { - info!("generate layers"); + ) -> Result<(Labels, Option>)> { + info!("generate labels"); let layers = layer_challenges.layers(); - let mut encodings: Vec> = Vec::with_capacity(layers); + let mut labels: Vec> = Vec::with_capacity(layers); let layer_size = graph.size() * NODE_SIZE; let mut parents = vec![0; graph.degree()]; - let mut encoding = vec![0u8; layer_size]; + let mut layer_labels = vec![0u8; layer_size]; use crate::crypto::pedersen::Hasher as PedersenHasher; @@ -266,7 +266,7 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { let graph_size = graph.size(); - // 1 less, to account for the thread we are on, which is doign the encoding. + // 1 less, to account for the thread we are on. let chunks = std::cmp::min(graph_size / 4, num_cpus::get() - 1); let chunk_len = (graph_size as f64 / chunks as f64).ceil() as usize; @@ -313,8 +313,6 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { for node in 0..graph.size() { graph.parents(node, &mut parents); - // CreateKey inlined, to avoid borrow issues - let mut hasher = base_hasher.clone(); // hash node id @@ -327,7 +325,8 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { // Base parents for parent in parents.iter().take(base_parents_count) { - let buf = data_at_node(&encoding, *parent as usize).expect("invalid node"); + let buf = + data_at_node(&layer_labels, *parent as usize).expect("invalid node"); hasher.input(buf); } @@ -351,7 +350,7 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { key[31] &= 0b0011_1111; // store the newly generated key - encoding[start..end].copy_from_slice(&key[..]); + layer_labels[start..end].copy_from_slice(&key[..]); if with_hashing { let sender_index = node / chunk_len; @@ -381,17 +380,17 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { // NOTE: this means we currently keep 2x sector size around, to improve speed. if let Some(ref mut exp_parents_data) = exp_parents_data { - exp_parents_data.copy_from_slice(&encoding); + exp_parents_data.copy_from_slice(&layer_labels); } else { - exp_parents_data = Some(encoding.clone()); + exp_parents_data = Some(layer_labels.clone()); } // Write the result to disk to avoid keeping it in memory all the time. - encodings.push(DiskStore::new_from_slice(layer_size, &encoding)?); + labels.push(DiskStore::new_from_slice(layer_size, &layer_labels)?); } assert_eq!( - encodings.len(), + labels.len(), layers, "Invalid amount of layers encoded expected" ); @@ -404,8 +403,8 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { .collect() }); - info!("Layers generated"); - Ok((Encodings::::new(encodings), column_hashes)) + info!("Labels generated"); + Ok((Labels::::new(labels), column_hashes)) } fn build_tree(tree_data: &[u8]) -> Tree { @@ -435,9 +434,9 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { let layers = layer_challenges.layers(); assert!(layers > 0); - let (encodings, column_hashes, tree_d) = crossbeam::thread::scope(|s| { + let (labels, column_hashes, tree_d) = crossbeam::thread::scope(|s| { // Generate key layers. - let h = s.spawn(|_| Self::generate_layers(graph, layer_challenges, replica_id, true)); + let h = s.spawn(|_| Self::generate_labels(graph, layer_challenges, replica_id, true)); // Build the MerkleTree over the original data. let tree_d = match data_tree { @@ -448,10 +447,10 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { } }; - let (encodings, column_hashes) = h.join().unwrap().unwrap(); + let (labels, column_hashes) = h.join().unwrap().unwrap(); let column_hashes = column_hashes.unwrap(); - (encodings, column_hashes, tree_d) + (labels, column_hashes, tree_d) })?; let (tree_r_last, tree_c, comm_r): (Tree, Tree, H::Domain) = @@ -459,9 +458,9 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { // Encode original data into the last layer. let tree_r_last_handle = s.spawn(|_| { info!("encoding data"); - let size = encodings.encoding_at_last_layer().len(); - encodings - .encoding_at_last_layer() + let size = labels.labels_for_last_layer().len(); + labels + .labels_for_last_layer() .read_range(0..size) .into_par_iter() .zip(data.par_chunks_mut(NODE_SIZE)) @@ -513,7 +512,7 @@ impl<'a, H: 'static + Hasher, G: 'static + Hasher> StackedDrg<'a, H, G> { comm_r_last: tree_r_last.root(), }, TemporaryAux { - encodings, + labels, tree_c, tree_d, tree_r_last, diff --git a/storage-proofs/src/stacked/proof_scheme.rs b/storage-proofs/src/stacked/proof_scheme.rs index 770fbe52f..8dab01145 100644 --- a/storage-proofs/src/stacked/proof_scheme.rs +++ b/storage-proofs/src/stacked/proof_scheme.rs @@ -1,3 +1,4 @@ +use paired::bls12_381::Fr; use rayon::prelude::*; use crate::drgraph::Graph; @@ -7,6 +8,7 @@ use crate::proof::ProofScheme; use crate::stacked::{ challenges::ChallengeRequirements, graph::StackedBucketGraph, + hash::hash2, params::{PrivateInputs, Proof, PublicInputs, PublicParams, SetupParams}, proof::StackedDrg, }; @@ -78,6 +80,12 @@ impl<'a, 'c, H: 'static + Hasher, G: 'static + Hasher> ProofScheme<'a> for Stack // generate graphs let graph = &pub_params.graph; + let expected_comm_r = if let Some(ref tau) = pub_inputs.tau { + &tau.comm_r + } else { + return Ok(false); + }; + for (k, proofs) in partition_proofs.iter().enumerate() { trace!( "verifying partition proof {}/{}", @@ -85,6 +93,17 @@ impl<'a, 'c, H: 'static + Hasher, G: 'static + Hasher> ProofScheme<'a> for Stack partition_proofs.len() ); + trace!("verify comm_r"); + let actual_comm_r: H::Domain = { + let comm_c = proofs[0].comm_c(); + let comm_r_last = proofs[0].comm_r_last(); + Fr::from(hash2(comm_c, comm_r_last)).into() + }; + + if expected_comm_r != &actual_comm_r { + return Ok(false); + } + let challenges = pub_inputs.all_challenges(&pub_params.layer_challenges, graph.size(), Some(k)); @@ -94,6 +113,15 @@ impl<'a, 'c, H: 'static + Hasher, G: 'static + Hasher> ProofScheme<'a> for Stack // Validate for this challenge let challenge = challenges[i]; + // make sure all proofs have the same comm_c + if proof.comm_c() != proofs[0].comm_c() { + return false; + } + // make sure all proofs have the same comm_r_last + if proof.comm_r_last() != proofs[0].comm_r_last() { + return false; + } + proof.verify(pub_params, pub_inputs, challenge, i, graph) }); diff --git a/storage-proofs/src/test_helper.rs b/storage-proofs/src/test_helper.rs index 81b0e35e5..a25d3304e 100644 --- a/storage-proofs/src/test_helper.rs +++ b/storage-proofs/src/test_helper.rs @@ -54,7 +54,7 @@ pub fn fake_drgpoprep_proof( // Part 2: replica data inputs // generate parent nodes let replica_parents: Vec = (0..m).map(|_| rng.gen()).collect(); - // run kdf for proverid, parent nodes + // run create_label for proverid, parent nodes let ciphertexts = replica_parents .iter() .fold( @@ -68,7 +68,7 @@ pub fn fake_drgpoprep_proof( ) .unwrap(); - let key = crypto::kdf::kdf(ciphertexts.as_slice(), m); + let key = crypto::create_label::create_label(ciphertexts.as_slice(), m); // run sloth(key, node) let replica_node: Fr = crypto::sloth::encode::(&key, &data_node);