Skip to content

Commit

Permalink
Merge pull request #27 from NilFoundation/add_consistency_checks
Browse files Browse the repository at this point in the history
Implement stage 'consistency-checks'.
  • Loading branch information
martun authored Sep 19, 2024
2 parents a478dcf + 5545316 commit e717055
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,7 @@ namespace nil {
proof_type proof_eval(transcript_type &transcript) {
PROFILE_SCOPE("LPC proof_eval");

this->eval_polys();

BOOST_ASSERT(this->_points.size() == this->_polys.size());
BOOST_ASSERT(this->_points.size() == this->_z.get_batches_num());

// For each batch we have a merkle tree.
for (auto const& it: this->_trees) {
transcript(it.second.root());
}
eval_polys_and_add_roots_to_transcipt(transcript);

// Prepare z-s and combined_Q;
auto theta = transcript.template challenge<field_type>();
Expand All @@ -168,16 +160,7 @@ namespace nil {
return proof_type({this->_z, fri_proof});
}

/** This function must be called for the cases where we want to skip the
* round proof for FRI. Must be called once per instance of prover for the aggregated FRI.
* \param[in] combined_Q - Polynomial combined_Q was already computed by the current
prover in the previous step of the aggregated FRI protocol.
* \param[in] transcript - This transcript is initialized from a challenge sent from the "Main" prover,
on which the round proof was created for the polynomial F(x) = Sum(combined_Q).
*/
lpc_proof_type proof_eval_lpc_proof(
const polynomial_type& combined_Q, transcript_type &transcript) {

void eval_polys_and_add_roots_to_transcipt(transcript_type &transcript) {
this->eval_polys();

BOOST_ASSERT(this->_points.size() == this->_polys.size());
Expand All @@ -187,9 +170,18 @@ namespace nil {
for (auto const& it: this->_trees) {
transcript(it.second.root());
}
}

std::vector<typename fri_type::field_type::value_type> challenges =
transcript.template challenges<typename fri_type::field_type>(this->_fri_params.lambda);
/** This function must be called for the cases where we want to skip the
* round proof for FRI. Must be called once per instance of prover for the aggregated FRI.
* \param[in] combined_Q - Polynomial combined_Q was already computed by the current
prover in the previous step of the aggregated FRI protocol.
* \param[in] challenges - These challenges were sent from the "Main" prover,
on which the round proof was created for the polynomial F(x) = Sum(combined_Q).
*/
lpc_proof_type proof_eval_lpc_proof(
const polynomial_type& combined_Q,
const std::vector<typename fri_type::field_type::value_type>& challenges) {

typename fri_type::initial_proofs_batch_type initial_proofs =
nil::crypto3::zk::algorithms::query_phase_initial_proofs<fri_type, polynomial_type>(
Expand Down Expand Up @@ -357,7 +349,6 @@ namespace nil {
// Computes and returns the maximal power of theta used to compute the value of Combined_Q.
std::size_t compute_theta_power_for_combined_Q() {
std::size_t theta_power = 0;
this->eval_polys();
this->build_points_map();

auto points = this->get_unique_points();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,15 @@ namespace nil {
// 8. Run evaluation proofs
_proof.eval_proof.challenge = transcript.template challenge<FieldType>();
generate_evaluation_points();

if (!_skip_commitment_scheme_eval_proofs) {
_proof.eval_proof.eval_proof = _commitment_scheme.proof_eval(transcript);
} else {
if constexpr (nil::crypto3::zk::is_lpc<commitment_scheme_type>) {
// This is required for aggregated prover. If we do not run the LPC proof right now,
// we still need to push the merkle tree roots into the transcript.
_commitment_scheme.eval_polys_and_add_roots_to_transcipt(transcript);
}
}

return _proof;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,7 @@ namespace nil {
proof_type proof_eval(transcript_type &transcript) {
PROFILE_SCOPE("LPC proof_eval");

this->eval_polys();

BOOST_ASSERT(this->_points.size() == this->_polys.size());
BOOST_ASSERT(this->_points.size() == this->_z.get_batches_num());

// For each batch we have a merkle tree.
for (auto const& it: this->_trees) {
transcript(it.second.root());
}
eval_polys_and_add_roots_to_transcipt(transcript);

// Prepare z-s and combined_Q;
auto theta = transcript.template challenge<field_type>();
Expand All @@ -170,28 +162,27 @@ namespace nil {
return proof_type({this->_z, fri_proof});
}

/** This function must be called for the cases where we want to skip the
* round proof for FRI. Must be called once per instance of prover for the aggregated FRI.
* \param[in] combined_Q - Polynomial combined_Q was already computed by the current
prover in the previous step of the aggregated FRI protocol.
* \param[in] transcript - This transcript is initialized from a challenge sent from the "Main" prover,
on which the round proof was created for the polynomial F(x) = Sum(combined_Q).
*/
lpc_proof_type proof_eval_lpc_proof(
const polynomial_type& combined_Q, transcript_type &transcript) {

void eval_polys_and_add_roots_to_transcipt(transcript_type &transcript) {
this->eval_polys();

BOOST_ASSERT(this->_points.size() == this->_polys.size());
BOOST_ASSERT(this->_points.size() == this->_z.get_batches_num());

// For each batch we have a merkle tree.
for (auto const& it: this->_trees) {
transcript(it.second.root());
}
}

std::vector<typename fri_type::field_type::value_type> challenges =
transcript.template challenges<typename fri_type::field_type>(this->_fri_params.lambda);
/** This function must be called for the cases where we want to skip the
* round proof for FRI. Must be called once per instance of prover for the aggregated FRI.
* \param[in] combined_Q - Polynomial combined_Q was already computed by the current
prover in the previous step of the aggregated FRI protocol.
* \param[in] challenges - These challenges were sent from the "Main" prover,
on which the round proof was created for the polynomial F(x) = Sum(combined_Q).
*/
lpc_proof_type proof_eval_lpc_proof(
const polynomial_type& combined_Q,
const std::vector<typename fri_type::field_type::value_type>& challenges) {

typename fri_type::initial_proofs_batch_type initial_proofs =
nil::crypto3::zk::algorithms::query_phase_initial_proofs<fri_type, polynomial_type>(
Expand Down Expand Up @@ -436,7 +427,6 @@ namespace nil {
// Computes and returns the maximal power of theta used to compute the value of Combined_Q.
std::size_t compute_theta_power_for_combined_Q() {
std::size_t theta_power = 0;
this->eval_polys();
this->build_points_map();

auto points = this->get_unique_points();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ namespace nil {
generate_evaluation_points();
if (!_skip_commitment_scheme_eval_proofs) {
_proof.eval_proof.eval_proof = _commitment_scheme.proof_eval(transcript);
} else {
if constexpr (nil::crypto3::zk::is_lpc<commitment_scheme_type>) {
// This is required for aggregated prover. If we do not run the LPC proof right now,
// we still need to push the merkle tree roots into the transcript.
_commitment_scheme.eval_polys_and_add_roots_to_transcipt(transcript);
}
}

return _proof;
Expand Down
32 changes: 24 additions & 8 deletions proof-producer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ In all the calls you can change the executable name from
proof-producer-single-threaded to proof-producer-multi-threaded to run on all
the CPUs of your machine.

## Using proof-producer to generate and verify a single proof

Generate a proof and verify it:
```bash
./build/bin/proof-producer/proof-producer-single-threaded \
Expand Down Expand Up @@ -111,7 +113,9 @@ Verify generated proof:
-q 10
```

Partial proof:
## Using proof-producer to generate and verify an aggregated proof.

Partial proof, ran on each prover.
```bash
./build/bin/proof-producer/proof-producer-single-threaded \
--stage partial-prove \
Expand All @@ -129,7 +133,7 @@ Partial proof:
--json $CIRCUIT-proof.json
```

Aggregate challenges, done once on the main prover
Aggregate challenges, done once on the main prover.
```bash
./build/bin/proof-producer/proof-producer-single-threaded \
--stage="generate-aggregated-challenge" \
Expand All @@ -138,23 +142,35 @@ Aggregate challenges, done once on the main prover
--aggregated-challenge-file="aggregated_challenge.dat"
```

Compute polynomial combined_Q, done on each prover
Compute polynomial combined_Q, done on each prover. Please notice that the caller must provide the correct value of --combined-Q-starting-power, which can be taken from "$CIRCUIT-theta-power.txt" generated on stage "partial-prove".
```bash
./build/bin/proof-producer/proof-producer-single-threaded \
--stage="compute-combined-Q" \
--aggregated-challenge-file="aggregated_challenge.dat" \
--combined-Q-starting-power=0 \
--commitment-state-file="commitment_state.dat" \
--combined-Q-polynomial-file="combined-Q.dat"
--commitment-state-file="$CIRCUIT-commitment_state.dat" \
--combined-Q-polynomial-file="$CIRCUIT-combined-Q.dat"
```

Compute aggregated FRI proof done once on the main prover. This is a part of the complete proof.
Compute aggregated FRI proof done once on the main prover. This is a part of the complete proof. The '--assignment-description-file' can point to any description file, since only the number of rows matters.
```bash
./build/bin/proof-producer/proof-producer-single-threaded \
--stage="aggregated-FRI" \
--assignment-description-file="assignment-description.dat"
--assignment-description-file="assignment-description.dat" \
--aggregated-challenge-file="aggregated_challenge.dat" \
--input-combined-Q-polynomial-files "combined-Q-1.dat" "combined-Q-2.dat" \
--input-combined-Q-polynomial-files "$CIRCUIT1-combined-Q.dat" "$CIRCUIT2_combined-Q.dat" \
--proof="aggregated_FRI_proof.bin" \
--proof-of-work-file="POW.dat" \
--consistency-checks-challenges-file="challenges.dat"
```

Compute LPC consistency check proofs for polynomial combined_Q, done on each prover.
```bash
./build/bin/proof-producer/proof-producer-single-threaded \
--stage="consistency-checks" \
--commitment-state-file="$CIRCUIT-commitment_scheme_state.dat" \
--combined-Q-polynomial-file="$CIRCUIT-combined-Q.dat" \
--consistency-checks-challenges-file="challenges.dat" \
--proof="$CIRCUIT-LPC_consistency_check_proof.bin"
```

Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ namespace nil {
HashesVariant hash_type = type_identity<nil::crypto3::hashes::keccak_1600<256>>{};

std::size_t lambda = 9;
std::size_t grind = 69;
std::size_t grind = 0;
std::size_t expand_factor = 2;
std::size_t max_quotient_chunks = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ namespace nil {
PARTIAL_PROVE = 5,
COMPUTE_COMBINED_Q = 6,
GENERATE_AGGREGATED_FRI_PROOF = 7,
GENERATE_LPC_INITIAL_PROOF = 8,
GENERATE_CONSISTENCY_CHECKS_PROOF = 8,
MERGE_PROOFS = 9
};

Expand All @@ -124,7 +124,8 @@ namespace nil {
{"partial-prove", ProverStage::PARTIAL_PROVE},
{"compute-combined-Q", ProverStage::COMPUTE_COMBINED_Q},
{"merge-proofs", ProverStage::MERGE_PROOFS},
{"aggregated-FRI", ProverStage::GENERATE_AGGREGATED_FRI_PROOF}
{"aggregated-FRI", ProverStage::GENERATE_AGGREGATED_FRI_PROOF},
{"consistency-checks", ProverStage::GENERATE_CONSISTENCY_CHECKS_PROOF}
};
auto it = stage_map.find(stage);
if (it == stage_map.end()) {
Expand Down Expand Up @@ -584,7 +585,7 @@ namespace nil {
// Lambdas and grinding bits should be passed through preprocessor directives
std::size_t table_rows_log = std::ceil(std::log2(table_description_->rows_amount));

lpc_scheme_.emplace(FriParams(1, table_rows_log, lambda_, expand_factor_));
lpc_scheme_.emplace(FriParams(1, table_rows_log, lambda_, expand_factor_, grind_!=0, grind_));
}

bool preprocess_public_data() {
Expand Down Expand Up @@ -768,7 +769,7 @@ namespace nil {

bool save_challenge_vector_to_file(
const std::vector<typename BlueprintField::value_type>& challenges,
const boost::filesystem::path &consistency_checks_challenges_output_file) {
const boost::filesystem::path& consistency_checks_challenges_output_file) {

using challenge_vector_marshalling_type = nil::crypto3::marshalling::types::field_element_vector<
typename BlueprintField::value_type, TTypeBase>;
Expand All @@ -783,6 +784,28 @@ namespace nil {
consistency_checks_challenges_output_file, marshalled_challenges);
}

std::optional<std::vector<typename BlueprintField::value_type>> read_challenge_vector_from_file(
const boost::filesystem::path& input_file) {

using challenge_vector_marshalling_type = nil::crypto3::marshalling::types::field_element_vector<
typename BlueprintField::value_type, TTypeBase>;

if (!nil::proof_generator::can_read_from_file(input_file.string())) {
BOOST_LOG_TRIVIAL(error) << "Can't read file " << input_file;
return std::nullopt;
}

auto marshalled_challenges = detail::decode_marshalling_from_file<challenge_vector_marshalling_type>(
input_file);

if (!marshalled_challenges) {
return std::nullopt;
}

return nil::crypto3::marshalling::types::make_field_element_vector<
typename BlueprintField::value_type, Endianness>(marshalled_challenges.value());
}

bool generate_aggregated_FRI_proof_to_file(
const boost::filesystem::path &aggregated_challenge_file,
const std::vector<boost::filesystem::path>& input_combined_Q_polynomial_files,
Expand Down Expand Up @@ -824,6 +847,41 @@ namespace nil {
save_challenge_vector_to_file(challenges, consistency_checks_challenges_output_file);
}

bool save_lpc_consistency_proof_to_file(
const typename LpcScheme::lpc_proof_type& lpc_consistency_proof,
const boost::filesystem::path &output_file) {
// TODO(martun): consider changinge the class name 'inital_eval_proof'.
using lpc_consistency_proof_marshalling_type = nil::crypto3::marshalling::types::inital_eval_proof<
TTypeBase, LpcScheme>;

BOOST_LOG_TRIVIAL(info) << "Writing LPC consistency proof to " << output_file << std::endl;

lpc_consistency_proof_marshalling_type marshalled_proof = nil::crypto3::marshalling::types::fill_initial_eval_proof<Endianness, LpcScheme>(lpc_consistency_proof);

return detail::encode_marshalling_to_file<lpc_consistency_proof_marshalling_type>(
output_file, marshalled_proof);
}

bool generate_consistency_checks_to_file(
const boost::filesystem::path& combined_Q_file,
const boost::filesystem::path& consistency_checks_challenges_output_file,
const boost::filesystem::path& output_proof_file) {

std::optional<std::vector<typename BlueprintField::value_type>> challenges = read_challenge_vector_from_file(
consistency_checks_challenges_output_file);
if (!challenges)
return false;

std::optional<polynomial_type> combined_Q = read_poly_from_file<polynomial_type>(combined_Q_file);
if (!combined_Q)
return false;

typename LpcScheme::lpc_proof_type proof = lpc_scheme_->proof_eval_lpc_proof(
combined_Q.value(), challenges.value());

return save_lpc_consistency_proof_to_file(proof, output_proof_file);
}

private:
const std::size_t expand_factor_;
const std::size_t max_quotient_chunks_;
Expand Down
Loading

0 comments on commit e717055

Please sign in to comment.