Skip to content

Commit

Permalink
feat: expose an API suitable for NI-PoRep proof aggregation
Browse files Browse the repository at this point in the history
feat: add tests to ensure NI-PoRep is tested w and w/o aggregation
  • Loading branch information
cryptonemo committed May 16, 2024
1 parent 2a9b81d commit 3e04757
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 96 deletions.
61 changes: 52 additions & 9 deletions filecoin-proofs/src/api/seal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,22 +492,30 @@ pub fn seal_commit_phase1_inner<T: AsRef<Path>, Tree: 'static + MerkleTreeTrait>
Ok(out)
}

/// This new API is added and made public specifically for generating
/// NonInteractive PoRep proofs that will later be aggregated using
/// the existing `aggregate_seal_commit_proofs` method. It is also
/// used internally outside of the NonInteractivePoRep use-case to
/// avoid code duplication.
///
/// Note that if `seal_commit_phase2` is used for NonInteractivePoRep
/// and it's later decided that multiple NI-PoRep proofs should be
/// aggregated, it will fail.
#[allow(clippy::too_many_arguments)]
pub fn seal_commit_phase2<Tree: 'static + MerkleTreeTrait>(
pub fn seal_commit_phase2_circuit_proofs<Tree: 'static + MerkleTreeTrait>(
porep_config: &PoRepConfig,
phase1_output: SealCommitPhase1Output<Tree>,
prover_id: ProverId,
sector_id: SectorId,
) -> Result<SealCommitOutput> {
info!("seal_commit_phase2:start: {:?}", sector_id);
info!("seal_commit_phase2_circuit_proofs:start: {:?}", sector_id);

let SealCommitPhase1Output {
vanilla_proofs,
comm_d,
comm_r,
replica_id,
seed,
ticket,
ticket: _,
} = phase1_output;

ensure!(comm_d != [0; 32], "Invalid all zero commitment (comm_d)");
Expand Down Expand Up @@ -562,23 +570,58 @@ pub fn seal_commit_phase2<Tree: 'static + MerkleTreeTrait>(
)?;
trace!("snark_proof:finish");

// By returning the groth proofs wrapped in the SealCommitOutput
// type as normal, we minimize exported types across the API and
// allow re-use of existing aggregation/verification APIs
let verifying_key = get_stacked_verifying_key::<Tree>(porep_config)?;
let proof = MultiProof::new(groth_proofs, &verifying_key);
let mut buf =
Vec::with_capacity(SINGLE_PARTITION_PROOF_LEN * usize::from(porep_config.partitions));

proof.write(&mut buf)?;

info!("seal_commit_phase2_circuit_proofs:finish: {:?}", sector_id);
Ok(SealCommitOutput { proof: buf })
}

#[allow(clippy::too_many_arguments)]
pub fn seal_commit_phase2<Tree: 'static + MerkleTreeTrait>(
porep_config: &PoRepConfig,
phase1_output: SealCommitPhase1Output<Tree>,
prover_id: ProverId,
sector_id: SectorId,
) -> Result<SealCommitOutput> {
info!("seal_commit_phase2:start: {:?}", sector_id);

let SealCommitPhase1Output {
vanilla_proofs: _,
comm_d,
comm_r,
replica_id: _,
seed,
ticket,
} = phase1_output;

let seal_commit_output =
seal_commit_phase2_circuit_proofs::<Tree>(porep_config, phase1_output, sector_id)?;

// Non-interactive PoRep is an aggregated proof, hence we use that as the returned buffer.
if porep_config.feature_enabled(ApiFeature::NonInteractivePoRep) {
buf = aggregate_seal_commit_proofs::<Tree>(
let buf = if porep_config.feature_enabled(ApiFeature::NonInteractivePoRep) {
ensure!(
porep_config.api_version >= ApiFeature::NonInteractivePoRep.first_supported_version(),
"API version does not support NonInteractivePoRep"
);

aggregate_seal_commit_proofs::<Tree>(
porep_config,
&[comm_r],
&[seed],
&[SealCommitOutput { proof: buf }],
&[seal_commit_output],
groth16::aggregate::AggregateVersion::V2,
)?;
}
)?
} else {
seal_commit_output.proof
};

// Verification is cheap when parameters are cached,
// and it is never correct to return a proof which does not verify.
Expand Down
Loading

0 comments on commit 3e04757

Please sign in to comment.