Skip to content

Commit

Permalink
WIP non-interactive PoRep
Browse files Browse the repository at this point in the history
  • Loading branch information
vmx committed Dec 6, 2023
1 parent 97f39b6 commit d882411
Show file tree
Hide file tree
Showing 13 changed files with 378 additions and 97 deletions.
4 changes: 3 additions & 1 deletion fil-proofs-tooling/src/bin/benchy/porep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ fn get_porep_config(sector_size: u64, api_version: ApiVersion, use_synthetic: bo
// Replicate the staged sector, write the replica file to `sealed_path`.
let mut config = PoRepConfig::new_groth16(sector_size, arbitrary_porep_id, api_version);
if use_synthetic {
config.enable_feature(ApiFeature::SyntheticPoRep);
config
.enable_feature(ApiFeature::SyntheticPoRep)
.expect("cannot enable feature");
}

config
Expand Down
4 changes: 3 additions & 1 deletion fil-proofs-tooling/src/bin/benchy/window_post.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ fn get_porep_config(sector_size: u64, api_version: ApiVersion, use_synthetic: bo
// Replicate the staged sector, write the replica file to `sealed_path`.
let mut config = PoRepConfig::new_groth16(sector_size, arbitrary_porep_id, api_version);
if use_synthetic {
config.enable_feature(ApiFeature::SyntheticPoRep);
config
.enable_feature(ApiFeature::SyntheticPoRep)
.expect("cannot enable feature");
}

config
Expand Down
4 changes: 3 additions & 1 deletion fil-proofs-tooling/src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ pub fn create_replicas<Tree: 'static + MerkleTreeTrait>(

let mut porep_config = PoRepConfig::new_groth16(u64::from(sector_size), porep_id, api_version);
for feature in api_features {
porep_config.enable_feature(feature);
porep_config
.enable_feature(feature)
.expect("could not add feature");
}

let mut out: Vec<(SectorId, PreCommitReplicaOutput<Tree>)> = Default::default();
Expand Down
86 changes: 68 additions & 18 deletions filecoin-proofs/src/api/seal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ use storage_proofs_porep::stacked::{
use storage_proofs_update::vanilla::prepare_tree_r_data;
use typenum::{Unsigned, U11, U2};

use crate::POREP_MINIMUM_CHALLENGES;
use crate::{
api::{as_safe_commitment, commitment_from_fr, get_base_tree_leafs, get_base_tree_size, util},
caches::{
Expand Down Expand Up @@ -570,19 +569,50 @@ pub fn seal_commit_phase2<Tree: 'static + MerkleTreeTrait>(

// Verification is cheap when parameters are cached,
// and it is never correct to return a proof which does not verify.
verify_seal::<Tree>(
porep_config,
comm_r,
comm_d,
prover_id,
sector_id,
ticket,
seed,
&buf,
)
.context("post-seal verification sanity check failed")?;

let out = SealCommitOutput { proof: buf };
// Non-interactive PoRep is an aggregated proof, hence we also need a different code path for
// the verifucation.
let out = if porep_config.feature_enabled(ApiFeature::NonInteractivePoRep) {
let aggregated = aggregate_seal_commit_proofs::<Tree>(
porep_config,
&[comm_r],
&[seed],
&[SealCommitOutput { proof: buf }],
groth16::aggregate::AggregateVersion::V2,
)?;
let inputs = get_seal_inputs::<Tree>(
porep_config,
comm_r,
comm_d,
prover_id,
sector_id,
ticket,
seed,
)?;
let is_valid = verify_aggregate_seal_commit_proofs::<Tree>(
porep_config,
aggregated.clone(),
&[comm_r],
&[seed],
inputs,
groth16::aggregate::AggregateVersion::V2,
)
.context("post-seal aggregation verification sanity check failed")?;
ensure!(is_valid, "post seal aggregation verifies");
SealCommitOutput { proof: aggregated }
} else {
verify_seal::<Tree>(
porep_config,
comm_r,
comm_d,
prover_id,
sector_id,
ticket,
seed,
&buf,
)
.context("post-seal verification sanity check failed")?;
SealCommitOutput { proof: buf }
};

info!("seal_commit_phase2:finish: {:?}", sector_id);
Ok(out)
Expand Down Expand Up @@ -969,6 +999,28 @@ pub fn verify_seal<Tree: 'static + MerkleTreeTrait>(
) -> Result<bool> {
info!("verify_seal:start: {:?}", sector_id);

// Non-interactive PoReps are aggregated, but it should be possible to use the usual PoRep
// APIs, hence branch out here and not one layer higher.
if porep_config.feature_enabled(ApiFeature::NonInteractivePoRep) {
let inputs = get_seal_inputs::<Tree>(
porep_config,
comm_r_in,
comm_d_in,
prover_id,
sector_id,
ticket,
seed,
)?;
return verify_aggregate_seal_commit_proofs::<Tree>(
porep_config,
proof_vec.to_vec(),
&[comm_r_in],
&[seed],
inputs,
groth16::aggregate::AggregateVersion::V2,
);
}

ensure!(comm_d_in != [0; 32], "Invalid all zero commitment (comm_d)");
ensure!(comm_r_in != [0; 32], "Invalid all zero commitment (comm_r)");
ensure!(!proof_vec.is_empty(), "Invalid proof bytes (empty vector)");
Expand Down Expand Up @@ -1023,8 +1075,7 @@ pub fn verify_seal<Tree: 'static + MerkleTreeTrait>(
&public_inputs,
&proof,
&ChallengeRequirements {
minimum_challenges: POREP_MINIMUM_CHALLENGES
.from_sector_size(u64::from(porep_config.sector_size)),
minimum_challenges: porep_config.minimum_challenges(),
},
)
};
Expand Down Expand Up @@ -1138,8 +1189,7 @@ pub fn verify_batch_seal<Tree: 'static + MerkleTreeTrait>(
&public_inputs,
&proofs,
&ChallengeRequirements {
minimum_challenges: POREP_MINIMUM_CHALLENGES
.from_sector_size(u64::from(porep_config.sector_size)),
minimum_challenges: porep_config.minimum_challenges(),
},
)
.map_err(Into::into);
Expand Down
82 changes: 41 additions & 41 deletions filecoin-proofs/src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::collections::HashMap;
use std::sync::RwLock;
use std::{collections::HashMap, sync::RwLockWriteGuard};

pub use storage_proofs_core::drgraph::BASE_DEGREE as DRG_DEGREE;
pub use storage_proofs_porep::stacked::EXP_DEGREE;
Expand Down Expand Up @@ -47,47 +47,7 @@ pub const PUBLISHED_SECTOR_SIZES: [u64; 10] = [
SECTOR_SIZE_64_GIB,
];

pub struct PorepMinimumChallenges(RwLock<HashMap<u64, usize>>);
impl PorepMinimumChallenges {
fn new() -> Self {
Self(RwLock::new(
[
(SECTOR_SIZE_2_KIB, 2),
(SECTOR_SIZE_4_KIB, 2),
(SECTOR_SIZE_16_KIB, 2),
(SECTOR_SIZE_32_KIB, 2),
(SECTOR_SIZE_8_MIB, 2),
(SECTOR_SIZE_16_MIB, 2),
(SECTOR_SIZE_512_MIB, 2),
(SECTOR_SIZE_1_GIB, 2),
(SECTOR_SIZE_32_GIB, 176),
(SECTOR_SIZE_64_GIB, 176),
]
.iter()
.copied()
.collect(),
))
}

pub fn get_mut(&self) -> RwLockWriteGuard<'_, HashMap<u64, usize>> {
self.0.write().expect("POREP_MINIMUM_CHALLENGES poisoned")
}

pub fn from_sector_size(&self, sector_size: u64) -> usize {
match self
.0
.read()
.expect("POREP_MINIMUM_CHALLENGES poisoned")
.get(&sector_size)
{
Some(c) => *c,
None => panic!("invalid sector size"),
}
}
}

lazy_static! {
pub static ref POREP_MINIMUM_CHALLENGES: PorepMinimumChallenges = PorepMinimumChallenges::new();
pub static ref POREP_PARTITIONS: RwLock<HashMap<u64, u8>> = RwLock::new(
[
(SECTOR_SIZE_2_KIB, 1),
Expand Down Expand Up @@ -144,6 +104,43 @@ lazy_static! {
);
}

/// Returns the minimum number of challenges used for the (synth and non-synth) interactive PoRep
/// for a certain sector size.
pub(crate) const fn get_porep_interactive_minimum_challenges(sector_size: u64) -> usize {
match sector_size {
SECTOR_SIZE_2_KIB | SECTOR_SIZE_4_KIB | SECTOR_SIZE_16_KIB | SECTOR_SIZE_32_KIB
| SECTOR_SIZE_8_MIB | SECTOR_SIZE_16_MIB | SECTOR_SIZE_512_MIB | SECTOR_SIZE_1_GIB => 2,
SECTOR_SIZE_32_GIB | SECTOR_SIZE_64_GIB => 176,
_ => panic!("invalid sector size"),
}
}

/// Returns the minimum number of challenges used for the non-interactive PoRep fo a certain sector
/// size.
pub(crate) const fn get_porep_non_interactive_minimum_challenges(sector_size: u64) -> usize {
match sector_size {
SECTOR_SIZE_2_KIB | SECTOR_SIZE_4_KIB | SECTOR_SIZE_16_KIB | SECTOR_SIZE_32_KIB
| SECTOR_SIZE_8_MIB | SECTOR_SIZE_16_MIB | SECTOR_SIZE_512_MIB | SECTOR_SIZE_1_GIB => 4,
SECTOR_SIZE_32_GIB | SECTOR_SIZE_64_GIB => 2253,
_ => panic!("invalid sector size"),
}
}

/// Returns the number of partitions for non-interactive PoRep for a certain sector size.
pub const fn get_porep_non_interactive_partitions(sector_size: u64) -> u8 {
match sector_size {
// The filename of the parameter files and verifying keys depend on the number of
// challenges per partition. In order to be able to re-use the files that were generated
// for the interactive PoRep, we need to use certain numbers, also for the test sector
// sizes. The number of challenges per partition for test sizes is 2, for production
// parameters it's 18.
SECTOR_SIZE_2_KIB | SECTOR_SIZE_4_KIB | SECTOR_SIZE_16_KIB | SECTOR_SIZE_32_KIB
| SECTOR_SIZE_8_MIB | SECTOR_SIZE_16_MIB | SECTOR_SIZE_512_MIB | SECTOR_SIZE_1_GIB => 2,
SECTOR_SIZE_32_GIB | SECTOR_SIZE_64_GIB => 126,
_ => panic!("invalid sector size"),
}
}

/// The size of a single snark proof.
pub const SINGLE_PARTITION_PROOF_LEN: usize = 192;

Expand All @@ -156,6 +153,9 @@ pub const MINIMUM_RESERVED_BYTES_FOR_PIECE_IN_FULLY_ALIGNED_SECTOR: u64 =
/// The minimum size a single piece must have before padding.
pub const MIN_PIECE_SIZE: UnpaddedBytesAmount = UnpaddedBytesAmount(127);

/// The maximum number of challenges per partition the circuits can work with.
pub(crate) const MAX_CHALLENGES_PER_PARTITION: u8 = 18;

/// The hasher used for creating comm_d.
pub type DefaultPieceHasher = Sha256Hasher;
pub type DefaultPieceDomain = <DefaultPieceHasher as Hasher>::Domain;
Expand Down
19 changes: 10 additions & 9 deletions filecoin-proofs/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ use storage_proofs_porep::stacked::{self, Challenges, StackedDrg};
use storage_proofs_post::fallback::{self, FallbackPoSt};

use crate::{
constants::{DefaultPieceHasher, DRG_DEGREE, EXP_DEGREE, LAYERS},
constants::{DefaultPieceHasher, DRG_DEGREE, EXP_DEGREE, LAYERS, MAX_CHALLENGES_PER_PARTITION},
types::{MerkleTreeTrait, PoRepConfig, PoStConfig},
POREP_MINIMUM_CHALLENGES,
};

type WinningPostSetupParams = fallback::SetupParams;
Expand Down Expand Up @@ -68,12 +67,11 @@ pub fn window_post_setup_params(post_config: &PoStConfig) -> WindowPostSetupPara
}

pub fn setup_params(porep_config: &PoRepConfig) -> Result<stacked::SetupParams> {
let use_synthetic = porep_config.feature_enabled(ApiFeature::SyntheticPoRep);
let sector_bytes = porep_config.padded_bytes_amount();
let challenges = select_challenges(
usize::from(porep_config.partitions),
POREP_MINIMUM_CHALLENGES.from_sector_size(u64::from(sector_bytes)),
use_synthetic,
porep_config.minimum_challenges(),
&porep_config.api_features,
);
let num_layers = *LAYERS
.read()
Expand Down Expand Up @@ -113,11 +111,15 @@ const fn div_ceil(x: usize, y: usize) -> usize {
fn select_challenges(
partitions: usize,
minimum_total_challenges: usize,
use_synthetic: bool,
features: &[ApiFeature],
) -> Challenges {
let challenges = div_ceil(minimum_total_challenges, partitions);
if use_synthetic {
assert!(challenges <= usize::from(MAX_CHALLENGES_PER_PARTITION));

if features.contains(&ApiFeature::SyntheticPoRep) {
Challenges::new_synthetic(challenges)
} else if features.contains(&ApiFeature::NonInteractivePoRep) {
Challenges::new_non_interactive(challenges)
} else {
Challenges::new_interactive(challenges)
}
Expand All @@ -131,8 +133,7 @@ mod tests {

#[test]
fn partition_layer_challenges_test() {
let f =
|partitions| select_challenges(partitions, 12, false).num_challenges_per_partition();
let f = |partitions| select_challenges(partitions, 12, &[]).num_challenges_per_partition();
// Update to ensure all supported PoRepProofPartitions options are represented here.
assert_eq!(6, f(usize::from(PoRepProofPartitions(2))));

Expand Down
Loading

0 comments on commit d882411

Please sign in to comment.