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 2a2312688..c1b23e011 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; @@ -212,6 +225,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)); @@ -253,6 +269,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, @@ -261,7 +280,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; @@ -473,6 +493,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), @@ -533,12 +558,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; @@ -568,6 +597,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), @@ -636,6 +673,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, @@ -648,7 +688,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; @@ -920,6 +961,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), @@ -1016,28 +1062,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 @@ -1054,7 +1112,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 5b34f3e47..81b5ab3ad 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -180,21 +180,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 2977770b0..ac04939f9 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -72,19 +72,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" @@ -97,38 +177,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 9a41f8bbf..031cce9a1 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -280,11 +280,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); print_vector(round_one_out.W_polys[i]); @@ -319,10 +320,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__); print_vector(round_two_out.z_poly); ASSERT_EQ(round_two_out.z_poly, example.z_poly); @@ -344,10 +346,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__); print_vector(round_three_out.t_poly_long); @@ -374,10 +384,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 "); @@ -416,7 +427,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, @@ -429,7 +441,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 "); @@ -478,32 +491,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, @@ -513,20 +553,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, @@ -540,7 +621,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 @@ -611,8 +693,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; @@ -889,8 +971,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; @@ -903,7 +985,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 @@ -988,8 +1070,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 8ad729a01..cff18f2db 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); @@ -622,7 +661,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 =