From cfee87483202c0425dadc39999c34a6831114231 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 21 Jul 2022 13:11:45 +0100 Subject: [PATCH 01/25] plonk: replaced structure transcript_hash_t with class transcript_hasher that makes a call to hash function. for the moment it directly returns the expected hash values for the purposes of testing. addresses issue https://github.com/clearmatics/libsnark/issues/56. --- libsnark/zk_proof_systems/plonk/prover.hpp | 13 +-- libsnark/zk_proof_systems/plonk/prover.tcc | 33 ++++--- libsnark/zk_proof_systems/plonk/srs.hpp | 42 ++++---- libsnark/zk_proof_systems/plonk/srs.tcc | 67 +++++++++++-- .../plonk/tests/test_plonk.cpp | 96 ++++++++----------- libsnark/zk_proof_systems/plonk/verifier.hpp | 33 +++---- libsnark/zk_proof_systems/plonk/verifier.tcc | 48 ++++------ 7 files changed, 165 insertions(+), 167 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index 7a43a2a9a..d4a878e01 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -461,15 +461,8 @@ template class plonk_prover /// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 /// used in prover rounds 1 and 2 (see Sect. 8.3, roumds /// 1,2 [GWC19]) - /// \param[in] transcript_hash: hashes of the communication transcript - /// after prover rounds 1,2,3,4,5. TODO: \attention - /// currently the structure is used as an input initialized - /// with hard-coded example values for debug purposes. In - /// the long run it should be modified to be used as an - /// output. More specifically, the hard-coded values should - /// be overwritten with the actual transcript hashes - /// produced after the respective rounds within \ref - /// compute_proof + /// \param[in] transcript_hasher: hashes of the communication + /// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] proof: SNARK proof Pi (see above) @@ -477,7 +470,7 @@ template class plonk_prover const srs &srs, const std::vector &witness, const std::vector> &blind_scalars, - transcript_hash_t &transcript_hash); + transcript_hasher &hasher); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index bd5a5d078..1f572ed79 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -987,15 +987,8 @@ plonk_proof::plonk_proof( /// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 /// used in prover rounds 1 and 2 (see Sect. 8.3, roumds /// 1,2 [GWC19]) -/// \param[in] transcript_hash: hashes of the communication transcript -/// after prover rounds 1,2,3,4,5. TODO: \attention -/// currently the structure is used as an input initialized -/// with hard-coded example values for debug purposes. In -/// the long run it should be modified to be used as an -/// output. More specifically, the hard-coded values should -/// be overwritten with the actual transcript hashes -/// produced after the respective rounds within \ref -/// compute_proof +/// \param[in] transcript_hasher: hashes of the communication +/// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] proof: SNARK proof Pi (see above) @@ -1004,7 +997,7 @@ plonk_proof plonk_prover::compute_proof( const srs &srs, const std::vector &witness, const std::vector> &blind_scalars, - transcript_hash_t &transcript_hash) + transcript_hasher &hasher) { // Prover Round 0 (initialization) printf("[%s:%d] Prover Round 0...\n", __FILE__, __LINE__); @@ -1017,27 +1010,28 @@ plonk_proof plonk_prover::compute_proof( printf("[%s:%d] Prover Round 2...\n", __FILE__, __LINE__); // - beta, gamma: permutation challenges - hashes of transcript of round 1 - const libff::Fr beta = transcript_hash.beta; - const libff::Fr gamma = transcript_hash.gamma; + const libff::Fr beta = hasher.get_hash(); + const libff::Fr gamma = hasher.get_hash(); + round_two_out_t round_two_out = plonk_prover::round_two( beta, gamma, round_zero_out, blind_scalars, witness, srs); printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); // - alpha: quotient challenge - hash of transcript of rounds 1,2 - libff::Fr alpha = transcript_hash.alpha; + const libff::Fr alpha = hasher.get_hash(); round_three_out_t round_three_out = plonk_prover::round_three( alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); // - zeta: evaluation challenge - hash of transcriptof rounds 1,2,3 - libff::Fr zeta = transcript_hash.zeta; + const libff::Fr zeta = hasher.get_hash(); round_four_out_t round_four_out = plonk_prover::round_four(zeta, round_one_out, round_three_out, srs); printf("[%s:%d] Prover Round 5...\n", __FILE__, __LINE__); /// - nu: opening challenge -- hash of transcript (denoted by v in /// [GWC19]) - libff::Fr nu = transcript_hash.nu; + const libff::Fr nu = hasher.get_hash(); round_five_out_t round_five_out = plonk_prover::round_five( alpha, beta, @@ -1053,10 +1047,15 @@ plonk_proof plonk_prover::compute_proof( // TODO: activate this part when we implement actual hashing of // communication transcripts -#if 0 +#if 0 // u: multipoint evaluation challenge -- hash of transcript from // rounds 1,2,3,4,5 - libff::Fr u = transcript_hash.u; + const libff::Fr u = hasher.get_hash(); +#else + // do the hash anyway in order to keep the correct count of the + // hasher istep member (which resets to 0 only after the last hash + // is performed which is hash of u) + hasher.get_hash(); #endif // construct proof diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 38bed687b..db208d28e 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -183,32 +183,22 @@ template class plonk_keypair plonk_keypair(plonk_keypair &&other) = default; }; -/// Hashes of transcript after prover rounds 1,2,3,4,5 -template struct transcript_hash_t { - - /// - beta: permutation challenge - hashes of transcript after round 1 - libff::Fr beta; - /// - gamma: permutation challenge - hashes of transcript after round 1 - libff::Fr gamma; - /// - alpha: quotient challenge - hash of transcript after rounds 1,2 - libff::Fr alpha; - /// - zeta: evaluation challenge - hash of transcriptafter rounds 1,2,3 - libff::Fr zeta; - /// - nu: opening challenge - hash of transcript after rounds 1,2,3,4 - /// (denoted by v in [GWC19]) - libff::Fr nu; - /// - u: multipoint evaluation challenge -- hash of transcript after rounds - /// 1,2,3,4,5 - libff::Fr u; - - /// struct constructor - transcript_hash_t( - libff::Fr &beta, - libff::Fr &gamma, - libff::Fr &alpha, - libff::Fr &zeta, - libff::Fr &nu, - libff::Fr &u); +/// transcript hasher interface +template class transcript_hasher +{ +private: + // the current step of the hasher + size_t istep; + +public: + void add_element(const libff::Fr &element); + void add_element(const libff::G1 &element); + void add_element(const libff::G2 &element); + + libff::Fr get_hash(); + + // constructor + transcript_hasher(size_t &istep); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index ef4ee9c30..2c552d9ed 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -72,19 +72,68 @@ plonk_keypair::plonk_keypair( { } -/// struct transcript_hash_t constructor +/// transcript_hasher constructor template -transcript_hash_t::transcript_hash_t( - libff::Fr &beta, - libff::Fr &gamma, - libff::Fr &alpha, - libff::Fr &zeta, - libff::Fr &nu, - libff::Fr &u) - : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) +transcript_hasher::transcript_hasher(size_t &istep) : istep(istep) { } +/// dummy implementation of get_hash that directly returns the +/// expected hard-coded hashes for the purposes of unit testing TODO +/// to be replaced by a call to a proper hash function e.g. SHA2, +/// BLAKE, etc. +template libff::Fr transcript_hasher::get_hash() +{ + assert((this->istep >= 0) && (this->istep <= 5)); + using Field = libff::Fr; + + Field beta = Field("3710899868510394644410941212967766116886736137326022751" + "891187938298987182388"); + Field gamma = Field("110379303840831945879077096653321168432672740458288022" + "49545114995763715746939"); + Field alpha = Field("379799789992747238930717819864848384921111623418803600" + "22719385400306128734648"); + Field zeta = Field("4327197228921839935583364394550235027071910395980312641" + "5018065799136107272465"); + Field nu = Field("275158598338697752421507265080923414294782807831923791651" + "55175653098691426347"); + Field u = Field("1781751143954696684632449211212056577828855388109883650570" + "6049265393896966778"); + if (this->istep == 0) { + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep++; + return beta; + } + if (this->istep == 1) { + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep++; + return gamma; + } + if (this->istep == 2) { + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep++; + return alpha; + } + if (this->istep == 3) { + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep++; + return zeta; + } + if (this->istep == 4) { + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep++; + return nu; + } + if (this->istep == 5) { + // reset step to 0 + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep = 0; + return u; + } + // error + return 0; +} + /// Compute a universal srs (usrs). It is composed *only* of encoded /// powers of the secret value in the group generator. Therefore a usrs /// is independent of any particular circuit. diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index ea6297f68..acfcae5f7 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -38,7 +38,7 @@ template void test_verify_invalid_proof( const plonk_proof &valid_proof, const srs &srs, - transcript_hash_t &transcript_hash) + transcript_hasher &hasher) { // initialize verifier plonk_verifier verifier; @@ -59,14 +59,14 @@ void test_verify_invalid_proof( G1_noise = libff::G1::random_element(); proof.W_polys_blinded_at_secret_g1[i] = proof.W_polys_blinded_at_secret_g1[i] + G1_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); } // manipulate [z]_1 proof = valid_proof; G1_noise = libff::G1::random_element(); proof.z_poly_at_secret_g1 = proof.z_poly_at_secret_g1 + G1_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate [t_lo]_1, [t_mi]_1, [t_hi]_1 for (size_t i = 0; i < valid_proof.t_poly_at_secret_g1.size(); ++i) { @@ -74,62 +74,62 @@ void test_verify_invalid_proof( proof = valid_proof; G1_noise = libff::G1::random_element(); proof.t_poly_at_secret_g1[i] = proof.t_poly_at_secret_g1[i] + G1_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); } // manipulate \bar{a} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.a_zeta = proof.a_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{b} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.b_zeta = proof.b_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{c} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.c_zeta = proof.c_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma1} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_0_zeta = proof.S_0_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma2} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_1_zeta = proof.S_1_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{z_w} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.z_poly_xomega_zeta = proof.z_poly_xomega_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate [W_zeta]_1 proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_at_secret = proof.W_zeta_at_secret + G1_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate [W_{zeta omega_roots}]_1 proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_omega_at_secret = proof.W_zeta_omega_at_secret + G1_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate r_zeta proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.r_zeta = proof.r_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); } @@ -455,14 +455,6 @@ template void test_plonk_prover_rounds() // example circuit circuit_t circuit = plonk_circuit_description_from_example(example); - // get hard-coded values for the transcipt hash - transcript_hash_t transcript_hash( - example.beta, - example.gamma, - example.alpha, - example.zeta, - example.nu, - example.u); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -473,6 +465,10 @@ template void test_plonk_prover_rounds() usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + // initialize hasher + size_t istep = 0; + transcript_hasher hasher(istep); + // Prover Round 0 (initialization) round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); @@ -482,8 +478,8 @@ template void test_plonk_prover_rounds() // Unit test Prover Round 2 printf("[%s:%d] Unit test Prover Round 2...\n", __FILE__, __LINE__); - const libff::Fr beta = transcript_hash.beta; - const libff::Fr gamma = transcript_hash.gamma; + const libff::Fr beta = hasher.get_hash(); + const libff::Fr gamma = hasher.get_hash(); test_plonk_prover_round_two( example, beta, gamma, round_zero_out, blind_scalars, witness, srs); @@ -496,7 +492,7 @@ template void test_plonk_prover_rounds() round_zero_out, blind_scalars, witness, srs); round_two_out_t round_two_out = plonk_prover::round_two( beta, gamma, round_zero_out, blind_scalars, witness, srs); - libff::Fr alpha = transcript_hash.alpha; + const libff::Fr alpha = hasher.get_hash(); test_plonk_prover_round_three( example, alpha, @@ -511,7 +507,7 @@ template void test_plonk_prover_rounds() printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); round_three_out_t round_three_out = plonk_prover::round_three( alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); - libff::Fr zeta = transcript_hash.zeta; + const libff::Fr zeta = hasher.get_hash(); test_plonk_prover_round_four( example, zeta, round_one_out, round_three_out, srs); @@ -519,7 +515,7 @@ template void test_plonk_prover_rounds() printf("[%s:%d] Unit test Prover Round 5...\n", __FILE__, __LINE__); round_four_out_t round_four_out = plonk_prover::round_four( zeta, round_one_out, round_three_out, srs); - libff::Fr nu = transcript_hash.nu; + const libff::Fr nu = hasher.get_hash(); test_plonk_prover_round_five( example, alpha, @@ -592,14 +588,6 @@ template void test_plonk_prover() // example circuit circuit_t circuit = plonk_circuit_description_from_example(example); - // get hard-coded values for the transcipt hash - transcript_hash_t transcript_hash( - example.beta, - example.gamma, - example.alpha, - example.zeta, - example.nu, - example.u); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -610,11 +598,15 @@ template void test_plonk_prover() usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + // initialize hasher + size_t istep = 0; + transcript_hasher hasher(istep); + // initialize prover plonk_prover prover; // compute proof plonk_proof proof = - prover.compute_proof(srs, witness, blind_scalars, transcript_hash); + prover.compute_proof(srs, witness, blind_scalars, hasher); // compare proof against test vector values (debug) ASSERT_EQ(proof.a_zeta, example.a_zeta); ASSERT_EQ(proof.b_zeta, example.b_zeta); @@ -874,14 +866,6 @@ template void test_plonk_verifier_steps() // example circuit circuit_t circuit = plonk_circuit_description_from_example(example); - // get hard-coded values for the transcipt hash - transcript_hash_t transcript_hash( - example.beta, - example.gamma, - example.alpha, - example.zeta, - example.nu, - example.u); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -892,18 +876,22 @@ template void test_plonk_verifier_steps() usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + // initialize hasher + size_t istep = 0; + transcript_hasher hasher(istep); + // initialize prover plonk_prover prover; // compute proof plonk_proof proof = - prover.compute_proof(srs, witness, blind_scalars, transcript_hash); + prover.compute_proof(srs, witness, blind_scalars, hasher); // Unit test verifier preprocessed input test_plonk_verifier_preprocessed_input(example, srs); // unit test verifier step 5 const step_four_out_t step_four_out = - plonk_verifier::step_four(transcript_hash); + plonk_verifier::step_four(hasher); test_plonk_verifier_step_five(example, step_four_out, srs); // unit test verifier step 6 @@ -977,14 +965,6 @@ template void test_plonk_verifier() // example circuit circuit_t circuit = plonk_circuit_description_from_example(example); - // get hard-coded values for the transcipt hash - transcript_hash_t transcript_hash( - example.beta, - example.gamma, - example.alpha, - example.zeta, - example.nu, - example.u); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -995,20 +975,24 @@ template void test_plonk_verifier() usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + // initialize hasher + size_t istep = 0; + transcript_hasher hasher(istep); + // initialize prover plonk_prover prover; // compute proof plonk_proof proof = - prover.compute_proof(srs, witness, blind_scalars, transcript_hash); + prover.compute_proof(srs, witness, blind_scalars, hasher); // initialize verifier plonk_verifier verifier; // verify proof - bool b_valid_proof = verifier.verify_proof(proof, srs, transcript_hash); + bool b_valid_proof = verifier.verify_proof(proof, srs, hasher); ASSERT_TRUE(b_valid_proof); // assert that proof verification fails when the proof is // manipulated - test_verify_invalid_proof(proof, srs, transcript_hash); + test_verify_invalid_proof(proof, srs, hasher); } TEST(TestPlonk, BLS12_381) diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index e9f9f6631..81bdd4841 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -81,12 +81,12 @@ template struct step_four_out_t { libff::Fr nu; libff::Fr u; step_four_out_t( - libff::Fr &&beta, - libff::Fr &&gamma, - libff::Fr &&alpha, - libff::Fr &&zeta, - libff::Fr &&nu, - libff::Fr &&u); + libff::Fr &beta, + libff::Fr &gamma, + libff::Fr &alpha, + libff::Fr &zeta, + libff::Fr &nu, + libff::Fr &u); }; /// Verifier step 5 output @@ -186,12 +186,8 @@ template class plonk_verifier /// pi-SNARK. TODO: fixed to the test vectors for now /// /// INPUT - /// \param[in] transcript_hash: hashes of the communication transcript - /// after prover rounds 1,2,3,4,5. TODO: \attention - /// currently the hashes are pre-computed by the caller and - /// passed as input for the purpouses of unit testing. In - /// the long run this input can be removed and the hashes - /// can be computed directly inside verifier::step_four() + /// \param[in] transcript_hasher: hashes of the communication + /// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] beta, gamma: permutation challenges - hashes of @@ -202,8 +198,7 @@ template class plonk_verifier /// v in [GWC19]) /// \param[out] u: multipoint evaluation challenge - hash of /// transcript - static step_four_out_t step_four( - const transcript_hash_t &transcript_hash); + static step_four_out_t step_four(transcript_hasher &hasher); /// Verifier Step 5: compute zero polynomial evaluation /// @@ -422,19 +417,15 @@ template class plonk_verifier /// \param[in] proof: SNARK proof produced by the prover /// \param[in] srs: structured reference string containing also /// circuit-specific information - /// \param[in] transcript_hash: hashes of the communication transcript - /// after prover rounds 1,2,3,4,5. TODO: \attention - /// currently the hashes are pre-computed by the caller and - /// passed as input for the purpouses of unit testing. In - /// the long run this input can be removed and the hashes - /// can be computed directly inside verifier::step_four() + /// \param[in] transcript_hasher: hashes of the communication + /// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] boolean 1/0 = valid/invalid proof bool verify_proof( const plonk_proof &proof, const srs &srs, - transcript_hash_t &transcript_hash); + transcript_hasher &hasher); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 3768469e7..dbf4ff2c5 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -85,12 +85,12 @@ template void plonk_verifier::step_three(const srs &srs) /// struct step_four_out_t constructor template step_four_out_t::step_four_out_t( - libff::Fr &&beta, - libff::Fr &&gamma, - libff::Fr &&alpha, - libff::Fr &&zeta, - libff::Fr &&nu, - libff::Fr &&u) + libff::Fr &beta, + libff::Fr &gamma, + libff::Fr &alpha, + libff::Fr &zeta, + libff::Fr &nu, + libff::Fr &u) : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) { } @@ -100,12 +100,8 @@ step_four_out_t::step_four_out_t( /// pi-SNARK. TODO: fixed to the test vectors for now /// /// INPUT -/// \param[in] transcript_hash: hashes of the communication transcript -/// after prover rounds 1,2,3,4,5. TODO: \attention -/// currently the hashes are pre-computed by the caller and -/// passed as input for the purpouses of unit testing. In -/// the long run this input can be removed and the hashes -/// can be computed directly inside verifier::step_four() +/// \param[in] transcript_hasher: hashes of the communication +/// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] beta, gamma: permutation challenges - hashes of @@ -118,16 +114,16 @@ step_four_out_t::step_four_out_t( /// transcript template step_four_out_t plonk_verifier::step_four( - const transcript_hash_t &transcript_hash) + transcript_hasher &hasher) { + libff::Fr beta = hasher.get_hash(); + libff::Fr gamma = hasher.get_hash(); + libff::Fr alpha = hasher.get_hash(); + libff::Fr zeta = hasher.get_hash(); + libff::Fr nu = hasher.get_hash(); + libff::Fr u = hasher.get_hash(); // step 4 output - step_four_out_t step_four_out( - Field(transcript_hash.beta), - Field(transcript_hash.gamma), - Field(transcript_hash.alpha), - Field(transcript_hash.zeta), - Field(transcript_hash.nu), - Field(transcript_hash.u)); + step_four_out_t step_four_out(beta, gamma, alpha, zeta, nu, u); return step_four_out; } @@ -600,12 +596,8 @@ bool plonk_verifier::step_twelve( /// \param[in] proof: SNARK proof produced by the prover /// \param[in] srs: structured reference string containing also /// circuit-specific information -/// \param[in] transcript_hash: hashes of the communication transcript -/// after prover rounds 1,2,3,4,5. TODO: \attention -/// currently the hashes are pre-computed by the caller and -/// passed as input for the purpouses of unit testing. In -/// the long run this input can be removed and the hashes -/// can be computed directly inside verifier::step_four() +/// \param[in] transcript_hasher: hashes of the communication +/// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] boolean 1/0 = valid/invalid proof @@ -613,7 +605,7 @@ template bool plonk_verifier::verify_proof( const plonk_proof &proof, const srs &srs, - transcript_hash_t &transcript_hash) + transcript_hasher &hasher) { // compute verifier preprocessed input const verifier_preprocessed_input_t preprocessed_input = @@ -629,7 +621,7 @@ bool plonk_verifier::verify_proof( // Verifier Step 4: compute challenges hashed transcript as in // prover description, from the common inputs, public input, and // elements of pi-SNARK (fixed to the test vectors for now) - const step_four_out_t step_four_out = this->step_four(transcript_hash); + const step_four_out_t step_four_out = this->step_four(hasher); // Verifier Step 5: compute zero polynomial evaluation const step_five_out_t step_five_out = From 138edecc46a23fbf97f9ff3eb20b14eedf644954 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 16 Aug 2022 15:22:37 +0100 Subject: [PATCH 02/25] plonk: implementation of transcript hasher, addressing issue #56 and PR #61. --- libsnark/zk_proof_systems/plonk/prover.hpp | 30 +++- libsnark/zk_proof_systems/plonk/prover.tcc | 85 ++++++++-- libsnark/zk_proof_systems/plonk/srs.hpp | 78 ++++++++- libsnark/zk_proof_systems/plonk/srs.tcc | 157 +++++++++++++++--- .../plonk/tests/test_plonk.cpp | 150 +++++++++++++---- libsnark/zk_proof_systems/plonk/verifier.hpp | 4 +- libsnark/zk_proof_systems/plonk/verifier.tcc | 43 ++++- 7 files changed, 468 insertions(+), 79 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index d4a878e01..f92a59bd1 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -269,11 +269,15 @@ template class plonk_prover /// \param[out] W_polys_blinded_at_secret_g1: the blinded witness /// polynomials evaluated at the secret input denoted /// [a]_1, [b]_1, [c]_1 in [GWC19] + /// \param[out] transcript_hasher: accumulates the communication + /// transcript into a buffer to be hashed after prover + /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). static round_one_out_t round_one( const round_zero_out_t &round_zero_out, const std::vector> &blind_scalars, const std::vector> &witness, - const srs &srs); + const srs &srs, + transcript_hasher &hasher); /// Prover Round 2 /// @@ -289,13 +293,17 @@ template class plonk_prover /// \param[out] z_poly: blinded accumulator poly z(x) /// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) /// evaluated at secret + /// \param[out] transcript_hasher: accumulates the communication + /// transcript into a buffer to be hashed after prover + /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). static round_two_out_t round_two( const libff::Fr &beta, const libff::Fr &gamma, const round_zero_out_t &round_zero_out, const std::vector> blind_scalars, const std::vector> &witness, - const srs &srs); + const srs &srs, + transcript_hasher &hasher); /// Prover Round 3 /// @@ -318,6 +326,9 @@ template class plonk_prover /// input zeta i.e. t(zeta) /// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted /// by w + /// \param[out] transcript_hasher: accumulates the communication + /// transcript into a buffer to be hashed after prover + /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). static round_three_out_t round_three( const libff::Fr &alpha, const libff::Fr &beta, @@ -325,7 +336,8 @@ template class plonk_prover const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, - const srs &srs); + const srs &srs, + transcript_hasher &hasher); /// Prover Round 4 /// @@ -358,11 +370,15 @@ template class plonk_prover /// Python reference implementation does, so we do the /// same in order to match the test vectors. TODO can /// remove t_zeta in the future + /// \param[out] transcript_hasher: accumulates the communication + /// transcript into a buffer to be hashed after prover + /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). static round_four_out_t round_four( const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, - const srs &srs); + const srs &srs, + transcript_hasher &hasher); /// Prover Round 5 /// @@ -408,6 +424,9 @@ template class plonk_prover /// \param[out] W_zeta_omega_at_secret: commitment to opening proof /// polynomial W_{zeta omega}(x) at secert input /// i.e. [W_{zeta omega}(secret)]_1 + /// \param[out] transcript_hasher: accumulates the communication + /// transcript into a buffer to be hashed after prover + /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). static round_five_out_t round_five( const libff::Fr &alpha, const libff::Fr &beta, @@ -419,7 +438,8 @@ template class plonk_prover const round_two_out_t &round_two_out, const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, - const srs &srs); + const srs &srs, + transcript_hasher &hasher); /// Prover compute SNARK proof /// diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 1f572ed79..a9c3640e6 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -93,12 +93,16 @@ round_one_out_t::round_one_out_t( /// \param[out] W_polys_blinded_at_secret_g1: the blinded witness /// polynomials evaluated at the secret input denoted /// [a]_1, [b]_1, [c]_1 in [GWC19] +/// \param[out] transcript_hasher: accumulates the communication +/// transcript into a buffer to be hashed after prover +/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_one_out_t plonk_prover::round_one( const round_zero_out_t &round_zero_out, const std::vector> &blind_scalars, const std::vector> &witness, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { using Field = libff::Fr; const size_t nwitness = NUM_HSETS; @@ -140,6 +144,11 @@ round_one_out_t plonk_prover::round_one( plonk_evaluate_polys_at_secret_G1( srs.secret_powers_g1, W_polys_blinded, W_polys_blinded_at_secret_g1); + // add outputs from Round 1 to the hash buffer + hasher.add_element(W_polys_blinded_at_secret_g1[a]); + hasher.add_element(W_polys_blinded_at_secret_g1[b]); + hasher.add_element(W_polys_blinded_at_secret_g1[c]); + round_one_out_t round_one_out( std::move(W_polys), std::move(W_polys_blinded), @@ -170,6 +179,9 @@ round_two_out_t::round_two_out_t( /// \param[out] z_poly: blinded accumulator poly z(x) /// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) /// evaluated at secret +/// \param[out] transcript_hasher: accumulates the communication +/// transcript into a buffer to be hashed after prover +/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_two_out_t plonk_prover::round_two( const libff::Fr &beta, @@ -177,7 +189,8 @@ round_two_out_t plonk_prover::round_two( const round_zero_out_t &round_zero_out, const std::vector> blind_scalars, const std::vector> &witness, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { using Field = libff::Fr; @@ -205,6 +218,9 @@ round_two_out_t plonk_prover::round_two( z_poly_at_secret_g1 = plonk_evaluate_poly_at_secret_G1(srs.secret_powers_g1, z_poly); + // add outputs from Round 2 to the hash buffer + hasher.add_element(z_poly_at_secret_g1); + round_two_out_t round_two_out( std::move(z_poly), std::move(z_poly_at_secret_g1)); @@ -246,6 +262,9 @@ round_three_out_t::round_three_out_t( /// input zeta i.e. t(zeta) /// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted /// by w +/// \param[out] transcript_hasher: accumulates the communication +/// transcript into a buffer to be hashed after prover +/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_three_out_t plonk_prover::round_three( const libff::Fr &alpha, @@ -254,7 +273,8 @@ round_three_out_t plonk_prover::round_three( const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { using Field = libff::Fr; int num_hgen = NUM_HSETS; @@ -462,6 +482,11 @@ round_three_out_t plonk_prover::round_three( srs.secret_powers_g1, t_poly[i]); } + // add outputs from Round 3 to the hash buffer + hasher.add_element(t_poly_at_secret_g1[lo]); + hasher.add_element(t_poly_at_secret_g1[mid]); + hasher.add_element(t_poly_at_secret_g1[hi]); + round_three_out_t round_three_out( std::move(z_poly_xomega), std::move(t_poly), @@ -522,12 +547,16 @@ round_four_out_t::round_four_out_t( /// Python reference implementation \[PlonkPy] does, so we /// do the same in order to match the test vectors. TODO /// can remove t_zeta in the future +/// \param[out] transcript_hasher: accumulates the communication +/// transcript into a buffer to be hashed after prover +/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_four_out_t plonk_prover::round_four( const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { using Field = libff::Fr; @@ -557,6 +586,14 @@ round_four_out_t plonk_prover::round_four( round_three_out.z_poly_xomega, zeta); + // add outputs from Round 4 to the hash buffer + hasher.add_element(a_zeta); + hasher.add_element(b_zeta); + hasher.add_element(c_zeta); + hasher.add_element(S_0_zeta); + hasher.add_element(S_1_zeta); + hasher.add_element(z_poly_xomega_zeta); + round_four_out_t round_four_out( std::move(a_zeta), std::move(b_zeta), @@ -625,6 +662,9 @@ round_five_out_t::round_five_out_t( /// \param[out] W_zeta_omega_at_secret: commitment to opening proof /// polynomial W_{zeta omega}(x) at secert input /// i.e. [W_{zeta omega}(secret)]_1 +/// \param[out] transcript_hasher: accumulates the communication +/// transcript into a buffer to be hashed after prover +/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_five_out_t plonk_prover::round_five( const libff::Fr &alpha, @@ -637,7 +677,8 @@ round_five_out_t plonk_prover::round_five( const round_two_out_t &round_two_out, const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { using Field = libff::Fr; polynomial remainder; @@ -909,6 +950,11 @@ round_five_out_t plonk_prover::round_five( W_zeta_omega_at_secret = plonk_evaluate_poly_at_secret_G1( srs.secret_powers_g1, W_zeta_omega); + // add outputs from Round 5 to the hash buffer + hasher.add_element(r_zeta); + hasher.add_element(W_zeta_at_secret); + hasher.add_element(W_zeta_omega_at_secret); + round_five_out_t round_five_out( std::move(r_zeta), std::move(W_zeta_at_secret), @@ -1005,28 +1051,40 @@ plonk_proof plonk_prover::compute_proof( // Prover Round 1 printf("[%s:%d] Prover Round 1...\n", __FILE__, __LINE__); - round_one_out_t round_one_out = - plonk_prover::round_one(round_zero_out, blind_scalars, witness, srs); + round_one_out_t round_one_out = plonk_prover::round_one( + round_zero_out, blind_scalars, witness, srs, hasher); printf("[%s:%d] Prover Round 2...\n", __FILE__, __LINE__); - // - beta, gamma: permutation challenges - hashes of transcript of round 1 + // - beta: permutation challenges - hashes of transcript of round + // 1 (\attention the original protocl appends a 0, while we don't + // append anyhting to avoid making a copy of the buffer) const libff::Fr beta = hasher.get_hash(); + // - gamma: permutation challenges - hashes of transcript of round + // 1 with 1 appended + hasher.add_element(libff::Fr::one()); const libff::Fr gamma = hasher.get_hash(); round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs); + beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); // - alpha: quotient challenge - hash of transcript of rounds 1,2 const libff::Fr alpha = hasher.get_hash(); round_three_out_t round_three_out = plonk_prover::round_three( - alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); + alpha, + beta, + gamma, + round_zero_out, + round_one_out, + round_two_out, + srs, + hasher); printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); // - zeta: evaluation challenge - hash of transcriptof rounds 1,2,3 const libff::Fr zeta = hasher.get_hash(); - round_four_out_t round_four_out = - plonk_prover::round_four(zeta, round_one_out, round_three_out, srs); + round_four_out_t round_four_out = plonk_prover::round_four( + zeta, round_one_out, round_three_out, srs, hasher); printf("[%s:%d] Prover Round 5...\n", __FILE__, __LINE__); /// - nu: opening challenge -- hash of transcript (denoted by v in @@ -1043,7 +1101,8 @@ plonk_proof plonk_prover::compute_proof( round_two_out, round_three_out, round_four_out, - srs); + srs, + hasher); // TODO: activate this part when we implement actual hashing of // communication transcripts diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index db208d28e..e58199855 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -184,21 +184,93 @@ template class plonk_keypair }; /// transcript hasher interface +/// +/// the hasher works in the Prover as follows: +/// +/// round 1 +/// +/// add_element(buffer, a_eval_exp) +/// add_element(buffer, b_eval_exp) +/// add_element(buffer, c_eval_exp) +/// // buffer = first_output +/// +/// round 2 +/// +/// beta = hash(str(buffer) + "0") +/// gamma = hash(str(buffer) + "1") +/// +/// acc_eval = evaluate_in_exponent(CRS, accumulator_poly.to_coeffs()) +/// +/// add_element(buffer, acc_eval) +/// // buffer = first_output + second_output +/// +/// round 3 +/// +/// alpha = hash(str(buffer)) +/// +/// add_element(buffer, t_lo_eval_exp) +/// add_element(buffer, t_mid_eval_exp) +/// add_element(buffer, t_hi_eval_exp) +/// // buffer = first_output + second_output + third_output +/// +/// round 4 +/// +/// zeta = hash(str(buffer)) +/// +/// add_element(buffer, a_zeta) +/// add_element(buffer, b_zeta) +/// add_element(buffer, c_zeta) +/// add_element(buffer, S_0_zeta) +/// add_element(buffer, S_1_zeta) +/// add_element(buffer, accumulator_shift_zeta) +/// add_element(buffer, t_zeta) +/// add_element(buffer, r_zeta) +/// // buffer = first_output + second_output + third_output + fourth_output +/// +/// round 5 +/// +/// nu = hash(str(buffer)) +/// +/// W_zeta_eval_exp = evaluate_in_exponent(CRS, W_zeta.to_coeffs()) +/// W_zeta_omega_eval_exp = evaluate_in_exponent(CRS, +/// W_zeta_omega.to_coeffs()) +/// +/// add_element(buffer, W_zeta_eval_exp) +/// add_element(buffer, W_zeta_omega_eval_exp) +/// +/// // buffer = first_output + second_output + third_output + fourth_output +/// + fifth_output +/// +/// u = hash(str(buffer)) +/// template class transcript_hasher { private: - // the current step of the hasher - size_t istep; + // buffer accumulating data to be hashed + std::vector buffer; public: void add_element(const libff::Fr &element); void add_element(const libff::G1 &element); void add_element(const libff::G2 &element); + // TODO: use next declaration to implement an actual hash function + // e.g. BLAKE (from Aztec barretenberg implementation): + // https://github.com/AztecProtocol/barretenberg/blob/master/barretenberg/src/aztec/plonk/transcript/transcript.cpp#L33 + // + // std::array + // Blake2sHasher::hash(std::vector const& buffer) + libff::Fr get_hash(); + // clear the buffer (for now only for testing) + void buffer_clear(); + + // get buffer size + size_t buffer_size(); + // constructor - transcript_hasher(size_t &istep); + transcript_hasher(std::vector &buffer); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 2c552d9ed..299adce8c 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -74,19 +74,99 @@ plonk_keypair::plonk_keypair( /// transcript_hasher constructor template -transcript_hasher::transcript_hasher(size_t &istep) : istep(istep) +transcript_hasher::transcript_hasher(std::vector &buffer) + : buffer(std::move(buffer)) { } +/// clear the buffer (for now only for testing) +template void transcript_hasher::buffer_clear() +{ + this->buffer.clear(); +} + +/// get buffer size +template size_t transcript_hasher::buffer_size() +{ + return this->buffer.size(); +} + +/// add an Fr element to the transcript buffer for hashing +template +void transcript_hasher::add_element(const libff::Fr &element) +{ + // convert the Fr element into a string + std::string str; + { + std::ostringstream ss; + libff::field_write( + element, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +/// add the coordinates of a G1 curve point to the transcript buffer for hashing +template +void transcript_hasher::add_element(const libff::G1 &element) +{ + libff::G1 element_aff(element); + element_aff.to_affine_coordinates(); + + // convert the affine coordinates of the curve point into a string + std::string str; + { + std::ostringstream ss; + libff::group_write< + libff::encoding_binary, + libff::form_plain, + libff::compression_off>(element_aff, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +/// add the coordinates of a G2 curve point to the transcript buffer for hashing +template +void transcript_hasher::add_element(const libff::G2 &element) +{ + libff::G2 element_aff(element); + element_aff.to_affine_coordinates(); + + // convert the affine coordinates of the curve point into a string + std::string str; + { + std::ostringstream ss; + libff::group_write< + libff::encoding_binary, + libff::form_plain, + libff::compression_off>(element_aff, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + /// dummy implementation of get_hash that directly returns the /// expected hard-coded hashes for the purposes of unit testing TODO /// to be replaced by a call to a proper hash function e.g. SHA2, /// BLAKE, etc. template libff::Fr transcript_hasher::get_hash() { - assert((this->istep >= 0) && (this->istep <= 5)); using Field = libff::Fr; + size_t buffer_len = this->buffer.size(); + // DEBUG + printf("[%s:%d] len %7d\n", __FILE__, __LINE__, (int)buffer_len); + + // vector of valid lengths (\attention specific to BLS12-381) + std::vector length{288, 320, 416, 704, 896, 1120}; + Field beta = Field("3710899868510394644410941212967766116886736137326022751" "891187938298987182388"); Field gamma = Field("110379303840831945879077096653321168432672740458288022" @@ -99,38 +179,73 @@ template libff::Fr transcript_hasher::get_hash() "55175653098691426347"); Field u = Field("1781751143954696684632449211212056577828855388109883650570" "6049265393896966778"); - if (this->istep == 0) { - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep++; + // beta + if (buffer_len == length[0]) { + printf( + "[%s:%d] buffer_len %d: beta\n", + __FILE__, + __LINE__, + (int)buffer_len); return beta; } - if (this->istep == 1) { - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep++; + // gamma + if (buffer_len == length[1]) { + printf( + "[%s:%d] buffer_len %d: gamma\n", + __FILE__, + __LINE__, + (int)buffer_len); return gamma; } - if (this->istep == 2) { - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep++; + // alpha + if (buffer_len == length[2]) { + printf( + "[%s:%d] buffer_len %d: alpha\n", + __FILE__, + __LINE__, + (int)buffer_len); return alpha; } - if (this->istep == 3) { - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep++; + // zeta + if (buffer_len == length[3]) { + printf( + "[%s:%d] buffer_len %d: zeta\n", + __FILE__, + __LINE__, + (int)buffer_len); return zeta; } - if (this->istep == 4) { - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep++; + // nu + if (buffer_len == length[4]) { + printf( + "[%s:%d] buffer_len %d: nu\n", __FILE__, __LINE__, (int)buffer_len); return nu; } - if (this->istep == 5) { + // u + if (buffer_len == length[5]) { // reset step to 0 - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep = 0; + printf( + "[%s:%d] buffer_len %d: u + clear()\n", + __FILE__, + __LINE__, + (int)buffer_len); + this->buffer.clear(); return u; } - // error + bool b_valid_length = + ((buffer_len == length[0]) || (buffer_len == length[1]) || + (buffer_len == length[2]) || (buffer_len == length[3]) || + (buffer_len == length[4]) || (buffer_len == length[5])); + try { + if (!b_valid_length) { + throw std::logic_error( + "Error: invalid length of transcript hasher buffer"); + } + } catch (const std::logic_error &e) { + std::cout << "Error: " << e.what() << "\n"; + } + assert(b_valid_length); + // If we are here, then the hasher buffer has invalid length so return error return 0; } diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index acfcae5f7..68e13ee87 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -268,11 +268,12 @@ void test_plonk_prover_round_one( const plonk_example &example, const round_zero_out_t &round_zero_out, const std::vector> &witness, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { std::vector> blind_scalars = example.prover_blind_scalars; round_one_out_t round_one_out = plonk_prover::round_one( - round_zero_out, blind_scalars, witness, srs); + round_zero_out, blind_scalars, witness, srs, hasher); for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, (int)i); libff::print_vector(round_one_out.W_polys[i]); @@ -307,10 +308,11 @@ void test_plonk_prover_round_two( const round_zero_out_t &round_zero_out, const std::vector> &blind_scalars, const std::vector> &witness, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs); + beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); printf("[%s:%d] z_poly\n", __FILE__, __LINE__); libff::print_vector(round_two_out.z_poly); ASSERT_EQ(round_two_out.z_poly, example.z_poly); @@ -332,10 +334,18 @@ void test_plonk_prover_round_three( const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { round_three_out_t round_three_out = plonk_prover::round_three( - alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); + alpha, + beta, + gamma, + round_zero_out, + round_one_out, + round_two_out, + srs, + hasher); printf("[%s:%d] Output from Round 3\n", __FILE__, __LINE__); printf("[%s:%d] t_poly_long\n", __FILE__, __LINE__); libff::print_vector(round_three_out.t_poly_long); @@ -362,10 +372,11 @@ void test_plonk_prover_round_four( const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { round_four_out_t round_four_out = plonk_prover::round_four( - zeta, round_one_out, round_three_out, srs); + zeta, round_one_out, round_three_out, srs, hasher); // Prover Round 4 output check against test vectors printf("[%s:%d] Output from Round 4\n", __FILE__, __LINE__); printf("a_zeta "); @@ -404,7 +415,8 @@ void test_plonk_prover_round_five( const round_two_out_t &round_two_out, const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { round_five_out_t round_five_out = plonk_prover::round_five( alpha, @@ -417,7 +429,8 @@ void test_plonk_prover_round_five( round_two_out, round_three_out, round_four_out, - srs); + srs, + hasher); printf("[%s:%d] Outputs from Prover round 5\n", __FILE__, __LINE__); printf("r_zeta "); @@ -466,32 +479,59 @@ template void test_plonk_prover_rounds() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - size_t istep = 0; - transcript_hasher hasher(istep); + std::vector buffer; + transcript_hasher hasher(buffer); // Prover Round 0 (initialization) round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); - // Unit test Prover Round 1 + // --- Unit test Prover Round 1 --- + // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Unit test Prover Round 1...\n", __FILE__, __LINE__); - test_plonk_prover_round_one(example, round_zero_out, witness, srs); + test_plonk_prover_round_one( + example, round_zero_out, witness, srs, hasher); - // Unit test Prover Round 2 + // --- Unit test Prover Round 2 --- + // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Unit test Prover Round 2...\n", __FILE__, __LINE__); + round_one_out_t round_one_out = plonk_prover::round_one( + round_zero_out, blind_scalars, witness, srs, hasher); + // clear hash buffer + hasher.buffer_clear(); + // add outputs from Round 1 to the hash buffer + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); const libff::Fr beta = hasher.get_hash(); + hasher.add_element(libff::Fr::one()); const libff::Fr gamma = hasher.get_hash(); test_plonk_prover_round_two( - example, beta, gamma, round_zero_out, blind_scalars, witness, srs); + example, + beta, + gamma, + round_zero_out, + blind_scalars, + witness, + srs, + hasher); // Unit test plonk_compute_accumulator test_plonk_compute_accumulator(example, beta, gamma, witness, srs); - // Unit test Prover Round 3 + // --- Unit test Prover Round 3 --- + // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); - round_one_out_t round_one_out = plonk_prover::round_one( - round_zero_out, blind_scalars, witness, srs); round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs); + beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); + // clear hash buffer + hasher.buffer_clear(); + // add outputs from Round 1 to the hash buffer + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); + hasher.add_element(libff::Fr::one()); + // add outputs from Round 2 to the hash buffer + hasher.add_element(round_two_out.z_poly_at_secret_g1); const libff::Fr alpha = hasher.get_hash(); test_plonk_prover_round_three( example, @@ -501,20 +541,61 @@ template void test_plonk_prover_rounds() round_zero_out, round_one_out, round_two_out, - srs); + srs, + hasher); - // Unit test Prover Round 4 + // --- Unit test Prover Round 4 --- printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); round_three_out_t round_three_out = plonk_prover::round_three( - alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); + alpha, + beta, + gamma, + round_zero_out, + round_one_out, + round_two_out, + srs, + hasher); + // clear hash buffer + hasher.buffer_clear(); + // add outputs from Round 1 to the hash buffer + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); + hasher.add_element(libff::Fr::one()); + // add outputs from Round 2 to the hash buffer + hasher.add_element(round_two_out.z_poly_at_secret_g1); + // add outputs from Round 3 to the hash buffer + hasher.add_element(round_three_out.t_poly_at_secret_g1[lo]); + hasher.add_element(round_three_out.t_poly_at_secret_g1[mid]); + hasher.add_element(round_three_out.t_poly_at_secret_g1[hi]); const libff::Fr zeta = hasher.get_hash(); test_plonk_prover_round_four( - example, zeta, round_one_out, round_three_out, srs); + example, zeta, round_one_out, round_three_out, srs, hasher); - // Unit test Prover Round 5 + // --- Unit test Prover Round 5 --- printf("[%s:%d] Unit test Prover Round 5...\n", __FILE__, __LINE__); round_four_out_t round_four_out = plonk_prover::round_four( - zeta, round_one_out, round_three_out, srs); + zeta, round_one_out, round_three_out, srs, hasher); + // clear hash buffer + hasher.buffer_clear(); + // add outputs from Round 1 to the hash buffer + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); + hasher.add_element(libff::Fr::one()); + // add outputs from Round 2 to the hash buffer + hasher.add_element(round_two_out.z_poly_at_secret_g1); + // add outputs from Round 3 to the hash buffer + hasher.add_element(round_three_out.t_poly_at_secret_g1[lo]); + hasher.add_element(round_three_out.t_poly_at_secret_g1[mid]); + hasher.add_element(round_three_out.t_poly_at_secret_g1[hi]); + // add outputs from Round 4 to the hash buffer + hasher.add_element(round_four_out.a_zeta); + hasher.add_element(round_four_out.b_zeta); + hasher.add_element(round_four_out.c_zeta); + hasher.add_element(round_four_out.S_0_zeta); + hasher.add_element(round_four_out.S_1_zeta); + hasher.add_element(round_four_out.z_poly_xomega_zeta); const libff::Fr nu = hasher.get_hash(); test_plonk_prover_round_five( example, @@ -528,7 +609,8 @@ template void test_plonk_prover_rounds() round_two_out, round_three_out, round_four_out, - srs); + srs, + hasher); } /// \attention the example class is defined specifically for the BLS12-381 @@ -599,8 +681,8 @@ template void test_plonk_prover() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - size_t istep = 0; - transcript_hasher hasher(istep); + std::vector buffer; + transcript_hasher hasher(buffer); // initialize prover plonk_prover prover; @@ -877,8 +959,8 @@ template void test_plonk_verifier_steps() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - size_t istep = 0; - transcript_hasher hasher(istep); + std::vector buffer; + transcript_hasher hasher(buffer); // initialize prover plonk_prover prover; @@ -891,7 +973,7 @@ template void test_plonk_verifier_steps() // unit test verifier step 5 const step_four_out_t step_four_out = - plonk_verifier::step_four(hasher); + plonk_verifier::step_four(proof, hasher); test_plonk_verifier_step_five(example, step_four_out, srs); // unit test verifier step 6 @@ -976,8 +1058,8 @@ template void test_plonk_verifier() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - size_t istep = 0; - transcript_hasher hasher(istep); + std::vector buffer; + transcript_hasher hasher(buffer); // initialize prover plonk_prover prover; diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index 81bdd4841..ea26340ea 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -186,6 +186,7 @@ template class plonk_verifier /// pi-SNARK. TODO: fixed to the test vectors for now /// /// INPUT + /// \param[in] proof: SNARK proof produced by the prover /// \param[in] transcript_hasher: hashes of the communication /// transcript after prover rounds 1,2,3,4,5. /// @@ -198,7 +199,8 @@ template class plonk_verifier /// v in [GWC19]) /// \param[out] u: multipoint evaluation challenge - hash of /// transcript - static step_four_out_t step_four(transcript_hasher &hasher); + static step_four_out_t step_four( + const plonk_proof &proof, transcript_hasher &hasher); /// Verifier Step 5: compute zero polynomial evaluation /// diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index dbf4ff2c5..5380fe5b3 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -100,6 +100,7 @@ step_four_out_t::step_four_out_t( /// pi-SNARK. TODO: fixed to the test vectors for now /// /// INPUT +/// \param[in] proof: SNARK proof produced by the prover /// \param[in] transcript_hasher: hashes of the communication /// transcript after prover rounds 1,2,3,4,5. /// @@ -114,14 +115,52 @@ step_four_out_t::step_four_out_t( /// transcript template step_four_out_t plonk_verifier::step_four( - transcript_hasher &hasher) + const plonk_proof &proof, transcript_hasher &hasher) { + // add outputs from Round 1 to the hash buffer + hasher.add_element(proof.W_polys_blinded_at_secret_g1[a]); + hasher.add_element(proof.W_polys_blinded_at_secret_g1[b]); + hasher.add_element(proof.W_polys_blinded_at_secret_g1[c]); + // - beta: permutation challenge - hashes of transcript of round + // 1 (\attention the original protocl appends a 0, while we don't + // append anyhting to avoid making a copy of the buffer) libff::Fr beta = hasher.get_hash(); + // - gamma: permutation challenge - hashes of transcript of round + // 1 with 1 appended + hasher.add_element(libff::Fr::one()); libff::Fr gamma = hasher.get_hash(); + + // add outputs from Round 2 to the hash buffer + hasher.add_element(proof.z_poly_at_secret_g1); + // - alpha: quotient challenge - hash of transcript of rounds 1,2 libff::Fr alpha = hasher.get_hash(); + + // add outputs from Round 3 to the hash buffer + hasher.add_element(proof.t_poly_at_secret_g1[lo]); + hasher.add_element(proof.t_poly_at_secret_g1[mid]); + hasher.add_element(proof.t_poly_at_secret_g1[hi]); + // - zeta: evaluation challenge - hash of transcriptof rounds 1,2,3 libff::Fr zeta = hasher.get_hash(); + + // add outputs from Round 4 to the hash buffer + hasher.add_element(proof.a_zeta); + hasher.add_element(proof.b_zeta); + hasher.add_element(proof.c_zeta); + hasher.add_element(proof.S_0_zeta); + hasher.add_element(proof.S_1_zeta); + hasher.add_element(proof.z_poly_xomega_zeta); + // - nu: opening challenge -- hash of transcript (denoted by v in + // [GWC19]) libff::Fr nu = hasher.get_hash(); + + // add outputs from Round 5 to the hash buffer + hasher.add_element(proof.r_zeta); + hasher.add_element(proof.W_zeta_at_secret); + hasher.add_element(proof.W_zeta_omega_at_secret); + // u: multipoint evaluation challenge -- hash of transcript from + // rounds 1,2,3,4,5 libff::Fr u = hasher.get_hash(); + // step 4 output step_four_out_t step_four_out(beta, gamma, alpha, zeta, nu, u); @@ -621,7 +660,7 @@ bool plonk_verifier::verify_proof( // Verifier Step 4: compute challenges hashed transcript as in // prover description, from the common inputs, public input, and // elements of pi-SNARK (fixed to the test vectors for now) - const step_four_out_t step_four_out = this->step_four(hasher); + const step_four_out_t step_four_out = this->step_four(proof, hasher); // Verifier Step 5: compute zero polynomial evaluation const step_five_out_t step_five_out = From 55fb22772325f1f2e41df956bd1e63c45af87315 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 17 Aug 2022 10:29:07 +0100 Subject: [PATCH 03/25] plonk: moved the initialisation of the array of expected hash values to the transcript hasher constructor (cf. https://github.com/clearmatics/libsnark/pull/61#discussion_r935463921); added exception handling in case the buffer length is invalid (cf. https://github.com/clearmatics/libsnark/pull/61#discussion_r935473057) --- libsnark/zk_proof_systems/plonk/srs.hpp | 3 + libsnark/zk_proof_systems/plonk/srs.tcc | 90 +++++++++++-------- .../plonk/tests/test_plonk.cpp | 1 - 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index e58199855..2acb93c4c 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -248,6 +248,9 @@ template class transcript_hasher private: // buffer accumulating data to be hashed std::vector buffer; + // array containing the hash values of the communication transcript + // i.e. the six challenges (in this order): beta, gamma, alpha, zeta, nu, u + std::array, 6> hash_values; public: void add_element(const libff::Fr &element); diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 299adce8c..e6fbcbd86 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -77,6 +77,25 @@ template transcript_hasher::transcript_hasher(std::vector &buffer) : buffer(std::move(buffer)) { + // test array containing the expected hash values of the communication + // transcript i.e. the communication challenges (in this order): beta, + // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 + this->hash_values = { + libff::Fr("3710899868510394644410941212967766116886736137326022751" + "891187938298987182388"), // beta + libff::Fr("110379303840831945879077096653321168432672740458288022" + "49545114995763715746939"), // gamma + libff::Fr("379799789992747238930717819864848384921111623418803600" + "22719385400306128734648"), // alpha + libff::Fr("4327197228921839935583364394550235027071910395980312641" + "5018065799136107272465"), // zeta + libff::Fr( + "275158598338697752421507265080923414294782807831923791651" + "55175653098691426347"), // nu + libff::Fr( + "1781751143954696684632449211212056577828855388109883650570" + "6049265393896966778"), // u + }; } /// clear the buffer (for now only for testing) @@ -158,27 +177,37 @@ void transcript_hasher::add_element(const libff::G2 &element) /// BLAKE, etc. template libff::Fr transcript_hasher::get_hash() { - using Field = libff::Fr; - size_t buffer_len = this->buffer.size(); // DEBUG printf("[%s:%d] len %7d\n", __FILE__, __LINE__, (int)buffer_len); // vector of valid lengths (\attention specific to BLS12-381) - std::vector length{288, 320, 416, 704, 896, 1120}; - - Field beta = Field("3710899868510394644410941212967766116886736137326022751" - "891187938298987182388"); - Field gamma = Field("110379303840831945879077096653321168432672740458288022" - "49545114995763715746939"); - Field alpha = Field("379799789992747238930717819864848384921111623418803600" - "22719385400306128734648"); - Field zeta = Field("4327197228921839935583364394550235027071910395980312641" - "5018065799136107272465"); - Field nu = Field("275158598338697752421507265080923414294782807831923791651" - "55175653098691426347"); - Field u = Field("1781751143954696684632449211212056577828855388109883650570" - "6049265393896966778"); + const std::vector length{288, 320, 416, 704, 896, 1120}; + + // If we are here, then the hasher buffer has invalid length so throw an + // exception + bool b_valid_length = + ((buffer_len == length[0]) || (buffer_len == length[1]) || + (buffer_len == length[2]) || (buffer_len == length[3]) || + (buffer_len == length[4]) || (buffer_len == length[5])); + try { + if (!b_valid_length) { + throw std::logic_error( + "Error: invalid length of transcript hasher buffer"); + } + } catch (const std::logic_error &e) { + std::cout << "Error: " << e.what() << "\n"; + } + if (!b_valid_length) { + printf( + "[%s:%d] Error: invalid length of transcript hasher buffer\n", + __FILE__, + __LINE__); + } + assert(b_valid_length); + + libff::Fr challenge = 0; + // beta if (buffer_len == length[0]) { printf( @@ -186,7 +215,7 @@ template libff::Fr transcript_hasher::get_hash() __FILE__, __LINE__, (int)buffer_len); - return beta; + challenge = this->hash_values[0]; // beta } // gamma if (buffer_len == length[1]) { @@ -195,7 +224,7 @@ template libff::Fr transcript_hasher::get_hash() __FILE__, __LINE__, (int)buffer_len); - return gamma; + challenge = this->hash_values[1]; // gamma } // alpha if (buffer_len == length[2]) { @@ -204,7 +233,7 @@ template libff::Fr transcript_hasher::get_hash() __FILE__, __LINE__, (int)buffer_len); - return alpha; + challenge = this->hash_values[2]; // alpha } // zeta if (buffer_len == length[3]) { @@ -213,13 +242,13 @@ template libff::Fr transcript_hasher::get_hash() __FILE__, __LINE__, (int)buffer_len); - return zeta; + challenge = this->hash_values[3]; // zeta } // nu if (buffer_len == length[4]) { printf( "[%s:%d] buffer_len %d: nu\n", __FILE__, __LINE__, (int)buffer_len); - return nu; + challenge = this->hash_values[4]; // nu } // u if (buffer_len == length[5]) { @@ -230,23 +259,10 @@ template libff::Fr transcript_hasher::get_hash() __LINE__, (int)buffer_len); this->buffer.clear(); - return u; + challenge = this->hash_values[5]; // u } - bool b_valid_length = - ((buffer_len == length[0]) || (buffer_len == length[1]) || - (buffer_len == length[2]) || (buffer_len == length[3]) || - (buffer_len == length[4]) || (buffer_len == length[5])); - try { - if (!b_valid_length) { - throw std::logic_error( - "Error: invalid length of transcript hasher buffer"); - } - } catch (const std::logic_error &e) { - std::cout << "Error: " << e.what() << "\n"; - } - assert(b_valid_length); - // If we are here, then the hasher buffer has invalid length so return error - return 0; + + return challenge; } /// Compute a universal srs (usrs). It is composed *only* of encoded diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 68e13ee87..e6329831c 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -20,7 +20,6 @@ namespace libsnark { - #define PLONK_MAX_DEGREE 245 // Manipulate elements of a valid proof to assert that proof From e6415bf7597937e8606ce8a501b4c5b52d78bef5 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 17 Aug 2022 20:07:52 +0100 Subject: [PATCH 04/25] plonk: removed catching the invalid size exception within the get_hash function. the caller must handle it. --- libsnark/zk_proof_systems/plonk/srs.tcc | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index e6fbcbd86..ff3ba75f5 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -190,13 +190,9 @@ template libff::Fr transcript_hasher::get_hash() ((buffer_len == length[0]) || (buffer_len == length[1]) || (buffer_len == length[2]) || (buffer_len == length[3]) || (buffer_len == length[4]) || (buffer_len == length[5])); - try { - if (!b_valid_length) { - throw std::logic_error( - "Error: invalid length of transcript hasher buffer"); - } - } catch (const std::logic_error &e) { - std::cout << "Error: " << e.what() << "\n"; + if (!b_valid_length) { + throw std::logic_error( + "Error: invalid length of transcript hasher buffer"); } if (!b_valid_length) { printf( From b6cb38e209f9fa3091ea77bd8a2030202be3bf33 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 18 Aug 2022 09:44:34 +0100 Subject: [PATCH 05/25] plonk: removed computation of the challenge u at the end of the prover process since u is not used by the prover anyway. removed the automatic clearing of the hasher buffer inside get_hash. the caller is now responsible to clear the buffer when reusing the same hasher object. see also PR comment https://github.com/clearmatics/libsnark/pull/61#discussion_r948822968 . --- libsnark/zk_proof_systems/plonk/prover.tcc | 13 --------- libsnark/zk_proof_systems/plonk/srs.tcc | 1 - .../plonk/tests/test_plonk.cpp | 28 ++++++++++++++++++- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index a9c3640e6..4b1596113 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -1104,19 +1104,6 @@ plonk_proof plonk_prover::compute_proof( srs, hasher); - // TODO: activate this part when we implement actual hashing of - // communication transcripts -#if 0 - // u: multipoint evaluation challenge -- hash of transcript from - // rounds 1,2,3,4,5 - const libff::Fr u = hasher.get_hash(); -#else - // do the hash anyway in order to keep the correct count of the - // hasher istep member (which resets to 0 only after the last hash - // is performed which is hash of u) - hasher.get_hash(); -#endif - // construct proof plonk_proof proof( round_one_out.W_polys_blinded_at_secret_g1, diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index ff3ba75f5..415f364a8 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -254,7 +254,6 @@ template libff::Fr transcript_hasher::get_hash() __FILE__, __LINE__, (int)buffer_len); - this->buffer.clear(); challenge = this->hash_values[5]; // u } diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index e6329831c..18cb18d36 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -54,6 +54,7 @@ void test_verify_invalid_proof( for (size_t i = 0; i < valid_proof.W_polys_blinded_at_secret_g1.size(); ++i) { // re-initialize the manipulated proof + hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_polys_blinded_at_secret_g1[i] = @@ -62,6 +63,7 @@ void test_verify_invalid_proof( ASSERT_FALSE(b_accept); } // manipulate [z]_1 + hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.z_poly_at_secret_g1 = proof.z_poly_at_secret_g1 + G1_noise; @@ -70,6 +72,7 @@ void test_verify_invalid_proof( // manipulate [t_lo]_1, [t_mi]_1, [t_hi]_1 for (size_t i = 0; i < valid_proof.t_poly_at_secret_g1.size(); ++i) { // re-initialize the manipulated proof + hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.t_poly_at_secret_g1[i] = proof.t_poly_at_secret_g1[i] + G1_noise; @@ -77,54 +80,63 @@ void test_verify_invalid_proof( ASSERT_FALSE(b_accept); } // manipulate \bar{a} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.a_zeta = proof.a_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{b} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.b_zeta = proof.b_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{c} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.c_zeta = proof.c_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma1} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_0_zeta = proof.S_0_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma2} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_1_zeta = proof.S_1_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{z_w} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.z_poly_xomega_zeta = proof.z_poly_xomega_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate [W_zeta]_1 + hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_at_secret = proof.W_zeta_at_secret + G1_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate [W_{zeta omega_roots}]_1 + hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_omega_at_secret = proof.W_zeta_omega_at_secret + G1_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate r_zeta + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.r_zeta = proof.r_zeta + Fr_noise; @@ -967,12 +979,18 @@ template void test_plonk_verifier_steps() plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); + // clear the hasher buffer in order to re-use the same transcript_hasher + // object for the verifier + hasher.buffer_clear(); + // Unit test verifier preprocessed input test_plonk_verifier_preprocessed_input(example, srs); - // unit test verifier step 5 + // compute step 4 const step_four_out_t step_four_out = plonk_verifier::step_four(proof, hasher); + + // unit test verifier step 5 test_plonk_verifier_step_five(example, step_four_out, srs); // unit test verifier step 6 @@ -1066,11 +1084,19 @@ template void test_plonk_verifier() plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); + // clear the hasher buffer in order to re-use the same transcript_hasher + // object for the verifier + hasher.buffer_clear(); + // initialize verifier plonk_verifier verifier; // verify proof bool b_valid_proof = verifier.verify_proof(proof, srs, hasher); ASSERT_TRUE(b_valid_proof); + + // clear the hasher buffer in order to re-use the same transcript_hasher + // object + hasher.buffer_clear(); // assert that proof verification fails when the proof is // manipulated test_verify_invalid_proof(proof, srs, hasher); From 7a9483a5ac3a7aeda9ac5e0f975b89c799c3fb84 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 18 Aug 2022 10:01:50 +0100 Subject: [PATCH 06/25] plonk: use std::count to check if the hasher buffer is of valid length instead of explicitly checking all valid lengths. --- libsnark/zk_proof_systems/plonk/srs.tcc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 415f364a8..2648a9a40 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -187,9 +187,7 @@ template libff::Fr transcript_hasher::get_hash() // If we are here, then the hasher buffer has invalid length so throw an // exception bool b_valid_length = - ((buffer_len == length[0]) || (buffer_len == length[1]) || - (buffer_len == length[2]) || (buffer_len == length[3]) || - (buffer_len == length[4]) || (buffer_len == length[5])); + (0 != std::count(length.begin(), length.end(), buffer_len)); if (!b_valid_length) { throw std::logic_error( "Error: invalid length of transcript hasher buffer"); From 91e7bb2097262786ff1c5bc49378511f9c617239 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 19 Aug 2022 11:41:54 +0100 Subject: [PATCH 07/25] plonk: removed doc comments /// from cpp and tcc files. left only in headers. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r949757635 --- libsnark/zk_proof_systems/plonk/circuit.tcc | 6 +- libsnark/zk_proof_systems/plonk/prover.tcc | 422 ++++++++-------- libsnark/zk_proof_systems/plonk/srs.tcc | 52 +- .../zk_proof_systems/plonk/tests/example.tcc | 4 +- libsnark/zk_proof_systems/plonk/utils.tcc | 172 ++++--- libsnark/zk_proof_systems/plonk/verifier.tcc | 468 +++++++++--------- 6 files changed, 580 insertions(+), 544 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index bae016eff..06a14e3fb 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -9,8 +9,8 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_TCC_ -/// Implementation of Common Preprocessed Input interfaces for a -/// ppzkSNARK for Plonk. See circuit.hpp . +// Implementation of Common Preprocessed Input interfaces for a +// ppzkSNARK for Plonk. See circuit.hpp . namespace libsnark { @@ -18,7 +18,7 @@ namespace libsnark // TODO: add here function for describing the target circuit through // the circuit_t structure -/// stuct constructor +// stuct constructor template circuit_t::circuit_t( size_t num_gates, diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 4b1596113..5d79429e3 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -9,13 +9,13 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_TCC_ -/// Implementation of Prover interfaces for a ppzkSNARK for Plonk. See -/// prover.hpp . +// Implementation of Prover interfaces for a ppzkSNARK for Plonk. See +// prover.hpp . namespace libsnark { -/// Prover round 0 output constructor +// Prover round 0 output constructor template round_zero_out_t::round_zero_out_t( const std::vector> &&zh_poly, @@ -25,18 +25,18 @@ round_zero_out_t::round_zero_out_t( { } -/// Prover Round 0 initialization -/// -/// Initialization -/// -/// INPUT -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] zh_poly: vanishing polynomial -/// \param[out] null_poly: 0 polynomial -/// \param[out] neg_one_poly: -1 polynomial +// Prover Round 0 initialization +// +// Initialization +// +// INPUT +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] zh_poly: vanishing polynomial +// \param[out] null_poly: 0 polynomial +// \param[out] neg_one_poly: -1 polynomial template round_zero_out_t plonk_prover::round_zero(const srs &srs) { @@ -62,7 +62,7 @@ round_zero_out_t plonk_prover::round_zero(const srs &srs) return round_zero_out; } -/// Prover round 1 output constructor +// Prover round 1 output constructor template round_one_out_t::round_one_out_t( const std::vector>> &&W_polys, @@ -74,28 +74,28 @@ round_one_out_t::round_one_out_t( { } -/// Prover Round 1 -/// -/// INPUT -/// \param[in] zh_poly: vanishing polynomial Zh (from round 0) -/// \param[in] null_poly: 0 polynomial (from round 0) -/// \param[in] neg_one_poly: -1 polynomial (from round 0) -/// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only -/// b1-b6 used in round 1) -/// \param[in] witness: witness values -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] W_polys: witness polynomials (Lagrange interpolation -/// of the witness values) -/// \param[out] W_polys_blinded: blinded witness polynomials -/// \param[out] W_polys_blinded_at_secret_g1: the blinded witness -/// polynomials evaluated at the secret input denoted -/// [a]_1, [b]_1, [c]_1 in [GWC19] -/// \param[out] transcript_hasher: accumulates the communication -/// transcript into a buffer to be hashed after prover -/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). +// Prover Round 1 +// +// INPUT +// \param[in] zh_poly: vanishing polynomial Zh (from round 0) +// \param[in] null_poly: 0 polynomial (from round 0) +// \param[in] neg_one_poly: -1 polynomial (from round 0) +// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only +// b1-b6 used in round 1) +// \param[in] witness: witness values +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] W_polys: witness polynomials (Lagrange interpolation +// of the witness values) +// \param[out] W_polys_blinded: blinded witness polynomials +// \param[out] W_polys_blinded_at_secret_g1: the blinded witness +// polynomials evaluated at the secret input denoted +// [a]_1, [b]_1, [c]_1 in [GWC19] +// \param[out] transcript_hasher: accumulates the communication +// transcript into a buffer to be hashed after prover +// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_one_out_t plonk_prover::round_one( const round_zero_out_t &round_zero_out, @@ -157,7 +157,7 @@ round_one_out_t plonk_prover::round_one( return round_one_out; } -/// Prover round 2 output +// Prover round 2 output template round_two_out_t::round_two_out_t( polynomial> &&z_poly, libff::G1 &&z_poly_at_secret_g1) @@ -165,23 +165,23 @@ round_two_out_t::round_two_out_t( { } -/// Prover Round 2 -/// -/// INPUT -/// \param[in] zh_poly: vanishing polynomial Zh (from round 0) -/// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only -/// b7,b8,b9 used in round 2) -/// \param[in] witness: witness values -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] z_poly: blinded accumulator poly z(x) -/// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) -/// evaluated at secret -/// \param[out] transcript_hasher: accumulates the communication -/// transcript into a buffer to be hashed after prover -/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). +// Prover Round 2 +// +// INPUT +// \param[in] zh_poly: vanishing polynomial Zh (from round 0) +// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only +// b7,b8,b9 used in round 2) +// \param[in] witness: witness values +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] z_poly: blinded accumulator poly z(x) +// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) +// evaluated at secret +// \param[out] transcript_hasher: accumulates the communication +// transcript into a buffer to be hashed after prover +// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_two_out_t plonk_prover::round_two( const libff::Fr &beta, @@ -227,7 +227,7 @@ round_two_out_t plonk_prover::round_two( return round_two_out; } -/// Prover round 3 output constructor +// Prover round 3 output constructor template round_three_out_t::round_three_out_t( std::vector> &&z_poly_xomega, @@ -241,30 +241,30 @@ round_three_out_t::round_three_out_t( { } -/// Prover Round 3 -/// -/// INPUT -/// \param[in] zh_poly: vanishing polynomial Zh (from Round 0) -/// \param[in] W_polys_blinded: blinded witness polynomials (from -/// Round 1) -/// \param[in] beta, gamma: permutation challenges -- hashes of -/// transcript (from round 2) -/// \param[in] z_poly: blinded accumulator poly z(x) (from Round 2) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] t_poly_long: the quotient polynomial t(x) (see Round -/// 3, pp28 [GWC19]) -/// \param[out] t_poly: t(x) divided in three parts t(x) = t_lo(x) + -/// t_mid(x) x^n + t_hi(x) x^{2n} -/// \param[out] t_poly_at_secret_g1: t(x) evaluated at the secret -/// input zeta i.e. t(zeta) -/// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted -/// by w -/// \param[out] transcript_hasher: accumulates the communication -/// transcript into a buffer to be hashed after prover -/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). +// Prover Round 3 +// +// INPUT +// \param[in] zh_poly: vanishing polynomial Zh (from Round 0) +// \param[in] W_polys_blinded: blinded witness polynomials (from +// Round 1) +// \param[in] beta, gamma: permutation challenges -- hashes of +// transcript (from round 2) +// \param[in] z_poly: blinded accumulator poly z(x) (from Round 2) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] t_poly_long: the quotient polynomial t(x) (see Round +// 3, pp28 [GWC19]) +// \param[out] t_poly: t(x) divided in three parts t(x) = t_lo(x) + +// t_mid(x) x^n + t_hi(x) x^{2n} +// \param[out] t_poly_at_secret_g1: t(x) evaluated at the secret +// input zeta i.e. t(zeta) +// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted +// by w +// \param[out] transcript_hasher: accumulates the communication +// transcript into a buffer to be hashed after prover +// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_three_out_t plonk_prover::round_three( const libff::Fr &alpha, @@ -496,7 +496,7 @@ round_three_out_t plonk_prover::round_three( return round_three_out; } -/// Prover round 4 output constructor +// Prover round 4 output constructor template round_four_out_t::round_four_out_t( libff::Fr &&a_zeta, @@ -516,40 +516,40 @@ round_four_out_t::round_four_out_t( { } -/// Prover Round 4 -/// -/// INPUT -/// \param[in] W_polys_blinded: blinded witness polynomials (from -/// Round 1) -/// \param[in] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted -/// by w (from Round 3) -/// \param[in] t_poly_long: the quotient polynomial t(x) (see Round 3, -/// pp28 [GWC19]) (from Round 3) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] a_zeta, b_zeta, c_zeta: the blinded witness -/// polynomials a(x), b(x), c(x) (denoted by -/// W_polys_blinded[] output from Round 1) evaluated at -/// x=zeta i.e. a(z), b(z), c(z) -/// \param[out] S_0_zeta, S_1_zeta: the permutation polynomials -/// S_sigma_1(x), S_sigma_2(x) from the common -/// preprocessed input (see [GWC19], Sect. 8.1) evaluated -/// at x=zeta i.e. S_sigma_1(z), S_sigma_2(z) -/// \param[out] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) -/// shifted by w (output from Round 3) evaluated at x=zeta -/// i.e. z(zeta*w) -/// \param[out] t_zeta: the quotient polynomial t(x) output from Round -/// 3, see pp28 [GWC19]) evaluated at x=zeta -/// i.e. t(z). IMPORTANT! the original Plonk proposal -/// [GWC19] does not output this parameter t_zeta. The -/// Python reference implementation \[PlonkPy] does, so we -/// do the same in order to match the test vectors. TODO -/// can remove t_zeta in the future -/// \param[out] transcript_hasher: accumulates the communication -/// transcript into a buffer to be hashed after prover -/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). +// Prover Round 4 +// +// INPUT +// \param[in] W_polys_blinded: blinded witness polynomials (from +// Round 1) +// \param[in] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted +// by w (from Round 3) +// \param[in] t_poly_long: the quotient polynomial t(x) (see Round 3, +// pp28 [GWC19]) (from Round 3) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] a_zeta, b_zeta, c_zeta: the blinded witness +// polynomials a(x), b(x), c(x) (denoted by +// W_polys_blinded[] output from Round 1) evaluated at +// x=zeta i.e. a(z), b(z), c(z) +// \param[out] S_0_zeta, S_1_zeta: the permutation polynomials +// S_sigma_1(x), S_sigma_2(x) from the common +// preprocessed input (see [GWC19], Sect. 8.1) evaluated +// at x=zeta i.e. S_sigma_1(z), S_sigma_2(z) +// \param[out] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) +// shifted by w (output from Round 3) evaluated at x=zeta +// i.e. z(zeta*w) +// \param[out] t_zeta: the quotient polynomial t(x) output from Round +// 3, see pp28 [GWC19]) evaluated at x=zeta +// i.e. t(z). IMPORTANT! the original Plonk proposal +// [GWC19] does not output this parameter t_zeta. The +// Python reference implementation \[PlonkPy] does, so we +// do the same in order to match the test vectors. TODO +// can remove t_zeta in the future +// \param[out] transcript_hasher: accumulates the communication +// transcript into a buffer to be hashed after prover +// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_four_out_t plonk_prover::round_four( const libff::Fr &zeta, @@ -606,7 +606,7 @@ round_four_out_t plonk_prover::round_four( return round_four_out; } -/// Prover round 5 output constructor +// Prover round 5 output constructor template round_five_out_t::round_five_out_t( libff::Fr &&r_zeta, @@ -618,53 +618,53 @@ round_five_out_t::round_five_out_t( { } -/// Prover Round 5 -/// -/// INPUT -/// \param[in] beta, gamma: permutation challenges -- hashes of -/// transcript (from round 2) -/// \param[in] alpha: quotinet challenge -- hash of transcript (from -/// round 3) -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// round 4) -/// \param[in] a_zeta, b_zeta, c_zeta: the blinded witness polynomials -/// a(x), b(x), c(x) (denoted by W_polys_blinded[] output -/// from Round 1) evaluated at x=zeta i.e. a(z), b(z), c(z) -/// (from round 4) -/// \param[in] S_0_zeta, S_1_zeta: the permutation polynomials -/// S_sigma_1(x), S_sigma_2(x) from the common preprocessed -/// input (see [GWC19], Sect. 8.1) evaluated at x=zeta -/// i.e. S_sigma_1(z), S_sigma_2(z) (from round 4) -/// \param[in] t_zeta: the quotient polynomial t(x) output from Round -/// 3, see pp28 [GWC19]) evaluated at x=zeta -/// i.e. t(z). IMPORTANT! the original Plonk proposal -/// [GWC19] does not output this parameter t_zeta. The -/// Python reference implementation \[PlonkPy] does, so we -/// do the same in order to match the test vectors. TODO -/// can remove t_zeta in the future (from round 4) -/// \param[in] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) -/// shifted by w (output from Round 3) evaluated at x=zeta -/// i.e. z(zeta*w) (from round 4) -/// \param[in] W_polys_blinded: blinded witness polynomials (from -/// round 1) -/// \param[in] t_poly: t(x) divided in three parts t(x) = t_lo(x) + -/// t_mid(x) x^n + t_hi(x) x^{2n} (from round 3) -/// \param[in] z_poly: blinded accumulator poly z(x) (from round 2) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] r_zeta: linearisation polynomial r(x) evaluated at -/// x=zeta ie. r(zeta) -/// \param[out] W_zeta_at_secret: commitment to opening proof -/// polynomial W_zeta(x) at secert input -/// i.e. [W_zeta(secret)]_1 -/// \param[out] W_zeta_omega_at_secret: commitment to opening proof -/// polynomial W_{zeta omega}(x) at secert input -/// i.e. [W_{zeta omega}(secret)]_1 -/// \param[out] transcript_hasher: accumulates the communication -/// transcript into a buffer to be hashed after prover -/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). +// Prover Round 5 +// +// INPUT +// \param[in] beta, gamma: permutation challenges -- hashes of +// transcript (from round 2) +// \param[in] alpha: quotinet challenge -- hash of transcript (from +// round 3) +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// round 4) +// \param[in] a_zeta, b_zeta, c_zeta: the blinded witness polynomials +// a(x), b(x), c(x) (denoted by W_polys_blinded[] output +// from Round 1) evaluated at x=zeta i.e. a(z), b(z), c(z) +// (from round 4) +// \param[in] S_0_zeta, S_1_zeta: the permutation polynomials +// S_sigma_1(x), S_sigma_2(x) from the common preprocessed +// input (see [GWC19], Sect. 8.1) evaluated at x=zeta +// i.e. S_sigma_1(z), S_sigma_2(z) (from round 4) +// \param[in] t_zeta: the quotient polynomial t(x) output from Round +// 3, see pp28 [GWC19]) evaluated at x=zeta +// i.e. t(z). IMPORTANT! the original Plonk proposal +// [GWC19] does not output this parameter t_zeta. The +// Python reference implementation \[PlonkPy] does, so we +// do the same in order to match the test vectors. TODO +// can remove t_zeta in the future (from round 4) +// \param[in] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) +// shifted by w (output from Round 3) evaluated at x=zeta +// i.e. z(zeta*w) (from round 4) +// \param[in] W_polys_blinded: blinded witness polynomials (from +// round 1) +// \param[in] t_poly: t(x) divided in three parts t(x) = t_lo(x) + +// t_mid(x) x^n + t_hi(x) x^{2n} (from round 3) +// \param[in] z_poly: blinded accumulator poly z(x) (from round 2) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] r_zeta: linearisation polynomial r(x) evaluated at +// x=zeta ie. r(zeta) +// \param[out] W_zeta_at_secret: commitment to opening proof +// polynomial W_zeta(x) at secert input +// i.e. [W_zeta(secret)]_1 +// \param[out] W_zeta_omega_at_secret: commitment to opening proof +// polynomial W_{zeta omega}(x) at secert input +// i.e. [W_{zeta omega}(secret)]_1 +// \param[out] transcript_hasher: accumulates the communication +// transcript into a buffer to be hashed after prover +// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_five_out_t plonk_prover::round_five( const libff::Fr &alpha, @@ -993,51 +993,51 @@ plonk_proof::plonk_proof( { } -/// Prover compute SNARK proof -/// -/// Pi ([a]_1, [b]_1, [c]_1, [z]_1, -/// [t_lo]_1, [t_mi]_1, [t_hi]_1, -/// \bar{a}, \bar{b}, \bar{c}, -/// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, -/// [W_zeta]_1, [W_{zeta omega}]_1 -/// r_zeta) -/// -/// \note in the reference Python implementation \[PlonkPy], r_zeta -/// (the evaluation of the linearlization polynomial r(X) at zeta from -/// Prover round 5) is added to the pi-SNARK proof. In the paper this -/// is omitted, which seems to make the proof shorter by 1 element at -/// the epxense of a slightly heavier computation on the verifier's -/// side. Here we follow the reference implementation \[PlonkPy] to -/// make sure we match the test values. TODO: once all test vectors -/// are verified, we may remove r_zeta from the proof to be fully -/// compliant with the paper. -/// -/// Mapping code-to-paper quantities -/// -/// \param W_polys_blinded_at_secret_g1[a, b, c]: [a]_1, [b]_1, [c]_1 -/// (from Round 1) -/// \param z_poly_at_secret_g1: [z]_1 (from Round 2) -/// \param t_poly_at_secret_g1[lo, mi, hi]: [t_lo]_1, [t_mi]_1, -/// [t_hi]_1 (from Round 3) -/// \param a_zeta, b_zeta, c_zeta, S_0_zeta, S_1_zeta, -/// z_poly_xomega_zeta: \bar{a}, \bar{b}, \bar{c}, -/// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w} (from Round 4) -/// \param W_zeta_at_secret, W_zeta_omega_at_secret: [W_zeta]_1, -/// [W_{zeta omega}]_1 (from Round 5) -/// -/// INPUT -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// \param[in] witness: all internal values and public input -/// corresponding to the given circuit -/// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 -/// used in prover rounds 1 and 2 (see Sect. 8.3, roumds -/// 1,2 [GWC19]) -/// \param[in] transcript_hasher: hashes of the communication -/// transcript after prover rounds 1,2,3,4,5. -/// -/// OUTPUT -/// \param[out] proof: SNARK proof Pi (see above) +// Prover compute SNARK proof +// +// Pi ([a]_1, [b]_1, [c]_1, [z]_1, +// [t_lo]_1, [t_mi]_1, [t_hi]_1, +// \bar{a}, \bar{b}, \bar{c}, +// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, +// [W_zeta]_1, [W_{zeta omega}]_1 +// r_zeta) +// +// \note in the reference Python implementation \[PlonkPy], r_zeta +// (the evaluation of the linearlization polynomial r(X) at zeta from +// Prover round 5) is added to the pi-SNARK proof. In the paper this +// is omitted, which seems to make the proof shorter by 1 element at +// the epxense of a slightly heavier computation on the verifier's +// side. Here we follow the reference implementation \[PlonkPy] to +// make sure we match the test values. TODO: once all test vectors +// are verified, we may remove r_zeta from the proof to be fully +// compliant with the paper. +// +// Mapping code-to-paper quantities +// +// \param W_polys_blinded_at_secret_g1[a, b, c]: [a]_1, [b]_1, [c]_1 +// (from Round 1) +// \param z_poly_at_secret_g1: [z]_1 (from Round 2) +// \param t_poly_at_secret_g1[lo, mi, hi]: [t_lo]_1, [t_mi]_1, +// [t_hi]_1 (from Round 3) +// \param a_zeta, b_zeta, c_zeta, S_0_zeta, S_1_zeta, +// z_poly_xomega_zeta: \bar{a}, \bar{b}, \bar{c}, +// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w} (from Round 4) +// \param W_zeta_at_secret, W_zeta_omega_at_secret: [W_zeta]_1, +// [W_{zeta omega}]_1 (from Round 5) +// +// INPUT +// \param[in] srs: structured reference string containing also +// circuit-specific information +// \param[in] witness: all internal values and public input +// corresponding to the given circuit +// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 +// used in prover rounds 1 and 2 (see Sect. 8.3, roumds +// 1,2 [GWC19]) +// \param[in] transcript_hasher: hashes of the communication +// transcript after prover rounds 1,2,3,4,5. +// +// OUTPUT +// \param[out] proof: SNARK proof Pi (see above) template plonk_proof plonk_prover::compute_proof( const srs &srs, @@ -1087,8 +1087,8 @@ plonk_proof plonk_prover::compute_proof( zeta, round_one_out, round_three_out, srs, hasher); printf("[%s:%d] Prover Round 5...\n", __FILE__, __LINE__); - /// - nu: opening challenge -- hash of transcript (denoted by v in - /// [GWC19]) + // - nu: opening challenge -- hash of transcript (denoted by v in + // [GWC19]) const libff::Fr nu = hasher.get_hash(); round_five_out_t round_five_out = plonk_prover::round_five( alpha, diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 2648a9a40..d52488575 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -9,8 +9,8 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_TCC_ -/// Implementation of SRS interfaces for a ppzkSNARK for Plonk. See -/// srs.hpp . +// Implementation of SRS interfaces for a ppzkSNARK for Plonk. See +// srs.hpp . namespace libsnark { @@ -58,13 +58,13 @@ srs::srs( { } -/// class plonk_verification_key +// class plonk_verification_key template plonk_verification_key::plonk_verification_key( std::vector> &&secret_powers_g2) : secret_powers_g2(std::move(secret_powers_g2)){}; -/// class plonk_keypair constructor +// class plonk_keypair constructor template plonk_keypair::plonk_keypair( plonk_proving_key &&pk, plonk_verification_key &&vk) @@ -72,7 +72,7 @@ plonk_keypair::plonk_keypair( { } -/// transcript_hasher constructor +// transcript_hasher constructor template transcript_hasher::transcript_hasher(std::vector &buffer) : buffer(std::move(buffer)) @@ -98,19 +98,19 @@ transcript_hasher::transcript_hasher(std::vector &buffer) }; } -/// clear the buffer (for now only for testing) +// clear the buffer (for now only for testing) template void transcript_hasher::buffer_clear() { this->buffer.clear(); } -/// get buffer size +// get buffer size template size_t transcript_hasher::buffer_size() { return this->buffer.size(); } -/// add an Fr element to the transcript buffer for hashing +// add an Fr element to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::Fr &element) { @@ -127,7 +127,7 @@ void transcript_hasher::add_element(const libff::Fr &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -/// add the coordinates of a G1 curve point to the transcript buffer for hashing +// add the coordinates of a G1 curve point to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::G1 &element) { @@ -149,7 +149,7 @@ void transcript_hasher::add_element(const libff::G1 &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -/// add the coordinates of a G2 curve point to the transcript buffer for hashing +// add the coordinates of a G2 curve point to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::G2 &element) { @@ -171,10 +171,10 @@ void transcript_hasher::add_element(const libff::G2 &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -/// dummy implementation of get_hash that directly returns the -/// expected hard-coded hashes for the purposes of unit testing TODO -/// to be replaced by a call to a proper hash function e.g. SHA2, -/// BLAKE, etc. +// dummy implementation of get_hash that directly returns the +// expected hard-coded hashes for the purposes of unit testing TODO +// to be replaced by a call to a proper hash function e.g. SHA2, +// BLAKE, etc. template libff::Fr transcript_hasher::get_hash() { size_t buffer_len = this->buffer.size(); @@ -258,11 +258,11 @@ template libff::Fr transcript_hasher::get_hash() return challenge; } -/// Compute a universal srs (usrs). It is composed *only* of encoded -/// powers of the secret value in the group generator. Therefore a usrs -/// is independent of any particular circuit. -/// -/// \note only for debug +// Compute a universal srs (usrs). It is composed *only* of encoded +// powers of the secret value in the group generator. Therefore a usrs +// is independent of any particular circuit. +// +// \note only for debug template usrs plonk_usrs_derive_from_secret( const libff::Fr &secret, const size_t max_degree) @@ -301,13 +301,13 @@ usrs plonk_usrs_derive_from_secret( return usrs(std::move(secret_powers_g1), std::move(secret_powers_g2)); } -/// Derive the (plain) SRS from the circuit description and the -/// USRS. The (plain) SRS is a specialization of the USRS for one -/// particular circuit i.e. -/// -/// usrs = -/// srs = (proving_key, verificataion_key) = derive(usrs, -/// circuit_description) +// Derive the (plain) SRS from the circuit description and the +// USRS. The (plain) SRS is a specialization of the USRS for one +// particular circuit i.e. +// +// usrs = +// srs = (proving_key, verificataion_key) = derive(usrs, +// circuit_description) template srs plonk_srs_derive_from_usrs( const usrs &usrs, const circuit_t &circuit) diff --git a/libsnark/zk_proof_systems/plonk/tests/example.tcc b/libsnark/zk_proof_systems/plonk/tests/example.tcc index 4ca63ce0a..81032512e 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.tcc +++ b/libsnark/zk_proof_systems/plonk/tests/example.tcc @@ -8,8 +8,8 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_TCC_ -/// Instantiation of the test vector values from the Python implementation -/// of the Plonk protocol. \see example.hpp . +// Instantiation of the test vector values from the Python implementation +// of the Plonk protocol. \see example.hpp . namespace libsnark { diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 13482419a..2cb62ae60 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -9,13 +9,13 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ -/// Implementation of interfaces for a ppzkSNARK for Plonk. See -/// utils.hpp . +// Implementation of interfaces for a ppzkSNARK for Plonk. See +// utils.hpp . namespace libsnark { -/// print the elements of a vector +// print the elements of a vector template void print_vector(const std::vector &v) { for (size_t i = 0; i < v.size(); ++i) { @@ -24,25 +24,61 @@ template void print_vector(const std::vector &v) } } -/// Interpolate a polynomial from a set of points through inverse FFT -/// -/// INPUT: -/// -/// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), -/// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], -/// ... which we want to interpolate as a polynomial -/// -/// OUTPUT: -/// -/// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., a_{n-1}] -/// of the polynomial f(x) interpolating the set of points -/// f_points. For example if f_poly[0..n-1] = [a0, a1, ..., -/// a_{n-1}] then this represents the polynomial f(x) = -/// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that -/// f(omega_i)=f_points[i], where omega_0, ..., omega_{n-1} -/// are the n roots of unity. -/// -/// \note uses libfqfft iFFT for the interpolation +// Compute the Lagrange basis polynomials for interpolating sets of +// n points +// +// INPUT: +// +// \param[in] npoints - number of points +// +// OUTPUT: +// +// \param[out] L[0..n-1][0..n-1]: Lagrange basis over the n roots of +// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, +// a1, ..., a_{n-1}] is a vector representing the +// coefficients of the i-th Lagrange polynomial L_i(x) = +// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 +// and L_i(x\neq{omega_i)})=0 +// +// \note uses libfqfft iFFT for the interpolation +template +void plonk_compute_lagrange_basis( + const size_t npoints, std::vector> &L) +{ + assert(L.size() != 0); + assert(L.size() == L[0].size()); + assert(L.size() == npoints); + + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(npoints); + for (size_t i = 0; i < npoints; ++i) { + polynomial u(npoints, FieldT(0)); + u[i] = FieldT(1); + // compute i-th Lagrange basis vector via inverse FFT + domain->iFFT(u); + L[i] = u; + } +} + +// Interpolate a polynomial from a set of points through inverse FFT +// +// INPUT: +// +// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), +// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], +// ... which we want to interpolate as a polynomial +// +// OUTPUT: +// +// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., a_{n-1}] +// of the polynomial f(x) interpolating the set of points +// f_points. For example if f_poly[0..n-1] = [a0, a1, ..., +// a_{n-1}] then this represents the polynomial f(x) = +// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that +// f(omega_i)=f_points[i], where omega_0, ..., omega_{n-1} +// are the n roots of unity. +// +// \note uses libfqfft iFFT for the interpolation template void plonk_interpolate_polynomial_from_points( const std::vector &f_points, polynomial &f_poly) @@ -54,11 +90,11 @@ void plonk_interpolate_polynomial_from_points( domain->iFFT(f_poly); } -/// Compute the selector polynomials of the given circuit (also -/// called here "q-polynomials"). See Sect. 8.1. The matrix -/// gates_matrix_transpose has 5 rows, each corresponding to the -/// values L, R, M, O and C for each gate; the number of columns is -/// equal to the number of gates. L_basis is the Lagrange basis. +// Compute the selector polynomials of the given circuit (also +// called here "q-polynomials"). See Sect. 8.1. The matrix +// gates_matrix_transpose has 5 rows, each corresponding to the +// values L, R, M, O and C for each gate; the number of columns is +// equal to the number of gates. L_basis is the Lagrange basis. template std::vector> plonk_compute_selector_polynomials( const size_t &num_gates, @@ -84,12 +120,12 @@ void plonk_compute_public_input_polynomial( plonk_interpolate_polynomial_from_points(PI_points, PI_poly); }; -/// This function computes the sets H, k1H, k2H. H is a -/// multiplicative subgroup containing the n-th roots of unity in Fr, -/// where \omega is a primitive n-th root of unity and a generator of -/// H i.e H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen -/// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus -/// consist of 3n distinct elements. \see [GWC19] pp26 (top). +// This function computes the sets H, k1H, k2H. H is a +// multiplicative subgroup containing the n-th roots of unity in Fr, +// where \omega is a primitive n-th root of unity and a generator of +// H i.e H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen +// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus +// consist of 3n distinct elements. \see [GWC19] pp26 (top). template void plonk_compute_roots_of_unity_omega( const size_t num_gates, @@ -126,14 +162,14 @@ void plonk_compute_roots_of_unity_omega( } } -/// This function computes the sets H, k1H, k2H, where H is a -/// multiplicative subgroup containing the n-th roots of unity in Fr and -/// \omega is a primitive n-th root of unity and a generator of -/// H ie. H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen -/// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus -/// consist of 3n distinct elements. \see [GWC19] pp26 (top) and Sect. 8. -/// -/// \note uses plonk_compute_roots_of_unity_omega +// This function computes the sets H, k1H, k2H, where H is a +// multiplicative subgroup containing the n-th roots of unity in Fr and +// \omega is a primitive n-th root of unity and a generator of +// H ie. H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen +// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus +// consist of 3n distinct elements. \see [GWC19] pp26 (top) and Sect. 8. +// +// \note uses plonk_compute_roots_of_unity_omega template void plonk_compute_cosets_H_k1H_k2H( const size_t num_gates, @@ -161,10 +197,10 @@ void plonk_compute_cosets_H_k1H_k2H( omega[base_k2].begin(), omega[base_k2].end(), back_inserter(H_gen)); } -/// permute the multiplicative subgroup H according to the wire -/// permutation: (see [GWC19] Sect. 8), \see -/// plonk_compute_roots_of_unity_omega, \see -/// plonk_roots_of_unity_omega_to_subgroup_H +// permute the multiplicative subgroup H according to the wire +// permutation: (see [GWC19] Sect. 8), \see +// plonk_compute_roots_of_unity_omega, \see +// plonk_roots_of_unity_omega_to_subgroup_H template std::vector plonk_permute_subgroup_H( const std::vector &H_gen, @@ -180,8 +216,8 @@ std::vector plonk_permute_subgroup_H( return H_gen_permute; } -/// compute the permutation polynomials S_sigma_1, S_sigma_2, -/// S_sigma_2 (see [GWC19], Sect. 8.1) +// compute the permutation polynomials S_sigma_1, S_sigma_2, +// S_sigma_2 (see [GWC19], Sect. 8.1) template std::vector> plonk_compute_permutation_polynomials( const std::vector &H_gen_permute, const size_t num_gates) @@ -222,21 +258,21 @@ libff::G1 plonk_multi_exp_G1( return product; } -/// Evaluate a polynomial F at the encoded secret input -/// \secret^i*G_1 ie. compute f(\secret)*G1 = [f(\secret)]_i -/// -/// INPUT -/// -/// \param[in] secret_powers_g1: \secret^i*G1: -/// 0\le{i} libff::G1 plonk_evaluate_poly_at_secret_G1( const std::vector> &secret_powers_g1, @@ -257,8 +293,8 @@ libff::G1 plonk_evaluate_poly_at_secret_G1( return f_poly_at_secret_g1; } -/// Evaluate a list of polynomials in the encrypted secret input: see -/// plonk_evaluate_poly_at_secret_G1 +// Evaluate a list of polynomials in the encrypted secret input: see +// plonk_evaluate_poly_at_secret_G1 template void plonk_evaluate_polys_at_secret_G1( const std::vector> &secret_powers_g1, @@ -275,10 +311,10 @@ void plonk_evaluate_polys_at_secret_G1( } } -/// Compute the factors in the product of the permutation polynomial -/// z(X) in Prover Round 2. Note that accumulator A[0]=1 and A[i], -/// i>0 is computed from values at i-1 for witness[i-1], H_gen[i-1], -/// H_gen_permute[i-1]m etc. +// Compute the factors in the product of the permutation polynomial +// z(X) in Prover Round 2. Note that accumulator A[0]=1 and A[i], +// i>0 is computed from values at i-1 for witness[i-1], H_gen[i-1], +// H_gen_permute[i-1]m etc. template FieldT plonk_compute_accumulator_factor( const size_t i, diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 5380fe5b3..c7cf4f650 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -9,13 +9,13 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_VERIFIER_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_VERIFIER_TCC_ -/// Implementation of Verifier interfaces for a ppzkSNARK for Plonk. See -/// verifier.hpp . +// Implementation of Verifier interfaces for a ppzkSNARK for Plonk. See +// verifier.hpp . namespace libsnark { -/// struct verifier_preprocessed_input_t constructor +// struct verifier_preprocessed_input_t constructor template verifier_preprocessed_input_t::verifier_preprocessed_input_t( std::vector> &&Q_polys_at_secret_g1, @@ -25,17 +25,17 @@ verifier_preprocessed_input_t::verifier_preprocessed_input_t( { } -/// Verifier precomputation -/// -/// INPUT -/// \param[in] srs: structured reference string -/// -/// OUTPUT -/// \param[out] Q_polys_at_secret_g1: circuit selector polynomials Q evaluated -/// at -/// the secret input -/// \param[out] S_polys_at_secret_g1: permutation polynomials S evaluated at the -/// secret input +// Verifier precomputation +// +// INPUT +// \param[in] srs: structured reference string +// +// OUTPUT +// \param[out] Q_polys_at_secret_g1: circuit selector polynomials Q evaluated +// at +// the secret input +// \param[out] S_polys_at_secret_g1: permutation polynomials S evaluated at the +// secret input template verifier_preprocessed_input_t plonk_verifier::preprocessed_input( const srs &srs) @@ -55,34 +55,34 @@ verifier_preprocessed_input_t plonk_verifier::preprocessed_input( return preprocessed_input; } -/// Verifier Step 1: validate that elements belong to group G1 -/// -/// \attention This validation MUST be done by the caller. Empty -/// function here for consistency with the description in [GWC19] +// Verifier Step 1: validate that elements belong to group G1 +// +// \attention This validation MUST be done by the caller. Empty +// function here for consistency with the description in [GWC19] template void plonk_verifier::step_one(const plonk_proof &proof) { } -/// Verifier Step 2: validate that elements belong to scalar field Fr -/// -/// \attention This validation MUST be done by the caller. Empty -/// function here for consistency with the description in [GWC19] +// Verifier Step 2: validate that elements belong to scalar field Fr +// +// \attention This validation MUST be done by the caller. Empty +// function here for consistency with the description in [GWC19] template void plonk_verifier::step_two(const plonk_proof &proof) { } -/// Verifier Step 3: validate that the public input belongs to scalar -/// field Fr -/// -/// \attention This validation MUST be done by the caller. Empty -/// function here for consistency with the description in [GWC19] +// Verifier Step 3: validate that the public input belongs to scalar +// field Fr +// +// \attention This validation MUST be done by the caller. Empty +// function here for consistency with the description in [GWC19] template void plonk_verifier::step_three(const srs &srs) { } -/// struct step_four_out_t constructor +// struct step_four_out_t constructor template step_four_out_t::step_four_out_t( libff::Fr &beta, @@ -95,24 +95,24 @@ step_four_out_t::step_four_out_t( { } -/// Verifier Step 4: compute challenges hashed transcript as in prover -/// description, from the common inputs, public input, and elements of -/// pi-SNARK. TODO: fixed to the test vectors for now -/// -/// INPUT -/// \param[in] proof: SNARK proof produced by the prover -/// \param[in] transcript_hasher: hashes of the communication -/// transcript after prover rounds 1,2,3,4,5. -/// -/// OUTPUT -/// \param[out] beta, gamma: permutation challenges - hashes of -/// transcript -/// \param[out] alpha: quotinet challenge - hash of transcript -/// \param[out] zeta: evaluation challenge - hash of transcript -/// \param[out] nu: opening challenge - hash of transcript (denoted by -/// v in [GWC19]) -/// \param[out] u: multipoint evaluation challenge - hash of -/// transcript +// Verifier Step 4: compute challenges hashed transcript as in prover +// description, from the common inputs, public input, and elements of +// pi-SNARK. TODO: fixed to the test vectors for now +// +// INPUT +// \param[in] proof: SNARK proof produced by the prover +// \param[in] transcript_hasher: hashes of the communication +// transcript after prover rounds 1,2,3,4,5. +// +// OUTPUT +// \param[out] beta, gamma: permutation challenges - hashes of +// transcript +// \param[out] alpha: quotinet challenge - hash of transcript +// \param[out] zeta: evaluation challenge - hash of transcript +// \param[out] nu: opening challenge - hash of transcript (denoted by +// v in [GWC19]) +// \param[out] u: multipoint evaluation challenge - hash of +// transcript template step_four_out_t plonk_verifier::step_four( const plonk_proof &proof, transcript_hasher &hasher) @@ -167,24 +167,24 @@ step_four_out_t plonk_verifier::step_four( return step_four_out; } -/// struct step_five_out_t constructor +// struct step_five_out_t constructor template step_five_out_t::step_five_out_t(libff::Fr &&zh_zeta) : zh_zeta(zh_zeta) { } -/// Verifier Step 5: compute zero polynomial evaluation -/// -/// INPUT -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] zh_zeta: evaluation of vanishing polynomial Zh at -/// x=zeta i.e. Zh(zeta) +// Verifier Step 5: compute zero polynomial evaluation +// +// INPUT +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] zh_zeta: evaluation of vanishing polynomial Zh at +// x=zeta i.e. Zh(zeta) template step_five_out_t plonk_verifier::step_five( const step_four_out_t &step_four_out, const srs &srs) @@ -197,25 +197,25 @@ step_five_out_t plonk_verifier::step_five( return step_five_out; } -/// struct step_six_out_t constructor +// struct step_six_out_t constructor template step_six_out_t::step_six_out_t(libff::Fr &&L_0_zeta) : L_0_zeta(L_0_zeta) { } -/// Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) -/// Note: the paper counts the L-polynomials from 1; we count from 0 -/// -/// INPUT -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] L_0_zeta: Lagrange polynomial evaluation of polynomial -/// L1 at x=zeta i.e. L1(zeta) +// Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) +// Note: the paper counts the L-polynomials from 1; we count from 0 +// +// INPUT +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] L_0_zeta: Lagrange polynomial evaluation of polynomial +// L1 at x=zeta i.e. L1(zeta) template step_six_out_t plonk_verifier::step_six( const step_four_out_t &step_four_out, const srs &srs) @@ -226,25 +226,25 @@ step_six_out_t plonk_verifier::step_six( return step_six_out; } -/// struct step_seven_out_t constructor +// struct step_seven_out_t constructor template step_seven_out_t::step_seven_out_t(libff::Fr &&PI_zeta) : PI_zeta(PI_zeta) { } -/// Verifier Step 7: compute public input polynomial evaluation -/// PI(zeta) -/// -/// INPUT -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] PI_zeta: public input polynomial PI evaluated at -/// x=zeta i.e. PI(zeta) +// Verifier Step 7: compute public input polynomial evaluation +// PI(zeta) +// +// INPUT +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] PI_zeta: public input polynomial PI evaluated at +// x=zeta i.e. PI(zeta) template step_seven_out_t plonk_verifier::step_seven( const step_four_out_t &step_four_out, const srs &srs) @@ -256,40 +256,40 @@ step_seven_out_t plonk_verifier::step_seven( return step_seven_out; } -/// struct step_eight_out_t constructor +// struct step_eight_out_t constructor template step_eight_out_t::step_eight_out_t(libff::Fr &&r_prime_zeta) : r_prime_zeta(r_prime_zeta) { } -/// Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = -/// r(zeta) - r0, where r0 is a constant term \note follows the Python -/// reference implementation, which slightly deviates from the paper -/// due to the presence of the r_zeta term in the proof (not present -/// in the paper). In particular, the reference code computes and -/// uses r'(zeta) in step 8, while the paper uses r0. In addition, the -/// reference code divides r'(zeta) by the vanishing polynomial at -/// zeta zh_zeta, while the paper does not do that (see also Step 9). -/// -/// INPUT -/// \param[in] beta, gamma: permutation challenges -- hashes of -/// transcript (from step 4) -/// \param[in] alpha: quotinet challenge -- hash of transcript (from -/// step 4) -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] zh_zeta: evaluation of vanishing polynomial Zh at -/// x=zeta i.e. Zh(zeta) (from step 5) -/// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial -/// L1 at x=zeta i.e. L1(zeta) (from step 6) -/// \param[in] PI_zeta: public input polynomial PI evaluated at x=zeta -/// i.e. PI(zeta) (from step 7) -/// \param[in] proof: SNARK proof produced by the prover -/// -/// OUTPUT -/// \param[out] r_prime_zeta: quotient polynomial evaluation r'(zeta) -/// = r(zeta) - r0, where r0 is a constant term +// Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = +// r(zeta) - r0, where r0 is a constant term \note follows the Python +// reference implementation, which slightly deviates from the paper +// due to the presence of the r_zeta term in the proof (not present +// in the paper). In particular, the reference code computes and +// uses r'(zeta) in step 8, while the paper uses r0. In addition, the +// reference code divides r'(zeta) by the vanishing polynomial at +// zeta zh_zeta, while the paper does not do that (see also Step 9). +// +// INPUT +// \param[in] beta, gamma: permutation challenges -- hashes of +// transcript (from step 4) +// \param[in] alpha: quotinet challenge -- hash of transcript (from +// step 4) +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] zh_zeta: evaluation of vanishing polynomial Zh at +// x=zeta i.e. Zh(zeta) (from step 5) +// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial +// L1 at x=zeta i.e. L1(zeta) (from step 6) +// \param[in] PI_zeta: public input polynomial PI evaluated at x=zeta +// i.e. PI(zeta) (from step 7) +// \param[in] proof: SNARK proof produced by the prover +// +// OUTPUT +// \param[out] r_prime_zeta: quotient polynomial evaluation r'(zeta) +// = r(zeta) - r0, where r0 is a constant term template step_eight_out_t plonk_verifier::step_eight( const step_four_out_t &step_four_out, @@ -322,47 +322,47 @@ step_eight_out_t plonk_verifier::step_eight( return step_eight_out; } -/// struct step_nine_out_t constructor +// struct step_nine_out_t constructor template step_nine_out_t::step_nine_out_t(libff::G1 &&D1) : D1(D1) { } -/// Verifier Step 9: compute first part of batched polynomial -/// commitment [D]_1 Note: the reference implemention differs from the -/// paper -- it does not add the following term to D1, but to F1 (Step -/// 10): -Zh(zeta)([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n -/// [t_hi]_1). Instead ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n -/// [t_hi]_1) is added to F1 in Step 10 and the multiplication by -/// Zh(zeta) is accounted for by dividing by Zh(zeta) of r'(zeta) in -/// Step 8. -/// -/// INPUT -/// \param[in] beta, gamma: permutation challenges -- hashes of -/// transcript (from step 4) -/// \param[in] alpha: quotinet challenge -- hash of transcript (from -/// step 4) -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] nu: opening challenge -- hash of transcript (denoted by -/// v in [GWC19]) (from step 4) -/// \param[in] u: multipoint evaluation challenge -- hash of -/// transcript (from step 4) -/// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial -/// L1 at x=zeta i.e. L1(zeta) (from step 6) -/// \param[in] Q_polys_at_secret_g1: circuit selector polynomials Q -/// evaluated at the secret input (from verifier -/// preprocessed input) -/// \param[in] S_polys_at_secret_g1: permutation polynomials S -/// evaluated at the secret input (from verifier -/// preprocessed input) -/// \param[in] proof: SNARK proof produced by the prover -/// \param[in] preprocessed_input: verifier preprocessed input -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] D1: first part of batched polynomial commitment [D]_1 +// Verifier Step 9: compute first part of batched polynomial +// commitment [D]_1 Note: the reference implemention differs from the +// paper -- it does not add the following term to D1, but to F1 (Step +// 10): -Zh(zeta)([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n +// [t_hi]_1). Instead ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n +// [t_hi]_1) is added to F1 in Step 10 and the multiplication by +// Zh(zeta) is accounted for by dividing by Zh(zeta) of r'(zeta) in +// Step 8. +// +// INPUT +// \param[in] beta, gamma: permutation challenges -- hashes of +// transcript (from step 4) +// \param[in] alpha: quotinet challenge -- hash of transcript (from +// step 4) +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] nu: opening challenge -- hash of transcript (denoted by +// v in [GWC19]) (from step 4) +// \param[in] u: multipoint evaluation challenge -- hash of +// transcript (from step 4) +// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial +// L1 at x=zeta i.e. L1(zeta) (from step 6) +// \param[in] Q_polys_at_secret_g1: circuit selector polynomials Q +// evaluated at the secret input (from verifier +// preprocessed input) +// \param[in] S_polys_at_secret_g1: permutation polynomials S +// evaluated at the secret input (from verifier +// preprocessed input) +// \param[in] proof: SNARK proof produced by the prover +// \param[in] preprocessed_input: verifier preprocessed input +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] D1: first part of batched polynomial commitment [D]_1 template step_nine_out_t plonk_verifier::step_nine( const step_four_out_t &step_four_out, @@ -430,36 +430,36 @@ step_nine_out_t plonk_verifier::step_nine( return step_nine_out; } -/// struct step_ten_out_t constructor +// struct step_ten_out_t constructor template step_ten_out_t::step_ten_out_t(libff::G1 &&F1) : F1(F1) { } -/// Verifier Step 10: compute full batched polynomial commitment [F]_1 -/// = [D]_1 + v [a]_1 + v^2 [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + -/// v^5 [s_sigma_2]_1 Note: to [F]_1 the erefernce code also adds the -/// term ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n [t_hi]_1) which is -/// addedto [D]_1 in the paper (see commenst to Steps 8,9) -/// -/// INPUT -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] nu: opening challenge -- hash of transcript (denoted by -/// v in [GWC19]) (from step 4) -/// \param[in] u: multipoint evaluation challenge -- hash of -/// transcript (from step 4) -/// \param[in] D1: first part of batched polynomial commitment [D]_1 -/// (from step 9) -/// \param[in] S_polys_at_secret_g1: permutation polynomials S -/// evaluated at the secret input (from verifier -/// preprocessed input) -/// \param[in] proof: SNARK proof produced by the prover -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] F1: full batched polynomial commitment [F]_1 +// Verifier Step 10: compute full batched polynomial commitment [F]_1 +// = [D]_1 + v [a]_1 + v^2 [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + +// v^5 [s_sigma_2]_1 Note: to [F]_1 the erefernce code also adds the +// term ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n [t_hi]_1) which is +// addedto [D]_1 in the paper (see commenst to Steps 8,9) +// +// INPUT +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] nu: opening challenge -- hash of transcript (denoted by +// v in [GWC19]) (from step 4) +// \param[in] u: multipoint evaluation challenge -- hash of +// transcript (from step 4) +// \param[in] D1: first part of batched polynomial commitment [D]_1 +// (from step 9) +// \param[in] S_polys_at_secret_g1: permutation polynomials S +// evaluated at the secret input (from verifier +// preprocessed input) +// \param[in] proof: SNARK proof produced by the prover +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] F1: full batched polynomial commitment [F]_1 template step_ten_out_t plonk_verifier::step_ten( const step_four_out_t &step_four_out, @@ -504,25 +504,25 @@ step_ten_out_t plonk_verifier::step_ten( return step_ten_out; } -/// struct step_eleven_out_t constructor +// struct step_eleven_out_t constructor template step_eleven_out_t::step_eleven_out_t(libff::G1 &&E1) : E1(E1) { } -/// Verifier Step 11: compute group-encoded batch evaluation [E]_1 -/// -/// INPUT -/// \param[in] nu: opening challenge -- hash of transcript (denoted by -/// v in [GWC19]) (from step 4) -/// \param[in] u: multipoint evaluation challenge -- hash of -/// transcript (from step 4) -/// \param[in] r_prime_zeta: quotient polynomial evaluation r'(zeta) = -/// r(zeta) - r0, where r0 is a constant term (from step 8) -/// \param[in] proof: SNARK proof produced by the prover -/// -/// OUTPUT -/// \param[out] E1: group-encoded batch evaluation [E]_1 +// Verifier Step 11: compute group-encoded batch evaluation [E]_1 +// +// INPUT +// \param[in] nu: opening challenge -- hash of transcript (denoted by +// v in [GWC19]) (from step 4) +// \param[in] u: multipoint evaluation challenge -- hash of +// transcript (from step 4) +// \param[in] r_prime_zeta: quotient polynomial evaluation r'(zeta) = +// r(zeta) - r0, where r0 is a constant term (from step 8) +// \param[in] proof: SNARK proof produced by the prover +// +// OUTPUT +// \param[out] E1: group-encoded batch evaluation [E]_1 template step_eleven_out_t plonk_verifier::step_eleven( const step_four_out_t &step_four_out, @@ -550,33 +550,33 @@ step_eleven_out_t plonk_verifier::step_eleven( return step_eleven_out; } -/// Verifier Step 12: batch validate all evaluations -/// -/// Checks the following equality -/// -/// e( [W_zeta]_1 + u [W_{zeta srs.omega_roots}]_1, [x]_2 ) * e( -zeta -/// [W_zeta ]_1 - u zeta srs.omega_roots [W_{zeta srs.omega_roots}]_1 -/// - [F]_1 + [E]_1, [1]_2 ) = Field(1) -/// -/// Denoted as: -/// -/// e(first_lhs, second_lhs) * e(first_rhs, second_rhs) = 1 -/// -/// INPUT -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] u: multipoint evaluation challenge -- hash of -/// transcript (from step 4) -/// \param[in] F1: full batched polynomial commitment [F]_1 (from step -/// 10) -/// \param[in] E1: group-encoded batch evaluation [E]_1 (from step 11) -/// \param[in] proof: SNARK proof produced by the prover -/// \param[in] srs: structured reference string -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] boolean 1/0 = valid/invalid proof +// Verifier Step 12: batch validate all evaluations +// +// Checks the following equality +// +// e( [W_zeta]_1 + u [W_{zeta srs.omega_roots}]_1, [x]_2 ) * e( -zeta +// [W_zeta ]_1 - u zeta srs.omega_roots [W_{zeta srs.omega_roots}]_1 +// - [F]_1 + [E]_1, [1]_2 ) = Field(1) +// +// Denoted as: +// +// e(first_lhs, second_lhs) * e(first_rhs, second_rhs) = 1 +// +// INPUT +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] u: multipoint evaluation challenge -- hash of +// transcript (from step 4) +// \param[in] F1: full batched polynomial commitment [F]_1 (from step +// 10) +// \param[in] E1: group-encoded batch evaluation [E]_1 (from step 11) +// \param[in] proof: SNARK proof produced by the prover +// \param[in] srs: structured reference string +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] boolean 1/0 = valid/invalid proof template bool plonk_verifier::step_twelve( const step_four_out_t &step_four_out, @@ -620,26 +620,26 @@ bool plonk_verifier::step_twelve( return b_accept; } -/// \attention The first three steps (as given in [GWC19] -- see -/// below) MUST be executed by the caller: -/// -/// - Verifier Step 1: validate that elements belong to group G1 -/// - Verifier Step 2: validate that elements belong to scalar field -/// Fr -/// - Verifier Step 3: validate that the public input belongs to -/// scalar field Fr -/// . -/// Therefore verification starts from Step 4 of [GWC19] -/// -/// INPUT -/// \param[in] proof: SNARK proof produced by the prover -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// \param[in] transcript_hasher: hashes of the communication -/// transcript after prover rounds 1,2,3,4,5. -/// -/// OUTPUT -/// \param[out] boolean 1/0 = valid/invalid proof +// \attention The first three steps (as given in [GWC19] -- see +// below) MUST be executed by the caller: +// +// - Verifier Step 1: validate that elements belong to group G1 +// - Verifier Step 2: validate that elements belong to scalar field +// Fr +// - Verifier Step 3: validate that the public input belongs to +// scalar field Fr +// . +// Therefore verification starts from Step 4 of [GWC19] +// +// INPUT +// \param[in] proof: SNARK proof produced by the prover +// \param[in] srs: structured reference string containing also +// circuit-specific information +// \param[in] transcript_hasher: hashes of the communication +// transcript after prover rounds 1,2,3,4,5. +// +// OUTPUT +// \param[out] boolean 1/0 = valid/invalid proof template bool plonk_verifier::verify_proof( const plonk_proof &proof, From e751e9852e3a011a7322dde1709d60e01ee429b9 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 19 Aug 2022 11:54:23 +0100 Subject: [PATCH 08/25] plonk: moved constructor of transcipt_hasher class as first method in the class. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r949761293 --- libsnark/zk_proof_systems/plonk/srs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 2acb93c4c..2d28c6fe5 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -253,6 +253,9 @@ template class transcript_hasher std::array, 6> hash_values; public: + // constructor + transcript_hasher(std::vector &buffer); + void add_element(const libff::Fr &element); void add_element(const libff::G1 &element); void add_element(const libff::G2 &element); @@ -271,9 +274,6 @@ template class transcript_hasher // get buffer size size_t buffer_size(); - - // constructor - transcript_hasher(std::vector &buffer); }; } // namespace libsnark From c4dccd1acc69a3191291b795e3a3b01b356196ab Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 26 Aug 2022 11:42:23 +0100 Subject: [PATCH 09/25] plonk: added back the computation of the multipoint challenge u in the last round of the prover. we need to compute u even though we are not using it in the prover in order to make sure that the prover and verifier make exactly the same number of calls to transcript_hasher.get_hash(). addresses PR #61 comment https://github.com/clearmatics/libsnark/pull/61#discussion_r952276778 --- libsnark/zk_proof_systems/plonk/prover.tcc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 5d79429e3..5fd95ff21 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -1104,6 +1104,16 @@ plonk_proof plonk_prover::compute_proof( srs, hasher); + // u: multipoint evaluation challenge -- hash of transcript from + // rounds 1,2,3,4,5 + const libff::Fr u = hasher.get_hash(); + // get_hash may update the internal state of the + // transcript_hasher, depending on the implementation, therefore + // the prover and verifier must make exactly the same calls to + // both add_element and get_hash. that's why here we are computing + // u even if we are not using it. + libff::UNUSED(u); + // construct proof plonk_proof proof( round_one_out.W_polys_blinded_at_secret_g1, From b42bc2a94af89910ac6a2228f99793bfad4c0dce Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 26 Aug 2022 12:51:59 +0100 Subject: [PATCH 10/25] plonk: in transcript_hasher removed the private buffer variable as an input parameter to the constructor. only the object has access to the buffer now. addresses PR #61 comment https://github.com/clearmatics/libsnark/pull/61#issuecomment-1223692351 --- libsnark/zk_proof_systems/plonk/srs.hpp | 2 +- libsnark/zk_proof_systems/plonk/srs.tcc | 6 +++--- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 12 ++++-------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 2d28c6fe5..d87646a77 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -254,7 +254,7 @@ template class transcript_hasher public: // constructor - transcript_hasher(std::vector &buffer); + transcript_hasher(); void add_element(const libff::Fr &element); void add_element(const libff::G1 &element); diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index d52488575..5f5d33945 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -73,10 +73,10 @@ plonk_keypair::plonk_keypair( } // transcript_hasher constructor -template -transcript_hasher::transcript_hasher(std::vector &buffer) - : buffer(std::move(buffer)) +template transcript_hasher::transcript_hasher() { + // initialize to empty vector + this->buffer.clear(); // test array containing the expected hash values of the communication // transcript i.e. the communication challenges (in this order): beta, // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 18cb18d36..2c82339dd 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -490,8 +490,7 @@ template void test_plonk_prover_rounds() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - std::vector buffer; - transcript_hasher hasher(buffer); + transcript_hasher hasher; // Prover Round 0 (initialization) round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); @@ -692,8 +691,7 @@ template void test_plonk_prover() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - std::vector buffer; - transcript_hasher hasher(buffer); + transcript_hasher hasher; // initialize prover plonk_prover prover; @@ -970,8 +968,7 @@ template void test_plonk_verifier_steps() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - std::vector buffer; - transcript_hasher hasher(buffer); + transcript_hasher hasher; // initialize prover plonk_prover prover; @@ -1075,8 +1072,7 @@ template void test_plonk_verifier() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - std::vector buffer; - transcript_hasher hasher(buffer); + transcript_hasher hasher; // initialize prover plonk_prover prover; From d8bdc13cfacf61205d0e437d4138a777f64185a6 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 5 Sep 2022 14:08:04 +0100 Subject: [PATCH 11/25] plonk: moved function signature comments from .tcc to .hpp files only; removed redundant comments indicating class constructors' other minor comments formatting --- libsnark/zk_proof_systems/plonk/circuit.tcc | 1 - libsnark/zk_proof_systems/plonk/prover.hpp | 7 +- libsnark/zk_proof_systems/plonk/prover.tcc | 208 ----------------- libsnark/zk_proof_systems/plonk/srs.hpp | 22 +- libsnark/zk_proof_systems/plonk/srs.tcc | 26 --- libsnark/zk_proof_systems/plonk/utils.tcc | 87 ------- libsnark/zk_proof_systems/plonk/verifier.hpp | 1 - libsnark/zk_proof_systems/plonk/verifier.tcc | 232 ------------------- 8 files changed, 22 insertions(+), 562 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index 06a14e3fb..721b70fa8 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -18,7 +18,6 @@ namespace libsnark // TODO: add here function for describing the target circuit through // the circuit_t structure -// stuct constructor template circuit_t::circuit_t( size_t num_gates, diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index f92a59bd1..aaf1f6661 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -97,7 +97,6 @@ template struct round_zero_out_t { /// - neg_one_poly: -1 polynomial (from round 0) polynomial> neg_one_poly; - /// stuct constructor round_zero_out_t( const std::vector> &&zh_poly, const polynomial> &&null_poly, @@ -119,7 +118,6 @@ template struct round_one_out_t { /// [GWC19] std::vector> W_polys_blinded_at_secret_g1; - /// stuct constructor round_one_out_t( const std::vector>> &&W_polys, const std::vector>> &&W_polys_blinded, @@ -136,7 +134,6 @@ template struct round_two_out_t { /// secret libff::G1 z_poly_at_secret_g1; - /// stuct constructor round_two_out_t( polynomial> &&z_poly, libff::G1 &&z_poly_at_secret_g1); @@ -160,7 +157,6 @@ template struct round_three_out_t { /// i.e. t(zeta) std::vector> t_poly_at_secret_g1; - /// stuct constructor round_three_out_t( std::vector> &&z_poly_xomega, std::vector>> &&t_poly, @@ -195,7 +191,7 @@ template struct round_four_out_t { /// same in order to match the test vectors. TODO can remove t_zeta /// in the future libff::Fr t_zeta; - /// stuct constructor + round_four_out_t( libff::Fr &&a_zeta, libff::Fr &&b_zeta, @@ -221,7 +217,6 @@ template struct round_five_out_t { /// W_{zeta omega}(x) at secert input i.e. [W_{zeta omega}(secret)]_1 libff::G1 W_zeta_omega_at_secret; - /// struct constructor round_five_out_t( libff::Fr &&r_zeta, libff::G1 &&W_zeta_at_secret, diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 5fd95ff21..02d3ed102 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -15,7 +15,6 @@ namespace libsnark { -// Prover round 0 output constructor template round_zero_out_t::round_zero_out_t( const std::vector> &&zh_poly, @@ -25,18 +24,6 @@ round_zero_out_t::round_zero_out_t( { } -// Prover Round 0 initialization -// -// Initialization -// -// INPUT -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] zh_poly: vanishing polynomial -// \param[out] null_poly: 0 polynomial -// \param[out] neg_one_poly: -1 polynomial template round_zero_out_t plonk_prover::round_zero(const srs &srs) { @@ -62,7 +49,6 @@ round_zero_out_t plonk_prover::round_zero(const srs &srs) return round_zero_out; } -// Prover round 1 output constructor template round_one_out_t::round_one_out_t( const std::vector>> &&W_polys, @@ -74,28 +60,6 @@ round_one_out_t::round_one_out_t( { } -// Prover Round 1 -// -// INPUT -// \param[in] zh_poly: vanishing polynomial Zh (from round 0) -// \param[in] null_poly: 0 polynomial (from round 0) -// \param[in] neg_one_poly: -1 polynomial (from round 0) -// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only -// b1-b6 used in round 1) -// \param[in] witness: witness values -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] W_polys: witness polynomials (Lagrange interpolation -// of the witness values) -// \param[out] W_polys_blinded: blinded witness polynomials -// \param[out] W_polys_blinded_at_secret_g1: the blinded witness -// polynomials evaluated at the secret input denoted -// [a]_1, [b]_1, [c]_1 in [GWC19] -// \param[out] transcript_hasher: accumulates the communication -// transcript into a buffer to be hashed after prover -// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_one_out_t plonk_prover::round_one( const round_zero_out_t &round_zero_out, @@ -157,7 +121,6 @@ round_one_out_t plonk_prover::round_one( return round_one_out; } -// Prover round 2 output template round_two_out_t::round_two_out_t( polynomial> &&z_poly, libff::G1 &&z_poly_at_secret_g1) @@ -165,23 +128,6 @@ round_two_out_t::round_two_out_t( { } -// Prover Round 2 -// -// INPUT -// \param[in] zh_poly: vanishing polynomial Zh (from round 0) -// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only -// b7,b8,b9 used in round 2) -// \param[in] witness: witness values -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] z_poly: blinded accumulator poly z(x) -// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) -// evaluated at secret -// \param[out] transcript_hasher: accumulates the communication -// transcript into a buffer to be hashed after prover -// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_two_out_t plonk_prover::round_two( const libff::Fr &beta, @@ -227,7 +173,6 @@ round_two_out_t plonk_prover::round_two( return round_two_out; } -// Prover round 3 output constructor template round_three_out_t::round_three_out_t( std::vector> &&z_poly_xomega, @@ -241,30 +186,6 @@ round_three_out_t::round_three_out_t( { } -// Prover Round 3 -// -// INPUT -// \param[in] zh_poly: vanishing polynomial Zh (from Round 0) -// \param[in] W_polys_blinded: blinded witness polynomials (from -// Round 1) -// \param[in] beta, gamma: permutation challenges -- hashes of -// transcript (from round 2) -// \param[in] z_poly: blinded accumulator poly z(x) (from Round 2) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] t_poly_long: the quotient polynomial t(x) (see Round -// 3, pp28 [GWC19]) -// \param[out] t_poly: t(x) divided in three parts t(x) = t_lo(x) + -// t_mid(x) x^n + t_hi(x) x^{2n} -// \param[out] t_poly_at_secret_g1: t(x) evaluated at the secret -// input zeta i.e. t(zeta) -// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted -// by w -// \param[out] transcript_hasher: accumulates the communication -// transcript into a buffer to be hashed after prover -// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_three_out_t plonk_prover::round_three( const libff::Fr &alpha, @@ -496,7 +417,6 @@ round_three_out_t plonk_prover::round_three( return round_three_out; } -// Prover round 4 output constructor template round_four_out_t::round_four_out_t( libff::Fr &&a_zeta, @@ -516,40 +436,6 @@ round_four_out_t::round_four_out_t( { } -// Prover Round 4 -// -// INPUT -// \param[in] W_polys_blinded: blinded witness polynomials (from -// Round 1) -// \param[in] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted -// by w (from Round 3) -// \param[in] t_poly_long: the quotient polynomial t(x) (see Round 3, -// pp28 [GWC19]) (from Round 3) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] a_zeta, b_zeta, c_zeta: the blinded witness -// polynomials a(x), b(x), c(x) (denoted by -// W_polys_blinded[] output from Round 1) evaluated at -// x=zeta i.e. a(z), b(z), c(z) -// \param[out] S_0_zeta, S_1_zeta: the permutation polynomials -// S_sigma_1(x), S_sigma_2(x) from the common -// preprocessed input (see [GWC19], Sect. 8.1) evaluated -// at x=zeta i.e. S_sigma_1(z), S_sigma_2(z) -// \param[out] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) -// shifted by w (output from Round 3) evaluated at x=zeta -// i.e. z(zeta*w) -// \param[out] t_zeta: the quotient polynomial t(x) output from Round -// 3, see pp28 [GWC19]) evaluated at x=zeta -// i.e. t(z). IMPORTANT! the original Plonk proposal -// [GWC19] does not output this parameter t_zeta. The -// Python reference implementation \[PlonkPy] does, so we -// do the same in order to match the test vectors. TODO -// can remove t_zeta in the future -// \param[out] transcript_hasher: accumulates the communication -// transcript into a buffer to be hashed after prover -// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_four_out_t plonk_prover::round_four( const libff::Fr &zeta, @@ -606,7 +492,6 @@ round_four_out_t plonk_prover::round_four( return round_four_out; } -// Prover round 5 output constructor template round_five_out_t::round_five_out_t( libff::Fr &&r_zeta, @@ -618,53 +503,6 @@ round_five_out_t::round_five_out_t( { } -// Prover Round 5 -// -// INPUT -// \param[in] beta, gamma: permutation challenges -- hashes of -// transcript (from round 2) -// \param[in] alpha: quotinet challenge -- hash of transcript (from -// round 3) -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// round 4) -// \param[in] a_zeta, b_zeta, c_zeta: the blinded witness polynomials -// a(x), b(x), c(x) (denoted by W_polys_blinded[] output -// from Round 1) evaluated at x=zeta i.e. a(z), b(z), c(z) -// (from round 4) -// \param[in] S_0_zeta, S_1_zeta: the permutation polynomials -// S_sigma_1(x), S_sigma_2(x) from the common preprocessed -// input (see [GWC19], Sect. 8.1) evaluated at x=zeta -// i.e. S_sigma_1(z), S_sigma_2(z) (from round 4) -// \param[in] t_zeta: the quotient polynomial t(x) output from Round -// 3, see pp28 [GWC19]) evaluated at x=zeta -// i.e. t(z). IMPORTANT! the original Plonk proposal -// [GWC19] does not output this parameter t_zeta. The -// Python reference implementation \[PlonkPy] does, so we -// do the same in order to match the test vectors. TODO -// can remove t_zeta in the future (from round 4) -// \param[in] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) -// shifted by w (output from Round 3) evaluated at x=zeta -// i.e. z(zeta*w) (from round 4) -// \param[in] W_polys_blinded: blinded witness polynomials (from -// round 1) -// \param[in] t_poly: t(x) divided in three parts t(x) = t_lo(x) + -// t_mid(x) x^n + t_hi(x) x^{2n} (from round 3) -// \param[in] z_poly: blinded accumulator poly z(x) (from round 2) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] r_zeta: linearisation polynomial r(x) evaluated at -// x=zeta ie. r(zeta) -// \param[out] W_zeta_at_secret: commitment to opening proof -// polynomial W_zeta(x) at secert input -// i.e. [W_zeta(secret)]_1 -// \param[out] W_zeta_omega_at_secret: commitment to opening proof -// polynomial W_{zeta omega}(x) at secert input -// i.e. [W_{zeta omega}(secret)]_1 -// \param[out] transcript_hasher: accumulates the communication -// transcript into a buffer to be hashed after prover -// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_five_out_t plonk_prover::round_five( const libff::Fr &alpha, @@ -963,7 +801,6 @@ round_five_out_t plonk_prover::round_five( return round_five_out; } -// class plonk_proof constructor template plonk_proof::plonk_proof( std::vector> &W_polys_blinded_at_secret_g1, @@ -993,51 +830,6 @@ plonk_proof::plonk_proof( { } -// Prover compute SNARK proof -// -// Pi ([a]_1, [b]_1, [c]_1, [z]_1, -// [t_lo]_1, [t_mi]_1, [t_hi]_1, -// \bar{a}, \bar{b}, \bar{c}, -// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, -// [W_zeta]_1, [W_{zeta omega}]_1 -// r_zeta) -// -// \note in the reference Python implementation \[PlonkPy], r_zeta -// (the evaluation of the linearlization polynomial r(X) at zeta from -// Prover round 5) is added to the pi-SNARK proof. In the paper this -// is omitted, which seems to make the proof shorter by 1 element at -// the epxense of a slightly heavier computation on the verifier's -// side. Here we follow the reference implementation \[PlonkPy] to -// make sure we match the test values. TODO: once all test vectors -// are verified, we may remove r_zeta from the proof to be fully -// compliant with the paper. -// -// Mapping code-to-paper quantities -// -// \param W_polys_blinded_at_secret_g1[a, b, c]: [a]_1, [b]_1, [c]_1 -// (from Round 1) -// \param z_poly_at_secret_g1: [z]_1 (from Round 2) -// \param t_poly_at_secret_g1[lo, mi, hi]: [t_lo]_1, [t_mi]_1, -// [t_hi]_1 (from Round 3) -// \param a_zeta, b_zeta, c_zeta, S_0_zeta, S_1_zeta, -// z_poly_xomega_zeta: \bar{a}, \bar{b}, \bar{c}, -// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w} (from Round 4) -// \param W_zeta_at_secret, W_zeta_omega_at_secret: [W_zeta]_1, -// [W_{zeta omega}]_1 (from Round 5) -// -// INPUT -// \param[in] srs: structured reference string containing also -// circuit-specific information -// \param[in] witness: all internal values and public input -// corresponding to the given circuit -// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 -// used in prover rounds 1 and 2 (see Sect. 8.3, roumds -// 1,2 [GWC19]) -// \param[in] transcript_hasher: hashes of the communication -// transcript after prover rounds 1,2,3,4,5. -// -// OUTPUT -// \param[out] proof: SNARK proof Pi (see above) template plonk_proof plonk_prover::compute_proof( const srs &srs, diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index d87646a77..5a8786d9a 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -63,6 +63,11 @@ template class usrs std::vector> &&secret_powers_g2); }; +/// Compute a universal srs (usrs). It is composed *only* of encoded +/// powers of the secret value in the group generator. Therefore a usrs +/// is independent of any particular circuit. +/// +/// \note only for debug template usrs plonk_usrs_derive_from_secret( const libff::Fr &secret, const size_t max_degree); @@ -138,6 +143,13 @@ template class srs std::shared_ptr> domain); }; +/// Derive the (plain) SRS from the circuit description and the +/// USRS. The (plain) SRS is a specialization of the USRS for one +/// particular circuit i.e. +/// +/// usrs = +/// srs = (proving_key, verificataion_key) = derive(usrs, +/// circuit_description) template srs plonk_srs_derive_from_usrs( const usrs &usrs, const circuit_t &circuit); @@ -253,11 +265,15 @@ template class transcript_hasher std::array, 6> hash_values; public: - // constructor transcript_hasher(); + // add an Fr element to the transcript buffer for hashing void add_element(const libff::Fr &element); + // add the coordinates of a G1 curve point to the transcript buffer for + // hashing void add_element(const libff::G1 &element); + // add the coordinates of a G2 curve point to the transcript buffer for + // hashing void add_element(const libff::G2 &element); // TODO: use next declaration to implement an actual hash function @@ -267,6 +283,10 @@ template class transcript_hasher // std::array // Blake2sHasher::hash(std::vector const& buffer) + // dummy implementation of get_hash that directly returns the + // expected hard-coded hashes for the purposes of unit testing TODO + // to be replaced by a call to a proper hash function e.g. SHA2, + // BLAKE, etc. libff::Fr get_hash(); // clear the buffer (for now only for testing) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 5f5d33945..4b2bb870c 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -15,7 +15,6 @@ namespace libsnark { -// class usrs constructor template usrs::usrs( std::vector> &&secret_powers_g1, @@ -24,7 +23,6 @@ usrs::usrs( { } -// class srs constructor template srs::srs( const size_t &num_gates, @@ -58,13 +56,11 @@ srs::srs( { } -// class plonk_verification_key template plonk_verification_key::plonk_verification_key( std::vector> &&secret_powers_g2) : secret_powers_g2(std::move(secret_powers_g2)){}; -// class plonk_keypair constructor template plonk_keypair::plonk_keypair( plonk_proving_key &&pk, plonk_verification_key &&vk) @@ -72,7 +68,6 @@ plonk_keypair::plonk_keypair( { } -// transcript_hasher constructor template transcript_hasher::transcript_hasher() { // initialize to empty vector @@ -98,19 +93,16 @@ template transcript_hasher::transcript_hasher() }; } -// clear the buffer (for now only for testing) template void transcript_hasher::buffer_clear() { this->buffer.clear(); } -// get buffer size template size_t transcript_hasher::buffer_size() { return this->buffer.size(); } -// add an Fr element to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::Fr &element) { @@ -127,7 +119,6 @@ void transcript_hasher::add_element(const libff::Fr &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -// add the coordinates of a G1 curve point to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::G1 &element) { @@ -149,7 +140,6 @@ void transcript_hasher::add_element(const libff::G1 &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -// add the coordinates of a G2 curve point to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::G2 &element) { @@ -171,10 +161,6 @@ void transcript_hasher::add_element(const libff::G2 &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -// dummy implementation of get_hash that directly returns the -// expected hard-coded hashes for the purposes of unit testing TODO -// to be replaced by a call to a proper hash function e.g. SHA2, -// BLAKE, etc. template libff::Fr transcript_hasher::get_hash() { size_t buffer_len = this->buffer.size(); @@ -258,11 +244,6 @@ template libff::Fr transcript_hasher::get_hash() return challenge; } -// Compute a universal srs (usrs). It is composed *only* of encoded -// powers of the secret value in the group generator. Therefore a usrs -// is independent of any particular circuit. -// -// \note only for debug template usrs plonk_usrs_derive_from_secret( const libff::Fr &secret, const size_t max_degree) @@ -301,13 +282,6 @@ usrs plonk_usrs_derive_from_secret( return usrs(std::move(secret_powers_g1), std::move(secret_powers_g2)); } -// Derive the (plain) SRS from the circuit description and the -// USRS. The (plain) SRS is a specialization of the USRS for one -// particular circuit i.e. -// -// usrs = -// srs = (proving_key, verificataion_key) = derive(usrs, -// circuit_description) template srs plonk_srs_derive_from_usrs( const usrs &usrs, const circuit_t &circuit) diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 2cb62ae60..aecdbe972 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -15,7 +15,6 @@ namespace libsnark { -// print the elements of a vector template void print_vector(const std::vector &v) { for (size_t i = 0; i < v.size(); ++i) { @@ -24,23 +23,6 @@ template void print_vector(const std::vector &v) } } -// Compute the Lagrange basis polynomials for interpolating sets of -// n points -// -// INPUT: -// -// \param[in] npoints - number of points -// -// OUTPUT: -// -// \param[out] L[0..n-1][0..n-1]: Lagrange basis over the n roots of -// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, -// a1, ..., a_{n-1}] is a vector representing the -// coefficients of the i-th Lagrange polynomial L_i(x) = -// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 -// and L_i(x\neq{omega_i)})=0 -// -// \note uses libfqfft iFFT for the interpolation template void plonk_compute_lagrange_basis( const size_t npoints, std::vector> &L) @@ -60,25 +42,6 @@ void plonk_compute_lagrange_basis( } } -// Interpolate a polynomial from a set of points through inverse FFT -// -// INPUT: -// -// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), -// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], -// ... which we want to interpolate as a polynomial -// -// OUTPUT: -// -// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., a_{n-1}] -// of the polynomial f(x) interpolating the set of points -// f_points. For example if f_poly[0..n-1] = [a0, a1, ..., -// a_{n-1}] then this represents the polynomial f(x) = -// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that -// f(omega_i)=f_points[i], where omega_0, ..., omega_{n-1} -// are the n roots of unity. -// -// \note uses libfqfft iFFT for the interpolation template void plonk_interpolate_polynomial_from_points( const std::vector &f_points, polynomial &f_poly) @@ -90,11 +53,6 @@ void plonk_interpolate_polynomial_from_points( domain->iFFT(f_poly); } -// Compute the selector polynomials of the given circuit (also -// called here "q-polynomials"). See Sect. 8.1. The matrix -// gates_matrix_transpose has 5 rows, each corresponding to the -// values L, R, M, O and C for each gate; the number of columns is -// equal to the number of gates. L_basis is the Lagrange basis. template std::vector> plonk_compute_selector_polynomials( const size_t &num_gates, @@ -120,12 +78,6 @@ void plonk_compute_public_input_polynomial( plonk_interpolate_polynomial_from_points(PI_points, PI_poly); }; -// This function computes the sets H, k1H, k2H. H is a -// multiplicative subgroup containing the n-th roots of unity in Fr, -// where \omega is a primitive n-th root of unity and a generator of -// H i.e H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen -// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus -// consist of 3n distinct elements. \see [GWC19] pp26 (top). template void plonk_compute_roots_of_unity_omega( const size_t num_gates, @@ -162,14 +114,6 @@ void plonk_compute_roots_of_unity_omega( } } -// This function computes the sets H, k1H, k2H, where H is a -// multiplicative subgroup containing the n-th roots of unity in Fr and -// \omega is a primitive n-th root of unity and a generator of -// H ie. H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen -// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus -// consist of 3n distinct elements. \see [GWC19] pp26 (top) and Sect. 8. -// -// \note uses plonk_compute_roots_of_unity_omega template void plonk_compute_cosets_H_k1H_k2H( const size_t num_gates, @@ -197,10 +141,6 @@ void plonk_compute_cosets_H_k1H_k2H( omega[base_k2].begin(), omega[base_k2].end(), back_inserter(H_gen)); } -// permute the multiplicative subgroup H according to the wire -// permutation: (see [GWC19] Sect. 8), \see -// plonk_compute_roots_of_unity_omega, \see -// plonk_roots_of_unity_omega_to_subgroup_H template std::vector plonk_permute_subgroup_H( const std::vector &H_gen, @@ -216,8 +156,6 @@ std::vector plonk_permute_subgroup_H( return H_gen_permute; } -// compute the permutation polynomials S_sigma_1, S_sigma_2, -// S_sigma_2 (see [GWC19], Sect. 8.1) template std::vector> plonk_compute_permutation_polynomials( const std::vector &H_gen_permute, const size_t num_gates) @@ -236,9 +174,6 @@ std::vector> plonk_compute_permutation_polynomials( return S_polys; } -// A wrapper for multi_exp_method_BDLO12_signed() dot-product a -// vector of group elements in G1 (curve points) with a vector of -// scalar elements in Fr template libff::G1 plonk_multi_exp_G1( const std::vector> &curve_points, @@ -258,21 +193,6 @@ libff::G1 plonk_multi_exp_G1( return product; } -// Evaluate a polynomial F at the encoded secret input -// \secret^i*G_1 ie. compute f(\secret)*G1 = [f(\secret)]_i -// -// INPUT -// -// \param[in] secret_powers_g1: \secret^i*G1: -// 0\le{i} libff::G1 plonk_evaluate_poly_at_secret_G1( const std::vector> &secret_powers_g1, @@ -293,8 +213,6 @@ libff::G1 plonk_evaluate_poly_at_secret_G1( return f_poly_at_secret_g1; } -// Evaluate a list of polynomials in the encrypted secret input: see -// plonk_evaluate_poly_at_secret_G1 template void plonk_evaluate_polys_at_secret_G1( const std::vector> &secret_powers_g1, @@ -311,10 +229,6 @@ void plonk_evaluate_polys_at_secret_G1( } } -// Compute the factors in the product of the permutation polynomial -// z(X) in Prover Round 2. Note that accumulator A[0]=1 and A[i], -// i>0 is computed from values at i-1 for witness[i-1], H_gen[i-1], -// H_gen_permute[i-1]m etc. template FieldT plonk_compute_accumulator_factor( const size_t i, @@ -355,7 +269,6 @@ FieldT plonk_compute_accumulator_factor( return res; } -// - A: accumulator vector template std::vector plonk_compute_accumulator( const size_t num_gates, diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index ea26340ea..cae73f192 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -66,7 +66,6 @@ template struct verifier_preprocessed_input_t { std::vector> Q_polys_at_secret_g1; std::vector> S_polys_at_secret_g1; - /// struct constructor verifier_preprocessed_input_t( std::vector> &&Q_polys_at_secret_g1, std::vector> &&S_polys_at_secret_g1); diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index c7cf4f650..1b23eeca2 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -15,7 +15,6 @@ namespace libsnark { -// struct verifier_preprocessed_input_t constructor template verifier_preprocessed_input_t::verifier_preprocessed_input_t( std::vector> &&Q_polys_at_secret_g1, @@ -25,17 +24,6 @@ verifier_preprocessed_input_t::verifier_preprocessed_input_t( { } -// Verifier precomputation -// -// INPUT -// \param[in] srs: structured reference string -// -// OUTPUT -// \param[out] Q_polys_at_secret_g1: circuit selector polynomials Q evaluated -// at -// the secret input -// \param[out] S_polys_at_secret_g1: permutation polynomials S evaluated at the -// secret input template verifier_preprocessed_input_t plonk_verifier::preprocessed_input( const srs &srs) @@ -55,34 +43,20 @@ verifier_preprocessed_input_t plonk_verifier::preprocessed_input( return preprocessed_input; } -// Verifier Step 1: validate that elements belong to group G1 -// -// \attention This validation MUST be done by the caller. Empty -// function here for consistency with the description in [GWC19] template void plonk_verifier::step_one(const plonk_proof &proof) { } -// Verifier Step 2: validate that elements belong to scalar field Fr -// -// \attention This validation MUST be done by the caller. Empty -// function here for consistency with the description in [GWC19] template void plonk_verifier::step_two(const plonk_proof &proof) { } -// Verifier Step 3: validate that the public input belongs to scalar -// field Fr -// -// \attention This validation MUST be done by the caller. Empty -// function here for consistency with the description in [GWC19] template void plonk_verifier::step_three(const srs &srs) { } -// struct step_four_out_t constructor template step_four_out_t::step_four_out_t( libff::Fr &beta, @@ -95,24 +69,6 @@ step_four_out_t::step_four_out_t( { } -// Verifier Step 4: compute challenges hashed transcript as in prover -// description, from the common inputs, public input, and elements of -// pi-SNARK. TODO: fixed to the test vectors for now -// -// INPUT -// \param[in] proof: SNARK proof produced by the prover -// \param[in] transcript_hasher: hashes of the communication -// transcript after prover rounds 1,2,3,4,5. -// -// OUTPUT -// \param[out] beta, gamma: permutation challenges - hashes of -// transcript -// \param[out] alpha: quotinet challenge - hash of transcript -// \param[out] zeta: evaluation challenge - hash of transcript -// \param[out] nu: opening challenge - hash of transcript (denoted by -// v in [GWC19]) -// \param[out] u: multipoint evaluation challenge - hash of -// transcript template step_four_out_t plonk_verifier::step_four( const plonk_proof &proof, transcript_hasher &hasher) @@ -167,24 +123,12 @@ step_four_out_t plonk_verifier::step_four( return step_four_out; } -// struct step_five_out_t constructor template step_five_out_t::step_five_out_t(libff::Fr &&zh_zeta) : zh_zeta(zh_zeta) { } -// Verifier Step 5: compute zero polynomial evaluation -// -// INPUT -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] zh_zeta: evaluation of vanishing polynomial Zh at -// x=zeta i.e. Zh(zeta) template step_five_out_t plonk_verifier::step_five( const step_four_out_t &step_four_out, const srs &srs) @@ -197,25 +141,12 @@ step_five_out_t plonk_verifier::step_five( return step_five_out; } -// struct step_six_out_t constructor template step_six_out_t::step_six_out_t(libff::Fr &&L_0_zeta) : L_0_zeta(L_0_zeta) { } -// Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) -// Note: the paper counts the L-polynomials from 1; we count from 0 -// -// INPUT -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] L_0_zeta: Lagrange polynomial evaluation of polynomial -// L1 at x=zeta i.e. L1(zeta) template step_six_out_t plonk_verifier::step_six( const step_four_out_t &step_four_out, const srs &srs) @@ -226,25 +157,12 @@ step_six_out_t plonk_verifier::step_six( return step_six_out; } -// struct step_seven_out_t constructor template step_seven_out_t::step_seven_out_t(libff::Fr &&PI_zeta) : PI_zeta(PI_zeta) { } -// Verifier Step 7: compute public input polynomial evaluation -// PI(zeta) -// -// INPUT -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] PI_zeta: public input polynomial PI evaluated at -// x=zeta i.e. PI(zeta) template step_seven_out_t plonk_verifier::step_seven( const step_four_out_t &step_four_out, const srs &srs) @@ -256,40 +174,12 @@ step_seven_out_t plonk_verifier::step_seven( return step_seven_out; } -// struct step_eight_out_t constructor template step_eight_out_t::step_eight_out_t(libff::Fr &&r_prime_zeta) : r_prime_zeta(r_prime_zeta) { } -// Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = -// r(zeta) - r0, where r0 is a constant term \note follows the Python -// reference implementation, which slightly deviates from the paper -// due to the presence of the r_zeta term in the proof (not present -// in the paper). In particular, the reference code computes and -// uses r'(zeta) in step 8, while the paper uses r0. In addition, the -// reference code divides r'(zeta) by the vanishing polynomial at -// zeta zh_zeta, while the paper does not do that (see also Step 9). -// -// INPUT -// \param[in] beta, gamma: permutation challenges -- hashes of -// transcript (from step 4) -// \param[in] alpha: quotinet challenge -- hash of transcript (from -// step 4) -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] zh_zeta: evaluation of vanishing polynomial Zh at -// x=zeta i.e. Zh(zeta) (from step 5) -// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial -// L1 at x=zeta i.e. L1(zeta) (from step 6) -// \param[in] PI_zeta: public input polynomial PI evaluated at x=zeta -// i.e. PI(zeta) (from step 7) -// \param[in] proof: SNARK proof produced by the prover -// -// OUTPUT -// \param[out] r_prime_zeta: quotient polynomial evaluation r'(zeta) -// = r(zeta) - r0, where r0 is a constant term template step_eight_out_t plonk_verifier::step_eight( const step_four_out_t &step_four_out, @@ -322,47 +212,11 @@ step_eight_out_t plonk_verifier::step_eight( return step_eight_out; } -// struct step_nine_out_t constructor template step_nine_out_t::step_nine_out_t(libff::G1 &&D1) : D1(D1) { } -// Verifier Step 9: compute first part of batched polynomial -// commitment [D]_1 Note: the reference implemention differs from the -// paper -- it does not add the following term to D1, but to F1 (Step -// 10): -Zh(zeta)([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n -// [t_hi]_1). Instead ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n -// [t_hi]_1) is added to F1 in Step 10 and the multiplication by -// Zh(zeta) is accounted for by dividing by Zh(zeta) of r'(zeta) in -// Step 8. -// -// INPUT -// \param[in] beta, gamma: permutation challenges -- hashes of -// transcript (from step 4) -// \param[in] alpha: quotinet challenge -- hash of transcript (from -// step 4) -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] nu: opening challenge -- hash of transcript (denoted by -// v in [GWC19]) (from step 4) -// \param[in] u: multipoint evaluation challenge -- hash of -// transcript (from step 4) -// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial -// L1 at x=zeta i.e. L1(zeta) (from step 6) -// \param[in] Q_polys_at_secret_g1: circuit selector polynomials Q -// evaluated at the secret input (from verifier -// preprocessed input) -// \param[in] S_polys_at_secret_g1: permutation polynomials S -// evaluated at the secret input (from verifier -// preprocessed input) -// \param[in] proof: SNARK proof produced by the prover -// \param[in] preprocessed_input: verifier preprocessed input -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] D1: first part of batched polynomial commitment [D]_1 template step_nine_out_t plonk_verifier::step_nine( const step_four_out_t &step_four_out, @@ -430,36 +284,11 @@ step_nine_out_t plonk_verifier::step_nine( return step_nine_out; } -// struct step_ten_out_t constructor template step_ten_out_t::step_ten_out_t(libff::G1 &&F1) : F1(F1) { } -// Verifier Step 10: compute full batched polynomial commitment [F]_1 -// = [D]_1 + v [a]_1 + v^2 [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + -// v^5 [s_sigma_2]_1 Note: to [F]_1 the erefernce code also adds the -// term ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n [t_hi]_1) which is -// addedto [D]_1 in the paper (see commenst to Steps 8,9) -// -// INPUT -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] nu: opening challenge -- hash of transcript (denoted by -// v in [GWC19]) (from step 4) -// \param[in] u: multipoint evaluation challenge -- hash of -// transcript (from step 4) -// \param[in] D1: first part of batched polynomial commitment [D]_1 -// (from step 9) -// \param[in] S_polys_at_secret_g1: permutation polynomials S -// evaluated at the secret input (from verifier -// preprocessed input) -// \param[in] proof: SNARK proof produced by the prover -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] F1: full batched polynomial commitment [F]_1 template step_ten_out_t plonk_verifier::step_ten( const step_four_out_t &step_four_out, @@ -504,25 +333,11 @@ step_ten_out_t plonk_verifier::step_ten( return step_ten_out; } -// struct step_eleven_out_t constructor template step_eleven_out_t::step_eleven_out_t(libff::G1 &&E1) : E1(E1) { } -// Verifier Step 11: compute group-encoded batch evaluation [E]_1 -// -// INPUT -// \param[in] nu: opening challenge -- hash of transcript (denoted by -// v in [GWC19]) (from step 4) -// \param[in] u: multipoint evaluation challenge -- hash of -// transcript (from step 4) -// \param[in] r_prime_zeta: quotient polynomial evaluation r'(zeta) = -// r(zeta) - r0, where r0 is a constant term (from step 8) -// \param[in] proof: SNARK proof produced by the prover -// -// OUTPUT -// \param[out] E1: group-encoded batch evaluation [E]_1 template step_eleven_out_t plonk_verifier::step_eleven( const step_four_out_t &step_four_out, @@ -550,33 +365,6 @@ step_eleven_out_t plonk_verifier::step_eleven( return step_eleven_out; } -// Verifier Step 12: batch validate all evaluations -// -// Checks the following equality -// -// e( [W_zeta]_1 + u [W_{zeta srs.omega_roots}]_1, [x]_2 ) * e( -zeta -// [W_zeta ]_1 - u zeta srs.omega_roots [W_{zeta srs.omega_roots}]_1 -// - [F]_1 + [E]_1, [1]_2 ) = Field(1) -// -// Denoted as: -// -// e(first_lhs, second_lhs) * e(first_rhs, second_rhs) = 1 -// -// INPUT -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] u: multipoint evaluation challenge -- hash of -// transcript (from step 4) -// \param[in] F1: full batched polynomial commitment [F]_1 (from step -// 10) -// \param[in] E1: group-encoded batch evaluation [E]_1 (from step 11) -// \param[in] proof: SNARK proof produced by the prover -// \param[in] srs: structured reference string -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] boolean 1/0 = valid/invalid proof template bool plonk_verifier::step_twelve( const step_four_out_t &step_four_out, @@ -620,26 +408,6 @@ bool plonk_verifier::step_twelve( return b_accept; } -// \attention The first three steps (as given in [GWC19] -- see -// below) MUST be executed by the caller: -// -// - Verifier Step 1: validate that elements belong to group G1 -// - Verifier Step 2: validate that elements belong to scalar field -// Fr -// - Verifier Step 3: validate that the public input belongs to -// scalar field Fr -// . -// Therefore verification starts from Step 4 of [GWC19] -// -// INPUT -// \param[in] proof: SNARK proof produced by the prover -// \param[in] srs: structured reference string containing also -// circuit-specific information -// \param[in] transcript_hasher: hashes of the communication -// transcript after prover rounds 1,2,3,4,5. -// -// OUTPUT -// \param[out] boolean 1/0 = valid/invalid proof template bool plonk_verifier::verify_proof( const plonk_proof &proof, From dcb5ce83db8a90d55f32a89182f97a25383317bb Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 8 Sep 2022 14:32:47 +0100 Subject: [PATCH 12/25] plonk: replaced test values in transcript_hasher with values from the plonk_example class; addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r964175573 . --- libsnark/zk_proof_systems/plonk/srs.tcc | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 4b2bb870c..c2878d679 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -70,26 +70,20 @@ plonk_keypair::plonk_keypair( template transcript_hasher::transcript_hasher() { + plonk_example example; + // initialize to empty vector this->buffer.clear(); // test array containing the expected hash values of the communication // transcript i.e. the communication challenges (in this order): beta, // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 this->hash_values = { - libff::Fr("3710899868510394644410941212967766116886736137326022751" - "891187938298987182388"), // beta - libff::Fr("110379303840831945879077096653321168432672740458288022" - "49545114995763715746939"), // gamma - libff::Fr("379799789992747238930717819864848384921111623418803600" - "22719385400306128734648"), // alpha - libff::Fr("4327197228921839935583364394550235027071910395980312641" - "5018065799136107272465"), // zeta - libff::Fr( - "275158598338697752421507265080923414294782807831923791651" - "55175653098691426347"), // nu - libff::Fr( - "1781751143954696684632449211212056577828855388109883650570" - "6049265393896966778"), // u + example.beta, + example.gamma, + example.alpha, + example.zeta, + example.nu, + example.u, }; } From bc297b904c6b319db89ad24b9f76682650c50545 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 8 Sep 2022 14:42:36 +0100 Subject: [PATCH 13/25] plonk: removed redundant debug info and unreachable debug checks. addresses PR# 61. --- libsnark/zk_proof_systems/plonk/srs.tcc | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index c2878d679..1ef98c32b 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -158,8 +158,6 @@ void transcript_hasher::add_element(const libff::G2 &element) template libff::Fr transcript_hasher::get_hash() { size_t buffer_len = this->buffer.size(); - // DEBUG - printf("[%s:%d] len %7d\n", __FILE__, __LINE__, (int)buffer_len); // vector of valid lengths (\attention specific to BLS12-381) const std::vector length{288, 320, 416, 704, 896, 1120}; @@ -172,13 +170,6 @@ template libff::Fr transcript_hasher::get_hash() throw std::logic_error( "Error: invalid length of transcript hasher buffer"); } - if (!b_valid_length) { - printf( - "[%s:%d] Error: invalid length of transcript hasher buffer\n", - __FILE__, - __LINE__); - } - assert(b_valid_length); libff::Fr challenge = 0; From 64069a054f58f0f393ba2c80ee3acd7366d51137 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 8 Sep 2022 14:45:00 +0100 Subject: [PATCH 14/25] plonk: set transcript hasher constants alpha, beta, ... to type const. see PR #61 --- libsnark/zk_proof_systems/plonk/verifier.hpp | 24 ++++++++++---------- libsnark/zk_proof_systems/plonk/verifier.tcc | 12 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index cae73f192..c1645627b 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -73,19 +73,19 @@ template struct verifier_preprocessed_input_t { /// Verifier step 4 output template struct step_four_out_t { - libff::Fr beta; - libff::Fr gamma; - libff::Fr alpha; - libff::Fr zeta; - libff::Fr nu; - libff::Fr u; + const libff::Fr beta; + const libff::Fr gamma; + const libff::Fr alpha; + const libff::Fr zeta; + const libff::Fr nu; + const libff::Fr u; step_four_out_t( - libff::Fr &beta, - libff::Fr &gamma, - libff::Fr &alpha, - libff::Fr &zeta, - libff::Fr &nu, - libff::Fr &u); + const libff::Fr &beta, + const libff::Fr &gamma, + const libff::Fr &alpha, + const libff::Fr &zeta, + const libff::Fr &nu, + const libff::Fr &u); }; /// Verifier step 5 output diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 1b23eeca2..134311749 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -59,12 +59,12 @@ template void plonk_verifier::step_three(const srs &srs) template step_four_out_t::step_four_out_t( - libff::Fr &beta, - libff::Fr &gamma, - libff::Fr &alpha, - libff::Fr &zeta, - libff::Fr &nu, - libff::Fr &u) + const libff::Fr &beta, + const libff::Fr &gamma, + const libff::Fr &alpha, + const libff::Fr &zeta, + const libff::Fr &nu, + const libff::Fr &u) : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) { } From b8665f202be63274c6d6e4622e3e290f6b61916f Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 12 Sep 2022 12:56:26 +0100 Subject: [PATCH 15/25] plonk: added the transcript_hasher class as an additional specialization parameter to the prover and verifier classes. moved the current transcript_hasher class from files srs.* to its own files under tests, the reason being that its implementation is specific to the bls12-381 curve. set the prover and verifier to be instantiated with this bls12-381-specific implementation of transcript_hasher. this commit addresses steps 2. and 4. from comment https://github.com/clearmatics/libsnark/pull/61#discussion_r966911185 of PR#61. --- libsnark/zk_proof_systems/plonk/prover.hpp | 15 +- libsnark/zk_proof_systems/plonk/prover.tcc | 41 +-- libsnark/zk_proof_systems/plonk/srs.hpp | 101 ------- libsnark/zk_proof_systems/plonk/srs.tcc | 161 ----------- ...ls12_381_test_vector_transcript_hasher.cpp | 182 ++++++++++++ ...ls12_381_test_vector_transcript_hasher.hpp | 120 ++++++++ .../plonk/tests/test_plonk.cpp | 271 ++++++++++-------- libsnark/zk_proof_systems/plonk/verifier.hpp | 6 +- libsnark/zk_proof_systems/plonk/verifier.tcc | 63 ++-- 9 files changed, 517 insertions(+), 443 deletions(-) create mode 100644 libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp create mode 100644 libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index aaf1f6661..ebf15c626 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -224,7 +224,8 @@ template struct round_five_out_t { }; /// Plonk prover. Computes object of class plonk_proof. -template class plonk_prover +template class plonk_prover +// template class plonk_prover { using Field = libff::Fr; @@ -272,7 +273,7 @@ template class plonk_prover const std::vector> &blind_scalars, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); /// Prover Round 2 /// @@ -298,7 +299,7 @@ template class plonk_prover const std::vector> blind_scalars, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); /// Prover Round 3 /// @@ -332,7 +333,7 @@ template class plonk_prover const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); /// Prover Round 4 /// @@ -373,7 +374,7 @@ template class plonk_prover const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); /// Prover Round 5 /// @@ -434,7 +435,7 @@ template class plonk_prover const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); /// Prover compute SNARK proof /// @@ -485,7 +486,7 @@ template class plonk_prover const srs &srs, const std::vector &witness, const std::vector> &blind_scalars, - transcript_hasher &hasher); + transcript_hasher &hasher); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 02d3ed102..2c3a17861 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -24,8 +24,9 @@ round_zero_out_t::round_zero_out_t( { } -template -round_zero_out_t plonk_prover::round_zero(const srs &srs) +template +round_zero_out_t plonk_prover::round_zero( + const srs &srs) { using Field = libff::Fr; @@ -60,13 +61,13 @@ round_one_out_t::round_one_out_t( { } -template -round_one_out_t plonk_prover::round_one( +template +round_one_out_t plonk_prover::round_one( const round_zero_out_t &round_zero_out, const std::vector> &blind_scalars, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { using Field = libff::Fr; const size_t nwitness = NUM_HSETS; @@ -128,15 +129,15 @@ round_two_out_t::round_two_out_t( { } -template -round_two_out_t plonk_prover::round_two( +template +round_two_out_t plonk_prover::round_two( const libff::Fr &beta, const libff::Fr &gamma, const round_zero_out_t &round_zero_out, const std::vector> blind_scalars, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { using Field = libff::Fr; @@ -186,8 +187,8 @@ round_three_out_t::round_three_out_t( { } -template -round_three_out_t plonk_prover::round_three( +template +round_three_out_t plonk_prover::round_three( const libff::Fr &alpha, const libff::Fr &beta, const libff::Fr &gamma, @@ -195,7 +196,7 @@ round_three_out_t plonk_prover::round_three( const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { using Field = libff::Fr; int num_hgen = NUM_HSETS; @@ -436,13 +437,13 @@ round_four_out_t::round_four_out_t( { } -template -round_four_out_t plonk_prover::round_four( +template +round_four_out_t plonk_prover::round_four( const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { using Field = libff::Fr; @@ -503,8 +504,8 @@ round_five_out_t::round_five_out_t( { } -template -round_five_out_t plonk_prover::round_five( +template +round_five_out_t plonk_prover::round_five( const libff::Fr &alpha, const libff::Fr &beta, const libff::Fr &gamma, @@ -516,7 +517,7 @@ round_five_out_t plonk_prover::round_five( const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { using Field = libff::Fr; polynomial remainder; @@ -830,12 +831,12 @@ plonk_proof::plonk_proof( { } -template -plonk_proof plonk_prover::compute_proof( +template +plonk_proof plonk_prover::compute_proof( const srs &srs, const std::vector &witness, const std::vector> &blind_scalars, - transcript_hasher &hasher) + transcript_hasher &hasher) { // Prover Round 0 (initialization) printf("[%s:%d] Prover Round 0...\n", __FILE__, __LINE__); diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 5a8786d9a..7fecac31b 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -195,107 +195,6 @@ template class plonk_keypair plonk_keypair(plonk_keypair &&other) = default; }; -/// transcript hasher interface -/// -/// the hasher works in the Prover as follows: -/// -/// round 1 -/// -/// add_element(buffer, a_eval_exp) -/// add_element(buffer, b_eval_exp) -/// add_element(buffer, c_eval_exp) -/// // buffer = first_output -/// -/// round 2 -/// -/// beta = hash(str(buffer) + "0") -/// gamma = hash(str(buffer) + "1") -/// -/// acc_eval = evaluate_in_exponent(CRS, accumulator_poly.to_coeffs()) -/// -/// add_element(buffer, acc_eval) -/// // buffer = first_output + second_output -/// -/// round 3 -/// -/// alpha = hash(str(buffer)) -/// -/// add_element(buffer, t_lo_eval_exp) -/// add_element(buffer, t_mid_eval_exp) -/// add_element(buffer, t_hi_eval_exp) -/// // buffer = first_output + second_output + third_output -/// -/// round 4 -/// -/// zeta = hash(str(buffer)) -/// -/// add_element(buffer, a_zeta) -/// add_element(buffer, b_zeta) -/// add_element(buffer, c_zeta) -/// add_element(buffer, S_0_zeta) -/// add_element(buffer, S_1_zeta) -/// add_element(buffer, accumulator_shift_zeta) -/// add_element(buffer, t_zeta) -/// add_element(buffer, r_zeta) -/// // buffer = first_output + second_output + third_output + fourth_output -/// -/// round 5 -/// -/// nu = hash(str(buffer)) -/// -/// W_zeta_eval_exp = evaluate_in_exponent(CRS, W_zeta.to_coeffs()) -/// W_zeta_omega_eval_exp = evaluate_in_exponent(CRS, -/// W_zeta_omega.to_coeffs()) -/// -/// add_element(buffer, W_zeta_eval_exp) -/// add_element(buffer, W_zeta_omega_eval_exp) -/// -/// // buffer = first_output + second_output + third_output + fourth_output -/// + fifth_output -/// -/// u = hash(str(buffer)) -/// -template class transcript_hasher -{ -private: - // buffer accumulating data to be hashed - std::vector buffer; - // array containing the hash values of the communication transcript - // i.e. the six challenges (in this order): beta, gamma, alpha, zeta, nu, u - std::array, 6> hash_values; - -public: - transcript_hasher(); - - // add an Fr element to the transcript buffer for hashing - void add_element(const libff::Fr &element); - // add the coordinates of a G1 curve point to the transcript buffer for - // hashing - void add_element(const libff::G1 &element); - // add the coordinates of a G2 curve point to the transcript buffer for - // hashing - void add_element(const libff::G2 &element); - - // TODO: use next declaration to implement an actual hash function - // e.g. BLAKE (from Aztec barretenberg implementation): - // https://github.com/AztecProtocol/barretenberg/blob/master/barretenberg/src/aztec/plonk/transcript/transcript.cpp#L33 - // - // std::array - // Blake2sHasher::hash(std::vector const& buffer) - - // dummy implementation of get_hash that directly returns the - // expected hard-coded hashes for the purposes of unit testing TODO - // to be replaced by a call to a proper hash function e.g. SHA2, - // BLAKE, etc. - libff::Fr get_hash(); - - // clear the buffer (for now only for testing) - void buffer_clear(); - - // get buffer size - size_t buffer_size(); -}; - } // namespace libsnark #include "libsnark/zk_proof_systems/plonk/srs.tcc" diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 1ef98c32b..c837e6326 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -68,167 +68,6 @@ plonk_keypair::plonk_keypair( { } -template transcript_hasher::transcript_hasher() -{ - plonk_example example; - - // initialize to empty vector - this->buffer.clear(); - // test array containing the expected hash values of the communication - // transcript i.e. the communication challenges (in this order): beta, - // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 - this->hash_values = { - example.beta, - example.gamma, - example.alpha, - example.zeta, - example.nu, - example.u, - }; -} - -template void transcript_hasher::buffer_clear() -{ - this->buffer.clear(); -} - -template size_t transcript_hasher::buffer_size() -{ - return this->buffer.size(); -} - -template -void transcript_hasher::add_element(const libff::Fr &element) -{ - // convert the Fr element into a string - std::string str; - { - std::ostringstream ss; - libff::field_write( - element, ss); - str = ss.str(); - } - // copy the string as a sequence of uint8_t elements at the end of - // the buffer - std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); -} - -template -void transcript_hasher::add_element(const libff::G1 &element) -{ - libff::G1 element_aff(element); - element_aff.to_affine_coordinates(); - - // convert the affine coordinates of the curve point into a string - std::string str; - { - std::ostringstream ss; - libff::group_write< - libff::encoding_binary, - libff::form_plain, - libff::compression_off>(element_aff, ss); - str = ss.str(); - } - // copy the string as a sequence of uint8_t elements at the end of - // the buffer - std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); -} - -template -void transcript_hasher::add_element(const libff::G2 &element) -{ - libff::G2 element_aff(element); - element_aff.to_affine_coordinates(); - - // convert the affine coordinates of the curve point into a string - std::string str; - { - std::ostringstream ss; - libff::group_write< - libff::encoding_binary, - libff::form_plain, - libff::compression_off>(element_aff, ss); - str = ss.str(); - } - // copy the string as a sequence of uint8_t elements at the end of - // the buffer - std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); -} - -template libff::Fr transcript_hasher::get_hash() -{ - size_t buffer_len = this->buffer.size(); - - // vector of valid lengths (\attention specific to BLS12-381) - const std::vector length{288, 320, 416, 704, 896, 1120}; - - // If we are here, then the hasher buffer has invalid length so throw an - // exception - bool b_valid_length = - (0 != std::count(length.begin(), length.end(), buffer_len)); - if (!b_valid_length) { - throw std::logic_error( - "Error: invalid length of transcript hasher buffer"); - } - - libff::Fr challenge = 0; - - // beta - if (buffer_len == length[0]) { - printf( - "[%s:%d] buffer_len %d: beta\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[0]; // beta - } - // gamma - if (buffer_len == length[1]) { - printf( - "[%s:%d] buffer_len %d: gamma\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[1]; // gamma - } - // alpha - if (buffer_len == length[2]) { - printf( - "[%s:%d] buffer_len %d: alpha\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[2]; // alpha - } - // zeta - if (buffer_len == length[3]) { - printf( - "[%s:%d] buffer_len %d: zeta\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[3]; // zeta - } - // nu - if (buffer_len == length[4]) { - printf( - "[%s:%d] buffer_len %d: nu\n", __FILE__, __LINE__, (int)buffer_len); - challenge = this->hash_values[4]; // nu - } - // u - if (buffer_len == length[5]) { - // reset step to 0 - printf( - "[%s:%d] buffer_len %d: u + clear()\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[5]; // u - } - - return challenge; -} - template usrs plonk_usrs_derive_from_secret( const libff::Fr &secret, const size_t max_degree) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp new file mode 100644 index 000000000..a8836e640 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -0,0 +1,182 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_CPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_CPP_ + +// Implementation of the transcript hasher interface specific to the BLS12-381 +// curve. See bls12_381_test_vector_transcript_hasher.hpp +namespace libsnark +{ + +bls12_381_test_vector_transcript_hasher:: + bls12_381_test_vector_transcript_hasher() +{ + plonk_example example; + + // initialize to empty vector + this->buffer.clear(); + // test array containing the expected hash values of the communication + // transcript i.e. the communication challenges (in this order): beta, + // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 + this->hash_values = { + example.beta, + example.gamma, + example.alpha, + example.zeta, + example.nu, + example.u, + }; +} + +void bls12_381_test_vector_transcript_hasher::buffer_clear() +{ + this->buffer.clear(); +} + +size_t bls12_381_test_vector_transcript_hasher::buffer_size() +{ + return this->buffer.size(); +} + +void bls12_381_test_vector_transcript_hasher::add_element( + const libff::Fr &element) +{ + // convert the Fr element into a string + std::string str; + { + std::ostringstream ss; + libff::field_write( + element, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +void bls12_381_test_vector_transcript_hasher::add_element( + const libff::G1 &element) +{ + libff::G1 element_aff(element); + element_aff.to_affine_coordinates(); + + // convert the affine coordinates of the curve point into a string + std::string str; + { + std::ostringstream ss; + libff::group_write< + libff::encoding_binary, + libff::form_plain, + libff::compression_off>(element_aff, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +void bls12_381_test_vector_transcript_hasher::add_element( + const libff::G2 &element) +{ + libff::G2 element_aff(element); + element_aff.to_affine_coordinates(); + + // convert the affine coordinates of the curve point into a string + std::string str; + { + std::ostringstream ss; + libff::group_write< + libff::encoding_binary, + libff::form_plain, + libff::compression_off>(element_aff, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +libff::Fr bls12_381_test_vector_transcript_hasher:: + get_hash() +{ + size_t buffer_len = this->buffer.size(); + + // vector of valid lengths (\attention specific to BLS12-381) + const std::vector length{288, 320, 416, 704, 896, 1120}; + + // If we are here, then the hasher buffer has invalid length so throw an + // exception + bool b_valid_length = + (0 != std::count(length.begin(), length.end(), buffer_len)); + if (!b_valid_length) { + throw std::logic_error( + "Error: invalid length of transcript hasher buffer"); + } + + libff::Fr challenge = 0; + + // beta + if (buffer_len == length[0]) { + printf( + "[%s:%d] buffer_len %d: beta\n", + __FILE__, + __LINE__, + (int)buffer_len); + challenge = this->hash_values[0]; // beta + } + // gamma + if (buffer_len == length[1]) { + printf( + "[%s:%d] buffer_len %d: gamma\n", + __FILE__, + __LINE__, + (int)buffer_len); + challenge = this->hash_values[1]; // gamma + } + // alpha + if (buffer_len == length[2]) { + printf( + "[%s:%d] buffer_len %d: alpha\n", + __FILE__, + __LINE__, + (int)buffer_len); + challenge = this->hash_values[2]; // alpha + } + // zeta + if (buffer_len == length[3]) { + printf( + "[%s:%d] buffer_len %d: zeta\n", + __FILE__, + __LINE__, + (int)buffer_len); + challenge = this->hash_values[3]; // zeta + } + // nu + if (buffer_len == length[4]) { + printf( + "[%s:%d] buffer_len %d: nu\n", __FILE__, __LINE__, (int)buffer_len); + challenge = this->hash_values[4]; // nu + } + // u + if (buffer_len == length[5]) { + // reset step to 0 + printf( + "[%s:%d] buffer_len %d: u + clear()\n", + __FILE__, + __LINE__, + (int)buffer_len); + challenge = this->hash_values[5]; // u + } + + return challenge; +} + +} // namespace libsnark + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_CPP_ diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp new file mode 100644 index 000000000..fd9be7093 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp @@ -0,0 +1,120 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ + +namespace libsnark +{ + +/// transcript hasher interface specific to the BLS12-381 curve +/// +/// the hasher works in the Prover as follows: +/// +/// round 1 +/// +/// add_element(buffer, a_eval_exp) +/// add_element(buffer, b_eval_exp) +/// add_element(buffer, c_eval_exp) +/// // buffer = first_output +/// +/// round 2 +/// +/// beta = hash(str(buffer) + "0") +/// gamma = hash(str(buffer) + "1") +/// +/// acc_eval = evaluate_in_exponent(CRS, accumulator_poly.to_coeffs()) +/// +/// add_element(buffer, acc_eval) +/// // buffer = first_output + second_output +/// +/// round 3 +/// +/// alpha = hash(str(buffer)) +/// +/// add_element(buffer, t_lo_eval_exp) +/// add_element(buffer, t_mid_eval_exp) +/// add_element(buffer, t_hi_eval_exp) +/// // buffer = first_output + second_output + third_output +/// +/// round 4 +/// +/// zeta = hash(str(buffer)) +/// +/// add_element(buffer, a_zeta) +/// add_element(buffer, b_zeta) +/// add_element(buffer, c_zeta) +/// add_element(buffer, S_0_zeta) +/// add_element(buffer, S_1_zeta) +/// add_element(buffer, accumulator_shift_zeta) +/// add_element(buffer, t_zeta) +/// add_element(buffer, r_zeta) +/// // buffer = first_output + second_output + third_output + fourth_output +/// +/// round 5 +/// +/// nu = hash(str(buffer)) +/// +/// W_zeta_eval_exp = evaluate_in_exponent(CRS, W_zeta.to_coeffs()) +/// W_zeta_omega_eval_exp = evaluate_in_exponent(CRS, +/// W_zeta_omega.to_coeffs()) +/// +/// add_element(buffer, W_zeta_eval_exp) +/// add_element(buffer, W_zeta_omega_eval_exp) +/// +/// // buffer = first_output + second_output + third_output + fourth_output +/// + fifth_output +/// +/// u = hash(str(buffer)) +/// +class bls12_381_test_vector_transcript_hasher +{ +private: + // buffer accumulating data to be hashed + std::vector buffer; + // array containing the hash values of the communication transcript + // i.e. the six challenges (in this order): beta, gamma, alpha, zeta, nu, u + std::array, 6> hash_values; + +public: + bls12_381_test_vector_transcript_hasher(); + + // add an Fr element to the transcript buffer for hashing + void add_element(const libff::Fr &element); + // add the coordinates of a G1 curve point to the transcript buffer for + // hashing + void add_element(const libff::G1 &element); + // add the coordinates of a G2 curve point to the transcript buffer for + // hashing + void add_element(const libff::G2 &element); + + // TODO: use next declaration to implement an actual hash function + // e.g. BLAKE (from Aztec barretenberg implementation): + // https://github.com/AztecProtocol/barretenberg/blob/master/barretenberg/src/aztec/plonk/transcript/transcript.cpp#L33 + // + // std::array + // Blake2sHasher::hash(std::vector const& buffer) + + // dummy implementation of get_hash that directly returns the + // expected hard-coded hashes for the purposes of unit testing TODO + // to be replaced by a call to a proper hash function e.g. SHA2, + // BLAKE, etc. + libff::Fr get_hash(); + + // clear the buffer (for now only for testing) + void buffer_clear(); + + // get buffer size + size_t buffer_size(); +}; + +} // namespace libsnark + +#include "libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp" + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 2c82339dd..55960b4e3 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -8,6 +8,7 @@ #include "libsnark/zk_proof_systems/plonk/circuit.hpp" #include "libsnark/zk_proof_systems/plonk/prover.hpp" +#include "libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp" #include "libsnark/zk_proof_systems/plonk/verifier.hpp" #include @@ -33,14 +34,14 @@ namespace libsnark // \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, // [W_zeta]_1, [W_{zeta omega_roots}]_1 // r_zeta (*)) -template +template void test_verify_invalid_proof( const plonk_proof &valid_proof, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { // initialize verifier - plonk_verifier verifier; + plonk_verifier verifier; bool b_accept = true; // random element on the curve initialized to zero @@ -274,17 +275,18 @@ void test_plonk_compute_accumulator( ASSERT_EQ(A_poly, example.A_poly); } -template +template void test_plonk_prover_round_one( const plonk_example &example, const round_zero_out_t &round_zero_out, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { std::vector> blind_scalars = example.prover_blind_scalars; - round_one_out_t round_one_out = plonk_prover::round_one( - round_zero_out, blind_scalars, witness, srs, hasher); + round_one_out_t round_one_out = + plonk_prover::round_one( + round_zero_out, blind_scalars, witness, srs, hasher); for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, (int)i); libff::print_vector(round_one_out.W_polys[i]); @@ -311,7 +313,7 @@ void test_plonk_prover_round_one( } } -template +template void test_plonk_prover_round_two( const plonk_example &example, const libff::Fr &beta, @@ -320,10 +322,11 @@ void test_plonk_prover_round_two( const std::vector> &blind_scalars, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { - round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); + round_two_out_t round_two_out = + plonk_prover::round_two( + beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); printf("[%s:%d] z_poly\n", __FILE__, __LINE__); libff::print_vector(round_two_out.z_poly); ASSERT_EQ(round_two_out.z_poly, example.z_poly); @@ -336,7 +339,7 @@ void test_plonk_prover_round_two( ASSERT_EQ(z_poly_at_secret_g1_aff.Y, example.z_poly_at_secret_g1[1]); } -template +template void test_plonk_prover_round_three( const plonk_example &example, const libff::Fr &alpha, @@ -346,17 +349,18 @@ void test_plonk_prover_round_three( const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { - round_three_out_t round_three_out = plonk_prover::round_three( - alpha, - beta, - gamma, - round_zero_out, - round_one_out, - round_two_out, - srs, - hasher); + round_three_out_t round_three_out = + plonk_prover::round_three( + alpha, + beta, + gamma, + round_zero_out, + round_one_out, + round_two_out, + srs, + hasher); printf("[%s:%d] Output from Round 3\n", __FILE__, __LINE__); printf("[%s:%d] t_poly_long\n", __FILE__, __LINE__); libff::print_vector(round_three_out.t_poly_long); @@ -377,17 +381,18 @@ void test_plonk_prover_round_three( } } -template +template void test_plonk_prover_round_four( const plonk_example &example, const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { - round_four_out_t round_four_out = plonk_prover::round_four( - zeta, round_one_out, round_three_out, srs, hasher); + round_four_out_t round_four_out = + plonk_prover::round_four( + zeta, round_one_out, round_three_out, srs, hasher); // Prover Round 4 output check against test vectors printf("[%s:%d] Output from Round 4\n", __FILE__, __LINE__); printf("a_zeta "); @@ -413,7 +418,7 @@ void test_plonk_prover_round_four( ASSERT_EQ(round_four_out.z_poly_xomega_zeta, example.z_poly_xomega_zeta); } -template +template void test_plonk_prover_round_five( const plonk_example &example, const libff::Fr &alpha, @@ -427,21 +432,22 @@ void test_plonk_prover_round_five( const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { - round_five_out_t round_five_out = plonk_prover::round_five( - alpha, - beta, - gamma, - zeta, - nu, - round_zero_out, - round_one_out, - round_two_out, - round_three_out, - round_four_out, - srs, - hasher); + round_five_out_t round_five_out = + plonk_prover::round_five( + alpha, + beta, + gamma, + zeta, + nu, + round_zero_out, + round_one_out, + round_two_out, + round_three_out, + round_four_out, + srs, + hasher); printf("[%s:%d] Outputs from Prover round 5\n", __FILE__, __LINE__); printf("r_zeta "); @@ -464,7 +470,7 @@ void test_plonk_prover_round_five( /// \attention the example class is defined specifically for the BLS12-381 /// curve, so make sure we are using this curve -template void test_plonk_prover_rounds() +template void test_plonk_prover_rounds() { using Field = libff::Fr; @@ -490,22 +496,24 @@ template void test_plonk_prover_rounds() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - transcript_hasher hasher; + transcript_hasher hasher; // Prover Round 0 (initialization) - round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); + round_zero_out_t round_zero_out = + plonk_prover::round_zero(srs); // --- Unit test Prover Round 1 --- // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Unit test Prover Round 1...\n", __FILE__, __LINE__); - test_plonk_prover_round_one( + test_plonk_prover_round_one( example, round_zero_out, witness, srs, hasher); // --- Unit test Prover Round 2 --- // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Unit test Prover Round 2...\n", __FILE__, __LINE__); - round_one_out_t round_one_out = plonk_prover::round_one( - round_zero_out, blind_scalars, witness, srs, hasher); + round_one_out_t round_one_out = + plonk_prover::round_one( + round_zero_out, blind_scalars, witness, srs, hasher); // clear hash buffer hasher.buffer_clear(); // add outputs from Round 1 to the hash buffer @@ -515,7 +523,7 @@ template void test_plonk_prover_rounds() const libff::Fr beta = hasher.get_hash(); hasher.add_element(libff::Fr::one()); const libff::Fr gamma = hasher.get_hash(); - test_plonk_prover_round_two( + test_plonk_prover_round_two( example, beta, gamma, @@ -531,8 +539,9 @@ template void test_plonk_prover_rounds() // --- Unit test Prover Round 3 --- // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); - round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); + round_two_out_t round_two_out = + plonk_prover::round_two( + beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); // clear hash buffer hasher.buffer_clear(); // add outputs from Round 1 to the hash buffer @@ -543,7 +552,7 @@ template void test_plonk_prover_rounds() // add outputs from Round 2 to the hash buffer hasher.add_element(round_two_out.z_poly_at_secret_g1); const libff::Fr alpha = hasher.get_hash(); - test_plonk_prover_round_three( + test_plonk_prover_round_three( example, alpha, beta, @@ -556,15 +565,16 @@ template void test_plonk_prover_rounds() // --- Unit test Prover Round 4 --- printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); - round_three_out_t round_three_out = plonk_prover::round_three( - alpha, - beta, - gamma, - round_zero_out, - round_one_out, - round_two_out, - srs, - hasher); + round_three_out_t round_three_out = + plonk_prover::round_three( + alpha, + beta, + gamma, + round_zero_out, + round_one_out, + round_two_out, + srs, + hasher); // clear hash buffer hasher.buffer_clear(); // add outputs from Round 1 to the hash buffer @@ -579,13 +589,14 @@ template void test_plonk_prover_rounds() hasher.add_element(round_three_out.t_poly_at_secret_g1[mid]); hasher.add_element(round_three_out.t_poly_at_secret_g1[hi]); const libff::Fr zeta = hasher.get_hash(); - test_plonk_prover_round_four( + test_plonk_prover_round_four( example, zeta, round_one_out, round_three_out, srs, hasher); // --- Unit test Prover Round 5 --- printf("[%s:%d] Unit test Prover Round 5...\n", __FILE__, __LINE__); - round_four_out_t round_four_out = plonk_prover::round_four( - zeta, round_one_out, round_three_out, srs, hasher); + round_four_out_t round_four_out = + plonk_prover::round_four( + zeta, round_one_out, round_three_out, srs, hasher); // clear hash buffer hasher.buffer_clear(); // add outputs from Round 1 to the hash buffer @@ -607,7 +618,7 @@ template void test_plonk_prover_rounds() hasher.add_element(round_four_out.S_1_zeta); hasher.add_element(round_four_out.z_poly_xomega_zeta); const libff::Fr nu = hasher.get_hash(); - test_plonk_prover_round_five( + test_plonk_prover_round_five( example, alpha, beta, @@ -666,7 +677,7 @@ template void test_plonk_srs() /// \attention the example class is defined specifically for the BLS12-381 /// curve, so make sure we are using this curve -template void test_plonk_prover() +template void test_plonk_prover() { using Field = libff::Fr; @@ -691,10 +702,10 @@ template void test_plonk_prover() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - transcript_hasher hasher; + transcript_hasher hasher; // initialize prover - plonk_prover prover; + plonk_prover prover; // compute proof plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); @@ -746,13 +757,13 @@ template void test_plonk_prover() /// \attention the example class is defined specifically for the BLS12-381 /// curve, so make sure we are using this curve -template +template void test_plonk_verifier_preprocessed_input( const plonk_example &example, const srs &srs) { // compute verifier preprocessed input const verifier_preprocessed_input_t preprocessed_input = - plonk_verifier::preprocessed_input(srs); + plonk_verifier::preprocessed_input(srs); for (int i = 0; i < (int)srs.Q_polys.size(); ++i) { printf("srs.Q_polys_at_secret_G1[%d] \n", i); @@ -774,46 +785,46 @@ void test_plonk_verifier_preprocessed_input( } } -template +template void test_plonk_verifier_step_five( const plonk_example &example, const step_four_out_t &step_four_out, const srs &srs) { const step_five_out_t step_five_out = - plonk_verifier::step_five(step_four_out, srs); + plonk_verifier::step_five(step_four_out, srs); printf("[%s:%d] zh_zeta ", __FILE__, __LINE__); step_five_out.zh_zeta.print(); ASSERT_EQ(step_five_out.zh_zeta, example.zh_zeta); } -template +template void test_plonk_verifier_step_six( const plonk_example &example, const step_four_out_t &step_four_out, const srs &srs) { const step_six_out_t step_six_out = - plonk_verifier::step_six(step_four_out, srs); + plonk_verifier::step_six(step_four_out, srs); printf("L_0_zeta "); step_six_out.L_0_zeta.print(); ASSERT_EQ(step_six_out.L_0_zeta, example.L_0_zeta); } -template +template void test_plonk_verifier_step_seven( const plonk_example &example, const step_four_out_t &step_four_out, const srs &srs) { const step_seven_out_t step_seven_out = - plonk_verifier::step_seven(step_four_out, srs); + plonk_verifier::step_seven(step_four_out, srs); printf("PI_zeta "); step_seven_out.PI_zeta.print(); ASSERT_EQ(step_seven_out.PI_zeta, example.PI_zeta); } -template +template void test_plonk_verifier_step_eight( const plonk_example &example, const step_four_out_t &step_four_out, @@ -823,12 +834,12 @@ void test_plonk_verifier_step_eight( const plonk_proof &proof) { const step_eight_out_t step_eight_out = - plonk_verifier::step_eight( + plonk_verifier::step_eight( step_four_out, step_five_out, step_six_out, step_seven_out, proof); ASSERT_EQ(step_eight_out.r_prime_zeta, example.r_prime_zeta); } -template +template void test_plonk_verifier_step_nine( const plonk_example &example, const step_four_out_t &step_four_out, @@ -837,8 +848,9 @@ void test_plonk_verifier_step_nine( const verifier_preprocessed_input_t &preprocessed_input, const srs &srs) { - step_nine_out_t step_nine_out = plonk_verifier::step_nine( - step_four_out, step_six_out, proof, preprocessed_input, srs); + step_nine_out_t step_nine_out = + plonk_verifier::step_nine( + step_four_out, step_six_out, proof, preprocessed_input, srs); step_nine_out.D1.print(); libff::G1 D1_aff(step_nine_out.D1); D1_aff.to_affine_coordinates(); @@ -846,7 +858,7 @@ void test_plonk_verifier_step_nine( ASSERT_EQ(D1_aff.Y, example.D1[1]); } -template +template void test_plonk_verifier_step_ten( const plonk_example &example, const step_four_out_t &step_four_out, @@ -855,8 +867,9 @@ void test_plonk_verifier_step_ten( const verifier_preprocessed_input_t &preprocessed_input, const srs &srs) { - step_ten_out_t step_ten_out = plonk_verifier::step_ten( - step_four_out, step_nine_out, proof, preprocessed_input, srs); + step_ten_out_t step_ten_out = + plonk_verifier::step_ten( + step_four_out, step_nine_out, proof, preprocessed_input, srs); printf("[%s:%d] F1\n", __FILE__, __LINE__); step_ten_out.F1.print(); libff::G1 F1_aff(step_ten_out.F1); @@ -865,7 +878,7 @@ void test_plonk_verifier_step_ten( ASSERT_EQ(F1_aff.Y, example.F1[1]); } -template +template void test_plonk_verifier_step_eleven( const plonk_example &example, const step_four_out_t &step_four_out, @@ -873,7 +886,8 @@ void test_plonk_verifier_step_eleven( const plonk_proof &proof) { const step_eleven_out_t step_eleven_out = - plonk_verifier::step_eleven(step_four_out, step_eight_out, proof); + plonk_verifier::step_eleven( + step_four_out, step_eight_out, proof); printf("[%s:%d] E1\n", __FILE__, __LINE__); step_eleven_out.E1.print(); libff::G1 E1_aff(step_eleven_out.E1); @@ -943,7 +957,7 @@ void test_plonk_verifier_pairing( /// \attention the example class is defined specifically for the BLS12-381 /// curve, so make sure we are using this curve -template void test_plonk_verifier_steps() +template void test_plonk_verifier_steps() { using Field = libff::Fr; @@ -968,42 +982,46 @@ template void test_plonk_verifier_steps() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - transcript_hasher hasher; + transcript_hasher hasher; // initialize prover - plonk_prover prover; + plonk_prover prover; // compute proof plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); - // clear the hasher buffer in order to re-use the same transcript_hasher - // object for the verifier + // clear the hasher buffer in order to re-use the same + // transcript_hasher object for the verifier hasher.buffer_clear(); // Unit test verifier preprocessed input - test_plonk_verifier_preprocessed_input(example, srs); + test_plonk_verifier_preprocessed_input( + example, srs); // compute step 4 const step_four_out_t step_four_out = - plonk_verifier::step_four(proof, hasher); + plonk_verifier::step_four(proof, hasher); // unit test verifier step 5 - test_plonk_verifier_step_five(example, step_four_out, srs); + test_plonk_verifier_step_five( + example, step_four_out, srs); // unit test verifier step 6 - test_plonk_verifier_step_six(example, step_four_out, srs); + test_plonk_verifier_step_six( + example, step_four_out, srs); // unit test verifier step 7 - test_plonk_verifier_step_seven(example, step_four_out, srs); + test_plonk_verifier_step_seven( + example, step_four_out, srs); // unit test verifier step 8 const step_five_out_t step_five_out = - plonk_verifier::step_five(step_four_out, srs); + plonk_verifier::step_five(step_four_out, srs); const step_six_out_t step_six_out = - plonk_verifier::step_six(step_four_out, srs); + plonk_verifier::step_six(step_four_out, srs); const step_seven_out_t step_seven_out = - plonk_verifier::step_seven(step_four_out, srs); - test_plonk_verifier_step_eight( + plonk_verifier::step_seven(step_four_out, srs); + test_plonk_verifier_step_eight( example, step_four_out, step_five_out, @@ -1013,28 +1031,31 @@ template void test_plonk_verifier_steps() // unit test verifier step 9 const verifier_preprocessed_input_t preprocessed_input = - plonk_verifier::preprocessed_input(srs); - test_plonk_verifier_step_nine( + plonk_verifier::preprocessed_input(srs); + test_plonk_verifier_step_nine( example, step_four_out, step_six_out, proof, preprocessed_input, srs); // unit test verifier step 10 - step_nine_out_t step_nine_out = plonk_verifier::step_nine( - step_four_out, step_six_out, proof, preprocessed_input, srs); - test_plonk_verifier_step_ten( + step_nine_out_t step_nine_out = + plonk_verifier::step_nine( + step_four_out, step_six_out, proof, preprocessed_input, srs); + test_plonk_verifier_step_ten( example, step_four_out, step_nine_out, proof, preprocessed_input, srs); // unit test verifier step 11 const step_eight_out_t step_eight_out = - plonk_verifier::step_eight( + plonk_verifier::step_eight( step_four_out, step_five_out, step_six_out, step_seven_out, proof); - test_plonk_verifier_step_eleven( + test_plonk_verifier_step_eleven( example, step_four_out, step_eight_out, proof); // unit test verifier pairing (step 12) - step_ten_out_t step_ten_out = plonk_verifier::step_ten( - step_four_out, step_nine_out, proof, preprocessed_input, srs); + step_ten_out_t step_ten_out = + plonk_verifier::step_ten( + step_four_out, step_nine_out, proof, preprocessed_input, srs); const step_eleven_out_t step_eleven_out = - plonk_verifier::step_eleven(step_four_out, step_eight_out, proof); + plonk_verifier::step_eleven( + step_four_out, step_eight_out, proof); test_plonk_verifier_pairing( example, step_four_out.zeta, @@ -1047,7 +1068,7 @@ template void test_plonk_verifier_steps() /// \attention the example class is defined specifically for the BLS12-381 /// curve, so make sure we are using this curve -template void test_plonk_verifier() +template void test_plonk_verifier() { using Field = libff::Fr; @@ -1072,26 +1093,26 @@ template void test_plonk_verifier() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - transcript_hasher hasher; + transcript_hasher hasher; // initialize prover - plonk_prover prover; + plonk_prover prover; // compute proof plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); - // clear the hasher buffer in order to re-use the same transcript_hasher - // object for the verifier + // clear the hasher buffer in order to re-use the same + // transcript_hasher object for the verifier hasher.buffer_clear(); // initialize verifier - plonk_verifier verifier; + plonk_verifier verifier; // verify proof bool b_valid_proof = verifier.verify_proof(proof, srs, hasher); ASSERT_TRUE(b_valid_proof); - // clear the hasher buffer in order to re-use the same transcript_hasher - // object + // clear the hasher buffer in order to re-use the same + // transcript_hasher object hasher.buffer_clear(); // assert that proof verification fails when the proof is // manipulated @@ -1101,10 +1122,18 @@ template void test_plonk_verifier() TEST(TestPlonk, BLS12_381) { test_plonk_srs(); - test_plonk_prover_rounds(); - test_plonk_prover(); - test_plonk_verifier_steps(); - test_plonk_verifier(); + test_plonk_prover_rounds< + libff::bls12_381_pp, + bls12_381_test_vector_transcript_hasher>(); + test_plonk_prover< + libff::bls12_381_pp, + bls12_381_test_vector_transcript_hasher>(); + test_plonk_verifier_steps< + libff::bls12_381_pp, + bls12_381_test_vector_transcript_hasher>(); + test_plonk_verifier< + libff::bls12_381_pp, + bls12_381_test_vector_transcript_hasher>(); } } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index c1645627b..bb02b9218 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -141,7 +141,7 @@ template struct step_eleven_out_t { }; /// Plonk verifier. Verifies object of class plonk_proof. -template class plonk_verifier +template class plonk_verifier { using Field = libff::Fr; @@ -199,7 +199,7 @@ template class plonk_verifier /// \param[out] u: multipoint evaluation challenge - hash of /// transcript static step_four_out_t step_four( - const plonk_proof &proof, transcript_hasher &hasher); + const plonk_proof &proof, transcript_hasher &hasher); /// Verifier Step 5: compute zero polynomial evaluation /// @@ -426,7 +426,7 @@ template class plonk_verifier bool verify_proof( const plonk_proof &proof, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 134311749..dea93dca2 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -24,9 +24,9 @@ verifier_preprocessed_input_t::verifier_preprocessed_input_t( { } -template -verifier_preprocessed_input_t plonk_verifier::preprocessed_input( - const srs &srs) +template +verifier_preprocessed_input_t plonk_verifier:: + preprocessed_input(const srs &srs) { std::vector> Q_polys_at_secret_g1; Q_polys_at_secret_g1.resize(srs.Q_polys.size()); @@ -43,17 +43,20 @@ verifier_preprocessed_input_t plonk_verifier::preprocessed_input( return preprocessed_input; } -template -void plonk_verifier::step_one(const plonk_proof &proof) +template +void plonk_verifier::step_one( + const plonk_proof &proof) { } -template -void plonk_verifier::step_two(const plonk_proof &proof) +template +void plonk_verifier::step_two( + const plonk_proof &proof) { } -template void plonk_verifier::step_three(const srs &srs) +template +void plonk_verifier::step_three(const srs &srs) { } @@ -69,9 +72,9 @@ step_four_out_t::step_four_out_t( { } -template -step_four_out_t plonk_verifier::step_four( - const plonk_proof &proof, transcript_hasher &hasher) +template +step_four_out_t plonk_verifier::step_four( + const plonk_proof &proof, transcript_hasher &hasher) { // add outputs from Round 1 to the hash buffer hasher.add_element(proof.W_polys_blinded_at_secret_g1[a]); @@ -129,8 +132,8 @@ step_five_out_t::step_five_out_t(libff::Fr &&zh_zeta) { } -template -step_five_out_t plonk_verifier::step_five( +template +step_five_out_t plonk_verifier::step_five( const step_four_out_t &step_four_out, const srs &srs) { libff::Fr zh_zeta; @@ -147,8 +150,8 @@ step_six_out_t::step_six_out_t(libff::Fr &&L_0_zeta) { } -template -step_six_out_t plonk_verifier::step_six( +template +step_six_out_t plonk_verifier::step_six( const step_four_out_t &step_four_out, const srs &srs) { libff::Fr L_0_zeta = libfqfft::evaluate_polynomial( @@ -163,8 +166,8 @@ step_seven_out_t::step_seven_out_t(libff::Fr &&PI_zeta) { } -template -step_seven_out_t plonk_verifier::step_seven( +template +step_seven_out_t plonk_verifier::step_seven( const step_four_out_t &step_four_out, const srs &srs) { libff::Fr PI_zeta; @@ -180,8 +183,8 @@ step_eight_out_t::step_eight_out_t(libff::Fr &&r_prime_zeta) { } -template -step_eight_out_t plonk_verifier::step_eight( +template +step_eight_out_t plonk_verifier::step_eight( const step_four_out_t &step_four_out, const step_five_out_t &step_five_out, const step_six_out_t &step_six_out, @@ -217,8 +220,8 @@ step_nine_out_t::step_nine_out_t(libff::G1 &&D1) : D1(D1) { } -template -step_nine_out_t plonk_verifier::step_nine( +template +step_nine_out_t plonk_verifier::step_nine( const step_four_out_t &step_four_out, const step_six_out_t &step_six_out, const plonk_proof &proof, @@ -289,8 +292,8 @@ step_ten_out_t::step_ten_out_t(libff::G1 &&F1) : F1(F1) { } -template -step_ten_out_t plonk_verifier::step_ten( +template +step_ten_out_t plonk_verifier::step_ten( const step_four_out_t &step_four_out, const step_nine_out_t &step_nine_out, const plonk_proof &proof, @@ -338,8 +341,8 @@ step_eleven_out_t::step_eleven_out_t(libff::G1 &&E1) : E1(E1) { } -template -step_eleven_out_t plonk_verifier::step_eleven( +template +step_eleven_out_t plonk_verifier::step_eleven( const step_four_out_t &step_four_out, const step_eight_out_t &step_eight_out, const plonk_proof &proof) @@ -365,8 +368,8 @@ step_eleven_out_t plonk_verifier::step_eleven( return step_eleven_out; } -template -bool plonk_verifier::step_twelve( +template +bool plonk_verifier::step_twelve( const step_four_out_t &step_four_out, const step_ten_out_t &step_ten_out, const step_eleven_out_t &step_eleven_out, @@ -408,11 +411,11 @@ bool plonk_verifier::step_twelve( return b_accept; } -template -bool plonk_verifier::verify_proof( +template +bool plonk_verifier::verify_proof( const plonk_proof &proof, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { // compute verifier preprocessed input const verifier_preprocessed_input_t preprocessed_input = From b423eeccf8f02252f281b5216acbbac6b00fb63b Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 12 Sep 2022 13:02:32 +0100 Subject: [PATCH 16/25] plonk: created a new transcript_hasher.hpp file with just a comment that describes the interface of a common transcript hasher. addresses step 1. from comment https://github.com/clearmatics/libsnark/pull/61#discussion_r966911185 of PR#61. --- .../transcript_hasher/transcript_hasher.hpp | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 libsnark/transcript_hasher/transcript_hasher.hpp diff --git a/libsnark/transcript_hasher/transcript_hasher.hpp b/libsnark/transcript_hasher/transcript_hasher.hpp new file mode 100644 index 000000000..1409c73cf --- /dev/null +++ b/libsnark/transcript_hasher/transcript_hasher.hpp @@ -0,0 +1,32 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_TRANSCRIPT_HASHER_TRANSCRIPT_HASHER_HPP_ +#define LIBSNARK_TRANSCRIPT_HASHER_TRANSCRIPT_HASHER_HPP_ + +// // interface for a common transcript_hasher class used to implement +// // functionality for hashing the communication transcript in ZK proof +// // systems under ./zk_proof_systems +// template class transcript_hasher +// { +// public: +// transcript_hasher(); +// +// // add an Fr element to the transcript buffer for hashing +// void add_element(const libff::Fr &element); +// // add the coordinates of a G1 curve point to the transcript buffer for +// // hashing +// void add_element(const libff::G1 &element); +// // add the coordinates of a G2 curve point to the transcript buffer for +// // hashing +// void add_element(const libff::G2 &element); +// // return the hash value of the communication transcript +// libff::Fr get_hash(); +// }; + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_HPP_ From 0fbd9aba57d4cfb66cbec6acc81223bd6e172fb2 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 12 Sep 2022 14:30:03 +0100 Subject: [PATCH 17/25] plonk: replaced the checks over all valid buffer lengths in the transcript hasher with a while loop directly finding the correct length; addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r964183723 . --- ...ls12_381_test_vector_transcript_hasher.cpp | 77 +++++++------------ 1 file changed, 26 insertions(+), 51 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index a8836e640..043d1bd05 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -121,59 +121,34 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: libff::Fr challenge = 0; - // beta - if (buffer_len == length[0]) { - printf( - "[%s:%d] buffer_len %d: beta\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[0]; // beta - } - // gamma - if (buffer_len == length[1]) { - printf( - "[%s:%d] buffer_len %d: gamma\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[1]; // gamma - } - // alpha - if (buffer_len == length[2]) { - printf( - "[%s:%d] buffer_len %d: alpha\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[2]; // alpha - } - // zeta - if (buffer_len == length[3]) { - printf( - "[%s:%d] buffer_len %d: zeta\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[3]; // zeta - } - // nu - if (buffer_len == length[4]) { - printf( - "[%s:%d] buffer_len %d: nu\n", __FILE__, __LINE__, (int)buffer_len); - challenge = this->hash_values[4]; // nu - } - // u - if (buffer_len == length[5]) { - // reset step to 0 - printf( - "[%s:%d] buffer_len %d: u + clear()\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[5]; // u + // map the index length=0,1...5 to the challenge string=beta, + // gamma, ...; used to print explicitly the challenge string for debug + std::map challenge_str; + challenge_str[0] = "beta"; + challenge_str[1] = "gamma"; + challenge_str[2] = "alpha"; + challenge_str[3] = "zeta"; + challenge_str[4] = "nu"; + challenge_str[5] = "u"; + + // find the mathcing index + size_t i = 0; + while (buffer_len != length[i]) { + ++i; + if (i >= length.size()) { + throw std::logic_error( + "Error: invalid index of transcript hasher buffer"); + } } + printf( + "[%s:%d] buffer_len %d: %s\n", + __FILE__, + __LINE__, + (int)buffer_len, + challenge_str[i].c_str()); + challenge = this->hash_values[i]; // beta + return challenge; } From 0508ed5d6ebeeb0d521e87b92494addd9f27c9cf Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 13 Sep 2022 08:49:02 +0100 Subject: [PATCH 18/25] plonk: replaced challenge_str map with a vector. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r968600750 . --- .../tests/bls12_381_test_vector_transcript_hasher.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 043d1bd05..8e3deae8b 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -123,13 +123,8 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: // map the index length=0,1...5 to the challenge string=beta, // gamma, ...; used to print explicitly the challenge string for debug - std::map challenge_str; - challenge_str[0] = "beta"; - challenge_str[1] = "gamma"; - challenge_str[2] = "alpha"; - challenge_str[3] = "zeta"; - challenge_str[4] = "nu"; - challenge_str[5] = "u"; + std::vector challenge_str = { + "beta", "gamma", "alpha", "zeta", "nu", "u"}; // find the mathcing index size_t i = 0; From 5f62026f28b36cb3b521df1369fc13cc37f245aa Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 13 Sep 2022 08:51:32 +0100 Subject: [PATCH 19/25] plonk: combine two error checks that are functionally the same into one. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r968604416 . --- .../bls12_381_test_vector_transcript_hasher.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 8e3deae8b..2e50d35e6 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -110,15 +110,6 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: // vector of valid lengths (\attention specific to BLS12-381) const std::vector length{288, 320, 416, 704, 896, 1120}; - // If we are here, then the hasher buffer has invalid length so throw an - // exception - bool b_valid_length = - (0 != std::count(length.begin(), length.end(), buffer_len)); - if (!b_valid_length) { - throw std::logic_error( - "Error: invalid length of transcript hasher buffer"); - } - libff::Fr challenge = 0; // map the index length=0,1...5 to the challenge string=beta, @@ -126,13 +117,15 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: std::vector challenge_str = { "beta", "gamma", "alpha", "zeta", "nu", "u"}; - // find the mathcing index + // find the matching index size_t i = 0; while (buffer_len != length[i]) { ++i; if (i >= length.size()) { + // If we are here, then the hasher buffer has invalid length so + // throw an exception throw std::logic_error( - "Error: invalid index of transcript hasher buffer"); + "Error: invalid length of transcript hasher buffer"); } } From 9453d589c3d2b3a02bd7aec2f1f947129c1ad02a Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 13 Sep 2022 11:13:25 +0100 Subject: [PATCH 20/25] plonk: declared const challenge upon assignment in bls12_381_test_vector_transcript_hasher::get_hash(). addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r968605915 . --- .../plonk/tests/bls12_381_test_vector_transcript_hasher.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 2e50d35e6..689935637 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -110,8 +110,6 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: // vector of valid lengths (\attention specific to BLS12-381) const std::vector length{288, 320, 416, 704, 896, 1120}; - libff::Fr challenge = 0; - // map the index length=0,1...5 to the challenge string=beta, // gamma, ...; used to print explicitly the challenge string for debug std::vector challenge_str = { @@ -135,7 +133,9 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: __LINE__, (int)buffer_len, challenge_str[i].c_str()); - challenge = this->hash_values[i]; // beta + + const libff::Fr challenge = + this->hash_values[i]; // beta return challenge; } From 297902668fb821cf92376b2510a8fd82b63bcd4f Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 13 Sep 2022 11:15:40 +0100 Subject: [PATCH 21/25] plonk: removed redundant this-> in get_hash. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r968607769 . --- .../plonk/tests/bls12_381_test_vector_transcript_hasher.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 689935637..453e42be0 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -134,8 +134,7 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: (int)buffer_len, challenge_str[i].c_str()); - const libff::Fr challenge = - this->hash_values[i]; // beta + const libff::Fr challenge = hash_values[i]; // beta return challenge; } From d9234145224e78dd33df03e8880d30d6f6704cb4 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 13 Sep 2022 12:13:50 +0100 Subject: [PATCH 22/25] plonk: created length and challenge arrays as const members of class bls12_381_test_vector_transcript_hasher initialized in the constructor. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r968607447 . --- .../bls12_381_test_vector_transcript_hasher.cpp | 16 +++++----------- .../bls12_381_test_vector_transcript_hasher.hpp | 7 ++++++- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 453e42be0..aed065d54 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -16,6 +16,8 @@ namespace libsnark bls12_381_test_vector_transcript_hasher:: bls12_381_test_vector_transcript_hasher() + : length_array({288, 320, 416, 704, 896, 1120}) + , challenge_array({"beta", "gamma", "alpha", "zeta", "nu", "u"}) { plonk_example example; @@ -107,19 +109,11 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: { size_t buffer_len = this->buffer.size(); - // vector of valid lengths (\attention specific to BLS12-381) - const std::vector length{288, 320, 416, 704, 896, 1120}; - - // map the index length=0,1...5 to the challenge string=beta, - // gamma, ...; used to print explicitly the challenge string for debug - std::vector challenge_str = { - "beta", "gamma", "alpha", "zeta", "nu", "u"}; - // find the matching index size_t i = 0; - while (buffer_len != length[i]) { + while (buffer_len != length_array[i]) { ++i; - if (i >= length.size()) { + if (i >= length_array.size()) { // If we are here, then the hasher buffer has invalid length so // throw an exception throw std::logic_error( @@ -132,7 +126,7 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: __FILE__, __LINE__, (int)buffer_len, - challenge_str[i].c_str()); + challenge_array[i].c_str()); const libff::Fr challenge = hash_values[i]; // beta diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp index fd9be7093..749bd7a49 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp @@ -80,6 +80,11 @@ class bls12_381_test_vector_transcript_hasher // array containing the hash values of the communication transcript // i.e. the six challenges (in this order): beta, gamma, alpha, zeta, nu, u std::array, 6> hash_values; + // vector of valid lengths (\attention specific to BLS12-381) + const std::array length_array; + // map the index length=0,1...5 to the challenge string=beta, + // gamma, ...; used to print explicitly the challenge string for debug + const std::array challenge_array; public: bls12_381_test_vector_transcript_hasher(); @@ -93,7 +98,7 @@ class bls12_381_test_vector_transcript_hasher // hashing void add_element(const libff::G2 &element); - // TODO: use next declaration to implement an actual hash function + // TODO: use following declaration to implement an actual hash function // e.g. BLAKE (from Aztec barretenberg implementation): // https://github.com/AztecProtocol/barretenberg/blob/master/barretenberg/src/aztec/plonk/transcript/transcript.cpp#L33 // From 5e499717c444d0b14d4b4865d9b3940066230f32 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 14 Sep 2022 14:00:54 +0100 Subject: [PATCH 23/25] plonk: amended comments to transcript hasher code according to suggestions in https://github.com/clearmatics/libsnark/pull/61#discussion_r970529544 . --- .../bls12_381_test_vector_transcript_hasher.hpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp index 749bd7a49..a992abff9 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp @@ -12,7 +12,12 @@ namespace libsnark { -/// transcript hasher interface specific to the BLS12-381 curve +/// Implementation of the transcript hasher interface (see +/// transcript_hasher.hpp), returning hard-coded test vector values +/// for the plonk proof system on a specific circuit, using the +/// BLS12-381 curve. Also performs a simple check on the transcript to +/// be hashed to verify correct operation of the plonk prover and +/// verifier. /// /// the hasher works in the Prover as follows: /// @@ -68,7 +73,7 @@ namespace libsnark /// add_element(buffer, W_zeta_omega_eval_exp) /// /// // buffer = first_output + second_output + third_output + fourth_output -/// + fifth_output +/// // + fifth_output /// /// u = hash(str(buffer)) /// @@ -98,13 +103,6 @@ class bls12_381_test_vector_transcript_hasher // hashing void add_element(const libff::G2 &element); - // TODO: use following declaration to implement an actual hash function - // e.g. BLAKE (from Aztec barretenberg implementation): - // https://github.com/AztecProtocol/barretenberg/blob/master/barretenberg/src/aztec/plonk/transcript/transcript.cpp#L33 - // - // std::array - // Blake2sHasher::hash(std::vector const& buffer) - // dummy implementation of get_hash that directly returns the // expected hard-coded hashes for the purposes of unit testing TODO // to be replaced by a call to a proper hash function e.g. SHA2, From 92e7806a5311197dc043cbc9c115b934e0a206b1 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 15 Sep 2022 17:12:14 +0100 Subject: [PATCH 24/25] plonk: replaced while loop in get_hash with for loop; assert-ed that length and challenge arrays are of same length in transcript hasher constructor; minor edits. addresses lates comments in PR #61 . --- ...ls12_381_test_vector_transcript_hasher.cpp | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index aed065d54..6cbc0cb1b 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -19,14 +19,16 @@ bls12_381_test_vector_transcript_hasher:: : length_array({288, 320, 416, 704, 896, 1120}) , challenge_array({"beta", "gamma", "alpha", "zeta", "nu", "u"}) { + assert(length_array.size() == challenge_array.size()); + plonk_example example; // initialize to empty vector - this->buffer.clear(); + buffer.clear(); // test array containing the expected hash values of the communication // transcript i.e. the communication challenges (in this order): beta, // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 - this->hash_values = { + hash_values = { example.beta, example.gamma, example.alpha, @@ -107,30 +109,25 @@ void bls12_381_test_vector_transcript_hasher::add_element( libff::Fr bls12_381_test_vector_transcript_hasher:: get_hash() { - size_t buffer_len = this->buffer.size(); - - // find the matching index - size_t i = 0; - while (buffer_len != length_array[i]) { - ++i; - if (i >= length_array.size()) { - // If we are here, then the hasher buffer has invalid length so - // throw an exception - throw std::logic_error( - "Error: invalid length of transcript hasher buffer"); + const size_t buffer_len = this->buffer.size(); + + // find the matching index and return the corresponding challenge. + for (size_t i = 0; i < length_array.size(); ++i) { + if (buffer_len == length_array[i]) { + printf( + "[%s:%d] buffer_len %d: %s\n", + __FILE__, + __LINE__, + (int)buffer_len, + challenge_array[i].c_str()); + + return hash_values[i]; } } - printf( - "[%s:%d] buffer_len %d: %s\n", - __FILE__, - __LINE__, - (int)buffer_len, - challenge_array[i].c_str()); - - const libff::Fr challenge = hash_values[i]; // beta - - return challenge; + // If we are here, then the hasher buffer has invalid length so + // throw an exception + throw std::logic_error("Error: invalid length of transcript hasher buffer"); } } // namespace libsnark From a30695f2b0e3a629a89b7cfa66b2411f9ccac567 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 16 Sep 2022 08:04:02 +0100 Subject: [PATCH 25/25] plonk: renamed example.tcc to example.cpp. added example.cpp and bls12_381_test_vector_transcript_hasher.cpp to CMakeLists.txt. added several headers to fix compilation errors. --- libsnark/CMakeLists.txt | 2 +- libsnark/zk_proof_systems/plonk/circuit.hpp | 2 ++ .../plonk/tests/bls12_381_test_vector_transcript_hasher.cpp | 2 ++ .../plonk/tests/bls12_381_test_vector_transcript_hasher.hpp | 6 ++++-- .../plonk/tests/{example.tcc => example.cpp} | 1 + libsnark/zk_proof_systems/plonk/tests/example.hpp | 4 ---- libsnark/zk_proof_systems/plonk/utils.hpp | 2 ++ 7 files changed, 12 insertions(+), 7 deletions(-) rename libsnark/zk_proof_systems/plonk/tests/{example.tcc => example.cpp} (99%) diff --git a/libsnark/CMakeLists.txt b/libsnark/CMakeLists.txt index 018748dcb..aac1a4492 100644 --- a/libsnark/CMakeLists.txt +++ b/libsnark/CMakeLists.txt @@ -200,7 +200,7 @@ if ("${IS_LIBSNARK_PARENT}") libsnark_test(test_r1cs_ppzksnark_verifier_gadget gadgetlib1/tests/test_r1cs_ppzksnark_verifier_gadget.cpp) libsnark_test(test_r1cs_gg_ppzksnark_verifier_gadget gadgetlib1/tests/test_r1cs_gg_ppzksnark_verifier_gadget.cpp) libsnark_test(test_kzg10_verifier_gadget gadgetlib1/tests/test_kzg10_verifier_gadget.cpp) - libsnark_test(test_plonk zk_proof_systems/plonk/tests/test_plonk.cpp) + libsnark_test(test_plonk zk_proof_systems/plonk/tests/example.cpp zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp zk_proof_systems/plonk/tests/test_plonk.cpp) # TODO (howardwu): Resolve runtime on targets: # libsnark_test(gadgetlib1_fooram_test gadgetlib1/gadgets/cpu_checkers/foora# m/examples/test_fooram.cpp) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index dd05fddd1..bbffccb65 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -11,6 +11,8 @@ #include "libsnark/zk_proof_systems/plonk/utils.hpp" +#include + /// Declaration of Common Preprocessed Input data structures for a /// specific arithmetic circuit. /// diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 6cbc0cb1b..fb9094bad 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -9,6 +9,8 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_CPP_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_CPP_ +#include "libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp" + // Implementation of the transcript hasher interface specific to the BLS12-381 // curve. See bls12_381_test_vector_transcript_hasher.hpp namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp index a992abff9..027afff2b 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp @@ -9,6 +9,10 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ +#include "libsnark/zk_proof_systems/plonk/utils.hpp" + +#include + namespace libsnark { @@ -118,6 +122,4 @@ class bls12_381_test_vector_transcript_hasher } // namespace libsnark -#include "libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp" - #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/tests/example.tcc b/libsnark/zk_proof_systems/plonk/tests/example.cpp similarity index 99% rename from libsnark/zk_proof_systems/plonk/tests/example.tcc rename to libsnark/zk_proof_systems/plonk/tests/example.cpp index 81032512e..9ab2bfcf9 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.tcc +++ b/libsnark/zk_proof_systems/plonk/tests/example.cpp @@ -10,6 +10,7 @@ // Instantiation of the test vector values from the Python implementation // of the Plonk protocol. \see example.hpp . +#include "libsnark/zk_proof_systems/plonk/tests/example.hpp" namespace libsnark { diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index fbc443ebe..de2431609 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -31,8 +31,6 @@ #include "libsnark/zk_proof_systems/plonk/circuit.hpp" #include -#include -#include #include namespace libsnark @@ -307,6 +305,4 @@ class plonk_example } // namespace libsnark -#include - #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 9daba2ef4..ad9386dfb 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -12,6 +12,8 @@ #include "libsnark/zk_proof_systems/plonk/tests/example.hpp" #include +#include +#include #include // enable debug checks. in particular enable comparisons to test