Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ad/IPA uses Fiat-Shamir #244

Closed
wants to merge 11 commits into from
13 changes: 6 additions & 7 deletions cpp/src/barretenberg/honk/pcs/commitment_key.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,7 @@ namespace ipa {

/**
* @brief CommitmentKey object over a group 𝔾₁, using a structured reference string (SRS).
* The SRS is given as a list of 𝔾₁ points
* { [xʲ]₁ }ⱼ where 'x' is unknown.
* The SRS is given as a list of 𝔾₁ points { [xʲ]₁ }ⱼ where 'x' is unknown.
*
* @todo This class should take ownership of the SRS, and handle reading the file from disk.
*/
Expand All @@ -216,7 +215,7 @@ class CommitmentKey {
CommitmentKey() = delete;

/**
* @brief Construct a new Kate Commitment Key object from existing SRS
* @brief Construct a new IPA Commitment Key object from existing SRS
*
* @param n
* @param path
Expand Down Expand Up @@ -257,10 +256,10 @@ class VerificationKey {
VerificationKey() = delete;

/**
* @brief Construct a new Kate Commitment Key object from existing SRS
*
*
* @param verifier_srs verifier G2 point
* @brief Construct a new IPA Verification Key object from existing SRS. srs and pippenger_runtime_state are set
* public to be used in 'reduce_verify` method for MSM
* @param num_points
* @param path
*/
VerificationKey(const size_t num_points, std::string_view path)
: pippenger_runtime_state(num_points)
Expand Down
100 changes: 55 additions & 45 deletions cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,44 +32,48 @@ template <typename Params> class InnerProductArgument {
std::vector<affine_element> R_vec;
Fr a_zero;
};
// To contain the public inputs for IPA proof
// For now we are including the aux_generator and round_challenges in public input. They will be computed by the
// prover and the verifier by Fiat-Shamir when the challengeGenerator is defined.
struct PubInput {
element commitment;
Fr challenge_point;
Fr evaluation;
size_t poly_degree;
element aux_generator; // To be removed
std::vector<Fr> round_challenges; // To be removed
};

/**
* @brief Compute a proof for opening a single polynomial at a single evaluation point
*
* @param ck The commitment key containing srs and pippenger_runtime_state for computing MSM
* @param pub_input Data required to compute the opening proof. See spec for more details
* @param ck Commitment key contains srs and pippenger_runtime_state for computing MSM
* @param opening_pair OpeningPair = {challenge_point, evaluation = polynomial(challenge_point)}
* @param polynomial The witness polynomial whose opening proof needs to be computed
*
* @return a Proof, containing information required to verify whether the commitment is computed correctly and
* @return a Proof, contains information required to verify whether the commitment is computed correctly and
* the polynomial evaluation is correct in the given challenge point.
*/
static Proof reduce_prove(std::shared_ptr<CK> ck, const PubInput& pub_input, const Polynomial& polynomial)
static Proof reduce_prove(std::shared_ptr<CK> ck,
const OpeningPair<Params>& opening_pair,
const Polynomial& polynomial,
const auto& transcript)
{
Proof proof;
auto& challenge_point = pub_input.challenge_point;
auto& challenge_point = opening_pair.query;
ASSERT(challenge_point != 0 && "The challenge point should not be zero");
const size_t poly_degree = pub_input.poly_degree;
const size_t poly_degree = polynomial.size();
// To check poly_degree is greater than zero and a power of two
// TODO(#220)(Arijit): To accomodate non power of two poly_degree

ASSERT((poly_degree > 0) && (!(poly_degree & (poly_degree - 1))) &&
"The poly_degree should be positive and a power of two");
auto& aux_generator = pub_input.aux_generator;
auto a_vec = polynomial;
// TODO(#220)(Arijit): to make it more efficient by directly using G_vector for the input points when i = 0 and write the
// output points to G_vec_local. Then use G_vec_local for rounds where i>0, this can be done after we use SRS
// instead of G_vector.

auto commitment = ck->commit(polynomial);
auto& evaluation = opening_pair.evaluation;
transcript->add_element("ipa_commitment", static_cast<affine_element>(commitment).to_buffer());
transcript->add_element("ipa_challenge_point", static_cast<Fr>(challenge_point).to_buffer());
transcript->add_element("ipa_eval", static_cast<Fr>(evaluation).to_buffer());
transcript->apply_fiat_shamir("ipa_aux");

const Fr aux_challenge = Fr::serialize_from_buffer(transcript->get_challenge("ipa_aux").begin());
auto srs_elements = ck->srs.get_monomial_points();
const auto aux_generator = srs_elements[poly_degree] * aux_challenge;

auto a_vec = polynomial;
// TODO(#220)(Arijit): to make it more efficient by directly using G_vector for the input points when i = 0 and
// write the output points to G_vec_local. Then use G_vec_local for rounds where i>0, this can be done after we
// use SRS instead of G_vector.

std::vector<affine_element> G_vec_local(poly_degree);
for (size_t i = 0; i < poly_degree; i++) {
G_vec_local[i] = srs_elements[i];
Expand Down Expand Up @@ -111,9 +115,13 @@ template <typename Params> class InnerProductArgument {

L_elements[i] = affine_element(partial_L);
R_elements[i] = affine_element(partial_R);

// Generate the round challenge. TODO(#220)(Arijit): Use Fiat-Shamir
const Fr round_challenge = pub_input.round_challenges[i];
// Using Fiat-Shamir
auto label = std::to_string(i);
transcript->add_element("L_" + label, static_cast<affine_element>(partial_L).to_buffer());
transcript->add_element("R_" + label, static_cast<affine_element>(partial_R).to_buffer());
transcript->apply_fiat_shamir("ipa_round_" + label);
const Fr round_challenge =
Fr::serialize_from_buffer(transcript->get_challenge("ipa_round_" + label).begin());
const Fr round_challenge_inv = round_challenge.invert();

// Update the vectors a_vec, b_vec and G_vec.
Expand Down Expand Up @@ -156,34 +164,41 @@ template <typename Params> class InnerProductArgument {
/**
* @brief Verify the correctness of a Proof
*
* @param vk Verification_key containing srs and pippenger_runtime_state to be used for MSM
* @param proof The proof containg L_vec, R_vec and a_zero
* @param pub_input Data required to verify the proof
* @param vk Verification_key contains the srs and pippenger_runtime_state to be used for MSM
* @param claim OpeningClaim contains the commitment, challenge, and the evaluation
* @param proof Proof contains L_vec, R_vec, and a_zero
* @param transcript Transcript contains the round challenges and the aux challenge
*
* @return true/false depending on if the proof verifies
*/
static bool reduce_verify(std::shared_ptr<VK> vk, const Proof& proof, const PubInput& pub_input)
static bool reduce_verify(std::shared_ptr<VK> vk,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To follow the idiom established in KZG, we would use a class ipa::VerificationKey to avoid passing the vk as an argument here.. I see you defined this and tested it but that you don't use it. Apologies if I forgot a discussion on this--did you explain why you chose this approach?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This problem stems from the fact that ipa::VerificationKey class does not take ownership of SRS and pippenger_runtime_state (we have an issue for this here

* TODO(#218)(Adrian): This class should take ownership of the SRS, and handle reading the file from disk.
). These two parameters are needed in ipa::reduce_verify for MSM unlike other PCSs. These parameter are set by calling a constructor in commitment_key.test.cpp here. Under this settings, we access these parameters by passing the vk shared ptr as argument to ipa::reduce_verify in ipa_test.cpp here.
This was a due point in PR #205, and we decided to go with this keeping this as an issue (#236). In the current PR, we somehow solved the issue with reduce_prove by using the transcript. But I could not see a path to resolve it for reduce_verify. Please let me know if this makes sense. I shall record this in the issue #236.

const OpeningClaim<Params>& claim,
const Proof& proof,
const auto& transcript)
{
// Local copies of public inputs
auto& a_zero = proof.a_zero;
auto& commitment = pub_input.commitment;
auto& challenge_point = pub_input.challenge_point;
auto& evaluation = pub_input.evaluation;
auto& poly_degree = pub_input.poly_degree;
auto& aux_generator = pub_input.aux_generator;
auto& commitment = claim.commitment;
auto& challenge_point = claim.opening_pair.query;
auto& evaluation = claim.opening_pair.evaluation;
const auto& log_poly_degree = static_cast<size_t>(proof.L_vec.size());
const auto& poly_degree = static_cast<size_t>(static_cast<uint64_t>(Fr(2).pow(log_poly_degree)));

const Fr aux_challenge = Fr::serialize_from_buffer(transcript->get_challenge("ipa_aux").begin());
auto srs_elements = vk->srs.get_monomial_points();
const auto aux_generator = srs_elements[poly_degree] * aux_challenge;

// Compute C_prime
element C_prime = commitment + (aux_generator * evaluation);

// Compute the round challeneges and their inverses.
const size_t log_poly_degree = static_cast<size_t>(numeric::get_msb(poly_degree));
std::vector<Fr> round_challenges(log_poly_degree);
for (size_t i = 0; i < log_poly_degree; i++) {
round_challenges[i] = pub_input.round_challenges[i];
auto label = std::to_string(i);
round_challenges[i] = Fr::serialize_from_buffer(transcript->get_challenge("ipa_round_" + label).begin());
}
std::vector<Fr> round_challenges_inv(log_poly_degree);
for (size_t i = 0; i < log_poly_degree; i++) {
round_challenges_inv[i] = pub_input.round_challenges[i];
round_challenges_inv[i] = round_challenges[i];
}
Fr::batch_invert(&round_challenges_inv[0], log_poly_degree);
std::vector<affine_element> L_vec(log_poly_degree);
Expand Down Expand Up @@ -236,14 +251,9 @@ template <typename Params> class InnerProductArgument {
}
s_vec[i] = s_vec_scalar;
}
auto srs_elements = vk->srs.get_monomial_points();
// Copy the G_vector to local memory.
std::vector<affine_element> G_vec_local(poly_degree);
for (size_t i = 0; i < poly_degree; i++) {
G_vec_local[i] = srs_elements[i];
}

auto G_zero = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points(
&s_vec[0], &G_vec_local[0], poly_degree, vk->pippenger_runtime_state);
&s_vec[0], &srs_elements[0], poly_degree, vk->pippenger_runtime_state);
element right_hand_side = G_zero * a_zero;
Fr a_zero_b_zero = a_zero * b_zero;
right_hand_side += aux_generator * a_zero_b_zero;
Expand Down
62 changes: 46 additions & 16 deletions cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "barretenberg/ecc/curves/bn254/fq12.hpp"
#include "barretenberg/honk/pcs/commitment_key.hpp"
#include "barretenberg/honk/pcs/commitment_key.test.hpp"
#include "barretenberg/transcript/manifest.hpp"
using namespace barretenberg;
namespace honk::pcs::ipa {

Expand All @@ -18,6 +19,41 @@ template <class Params> class IpaCommitmentTest : public CommitmentTest<Params>
using Polynomial = barretenberg::Polynomial<Fr>;
};

// Creating mock manifest to test only the IPA PCS

static transcript::Manifest create_mock_manifest(const size_t num_ipa_rounds)
{
constexpr size_t g1_size = 64;
constexpr size_t fr_size = 32;
std::vector<transcript::Manifest::RoundManifest> manifest_rounds;

std::vector<transcript::Manifest::ManifestEntry> aux_generator_entries;
aux_generator_entries.emplace_back(transcript::Manifest::ManifestEntry(
{ .name = "ipa_commitment", .num_bytes = g1_size, .derived_by_verifier = false }));
aux_generator_entries.emplace_back(transcript::Manifest::ManifestEntry(
{ .name = "ipa_challenge_point", .num_bytes = fr_size, .derived_by_verifier = false }));
aux_generator_entries.emplace_back(transcript::Manifest::ManifestEntry(
{ .name = "ipa_eval", .num_bytes = fr_size, .derived_by_verifier = false }));
manifest_rounds.emplace_back(transcript::Manifest::RoundManifest(aux_generator_entries,
/* challenge_name = */ "ipa_aux",
/* num_challenges_in */ 1));
std::vector<transcript::Manifest::ManifestEntry> ipa_round_challenges_entries;
for (size_t i = 0; i < num_ipa_rounds; i++) {
auto label = std::to_string(i);
ipa_round_challenges_entries.emplace_back(transcript::Manifest::ManifestEntry(
{ .name = "L_" + label, .num_bytes = g1_size, .derived_by_verifier = false }));
ipa_round_challenges_entries.emplace_back(transcript::Manifest::ManifestEntry(
{ .name = "R_" + label, .num_bytes = g1_size, .derived_by_verifier = false }));
manifest_rounds.emplace_back(transcript::Manifest::RoundManifest(ipa_round_challenges_entries,
/* challenge_name = */ "ipa_round_" + label,
/* num_challenges_in */ 1));
ipa_round_challenges_entries.clear();
};

auto output = transcript::Manifest(manifest_rounds);
return output;
}

TYPED_TEST_SUITE(IpaCommitmentTest, IpaCommitmentSchemeParams);

TYPED_TEST(IpaCommitmentTest, commit)
Expand All @@ -36,26 +72,20 @@ TYPED_TEST(IpaCommitmentTest, commit)
TYPED_TEST(IpaCommitmentTest, open)
{
using IPA = InnerProductArgument<TypeParam>;
using PubInput = typename IPA::PubInput;
// generate a random polynomial, degree needs to be a power of two
size_t n = 128;
const size_t log_n = static_cast<size_t>(numeric::get_msb(n));
using Transcript = transcript::StandardTranscript;
auto transcript = std::make_shared<Transcript>(create_mock_manifest(log_n));
auto poly = this->random_polynomial(n);
auto [x, eval] = this->random_eval(poly);
auto [challenge_point, eval] = this->random_eval(poly);
barretenberg::g1::element commitment = this->commit(poly);
PubInput pub_input;
pub_input.commitment = commitment;
pub_input.challenge_point = x;
pub_input.evaluation = eval;
pub_input.poly_degree = n;
auto aux_scalar = fr::random_element();
pub_input.aux_generator = barretenberg::g1::one * aux_scalar;
const size_t log_n = static_cast<size_t>(numeric::get_msb(n));
pub_input.round_challenges = std::vector<barretenberg::fr>(log_n);
for (size_t i = 0; i < log_n; i++) {
pub_input.round_challenges[i] = barretenberg::fr::random_element();
}
auto proof = IPA::reduce_prove(this->ck(), pub_input, poly);
auto result = IPA::reduce_verify(this->vk(), proof, pub_input);

auto opening_pair = OpeningPair<TypeParam>{ challenge_point, eval };
auto opening_claim = OpeningClaim<TypeParam>{ opening_pair, commitment };

auto proof = IPA::reduce_prove(this->ck(), opening_pair, poly, transcript);
auto result = IPA::reduce_verify(this->vk(), opening_claim, proof, transcript);
EXPECT_TRUE(result);
}
} // namespace honk::pcs::ipa