diff --git a/tachyon/zk/plonk/vanishing/BUILD.bazel b/tachyon/zk/plonk/vanishing/BUILD.bazel index bc8af2121..43f9d184c 100644 --- a/tachyon/zk/plonk/vanishing/BUILD.bazel +++ b/tachyon/zk/plonk/vanishing/BUILD.bazel @@ -31,6 +31,22 @@ tachyon_cc_library( ], ) +tachyon_cc_library( + name = "prover_vanishing_argument", + hdrs = ["prover_vanishing_argument.h"], + deps = [ + ":vanishing_committed", + ":vanishing_constructed", + ":vanishing_evaluated", + ":vanishing_utils", + "//tachyon/base:parallelize", + "//tachyon/crypto/transcripts:transcript", + "//tachyon/zk/base:prover_query", + "//tachyon/zk/base/entities:entity_ty", + "//tachyon/zk/base/entities:prover", + ], +) + tachyon_cc_library( name = "value_source", srcs = ["value_source.cc"], @@ -58,6 +74,68 @@ tachyon_cc_library( ], ) +tachyon_cc_library( + name = "vanishing_committed", + hdrs = ["vanishing_committed.h"], + deps = ["//tachyon/zk/base/entities:entity_ty"], +) + +tachyon_cc_library( + name = "vanishing_constructed", + hdrs = ["vanishing_constructed.h"], + deps = [ + ":vanishing_committed", + "//tachyon/zk/base/entities:entity_ty", + ], +) + +tachyon_cc_library( + name = "vanishing_evaluated", + hdrs = ["vanishing_evaluated.h"], + deps = [ + ":vanishing_committed", + "//tachyon/zk/base/entities:entity_ty", + ], +) + +tachyon_cc_library( + name = "vanishing_partially_evaluated", + hdrs = ["vanishing_partially_evaluated.h"], +) + +tachyon_cc_library( + name = "vanishing_utils", + hdrs = ["vanishing_utils.h"], + deps = ["//tachyon/base:parallelize"], +) + +tachyon_cc_library( + name = "verifier_vanishing_argument", + hdrs = ["verifier_vanishing_argument.h"], + deps = [ + ":vanishing_committed", + ":vanishing_constructed", + ":vanishing_evaluated", + ":vanishing_partially_evaluated", + "//tachyon/crypto/transcripts:transcript", + "//tachyon/zk/base:verifier_query", + "//tachyon/zk/plonk/keys:verifying_key", + ], +) + +tachyon_cc_unittest( + name = "vanishing_argument_unittests", + srcs = ["vanishing_argument_unittest.cc"], + deps = [ + ":prover_vanishing_argument", + ":verifier_vanishing_argument", + "//tachyon/zk/base/entities:verifier", + "//tachyon/zk/base/halo2:halo2_prover_test", + "//tachyon/zk/plonk/circuit/examples:simple_circuit", + "//tachyon/zk/plonk/keys/halo2:pinned_verifying_key", + ], +) + tachyon_cc_unittest( name = "vanishing_unittests", srcs = [ diff --git a/tachyon/zk/plonk/vanishing/prover_vanishing_argument.h b/tachyon/zk/plonk/vanishing/prover_vanishing_argument.h new file mode 100644 index 000000000..00335811b --- /dev/null +++ b/tachyon/zk/plonk/vanishing/prover_vanishing_argument.h @@ -0,0 +1,145 @@ +// Copyright 2020-2022 The Electric Coin Company +// Copyright 2022 The Halo2 developers +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.halo2 and the LICENCE-APACHE.halo2 +// file. + +#ifndef TACHYON_ZK_PLONK_VANISHING_PROVER_VANISHING_ARGUMENT_H_ +#define TACHYON_ZK_PLONK_VANISHING_PROVER_VANISHING_ARGUMENT_H_ + +#include +#include +#include + +#include "tachyon/base/parallelize.h" +#include "tachyon/crypto/transcripts/transcript.h" +#include "tachyon/zk/base/entities/entity_ty.h" +#include "tachyon/zk/base/entities/prover.h" +#include "tachyon/zk/base/prover_query.h" +#include "tachyon/zk/plonk/vanishing/vanishing_committed.h" +#include "tachyon/zk/plonk/vanishing/vanishing_constructed.h" +#include "tachyon/zk/plonk/vanishing/vanishing_evaluated.h" +#include "tachyon/zk/plonk/vanishing/vanishing_utils.h" + +namespace tachyon::zk { + +template +[[nodiscard]] bool VanishingCommit( + Prover* prover, VanishingCommitted* out) { + // Sample a random polynomial of degree n - 1 + const typename PCSTy::Evals random_eval = + PCSTy::Evals::One(prover->pcs().N()); + typename PCSTy::Poly random_poly = prover->domain()->IFFT(random_eval); + + // Sample a random blinding factor + // TODO(TomTaehoonKim): Figure out why it is named |random_blind|. + // See + // https://github.com/kroma-network/halo2/blob/7d0a36990452c8e7ebd600de258420781a9b7917/halo2_proofs/src/plonk/vanishing/prover.rs#L55-L56 + typename PCSTy::Field random_blind = PCSTy::Field::Zero(); + + if (!prover->Commit(random_poly)) return false; + + *out = {std::move(random_poly), std::move(random_blind)}; + return true; +} + +template +[[nodiscard]] bool VanishingConstruct( + Prover* prover, + VanishingCommitted&& committed, + const ExtendedEvals& linear_combination_of_gates, + VanishingConstructed* constructed_out) { + // Divide by t(X) = X^{params.n} - 1. + ExtendedEvals h_evals = DivideByVanishingPoly( + linear_combination_of_gates, prover->extended_domain(), prover->domain()); + + // Obtain final h(X) polynomial + typename PCSTy::ExtendedPoly h_poly = + ExtendedToCoeff( + h_evals, prover->extended_domain()); + + // Truncate it to match the size of the quotient polynomial; the + // evaluation domain might be slightly larger than necessary because + // it always lies on a power-of-two boundary. + std::vector h_coeffs = + h_poly.coefficients().coefficients(); + h_coeffs.resize(prover->extended_domain()->size(), PCSTy::Field::Zero()); + + // Compute commitments to each h(X) piece + const size_t kCommitmentNum = h_coeffs.size() / prover->pcs().N(); + + std::vector results = base::ParallelizeMapByChunkSize( + h_coeffs, prover->pcs().N(), + [prover](absl::Span h_piece, + size_t chunk_index) { return prover->Commit(h_piece); }); + if (std::any_of(results.begin(), results.end(), + [](bool result) { return result == false; })) { + return false; + } + + // FIXME(TomTaehoonKim): Remove this if possible. + std::vector h_blinds = base::CreateVector( + kCommitmentNum, [prover]() { return prover->blinder().Generate(); }); + + *constructed_out = {std::move(h_poly), std::move(h_blinds), + std::move(committed)}; + return true; +} + +template +[[nodiscard]] bool VanishingEvaluate( + const PCSTy& pcs, + VanishingConstructed&& constructed, + const crypto::Challenge255& x, const F& x_n, + crypto::TranscriptWriter* writer, + VanishingEvaluated* evaluated_out) { + typename PCSTy::Poly h_poly = PCSTy::Poly::Zero(); + auto h_chunks = base::Chunked( + constructed.h_poly().coefficients().coefficients(), pcs.N()); + auto h_pieces = + base::Map(h_chunks.begin(), h_chunks.end(), + [](const absl::Span& h_piece) { return h_piece; }); + for (absl::Span h_piece : base::Reversed(h_pieces)) { + std::vector h_vec(h_piece.begin(), h_piece.end()); + h_poly = h_poly * x_n + + typename PCSTy::Poly( + typename PCSTy::Poly::Coefficients(std::move(h_vec))); + } + + F h_blind = std::accumulate(constructed.h_blinds().rbegin(), + constructed.h_blinds().rend(), F::Zero(), + [&x_n](F& acc, const F& eval) { + acc *= x_n; + return acc + eval; + }); + + VanishingCommitted committed = + std::move(std::move(constructed).TakeCommitted()); + F random_eval = committed.random_poly().Evaluate(x.ChallengeAsScalar()); + if (!writer->WriteToProof(random_eval)) return false; + + *evaluated_out = {std::move(h_poly), std::move(h_blind), + std::move(committed)}; + return true; +} + +template +std::vector> VanishingOpen( + VanishingEvaluated&& evaluated, + const crypto::Challenge255& x) { + F x_scalar = x.ChallengeAsScalar(); + VanishingCommitted&& committed = + std::move(evaluated).TakeCommitted(); + return {{x_scalar, BlindedPolynomial( + std::move(evaluated).TakeHPoly(), + std::move(evaluated).TakeHBlind()) + .ToRef()}, + {x_scalar, BlindedPolynomial( + std::move(committed).TakeRandomPoly(), + std::move(committed).TakeRandomBlind()) + .ToRef()}}; +} + +} // namespace tachyon::zk + +#endif // TACHYON_ZK_PLONK_VANISHING_PROVER_VANISHING_ARGUMENT_H_ diff --git a/tachyon/zk/plonk/vanishing/vanishing_argument_unittest.cc b/tachyon/zk/plonk/vanishing/vanishing_argument_unittest.cc new file mode 100644 index 000000000..b2c6444c6 --- /dev/null +++ b/tachyon/zk/plonk/vanishing/vanishing_argument_unittest.cc @@ -0,0 +1,73 @@ +// Copyright 2020-2022 The Electric Coin Company +// Copyright 2022 The Halo2 developers +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.halo2 and the LICENCE-APACHE.halo2 +// file. + +#include "gtest/gtest.h" + +#include "tachyon/zk/base/entities/verifier.h" +#include "tachyon/zk/base/halo2/halo2_prover_test.h" +#include "tachyon/zk/plonk/circuit/examples/simple_circuit.h" +#include "tachyon/zk/plonk/keys/halo2/pinned_verifying_key.h" +#include "tachyon/zk/plonk/vanishing/prover_vanishing_argument.h" +#include "tachyon/zk/plonk/vanishing/verifier_vanishing_argument.h" + +namespace tachyon::zk { + +namespace { + +class VanishingArgumentTest : public Halo2ProverTest {}; + +} // namespace + +TEST_F(VanishingArgumentTest, VanishingArgument) { + VanishingCommitted committed_p; + ASSERT_TRUE(VanishingCommit(prover_.get(), &committed_p)); + + ExtendedEvals extended_evals = ExtendedEvals::One(kMaxExtendedDegree); + VanishingConstructed constructed_p; + ASSERT_TRUE(VanishingConstruct(prover_.get(), std::move(committed_p), + extended_evals, &constructed_p)); + + crypto::Challenge255 x(F::One()); + VanishingEvaluated evaluated; + ASSERT_TRUE(VanishingEvaluate(prover_->pcs(), std::move(constructed_p), x, + F::One(), prover_->GetWriter(), &evaluated)); + + std::vector> h_x = VanishingOpen(std::move(evaluated), x); + + base::Buffer read_buf(prover_->GetWriter()->buffer().buffer(), + prover_->GetWriter()->buffer().buffer_len()); + std::unique_ptr> reader = + absl::WrapUnique( + new crypto::PoseidonReader(std::move(read_buf))); + + std::unique_ptr> verifier = std::make_unique>( + Verifier(prover_->TakePCS(), std::move(reader))); + verifier->set_domain(prover_->TakeDomain()); + verifier->set_extended_domain(prover_->TakeExtendedDomain()); + + VanishingCommitted committed_v; + ASSERT_TRUE(ReadCommitmentsBeforeY(verifier->GetReader(), &committed_v)); + + SimpleCircuit circuit = SimpleCircuit(); + VerifyingKey vkey; + ASSERT_TRUE(VerifyingKey::Generate(verifier.get(), circuit, &vkey)); + VanishingConstructed constructed_v; + ASSERT_TRUE(ReadCommitmentsAfterY(std::move(committed_v), vkey, + verifier->GetReader(), &constructed_v)); + + VanishingPartiallyEvaluated partially_evaluated_v; + ASSERT_TRUE(EvaluateAfterX(std::move(constructed_v), verifier->GetReader(), + &partially_evaluated_v)); + + crypto::Challenge255 y(F::One()); + Evals evals = Evals::One(kMaxDegree); + VanishingEvaluated evaluated_v = + VanishingVerify(std::move(partially_evaluated_v), evals, y, F(2)); + + VanishingQueries(std::move(evaluated_v), x); +} + +} // namespace tachyon::zk diff --git a/tachyon/zk/plonk/vanishing/vanishing_committed.h b/tachyon/zk/plonk/vanishing/vanishing_committed.h new file mode 100644 index 000000000..6dad6cce6 --- /dev/null +++ b/tachyon/zk/plonk/vanishing/vanishing_committed.h @@ -0,0 +1,58 @@ +// Copyright 2020-2022 The Electric Coin Company +// Copyright 2022 The Halo2 developers +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.halo2 and the LICENCE-APACHE.halo2 +// file. + +#ifndef TACHYON_ZK_PLONK_VANISHING_VANISHING_COMMITTED_H_ +#define TACHYON_ZK_PLONK_VANISHING_VANISHING_COMMITTED_H_ + +#include + +#include "tachyon/zk/base/entities/entity_ty.h" + +namespace tachyon::zk { + +template +class VanishingCommitted; + +template +class VanishingCommitted { + public: + VanishingCommitted() = default; + VanishingCommitted(typename PCSTy::Poly&& random_poly, + typename PCSTy::Field&& random_blind) + : random_poly_(std::move(random_poly)), + random_blind_(std::move(random_blind)) {} + + const typename PCSTy::Poly& random_poly() { return random_poly_; } + + typename PCSTy::Poly&& TakeRandomPoly() && { return std::move(random_poly_); } + typename PCSTy::Field&& TakeRandomBlind() && { + return std::move(random_blind_); + } + + private: + typename PCSTy::Poly random_poly_; + typename PCSTy::Field random_blind_; +}; + +template +class VanishingCommitted { + public: + VanishingCommitted() = default; + explicit VanishingCommitted( + typename PCSTy::Commitment&& random_poly_commitment) + : random_poly_commitment_(std::move(random_poly_commitment)) {} + + typename PCSTy::Commitment&& TakeRandomPolyCommitment() && { + return std::move(random_poly_commitment_); + } + + private: + typename PCSTy::Commitment random_poly_commitment_; +}; + +} // namespace tachyon::zk + +#endif // TACHYON_ZK_PLONK_VANISHING_VANISHING_COMMITTED_H_ diff --git a/tachyon/zk/plonk/vanishing/vanishing_constructed.h b/tachyon/zk/plonk/vanishing/vanishing_constructed.h new file mode 100644 index 000000000..65df7444a --- /dev/null +++ b/tachyon/zk/plonk/vanishing/vanishing_constructed.h @@ -0,0 +1,70 @@ +// Copyright 2020-2022 The Electric Coin Company +// Copyright 2022 The Halo2 developers +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.halo2 and the LICENCE-APACHE.halo2 +// file. + +#ifndef TACHYON_ZK_PLONK_VANISHING_VANISHING_CONSTRUCTED_H_ +#define TACHYON_ZK_PLONK_VANISHING_VANISHING_CONSTRUCTED_H_ + +#include +#include + +#include "tachyon/zk/base/entities/entity_ty.h" +#include "tachyon/zk/plonk/vanishing/vanishing_committed.h" + +namespace tachyon::zk { + +template +class VanishingConstructed; + +template +class VanishingConstructed { + public: + VanishingConstructed() = default; + VanishingConstructed(typename PCSTy::ExtendedPoly&& h_poly, + std::vector&& h_blinds, + VanishingCommitted&& committed) + : h_poly_(std::move(h_poly)), + h_blinds_(std::move(h_blinds)), + committed_(std::move(committed)) {} + + const typename PCSTy::ExtendedPoly& h_poly() const { return h_poly_; } + const std::vector& h_blinds() const { + return h_blinds_; + } + + VanishingCommitted&& TakeCommitted() && { + return std::move(committed_); + } + + private: + typename PCSTy::ExtendedPoly h_poly_; + std::vector h_blinds_; + VanishingCommitted committed_; +}; + +template +class VanishingConstructed { + public: + VanishingConstructed() = default; + VanishingConstructed(std::vector&& h_commitments, + typename PCSTy::Commitment&& random_poly_commitment) + : h_commitments_(std::move(h_commitments)), + random_poly_commitment_(std::move(random_poly_commitment)) {} + + std::vector&& TakeHCommitments() && { + return std::move(h_commitments_); + } + typename PCSTy::Commitment&& TakeRandomPolyCommitment() && { + return std::move(random_poly_commitment_); + } + + private: + std::vector h_commitments_; + typename PCSTy::Commitment random_poly_commitment_; +}; + +} // namespace tachyon::zk + +#endif // TACHYON_ZK_PLONK_VANISHING_VANISHING_CONSTRUCTED_H_ diff --git a/tachyon/zk/plonk/vanishing/vanishing_evaluated.h b/tachyon/zk/plonk/vanishing/vanishing_evaluated.h new file mode 100644 index 000000000..779523da8 --- /dev/null +++ b/tachyon/zk/plonk/vanishing/vanishing_evaluated.h @@ -0,0 +1,79 @@ +// Copyright 2020-2022 The Electric Coin Company +// Copyright 2022 The Halo2 developers +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.halo2 and the LICENCE-APACHE.halo2 +// file. + +#ifndef TACHYON_ZK_PLONK_VANISHING_VANISHING_EVALUATED_H_ +#define TACHYON_ZK_PLONK_VANISHING_VANISHING_EVALUATED_H_ + +#include +#include + +#include "tachyon/zk/base/entities/entity_ty.h" +#include "tachyon/zk/plonk/vanishing/vanishing_committed.h" + +namespace tachyon::zk { + +template +class VanishingEvaluated; + +template +class VanishingEvaluated { + public: + VanishingEvaluated() = default; + VanishingEvaluated(typename PCSTy::Poly&& h_poly, + typename PCSTy::Field&& h_blind, + VanishingCommitted&& committed) + : h_poly_(std::move(h_poly)), + h_blind_(std::move(h_blind)), + committed_(std::move(committed)) {} + + typename PCSTy::Poly&& TakeHPoly() && { return std::move(h_poly_); } + typename PCSTy::Field&& TakeHBlind() && { return std::move(h_blind_); } + VanishingCommitted&& TakeCommitted() && { + return std::move(committed_); + } + + private: + typename PCSTy::Poly h_poly_; + typename PCSTy::Field h_blind_; + VanishingCommitted committed_; +}; + +template +class VanishingEvaluated { + public: + VanishingEvaluated() = default; + VanishingEvaluated(typename PCSTy::Commitment&& h_commitment, + typename PCSTy::Commitment&& random_poly_commitment, + typename PCSTy::Field&& expected_h_eval, + typename PCSTy::Field&& random_eval) + : h_commitment_(std::move(h_commitment)), + random_poly_commitment_(std::move(random_poly_commitment)), + expected_h_eval_(std::move(expected_h_eval)), + random_eval_(std::move(random_eval)) {} + + const typename PCSTy::Commitment& h_commitment() const { + return h_commitment_; + } + const typename PCSTy::Commitment& random_poly_commitment() const { + return std::move(random_poly_commitment_); + } + typename PCSTy::Field&& TakeExpectedHEval() && { + return std::move(expected_h_eval_); + } + typename PCSTy::Field&& TakeRandomEval() && { + return std::move(random_eval_); + } + + private: + typename PCSTy::Commitment h_commitment_; + typename PCSTy::Commitment random_poly_commitment_; + typename PCSTy::Field expected_h_eval_; + typename PCSTy::Field random_eval_; +}; + +} // namespace tachyon::zk + +#endif // TACHYON_ZK_PLONK_VANISHING_VANISHING_EVALUATED_H_ diff --git a/tachyon/zk/plonk/vanishing/vanishing_partially_evaluated.h b/tachyon/zk/plonk/vanishing/vanishing_partially_evaluated.h new file mode 100644 index 000000000..d52fca911 --- /dev/null +++ b/tachyon/zk/plonk/vanishing/vanishing_partially_evaluated.h @@ -0,0 +1,45 @@ +// Copyright 2020-2022 The Electric Coin Company +// Copyright 2022 The Halo2 developers +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.halo2 and the LICENCE-APACHE.halo2 +// file. + +#ifndef TACHYON_ZK_PLONK_VANISHING_VANISHING_PARTIALLY_EVALUATED_H_ +#define TACHYON_ZK_PLONK_VANISHING_VANISHING_PARTIALLY_EVALUATED_H_ + +#include +#include + +namespace tachyon::zk { + +template +class VanishingPartiallyEvaluated { + public: + VanishingPartiallyEvaluated() = default; + VanishingPartiallyEvaluated( + std::vector&& h_commitments, + typename PCSTy::Commitment&& random_poly_commitment, + typename PCSTy::Field&& random_eval) + : h_commitments_(std::move(h_commitments)), + random_poly_commitment_(std::move(random_poly_commitment)), + random_eval_(std::move(random_eval)) {} + + const std::vector& h_commitments() const { + return h_commitments_; + } + typename PCSTy::Commitment&& TakeRandomPolyCommitment() && { + return std::move(random_poly_commitment_); + } + typename PCSTy::Field&& TakeRandomEval() && { + return std::move(random_eval_); + } + + private: + std::vector h_commitments_; + typename PCSTy::Commitment random_poly_commitment_; + typename PCSTy::Field random_eval_; +}; + +} // namespace tachyon::zk + +#endif // TACHYON_ZK_PLONK_VANISHING_VANISHING_PARTIALLY_EVALUATED_H_ diff --git a/tachyon/zk/plonk/vanishing/vanishing_utils.h b/tachyon/zk/plonk/vanishing/vanishing_utils.h new file mode 100644 index 000000000..e6e79b591 --- /dev/null +++ b/tachyon/zk/plonk/vanishing/vanishing_utils.h @@ -0,0 +1,133 @@ +// Copyright 2020-2022 The Electric Coin Company +// Copyright 2022 The Halo2 developers +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.halo2 and the LICENCE-APACHE.halo2 +// file. + +#ifndef TACHYON_ZK_PLONK_VANISHING_VANISHING_UTILS_H_ +#define TACHYON_ZK_PLONK_VANISHING_VANISHING_UTILS_H_ + +#include +#include + +#include "tachyon/base/parallelize.h" + +namespace tachyon::zk { + +// Calculate ζ⁻¹ = g^((2ˢ * T) / 3). +// NOTE(TomTaehoonKim): Halo2 calculates ζ = g^((2ˢ * T) / 3)². So in need of +// ζ, square the result of this function. +template +constexpr F GetZetaInv() { + CHECK_EQ(F::Config::kTrace % math::BigInt(3), + math::BigInt(0)); + return F::FromMontgomery(F::Config::kSubgroupGenerator) + .Pow(F(2).Pow(F::Config::kTwoAdicity).ToBigInt() * F::Config::kTrace / + math::BigInt(3)); +} + +// This divides the polynomial (in the extended domain) by the vanishing +// polynomial of the 2ᵏ size domain. +template +ExtendedEvals DivideByVanishingPoly(const ExtendedEvals& evals, + const ExtendedDomain* extended_domain, + const Domain* domain) { + CHECK_EQ(evals.NumElements(), extended_domain->size()); + + F zeta = GetZetaInv().Square(); + + // Compute the evaluations of t(X) = Xⁿ - 1 in the coset evaluation domain. + // We don't have to compute all of them, because it will repeat. + std::vector t_evaluations; + t_evaluations.reserve(size_t{1} << (extended_domain->log_size_of_group() - + domain->log_size_of_group())); + F orig = zeta.Pow(domain->size()); + F step = extended_domain->group_gen().Pow(domain->size()); + F cur = orig; + do { + t_evaluations.push_back(cur); + cur *= step; + } while (cur != orig); + CHECK_EQ(t_evaluations.size(), + size_t{1} << (extended_domain->log_size_of_group() - + domain->log_size_of_group())); + + // Subtract 1 from each to give us t_evaluations[i] = t(zeta * + // extended_omegaⁱ) + // TODO(TomTaehoonKim): Consider implementing "translate" function. + base::Parallelize(t_evaluations, [](absl::Span chunk) { + for (F& coeff : chunk) { + coeff -= F::One(); + } + }); + + F::BatchInverseInPlace(t_evaluations); + + // Multiply the inverse to obtain the quotient polynomial in the coset + // evaluation domain. + std::vector evaluations = evals.evaluations(); + base::Parallelize(evaluations, + [t_evaluations](absl::Span chunk, size_t chunk_idx, + size_t chunk_size) { + size_t index = chunk_idx * chunk_size; + for (F& h : chunk) { + h *= t_evaluations[index % t_evaluations.size()]; + ++index; + } + }); + + return ExtendedEvals(std::move(evaluations)); +} + +// Given a |poly| of coefficients [a₀, a₁, a₂, ...], this returns +// [a₀, ζa₁, ζ²a₂, a₃, ζa₄, ζ²a₅, a₆, ...], where ζ is a cube root of unity in +// the multiplicative subgroup with order (p - 1), i.e. ζ³ = 1. +// +// |into_coset| should be set to true when moving into the coset, and false +// when moving out. This toggles the choice of ζ. +template +void DistributePowersZeta(const ExtendedPoly& poly, bool into_coset) { + F zeta_inv = GetZetaInv(); + F zeta = zeta_inv.Square(); + std::vector coset_powers{into_coset ? zeta : zeta_inv, + into_coset ? zeta_inv : zeta}; + + std::vector coeffs = poly.coefficients().coefficients(); + base::Parallelize(coeffs, + [&coset_powers](absl::Span chunk, size_t chunk_idx, + size_t chunk_size) { + size_t i = chunk_idx * chunk_size; + for (F& a : chunk) { + // Distribute powers to move into/from coset + size_t j = i % (coset_powers.size() + 1); + if (j != 0) { + a *= coset_powers[j - 1]; + } + ++i; + } + }); +} + +// This takes us from the extended evaluation domain and gets us the quotient +// polynomial coefficients. +// +// This function will panic if the provided vector is not the correct length. +template +ExtendedPoly ExtendedToCoeff(const ExtendedEvals& evals, + const ExtendedDomain* extended_domain) { + CHECK_EQ(evals.NumElements(), extended_domain->size()); + + ExtendedPoly poly = extended_domain->IFFT(evals); + + // Distribute powers to move from coset; opposite from the + // transformation we performed earlier. + DistributePowersZeta(poly, false); + + return poly; +} + +} // namespace tachyon::zk + +#endif // TACHYON_ZK_PLONK_VANISHING_VANISHING_UTILS_H_ diff --git a/tachyon/zk/plonk/vanishing/verifier_vanishing_argument.h b/tachyon/zk/plonk/vanishing/verifier_vanishing_argument.h new file mode 100644 index 000000000..500611837 --- /dev/null +++ b/tachyon/zk/plonk/vanishing/verifier_vanishing_argument.h @@ -0,0 +1,113 @@ +// Copyright 2020-2022 The Electric Coin Company +// Copyright 2022 The Halo2 developers +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.halo2 and the LICENCE-APACHE.halo2 +// file. + +#ifndef TACHYON_ZK_PLONK_VANISHING_VERIFIER_VANISHING_ARGUMENT_H_ +#define TACHYON_ZK_PLONK_VANISHING_VERIFIER_VANISHING_ARGUMENT_H_ + +#include +#include + +#include "tachyon/base/ref.h" +#include "tachyon/crypto/transcripts/transcript.h" +#include "tachyon/zk/base/entities/entity_ty.h" +#include "tachyon/zk/base/verifier_query.h" +#include "tachyon/zk/plonk/keys/verifying_key.h" +#include "tachyon/zk/plonk/vanishing/vanishing_committed.h" +#include "tachyon/zk/plonk/vanishing/vanishing_constructed.h" +#include "tachyon/zk/plonk/vanishing/vanishing_evaluated.h" +#include "tachyon/zk/plonk/vanishing/vanishing_partially_evaluated.h" + +namespace tachyon::zk { + +template +[[nodiscard]] bool ReadCommitmentsBeforeY( + crypto::TranscriptReader* transcript, + VanishingCommitted* out) { + Commitment c; + if (!transcript->ReadPoint(&c)) return false; + + *out = VanishingCommitted{std::move(c)}; + return true; +} + +template +[[nodiscard]] bool ReadCommitmentsAfterY( + VanishingCommitted&& committed, + const VerifyingKey& vk, + crypto::TranscriptReader* transcript, + VanishingConstructed* out) { + // Obtain a commitment to h(X) in the form of multiple pieces of degree + // n - 1 + std::vector h_commitments; + size_t quotient_poly_degree = vk.constraint_system().ComputeDegree() - 1; + h_commitments.reserve(quotient_poly_degree); + for (Commitment& commitment : h_commitments) { + if (!transcript->ReadPoint(&commitment)) return false; + } + + *out = {std::move(h_commitments), + std::move(committed).TakeRandomPolyCommitment()}; + return true; +} + +template +[[nodiscard]] bool EvaluateAfterX( + VanishingConstructed&& constructed, + crypto::TranscriptReader* transcript, + VanishingPartiallyEvaluated* out) { + F random_eval; + if (!transcript->ReadScalar(&random_eval)) return false; + + *out = {std::move(constructed).TakeHCommitments(), + std::move(constructed).TakeRandomPolyCommitment(), + std::move(random_eval)}; + return true; +} + +template +VanishingEvaluated VanishingVerify( + VanishingPartiallyEvaluated&& partially_evaluated, + const Evals& expressions, const crypto::Challenge255& y, const F& x_n) { + F y_scalar = y.ChallengeAsScalar(); + F expected_h_eval = std::accumulate( + expressions.evaluations().begin(), expressions.evaluations().end(), + F::Zero(), [y_scalar](F& h_eval, const F& v) { + h_eval *= y_scalar; + return h_eval + v; + }); + expected_h_eval *= (x_n - F::One()).Inverse(); + + typename PCSTy::Commitment h_commitment = std::accumulate( + partially_evaluated.h_commitments().rbegin(), + partially_evaluated.h_commitments().rend(), PCSTy::Commitment::Zero(), + [&x_n](typename PCSTy::Commitment& acc, + const typename PCSTy::Commitment& commitment) { + return (acc * x_n + commitment).ToAffine(); + }); + + return {std::move(h_commitment), + std::move(partially_evaluated).TakeRandomPolyCommitment(), + std::move(expected_h_eval), + std::move(partially_evaluated).TakeRandomEval()}; +} + +template +std::vector> VanishingQueries( + VanishingEvaluated&& evaluated, + const crypto::Challenge255& x) { + return { + {x.ChallengeAsScalar(), + base::Ref(&evaluated.h_commitment()), + std::move(evaluated).TakeExpectedHEval()}, + {std::move(x.ChallengeAsScalar()), + base::Ref( + &evaluated.random_poly_commitment()), + std::move(evaluated).TakeRandomEval()}}; +} + +} // namespace tachyon::zk + +#endif // TACHYON_ZK_PLONK_VANISHING_VERIFIER_VANISHING_ARGUMENT_H_