diff --git a/filecoin-proofs/examples/drgporep.rs b/filecoin-proofs/examples/drgporep.rs index 9f35106ba..8b4d94406 100644 --- a/filecoin-proofs/examples/drgporep.rs +++ b/filecoin-proofs/examples/drgporep.rs @@ -14,8 +14,8 @@ use sapling_crypto::jubjub::{JubjubBls12, JubjubEngine}; use storage_proofs::circuit; use storage_proofs::circuit::variables::Root; - use storage_proofs::example_helper::Example; +use storage_proofs::hasher::PedersenHasher; use storage_proofs::test_helper::fake_drgpoprep_proof; struct DrgPoRepExample<'a, E: JubjubEngine> { @@ -35,7 +35,7 @@ struct DrgPoRepExample<'a, E: JubjubEngine> { impl<'a> Circuit for DrgPoRepExample<'a, Bls12> { fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { - circuit::drgporep::DrgPoRepCircuit::synthesize( + circuit::drgporep::DrgPoRepCircuit::<_, PedersenHasher>::synthesize( cs.namespace(|| "drgporep"), self.params, self.sloth_iter, diff --git a/parameters.json b/parameters.json index 0852e20fe..9876a2fed 100644 --- a/parameters.json +++ b/parameters.json @@ -1,32 +1,32 @@ { - "v10-zigzag-proof-of-replication-b8f3290335d11af86f8193cc2c3bbf451b4b2cc33e59e8ecad060999f3bebe77": { - "cid": "QmeAwbo2CM4t58kV7byr1X2beA7pzbGvStCVSDSG4ydu2E", - "digest": "a30003a7b2b2512cd5e66cfefdd9fe7b" - }, - "v10-zigzag-proof-of-replication-b8f3290335d11af86f8193cc2c3bbf451b4b2cc33e59e8ecad060999f3bebe77.vk": { - "cid": "QmeubWLDsLvL5ULFote1Gce1RfNKcHicCkcwsNyBkhtWuv", - "digest": "61eb4d1b2862feb1149284108c29386b" - }, "v10-vdf-post-c8ddc8e74f9c2ed6a4bc83df171a9e9e84e242cf6e48e20f71585106fa8a3ce6.vk": { "cid": "QmTKL1MiWSWFUMEECZPaBX6ddoZy9HCAA4mdaW65BKDoEp", "digest": "2684b87a68d3a02118584e524a3f073a" }, - "v10-vdf-post-c8ddc8e74f9c2ed6a4bc83df171a9e9e84e242cf6e48e20f71585106fa8a3ce6": { - "cid": "QmPuZ1fZGVDBTjsARTWuMesKjaXqUeNENsQrWBLh7PAjEU", - "digest": "71f6673c73376cca102390150174bbe4" - }, - "v10-zigzag-proof-of-replication-733b035c440d8b0e4a03ab5e4c58553b6c674cc64bd6a130e8764f7abeb38f69.vk": { - "cid": "QmRkiXN7RTWjTgTz3DTjCjDaVNS5vNd8z174UrZLyMowmS", - "digest": "d9f8f2c3a74c45cce4dfa26b65ccc3c9" + "v10-zigzag-proof-of-replication-6648cd509799c8b76f944bbc971692c69d1480fa60c569bfc1284f0bd8ead988": { + "cid": "QmeAwbo2CM4t58kV7byr1X2beA7pzbGvStCVSDSG4ydu2E", + "digest": "a30003a7b2b2512cd5e66cfefdd9fe7b" }, "v10-vdf-post-912e5a392c09cbfa0bf369ac77f939a45e0f2aec968cf3846cbe356a19b76685": { "cid": "QmP1PkagfiC9cUEh3r7NEWaJfnBGEnqfABxXxh3PSoiMtX", "digest": "ff7fa52e9bf2a3b5261f6d5740156f79" }, - "v10-zigzag-proof-of-replication-733b035c440d8b0e4a03ab5e4c58553b6c674cc64bd6a130e8764f7abeb38f69": { + "v10-vdf-post-c8ddc8e74f9c2ed6a4bc83df171a9e9e84e242cf6e48e20f71585106fa8a3ce6": { + "cid": "QmPuZ1fZGVDBTjsARTWuMesKjaXqUeNENsQrWBLh7PAjEU", + "digest": "71f6673c73376cca102390150174bbe4" + }, + "v10-zigzag-proof-of-replication-56360c4554216174de15d2c76acbd0f360e0fabf07dd470ca50f7d39676e7874": { "cid": "QmbPHbry667qc7JEhYDWpvs6mj6rD9UQRi9ZpQb6q6pcoq", "digest": "9268d86f4e3c23eb8483d65834e27c0d" }, + "v10-zigzag-proof-of-replication-6648cd509799c8b76f944bbc971692c69d1480fa60c569bfc1284f0bd8ead988.vk": { + "cid": "QmeubWLDsLvL5ULFote1Gce1RfNKcHicCkcwsNyBkhtWuv", + "digest": "61eb4d1b2862feb1149284108c29386b" + }, + "v10-zigzag-proof-of-replication-56360c4554216174de15d2c76acbd0f360e0fabf07dd470ca50f7d39676e7874.vk": { + "cid": "QmRkiXN7RTWjTgTz3DTjCjDaVNS5vNd8z174UrZLyMowmS", + "digest": "d9f8f2c3a74c45cce4dfa26b65ccc3c9" + }, "v10-vdf-post-912e5a392c09cbfa0bf369ac77f939a45e0f2aec968cf3846cbe356a19b76685.vk": { "cid": "QmaNXg87KFw4pKxa9mXThprpDns7aJZCN5k9WCtneMBkoY", "digest": "3e97aff1d9d2d712163befee897c8b5d" diff --git a/storage-proofs/src/circuit/drgporep.rs b/storage-proofs/src/circuit/drgporep.rs index a521d610d..652e576ec 100644 --- a/storage-proofs/src/circuit/drgporep.rs +++ b/storage-proofs/src/circuit/drgporep.rs @@ -51,7 +51,7 @@ use std::marker::PhantomData; use crate::circuit::por::{PoRCircuit, PoRCompound}; use crate::hasher::{Domain, Hasher}; -pub struct DrgPoRepCircuit<'a, E: JubjubEngine> { +pub struct DrgPoRepCircuit<'a, E: JubjubEngine, H: Hasher> { params: &'a E::Params, sloth_iter: usize, replica_nodes: Vec>, @@ -68,9 +68,10 @@ pub struct DrgPoRepCircuit<'a, E: JubjubEngine> { replica_id: Option, degree: usize, private: bool, + _h: PhantomData, } -impl<'a, E: JubjubEngine> DrgPoRepCircuit<'a, E> { +impl<'a, E: JubjubEngine, H: Hasher> DrgPoRepCircuit<'a, E, H> { #[allow(clippy::type_complexity, clippy::too_many_arguments)] pub fn synthesize( mut cs: CS, @@ -92,7 +93,7 @@ impl<'a, E: JubjubEngine> DrgPoRepCircuit<'a, E> { E: JubjubEngine, CS: ConstraintSystem, { - DrgPoRepCircuit { + DrgPoRepCircuit::<_, H> { params, sloth_iter, replica_nodes, @@ -106,6 +107,7 @@ impl<'a, E: JubjubEngine> DrgPoRepCircuit<'a, E> { replica_id, degree, private, + _h: Default::default(), } .synthesize(&mut cs) } @@ -126,7 +128,7 @@ impl Default for ComponentPrivateInputs { } } -impl<'a, E: JubjubEngine> CircuitComponent for DrgPoRepCircuit<'a, E> { +impl<'a, E: JubjubEngine, H: Hasher> CircuitComponent for DrgPoRepCircuit<'a, E, H> { type ComponentPrivateInputs = ComponentPrivateInputs; } @@ -144,11 +146,11 @@ impl, H: Hasher, G: Graph, P: ParameterSetIden CacheableParameters for DrgPoRepCompound { fn cache_prefix() -> String { - String::from("drg-proof-of-replication") + format!("drg-proof-of-replication-{}", H::name()) } } -impl<'a, H, G> CompoundProof<'a, Bls12, DrgPoRep<'a, H, G>, DrgPoRepCircuit<'a, Bls12>> +impl<'a, H, G> CompoundProof<'a, Bls12, DrgPoRep<'a, H, G>, DrgPoRepCircuit<'a, Bls12, H>> for DrgPoRepCompound where H: 'a + Hasher, @@ -219,11 +221,11 @@ where fn circuit<'b>( public_inputs: &'b as ProofScheme<'a>>::PublicInputs, - component_private_inputs: as CircuitComponent>::ComponentPrivateInputs, + component_private_inputs: as CircuitComponent>::ComponentPrivateInputs, proof: &'b as ProofScheme<'a>>::Proof, public_params: &'b as ProofScheme<'a>>::PublicParams, engine_params: &'a ::Params, - ) -> DrgPoRepCircuit<'a, Bls12> { + ) -> DrgPoRepCircuit<'a, Bls12, H> { let challenges = public_params.challenges_count; let len = proof.nodes.len(); @@ -314,13 +316,14 @@ where replica_id: replica_id.map(Into::into), degree: public_params.graph.degree(), private: public_params.private, + _h: Default::default(), } } fn blank_circuit( public_params: & as ProofScheme<'a>>::PublicParams, params: &'a ::Params, - ) -> DrgPoRepCircuit<'a, Bls12> { + ) -> DrgPoRepCircuit<'a, Bls12, H> { let depth = public_params.graph.merkle_tree_depth() as usize; let degree = public_params.graph.degree(); let challenges_count = public_params.challenges_count; @@ -349,6 +352,7 @@ where replica_id: None, degree: public_params.graph.degree(), private: public_params.private, + _h: Default::default(), } } } @@ -376,7 +380,7 @@ where /// /// Total = 2 + replica_parents.len() /// -impl<'a, E: JubjubEngine> Circuit for DrgPoRepCircuit<'a, E> { +impl<'a, E: JubjubEngine, H: Hasher> Circuit for DrgPoRepCircuit<'a, E, H> { fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> where E: JubjubEngine, @@ -437,7 +441,7 @@ impl<'a, E: JubjubEngine> Circuit for DrgPoRepCircuit<'a, E> { // Inclusion checks { let mut cs = cs.namespace(|| "inclusion_checks"); - PoRCircuit::synthesize( + PoRCircuit::<_, H>::synthesize( cs.namespace(|| "replica_inclusion"), ¶ms, *replica_node, @@ -448,7 +452,7 @@ impl<'a, E: JubjubEngine> Circuit for DrgPoRepCircuit<'a, E> { // validate each replica_parents merkle proof for j in 0..replica_parents.len() { - PoRCircuit::synthesize( + PoRCircuit::<_, H>::synthesize( cs.namespace(|| format!("parents_inclusion_{}", j)), ¶ms, replica_parents[j], @@ -459,7 +463,7 @@ impl<'a, E: JubjubEngine> Circuit for DrgPoRepCircuit<'a, E> { } // validate data node commitment - PoRCircuit::synthesize( + PoRCircuit::<_, H>::synthesize( cs.namespace(|| "data_inclusion"), ¶ms, *data_node, @@ -530,10 +534,11 @@ mod tests { use crate::drgporep; use crate::drgraph::{graph_height, new_seed, BucketGraph}; use crate::fr32::{bytes_into_fr, fr_into_bytes}; - use crate::hasher::pedersen::*; + use crate::hasher::{Blake2sHasher, Hasher, PedersenHasher}; use crate::porep::PoRep; use crate::proof::ProofScheme; use crate::util::data_at_node; + use pairing::Field; use rand::Rand; use rand::{Rng, SeedableRng, XorShiftRng}; @@ -645,7 +650,7 @@ mod tests { ); let mut cs = TestConstraintSystem::::new(); - DrgPoRepCircuit::synthesize( + DrgPoRepCircuit::<_, PedersenHasher>::synthesize( cs.namespace(|| "drgporep"), params, sloth_iter, @@ -694,7 +699,7 @@ mod tests { let sloth_iter = 1; let mut cs = TestConstraintSystem::::new(); - DrgPoRepCircuit::synthesize( + DrgPoRepCircuit::<_, PedersenHasher>::synthesize( cs.namespace(|| "drgporep"), params, sloth_iter, @@ -718,7 +723,17 @@ mod tests { #[test] #[ignore] // Slow test – run only when compiled for release. - fn drgporep_test_compound() { + fn test_drgporep_compound_pedersen() { + drgporep_test_compound::(); + } + + #[test] + #[ignore] // Slow test – run only when compiled for release. + fn test_drgporep_compound_blake2s() { + drgporep_test_compound::(); + } + + fn drgporep_test_compound() { let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); @@ -752,10 +767,9 @@ mod tests { }; let public_params = - DrgPoRepCompound::>::setup(&setup_params) - .expect("setup failed"); + DrgPoRepCompound::>::setup(&setup_params).expect("setup failed"); - let (tau, aux) = drgporep::DrgPoRep::::replicate( + let (tau, aux) = drgporep::DrgPoRep::::replicate( &public_params.vanilla_params, &replica_id.into(), data.as_mut_slice(), @@ -763,7 +777,7 @@ mod tests { ) .expect("failed to replicate"); - let public_inputs = drgporep::PublicInputs:: { + let public_inputs = drgporep::PublicInputs:: { replica_id: Some(replica_id.into()), challenges, tau: Some(tau), @@ -791,11 +805,10 @@ mod tests { }; let public_params = - DrgPoRepCompound::>::setup(&setup_params) - .expect("setup failed"); + DrgPoRepCompound::>::setup(&setup_params).expect("setup failed"); { - let (circuit, inputs) = DrgPoRepCompound::::circuit_for_test( + let (circuit, inputs) = DrgPoRepCompound::::circuit_for_test( &public_params, &public_inputs, &private_inputs, @@ -809,13 +822,11 @@ mod tests { } { - let gparams = DrgPoRepCompound::::groth_params( - &public_params.vanilla_params, - ¶ms, - ) - .expect("failed to get groth params"); + let gparams = + DrgPoRepCompound::::groth_params(&public_params.vanilla_params, ¶ms) + .expect("failed to get groth params"); - let proof = DrgPoRepCompound::::prove( + let proof = DrgPoRepCompound::::prove( &public_params, &public_inputs, &private_inputs, @@ -823,12 +834,8 @@ mod tests { ) .expect("failed while proving"); - let verified = DrgPoRepCompound::::verify( - &public_params, - &public_inputs, - &proof, - ) - .expect("failed while verifying"); + let verified = DrgPoRepCompound::::verify(&public_params, &public_inputs, &proof) + .expect("failed while verifying"); assert!(verified); } diff --git a/storage-proofs/src/circuit/por.rs b/storage-proofs/src/circuit/por.rs index bbe5c795d..72569ffe2 100644 --- a/storage-proofs/src/circuit/por.rs +++ b/storage-proofs/src/circuit/por.rs @@ -1,12 +1,15 @@ +use std::marker::PhantomData; + use bellman::{Circuit, ConstraintSystem, SynthesisError}; use pairing::bls12_381::{Bls12, Fr}; -use sapling_crypto::circuit::{boolean, multipack, num, pedersen_hash}; +use sapling_crypto::circuit::{boolean, multipack, num}; use sapling_crypto::jubjub::{JubjubBls12, JubjubEngine}; use crate::circuit::constraint; use crate::circuit::variables::Root; use crate::compound_proof::{CircuitComponent, CompoundProof}; use crate::drgraph::graph_height; +use crate::hasher::{HashFunction, Hasher}; use crate::merklepor::MerklePoR; use crate::parameter_cache::{CacheableParameters, ParameterSetIdentifier}; use crate::proof::ProofScheme; @@ -20,18 +23,16 @@ use crate::proof::ProofScheme; /// * `auth_path` - The authentication path of the leaf in the tree. /// * `root` - The merkle root of the tree. /// -use crate::hasher::Hasher; -use std::marker::PhantomData; - -pub struct PoRCircuit<'a, E: JubjubEngine> { +pub struct PoRCircuit<'a, E: JubjubEngine, H: Hasher> { params: &'a E::Params, value: Option, auth_path: Vec>, root: Root, private: bool, + _h: PhantomData, } -impl<'a, E: JubjubEngine> CircuitComponent for PoRCircuit<'a, E> { +impl<'a, E: JubjubEngine, H: Hasher> CircuitComponent for PoRCircuit<'a, E, H> { type ComponentPrivateInputs = Option>; } @@ -54,22 +55,22 @@ impl, P: ParameterSetIdentifier, H: Hasher> CacheableParameters for PoRCompound { fn cache_prefix() -> String { - String::from("proof-of-retrievability") + format!("proof-of-retrievability-{}", H::name()) } } // can only implment for Bls12 because merklepor is not generic over the engine. -impl<'a, H> CompoundProof<'a, Bls12, MerklePoR, PoRCircuit<'a, Bls12>> for PoRCompound +impl<'a, H> CompoundProof<'a, Bls12, MerklePoR, PoRCircuit<'a, Bls12, H>> for PoRCompound where H: 'a + Hasher, { fn circuit<'b>( public_inputs: & as ProofScheme<'a>>::PublicInputs, - _component_private_inputs: as CircuitComponent>::ComponentPrivateInputs, + _component_private_inputs: as CircuitComponent>::ComponentPrivateInputs, proof: &'b as ProofScheme<'a>>::Proof, public_params: &'b as ProofScheme<'a>>::PublicParams, engine_params: &'a JubjubBls12, - ) -> PoRCircuit<'a, Bls12> { + ) -> PoRCircuit<'a, Bls12, H> { let (root, private) = match (*public_inputs).commitment { None => (Root::Val(Some(proof.proof.root.into())), true), Some(commitment) => (Root::Val(Some(commitment.into())), false), @@ -78,25 +79,27 @@ where // Ensure inputs are consistent with public params. assert_eq!(private, public_params.private); - PoRCircuit:: { + PoRCircuit:: { params: engine_params, value: Some(proof.data.into()), auth_path: proof.proof.as_options(), root, private, + _h: Default::default(), } } fn blank_circuit( public_params: & as ProofScheme<'a>>::PublicParams, params: &'a JubjubBls12, - ) -> PoRCircuit<'a, Bls12> { - PoRCircuit:: { + ) -> PoRCircuit<'a, Bls12, H> { + PoRCircuit:: { params, value: None, auth_path: vec![None; graph_height(public_params.leaves)], root: Root::Val(None), private: public_params.private, + _h: Default::default(), } } @@ -122,7 +125,7 @@ where } } -impl<'a, E: JubjubEngine> Circuit for PoRCircuit<'a, E> { +impl<'a, E: JubjubEngine, H: Hasher> Circuit for PoRCircuit<'a, E, H> { /// # Public Inputs /// /// This circuit expects the following public inputs. @@ -178,24 +181,17 @@ impl<'a, E: JubjubEngine> Circuit for PoRCircuit<'a, E> { &cur_is_right, )?; - // We don't need to be strict, because the function is - // collision-resistant. If the prover witnesses a congruency, - // they will be unable to find an authentication path in the - // tree with high probability. - let mut preimage = vec![]; - preimage.extend(xl.into_bits_le(cs.namespace(|| "xl into bits"))?); - preimage.extend(xr.into_bits_le(cs.namespace(|| "xr into bits"))?); + let xl_bits = xl.into_bits_le(cs.namespace(|| "xl into bits"))?; + let xr_bits = xr.into_bits_le(cs.namespace(|| "xr into bits"))?; // Compute the new subtree value - cur = pedersen_hash::pedersen_hash( + cur = H::Function::hash_leaf_circuit( cs.namespace(|| "computation of pedersen hash"), - pedersen_hash::Personalization::MerkleTree(i), - &preimage, + &xl_bits, + &xr_bits, + i, params, - )? - .get_x() - .clone(); // Injective encoding - + )?; auth_path_bits.push(cur_is_right); } @@ -219,7 +215,7 @@ impl<'a, E: JubjubEngine> Circuit for PoRCircuit<'a, E> { } } -impl<'a, E: JubjubEngine> PoRCircuit<'a, E> { +impl<'a, E: JubjubEngine, H: Hasher> PoRCircuit<'a, E, H> { pub fn synthesize( mut cs: CS, params: &E::Params, @@ -232,12 +228,13 @@ impl<'a, E: JubjubEngine> PoRCircuit<'a, E> { E: JubjubEngine, CS: ConstraintSystem, { - let por = PoRCircuit:: { + let por = PoRCircuit:: { params, value, auth_path, root, private, + _h: Default::default(), }; por.synthesize(&mut cs) @@ -257,7 +254,7 @@ mod tests { use crate::compound_proof; use crate::drgraph::{new_seed, BucketGraph, Graph}; use crate::fr32::{bytes_into_fr, fr_into_bytes}; - use crate::hasher::pedersen::*; + use crate::hasher::{Blake2sHasher, Domain, Hasher, PedersenHasher}; use crate::merklepor; use crate::proof::ProofScheme; use crate::util::data_at_node; @@ -332,7 +329,16 @@ mod tests { } #[test] - fn test_por_input_circuit_with_bls12_381() { + fn test_por_input_circuit_with_bls12_381_pedersen() { + test_por_input_circuit_with_bls12_381::(4149); + } + + #[test] + fn test_por_input_circuit_with_bls12_381_blake2s() { + test_por_input_circuit_with_bls12_381::(128928); + } + + fn test_por_input_circuit_with_bls12_381(num_constraints: usize) { let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); @@ -345,7 +351,7 @@ mod tests { .flat_map(|_| fr_into_bytes::(&rng.gen())) .collect(); - let graph = BucketGraph::::new(leaves, 16, 0, new_seed()); + let graph = BucketGraph::::new(leaves, 16, 0, new_seed()); let tree = graph.merkle_tree(data.as_slice()).unwrap(); // -- MerklePoR @@ -354,52 +360,50 @@ mod tests { leaves, private: true, }; - let pub_inputs = merklepor::PublicInputs { + let pub_inputs = merklepor::PublicInputs:: { challenge: i, - commitment: Some(tree.root().into()), + commitment: Some(tree.root()), }; - let priv_inputs = merklepor::PrivateInputs::::new( - bytes_into_fr::( + let priv_inputs = merklepor::PrivateInputs::::new( + H::Domain::try_from_bytes( data_at_node(data.as_slice(), pub_inputs.challenge).unwrap(), ) - .unwrap() - .into(), + .unwrap(), &tree, ); // create a non circuit proof - let proof = merklepor::MerklePoR::::prove( - &pub_params, - &pub_inputs, - &priv_inputs, - ) - .unwrap(); + let proof = + merklepor::MerklePoR::::prove(&pub_params, &pub_inputs, &priv_inputs).unwrap(); // make sure it verifies assert!( - merklepor::MerklePoR::::verify(&pub_params, &pub_inputs, &proof) - .unwrap(), + merklepor::MerklePoR::::verify(&pub_params, &pub_inputs, &proof).unwrap(), "failed to verify merklepor proof" ); // -- Circuit let mut cs = TestConstraintSystem::::new(); - - let por = PoRCircuit:: { + let por = PoRCircuit:: { params, value: Some(proof.data.into()), auth_path: proof.proof.as_options(), root: Root::Val(Some(pub_inputs.commitment.unwrap().into())), private: false, + _h: Default::default(), }; por.synthesize(&mut cs).unwrap(); assert!(cs.is_satisfied(), "constraints not satisfied"); assert_eq!(cs.num_inputs(), 3, "wrong number of inputs"); - assert_eq!(cs.num_constraints(), 4149, "wrong number of constraints"); + assert_eq!( + cs.num_constraints(), + num_constraints, + "wrong number of constraints" + ); let auth_path_bits: Vec = proof .proof @@ -434,13 +438,23 @@ mod tests { #[ignore] // Slow test – run only when compiled for release. #[test] - fn private_por_test_compound() { + fn test_private_por_compound_pedersen() { + private_por_test_compound::(); + } + + #[ignore] // Slow test – run only when compiled for release. + #[test] + fn test_private_por_compound_blake2s() { + private_por_test_compound::(); + } + + fn private_por_test_compound() { let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); let leaves = 6; let data: Vec = (0..leaves) .flat_map(|_| fr_into_bytes::(&rng.gen())) .collect(); - let graph = BucketGraph::::new(leaves, 16, 0, new_seed()); + let graph = BucketGraph::::new(leaves, 16, 0, new_seed()); let tree = graph.merkle_tree(data.as_slice()).unwrap(); for i in 0..3 { @@ -457,10 +471,9 @@ mod tests { engine_params: &JubjubBls12::new(), partitions: None, }; - let public_params = - PoRCompound::::setup(&setup_params).expect("setup failed"); + let public_params = PoRCompound::::setup(&setup_params).expect("setup failed"); - let private_inputs = merklepor::PrivateInputs::::new( + let private_inputs = merklepor::PrivateInputs::::new( bytes_into_fr::( data_at_node(data.as_slice(), public_inputs.challenge).unwrap(), ) @@ -469,22 +482,18 @@ mod tests { &tree, ); - let gparams = PoRCompound::::groth_params( + let gparams = PoRCompound::::groth_params( &public_params.vanilla_params, setup_params.engine_params, ) .unwrap(); - let proof = PoRCompound::::prove( - &public_params, - &public_inputs, - &private_inputs, - &gparams, - ) - .expect("failed while proving"); + let proof = + PoRCompound::::prove(&public_params, &public_inputs, &private_inputs, &gparams) + .expect("failed while proving"); { - let (circuit, inputs) = PoRCompound::::circuit_for_test( + let (circuit, inputs) = PoRCompound::::circuit_for_test( &public_params, &public_inputs, &private_inputs, @@ -498,9 +507,8 @@ mod tests { assert!(cs.verify(&inputs)); } - let verified = - PoRCompound::::verify(&public_params, &public_inputs, &proof) - .expect("failed while verifying"); + let verified = PoRCompound::::verify(&public_params, &public_inputs, &proof) + .expect("failed while verifying"); assert!(verified); } } @@ -561,12 +569,13 @@ mod tests { let mut cs = TestConstraintSystem::::new(); - let por = PoRCircuit:: { + let por = PoRCircuit:: { params, value: Some(proof.data.into()), auth_path: proof.proof.as_options(), root: Root::Val(Some(tree.root().into())), private: true, + _h: Default::default(), }; por.synthesize(&mut cs).unwrap(); diff --git a/storage-proofs/src/circuit/zigzag.rs b/storage-proofs/src/circuit/zigzag.rs index 695504cda..a0e53f727 100644 --- a/storage-proofs/src/circuit/zigzag.rs +++ b/storage-proofs/src/circuit/zigzag.rs @@ -7,12 +7,11 @@ use sapling_crypto::jubjub::JubjubEngine; use crate::circuit::constraint; use crate::circuit::drgporep::{ComponentPrivateInputs, DrgPoRepCompound}; -use crate::circuit::pedersen::pedersen_md_no_padding; use crate::circuit::variables::Root; use crate::compound_proof::{CircuitComponent, CompoundProof}; use crate::drgporep::{self, DrgPoRep}; use crate::drgraph::Graph; -use crate::hasher::Hasher; +use crate::hasher::{HashFunction, Hasher}; use crate::layered_drgporep::{self, Layers as LayersTrait}; use crate::parameter_cache::{CacheableParameters, ParameterSetIdentifier}; use crate::porep; @@ -226,10 +225,10 @@ impl<'a, H: Hasher> Circuit for ZigZagCircuit<'a, Bls12, H> { } // Calculate the pedersen hash. - let computed_comm_r_star = pedersen_md_no_padding( + let computed_comm_r_star = H::Function::hash_circuit( cs.namespace(|| "comm_r_star"), - self.params, &crs_boolean[..], + self.params, )?; // Allocate the resulting hash. @@ -378,7 +377,7 @@ mod tests { use crate::drgporep; use crate::drgraph::new_seed; use crate::fr32::fr_into_bytes; - use crate::hasher::pedersen::*; + use crate::hasher::{Blake2sHasher, Hasher, PedersenHasher}; use crate::layered_drgporep::{self, LayerChallenges}; use crate::porep::PoRep; use crate::proof::ProofScheme; @@ -429,7 +428,7 @@ mod tests { let simplified_tau = tau.clone().simplify(); - let pub_inputs = layered_drgporep::PublicInputs:: { + let pub_inputs = layered_drgporep::PublicInputs::<::Domain> { replica_id: replica_id.into(), tau: Some(tau.simplify().into()), comm_r_star: tau.comm_r_star.into(), @@ -571,13 +570,23 @@ mod tests { #[test] #[ignore] // Slow test – run only when compiled for release. - fn zigzag_test_compound() { + fn test_zigzag_compound_pedersen() { + zigzag_test_compound::(); + } + + #[test] + #[ignore] // Slow test – run only when compiled for release. + fn test_zigzag_compound_blake2s() { + zigzag_test_compound::(); + } + + fn zigzag_test_compound() { let params = &JubjubBls12::new(); let nodes = 5; let degree = 2; let expansion_degree = 1; - let num_layers = 4; - let layer_challenges = LayerChallenges::new_tapered(num_layers, 4, num_layers, 1.0 / 3.0); + let num_layers = 2; + let layer_challenges = LayerChallenges::new_tapered(num_layers, 3, num_layers, 1.0 / 3.0); let sloth_iter = 1; let partition_count = 1; @@ -620,13 +629,13 @@ mod tests { .unwrap(); assert_ne!(data, data_copy); - let public_inputs = layered_drgporep::PublicInputs:: { + let public_inputs = layered_drgporep::PublicInputs:: { replica_id: replica_id.into(), tau: Some(tau.simplify()), comm_r_star: tau.comm_r_star, k: None, }; - let private_inputs = layered_drgporep::PrivateInputs:: { + let private_inputs = layered_drgporep::PrivateInputs:: { aux, tau: tau.layer_taus, }; diff --git a/storage-proofs/src/drgraph.rs b/storage-proofs/src/drgraph.rs index 53301762d..a8d32bc0a 100644 --- a/storage-proofs/src/drgraph.rs +++ b/storage-proofs/src/drgraph.rs @@ -107,8 +107,10 @@ impl ParameterSetIdentifier for BucketGraph { fn parameter_set_identifier(&self) -> String { // NOTE: Seed is not included because it does not influence parameter generation. format!( - "drgraph::BucketGraph{{size: {}; degree: {}}}", - self.nodes, self.base_degree, + "drgraph::BucketGraph{{size: {}; degree: {}; hasher: {}}}", + self.nodes, + self.base_degree, + H::name(), ) } } diff --git a/storage-proofs/src/hasher/blake2b.rs b/storage-proofs/src/hasher/blake2b.rs index e5ea92fe4..e1feed5fe 100644 --- a/storage-proofs/src/hasher/blake2b.rs +++ b/storage-proofs/src/hasher/blake2b.rs @@ -2,6 +2,10 @@ use blake2::Blake2b; use super::{DigestHasher, Digester}; -impl Digester for Blake2b {} +impl Digester for Blake2b { + fn name() -> String { + "Blake2b".into() + } +} pub type Blake2bHasher = DigestHasher; diff --git a/storage-proofs/src/hasher/blake2s.rs b/storage-proofs/src/hasher/blake2s.rs index d481980ca..aad57f2f4 100644 --- a/storage-proofs/src/hasher/blake2s.rs +++ b/storage-proofs/src/hasher/blake2s.rs @@ -1,7 +1,293 @@ -use blake2::Blake2s; +use std::fmt; +use std::hash::Hasher as StdHasher; -use super::{DigestHasher, Digester}; +use bellman::{ConstraintSystem, SynthesisError}; +use blake2s_simd::{Hash as Blake2sHash, Params as Blake2s, State}; +use byteorder::{LittleEndian, WriteBytesExt}; +use merkle_light::hash::{Algorithm, Hashable}; +use pairing::bls12_381::{Bls12, Fr, FrRepr}; +use pairing::{PrimeField, PrimeFieldRepr}; +use rand::{Rand, Rng}; +use sapling_crypto::circuit::{blake2s as blake2s_circuit, boolean, multipack, num}; +use sapling_crypto::jubjub::JubjubEngine; -impl Digester for Blake2s {} +use super::{Domain, HashFunction, Hasher}; +use crate::crypto::sloth; +use crate::error::*; -pub type Blake2sHasher = DigestHasher; +#[derive(Default, Copy, Clone, PartialEq, Eq, Debug)] +pub struct Blake2sHasher {} + +impl Hasher for Blake2sHasher { + type Domain = Blake2sDomain; + type Function = Blake2sFunction; + + fn name() -> String { + "Blake2sHasher".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 + ); + + >::hash(data) + } + + fn sloth_encode(key: &Self::Domain, ciphertext: &Self::Domain, rounds: usize) -> Self::Domain { + // TODO: validate this is how sloth should work in this case + let k = (*key).into(); + let c = (*ciphertext).into(); + + sloth::encode::(&k, &c, rounds).into() + } + + fn sloth_decode(key: &Self::Domain, ciphertext: &Self::Domain, rounds: usize) -> Self::Domain { + // TODO: validate this is how sloth should work in this case + sloth::decode::(&(*key).into(), &(*ciphertext).into(), rounds).into() + } +} + +#[derive(Clone)] +pub struct Blake2sFunction(State); + +impl Default for Blake2sFunction { + fn default() -> Self { + Blake2sFunction(Blake2s::new().hash_length(32).to_state()) + } +} + +impl PartialEq for Blake2sFunction { + fn eq(&self, other: &Self) -> bool { + format!("{:?}", self) == format!("{:?}", other) + } +} + +impl Eq for Blake2sFunction {} + +impl fmt::Debug for Blake2sFunction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Blake2sFunction({:?})", self.0) + } +} + +impl StdHasher for Blake2sFunction { + #[inline] + fn write(&mut self, msg: &[u8]) { + self.0.update(msg); + } + + #[inline] + fn finish(&self) -> u64 { + unreachable!("unused by Function -- should never be called") + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Default, Serialize, Deserialize)] +pub struct Blake2sDomain(pub [u8; 32]); + +impl Blake2sDomain { + fn trim_to_fr32(&mut self) { + // strip last two bits, to ensure result is in Fr. + self.0[31] &= 0b0011_1111; + } +} + +impl Rand for Blake2sDomain { + fn rand(rng: &mut R) -> Self { + // generating an Fr and converting it, to ensure we stay in the field + rng.gen::().into() + } +} + +impl AsRef<[u8]> for Blake2sDomain { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl Hashable for Blake2sDomain { + fn hash(&self, state: &mut Blake2sFunction) { + state.write(self.as_ref()) + } +} + +impl From for Blake2sDomain { + fn from(val: Fr) -> Self { + let mut res = Self::default(); + val.into_repr().write_le(&mut res.0[0..32]).unwrap(); + + res + } +} + +impl From for Blake2sDomain { + fn from(val: FrRepr) -> Self { + let mut res = Self::default(); + val.write_le(&mut res.0[0..32]).unwrap(); + + res + } +} + +impl From for Fr { + fn from(val: Blake2sDomain) -> Self { + let mut res = FrRepr::default(); + res.read_le(&val.0[0..32]).unwrap(); + + Fr::from_repr(res).unwrap() + } +} + +impl Domain for Blake2sDomain { + fn serialize(&self) -> Vec { + self.0.to_vec() + } + + fn into_bytes(&self) -> Vec { + self.0.to_vec() + } + + fn try_from_bytes(raw: &[u8]) -> Result { + if raw.len() != 32 { + return Err(Error::InvalidInputSize); + } + let mut res = Blake2sDomain::default(); + res.0.copy_from_slice(&raw[0..32]); + Ok(res) + } + + fn write_bytes(&self, dest: &mut [u8]) -> Result<()> { + if dest.len() < 32 { + return Err(Error::InvalidInputSize); + } + dest[0..32].copy_from_slice(&self.0[..]); + Ok(()) + } +} + +impl Into for Blake2sHash { + fn into(self) -> Blake2sDomain { + let mut res = Blake2sDomain::default(); + res.0[..].copy_from_slice(self.as_ref()); + res.trim_to_fr32(); + + res + } +} + +impl HashFunction for Blake2sFunction { + fn hash(data: &[u8]) -> Blake2sDomain { + Blake2s::new() + .hash_length(32) + .to_state() + .update(data) + .finalize() + .into() + } + + fn hash_leaf_circuit>( + mut cs: CS, + left: &[boolean::Boolean], + right: &[boolean::Boolean], + height: usize, + params: &E::Params, + ) -> std::result::Result, SynthesisError> { + let mut preimage: Vec = vec![]; + let mut height_bytes = vec![]; + height_bytes + .write_u64::(height as u64) + .expect("failed to write height"); + + preimage.extend( + multipack::bytes_to_bits_le(&height_bytes) + .iter() + .enumerate() + .map(|(i, b)| { + boolean::AllocatedBit::alloc( + cs.namespace(|| format!("height_bit {}", i)), + Some(*b), + ) + .map(boolean::Boolean::Is) + }) + .collect::<::std::result::Result, _>>()?, + ); + preimage.extend_from_slice(left); + while preimage.len() % 8 != 0 { + preimage.push(boolean::Boolean::Constant(false)); + } + + preimage.extend_from_slice(right); + while preimage.len() % 8 != 0 { + preimage.push(boolean::Boolean::Constant(false)); + } + + Self::hash_circuit(cs, &preimage[..], params) + } + + fn hash_circuit>( + mut cs: CS, + bits: &[boolean::Boolean], + _params: &E::Params, + ) -> std::result::Result, SynthesisError> { + let personalization = vec![0u8; 8]; + let alloc_bits = + blake2s_circuit::blake2s(cs.namespace(|| "hash"), &bits[..], &personalization)?; + let fr = match alloc_bits[0].get_value() { + Some(_) => { + let bits = alloc_bits + .iter() + .map(|v| v.get_value().unwrap()) + .collect::>(); + // TODO: figure out if we can avoid this + let frs = multipack::compute_multipacking::(&bits); + Ok(frs[0]) + } + None => Err(SynthesisError::AssignmentMissing), + }; + + num::AllocatedNum::::alloc(cs.namespace(|| "num"), || fr) + } +} + +impl Algorithm for Blake2sFunction { + #[inline] + fn hash(&mut self) -> Blake2sDomain { + self.0.clone().finalize().into() + } + + #[inline] + fn reset(&mut self) { + self.0 = Blake2s::new().hash_length(32).to_state() + } + + fn leaf(&mut self, leaf: Blake2sDomain) -> Blake2sDomain { + leaf + } + + fn node(&mut self, left: Blake2sDomain, right: Blake2sDomain, height: usize) -> Blake2sDomain { + height.hash(self); + + left.hash(self); + right.hash(self); + self.hash() + } +} + +impl From<[u8; 32]> for Blake2sDomain { + #[inline] + fn from(val: [u8; 32]) -> Self { + Blake2sDomain(val) + } +} + +impl From for [u8; 32] { + #[inline] + fn from(val: Blake2sDomain) -> Self { + val.0 + } +} diff --git a/storage-proofs/src/hasher/digest.rs b/storage-proofs/src/hasher/digest.rs index 5c18878a9..99f1063a6 100644 --- a/storage-proofs/src/hasher/digest.rs +++ b/storage-proofs/src/hasher/digest.rs @@ -2,17 +2,22 @@ use std::fmt; use std::hash::Hasher as StdHasher; use std::marker::PhantomData; +use bellman::{ConstraintSystem, SynthesisError}; use merkle_light::hash::{Algorithm, Hashable}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use pairing::{PrimeField, PrimeFieldRepr}; use rand::{Rand, Rng}; +use sapling_crypto::circuit::{boolean, num}; +use sapling_crypto::jubjub::JubjubEngine; use sha2::Digest; use super::{Domain, HashFunction, Hasher}; use crate::crypto::sloth; use crate::error::*; -pub trait Digester: Digest + Clone + Default + ::std::fmt::Debug + Send + Sync {} +pub trait Digester: Digest + Clone + Default + ::std::fmt::Debug + Send + Sync { + fn name() -> String; +} #[derive(Default, Copy, Clone, Debug)] pub struct DigestHasher { @@ -31,6 +36,10 @@ impl Hasher for DigestHasher { type Domain = DigestDomain; type Function = DigestFunction; + fn name() -> String { + format!("DigestHasher<{}>", D::name()) + } + fn kdf(data: &[u8], m: usize) -> Self::Domain { assert_eq!( data.len(), @@ -177,6 +186,22 @@ impl HashFunction for DigestFunction { res.trim_to_fr32(); res } + fn hash_leaf_circuit>( + _cs: CS, + _left: &[boolean::Boolean], + _right: &[boolean::Boolean], + _height: usize, + _params: &E::Params, + ) -> std::result::Result, SynthesisError> { + unimplemented!("circuit leaf hash"); + } + fn hash_circuit>( + _cs: CS, + _bits: &[boolean::Boolean], + _params: &E::Params, + ) -> std::result::Result, SynthesisError> { + unimplemented!("circuit hash"); + } } impl Algorithm for DigestFunction { diff --git a/storage-proofs/src/hasher/pedersen.rs b/storage-proofs/src/hasher/pedersen.rs index 35691d799..13977b8fd 100644 --- a/storage-proofs/src/hasher/pedersen.rs +++ b/storage-proofs/src/hasher/pedersen.rs @@ -1,18 +1,22 @@ use std::hash::Hasher as StdHasher; +use bellman::{ConstraintSystem, SynthesisError}; use bitvec::{self, BitVec}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use merkle_light::hash::{Algorithm as LightAlgorithm, Hashable}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use pairing::{PrimeField, PrimeFieldRepr}; use rand::{Rand, Rng}; +use sapling_crypto::circuit::{boolean, num, pedersen_hash as pedersen_hash_circuit}; +use sapling_crypto::jubjub::JubjubEngine; use sapling_crypto::pedersen_hash::{pedersen_hash, Personalization}; use serde::de::{Deserialize, Deserializer}; use serde::ser::Serializer; -use super::{Domain, HashFunction, Hasher}; +use crate::circuit::pedersen::pedersen_md_no_padding; use crate::crypto::{kdf, pedersen, sloth}; use crate::error::{Error, Result}; +use crate::hasher::{Domain, HashFunction, Hasher}; #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] pub struct PedersenHasher {} @@ -21,6 +25,10 @@ impl Hasher for PedersenHasher { type Domain = PedersenDomain; type Function = PedersenFunction; + fn name() -> String { + "PedersenHasher".into() + } + fn kdf(data: &[u8], m: usize) -> Self::Domain { kdf::kdf(data, m).into() } @@ -209,6 +217,35 @@ impl HashFunction for PedersenFunction { fn hash(data: &[u8]) -> PedersenDomain { pedersen::pedersen_md_no_padding(data).into() } + + fn hash_leaf_circuit>( + cs: CS, + left: &[boolean::Boolean], + right: &[boolean::Boolean], + height: usize, + params: &E::Params, + ) -> ::std::result::Result, SynthesisError> { + let mut preimage: Vec = vec![]; + preimage.extend_from_slice(left); + preimage.extend_from_slice(right); + + Ok(pedersen_hash_circuit::pedersen_hash( + cs, + Personalization::MerkleTree(height), + &preimage, + params, + )? + .get_x() + .clone()) + } + + fn hash_circuit>( + cs: CS, + bits: &[boolean::Boolean], + params: &E::Params, + ) -> std::result::Result, SynthesisError> { + pedersen_md_no_padding(cs, params, bits) + } } impl LightAlgorithm for PedersenFunction { diff --git a/storage-proofs/src/hasher/sha256.rs b/storage-proofs/src/hasher/sha256.rs index cfc77f582..2b662692c 100644 --- a/storage-proofs/src/hasher/sha256.rs +++ b/storage-proofs/src/hasher/sha256.rs @@ -2,7 +2,11 @@ use sha2::Sha256; use super::{DigestHasher, Digester}; -impl Digester for Sha256 {} +impl Digester for Sha256 { + fn name() -> String { + "Sha256".into() + } +} pub type Sha256Hasher = DigestHasher; diff --git a/storage-proofs/src/hasher/types.rs b/storage-proofs/src/hasher/types.rs index de5dc8f56..0cc4bdf13 100644 --- a/storage-proofs/src/hasher/types.rs +++ b/storage-proofs/src/hasher/types.rs @@ -1,10 +1,14 @@ -use crate::error::Result; +use bellman::{ConstraintSystem, SynthesisError}; use merkle_light::hash::{Algorithm as LightAlgorithm, Hashable as LightHashable}; use pairing::bls12_381::{Fr, FrRepr}; use rand::Rand; +use sapling_crypto::circuit::{boolean, num}; +use sapling_crypto::jubjub::JubjubEngine; use serde::de::DeserializeOwned; use serde::ser::Serialize; +use crate::error::Result; + pub trait Domain: Ord + Copy @@ -46,6 +50,20 @@ pub trait HashFunction: data.hash(&mut a); a.hash() } + + fn hash_leaf_circuit>( + cs: CS, + left: &[boolean::Boolean], + right: &[boolean::Boolean], + height: usize, + params: &E::Params, + ) -> std::result::Result, SynthesisError>; + + fn hash_circuit>( + cs: CS, + bits: &[boolean::Boolean], + params: &E::Params, + ) -> std::result::Result, SynthesisError>; } pub trait Hasher: Clone + ::std::fmt::Debug + Eq + Default + Send + Sync { @@ -55,4 +73,6 @@ pub trait Hasher: Clone + ::std::fmt::Debug + Eq + Default + Send + Sync { fn kdf(data: &[u8], m: usize) -> Self::Domain; fn sloth_encode(key: &Self::Domain, ciphertext: &Self::Domain, rounds: usize) -> Self::Domain; fn sloth_decode(key: &Self::Domain, ciphertext: &Self::Domain, rounds: usize) -> Self::Domain; + + fn name() -> String; }