From 9dc4cdfce790242a01b73fff369d4181f934025c Mon Sep 17 00:00:00 2001 From: "Inseon Yu(Merlyn)" Date: Tue, 11 Jun 2024 00:23:16 +0900 Subject: [PATCH 01/31] refac(zk): add `GetExprMaxDegree` function --- tachyon/zk/lookup/lookup_argument.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tachyon/zk/lookup/lookup_argument.h b/tachyon/zk/lookup/lookup_argument.h index d9860f3d2..685d28700 100644 --- a/tachyon/zk/lookup/lookup_argument.h +++ b/tachyon/zk/lookup/lookup_argument.h @@ -107,17 +107,9 @@ class Argument { // clang-format off // (1 - (l_last(X) + l_blind(X))) * (A′(X) − S′(X)) * (A′(X) − A′(ω⁻¹ * X)) = 0 // clang-format on - size_t max_input_degree = std::accumulate( - input_expressions_.begin(), input_expressions_.end(), 1, - [](size_t degree, const std::unique_ptr>& input_expr) { - return std::max(degree, input_expr->Degree()); - }); + size_t max_input_degree = GetMaxExprDegree(input_expressions_); - size_t max_table_degree = std::accumulate( - table_expressions_.begin(), table_expressions_.end(), 1, - [](size_t degree, const std::unique_ptr>& table_expr) { - return std::max(degree, table_expr->Degree()); - }); + size_t max_table_degree = GetMaxExprDegree(table_expressions_); // In practice because input_degree and table_degree are initialized to // one, the latter half of this max() invocation is at least 4 always, @@ -137,6 +129,15 @@ class Argument { } private: + static size_t GetMaxExprDegree( + const std::vector>>& expressions) { + return std::accumulate( + expressions.begin(), expressions.end(), 1, + [](size_t degree, const std::unique_ptr>& expr_ptr) { + return std::max(degree, expr_ptr->Degree()); + }); + } + std::string name_; std::vector>> input_expressions_; std::vector>> table_expressions_; From 5a72c97af567e2566a0ba92091a8c32748226d47 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Thu, 13 Jun 2024 18:41:40 +0900 Subject: [PATCH 02/31] refac(zk): use 2d vector for `inputs_expressions` in LookupArgument Change input expression interface in lookup argument to support `LogDerivativeHalo2` scheme. --- tachyon/zk/lookup/lookup_argument.h | 115 +++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 21 deletions(-) diff --git a/tachyon/zk/lookup/lookup_argument.h b/tachyon/zk/lookup/lookup_argument.h index 685d28700..e5c3965da 100644 --- a/tachyon/zk/lookup/lookup_argument.h +++ b/tachyon/zk/lookup/lookup_argument.h @@ -26,27 +26,47 @@ class Argument { std::vector>> input_expressions, std::vector>> table_expressions) : name_(std::string(name)), - input_expressions_(std::move(input_expressions)), + table_expressions_(std::move(table_expressions)) { + inputs_expressions_.push_back(std::move(input_expressions)); + } + Argument(std::string_view name, + std::vector>>> + inputs_expressions, + std::vector>> table_expressions) + : name_(std::string(name)), + inputs_expressions_(std::move(inputs_expressions)), table_expressions_(std::move(table_expressions)) {} Argument(std::string_view name, Pairs>> pairs) : name_(std::string(name)) { - input_expressions_.reserve(pairs.size()); + std::vector>> input_expressions; + input_expressions.reserve(pairs.size()); table_expressions_.reserve(pairs.size()); for (Pair>>& pair : pairs) { - input_expressions_.push_back(std::move(pair).TakeInput()); + input_expressions.push_back(std::move(pair).TakeInput()); table_expressions_.push_back(std::move(pair).TakeTable()); } + inputs_expressions_.push_back(std::move(input_expressions)); pairs.clear(); } + const std::vector>>>& + inputs_expressions() const { + return inputs_expressions_; + } + + std::vector>>>& + inputs_expressions() { + return inputs_expressions_; + } + const std::vector>>& input_expressions() const { - return input_expressions_; + return inputs_expressions_[0]; } std::vector>>& input_expressions() { - return input_expressions_; + return inputs_expressions_[0]; } const std::vector>>& table_expressions() const { @@ -59,12 +79,17 @@ class Argument { bool operator==(const Argument& other) const { if (name_ != other.name_) return false; - if (input_expressions_.size() != other.input_expressions_.size()) + if (inputs_expressions_.size() != other.inputs_expressions_.size()) return false; if (table_expressions_.size() != other.table_expressions_.size()) return false; - for (size_t i = 0; i < input_expressions_.size(); ++i) { - if (*input_expressions_[i] != *other.input_expressions_[i]) return false; + for (size_t i = 0; i < inputs_expressions_.size(); ++i) { + if (inputs_expressions_[i].size() != other.inputs_expressions_[i].size()) + return false; + for (size_t j = 0; j < inputs_expressions_[i].size(); ++j) { + if (*inputs_expressions_[i][j] != *other.inputs_expressions_[i][j]) + return false; + } } for (size_t i = 0; i < table_expressions_.size(); ++i) { if (*table_expressions_[i] != *other.table_expressions_[i]) return false; @@ -74,7 +99,11 @@ class Argument { bool operator!=(const Argument& other) const { return !operator==(other); } size_t RequiredDegree() const { - CHECK_EQ(input_expressions_.size(), table_expressions_.size()); + for (const std::vector>>& input_expressions : + inputs_expressions_) { + CHECK_EQ(input_expressions.size(), table_expressions_.size()); + } + // [Halo2 Lookup] // See https://zcash.github.io/halo2/design/proving-system/lookup.html // for more details. // @@ -89,8 +118,8 @@ class Argument { // l_last(X) * (Z(X)² - Z(X)) = 0 // // Enable the permutation argument for only the rows involved. - // degree (2 + max_input_degree + max_table_degree) or 4, whichever is - // larger: + // degree (2 + |combined_input_degree| + |max_table_degree|) or 4, whichever + // is larger: // clang-format off // (1 - (l_last(X) + l_blind(X))) * (Z(ω * X) * (A'(X) + β) * (S'(X) + γ) - Z(X) * (A_compressed(X) + β) * (S_compressed(X) + γ)) = 0 // clang-format on @@ -107,7 +136,35 @@ class Argument { // clang-format off // (1 - (l_last(X) + l_blind(X))) * (A′(X) − S′(X)) * (A′(X) − A′(ω⁻¹ * X)) = 0 // clang-format on - size_t max_input_degree = GetMaxExprDegree(input_expressions_); + // + // [LogDerivativeHalo2] + // The first value in the sum poly should be zero. + // degree 2: + // l_first(X) * ϕ(X) = 0 + // + // The last value in the sum poly should be zero. + // degree 2: + // l_last(X) * ϕ(X) = 0 + // + // Enable the sum argument for only the rows involved. + // degree (2 + |combined_input_degree| + |max_table_degree|) or + // (3 + |inputs_expressions_.size()|), whichever is larger: + // clang-format off + // φᵢ(X) = fᵢ(X) + β + // τ(X) = t(X) + β + // LHS = τ(X) * Π(φᵢ(X)) * (ϕ(ω * X) - ϕ(X)) + // ↪ DEG(LHS) = |max_table_degree| + |combined_input_degree| + 1 + // RHS = τ(X) * Π(φᵢ(X)) * ((Σ 1/φᵢ(X)) - m(X) / τ(X)) + // ↪ DEG(RHS) = |combined_input_degree| + 1 + // (1 - (l_last(X) + l_blind(X))) * (ϕ(ω * X) * τ(X) * Π(φᵢ(X)) - (LHS - RHS)) + // clang-format on + size_t combined_input_degree = std::accumulate( + inputs_expressions_.begin(), inputs_expressions_.end(), 0, + [](size_t combined_degree, + const std::vector>>& + input_expressions) { + return combined_degree + GetMaxExprDegree(input_expressions); + }); size_t max_table_degree = GetMaxExprDegree(table_expressions_); @@ -115,17 +172,33 @@ class Argument { // one, the latter half of this max() invocation is at least 4 always, // rendering this call pointless except to be explicit in case we change // the initialization of input_degree/table_degree in the future. - - // NOTE(chokobole): Even though, this actually is same as |2 + - // max_input_degree + max_table_degree|, for a better explanation, we follow - // the Halo2 style. return std::max( - // (1 - (l_last + l_blind)) * Z(ω * X) * (A'(X) + β) * (S'(X) + γ) - size_t{4}, // clang-format off - // (1 - (l_last + l_blind)) * Z(X) * (A_compressed(X) + β) * (S_compressed(X) + γ) + // [Halo2 Lookup] + // NOTE(Insun35): The size of |inputs_expressions_| for Halo2 lookup is 1. + // Thus, (3 + |inputs_expressions_.size()|) is always 4. + // (1 - (l_last(X) + l_blind(X))) * Z(ω * X) * (A'(X) + β) * (S'(X) + γ) + // ↪ degree = 4 + // + // [LogDerivativeHalo2] + // (1 - (l_last(X) + l_blind(X))) * ϕ(ω * X) * τ(X) * Π(φᵢ(X)) + // ↪ degree = |3 + inputs_expressions_.size()| + // clang-format on + 3 + inputs_expressions_.size(), + // clang-format off + // [Halo2 Lookup] + // max_degree = + // DEG((l_last(X) + l_blind(X))) * Z(X) * (A_compressed(X) + β) * (S_compressed(X) + γ)) + // + // [LogDerivativeHalo2] + // LHS = τ(X) * Π(φᵢ(X)) * (ϕ(ω * X) - ϕ(X)) + // ↪ DEG(LHS) = |max_table_degree| + |combined_input_degree| + 1 + // RHS = τ(X) * Π(φᵢ(X)) * ((Σ 1/φᵢ(X)) - m(X) / τ(X)) + // ↪ DEG(RHS) = |combined_input_degree| + 1 + // max_degree = DEG((1 - (l_last(X) + l_blind(X))) * (LHS - RHS)) + // = 1 + DEG(LHS) = 2 + |combined_input_degree| + |max_table_degree| // clang-format on - size_t{2} + max_input_degree + max_table_degree); + size_t{2} + combined_input_degree + max_table_degree); } private: @@ -139,7 +212,7 @@ class Argument { } std::string name_; - std::vector>> input_expressions_; + std::vector>>> inputs_expressions_; std::vector>> table_expressions_; }; From 7a0b7cbb266e17d65b8dd651f9be0eb7b1335195 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 20 May 2024 03:24:55 +0900 Subject: [PATCH 03/31] refac(zk): change return type of `Lookup()` and `LookupAny()` to void Change return type of `Lookup()` and `LookupAny()` from size_t (size of lookups) to void because it is redundant. --- .../constraint_system/constraint_system.h | 6 +- .../constraint_system_unittest.cc | 144 +++++++++--------- 2 files changed, 70 insertions(+), 80 deletions(-) diff --git a/tachyon/zk/plonk/constraint_system/constraint_system.h b/tachyon/zk/plonk/constraint_system/constraint_system.h index 757db1da5..309c67423 100644 --- a/tachyon/zk/plonk/constraint_system/constraint_system.h +++ b/tachyon/zk/plonk/constraint_system/constraint_system.h @@ -135,7 +135,7 @@ class ConstraintSystem { // // |callback| returns a map between the input expressions and the table // columns they need to match. - size_t Lookup(std::string_view name, LookupCallback callback) { + void Lookup(std::string_view name, LookupCallback callback) { VirtualCells cells(this); lookup::Pairs>> pairs = base::Map(std::move(callback).Run(cells), @@ -153,14 +153,13 @@ class ConstraintSystem { }); lookups_.emplace_back(name, std::move(pairs)); - return lookups_.size() - 1; } // Add a lookup argument for some input expressions and table expressions. // // |callback| returns a map between the input expressions and the table // expressions they need to match. - size_t LookupAny(std::string_view name, LookupAnyCallback callback) { + void LookupAny(std::string_view name, LookupAnyCallback callback) { VirtualCells cells(this); lookup::Pairs>> pairs = std::move(callback).Run(cells); @@ -172,7 +171,6 @@ class ConstraintSystem { } lookups_.emplace_back(name, std::move(pairs)); - return lookups_.size() - 1; } size_t QueryFixedIndex(const FixedColumnKey& column, Rotation at) { diff --git a/tachyon/zk/plonk/constraint_system/constraint_system_unittest.cc b/tachyon/zk/plonk/constraint_system/constraint_system_unittest.cc index 4f31a4fd6..cd7d8ec6d 100644 --- a/tachyon/zk/plonk/constraint_system/constraint_system_unittest.cc +++ b/tachyon/zk/plonk/constraint_system/constraint_system_unittest.cc @@ -68,48 +68,44 @@ TEST_F(ConstraintSystemTest, Lookup) { "expression containing simple selector supplied to lookup argument"); Selector complex_selector = constraint_system.CreateComplexSelector(); - EXPECT_EQ( - constraint_system.Lookup( - "lookup", - [complex_selector, &advice, &table](VirtualCells& cells) { - std::unique_ptr> complex_selector_expr = - cells.QuerySelector(complex_selector); - std::unique_ptr> advice0_expr = - cells.QueryAdvice(advice[0], Rotation::Cur()); - - lookup::Pairs>, LookupTableColumn> - lookup_pairs; - lookup_pairs.emplace_back( - std::move(complex_selector_expr) * std::move(advice0_expr), - table[0]); - return lookup_pairs; - }), - 0); - - EXPECT_EQ( - constraint_system.Lookup( - "lookup", - [complex_selector, &advice, &table](VirtualCells& cells) { - std::unique_ptr> complex_selector_expr = - cells.QuerySelector(complex_selector); - std::unique_ptr> advice1_expr = - cells.QueryAdvice(advice[1], Rotation::Cur()); - std::unique_ptr> not_complex_selector_expr = - ExpressionFactory::Constant(F::One()) - - complex_selector_expr->Clone(); - std::unique_ptr> default_expr = - ExpressionFactory::Constant(F(2)); - - lookup::Pairs>, LookupTableColumn> - lookup_pairs; - lookup_pairs.emplace_back( - std::move(complex_selector_expr) * std::move(advice1_expr) + - std::move(not_complex_selector_expr) * - std::move(default_expr), - table[1]); - return lookup_pairs; - }), - 1); + constraint_system.Lookup("lookup", [complex_selector, &advice, + &table](VirtualCells& cells) { + std::unique_ptr> complex_selector_expr = + cells.QuerySelector(complex_selector); + std::unique_ptr> advice0_expr = + cells.QueryAdvice(advice[0], Rotation::Cur()); + + lookup::Pairs>, LookupTableColumn> + lookup_pairs; + lookup_pairs.emplace_back( + std::move(complex_selector_expr) * std::move(advice0_expr), table[0]); + return lookup_pairs; + }); + + EXPECT_EQ(constraint_system.lookups().size(), 1); + + constraint_system.Lookup( + "lookup", [complex_selector, &advice, &table](VirtualCells& cells) { + std::unique_ptr> complex_selector_expr = + cells.QuerySelector(complex_selector); + std::unique_ptr> advice1_expr = + cells.QueryAdvice(advice[1], Rotation::Cur()); + std::unique_ptr> not_complex_selector_expr = + ExpressionFactory::Constant(F::One()) - + complex_selector_expr->Clone(); + std::unique_ptr> default_expr = + ExpressionFactory::Constant(F(2)); + + lookup::Pairs>, LookupTableColumn> + lookup_pairs; + lookup_pairs.emplace_back( + std::move(complex_selector_expr) * std::move(advice1_expr) + + std::move(not_complex_selector_expr) * std::move(default_expr), + table[1]); + return lookup_pairs; + }); + + EXPECT_EQ(constraint_system.lookups().size(), 2); EXPECT_EQ(constraint_system.ComputeLookupRequiredDegree(), 5); @@ -177,40 +173,36 @@ TEST_F(ConstraintSystemTest, LookupAny) { "expression containing simple selector supplied to lookup argument"); Selector complex_selector = constraint_system.CreateComplexSelector(); - EXPECT_EQ( - constraint_system.LookupAny( - "lookup", - [&advice, complex_selector, &advice_table, - &table](VirtualCells& cells) { - std::unique_ptr> advice_expr = - cells.QueryAdvice(advice, Rotation::Cur()); - std::unique_ptr> complex_selector_expr = - cells.QuerySelector(complex_selector); - std::unique_ptr> not_complex_selector_expr = - ExpressionFactory::Constant(F::One()) - - complex_selector_expr->Clone(); - std::unique_ptr> default_expr = - ExpressionFactory::Constant(F(2)); - std::unique_ptr> advice_table_expr = - cells.QueryAdvice(advice_table, Rotation::Cur()); - std::unique_ptr> table_expr = - cells.QueryInstance(table, Rotation::Cur()); - - lookup::Pairs>> lookup_pairs; - lookup_pairs.emplace_back( - complex_selector_expr->Clone() * advice_expr->Clone() + - not_complex_selector_expr->Clone() * default_expr->Clone(), - std::move(table_expr)); - lookup_pairs.emplace_back( - std::move(complex_selector_expr) * std::move(advice_expr) + - std::move(not_complex_selector_expr) * - std::move(default_expr), - std::move(advice_table_expr)); - return lookup_pairs; - }), - 0); - - EXPECT_EQ(constraint_system.ComputeLookupRequiredDegree(), 5); + constraint_system.LookupAny( + "lookup", [&advice, complex_selector, &advice_table, + &table](VirtualCells& cells) { + std::unique_ptr> advice_expr = + cells.QueryAdvice(advice, Rotation::Cur()); + std::unique_ptr> complex_selector_expr = + cells.QuerySelector(complex_selector); + std::unique_ptr> not_complex_selector_expr = + ExpressionFactory::Constant(F::One()) - + complex_selector_expr->Clone(); + std::unique_ptr> default_expr = + ExpressionFactory::Constant(F(2)); + std::unique_ptr> advice_table_expr = + cells.QueryAdvice(advice_table, Rotation::Cur()); + std::unique_ptr> table_expr = + cells.QueryInstance(table, Rotation::Cur()); + + lookup::Pairs>> lookup_pairs; + lookup_pairs.emplace_back( + complex_selector_expr->Clone() * advice_expr->Clone() + + not_complex_selector_expr->Clone() * default_expr->Clone(), + std::move(table_expr)); + lookup_pairs.emplace_back( + std::move(complex_selector_expr) * std::move(advice_expr) + + std::move(not_complex_selector_expr) * std::move(default_expr), + std::move(advice_table_expr)); + return lookup_pairs; + }); + + EXPECT_EQ(constraint_system.lookups().size(), 1); std::vector> expected_lookups; { From 32362eeaad233baa37729e4dac053c10f071f72b Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 20 May 2024 03:29:35 +0900 Subject: [PATCH 04/31] feat(zk): add identifier to expressions See https://github.com/kroma-network/halo2/blob/4ad1359c12e396537db7cfd99eda3012229e4640/halo2_proofs/src/plonk/circuit.rs#L1252-L1313 --- tachyon/zk/expressions/advice_expression.h | 5 +++++ tachyon/zk/expressions/challenge_expression.h | 4 ++++ tachyon/zk/expressions/constant_expression.h | 4 ++++ tachyon/zk/expressions/expression.h | 9 +++++++++ tachyon/zk/expressions/fixed_expression.h | 5 +++++ tachyon/zk/expressions/instance_expression.h | 5 +++++ tachyon/zk/expressions/negated_expression.h | 6 ++++++ tachyon/zk/expressions/product_expression.h | 8 ++++++++ tachyon/zk/expressions/scaled_expression.h | 4 ++++ tachyon/zk/expressions/selector_expression.h | 4 ++++ tachyon/zk/expressions/sum_expression.h | 8 ++++++++ 11 files changed, 62 insertions(+) diff --git a/tachyon/zk/expressions/advice_expression.h b/tachyon/zk/expressions/advice_expression.h index 5fe97c08f..a38963f53 100644 --- a/tachyon/zk/expressions/advice_expression.h +++ b/tachyon/zk/expressions/advice_expression.h @@ -42,6 +42,11 @@ class AdviceExpression : public Expression { query_.ToString()); } + void WriteIdentifier(std::ostream& out) const override { + out << "advice[" << query_.column().index() << "][" + << query_.rotation().value() << "]"; + } + bool operator==(const Expression& other) const override { if (!Expression::operator==(other)) return false; const AdviceExpression* advice = other.ToAdvice(); diff --git a/tachyon/zk/expressions/challenge_expression.h b/tachyon/zk/expressions/challenge_expression.h index 230ae9b6d..8c54e6bab 100644 --- a/tachyon/zk/expressions/challenge_expression.h +++ b/tachyon/zk/expressions/challenge_expression.h @@ -44,6 +44,10 @@ class ChallengeExpression : public Expression { challenge_.ToString()); } + void WriteIdentifier(std::ostream& out) const override { + out << "challenge[" << challenge_.index() << "]"; + } + bool operator==(const Expression& other) const override { if (!Expression::operator==(other)) return false; const ChallengeExpression* challenge = other.ToChallenge(); diff --git a/tachyon/zk/expressions/constant_expression.h b/tachyon/zk/expressions/constant_expression.h index 1e513c72b..e4618dbf9 100644 --- a/tachyon/zk/expressions/constant_expression.h +++ b/tachyon/zk/expressions/constant_expression.h @@ -42,6 +42,10 @@ class ConstantExpression : public Expression { value_.ToString()); } + void WriteIdentifier(std::ostream& out) const override { + out << value_.ToString(); + } + bool operator==(const Expression& other) const override { if (!Expression::operator==(other)) return false; const ConstantExpression* constant = other.ToConstant(); diff --git a/tachyon/zk/expressions/expression.h b/tachyon/zk/expressions/expression.h index 20a48378c..1157098c3 100644 --- a/tachyon/zk/expressions/expression.h +++ b/tachyon/zk/expressions/expression.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -72,6 +73,14 @@ class Expression { virtual std::unique_ptr Clone() const = 0; + virtual void WriteIdentifier(std::ostream& out) const = 0; + + std::string Identifier() const { + std::ostringstream ss; + WriteIdentifier(ss); + return ss.str(); + } + virtual bool operator==(const Expression& other) const { return type_ == other.type_; } diff --git a/tachyon/zk/expressions/fixed_expression.h b/tachyon/zk/expressions/fixed_expression.h index eca9f899b..c86daff2b 100644 --- a/tachyon/zk/expressions/fixed_expression.h +++ b/tachyon/zk/expressions/fixed_expression.h @@ -42,6 +42,11 @@ class FixedExpression : public Expression { query_.ToString()); } + void WriteIdentifier(std::ostream& out) const override { + out << "fixed[" << query_.column().index() << "][" + << query_.rotation().value() << "]"; + } + bool operator==(const Expression& other) const override { if (!Expression::operator==(other)) return false; const FixedExpression* fixed = other.ToFixed(); diff --git a/tachyon/zk/expressions/instance_expression.h b/tachyon/zk/expressions/instance_expression.h index 2e55b6463..486f0b022 100644 --- a/tachyon/zk/expressions/instance_expression.h +++ b/tachyon/zk/expressions/instance_expression.h @@ -42,6 +42,11 @@ class InstanceExpression : public Expression { query_.ToString()); } + void WriteIdentifier(std::ostream& out) const override { + out << "instance[" << query_.column().index() << "][" + << query_.rotation().value() << "]"; + } + bool operator==(const Expression& other) const override { if (!Expression::operator==(other)) return false; const InstanceExpression* instance = other.ToInstance(); diff --git a/tachyon/zk/expressions/negated_expression.h b/tachyon/zk/expressions/negated_expression.h index 6c2cdd91c..63ca5df73 100644 --- a/tachyon/zk/expressions/negated_expression.h +++ b/tachyon/zk/expressions/negated_expression.h @@ -47,6 +47,12 @@ class NegatedExpression : public Expression { expr_->ToString()); } + void WriteIdentifier(std::ostream& out) const override { + out << "(-"; + expr_->WriteIdentifier(out); + out << ")"; + } + bool operator==(const Expression& other) const override { if (!Expression::operator==(other)) return false; const NegatedExpression* negated = other.ToNegated(); diff --git a/tachyon/zk/expressions/product_expression.h b/tachyon/zk/expressions/product_expression.h index 959d47313..4b52fe5ab 100644 --- a/tachyon/zk/expressions/product_expression.h +++ b/tachyon/zk/expressions/product_expression.h @@ -51,6 +51,14 @@ class ProductExpression : public Expression { left_->ToString(), right_->ToString()); } + void WriteIdentifier(std::ostream& out) const override { + out << "("; + left_->WriteIdentifier(out); + out << "*"; + right_->WriteIdentifier(out); + out << ")"; + } + bool operator==(const Expression& other) const override { if (!Expression::operator==(other)) return false; const ProductExpression* product = other.ToProduct(); diff --git a/tachyon/zk/expressions/scaled_expression.h b/tachyon/zk/expressions/scaled_expression.h index ea4f2088a..c7f6e76e5 100644 --- a/tachyon/zk/expressions/scaled_expression.h +++ b/tachyon/zk/expressions/scaled_expression.h @@ -48,6 +48,10 @@ class ScaledExpression : public Expression { expr_->ToString(), scale_.ToString()); } + void WriteIdentifier(std::ostream& out) const override { + out << "*" << scale_.ToString(); + } + bool operator==(const Expression& other) const override { if (!Expression::operator==(other)) return false; const ScaledExpression* scaled = other.ToScaled(); diff --git a/tachyon/zk/expressions/selector_expression.h b/tachyon/zk/expressions/selector_expression.h index 315af47bb..48d1595de 100644 --- a/tachyon/zk/expressions/selector_expression.h +++ b/tachyon/zk/expressions/selector_expression.h @@ -43,6 +43,10 @@ class SelectorExpression : public Expression { selector_.ToString()); } + void WriteIdentifier(std::ostream& out) const override { + out << "selector[" << selector_.index() << "]"; + } + bool operator==(const Expression& other) const override { if (!Expression::operator==(other)) return false; const SelectorExpression* selector = other.ToSelector(); diff --git a/tachyon/zk/expressions/sum_expression.h b/tachyon/zk/expressions/sum_expression.h index 48cbdaa69..e266234f6 100644 --- a/tachyon/zk/expressions/sum_expression.h +++ b/tachyon/zk/expressions/sum_expression.h @@ -55,6 +55,14 @@ class SumExpression : public Expression { left_->ToString(), right_->ToString()); } + void WriteIdentifier(std::ostream& out) const override { + out << "("; + left_->WriteIdentifier(out); + out << "+"; + right_->WriteIdentifier(out); + out << ")"; + } + bool operator==(const Expression& other) const override { if (!Expression::operator==(other)) return false; const SumExpression* sum = other.ToSum(); From 6c12e4f77f6daf3b74b22d10c18bb6b1b6a1fd60 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 20 May 2024 03:32:35 +0900 Subject: [PATCH 05/31] feat(zk): add `CloneExpressions` `CloneExpressions` function clones a vector of `std::unique_ptr`. It is needed to handle both `lookups` and `lookups_map` in LogDerivativeHalo2. --- tachyon/zk/expressions/BUILD.bazel | 1 + tachyon/zk/expressions/expression.h | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/tachyon/zk/expressions/BUILD.bazel b/tachyon/zk/expressions/BUILD.bazel index b803d6cbb..2aae08aa5 100644 --- a/tachyon/zk/expressions/BUILD.bazel +++ b/tachyon/zk/expressions/BUILD.bazel @@ -45,6 +45,7 @@ tachyon_cc_library( deps = [ ":expression_type", "//tachyon/base:ref", + "//tachyon/base/containers:container_util", "//tachyon/zk/plonk/constraint_system:selector", ], ) diff --git a/tachyon/zk/expressions/expression.h b/tachyon/zk/expressions/expression.h index 1157098c3..2495763d4 100644 --- a/tachyon/zk/expressions/expression.h +++ b/tachyon/zk/expressions/expression.h @@ -13,6 +13,7 @@ #include #include +#include "tachyon/base/containers/container_util.h" #include "tachyon/base/logging.h" #include "tachyon/base/ref.h" #include "tachyon/zk/expressions/expression_type.h" @@ -96,6 +97,13 @@ class Expression { // Extracts a simple selector from this gate, if present. std::optional ExtractSimpleSelector() const; + static std::vector> CloneExpressions( + const std::vector>& expressions) { + return base::CreateVector(expressions.size(), [&expressions](size_t i) { + return expressions[i]->Clone(); + }); + } + std::unique_ptr> ReplaceSelectors( const std::vector>>& replacements, bool must_be_non_simple) const; From 23f22047da7769565929fbbc398b7c6e1559f6d7 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 20 May 2024 03:33:56 +0900 Subject: [PATCH 06/31] feat(zk): add LogDerivativeHalo2 type --- tachyon/zk/lookup/type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tachyon/zk/lookup/type.h b/tachyon/zk/lookup/type.h index cec9d51b4..55674d335 100644 --- a/tachyon/zk/lookup/type.h +++ b/tachyon/zk/lookup/type.h @@ -3,7 +3,7 @@ namespace tachyon::zk::lookup { -enum class Type { kHalo2 }; +enum class Type { kHalo2, kLogDerivativeHalo2 }; } // namespace tachyon::zk::lookup From f88ed1aae4e2721bdfde70293ed7ce3969c82581 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Fri, 31 May 2024 15:56:48 +0900 Subject: [PATCH 07/31] fix(zk): compare degrees between input and existing value --- tachyon/zk/plonk/constraint_system/constraint_system.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tachyon/zk/plonk/constraint_system/constraint_system.h b/tachyon/zk/plonk/constraint_system/constraint_system.h index 309c67423..139cf33c1 100644 --- a/tachyon/zk/plonk/constraint_system/constraint_system.h +++ b/tachyon/zk/plonk/constraint_system/constraint_system.h @@ -113,7 +113,13 @@ class ConstraintSystem { // Sets the minimum degree required by the circuit, which can be set to a // larger amount than actually needed. This can be used, for example, to // force the permutation argument to involve more columns in the same set. - void set_minimum_degree(size_t degree) { minimum_degree_ = degree; } + void set_minimum_degree(size_t degree) { + if (minimum_degree_) { + minimum_degree_ = std::max(minimum_degree_.value(), degree); + } else { + minimum_degree_ = degree; + } + } // Enables this fixed |column| to be used for global constant assignments. // The |column| will be equality-enabled, too. From 25b8c70e63567d235e47d339af6f63734190c2c6 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 3 Jun 2024 15:06:26 +0900 Subject: [PATCH 08/31] feat(zk): add `QueryLookupTable` to `VirtualCells` --- tachyon/zk/plonk/constraint_system/BUILD.bazel | 1 + tachyon/zk/plonk/constraint_system/virtual_cells.h | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/tachyon/zk/plonk/constraint_system/BUILD.bazel b/tachyon/zk/plonk/constraint_system/BUILD.bazel index 834e739f8..2cef64af9 100644 --- a/tachyon/zk/plonk/constraint_system/BUILD.bazel +++ b/tachyon/zk/plonk/constraint_system/BUILD.bazel @@ -139,6 +139,7 @@ tachyon_cc_library( ":selector", ":virtual_cell", "//tachyon/zk/expressions:expression_factory", + "//tachyon/zk/plonk/layout:lookup_table_column", ], ) diff --git a/tachyon/zk/plonk/constraint_system/virtual_cells.h b/tachyon/zk/plonk/constraint_system/virtual_cells.h index 813e9518c..2600ff4c0 100644 --- a/tachyon/zk/plonk/constraint_system/virtual_cells.h +++ b/tachyon/zk/plonk/constraint_system/virtual_cells.h @@ -8,6 +8,7 @@ #include "tachyon/zk/expressions/expression_factory.h" #include "tachyon/zk/plonk/constraint_system/selector.h" #include "tachyon/zk/plonk/constraint_system/virtual_cell.h" +#include "tachyon/zk/plonk/layout/lookup_table_column.h" namespace tachyon::zk::plonk { @@ -87,6 +88,17 @@ class VirtualCells { return ExpressionFactory::Challenge(challenge); } + // Query a lookup table + std::unique_ptr> QueryLookupTable( + const lookup::Pair>, LookupTableColumn>& + pair, + Rotation at) { + CHECK(!pair.input()->ContainsSimpleSelector()) + << "expression containing simple selector supplied to lookup argument"; + + return QueryFixed(pair.table().column(), at); + } + private: // not owned ConstraintSystem* const meta_; From 453958090c3f0538f8e60d652222ba10f45e3cab Mon Sep 17 00:00:00 2001 From: Insun35 Date: Fri, 31 May 2024 16:17:26 +0900 Subject: [PATCH 09/31] feat(zk): add `constraint_system` lookup logic for `LookupsMap` Add `Lookup()`, `LookupAny()`, and `ChunkLookup()` for LogDerivativeHalo2 scheme. Constraint system selects logic dynamically using lookup type. - Add constructor that can take a lookup type. - `LookupTracker`: holds table and input expressions with its name - `LookupsMap`: `btree_map` with `table_expressions_identifier` as a key and `LookupTracker` as values. See: https://github.com/scroll-tech/halo2/blob/1070391642dd64b2d68b47ec246cba9e35bd3c15/halo2_proofs/src/plonk/circuit.rs#L1572-L1706 --- .../zk/plonk/constraint_system/BUILD.bazel | 10 + .../constraint_system/constraint_system.h | 252 ++++++++++++++++-- .../constraint_system_unittest.cc | 6 +- .../plonk/constraint_system/lookup_tracker.h | 29 ++ tachyon/zk/plonk/examples/circuit_test.cc | 13 +- tachyon/zk/plonk/halo2/synthesizer.h | 4 +- tachyon/zk/plonk/keys/key.h | 8 + tachyon/zk/plonk/keys/proving_key.h | 4 +- tachyon/zk/plonk/keys/verifying_key.h | 5 +- 9 files changed, 296 insertions(+), 35 deletions(-) create mode 100644 tachyon/zk/plonk/constraint_system/lookup_tracker.h diff --git a/tachyon/zk/plonk/constraint_system/BUILD.bazel b/tachyon/zk/plonk/constraint_system/BUILD.bazel index 2cef64af9..012ccf08e 100644 --- a/tachyon/zk/plonk/constraint_system/BUILD.bazel +++ b/tachyon/zk/plonk/constraint_system/BUILD.bazel @@ -32,6 +32,7 @@ tachyon_cc_library( deps = [ ":constraint", ":gate", + ":lookup_tracker", ":query", ":selector_compressor", ":virtual_cells", @@ -43,11 +44,14 @@ tachyon_cc_library( "//tachyon/zk/base:row_types", "//tachyon/zk/expressions/evaluator:simple_selector_finder", "//tachyon/zk/lookup:lookup_argument", + "//tachyon/zk/lookup:type", "//tachyon/zk/plonk/keys:c_proving_key_impl_base_forward", "//tachyon/zk/plonk/layout:lookup_table_column", "//tachyon/zk/plonk/permutation:permutation_argument", "//tachyon/zk/plonk/permutation:permutation_utils", + "@com_google_absl//absl/container:btree", "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/numeric:bits", ], ) @@ -72,6 +76,12 @@ tachyon_cc_library( ], ) +tachyon_cc_library( + name = "lookup_tracker", + hdrs = ["lookup_tracker.h"], + deps = ["//tachyon/zk/expressions:expression"], +) + tachyon_cc_library( name = "query", hdrs = ["query.h"], diff --git a/tachyon/zk/plonk/constraint_system/constraint_system.h b/tachyon/zk/plonk/constraint_system/constraint_system.h index 139cf33c1..4a0c03aa7 100644 --- a/tachyon/zk/plonk/constraint_system/constraint_system.h +++ b/tachyon/zk/plonk/constraint_system/constraint_system.h @@ -18,7 +18,9 @@ #include #include +#include "absl/container/btree_map.h" #include "absl/container/flat_hash_map.h" +#include "absl/numeric/bits.h" #include "gtest/gtest_prod.h" #include "tachyon/base/containers/container_util.h" @@ -29,8 +31,10 @@ #include "tachyon/zk/base/row_types.h" #include "tachyon/zk/expressions/evaluator/simple_selector_finder.h" #include "tachyon/zk/lookup/lookup_argument.h" +#include "tachyon/zk/lookup/type.h" #include "tachyon/zk/plonk/constraint_system/constraint.h" #include "tachyon/zk/plonk/constraint_system/gate.h" +#include "tachyon/zk/plonk/constraint_system/lookup_tracker.h" #include "tachyon/zk/plonk/constraint_system/query.h" #include "tachyon/zk/plonk/constraint_system/selector_compressor.h" #include "tachyon/zk/plonk/constraint_system/virtual_cells.h" @@ -55,6 +59,13 @@ class ConstraintSystem { using ConstrainCallback = base::OnceCallback>(VirtualCells&)>; + ConstraintSystem() = default; + + explicit ConstraintSystem(lookup::Type lookup_type) + : lookup_type_(lookup_type) {} + + lookup::Type lookup_type() const { return lookup_type_; } + size_t num_fixed_columns() const { return num_fixed_columns_; } size_t num_advice_columns() const { return num_advice_columns_; } @@ -99,6 +110,10 @@ class ConstraintSystem { const std::vector>& lookups() const { return lookups_; } + const absl::btree_map>& lookups_map() const { + return lookups_map_; + } + const absl::flat_hash_map& general_column_annotations() const { return general_column_annotations_; @@ -143,22 +158,41 @@ class ConstraintSystem { // columns they need to match. void Lookup(std::string_view name, LookupCallback callback) { VirtualCells cells(this); - lookup::Pairs>> pairs = - base::Map(std::move(callback).Run(cells), - [&cells](lookup::Pair>, - LookupTableColumn>& pair) { - CHECK(!pair.input()->ContainsSimpleSelector()) - << "expression containing simple selector " - "supplied to lookup argument"; - - std::unique_ptr> table = cells.QueryFixed( - pair.table().column(), Rotation::Cur()); - - return lookup::Pair>>( - std::move(pair).TakeInput(), std::move(table)); - }); + lookup::Pairs>, LookupTableColumn> pairs = + std::move(callback).Run(cells); - lookups_.emplace_back(name, std::move(pairs)); + switch (lookup_type_) { + case lookup::Type::kHalo2: { + lookup::Pairs>> lookup_pairs = base::Map( + pairs, [&cells](lookup::Pair>, + LookupTableColumn>& pair) { + std::unique_ptr> table = + cells.QueryLookupTable(pair, Rotation::Cur()); + return lookup::Pair>>( + std::move(pair).TakeInput(), std::move(table)); + }); + lookups_.emplace_back(name, std::move(lookup_pairs)); + break; + } + case lookup::Type::kLogDerivativeHalo2: { + std::vector>> input_expressions; + std::vector>> table_expressions; + + input_expressions.reserve(pairs.size()); + table_expressions.reserve(pairs.size()); + + for (lookup::Pair>, LookupTableColumn>& + pair : pairs) { + std::unique_ptr> table = + cells.QueryLookupTable(pair, Rotation::Cur()); + input_expressions.push_back(std::move(pair).TakeInput()); + table_expressions.push_back(std::move(table)); + } + CreateLookupsMap(name, std::move(input_expressions), + std::move(table_expressions)); + break; + } + } } // Add a lookup argument for some input expressions and table expressions. @@ -170,13 +204,120 @@ class ConstraintSystem { lookup::Pairs>> pairs = std::move(callback).Run(cells); - for (const lookup::Pair>>& pair : pairs) { - CHECK(!pair.input()->ContainsSimpleSelector()) - << "expression containing simple selector " - "supplied to lookup argument"; + switch (lookup_type_) { + case lookup::Type::kHalo2: { + for (const lookup::Pair>>& pair : pairs) { + CHECK(!pair.input()->ContainsSimpleSelector()) + << "expression containing simple selector " + "supplied to lookup argument"; + } + lookups_.emplace_back(name, std::move(pairs)); + break; + } + case lookup::Type::kLogDerivativeHalo2: { + std::vector>> input_expressions; + std::vector>> table_expressions; + + input_expressions.reserve(pairs.size()); + table_expressions.reserve(pairs.size()); + + for (lookup::Pair>>& pair : pairs) { + CHECK(!pair.input()->ContainsSimpleSelector()) + << "expression containing simple selector " + "supplied to lookup argument"; + + input_expressions.push_back(std::move(pair).TakeInput()); + table_expressions.push_back(std::move(pair).TakeTable()); + } + + CreateLookupsMap(name, std::move(input_expressions), + std::move(table_expressions)); + break; + } } + } + + // Chunk lookup arguments into pieces below a given degree bound. Compute the + // |minimum_degree| from gates and lookups, and then construct the + // |lookup_arguments| of chunks smaller than the |minimum_degree| from the + // |lookups_map|. + void ChunkLookups() { + CHECK_EQ(lookup_type_, lookup::Type::kLogDerivativeHalo2); + + if (lookups_map_.empty()) { + return; + } + + size_t max_gate_degree = ComputeGateRequiredDegree(); - lookups_.emplace_back(name, std::move(pairs)); + size_t max_single_lookup_degree = 0; + for (const auto& [_, lookup_tracker] : lookups_map_) { + size_t table_degree = ComputeColumnDegree(lookup_tracker.table); + + // Compute base degree only from table without inputs. + size_t base_lookup_degree = ComputeBaseDegree(table_degree); + + size_t max_inputs_degree = 0; + for (const std::vector>>& input : + lookup_tracker.inputs) { + max_inputs_degree = + std::max(max_inputs_degree, ComputeColumnDegree(input)); + } + + size_t current_degree = + ComputeDegreeWithInput(base_lookup_degree, max_inputs_degree); + max_single_lookup_degree = + std::max(max_single_lookup_degree, current_degree); + } + + size_t required_degree = + std::max(max_gate_degree, max_single_lookup_degree); + + // The smallest power of 2 greater than or equal to |required_degree|. + size_t next_power_of_two = absl::bit_ceil(required_degree); + + set_minimum_degree(next_power_of_two + 1); + + size_t minimum_degree = minimum_degree_.value(); + + for (const auto& [_, lookup_tracker] : lookups_map_) { + std::vector>> cloned_input = + Expression::CloneExpressions(lookup_tracker.inputs[0]); + std::vector>> cloned_table = + Expression::CloneExpressions(lookup_tracker.table); + lookups_.emplace_back(lookup_tracker.name, std::move(cloned_input), + std::move(cloned_table)); + + for (auto input = lookup_tracker.inputs.begin() + 1; + input != lookup_tracker.inputs.end(); ++input) { + // Compute the degree of the current set of input expressions. + size_t cur_input_degree = ComputeColumnDegree(*input); + + bool added = false; + for (lookup::Argument& lookup_argument : lookups_) { + // Try to fit input into one of the |lookup_arguments|. + size_t cur_argument_degree = lookup_argument.RequiredDegree(); + size_t new_potential_degree = cur_argument_degree + cur_input_degree; + if (new_potential_degree <= minimum_degree) { + std::vector>> cloned_input = + Expression::CloneExpressions(*input); + lookup_argument.inputs_expressions().push_back( + std::move(cloned_input)); + added = true; + break; + } + } + + if (!added) { + std::vector>> cloned_input = + Expression::CloneExpressions(*input); + std::vector>> cloned_table = + Expression::CloneExpressions(lookup_tracker.table); + lookups_.emplace_back(lookup_tracker.name, std::move(cloned_input), + std::move(cloned_table)); + } + } + } } size_t QueryFixedIndex(const FixedColumnKey& column, Rotation at) { @@ -345,9 +486,12 @@ class ConstraintSystem { } } for (lookup::Argument& lookup : lookups_) { - for (std::unique_ptr>& expression : - lookup.input_expressions()) { - expression = expression->ReplaceSelectors(selector_replacements, true); + for (std::vector>>& input_expressions : + lookup.inputs_expressions()) { + for (std::unique_ptr>& expression : input_expressions) { + expression = + expression->ReplaceSelectors(selector_replacements, true); + } } for (std::unique_ptr>& expression : lookup.table_expressions()) { @@ -571,6 +715,27 @@ class ConstraintSystem { FRIEND_TEST(ConstraintSystemTest, Lookup); FRIEND_TEST(ConstraintSystemTest, LookupAny); + void CreateLookupsMap( + std::string_view name, + std::vector>>&& input_expressions, + std::vector>>&& table_expressions) { + std::stringstream table_expressions_ss; + for (const std::unique_ptr>& expr : table_expressions) { + table_expressions_ss << expr->Identifier(); + } + + std::string table_expressions_identifier = table_expressions_ss.str(); + + auto it = lookups_map_.find(table_expressions_identifier); + if (it != lookups_map_.end()) { + it->second.inputs.push_back(std::move(input_expressions)); + } else { + LookupTracker lookup_tracker(name, std::move(table_expressions), + std::move(input_expressions)); + lookups_map_[table_expressions_identifier] = std::move(lookup_tracker); + } + } + template static bool QueryIndex(const std::vector& queries, const Column& column, Rotation at, size_t* index_out) { @@ -583,6 +748,16 @@ class ConstraintSystem { return true; } + static size_t ComputeColumnDegree( + const std::vector>>& column) { + return (*std::max_element(column.begin(), column.end(), + [](const std::unique_ptr>& a, + const std::unique_ptr>& b) { + return a->Degree() < b->Degree(); + })) + ->Degree(); + } + size_t ComputeLookupRequiredDegree() const { std::vector required_degrees = base::Map(lookups_, [](const lookup::Argument& argument) { @@ -608,6 +783,32 @@ class ConstraintSystem { return *max_required_degree; } + // Degree of lookup without inputs + constexpr static size_t ComputeBaseDegree(size_t table_degree) { + // φᵢ(X) = fᵢ(X) + α + // τ(X) = t(X) + α + // + // LHS = τ(X) * Π(φᵢ(X)) * (ϕ(gX) - ϕ(X)) + // ↪ DEG(LHS) = |table_degree| + inputs_degree(= 0) + 1 + // = |table_degree| + 1 + // + // RHS = τ(X) * Π(φᵢ(X)) * (∑ 1/(φᵢ(X)) - m(X) / τ(X)) + // ↪ DEG(RHS) = |table_degree| + // + // (1 - (l_last(X) + l_blind(X))) * (LHS - RHS) + // ↪ degree = DEG(LHS) + 1 = |table_degree| + 2 + return std::max(size_t{3}, table_degree + 2); + } + + constexpr static size_t ComputeDegreeWithInput( + size_t base_degree, size_t input_expression_degree) { + return base_degree + input_expression_degree; + } + + // TODO(Insun35): Change default |lookup_type_| to |kLogDerivativeHalo2| + // after implementing C API for LogDerivativeHalo2 scheme. + lookup::Type lookup_type_ = lookup::Type::kHalo2; + size_t num_fixed_columns_ = 0; size_t num_advice_columns_ = 0; size_t num_instance_columns_ = 0; @@ -642,6 +843,11 @@ class ConstraintSystem { // of table expressions involved in the lookup. std::vector> lookups_; + // NOTE(Insun35): |lookups_map_| is only used for LogDerivativeHalo2. + // btree_map with |table_expressions_identifier| as a key and |LookupTracker| + // as values. + absl::btree_map> lookups_map_; + // List of indexes of Fixed columns which are associated to a // circuit-general Column tied to their annotation. absl::flat_hash_map general_column_annotations_; diff --git a/tachyon/zk/plonk/constraint_system/constraint_system_unittest.cc b/tachyon/zk/plonk/constraint_system/constraint_system_unittest.cc index cd7d8ec6d..480380b3a 100644 --- a/tachyon/zk/plonk/constraint_system/constraint_system_unittest.cc +++ b/tachyon/zk/plonk/constraint_system/constraint_system_unittest.cc @@ -38,7 +38,8 @@ TEST_F(ConstraintSystemTest, EnableConstant) { } TEST_F(ConstraintSystemTest, Lookup) { - ConstraintSystem constraint_system; + ConstraintSystem constraint_system(lookup::Type::kHalo2); + std::array advice = { constraint_system.CreateAdviceColumn(), constraint_system.CreateAdviceColumn(), @@ -141,7 +142,8 @@ TEST_F(ConstraintSystemTest, Lookup) { } TEST_F(ConstraintSystemTest, LookupAny) { - ConstraintSystem constraint_system; + ConstraintSystem constraint_system(lookup::Type::kHalo2); + AdviceColumnKey advice = constraint_system.CreateAdviceColumn(); InstanceColumnKey table = constraint_system.CreateInstanceColumn(); AdviceColumnKey advice_table = constraint_system.CreateAdviceColumn(); diff --git a/tachyon/zk/plonk/constraint_system/lookup_tracker.h b/tachyon/zk/plonk/constraint_system/lookup_tracker.h new file mode 100644 index 000000000..ff1a1b04b --- /dev/null +++ b/tachyon/zk/plonk/constraint_system/lookup_tracker.h @@ -0,0 +1,29 @@ +#ifndef TACHYON_ZK_PLONK_CONSTRAINT_SYSTEM_LOOKUP_TRACKER_H_ +#define TACHYON_ZK_PLONK_CONSTRAINT_SYSTEM_LOOKUP_TRACKER_H_ + +#include +#include +#include +#include + +#include "tachyon/zk/expressions/expression.h" + +namespace tachyon::zk::plonk { + +template +struct LookupTracker { + std::string name; + std::vector>> table; + std::vector>>> inputs; + LookupTracker() = default; + LookupTracker(std::string_view name, + std::vector>> table, + std::vector>> input) + : name(std::string(name)), table(std::move(table)) { + inputs.push_back(std::move(input)); + } +}; + +} // namespace tachyon::zk::plonk + +#endif // TACHYON_ZK_PLONK_CONSTRAINT_SYSTEM_LOOKUP_TRACKER_H_ diff --git a/tachyon/zk/plonk/examples/circuit_test.cc b/tachyon/zk/plonk/examples/circuit_test.cc index 20ad05d17..cc0499df6 100644 --- a/tachyon/zk/plonk/examples/circuit_test.cc +++ b/tachyon/zk/plonk/examples/circuit_test.cc @@ -29,7 +29,8 @@ namespace tachyon::zk::plonk { template void CircuitTest::ConfigureTest() { - ConstraintSystem constraint_system; + ConstraintSystem constraint_system(TestArguments::LS::type); + auto config = Circuit::Configure(constraint_system); TestData::TestConfig(config); @@ -48,7 +49,8 @@ void CircuitTest::SynthesizeTest() { this->prover_->set_domain(Domain::Create(TestData::kN)); const Domain* domain = this->prover_->domain(); - ConstraintSystem constraint_system; + ConstraintSystem constraint_system(TestArguments::LS::type); + auto config = Circuit::Configure(constraint_system); Assembly assembly = VerifyingKey::template CreateAssembly( @@ -116,7 +118,7 @@ void CircuitTest::LoadVerifyingKeyTest() { Circuit circuit = TestData::GetCircuit(); VerifyingKey vkey; - ASSERT_TRUE(vkey.Load(this->prover_.get(), circuit)); + ASSERT_TRUE(vkey.Load(this->prover_.get(), circuit, TestArguments::LS::type)); halo2::PinnedVerifyingKey pinned_vkey(this->prover_.get(), vkey); EXPECT_EQ(base::ToRustDebugString(pinned_vkey), @@ -140,7 +142,8 @@ void CircuitTest::LoadProvingKeyTest() { absl::Substitute("load_verifying_key: $0", load_verifying_key)); if (load_verifying_key) { VerifyingKey vkey; - ASSERT_TRUE(vkey.Load(this->prover_.get(), circuit)); + ASSERT_TRUE( + vkey.Load(this->prover_.get(), circuit, TestArguments::LS::type)); ASSERT_TRUE(pkey.LoadWithVerifyingKey(this->prover_.get(), circuit, std::move(vkey))); } else { @@ -233,7 +236,7 @@ void CircuitTest::VerifyProofTest() { Circuit circuit = TestData::GetCircuit(); VerifyingKey vkey; - ASSERT_TRUE(vkey.Load(this->prover_.get(), circuit)); + ASSERT_TRUE(vkey.Load(this->prover_.get(), circuit, TestArguments::LS::type)); std::vector owned_proof = base::ArrayToVector(TestData::kProof); diff --git a/tachyon/zk/plonk/halo2/synthesizer.h b/tachyon/zk/plonk/halo2/synthesizer.h index ac3943537..5e66f3691 100644 --- a/tachyon/zk/plonk/halo2/synthesizer.h +++ b/tachyon/zk/plonk/halo2/synthesizer.h @@ -45,7 +45,9 @@ class Synthesizer { VLOG(2) << "Generating advice columns"; CHECK_EQ(num_circuits_, circuits.size()); - ConstraintSystem empty_constraint_system; + ConstraintSystem empty_constraint_system( + constraint_system_->lookup_type()); + typename Circuit::Config config = Circuit::Configure(empty_constraint_system); diff --git a/tachyon/zk/plonk/keys/key.h b/tachyon/zk/plonk/keys/key.h index c17a59f62..10b68dcd6 100644 --- a/tachyon/zk/plonk/keys/key.h +++ b/tachyon/zk/plonk/keys/key.h @@ -28,6 +28,10 @@ struct KeyPreLoadResult { ConstraintSystem constraint_system; Assembly assembly; std::vector fixed_columns; + + KeyPreLoadResult() = default; + explicit KeyPreLoadResult(lookup::Type lookup_type) + : constraint_system(ConstraintSystem(lookup_type)) {} }; class TACHYON_EXPORT Key { @@ -62,6 +66,10 @@ class TACHYON_EXPORT Key { ConstraintSystem& constraint_system = result->constraint_system; Config config = Circuit::Configure(constraint_system); + if (constraint_system.lookup_type() == lookup::Type::kLogDerivativeHalo2) { + constraint_system.ChunkLookups(); + } + PCS& pcs = entity->pcs(); if (pcs.N() < constraint_system.ComputeMinimumRows()) { LOG(ERROR) << "Not enough rows available " << pcs.N() << " vs " diff --git a/tachyon/zk/plonk/keys/proving_key.h b/tachyon/zk/plonk/keys/proving_key.h index a560c4635..b3ad4a8cc 100644 --- a/tachyon/zk/plonk/keys/proving_key.h +++ b/tachyon/zk/plonk/keys/proving_key.h @@ -45,7 +45,7 @@ class ProvingKey : public Key { template [[nodiscard]] bool Load(ProverBase* prover, const Circuit& circuit) { using RationalEvals = typename PCS::RationalEvals; - KeyPreLoadResult pre_load_result; + KeyPreLoadResult pre_load_result(LS::type); if (!this->PreLoad(prover, circuit, &pre_load_result)) return false; VerifyingKeyLoadResult vk_result; if (!verifying_key_.DoLoad(prover, std::move(pre_load_result), &vk_result)) @@ -60,7 +60,7 @@ class ProvingKey : public Key { const Circuit& circuit, VerifyingKey&& verifying_key) { using RationalEvals = typename PCS::RationalEvals; - KeyPreLoadResult pre_load_result; + KeyPreLoadResult pre_load_result(LS::type); if (!this->PreLoad(prover, circuit, &pre_load_result)) return false; verifying_key_ = std::move(verifying_key); return DoLoad(prover, std::move(pre_load_result), nullptr); diff --git a/tachyon/zk/plonk/keys/verifying_key.h b/tachyon/zk/plonk/keys/verifying_key.h index ef05c65d9..2a71f9722 100644 --- a/tachyon/zk/plonk/keys/verifying_key.h +++ b/tachyon/zk/plonk/keys/verifying_key.h @@ -57,10 +57,11 @@ class VerifyingKey : public Key { // Return true if it is able to load from an instance of |circuit|. template - [[nodiscard]] bool Load(Entity* entity, const Circuit& circuit) { + [[nodiscard]] bool Load(Entity* entity, const Circuit& circuit, + lookup::Type lookup_type) { using Evals = typename PCS::Evals; using RationalEvals = typename PCS::RationalEvals; - KeyPreLoadResult result; + KeyPreLoadResult result(lookup_type); if (!this->PreLoad(entity, circuit, &result)) return false; // NOTE(chokobole): This helps the compiler to infer type easily. // Without this line, it won't compile. From 2e0363c8280ab39e83e16268b4a9a3a185b1af33 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Fri, 31 May 2024 18:15:29 +0900 Subject: [PATCH 10/31] refac(zk): get `RustFormatter` as a ref --- tachyon/base/strings/rust_stringifier.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tachyon/base/strings/rust_stringifier.h b/tachyon/base/strings/rust_stringifier.h index 6071dd89e..c6ae2ff05 100644 --- a/tachyon/base/strings/rust_stringifier.h +++ b/tachyon/base/strings/rust_stringifier.h @@ -20,7 +20,7 @@ class RustDebugStringifier; class TACHYON_EXPORT DebugStruct { public: - DebugStruct(RustFormatter* fmt, std::string_view name) : fmt_(fmt) { + DebugStruct(RustFormatter& fmt, std::string_view name) : fmt_(fmt) { ss_ << name << " { "; } @@ -30,7 +30,7 @@ class TACHYON_EXPORT DebugStruct { ss_ << ", "; } ss_ << name << ": "; - RustDebugStringifier::AppendToStream(ss_, *fmt_, value); + RustDebugStringifier::AppendToStream(ss_, fmt_, value); has_field_ = true; return *this; } @@ -41,14 +41,14 @@ class TACHYON_EXPORT DebugStruct { } private: - RustFormatter* fmt_ = nullptr; + RustFormatter& fmt_; std::stringstream ss_; bool has_field_ = false; }; class TACHYON_EXPORT DebugTuple { public: - DebugTuple(RustFormatter* fmt, std::string_view name) : fmt_(fmt) { + DebugTuple(RustFormatter& fmt, std::string_view name) : fmt_(fmt) { ss_ << name << "("; } @@ -57,7 +57,7 @@ class TACHYON_EXPORT DebugTuple { if (has_field_) { ss_ << ", "; } - RustDebugStringifier::AppendToStream(ss_, *fmt_, value); + RustDebugStringifier::AppendToStream(ss_, fmt_, value); has_field_ = true; return *this; } @@ -68,21 +68,21 @@ class TACHYON_EXPORT DebugTuple { } private: - RustFormatter* fmt_ = nullptr; + RustFormatter& fmt_; std::stringstream ss_; bool has_field_ = false; }; class TACHYON_EXPORT DebugList { public: - explicit DebugList(RustFormatter* fmt) : fmt_(fmt) { ss_ << "["; } + explicit DebugList(RustFormatter& fmt) : fmt_(fmt) { ss_ << "["; } template DebugList& Entry(const T& value) { if (has_entry_) { ss_ << ", "; } - RustDebugStringifier::AppendToStream(ss_, *fmt_, value); + RustDebugStringifier::AppendToStream(ss_, fmt_, value); has_entry_ = true; return *this; } @@ -93,7 +93,7 @@ class TACHYON_EXPORT DebugList { } private: - RustFormatter* fmt_ = nullptr; + RustFormatter& fmt_; std::stringstream ss_; bool has_entry_ = false; }; @@ -105,14 +105,14 @@ class TACHYON_EXPORT RustFormatter { RustFormatter() = default; internal::DebugStruct DebugStruct(std::string_view name) { - return internal::DebugStruct(this, name); + return internal::DebugStruct(*this, name); } internal::DebugTuple DebugTuple(std::string_view name) { - return internal::DebugTuple(this, name); + return internal::DebugTuple(*this, name); } - internal::DebugList DebugList() { return internal::DebugList(this); } + internal::DebugList DebugList() { return internal::DebugList(*this); } }; namespace internal { From e48089b8a97abb68cadcf3142617a47b0511e241 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Thu, 13 Jun 2024 19:02:20 +0900 Subject: [PATCH 11/31] feat(zk): add stringifiers for `LookupsMap` Add `btree_map_stringifier` and `lookup_tracker_stringifier`. --- tachyon/base/strings/BUILD.bazel | 5 ++- tachyon/base/strings/rust_stringifier.h | 44 +++++++++++++++++++ tachyon/zk/plonk/halo2/BUILD.bazel | 1 + .../zk/plonk/halo2/pinned_constraint_system.h | 22 ++++++++-- .../zk/plonk/halo2/stringifiers/BUILD.bazel | 9 ++++ .../stringifiers/lookup_tracker_stringifier.h | 32 ++++++++++++++ 6 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 tachyon/zk/plonk/halo2/stringifiers/lookup_tracker_stringifier.h diff --git a/tachyon/base/strings/BUILD.bazel b/tachyon/base/strings/BUILD.bazel index f0f504bfe..4d0433a64 100644 --- a/tachyon/base/strings/BUILD.bazel +++ b/tachyon/base/strings/BUILD.bazel @@ -11,7 +11,10 @@ package(default_visibility = ["//visibility:public"]) tachyon_cc_library( name = "rust_stringifier", hdrs = ["rust_stringifier.h"], - deps = ["//tachyon:export"], + deps = [ + "//tachyon:export", + "@com_google_absl//absl/container:btree", + ], ) tachyon_cc_library( diff --git a/tachyon/base/strings/rust_stringifier.h b/tachyon/base/strings/rust_stringifier.h index c6ae2ff05..feb6ba87d 100644 --- a/tachyon/base/strings/rust_stringifier.h +++ b/tachyon/base/strings/rust_stringifier.h @@ -7,6 +7,8 @@ #include #include +#include "absl/container/btree_map.h" + #include "tachyon/export.h" namespace tachyon::base { @@ -98,6 +100,33 @@ class TACHYON_EXPORT DebugList { bool has_entry_ = false; }; +class TACHYON_EXPORT DebugMap { + public: + explicit DebugMap(RustFormatter& fmt) : fmt_(fmt) { ss_ << "{"; } + + template + DebugMap& Pair(const T& key, const U& value) { + if (has_entry_) { + ss_ << ", "; + } + RustDebugStringifier::AppendToStream(ss_, fmt_, key); + ss_ << ": "; + RustDebugStringifier::AppendToStream(ss_, fmt_, value); + has_entry_ = true; + return *this; + } + + std::string Finish() { + ss_ << "}"; + return ss_.str(); + } + + private: + RustFormatter& fmt_; + std::stringstream ss_; + bool has_entry_ = false; +}; + } // namespace internal class TACHYON_EXPORT RustFormatter { @@ -113,6 +142,8 @@ class TACHYON_EXPORT RustFormatter { } internal::DebugList DebugList() { return internal::DebugList(*this); } + + internal::DebugMap DebugMap() { return internal::DebugMap(*this); } }; namespace internal { @@ -198,6 +229,19 @@ class RustDebugStringifier> { } }; +template +class RustDebugStringifier> { + public: + static std::ostream& AppendToStream(std::ostream& os, RustFormatter& fmt, + const absl::btree_map& btree_map) { + DebugMap debug_map = fmt.DebugMap(); + for (const auto& [key, value] : btree_map) { + debug_map.Pair(key, value); + } + return os << debug_map.Finish(); + } +}; + } // namespace internal template diff --git a/tachyon/zk/plonk/halo2/BUILD.bazel b/tachyon/zk/plonk/halo2/BUILD.bazel index 4cb72e368..480310369 100644 --- a/tachyon/zk/plonk/halo2/BUILD.bazel +++ b/tachyon/zk/plonk/halo2/BUILD.bazel @@ -69,6 +69,7 @@ tachyon_cc_library( ":pinned_gates", "//tachyon/zk/plonk/constraint_system", "//tachyon/zk/plonk/halo2/stringifiers:lookup_argument_stringifier", + "//tachyon/zk/plonk/halo2/stringifiers:lookup_tracker_stringifier", "//tachyon/zk/plonk/halo2/stringifiers:permutation_argument_stringifier", "//tachyon/zk/plonk/halo2/stringifiers:phase_stringifier", "//tachyon/zk/plonk/halo2/stringifiers:query_stringifier", diff --git a/tachyon/zk/plonk/halo2/pinned_constraint_system.h b/tachyon/zk/plonk/halo2/pinned_constraint_system.h index e586a050c..b81505234 100644 --- a/tachyon/zk/plonk/halo2/pinned_constraint_system.h +++ b/tachyon/zk/plonk/halo2/pinned_constraint_system.h @@ -14,6 +14,7 @@ #include "tachyon/zk/plonk/constraint_system/constraint_system.h" #include "tachyon/zk/plonk/halo2/pinned_gates.h" #include "tachyon/zk/plonk/halo2/stringifiers/lookup_argument_stringifier.h" +#include "tachyon/zk/plonk/halo2/stringifiers/lookup_tracker_stringifier.h" #include "tachyon/zk/plonk/halo2/stringifiers/permutation_argument_stringifier.h" #include "tachyon/zk/plonk/halo2/stringifiers/phase_stringifier.h" #include "tachyon/zk/plonk/halo2/stringifiers/query_stringifier.h" @@ -25,7 +26,8 @@ template class PinnedConstraintSystem { public: explicit PinnedConstraintSystem(const ConstraintSystem& constraint_system) - : num_fixed_columns_(constraint_system.num_fixed_columns()), + : lookup_type_(constraint_system.lookup_type()), + num_fixed_columns_(constraint_system.num_fixed_columns()), num_advice_columns_(constraint_system.num_advice_columns()), num_instance_columns_(constraint_system.num_instance_columns()), num_selectors_(constraint_system.num_selectors()), @@ -38,9 +40,11 @@ class PinnedConstraintSystem { fixed_queries_(constraint_system.fixed_queries()), permutation_(constraint_system.permutation()), lookups_(constraint_system.lookups()), + lookups_map_(constraint_system.lookups_map()), constants_(constraint_system.constants()), minimum_degree_(constraint_system.minimum_degree()) {} + lookup::Type lookup_type() const { return lookup_type_; } size_t num_fixed_columns() const { return num_fixed_columns_; } size_t num_advice_columns() const { return num_advice_columns_; } size_t num_instance_columns() const { return num_instance_columns_; } @@ -65,11 +69,15 @@ class PinnedConstraintSystem { const PermutationArgument& permutation() const { return permutation_; } const std::vector>& lookups() const { return lookups_; } const std::vector& constants() const { return constants_; } + const absl::btree_map>& lookups_map() const { + return lookups_map_; + } const std::optional& minimum_degree() const { return minimum_degree_; } private: + lookup::Type lookup_type_; size_t num_fixed_columns_; size_t num_advice_columns_; size_t num_instance_columns_; @@ -83,6 +91,7 @@ class PinnedConstraintSystem { const std::vector& fixed_queries_; PermutationArgument permutation_; const std::vector>& lookups_; + const absl::btree_map>& lookups_map_; const std::vector& constants_; const std::optional& minimum_degree_; }; @@ -113,9 +122,14 @@ class RustDebugStringifier> { .Field("advice_queries", constraint_system.advice_queries()) .Field("instance_queries", constraint_system.instance_queries()) .Field("fixed_queries", constraint_system.fixed_queries()) - .Field("permutation", constraint_system.permutation()) - .Field("lookups", constraint_system.lookups()) - .Field("constants", constraint_system.constants()) + .Field("permutation", constraint_system.permutation()); + if (constraint_system.lookup_type() == zk::lookup::Type::kHalo2) { + debug_struct.Field("lookups", constraint_system.lookups()); + } else if (constraint_system.lookup_type() == + zk::lookup::Type::kLogDerivativeHalo2) { + debug_struct.Field("lookups_map", constraint_system.lookups_map()); + } + debug_struct.Field("constants", constraint_system.constants()) .Field("minimum_degree", constraint_system.minimum_degree()); return os << debug_struct.Finish(); } diff --git a/tachyon/zk/plonk/halo2/stringifiers/BUILD.bazel b/tachyon/zk/plonk/halo2/stringifiers/BUILD.bazel index 96537fa26..80ee180b5 100644 --- a/tachyon/zk/plonk/halo2/stringifiers/BUILD.bazel +++ b/tachyon/zk/plonk/halo2/stringifiers/BUILD.bazel @@ -69,6 +69,15 @@ tachyon_cc_library( ], ) +tachyon_cc_library( + name = "lookup_tracker_stringifier", + hdrs = ["lookup_tracker_stringifier.h"], + deps = [ + "//tachyon/base/strings:rust_stringifier", + "//tachyon/zk/plonk/constraint_system:lookup_tracker", + ], +) + tachyon_cc_library( name = "permutation_argument_stringifier", hdrs = ["permutation_argument_stringifier.h"], diff --git a/tachyon/zk/plonk/halo2/stringifiers/lookup_tracker_stringifier.h b/tachyon/zk/plonk/halo2/stringifiers/lookup_tracker_stringifier.h new file mode 100644 index 000000000..368ea4635 --- /dev/null +++ b/tachyon/zk/plonk/halo2/stringifiers/lookup_tracker_stringifier.h @@ -0,0 +1,32 @@ +// 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_HALO2_STRINGIFIERS_LOOKUP_TRACKER_STRINGIFIER_H_ +#define TACHYON_ZK_PLONK_HALO2_STRINGIFIERS_LOOKUP_TRACKER_STRINGIFIER_H_ + +#include + +#include "tachyon/base/strings/rust_stringifier.h" +#include "tachyon/zk/plonk/constraint_system/lookup_tracker.h" + +namespace tachyon::base::internal { + +template +class RustDebugStringifier> { + public: + static std::ostream& AppendToStream( + std::ostream& os, RustFormatter& fmt, + const zk::plonk::LookupTracker& lookup_tracker) { + return os << fmt.DebugStruct("LookupTracker") + .Field("table", lookup_tracker.table) + .Field("inputs", lookup_tracker.inputs) + .Finish(); + } +}; + +} // namespace tachyon::base::internal + +#endif // TACHYON_ZK_PLONK_HALO2_STRINGIFIERS_LOOKUP_TRACKER_STRINGIFIER_H_ From 08369d672022df6b79d69ea9ceaf53505b3a1e09 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 3 Jun 2024 15:42:09 +0900 Subject: [PATCH 12/31] chore(zk): change specifiers order --- tachyon/zk/lookup/halo2/scheme.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tachyon/zk/lookup/halo2/scheme.h b/tachyon/zk/lookup/halo2/scheme.h index dabfb4e84..943152339 100644 --- a/tachyon/zk/lookup/halo2/scheme.h +++ b/tachyon/zk/lookup/halo2/scheme.h @@ -21,7 +21,7 @@ struct Scheme { using VerifierData = lookup::halo2::VerifierData; using Evaluator = lookup::halo2::Evaluator; - static constexpr Type type = Type::kHalo2; + constexpr static Type type = Type::kHalo2; }; } // namespace tachyon::zk::lookup::halo2 From a10b8cac58997b54b18795cbbdf80fc3d033ab8d Mon Sep 17 00:00:00 2001 From: Insun35 Date: Thu, 13 Jun 2024 17:20:13 +0900 Subject: [PATCH 13/31] feat(base): implement `BinarySearchByKey` See https://doc.rust-lang.org/src/core/slice/mod.rs.html#2788-2821 --- tachyon/base/containers/container_util.h | 22 ++++++++++++++ .../containers/container_util_unittest.cc | 30 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/tachyon/base/containers/container_util.h b/tachyon/base/containers/container_util.h index 6d9f79644..b573d5de0 100644 --- a/tachyon/base/containers/container_util.h +++ b/tachyon/base/containers/container_util.h @@ -134,6 +134,28 @@ auto FlatMap(Container&& container, UnaryOp&& op) { std::forward(op)); } +enum class Ordering { Less, Equal, Greater }; + +template +Iterator BinarySearchByKey(Iterator begin, Iterator end, const T& value, + Comparator cmp) { + Iterator left = begin; + Iterator right = end; + + while (left < right) { + Iterator mid = left + (std::distance(left, right) / 2); + Ordering order = cmp(*mid, value); + if (order == Ordering::Less) { + left = mid + 1; + } else if (order == Ordering::Greater) { + right = mid; + } else { + return mid; + } + } + return end; +} + template std::optional FindIndex(Iterator begin, Iterator end, const T& value) { auto it = std::find(begin, end, value); diff --git a/tachyon/base/containers/container_util_unittest.cc b/tachyon/base/containers/container_util_unittest.cc index d1e40740e..564d08c35 100644 --- a/tachyon/base/containers/container_util_unittest.cc +++ b/tachyon/base/containers/container_util_unittest.cc @@ -142,4 +142,34 @@ TEST(ContainerUtilTest, Shuffle) { FAIL() << "shuffle seems not working"; } +TEST(ContainerUtilTest, BinarySearchByKey) { + struct TestData { + std::vector data; + int value; + std::optional expected_index; + }; + + std::vector tests = { + {{1, 2, 3, 4, 5}, 3, 2}, {{1, 2, 3, 4, 5}, 1, 0}, + {{1, 2, 3, 4, 5}, 5, 4}, {{1, 2, 3, 4, 5}, 6, std::nullopt}, + {{}, 3, std::nullopt}, + }; + + for (const auto& test : tests) { + auto it = BinarySearchByKey(test.data.begin(), test.data.end(), test.value, + [](const int& elem, const int& value) { + if (elem < value) return Ordering::Less; + if (elem > value) return Ordering::Greater; + return Ordering::Equal; + }); + + if (test.expected_index.has_value()) { + EXPECT_EQ(std::distance(test.data.begin(), it), + test.expected_index.value()); + } else { + EXPECT_EQ(it, test.data.end()); + } + } +} + } // namespace tachyon::base From 09b77c8a1fcda3f5627b3cccf5a98bee89b82287 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 20 May 2024 04:58:02 +0900 Subject: [PATCH 14/31] feat(zk): implement `LogDerivativeHalo2` prover See: https://github.com/scroll-tech/halo2/blob/1070391642dd64b2d68b47ec246cba9e35bd3c15/halo2_proofs/src/plonk/mv_lookup/prover.rs --- LICENSE-APACHE.scroll | 202 +++++++++ LICENSE-MIT.scroll | 21 + .../lookup/log_derivative_halo2/BUILD.bazel | 33 ++ .../zk/lookup/log_derivative_halo2/prover.h | 160 +++++++ .../lookup/log_derivative_halo2/prover_impl.h | 397 ++++++++++++++++++ .../zk/lookup/log_derivative_halo2/scheme.h | 23 + 6 files changed, 836 insertions(+) create mode 100644 LICENSE-APACHE.scroll create mode 100644 LICENSE-MIT.scroll create mode 100644 tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel create mode 100644 tachyon/zk/lookup/log_derivative_halo2/prover.h create mode 100644 tachyon/zk/lookup/log_derivative_halo2/prover_impl.h create mode 100644 tachyon/zk/lookup/log_derivative_halo2/scheme.h diff --git a/LICENSE-APACHE.scroll b/LICENSE-APACHE.scroll new file mode 100644 index 000000000..1e5006dc1 --- /dev/null +++ b/LICENSE-APACHE.scroll @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/LICENSE-MIT.scroll b/LICENSE-MIT.scroll new file mode 100644 index 000000000..606971910 --- /dev/null +++ b/LICENSE-MIT.scroll @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2024 Scroll + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel b/tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel new file mode 100644 index 000000000..067e9b93b --- /dev/null +++ b/tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel @@ -0,0 +1,33 @@ +load("//bazel:tachyon_cc.bzl", "tachyon_cc_library") + +package(default_visibility = ["//visibility:public"]) + +tachyon_cc_library( + name = "prover", + hdrs = [ + "prover.h", + "prover_impl.h", + ], + deps = [ + "//tachyon/base:parallelize", + "//tachyon/base:ref", + "//tachyon/base/containers:container_util", + "//tachyon/crypto/commitments:polynomial_openings", + "//tachyon/zk/base/entities:prover_base", + "//tachyon/zk/lookup:lookup_argument", + "//tachyon/zk/lookup:proving_evaluator", + "//tachyon/zk/lookup/halo2:compress_expression", + "//tachyon/zk/lookup/halo2:opening_point_set", + "//tachyon/zk/plonk/base:multi_phase_ref_table", + "@pdqsort", + ], +) + +tachyon_cc_library( + name = "scheme", + hdrs = ["scheme.h"], + deps = [ + ":prover", + "//tachyon/zk/lookup:type", + ], +) diff --git a/tachyon/zk/lookup/log_derivative_halo2/prover.h b/tachyon/zk/lookup/log_derivative_halo2/prover.h new file mode 100644 index 000000000..6dac41d2f --- /dev/null +++ b/tachyon/zk/lookup/log_derivative_halo2/prover.h @@ -0,0 +1,160 @@ +// Copyright (c) 2022-2024 Scroll +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.scroll and the LICENCE-APACHE.scroll +// file. + +#ifndef TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_PROVER_H_ +#define TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_PROVER_H_ + +#include + +#include "tachyon/crypto/commitments/polynomial_openings.h" +#include "tachyon/zk/base/blinded_polynomial.h" +#include "tachyon/zk/base/entities/prover_base.h" +#include "tachyon/zk/lookup/halo2/opening_point_set.h" +#include "tachyon/zk/lookup/lookup_argument.h" +#include "tachyon/zk/lookup/proving_evaluator.h" +#include "tachyon/zk/plonk/base/multi_phase_ref_table.h" + +namespace tachyon::zk::lookup::log_derivative_halo2 { + +template +class Prover { + public: + using F = typename Poly::Field; + + const std::vector>& compressed_inputs_vec() const { + return compressed_inputs_vec_; + } + const std::vector& compressed_tables() const { + return compressed_tables_; + } + const std::vector>& m_polys() const { + return m_polys_; + } + const std::vector>& grand_sum_polys() const { + return grand_sum_polys_; + } + + template + static void BatchCompressPairs( + std::vector& lookup_provers, const Domain* domain, + const std::vector>& arguments, const F& theta, + const std::vector>& tables); + + template + static void BatchComputeMPolys(std::vector& lookup_provers, + ProverBase* prover) { + for (Prover& lookup_prover : lookup_provers) { + lookup_prover.ComputeMPolys(prover); + } + } + + constexpr static size_t GetNumMPolysCommitments( + const std::vector& lookup_provers) { + if (lookup_provers.empty()) return 0; + return lookup_provers.size() * lookup_provers[0].m_polys_.size(); + } + + template + static void BatchCommitMPolys(const std::vector& lookup_provers, + ProverBase* prover, size_t& commit_idx); + + template + static void BatchCreateGrandSumPolys(std::vector& lookup_provers, + ProverBase* prover, const F& beta) { + for (Prover& lookup_prover : lookup_provers) { + lookup_prover.CreateGrandSumPolys(prover, beta); + } + } + + constexpr static size_t GetNumGrandSumPolysCommitments( + const std::vector& lookup_provers) { + if (lookup_provers.empty()) return 0; + return lookup_provers.size() * lookup_provers[0].grand_sum_polys_.size(); + } + + template + static void BatchCommitGrandSumPolys( + const std::vector& lookup_provers, ProverBase* prover, + size_t& commit_idx); + + template + static void TransformEvalsToPoly(std::vector& lookup_provers, + const Domain* domain) { + VLOG(2) << "Transform lookup virtual columns to polys"; + for (Prover& lookup_prover : lookup_provers) { + lookup_prover.TransformEvalsToPoly(domain); + } + } + + template + static void BatchEvaluate(const std::vector& lookup_provers, + ProverBase* prover, + const halo2::OpeningPointSet& point_set) { + for (const Prover& lookup_prover : lookup_provers) { + lookup_prover.Evaluate(prover, point_set); + } + } + + void Open(const halo2::OpeningPointSet& point_set, + std::vector>& openings) const; + + private: + template + static std::vector CompressInputs( + const Domain* domain, const Argument& argument, const F& theta, + const ProvingEvaluator& evaluator_tpl); + + template + static Evals CompressTable(const Domain* domain, const Argument& argument, + const F& theta, + const ProvingEvaluator& evaluator_tpl); + + template + void CompressPairs(const Domain* domain, + const std::vector>& arguments, const F& theta, + const ProvingEvaluator& evaluator_tpl); + + template + static BlindedPolynomial ComputeMPoly( + ProverBase* prover, const std::vector& compressed_inputs, + const Evals& compressed_table); + + template + void ComputeMPolys(ProverBase* prover); + + static void ComputeLogDerivatives(const Evals& evals, const F& beta, + std::vector& ret); + + template + static BlindedPolynomial CreateGrandSumPoly( + ProverBase* prover, const Evals& m_values, + const std::vector& compressed_inputs, + const Evals& compressed_table, const F& beta); + + template + void CreateGrandSumPolys(ProverBase* prover, const F& beta); + + template + void TransformEvalsToPoly(const Domain* domain); + + template + void Evaluate(ProverBase* prover, + const halo2::OpeningPointSet& point_set) const; + + // fᵢ(X) + std::vector> compressed_inputs_vec_; + // t(X) + std::vector compressed_tables_; + // m(X) + std::vector> m_polys_; + // ϕ(X) + std::vector> grand_sum_polys_; +}; + +} // namespace tachyon::zk::lookup::log_derivative_halo2 + +#include "tachyon/zk/lookup/log_derivative_halo2/prover_impl.h" + +#endif // TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_PROVER_H_ diff --git a/tachyon/zk/lookup/log_derivative_halo2/prover_impl.h b/tachyon/zk/lookup/log_derivative_halo2/prover_impl.h new file mode 100644 index 000000000..f8e817263 --- /dev/null +++ b/tachyon/zk/lookup/log_derivative_halo2/prover_impl.h @@ -0,0 +1,397 @@ +// Copyright (c) 2022-2024 Scroll +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.scroll and the LICENCE-APACHE.scroll +// file. + +#ifndef TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_PROVER_IMPL_H_ +#define TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_PROVER_IMPL_H_ + +#include +#include +#include +#include + +#include "third_party/pdqsort/include/pdqsort.h" + +#include "tachyon/base/containers/container_util.h" +#include "tachyon/base/parallelize.h" +#include "tachyon/base/ref.h" +#include "tachyon/zk/lookup/halo2/compress_expression.h" +#include "tachyon/zk/lookup/log_derivative_halo2/prover.h" + +namespace tachyon::zk::lookup::log_derivative_halo2 { + +// static +template +template +std::vector Prover::CompressInputs( + const Domain* domain, const Argument& argument, const F& theta, + const ProvingEvaluator& evaluator_tpl) { + // f_compressedᵢ(X) = θᵐ⁻¹f₀(X) + θᵐ⁻²f₁(X) + ... + θfₘ₋₂(X) + fₘ₋₁(X) + return base::Map(argument.inputs_expressions(), + [&domain, &theta, &evaluator_tpl]( + const std::vector>>& + input_expressions) { + return halo2::CompressExpressions( + domain, input_expressions, theta, evaluator_tpl); + }); +} + +// static +template +template +Evals Prover::CompressTable( + const Domain* domain, const Argument& argument, const F& theta, + const ProvingEvaluator& evaluator_tpl) { + // t_compressedᵢ(X) = θᵐ⁻¹t₀(X) + θᵐ⁻²t₁(X) + ... + θtₘ₋₂(X) + tₘ₋₁(X) + return halo2::CompressExpressions(domain, argument.table_expressions(), theta, + evaluator_tpl); +} + +template +template +void Prover::CompressPairs( + const Domain* domain, const std::vector>& arguments, + const F& theta, const ProvingEvaluator& evaluator_tpl) { + compressed_inputs_vec_.reserve(arguments.size()); + compressed_tables_.reserve(arguments.size()); + for (const Argument& argument : arguments) { + compressed_inputs_vec_.push_back( + CompressInputs(domain, argument, theta, evaluator_tpl)); + compressed_tables_.push_back( + CompressTable(domain, argument, theta, evaluator_tpl)); + } +} + +// static +template +template +void Prover::BatchCompressPairs( + std::vector& lookup_provers, const Domain* domain, + const std::vector>& arguments, const F& theta, + const std::vector>& tables) { + CHECK_EQ(lookup_provers.size(), tables.size()); + // NOTE(chokobole): It's safe to downcast because domain is already checked. + int32_t n = static_cast(domain->size()); + for (size_t i = 0; i < lookup_provers.size(); ++i) { + ProvingEvaluator proving_evaluator(0, n, 1, tables[i]); + lookup_provers[i].CompressPairs(domain, arguments, theta, + proving_evaluator); + } +} + +template +struct TableEvalWithIndex { + RowIndex index; + BigInt eval; + + TableEvalWithIndex(RowIndex index, const BigInt& eval) + : index(index), eval(eval) {} + + bool operator<(const TableEvalWithIndex& other) const { + return eval < other.eval; + } +}; + +// static +template +template +BlindedPolynomial Prover::ComputeMPoly( + ProverBase* prover, const std::vector& compressed_inputs, + const Evals& compressed_table) { + RowIndex usable_rows = static_cast(prover->GetUsableRows()); + + std::vector> + sorted_table_with_indices = + base::CreateVector(usable_rows, [&compressed_table](RowIndex i) { + return TableEvalWithIndex(i, compressed_table[i].ToBigInt()); + }); + + pdqsort(sorted_table_with_indices.begin(), sorted_table_with_indices.end()); + + std::vector> m_values_atomic(prover->pcs().N()); + std::fill(m_values_atomic.begin(), m_values_atomic.end(), 0); + OPENMP_PARALLEL_NESTED_FOR(size_t i = 0; i < compressed_inputs.size(); ++i) { + for (RowIndex j = 0; j < usable_rows; ++j) { + typename F::BigIntTy input = compressed_inputs[i][j].ToBigInt(); + auto it = base::BinarySearchByKey( + sorted_table_with_indices.begin(), sorted_table_with_indices.end(), + input, + [](const TableEvalWithIndex& elem, + const typename F::BigIntTy& value) { + if (elem.eval < value) { + return base::Ordering::Less; + } else if (value < elem.eval) { + return base::Ordering::Greater; + } else { + return base::Ordering::Equal; + } + }); + if (it != sorted_table_with_indices.end() && it->eval == input) { + m_values_atomic[it->index].fetch_add(1, std::memory_order_relaxed); + } + } + } + + // Convert atomic |m_values| to |Evals|. + std::vector m_values(m_values_atomic.size()); + std::transform(m_values_atomic.begin(), m_values_atomic.end(), + m_values.begin(), [](const std::atomic& val) { + return F(val.load(std::memory_order_relaxed)); + }); + + BlindedPolynomial m_poly(Evals(std::move(m_values)), + prover->blinder().Generate()); + return m_poly; +} + +template +template +void Prover::ComputeMPolys(ProverBase* prover) { + CHECK_EQ(compressed_inputs_vec_.size(), compressed_tables_.size()); + m_polys_ = base::Map( + compressed_inputs_vec_, + [this, prover](size_t i, const std::vector& compressed_inputs) { + return ComputeMPoly(prover, compressed_inputs, compressed_tables_[i]); + }); +} + +// static +template +template +void Prover::BatchCommitMPolys( + const std::vector& lookup_provers, ProverBase* prover, + size_t& commit_idx) { + if (lookup_provers.empty()) return; + + if constexpr (PCS::kSupportsBatchMode) { + for (const Prover& lookup_prover : lookup_provers) { + for (const BlindedPolynomial& m_poly : + lookup_prover.m_polys()) { + prover->BatchCommitAt(m_poly.evals(), commit_idx++); + } + } + } else { + for (const Prover& lookup_prover : lookup_provers) { + for (const BlindedPolynomial& m_poly : + lookup_prover.m_polys()) { + prover->CommitAndWriteToProof(m_poly.evals()); + } + } + } +} + +// static +template +void Prover::ComputeLogDerivatives(const Evals& evals, + const F& beta, + std::vector& ret) { + base::Parallelize(ret, + [&evals, &beta](absl::Span chunk, size_t chunk_offset, + size_t chunk_size) { + size_t start = chunk_offset * chunk_size; + for (size_t i = 0; i < chunk.size(); ++i) { + chunk[i] = beta + evals.evaluations()[start + i]; + } + CHECK(F::BatchInverseInPlaceSerial(chunk)); + }); +} + +// static +template +template +BlindedPolynomial Prover::CreateGrandSumPoly( + ProverBase* prover, const Evals& m_values, + const std::vector& compressed_inputs, const Evals& compressed_table, + const F& beta) { + size_t n = prover->pcs().N(); + + // Σ 1/(φᵢ(X)) + std::vector inputs_log_derivatives(n, F::Zero()); + std::vector input_log_derivatives( + compressed_inputs[0].evaluations().size()); + for (const Evals& compressed_input : compressed_inputs) { + ComputeLogDerivatives(compressed_input, beta, input_log_derivatives); + + OPENMP_PARALLEL_FOR(size_t i = 0; i < n; ++i) { + inputs_log_derivatives[i] += input_log_derivatives[i]; + } + } + + // 1 / τ(X) + std::vector table_log_derivatives(compressed_table.evaluations().size()); + ComputeLogDerivatives(compressed_table, beta, table_log_derivatives); + + std::vector grand_sum(n); + grand_sum[0] = F::Zero(); + + // (Σ 1/φᵢ(X)) - m(X) / τ(X) + RowIndex usable_rows = prover->GetUsableRows(); + std::vector log_derivatives_diff(usable_rows); + OPENMP_PARALLEL_FOR(size_t i = 0; i < usable_rows; ++i) { + log_derivatives_diff[i] = + inputs_log_derivatives[i] - m_values[i] * table_log_derivatives[i]; + if (i != usable_rows - 1) { + grand_sum[i + 1] = log_derivatives_diff[i]; + } + } + +// let L(X) = (Σ 1/φᵢ(X)) - m(X) / τ(X) +// ϕ(ω⁰) = 0 +// ϕ(ω¹) = L(ω⁰) +// ... +// ϕ(ω^last) = L(ω⁰) + L(ω¹) + ... + L(ω^{usable_rows - 1}) +#if defined(TACHYON_HAS_OPENMP) + size_t thread_nums = static_cast(omp_get_max_threads()); + size_t chunk_size = usable_rows / thread_nums; + if (chunk_size < thread_nums) { + chunk_size = 1; + } + size_t num_chunks = (usable_rows + chunk_size - 1) / chunk_size; + + std::vector segment_sum(num_chunks, F::Zero()); + + OPENMP_PARALLEL_FOR(size_t chunk_idx = 0; chunk_idx < num_chunks; + ++chunk_idx) { + size_t start = chunk_idx * chunk_size; + size_t end = std::min(start + chunk_size, static_cast(usable_rows)); + for (size_t i = start + 1; i < end; ++i) { + grand_sum[i] = grand_sum[i - 1] + log_derivatives_diff[i - 1]; + } + segment_sum[chunk_idx] = grand_sum[end - 1]; + } + + for (size_t i = 1; i < segment_sum.size(); ++i) { + segment_sum[i] += segment_sum[i - 1]; + } + + OPENMP_PARALLEL_FOR(size_t chunk_idx = 1; chunk_idx < num_chunks; + ++chunk_idx) { + size_t start = chunk_idx * chunk_size; + size_t end = std::min(start + chunk_size, static_cast(usable_rows)); + F prefix_sum = segment_sum[chunk_idx - 1]; + for (size_t i = start; i < end; ++i) { + grand_sum[i] += prefix_sum; + } + } +#else + std::partial_sum(log_derivatives_diff.begin(), log_derivatives_diff.end() - 1, + grand_sum.begin() + 1); +#endif + + Evals grand_sum_poly(std::move(grand_sum)); + + CHECK(prover->blinder().Blind(grand_sum_poly)); + + return BlindedPolynomial(std::move(grand_sum_poly), + prover->blinder().Generate()); +} + +template +template +void Prover::CreateGrandSumPolys(ProverBase* prover, + const F& beta) { + CHECK_EQ(compressed_inputs_vec_.size(), compressed_tables_.size()); + grand_sum_polys_ = + base::Map(compressed_inputs_vec_, + [this, &prover, &beta]( + size_t i, const std::vector& compressed_inputs) { + return CreateGrandSumPoly(prover, m_polys_[i].evals(), + compressed_inputs, + compressed_tables_[i], beta); + }); +} + +// static +template +template +void Prover::BatchCommitGrandSumPolys( + const std::vector& lookup_provers, ProverBase* prover, + size_t& commit_idx) { + if (lookup_provers.empty()) return; + + if constexpr (PCS::kSupportsBatchMode) { + for (const Prover& lookup_prover : lookup_provers) { + for (const BlindedPolynomial& grand_sum_poly : + lookup_prover.grand_sum_polys_) { + prover->BatchCommitAt(grand_sum_poly.evals(), commit_idx++); + } + } + } else { + for (const Prover& lookup_prover : lookup_provers) { + for (const BlindedPolynomial& grand_sum_poly : + lookup_prover.grand_sum_polys_) { + prover->CommitAndWriteToProof(grand_sum_poly.evals()); + } + } + } +} + +template +template +void Prover::TransformEvalsToPoly(const Domain* domain) { + for (BlindedPolynomial& m_poly : m_polys_) { + m_poly.TransformEvalsToPoly(domain); + } + for (BlindedPolynomial& grand_sum_poly : grand_sum_polys_) { + grand_sum_poly.TransformEvalsToPoly(domain); + } +} + +template +template +void Prover::Evaluate( + ProverBase* prover, const halo2::OpeningPointSet& point_set) const { + size_t size = grand_sum_polys_.size(); + CHECK_EQ(size, m_polys_.size()); + +#define EVALUATE(polynomial, point) \ + prover->EvaluateAndWriteToProof(polynomial.poly(), point_set.point) + + // THE ORDER IS IMPORTANT!! DO NOT CHANGE! + // See + // https://github.com/scroll-tech/halo2/blob/1070391642dd64b2d68b47ec246cba9e35bd3c15/halo2_proofs/src/plonk/mv_lookup/prover.rs#L428-L453 + for (size_t i = 0; i < size; ++i) { + const BlindedPolynomial& grand_sum_poly = grand_sum_polys_[i]; + const BlindedPolynomial& m_poly = m_polys_[i]; + + // ϕᵢ(x) + EVALUATE(grand_sum_poly, x); + // ϕᵢ(ω * x) + EVALUATE(grand_sum_poly, x_next); + // mᵢ(x) + EVALUATE(m_poly, x); + } +#undef EVALUATE +} + +template +void Prover::Open( + const halo2::OpeningPointSet& point_set, + std::vector>& openings) const { + size_t size = grand_sum_polys_.size(); + CHECK_EQ(size, m_polys_.size()); + +#define OPENING(polynomial, point) \ + base::Ref(&polynomial.poly()), point_set.point, \ + polynomial.poly().Evaluate(point_set.point) + + // THE ORDER IS IMPORTANT!! DO NOT CHANGE! + // See + // https://github.com/scroll-tech/halo2/blob/1070391642dd64b2d68b47ec246cba9e35bd3c15/halo2_proofs/src/plonk/mv_lookup/prover.rs#L455-L480 + for (size_t i = 0; i < size; ++i) { + const BlindedPolynomial& grand_sum_poly = grand_sum_polys_[i]; + const BlindedPolynomial& m_poly = m_polys_[i]; + // ϕᵢ(x) + openings.emplace_back(OPENING(grand_sum_poly, x)); + // ϕᵢ(ω * x) + openings.emplace_back(OPENING(grand_sum_poly, x_next)); + // mᵢ(x) + openings.emplace_back(OPENING(m_poly, x)); + } +#undef OPENING +} + +} // namespace tachyon::zk::lookup::log_derivative_halo2 + +#endif // TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_PROVER_IMPL_H_ diff --git a/tachyon/zk/lookup/log_derivative_halo2/scheme.h b/tachyon/zk/lookup/log_derivative_halo2/scheme.h new file mode 100644 index 000000000..2896055bb --- /dev/null +++ b/tachyon/zk/lookup/log_derivative_halo2/scheme.h @@ -0,0 +1,23 @@ +#ifndef TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_SCHEME_H_ +#define TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_SCHEME_H_ + +#include "tachyon/zk/lookup/log_derivative_halo2/prover.h" +#include "tachyon/zk/lookup/type.h" + +namespace tachyon::zk::lookup::log_derivative_halo2 { + +template +struct Scheme { + using Poly = _Poly; + using Evals = _Evals; + using Commitment = _Commitment; + using Field = typename Poly::Field; + + using Prover = lookup::log_derivative_halo2::Prover; + + constexpr static Type type = Type::kLogDerivativeHalo2; +}; + +} // namespace tachyon::zk::lookup::log_derivative_halo2 + +#endif // TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_SCHEME_H_ From 3bf321b2e013cddf0a7a5650153b3671eac421fb Mon Sep 17 00:00:00 2001 From: Insun35 Date: Tue, 11 Jun 2024 18:47:47 +0900 Subject: [PATCH 15/31] feat(zk): implement `LogDerivativeHalo2` evaluator See https://github.com/scroll-tech/halo2/blob/1070391642dd64b2d68b47ec246cba9e35bd3c15/halo2_proofs/src/plonk/evaluation.rs#L516-L715 --- .../lookup/log_derivative_halo2/BUILD.bazel | 11 + .../lookup/log_derivative_halo2/evaluator.h | 197 ++++++++++++++++++ .../zk/lookup/log_derivative_halo2/scheme.h | 2 + tachyon/zk/plonk/vanishing/BUILD.bazel | 2 + .../vanishing/circuit_polynomial_builder.h | 15 +- 5 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 tachyon/zk/lookup/log_derivative_halo2/evaluator.h diff --git a/tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel b/tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel index 067e9b93b..061291517 100644 --- a/tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel +++ b/tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel @@ -2,6 +2,16 @@ load("//bazel:tachyon_cc.bzl", "tachyon_cc_library") package(default_visibility = ["//visibility:public"]) +tachyon_cc_library( + name = "evaluator", + hdrs = ["evaluator.h"], + deps = [ + ":prover", + "//tachyon/zk/plonk/vanishing:circuit_polynomial_builder_forward", + "//tachyon/zk/plonk/vanishing:graph_evaluator", + ], +) + tachyon_cc_library( name = "prover", hdrs = [ @@ -27,6 +37,7 @@ tachyon_cc_library( name = "scheme", hdrs = ["scheme.h"], deps = [ + ":evaluator", ":prover", "//tachyon/zk/lookup:type", ], diff --git a/tachyon/zk/lookup/log_derivative_halo2/evaluator.h b/tachyon/zk/lookup/log_derivative_halo2/evaluator.h new file mode 100644 index 000000000..1903d648f --- /dev/null +++ b/tachyon/zk/lookup/log_derivative_halo2/evaluator.h @@ -0,0 +1,197 @@ +// Copyright (c) 2022-2024 Scroll +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.scroll and the LICENCE-APACHE.scroll +// file. + +#ifndef TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_EVALUATOR_H_ +#define TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_EVALUATOR_H_ + +#include +#include +#include +#include +#include + +#include "tachyon/zk/lookup/log_derivative_halo2/prover.h" +#include "tachyon/zk/plonk/vanishing/circuit_polynomial_builder_forward.h" +#include "tachyon/zk/plonk/vanishing/graph_evaluator.h" + +namespace tachyon::zk::lookup::log_derivative_halo2 { + +template +struct LookupEvaluatorsPair { + std::vector> inputs_evaluator; + plonk::GraphEvaluator table_evaluator; + + LookupEvaluatorsPair(std::vector>&& inputs_evaluator, + plonk::GraphEvaluator&& table_evaluator) + : inputs_evaluator(std::move(inputs_evaluator)), + table_evaluator(std::move(table_evaluator)) {} +}; + +template +class Evaluator { + public: + const std::vector>& lookup_evaluators_pairs() const { + return lookup_evaluators_pairs_; + } + + void EvaluateLookups(const std::vector>& lookups) { + for (const Argument& lookup : lookups) { + plonk::GraphEvaluator graph_table; + std::vector> graph_inputs( + lookup.inputs_expressions().size()); + + auto compress = + [](plonk::GraphEvaluator& graph, + const std::vector>>& expressions) { + std::vector parts = base::Map( + expressions, + [&graph](const std::unique_ptr>& expression) { + return graph.AddExpression(expression.get()); + }); + return graph.AddCalculation(plonk::Calculation::Horner( + plonk::ValueSource::ZeroConstant(), std::move(parts), + plonk::ValueSource::Theta())); + }; + + for (size_t i = 0; i < lookup.inputs_expressions().size(); ++i) { + // f_compressed(X) = θᵐ⁻¹f₀(X) + θᵐ⁻²f₁(X) + ... + θfₘ₋₂(X) + fₘ₋₁(X) + plonk::ValueSource compressed_input_coset = + compress(graph_inputs[i], lookup.inputs_expressions()[i]); + // f_compressed(X) + β + graph_inputs[i].AddCalculation(plonk::Calculation::Add( + compressed_input_coset, plonk::ValueSource::Beta())); + } + // t_compressed(X) = θᵐ⁻¹t₀(X) + θᵐ⁻²t₁(X) + ... + θtₘ₋₂(X) + tₘ₋₁(X) + plonk::ValueSource compressed_table_coset = + compress(graph_table, lookup.table_expressions()); + // t_compressed(X) + β + graph_table.AddCalculation(plonk::Calculation::Add( + compressed_table_coset, plonk::ValueSource::Beta())); + + lookup_evaluators_pairs_.push_back(LookupEvaluatorsPair( + std::move(graph_inputs), std::move(graph_table))); + } + } + + template + void UpdateChunkByLookups(plonk::CircuitPolynomialBuilder& builder, + absl::Span chunk, size_t chunk_offset, + size_t chunk_size) { + for (size_t lookup_idx = 0; lookup_idx < lookup_evaluators_pairs_.size(); + ++lookup_idx) { + const std::vector>& inputs_evaluator = + lookup_evaluators_pairs_[lookup_idx].inputs_evaluator; + const plonk::GraphEvaluator& table_evaluator = + lookup_evaluators_pairs_[lookup_idx].table_evaluator; + const Evals& sum_coset = lookup_sum_cosets_[lookup_idx]; + const Evals& m_coset = lookup_m_cosets_[lookup_idx]; + + std::vector> inputs_eval_data = base::Map( + inputs_evaluator, + [&builder](const plonk::GraphEvaluator& input_evaluator) { + return builder.ExtractEvaluationInput( + input_evaluator.CreateInitialIntermediates(), + input_evaluator.CreateEmptyRotations()); + }); + + plonk::EvaluationInput table_eval_data = + builder.ExtractEvaluationInput( + table_evaluator.CreateInitialIntermediates(), + table_evaluator.CreateEmptyRotations()); + + // φᵢ(X) = fᵢ(X) + β + // τ(X) = t(X) + β + // LHS = τ(X) * Π(φᵢ(X)) * (ϕ(ω * X) - ϕ(X)) + // RHS = τ(X) * Π(φᵢ(X)) * (Σ 1/(φᵢ(X)) - m(X) / τ(X)))) + // = (τ(X) * Π(φᵢ(X)) * Σ 1/(φᵢ(X))) - Π(φᵢ(X)) * m(X) + // = Π(φᵢ(X)) * (τ(X) * Σ 1/(φᵢ(X)) - m(X)) + // = Σᵢ(τ(X) * Π_{j != i} φⱼ(X)) - m(X) * Π(φᵢ(X)) + // + // (1 - (l_last(X) + l_blind(X))) * (LHS - RHS) = 0 + size_t start = chunk_offset * chunk_size; + for (size_t idx = 0; idx < chunk.size(); ++idx) { + size_t cur_idx = start + idx; + + // φᵢ(X) = fᵢ(X) + β + std::vector inputs_value = base::Map( + inputs_eval_data, + [&inputs_evaluator, &cur_idx]( + size_t i, plonk::EvaluationInput& input_eval_data) { + return inputs_evaluator[i].Evaluate(input_eval_data, cur_idx, + /*scale=*/1, F::Zero()); + }); + + // Π(φᵢ(X)) + F inputs_prod = std::accumulate( + inputs_value.begin(), inputs_value.end(), F::One(), + [](F& acc, const F& input) { return acc *= input; }); + + // τ(X) = t(X) + β + F table_value = table_evaluator.Evaluate(table_eval_data, cur_idx, + /*scale=*/1, F::Zero()); + RowIndex r_next = + Rotation(1).GetIndex(cur_idx, /*scale=*/1, builder.n_); + + // LHS = τ(X) * Π(φᵢ(X)) * (ϕ(ω * X) - ϕ(X)) + F lhs = table_value * inputs_prod * + (sum_coset[r_next] - sum_coset[cur_idx]); + + F inputs_exclusive = F::Zero(); + for (size_t i = 0; i < inputs_value.size(); ++i) { + // Π_{j != i} φⱼ(X) + F inputs_exclusive_prod = F::One(); + for (size_t j = 0; j < inputs_value.size(); ++j) { + if (j != i) { + inputs_exclusive_prod *= inputs_value[j]; + } + } + inputs_exclusive += inputs_exclusive_prod; + } + + // RHS = Σᵢ τ(X) * Π_{j != i} φⱼ(X) - m(X) * Π(φᵢ(X)) + F rhs = table_value * inputs_exclusive - inputs_prod * m_coset[cur_idx]; + + // l_first(X) * ϕ(X) = 0 + chunk[idx] *= builder.y_; + chunk[idx] += builder.l_first_[cur_idx] * sum_coset[cur_idx]; + + // l_last(X) * ϕ(X) = 0 + chunk[idx] *= builder.y_; + chunk[idx] += builder.l_last_[cur_idx] * sum_coset[cur_idx]; + + // (1 - (l_last(X) + l_blind(X))) * (lhs - rhs) = 0 + chunk[idx] *= builder.y_; + chunk[idx] += (lhs - rhs) * builder.l_active_row_[cur_idx]; + } + } + } + + template + void UpdateLookupCosets(plonk::CircuitPolynomialBuilder& builder, + size_t circuit_idx) { + using LookupProver = Prover; + + size_t num_lookups = + builder.lookup_provers_[circuit_idx].grand_sum_polys().size(); + const LookupProver& lookup_prover = builder.lookup_provers_[circuit_idx]; + lookup_sum_cosets_.resize(num_lookups); + lookup_m_cosets_.resize(num_lookups); + for (size_t i = 0; i < num_lookups; ++i) { + lookup_sum_cosets_[i] = + builder.coset_domain_->FFT(lookup_prover.grand_sum_polys()[i].poly()); + lookup_m_cosets_[i] = + builder.coset_domain_->FFT(lookup_prover.m_polys()[i].poly()); + } + } + + private: + std::vector> lookup_evaluators_pairs_; + std::vector lookup_sum_cosets_; + std::vector lookup_m_cosets_; +}; + +} // namespace tachyon::zk::lookup::log_derivative_halo2 + +#endif // TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_EVALUATOR_H_ diff --git a/tachyon/zk/lookup/log_derivative_halo2/scheme.h b/tachyon/zk/lookup/log_derivative_halo2/scheme.h index 2896055bb..a2ad2e479 100644 --- a/tachyon/zk/lookup/log_derivative_halo2/scheme.h +++ b/tachyon/zk/lookup/log_derivative_halo2/scheme.h @@ -1,6 +1,7 @@ #ifndef TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_SCHEME_H_ #define TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_SCHEME_H_ +#include "tachyon/zk/lookup/log_derivative_halo2/evaluator.h" #include "tachyon/zk/lookup/log_derivative_halo2/prover.h" #include "tachyon/zk/lookup/type.h" @@ -14,6 +15,7 @@ struct Scheme { using Field = typename Poly::Field; using Prover = lookup::log_derivative_halo2::Prover; + using Evaluator = lookup::log_derivative_halo2::Evaluator; constexpr static Type type = Type::kLogDerivativeHalo2; }; diff --git a/tachyon/zk/plonk/vanishing/BUILD.bazel b/tachyon/zk/plonk/vanishing/BUILD.bazel index 4d0f03fc2..ca16d686a 100644 --- a/tachyon/zk/plonk/vanishing/BUILD.bazel +++ b/tachyon/zk/plonk/vanishing/BUILD.bazel @@ -23,9 +23,11 @@ tachyon_cc_library( "//tachyon/base:parallelize", "//tachyon/base/containers:adapters", "//tachyon/base/numerics:checked_math", + "//tachyon/base/types:always_false", "//tachyon/zk/base:rotation", "//tachyon/zk/lookup/halo2:evaluator", "//tachyon/zk/lookup/halo2:prover", + "//tachyon/zk/lookup/log_derivative_halo2:evaluator", "//tachyon/zk/plonk/base:column_key", "//tachyon/zk/plonk/base:multi_phase_owned_table", "//tachyon/zk/plonk/base:multi_phase_ref_table", diff --git a/tachyon/zk/plonk/vanishing/circuit_polynomial_builder.h b/tachyon/zk/plonk/vanishing/circuit_polynomial_builder.h index c3f3889dc..99efe1de5 100644 --- a/tachyon/zk/plonk/vanishing/circuit_polynomial_builder.h +++ b/tachyon/zk/plonk/vanishing/circuit_polynomial_builder.h @@ -16,8 +16,10 @@ #include "tachyon/base/containers/adapters.h" #include "tachyon/base/numerics/checked_math.h" #include "tachyon/base/parallelize.h" +#include "tachyon/base/types/always_false.h" #include "tachyon/zk/base/rotation.h" #include "tachyon/zk/lookup/halo2/prover.h" +#include "tachyon/zk/lookup/log_derivative_halo2/evaluator.h" #include "tachyon/zk/plonk/base/column_key.h" #include "tachyon/zk/plonk/base/owned_table.h" #include "tachyon/zk/plonk/base/ref_table.h" @@ -119,8 +121,16 @@ class CircuitPolynomialBuilder { if (permutation_provers_[j].grand_product_polys().size() > 0) UpdatePermutationCosets(j); // Do iff there are lookup constraints. - if (lookup_provers_[j].grand_product_polys().size() > 0) - lookup_evaluator.UpdateLookupCosets(*this, j); + size_t lookup_polys_num = 0; + if constexpr (LS::type == lookup::Type::kHalo2) { + lookup_polys_num = lookup_provers_[j].grand_product_polys().size(); + } else if constexpr (LS::type == lookup::Type::kLogDerivativeHalo2) { + lookup_polys_num = lookup_provers_[j].grand_sum_polys().size(); + } else { + static_assert(base::AlwaysFalse); + } + + if (lookup_polys_num > 0) lookup_evaluator.UpdateLookupCosets(*this, j); base::Parallelize( value_part, [this, &custom_gate_evaluator, &lookup_evaluator]( @@ -203,6 +213,7 @@ class CircuitPolynomialBuilder { private: friend class lookup::halo2::Evaluator; + friend class lookup::log_derivative_halo2::Evaluator; EvaluationInput ExtractEvaluationInput( std ::vector&& intermediates, std::vector&& rotations) { From 26c0ae2dd9b5e0ae250f1ba7ec27285fe5e3aabb Mon Sep 17 00:00:00 2001 From: Insun35 Date: Tue, 11 Jun 2024 18:53:11 +0900 Subject: [PATCH 16/31] feat(zk): implement `LogDerivativeHalo2` verifier See https://github.com/scroll-tech/halo2/blob/1070391642dd64b2d68b47ec246cba9e35bd3c15/halo2_proofs/src/plonk/mv_lookup/verifier.rs --- .../lookup/log_derivative_halo2/BUILD.bazel | 23 +++ .../zk/lookup/log_derivative_halo2/scheme.h | 5 + .../zk/lookup/log_derivative_halo2/verifier.h | 134 ++++++++++++++++++ .../log_derivative_halo2/verifier_data.h | 50 +++++++ 4 files changed, 212 insertions(+) create mode 100644 tachyon/zk/lookup/log_derivative_halo2/verifier.h create mode 100644 tachyon/zk/lookup/log_derivative_halo2/verifier_data.h diff --git a/tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel b/tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel index 061291517..3555fb172 100644 --- a/tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel +++ b/tachyon/zk/lookup/log_derivative_halo2/BUILD.bazel @@ -39,6 +39,29 @@ tachyon_cc_library( deps = [ ":evaluator", ":prover", + ":verifier", + ":verifier_data", "//tachyon/zk/lookup:type", ], ) + +tachyon_cc_library( + name = "verifier", + hdrs = ["verifier.h"], + deps = [ + ":verifier_data", + "//tachyon/crypto/commitments:polynomial_openings", + "//tachyon/zk/lookup:lookup_argument", + "//tachyon/zk/lookup:verifier", + "//tachyon/zk/lookup:verifying_evaluator", + "//tachyon/zk/lookup/halo2:opening_point_set", + "//tachyon/zk/plonk/base:l_values", + "//tachyon/zk/plonk/halo2:proof", + ], +) + +tachyon_cc_library( + name = "verifier_data", + hdrs = ["verifier_data.h"], + deps = ["//tachyon/zk/plonk/base:multi_phase_evaluations"], +) diff --git a/tachyon/zk/lookup/log_derivative_halo2/scheme.h b/tachyon/zk/lookup/log_derivative_halo2/scheme.h index a2ad2e479..abb08465e 100644 --- a/tachyon/zk/lookup/log_derivative_halo2/scheme.h +++ b/tachyon/zk/lookup/log_derivative_halo2/scheme.h @@ -3,6 +3,8 @@ #include "tachyon/zk/lookup/log_derivative_halo2/evaluator.h" #include "tachyon/zk/lookup/log_derivative_halo2/prover.h" +#include "tachyon/zk/lookup/log_derivative_halo2/verifier.h" +#include "tachyon/zk/lookup/log_derivative_halo2/verifier_data.h" #include "tachyon/zk/lookup/type.h" namespace tachyon::zk::lookup::log_derivative_halo2 { @@ -15,6 +17,9 @@ struct Scheme { using Field = typename Poly::Field; using Prover = lookup::log_derivative_halo2::Prover; + using Verifier = lookup::log_derivative_halo2::Verifier; + using VerifierData = + lookup::log_derivative_halo2::VerifierData; using Evaluator = lookup::log_derivative_halo2::Evaluator; constexpr static Type type = Type::kLogDerivativeHalo2; diff --git a/tachyon/zk/lookup/log_derivative_halo2/verifier.h b/tachyon/zk/lookup/log_derivative_halo2/verifier.h new file mode 100644 index 000000000..099956ec3 --- /dev/null +++ b/tachyon/zk/lookup/log_derivative_halo2/verifier.h @@ -0,0 +1,134 @@ +// Copyright (c) 2022-2024 Scroll +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.scroll and the LICENCE-APACHE.scroll +// file. + +#ifndef TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_VERIFIER_H_ +#define TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_VERIFIER_H_ + +#include +#include + +#include "tachyon/crypto/commitments/polynomial_openings.h" +#include "tachyon/zk/lookup/halo2/opening_point_set.h" +#include "tachyon/zk/lookup/log_derivative_halo2/verifier_data.h" +#include "tachyon/zk/lookup/lookup_argument.h" +#include "tachyon/zk/lookup/verifier.h" +#include "tachyon/zk/lookup/verifying_evaluator.h" +#include "tachyon/zk/plonk/base/l_values.h" +#include "tachyon/zk/plonk/halo2/proof.h" + +namespace tachyon::zk::lookup { +namespace log_derivative_halo2 { + +template +class Verifier final + : public lookup::Verifier> { + public: + using Proof = plonk::halo2::LogUpProof; + + Verifier(const Proof& proof, size_t circuit_idx) + : data_(proof.ToLookupVerifierData(circuit_idx)) {} + + Verifier(const Proof& proof, size_t circuit_idx, + const plonk::LValues& l_values) + : data_(proof.ToLookupVerifierData(circuit_idx)), l_values_(&l_values) {} + + void DoEvaluate(const std::vector>& arguments, + std::vector& evals) { + lookup::VerifyingEvaluator evaluator(data_); + + F active_rows = F::One() - (l_values_->last + l_values_->blind); + + for (size_t i = 0; i < data_.grand_sum_commitments.size(); ++i) { + // l_first(X) * ϕ(X) = 0 + evals.push_back(l_values_->first * data_.grand_sum_evals[i]); + // l_last(X) * ϕ(X) = 0 + evals.push_back(l_values_->last * data_.grand_sum_evals[i]); + // (1 - (l_last(X) + l_blind(X))) * (lhs - rhs) = 0 + evals.push_back(active_rows * + CreateGrandSumEvaluation(i, arguments[i], evaluator)); + } + } + + template + void DoOpen(const halo2::OpeningPointSet& point_set, + std::vector>& openings) const { + if (data_.grand_sum_commitments.empty()) return; + +#define OPENING(commitment, point, eval) \ + base::Ref(&data_.commitment), point_set.point, data_.eval + + for (size_t i = 0; i < data_.grand_sum_commitments.size(); ++i) { + openings.emplace_back( + OPENING(grand_sum_commitments[i], x, grand_sum_evals[i])); + openings.emplace_back( + OPENING(grand_sum_commitments[i], x_next, grand_sum_next_evals[i])); + openings.emplace_back(OPENING(m_poly_commitments[i], x, m_evals[i])); + } + +#undef OPENING + } + + private: + F CompressExpressions( + const std::vector>>& expressions, + lookup::VerifyingEvaluator& evaluator) const { + F compressed_value = F::Zero(); + for (const std::unique_ptr>& expression : expressions) { + compressed_value *= data_.theta; + compressed_value += evaluator.Evaluate(expression.get()); + } + return compressed_value; + } + + F CreateGrandSumEvaluation(size_t i, const lookup::Argument& argument, + lookup::VerifyingEvaluator& evaluator) { + // φᵢ(X) = fᵢ(X) + β + std::vector f_evals = base::Map( + argument.inputs_expressions(), + [this, &evaluator](const std::vector>>& + input_expressions) { + return CompressExpressions(input_expressions, evaluator) + data_.beta; + }); + + F t_eval = CompressExpressions(argument.table_expressions(), evaluator); + + F tau = t_eval + data_.beta; + + // Π(φᵢ(X)) + F prod_fi = + std::accumulate(f_evals.begin(), f_evals.end(), F::One(), + [](F& acc, const F& f_eval) { return acc *= f_eval; }); + + CHECK(F::BatchInverseInPlace(f_evals)); + + // Σ 1/(φᵢ(X)) + F sum_inv_fi = + std::accumulate(f_evals.begin(), f_evals.end(), F::Zero(), + [](F& acc, const F& f_eval) { return acc += f_eval; }); + + // LHS = τ(X) * Π(φᵢ(X)) * (ϕ(ω * X) - ϕ(X)) + F lhs = tau * prod_fi * + (data_.grand_sum_next_evals[i] - data_.grand_sum_evals[i]); + + // RHS = τ(X) * Π(φᵢ(X)) * (Σ 1/(φᵢ(X)) - m(X) / τ(X)) + F rhs = tau * prod_fi * (sum_inv_fi - data_.m_evals[i] * *tau.Inverse()); + + return lhs - rhs; + } + + VerifierData data_; + const plonk::LValues* l_values_ = nullptr; +}; + +} // namespace log_derivative_halo2 + +template +struct VerifierTraits> { + using Field = F; +}; + +} // namespace tachyon::zk::lookup + +#endif // TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_VERIFIER_H_ diff --git a/tachyon/zk/lookup/log_derivative_halo2/verifier_data.h b/tachyon/zk/lookup/log_derivative_halo2/verifier_data.h new file mode 100644 index 000000000..6626abcee --- /dev/null +++ b/tachyon/zk/lookup/log_derivative_halo2/verifier_data.h @@ -0,0 +1,50 @@ +// Copyright (c) 2022-2024 Scroll +// Use of this source code is governed by a MIT/Apache-2.0 style license that +// can be found in the LICENSE-MIT.scroll and the LICENCE-APACHE.scroll +// file. + +#ifndef TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_VERIFIER_DATA_H_ +#define TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_VERIFIER_DATA_H_ + +#include "tachyon/zk/plonk/base/multi_phase_evaluations.h" + +namespace tachyon::zk::lookup::log_derivative_halo2 { + +template +struct VerifierData : public plonk::MultiPhaseEvaluations { + VerifierData(absl::Span fixed_evals, + absl::Span advice_evals, + absl::Span instance_evals, + absl::Span challenges, + absl::Span m_poly_commitments, + absl::Span grand_sum_commitments, + absl::Span grand_sum_evals, + absl::Span grand_sum_next_evals, + absl::Span m_evals, const F& theta, const F& beta) + : plonk::MultiPhaseEvaluations(fixed_evals, advice_evals, + instance_evals, challenges), + m_poly_commitments(m_poly_commitments), + grand_sum_commitments(grand_sum_commitments), + grand_sum_evals(grand_sum_evals), + grand_sum_next_evals(grand_sum_next_evals), + m_evals(m_evals), + theta(theta), + beta(beta) {} + + // [m(τ)]₁ + absl::Span m_poly_commitments; + // [ϕ(τ)]₁ + absl::Span grand_sum_commitments; + // ϕ(X) + absl::Span grand_sum_evals; + // ϕ(ω * X) + absl::Span grand_sum_next_evals; + // m(X) + absl::Span m_evals; + const F& theta; + const F& beta; +}; + +} // namespace tachyon::zk::lookup::log_derivative_halo2 + +#endif // TACHYON_ZK_LOOKUP_LOG_DERIVATIVE_HALO2_VERIFIER_DATA_H_ From 7d947e4dd6850462ab00a7f5e89e09552bcb4d8c Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 20 May 2024 05:59:55 +0900 Subject: [PATCH 17/31] feat(zk): add lookup type condition to halo2 utils --- tachyon/zk/lookup/halo2/BUILD.bazel | 4 +++ tachyon/zk/lookup/halo2/utils.h | 27 ++++++++++++++++--- .../zk/lookup/log_derivative_halo2/verifier.h | 2 +- tachyon/zk/plonk/halo2/verifier.h | 4 +-- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/tachyon/zk/lookup/halo2/BUILD.bazel b/tachyon/zk/lookup/halo2/BUILD.bazel index 497a731b9..00c4d29a7 100644 --- a/tachyon/zk/lookup/halo2/BUILD.bazel +++ b/tachyon/zk/lookup/halo2/BUILD.bazel @@ -74,6 +74,10 @@ tachyon_cc_library( tachyon_cc_library( name = "utils", hdrs = ["utils.h"], + deps = [ + "//tachyon/base:logging", + "//tachyon/zk/lookup:type", + ], ) tachyon_cc_library( diff --git a/tachyon/zk/lookup/halo2/utils.h b/tachyon/zk/lookup/halo2/utils.h index d18861634..7acf32a63 100644 --- a/tachyon/zk/lookup/halo2/utils.h +++ b/tachyon/zk/lookup/halo2/utils.h @@ -9,14 +9,33 @@ #include +#include "tachyon/base/logging.h" +#include "tachyon/zk/lookup/type.h" + namespace tachyon::zk::lookup::halo2 { -constexpr size_t GetNumEvals(size_t num_circuits, size_t num_lookups) { - return num_circuits * num_lookups * 5; +constexpr size_t GetNumEvals(Type lookup_type, size_t num_circuits, + size_t num_lookups) { + switch (lookup_type) { + case Type::kHalo2: + return num_circuits * num_lookups * 5; + case Type::kLogDerivativeHalo2: + return num_circuits * num_lookups * 3; + } + NOTREACHED(); + return 0; } -constexpr size_t GetNumOpenings(size_t num_circuits, size_t num_lookups) { - return num_circuits * num_lookups * 5; +constexpr size_t GetNumOpenings(Type lookup_type, size_t num_circuits, + size_t num_lookups) { + switch (lookup_type) { + case Type::kHalo2: + return num_circuits * num_lookups * 5; + case Type::kLogDerivativeHalo2: + return num_circuits * num_lookups * 3; + } + NOTREACHED(); + return 0; } } // namespace tachyon::zk::lookup::halo2 diff --git a/tachyon/zk/lookup/log_derivative_halo2/verifier.h b/tachyon/zk/lookup/log_derivative_halo2/verifier.h index 099956ec3..6ca71249d 100644 --- a/tachyon/zk/lookup/log_derivative_halo2/verifier.h +++ b/tachyon/zk/lookup/log_derivative_halo2/verifier.h @@ -25,7 +25,7 @@ template class Verifier final : public lookup::Verifier> { public: - using Proof = plonk::halo2::LogUpProof; + using Proof = plonk::halo2::LogDerivativeHalo2Proof; Verifier(const Proof& proof, size_t circuit_idx) : data_(proof.ToLookupVerifierData(circuit_idx)) {} diff --git a/tachyon/zk/plonk/halo2/verifier.h b/tachyon/zk/plonk/halo2/verifier.h index f2df57ab7..0ada87c4c 100644 --- a/tachyon/zk/plonk/halo2/verifier.h +++ b/tachyon/zk/plonk/halo2/verifier.h @@ -297,7 +297,7 @@ class Verifier : public VerifierBase { GetNumVanishingEvals(num_circuits, constraint_system.gates()) + GetNumPermutationEvals( num_circuits, proof.permutation_product_commitments_vec[0].size()) + - lookup::halo2::GetNumEvals(num_circuits, + lookup::halo2::GetNumEvals(LS::type, num_circuits, constraint_system.lookups().size()); std::vector evals; evals.reserve(size); @@ -344,7 +344,7 @@ class Verifier : public VerifierBase { GetNumPermutationOpenings( num_circuits, proof.permutation_product_commitments_vec[0].size(), vkey.permutation_verifying_key().commitments().size()) + - lookup::halo2::GetNumOpenings(num_circuits, + lookup::halo2::GetNumOpenings(LS::type, num_circuits, constraint_system.lookups().size()); std::vector openings; openings.reserve(size); From 91b06a39859f1f619bd555beb3243e0671aea35d Mon Sep 17 00:00:00 2001 From: Insun35 Date: Tue, 11 Jun 2024 18:58:05 +0900 Subject: [PATCH 18/31] feat(zk): add `LogDerivativeHalo2` proof type --- tachyon/zk/lookup/halo2/scheme.h | 2 + tachyon/zk/lookup/halo2/verifier.h | 2 +- .../zk/lookup/log_derivative_halo2/scheme.h | 2 + tachyon/zk/plonk/examples/circuit_test.cc | 3 +- tachyon/zk/plonk/halo2/BUILD.bazel | 1 + tachyon/zk/plonk/halo2/proof.h | 221 ++++++++++++++---- tachyon/zk/plonk/halo2/proof_reader.h | 119 ++++++---- tachyon/zk/plonk/halo2/proof_unittest.cc | 67 +++++- tachyon/zk/plonk/halo2/prover.h | 2 +- tachyon/zk/plonk/halo2/verifier.h | 27 ++- 10 files changed, 338 insertions(+), 108 deletions(-) diff --git a/tachyon/zk/lookup/halo2/scheme.h b/tachyon/zk/lookup/halo2/scheme.h index 943152339..b761ceefb 100644 --- a/tachyon/zk/lookup/halo2/scheme.h +++ b/tachyon/zk/lookup/halo2/scheme.h @@ -6,6 +6,7 @@ #include "tachyon/zk/lookup/halo2/verifier.h" #include "tachyon/zk/lookup/halo2/verifier_data.h" #include "tachyon/zk/lookup/type.h" +#include "tachyon/zk/plonk/halo2/proof.h" namespace tachyon::zk::lookup::halo2 { @@ -20,6 +21,7 @@ struct Scheme { using Verifier = lookup::halo2::Verifier; using VerifierData = lookup::halo2::VerifierData; using Evaluator = lookup::halo2::Evaluator; + using Proof = plonk::halo2::Halo2Proof; constexpr static Type type = Type::kHalo2; }; diff --git a/tachyon/zk/lookup/halo2/verifier.h b/tachyon/zk/lookup/halo2/verifier.h index 480596e4b..2d3687c03 100644 --- a/tachyon/zk/lookup/halo2/verifier.h +++ b/tachyon/zk/lookup/halo2/verifier.h @@ -25,7 +25,7 @@ namespace halo2 { template class Verifier final : public lookup::Verifier> { public: - using Proof = plonk::halo2::Proof; + using Proof = plonk::halo2::Halo2Proof; Verifier(const Proof& proof, size_t circuit_idx) : data_(proof.ToLookupVerifierData(circuit_idx)) {} diff --git a/tachyon/zk/lookup/log_derivative_halo2/scheme.h b/tachyon/zk/lookup/log_derivative_halo2/scheme.h index abb08465e..2ffe93dad 100644 --- a/tachyon/zk/lookup/log_derivative_halo2/scheme.h +++ b/tachyon/zk/lookup/log_derivative_halo2/scheme.h @@ -6,6 +6,7 @@ #include "tachyon/zk/lookup/log_derivative_halo2/verifier.h" #include "tachyon/zk/lookup/log_derivative_halo2/verifier_data.h" #include "tachyon/zk/lookup/type.h" +#include "tachyon/zk/plonk/halo2/proof.h" namespace tachyon::zk::lookup::log_derivative_halo2 { @@ -21,6 +22,7 @@ struct Scheme { using VerifierData = lookup::log_derivative_halo2::VerifierData; using Evaluator = lookup::log_derivative_halo2::Evaluator; + using Proof = plonk::halo2::LogDerivativeHalo2Proof; constexpr static Type type = Type::kLogDerivativeHalo2; }; diff --git a/tachyon/zk/plonk/examples/circuit_test.cc b/tachyon/zk/plonk/examples/circuit_test.cc index cc0499df6..adaf64f1b 100644 --- a/tachyon/zk/plonk/examples/circuit_test.cc +++ b/tachyon/zk/plonk/examples/circuit_test.cc @@ -230,6 +230,7 @@ void CircuitTest::CreateProofTest() { template void CircuitTest::VerifyProofTest() { + using Proof = typename TestArguments::LS::Proof; CHECK(this->prover_->pcs().UnsafeSetup(TestData::kN, F(2))); this->prover_->set_domain(Domain::Create(TestData::kN)); @@ -247,7 +248,7 @@ void CircuitTest::VerifyProofTest() { std::vector> instance_columns_vec = { instance_columns, std::move(instance_columns)}; - halo2::Proof proof; + Proof proof; F h_eval; ASSERT_TRUE(verifier.VerifyProofForTesting(vkey, instance_columns_vec, &proof, &h_eval)); diff --git a/tachyon/zk/plonk/halo2/BUILD.bazel b/tachyon/zk/plonk/halo2/BUILD.bazel index 480310369..40e242760 100644 --- a/tachyon/zk/plonk/halo2/BUILD.bazel +++ b/tachyon/zk/plonk/halo2/BUILD.bazel @@ -138,6 +138,7 @@ tachyon_cc_library( "//tachyon/zk/lookup:lookup_pair", "//tachyon/zk/lookup:type", "//tachyon/zk/lookup/halo2:verifier_data", + "//tachyon/zk/lookup/log_derivative_halo2:verifier_data", "//tachyon/zk/plonk/permutation:permutation_verifier_data", "//tachyon/zk/plonk/vanishing:vanishing_verifier_data", ], diff --git a/tachyon/zk/plonk/halo2/proof.h b/tachyon/zk/plonk/halo2/proof.h index ee3b11fce..e1dcbb4e8 100644 --- a/tachyon/zk/plonk/halo2/proof.h +++ b/tachyon/zk/plonk/halo2/proof.h @@ -8,6 +8,7 @@ #include "tachyon/base/json/json.h" #include "tachyon/zk/lookup/halo2/verifier_data.h" +#include "tachyon/zk/lookup/log_derivative_halo2/verifier_data.h" #include "tachyon/zk/lookup/lookup_pair.h" #include "tachyon/zk/lookup/type.h" #include "tachyon/zk/plonk/permutation/permutation_verifier_data.h" @@ -21,11 +22,9 @@ struct Proof { std::vector> advices_commitments_vec; std::vector challenges; F theta; - std::vector>> lookup_permuted_commitments_vec; F beta; F gamma; std::vector> permutation_product_commitments_vec; - std::vector> lookup_product_commitments_vec; C vanishing_random_poly_commitment; F y; std::vector vanishing_h_poly_commitments; @@ -38,11 +37,6 @@ struct Proof { std::vector> permutation_product_evals_vec; std::vector> permutation_product_next_evals_vec; std::vector>> permutation_product_last_evals_vec; - std::vector> lookup_product_evals_vec; - std::vector> lookup_product_next_evals_vec; - std::vector> lookup_permuted_input_evals_vec; - std::vector> lookup_permuted_input_prev_evals_vec; - std::vector> lookup_permuted_table_evals_vec; // auxiliary values F l_first; @@ -56,13 +50,9 @@ struct Proof { bool operator==(const Proof& other) const { return advices_commitments_vec == other.advices_commitments_vec && challenges == other.challenges && theta == other.theta && - lookup_permuted_commitments_vec == - other.lookup_permuted_commitments_vec && beta == other.beta && gamma == other.gamma && permutation_product_commitments_vec == other.permutation_product_commitments_vec && - lookup_product_commitments_vec == - other.lookup_product_commitments_vec && vanishing_random_poly_commitment == other.vanishing_random_poly_commitment && y == other.y && @@ -77,16 +67,7 @@ struct Proof { permutation_product_next_evals_vec == other.permutation_product_next_evals_vec && permutation_product_last_evals_vec == - other.permutation_product_last_evals_vec && - lookup_product_evals_vec == other.lookup_product_evals_vec && - lookup_product_next_evals_vec == - other.lookup_product_next_evals_vec && - lookup_permuted_input_evals_vec == - other.lookup_permuted_input_evals_vec && - lookup_permuted_input_prev_evals_vec == - other.lookup_permuted_input_prev_evals_vec && - lookup_permuted_table_evals_vec == - other.lookup_permuted_table_evals_vec; + other.permutation_product_last_evals_vec; } bool operator!=(const Proof& other) const { return !operator==(other); } @@ -125,14 +106,43 @@ struct Proof { gamma, }; } +}; + +template +struct Halo2Proof : public Proof { + std::vector>> lookup_permuted_commitments_vec; + std::vector> lookup_product_commitments_vec; + std::vector> lookup_product_evals_vec; + std::vector> lookup_product_next_evals_vec; + std::vector> lookup_permuted_input_evals_vec; + std::vector> lookup_permuted_input_prev_evals_vec; + std::vector> lookup_permuted_table_evals_vec; + + bool operator==(const Halo2Proof& other) const { + return Proof::operator==(other) && + lookup_permuted_commitments_vec == + other.lookup_permuted_commitments_vec && + lookup_product_commitments_vec == + other.lookup_product_commitments_vec && + lookup_product_evals_vec == other.lookup_product_evals_vec && + lookup_product_next_evals_vec == + other.lookup_product_next_evals_vec && + lookup_permuted_input_evals_vec == + other.lookup_permuted_input_evals_vec && + lookup_permuted_input_prev_evals_vec == + other.lookup_permuted_input_prev_evals_vec && + lookup_permuted_table_evals_vec == + other.lookup_permuted_table_evals_vec; + } + bool operator!=(const Halo2Proof& other) const { return !operator==(other); } lookup::halo2::VerifierData ToLookupVerifierData( size_t circuit_idx) const { return { - fixed_evals, - advice_evals_vec[circuit_idx], - instance_evals_vec[circuit_idx], - challenges, + this->fixed_evals, + this->advice_evals_vec[circuit_idx], + this->instance_evals_vec[circuit_idx], + this->challenges, lookup_permuted_commitments_vec[circuit_idx], lookup_product_commitments_vec[circuit_idx], lookup_product_evals_vec[circuit_idx], @@ -140,9 +150,48 @@ struct Proof { lookup_permuted_input_evals_vec[circuit_idx], lookup_permuted_input_prev_evals_vec[circuit_idx], lookup_permuted_table_evals_vec[circuit_idx], - theta, - beta, - gamma, + this->theta, + this->beta, + this->gamma, + }; + } +}; + +template +struct LogDerivativeHalo2Proof : public Proof { + std::vector> lookup_m_poly_commitments_vec; + std::vector> lookup_sum_commitments_vec; + std::vector> lookup_sum_evals_vec; + std::vector> lookup_sum_next_evals_vec; + std::vector> lookup_m_evals_vec; + + bool operator==(const LogDerivativeHalo2Proof& other) const { + return Proof::operator==(other) && + lookup_m_poly_commitments_vec == + other.lookup_m_poly_commitments_vec && + lookup_sum_commitments_vec == other.lookup_sum_commitments_vec && + lookup_sum_evals_vec == other.lookup_sum_evals_vec && + lookup_sum_next_evals_vec == other.lookup_sum_next_evals_vec && + lookup_m_evals_vec == other.lookup_m_evals_vec; + } + bool operator!=(const LogDerivativeHalo2Proof& other) const { + return !operator==(other); + } + + lookup::log_derivative_halo2::VerifierData ToLookupVerifierData( + size_t circuit_idx) const { + return { + this->fixed_evals, + this->advice_evals_vec[circuit_idx], + this->instance_evals_vec[circuit_idx], + this->challenges, + lookup_m_poly_commitments_vec[circuit_idx], + lookup_sum_commitments_vec[circuit_idx], + lookup_sum_evals_vec[circuit_idx], + lookup_sum_next_evals_vec[circuit_idx], + lookup_m_evals_vec[circuit_idx], + this->theta, + this->beta, }; } }; @@ -162,14 +211,10 @@ class RapidJsonValueConverter> { value.advices_commitments_vec, allocator); AddJsonElement(object, "challenges", value.challenges, allocator); AddJsonElement(object, "theta", value.theta, allocator); - AddJsonElement(object, "lookup_permuted_commitments_vec", - value.lookup_permuted_commitments_vec, allocator); AddJsonElement(object, "beta", value.beta, allocator); AddJsonElement(object, "gamma", value.gamma, allocator); AddJsonElement(object, "permutation_product_commitments_vec", value.permutation_product_commitments_vec, allocator); - AddJsonElement(object, "lookup_product_commitments_vec", - value.lookup_product_commitments_vec, allocator); AddJsonElement(object, "vanishing_random_poly_commitment", value.vanishing_random_poly_commitment, allocator); AddJsonElement(object, "y", value.y, allocator); @@ -191,16 +236,6 @@ class RapidJsonValueConverter> { value.permutation_product_next_evals_vec, allocator); AddJsonElement(object, "permutation_product_last_evals_vec", value.permutation_product_last_evals_vec, allocator); - AddJsonElement(object, "lookup_product_evals_vec", - value.lookup_product_evals_vec, allocator); - AddJsonElement(object, "lookup_product_next_evals_vec", - value.lookup_product_next_evals_vec, allocator); - AddJsonElement(object, "lookup_permuted_input_evals_vec", - value.lookup_permuted_input_evals_vec, allocator); - AddJsonElement(object, "lookup_permuted_input_prev_evals_vec", - value.lookup_permuted_input_prev_evals_vec, allocator); - AddJsonElement(object, "lookup_permuted_table_evals_vec", - value.lookup_permuted_table_evals_vec, allocator); return object; } @@ -214,18 +249,12 @@ class RapidJsonValueConverter> { return false; if (!ParseJsonElement(json_value, "theta", &proof.theta, error)) return false; - if (!ParseJsonElement(json_value, "lookup_permuted_commitments_vec", - &proof.lookup_permuted_commitments_vec, error)) - return false; if (!ParseJsonElement(json_value, "beta", &proof.beta, error)) return false; if (!ParseJsonElement(json_value, "gamma", &proof.gamma, error)) return false; if (!ParseJsonElement(json_value, "permutation_product_commitments_vec", &proof.permutation_product_commitments_vec, error)) return false; - if (!ParseJsonElement(json_value, "lookup_product_commitments_vec", - &proof.lookup_product_commitments_vec, error)) - return false; if (!ParseJsonElement(json_value, "vanishing_random_poly_commitment", &proof.vanishing_random_poly_commitment, error)) return false; @@ -266,6 +295,51 @@ class RapidJsonValueConverter> { if (!ParseJsonElement(json_value, "permutation_product_last_evals_vec", &proof.permutation_product_last_evals_vec, error)) return false; + + *proof_out = std::move(proof); + return true; + } +}; + +template +class RapidJsonValueConverter> { + public: + template + static rapidjson::Value From(const zk::plonk::halo2::Halo2Proof& value, + Allocator& allocator) { + rapidjson::Value object = + RapidJsonValueConverter>::From(value, + allocator); + AddJsonElement(object, "lookup_permuted_commitments_vec", + value.lookup_permuted_commitments_vec, allocator); + AddJsonElement(object, "lookup_product_commitments_vec", + value.lookup_product_commitments_vec, allocator); + AddJsonElement(object, "lookup_product_evals_vec", + value.lookup_product_evals_vec, allocator); + AddJsonElement(object, "lookup_product_next_evals_vec", + value.lookup_product_next_evals_vec, allocator); + AddJsonElement(object, "lookup_permuted_input_evals_vec", + value.lookup_permuted_input_evals_vec, allocator); + AddJsonElement(object, "lookup_permuted_input_prev_evals_vec", + value.lookup_permuted_input_prev_evals_vec, allocator); + AddJsonElement(object, "lookup_permuted_table_evals_vec", + value.lookup_permuted_table_evals_vec, allocator); + return object; + } + + static bool To(const rapidjson::Value& json_value, std::string_view key, + zk::plonk::halo2::Halo2Proof* proof_out, + std::string* error) { + zk::plonk::halo2::Halo2Proof proof; + if (!RapidJsonValueConverter>::To( + json_value, key, &proof, error)) + return false; + if (!ParseJsonElement(json_value, "lookup_permuted_commitments_vec", + &proof.lookup_permuted_commitments_vec, error)) + return false; + if (!ParseJsonElement(json_value, "lookup_product_commitments_vec", + &proof.lookup_product_commitments_vec, error)) + return false; if (!ParseJsonElement(json_value, "lookup_product_evals_vec", &proof.lookup_product_evals_vec, error)) return false; @@ -287,6 +361,57 @@ class RapidJsonValueConverter> { } }; +template +class RapidJsonValueConverter> { + public: + template + static rapidjson::Value From( + const zk::plonk::halo2::LogDerivativeHalo2Proof& value, + Allocator& allocator) { + rapidjson::Value object = + RapidJsonValueConverter>::From(value, + allocator); + AddJsonElement(object, "lookup_m_poly_commitments_vec", + value.lookup_m_poly_commitments_vec, allocator); + AddJsonElement(object, "lookup_sum_commitments_vec", + value.lookup_sum_commitments_vec, allocator); + AddJsonElement(object, "lookup_sum_evals_vec", value.lookup_sum_evals_vec, + allocator); + AddJsonElement(object, "lookup_sum_next_evals_vec", + value.lookup_sum_next_evals_vec, allocator); + AddJsonElement(object, "lookup_m_evals_vec", value.lookup_m_evals_vec, + allocator); + return object; + } + + static bool To(const rapidjson::Value& json_value, std::string_view key, + zk::plonk::halo2::LogDerivativeHalo2Proof* proof_out, + std::string* error) { + zk::plonk::halo2::LogDerivativeHalo2Proof proof; + if (!RapidJsonValueConverter>::To( + json_value, key, &proof, error)) + return false; + if (!ParseJsonElement(json_value, "lookup_m_poly_commitments_vec", + &proof.lookup_m_poly_commitments_vec, error)) + return false; + if (!ParseJsonElement(json_value, "lookup_sum_commitments_vec", + &proof.lookup_sum_commitments_vec, error)) + return false; + if (!ParseJsonElement(json_value, "lookup_sum_evals_vec", + &proof.lookup_sum_evals_vec, error)) + return false; + if (!ParseJsonElement(json_value, "lookup_sum_next_evals_vec", + &proof.lookup_sum_next_evals_vec, error)) + return false; + if (!ParseJsonElement(json_value, "lookup_m_evals_vec", + &proof.lookup_m_evals_vec, error)) + return false; + + *proof_out = std::move(proof); + return true; + } +}; + } // namespace base } // namespace tachyon diff --git a/tachyon/zk/plonk/halo2/proof_reader.h b/tachyon/zk/plonk/halo2/proof_reader.h index 0e3fcb31f..43492f089 100644 --- a/tachyon/zk/plonk/halo2/proof_reader.h +++ b/tachyon/zk/plonk/halo2/proof_reader.h @@ -15,10 +15,10 @@ namespace tachyon::zk::plonk::halo2 { enum class ProofCursor { kAdviceCommitmentsVecAndChallenges, kTheta, - kLookupPermutedCommitments, + kLookupPreparedCommitments, kBetaAndGamma, kPermutationProductCommitments, - kLookupProductCommitments, + kLookupGrandCommitments, kVanishingRandomPolyCommitment, kY, kVanishingHPolyCommitments, @@ -33,11 +33,12 @@ enum class ProofCursor { kDone, }; -template +template class ProofReader { public: using F = typename PCS::Field; using C = typename PCS::Commitment; + using Proof = typename LS::Proof; ProofReader(const VerifyingKey& verifying_key, crypto::TranscriptReader* transcript, size_t num_circuits) @@ -45,8 +46,8 @@ class ProofReader { transcript_(transcript), num_circuits_(num_circuits) {} - const Proof& proof() const { return proof_; } - Proof& proof() { return proof_; } + const Proof& proof() const { return proof_; } + Proof& proof() { return proof_; } void ReadAdviceCommitmentsVecAndChallenges() { CHECK_EQ(cursor_, ProofCursor::kAdviceCommitmentsVecAndChallenges); @@ -84,20 +85,28 @@ class ProofReader { CHECK_EQ(cursor_, ProofCursor::kTheta); proof_.theta = transcript_->SqueezeChallenge(); VLOG(2) << "Halo2(theta): " << proof_.theta.ToHexString(true); - cursor_ = ProofCursor::kLookupPermutedCommitments; + cursor_ = ProofCursor::kLookupPreparedCommitments; } - void ReadLookupPermutedCommitments() { - CHECK_EQ(cursor_, ProofCursor::kLookupPermutedCommitments); + void ReadLookupPreparedCommitments() { + CHECK_EQ(cursor_, ProofCursor::kLookupPreparedCommitments); size_t num_lookups = verifying_key_.constraint_system().lookups().size(); - proof_.lookup_permuted_commitments_vec = - base::CreateVector(num_circuits_, [this, num_lookups]() { - return base::CreateVector(num_lookups, [this]() { - C input = Read(); - C table = Read(); - return lookup::Pair(std::move(input), std::move(table)); + if constexpr (LS::type == lookup::Type::kHalo2) { + proof_.lookup_permuted_commitments_vec = + base::CreateVector(num_circuits_, [this, num_lookups]() { + return base::CreateVector(num_lookups, [this]() { + C input = Read(); + C table = Read(); + return lookup::Pair(std::move(input), std::move(table)); + }); }); - }); + } else if constexpr (LS::type == lookup::Type::kLogDerivativeHalo2) { + proof_.lookup_m_poly_commitments_vec = base::CreateVector( + num_circuits_, + [this, num_lookups]() { return ReadMany(num_lookups); }); + } else { + static_assert(base::AlwaysFalse); + } cursor_ = ProofCursor::kBetaAndGamma; } @@ -118,15 +127,24 @@ class ProofReader { proof_.permutation_product_commitments_vec = base::CreateVector( num_circuits_, [this, num_products]() { return ReadMany(num_products); }); - cursor_ = ProofCursor::kLookupProductCommitments; + cursor_ = ProofCursor::kLookupGrandCommitments; } - void ReadLookupProductCommitments() { - CHECK_EQ(cursor_, ProofCursor::kLookupProductCommitments); + void ReadLookupGrandCommitments() { + CHECK_EQ(cursor_, ProofCursor::kLookupGrandCommitments); size_t num_lookups = verifying_key_.constraint_system().lookups().size(); - proof_.lookup_product_commitments_vec = base::CreateVector( - num_circuits_, - [this, num_lookups]() { return ReadMany(num_lookups); }); + if constexpr (LS::type == lookup::Type::kHalo2) { + proof_.lookup_product_commitments_vec = base::CreateVector( + num_circuits_, + [this, num_lookups]() { return ReadMany(num_lookups); }); + } else if constexpr (LS::type == lookup::Type::kLogDerivativeHalo2) { + proof_.lookup_sum_commitments_vec = base::CreateVector( + num_circuits_, + [this, num_lookups]() { return ReadMany(num_lookups); }); + } else { + static_assert(base::AlwaysFalse); + } + cursor_ = ProofCursor::kVanishingRandomPolyCommitment; } @@ -228,26 +246,47 @@ class ProofReader { void ReadLookupEvals() { CHECK_EQ(cursor_, ProofCursor::kLookupEvalsVec); - proof_.lookup_product_evals_vec.resize(num_circuits_); - proof_.lookup_product_next_evals_vec.resize(num_circuits_); - proof_.lookup_permuted_input_evals_vec.resize(num_circuits_); - proof_.lookup_permuted_input_prev_evals_vec.resize(num_circuits_); - proof_.lookup_permuted_table_evals_vec.resize(num_circuits_); - for (size_t i = 0; i < num_circuits_; ++i) { - size_t size = proof_.lookup_product_commitments_vec[i].size(); - proof_.lookup_product_evals_vec[i].reserve(size); - proof_.lookup_product_next_evals_vec[i].reserve(size); - proof_.lookup_permuted_input_evals_vec[i].reserve(size); - proof_.lookup_permuted_input_prev_evals_vec[i].reserve(size); - proof_.lookup_permuted_table_evals_vec[i].reserve(size); - for (size_t j = 0; j < size; ++j) { - proof_.lookup_product_evals_vec[i].push_back(Read()); - proof_.lookup_product_next_evals_vec[i].push_back(Read()); - proof_.lookup_permuted_input_evals_vec[i].push_back(Read()); - proof_.lookup_permuted_input_prev_evals_vec[i].push_back(Read()); - proof_.lookup_permuted_table_evals_vec[i].push_back(Read()); + + if constexpr (LS::type == lookup::Type::kHalo2) { + proof_.lookup_product_evals_vec.resize(num_circuits_); + proof_.lookup_product_next_evals_vec.resize(num_circuits_); + proof_.lookup_permuted_input_evals_vec.resize(num_circuits_); + proof_.lookup_permuted_input_prev_evals_vec.resize(num_circuits_); + proof_.lookup_permuted_table_evals_vec.resize(num_circuits_); + for (size_t i = 0; i < num_circuits_; ++i) { + size_t size = proof_.lookup_product_commitments_vec[i].size(); + proof_.lookup_product_evals_vec[i].reserve(size); + proof_.lookup_product_next_evals_vec[i].reserve(size); + proof_.lookup_permuted_input_evals_vec[i].reserve(size); + proof_.lookup_permuted_input_prev_evals_vec[i].reserve(size); + proof_.lookup_permuted_table_evals_vec[i].reserve(size); + for (size_t j = 0; j < size; ++j) { + proof_.lookup_product_evals_vec[i].push_back(Read()); + proof_.lookup_product_next_evals_vec[i].push_back(Read()); + proof_.lookup_permuted_input_evals_vec[i].push_back(Read()); + proof_.lookup_permuted_input_prev_evals_vec[i].push_back(Read()); + proof_.lookup_permuted_table_evals_vec[i].push_back(Read()); + } } + } else if constexpr (LS::type == lookup::Type::kLogDerivativeHalo2) { + proof_.lookup_sum_evals_vec.resize(num_circuits_); + proof_.lookup_sum_next_evals_vec.resize(num_circuits_); + proof_.lookup_m_evals_vec.resize(num_circuits_); + for (size_t i = 0; i < num_circuits_; ++i) { + size_t size = proof_.lookup_sum_commitments_vec[i].size(); + proof_.lookup_sum_evals_vec.reserve(size); + proof_.lookup_sum_next_evals_vec.reserve(size); + proof_.lookup_m_evals_vec.reserve(size); + for (size_t j = 0; j < size; ++j) { + proof_.lookup_sum_evals_vec[i].push_back(Read()); + proof_.lookup_sum_next_evals_vec[i].push_back(Read()); + proof_.lookup_m_evals_vec[i].push_back(Read()); + } + } + } else { + static_assert(base::AlwaysFalse); } + cursor_ = ProofCursor::kDone; } @@ -270,7 +309,7 @@ class ProofReader { // not owned crypto::TranscriptReader* const transcript_ = nullptr; size_t num_circuits_ = 0; - Proof proof_; + Proof proof_; ProofCursor cursor_ = ProofCursor::kAdviceCommitmentsVecAndChallenges; }; diff --git a/tachyon/zk/plonk/halo2/proof_unittest.cc b/tachyon/zk/plonk/halo2/proof_unittest.cc index 6877c7c25..241dbfe56 100644 --- a/tachyon/zk/plonk/halo2/proof_unittest.cc +++ b/tachyon/zk/plonk/halo2/proof_unittest.cc @@ -38,13 +38,13 @@ CreateRandomLookupPairsVec(RowIndex rows, size_t cols) { } // namespace -TEST(ProofTest, JsonValueConverter) { +TEST(ProofTest, Halo2JsonValueConverter) { math::bn254::G1Curve::Init(); size_t num_circuits_ = 2; size_t num_elements_ = 3; - Proof expected_proof; + Halo2Proof expected_proof; expected_proof.advices_commitments_vec = CreateRandomElementsVec(num_circuits_, num_elements_); expected_proof.challenges = @@ -97,7 +97,68 @@ TEST(ProofTest, JsonValueConverter) { CreateRandomElementsVec(num_circuits_, num_elements_); std::string json = base::WriteToJson(expected_proof); - Proof proof; + Halo2Proof proof; + std::string error; + ASSERT_TRUE(base::ParseJson(json, &proof, &error)); + ASSERT_TRUE(error.empty()); + EXPECT_EQ(proof, expected_proof); +} + +TEST(ProofTest, LogDerivativeHalo2JsonValueConverter) { + math::bn254::G1Curve::Init(); + + size_t num_circuits_ = 2; + size_t num_elements_ = 3; + + LogDerivativeHalo2Proof expected_proof; + expected_proof.advices_commitments_vec = + CreateRandomElementsVec(num_circuits_, num_elements_); + expected_proof.challenges = + base::CreateVector(num_circuits_, []() { return F::Random(); }); + expected_proof.theta = F::Random(); + expected_proof.lookup_m_poly_commitments_vec = + CreateRandomElementsVec(num_circuits_, num_elements_); + expected_proof.beta = F::Random(); + expected_proof.permutation_product_commitments_vec = + CreateRandomElementsVec(num_circuits_, num_elements_); + expected_proof.lookup_sum_commitments_vec = + CreateRandomElementsVec(num_circuits_, num_elements_); + expected_proof.vanishing_random_poly_commitment = Commitment::Random(); + expected_proof.y = F::Random(); + expected_proof.vanishing_h_poly_commitments = + base::CreateVector(5, []() { return Commitment::Random(); }); + expected_proof.x = F::Random(); + expected_proof.instance_evals_vec = + CreateRandomElementsVec(num_circuits_, num_elements_); + expected_proof.advice_evals_vec = + CreateRandomElementsVec(num_circuits_, num_elements_); + expected_proof.fixed_evals = + base::CreateVector(num_circuits_, []() { return F::Random(); }); + expected_proof.vanishing_random_eval = F::Random(); + expected_proof.common_permutation_evals = + base::CreateVector(num_circuits_, []() { return F::Random(); }); + expected_proof.permutation_product_evals_vec = + CreateRandomElementsVec(num_circuits_, num_elements_); + expected_proof.permutation_product_next_evals_vec = + CreateRandomElementsVec(num_circuits_, num_elements_); + expected_proof.permutation_product_last_evals_vec = + std::vector>>( + num_circuits_, base::CreateVector(num_elements_, [](size_t i) { + if (i % 2 == 0) { + return std::optional(F::Random()); + } else { + return std::optional(); + } + })); + expected_proof.lookup_sum_evals_vec = + CreateRandomElementsVec(num_circuits_, num_elements_); + expected_proof.lookup_sum_next_evals_vec = + CreateRandomElementsVec(num_circuits_, num_elements_); + expected_proof.lookup_m_evals_vec = + CreateRandomElementsVec(num_circuits_, num_elements_); + std::string json = base::WriteToJson(expected_proof); + + LogDerivativeHalo2Proof proof; std::string error; ASSERT_TRUE(base::ParseJson(json, &proof, &error)); ASSERT_TRUE(error.empty()); diff --git a/tachyon/zk/plonk/halo2/prover.h b/tachyon/zk/plonk/halo2/prover.h index 12660fd42..20df853d2 100644 --- a/tachyon/zk/plonk/halo2/prover.h +++ b/tachyon/zk/plonk/halo2/prover.h @@ -307,7 +307,7 @@ class Prover : public ProverBase { GetNumPermutationOpenings( num_circuits, permutation_provers[0].grand_product_polys().size(), proving_key.permutation_proving_key().permutations().size()) + - lookup::halo2::GetNumOpenings(lookup_provers.size(), + lookup::halo2::GetNumOpenings(LS::type, lookup_provers.size(), constraint_system.lookups().size()); openings.reserve(size); diff --git a/tachyon/zk/plonk/halo2/verifier.h b/tachyon/zk/plonk/halo2/verifier.h index 0ada87c4c..ea69ab043 100644 --- a/tachyon/zk/plonk/halo2/verifier.h +++ b/tachyon/zk/plonk/halo2/verifier.h @@ -43,6 +43,7 @@ class Verifier : public VerifierBase { using Coefficients = typename Poly::Coefficients; using Opening = crypto::PolynomialOpening; using LookupVerifier = typename LS::Verifier; + using Proof = typename LS::Proof; using VerifierBase::VerifierBase; @@ -59,7 +60,7 @@ class Verifier : public VerifierBase { bool VerifyProofForTesting( const VerifyingKey& vkey, const std::vector>& instance_columns_vec, - Proof* proof_out, F* expected_h_eval_out) { + Proof* proof_out, F* expected_h_eval_out) { if (!ValidateInstanceColumnsVec(vkey, instance_columns_vec)) return false; std::vector> instance_commitments_vec; @@ -78,15 +79,15 @@ class Verifier : public VerifierBase { WriteColumnsVecToTranscript(transcript, instance_columns_vec); } - ProofReader proof_reader(vkey, transcript, - instance_commitments_vec.size()); - Proof& proof = proof_reader.proof(); + ProofReader proof_reader(vkey, transcript, + instance_commitments_vec.size()); + Proof& proof = proof_reader.proof(); proof_reader.ReadAdviceCommitmentsVecAndChallenges(); proof_reader.ReadTheta(); - proof_reader.ReadLookupPermutedCommitments(); + proof_reader.ReadLookupPreparedCommitments(); proof_reader.ReadBetaAndGamma(); proof_reader.ReadPermutationProductCommitments(); - proof_reader.ReadLookupProductCommitments(); + proof_reader.ReadLookupGrandCommitments(); proof_reader.ReadVanishingRandomPolyCommitment(); proof_reader.ReadY(); proof_reader.ReadVanishingHPolyCommitments(); @@ -116,7 +117,7 @@ class Verifier : public VerifierBase { } void ComputeAuxValues(const ConstraintSystem& constraint_system, - Proof& proof) const { + Proof& proof) const { RowIndex blinding_factors = constraint_system.ComputeBlindingFactors(); std::vector l_evals = this->domain_->EvaluatePartialLagrangeCoefficients( proof.x, base::Range { F EvaluateH( const std::vector>& instance_commitments_vec, - const VerifyingKey& vkey, - const Proof& proof) { + const VerifyingKey& vkey, const Proof& proof) { size_t num_circuits = proof.advices_commitments_vec.size(); const ConstraintSystem& constraint_system = vkey.constraint_system(); size_t size = @@ -331,9 +331,8 @@ class Verifier : public VerifierBase { std::vector Open( const std::vector>& instance_commitments_vec, - const VerifyingKey& vkey, - const Proof& proof, Commitment& expected_h_commitment, - const F& expected_h_eval) { + const VerifyingKey& vkey, const Proof& proof, + Commitment& expected_h_commitment, const F& expected_h_eval) { size_t num_circuits = proof.advices_commitments_vec.size(); const ConstraintSystem& constraint_system = vkey.constraint_system(); size_t size = @@ -392,8 +391,8 @@ class Verifier : public VerifierBase { bool DoVerify( const std::vector>& instance_commitments_vec, - const VerifyingKey& vkey, - const Proof& proof, F* expected_h_eval_out) { + const VerifyingKey& vkey, const Proof& proof, + F* expected_h_eval_out) { F expected_h_eval = EvaluateH(instance_commitments_vec, vkey, proof); if (expected_h_eval_out) { *expected_h_eval_out = expected_h_eval; From 85e5161b2755dbbe9638740f70e8e90bbeca4b58 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Wed, 22 May 2024 16:08:28 +0900 Subject: [PATCH 19/31] fix(zk): fix wrong template argument --- tachyon/zk/plonk/halo2/prover.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tachyon/zk/plonk/halo2/prover.h b/tachyon/zk/plonk/halo2/prover.h index 20df853d2..3cff491ce 100644 --- a/tachyon/zk/plonk/halo2/prover.h +++ b/tachyon/zk/plonk/halo2/prover.h @@ -159,7 +159,7 @@ class Prover : public ProverBase { } LookupProver::BatchCommitPermutedPairs(lookup_provers, this, commit_idx); } else { - base::AlwaysFalse(); + static_assert(base::AlwaysFalse); } if constexpr (PCS::kSupportsBatchMode) { @@ -184,7 +184,7 @@ class Prover : public ProverBase { num_lookup_poly = LookupProver::GetNumGrandProductPolysCommitments(lookup_provers); } else { - base::AlwaysFalse(); + static_assert(base::AlwaysFalse); } this->pcs_.SetBatchMode( PermutationProver::GetNumGrandProductPolysCommitments( @@ -200,7 +200,7 @@ class Prover : public ProverBase { LookupProver::BatchCommitGrandProductPolys(lookup_provers, this, commit_idx); } else { - base::AlwaysFalse(); + static_assert(base::AlwaysFalse); } vanishing_prover.CommitRandomPoly(this, commit_idx); if constexpr (PCS::kSupportsBatchMode) { From b936c42f61ceb09de688756f90080b882853499a Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 20 May 2024 18:13:15 +0900 Subject: [PATCH 20/31] feat(zk): integrate halo2 prover with `LogDerivativeHalo2` scheme --- tachyon/zk/plonk/halo2/prover.h | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/tachyon/zk/plonk/halo2/prover.h b/tachyon/zk/plonk/halo2/prover.h index 3cff491ce..3420a2d4a 100644 --- a/tachyon/zk/plonk/halo2/prover.h +++ b/tachyon/zk/plonk/halo2/prover.h @@ -158,6 +158,16 @@ class Prover : public ProverBase { LookupProver::GetNumPermutedPairsCommitments(lookup_provers)); } LookupProver::BatchCommitPermutedPairs(lookup_provers, this, commit_idx); + } else if constexpr (LS::type == lookup::Type::kLogDerivativeHalo2) { + LookupProver::BatchCompressPairs(lookup_provers, domain, cs.lookups(), + theta, column_tables); + LookupProver::BatchComputeMPolys(lookup_provers, this); + + if constexpr (PCS::kSupportsBatchMode) { + this->pcs_.SetBatchMode( + LookupProver::GetNumMPolysCommitments(lookup_provers)); + } + LookupProver::BatchCommitMPolys(lookup_provers, this, commit_idx); } else { static_assert(base::AlwaysFalse); } @@ -174,8 +184,16 @@ class Prover : public ProverBase { PermutationProver::BatchCreateGrandProductPolys( permutation_provers, this, cs.permutation(), column_tables, cs.ComputeDegree(), proving_key.permutation_proving_key(), beta, gamma); - LookupProver::BatchCreateGrandProductPolys(lookup_provers, this, beta, - gamma); + + if constexpr (LS::type == lookup::Type::kHalo2) { + LookupProver::BatchCreateGrandProductPolys(lookup_provers, this, beta, + gamma); + } else if constexpr (LS::type == lookup::Type::kLogDerivativeHalo2) { + LookupProver::BatchCreateGrandSumPolys(lookup_provers, this, beta); + } else { + static_assert(base::AlwaysFalse); + } + vanishing_prover.CreateRandomPoly(this); if constexpr (PCS::kSupportsBatchMode) { @@ -183,6 +201,9 @@ class Prover : public ProverBase { if constexpr (LS::type == lookup::Type::kHalo2) { num_lookup_poly = LookupProver::GetNumGrandProductPolysCommitments(lookup_provers); + } else if constexpr (LS::type == lookup::Type::kLogDerivativeHalo2) { + num_lookup_poly = + LookupProver::GetNumGrandSumPolysCommitments(lookup_provers); } else { static_assert(base::AlwaysFalse); } @@ -199,6 +220,8 @@ class Prover : public ProverBase { if constexpr (LS::type == lookup::Type::kHalo2) { LookupProver::BatchCommitGrandProductPolys(lookup_provers, this, commit_idx); + } else if constexpr (LS::type == lookup::Type::kLogDerivativeHalo2) { + LookupProver::BatchCommitGrandSumPolys(lookup_provers, this, commit_idx); } else { static_assert(base::AlwaysFalse); } From eddbc5b6ca70a09f02b441c11f2cf7c24ecb0e4d Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 20 May 2024 09:37:03 +0900 Subject: [PATCH 21/31] fix(zk): change commit input to `Evals` to use `CommitLagrange` --- tachyon/zk/plonk/halo2/verifier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tachyon/zk/plonk/halo2/verifier.h b/tachyon/zk/plonk/halo2/verifier.h index ea69ab043..0141a20ca 100644 --- a/tachyon/zk/plonk/halo2/verifier.h +++ b/tachyon/zk/plonk/halo2/verifier.h @@ -175,7 +175,7 @@ class Verifier : public VerifierBase { return base::Map(columns, [this](const Evals& column) { std::vector expanded_evals = column.evaluations(); expanded_evals.resize(this->pcs_.N()); - return this->Commit(expanded_evals); + return this->Commit(Evals(expanded_evals)); }); } From 8450f3d58a1b79f7d1ccbb4344b97d2fb6ba52c6 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Thu, 13 Jun 2024 18:30:37 +0900 Subject: [PATCH 22/31] fix: add missing change from #430 --- tachyon/crypto/commitments/kzg/shplonk.h | 4 ++-- tachyon/zk/plonk/examples/circuit_test.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tachyon/crypto/commitments/kzg/shplonk.h b/tachyon/crypto/commitments/kzg/shplonk.h index 93f85d97d..41950c90c 100644 --- a/tachyon/crypto/commitments/kzg/shplonk.h +++ b/tachyon/crypto/commitments/kzg/shplonk.h @@ -177,8 +177,8 @@ class SHPlonk final : public UnivariatePolynomialCommitmentScheme< return poly; } - return Poly( - Coefficients({-low_degree_extensions[i].Evaluate(u)})); + return Poly(Coefficients( + {-low_degree_extensions[i].Evaluate(u)}, true)); }); // clang-format off diff --git a/tachyon/zk/plonk/examples/circuit_test.h b/tachyon/zk/plonk/examples/circuit_test.h index 7911a2d75..400389893 100644 --- a/tachyon/zk/plonk/examples/circuit_test.h +++ b/tachyon/zk/plonk/examples/circuit_test.h @@ -97,7 +97,7 @@ class CircuitTest : public halo2::ProverTest coefficients = base::Map( poly, [](std::string_view coeff) { return *F::FromHexString(coeff); }); return Poly(math::UnivariateDenseCoefficients( - std::move(coefficients))); + std::move(coefficients), true)); } static std::vector CreatePolys( From 85d66a024b00d51e4c314ab01362c10383c4fd37 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 20 May 2024 09:51:30 +0900 Subject: [PATCH 23/31] build(zk): add missing deps --- tachyon/zk/plonk/vanishing/circuit_polynomial_builder.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tachyon/zk/plonk/vanishing/circuit_polynomial_builder.h b/tachyon/zk/plonk/vanishing/circuit_polynomial_builder.h index 99efe1de5..2e17c5080 100644 --- a/tachyon/zk/plonk/vanishing/circuit_polynomial_builder.h +++ b/tachyon/zk/plonk/vanishing/circuit_polynomial_builder.h @@ -18,6 +18,7 @@ #include "tachyon/base/parallelize.h" #include "tachyon/base/types/always_false.h" #include "tachyon/zk/base/rotation.h" +#include "tachyon/zk/lookup/halo2/evaluator.h" #include "tachyon/zk/lookup/halo2/prover.h" #include "tachyon/zk/lookup/log_derivative_halo2/evaluator.h" #include "tachyon/zk/plonk/base/column_key.h" From bf57ece189169a3c1138692074252ef29f3692cd Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 20 May 2024 16:47:06 +0900 Subject: [PATCH 24/31] test(zk): fix wrong iterator access --- tachyon/zk/plonk/examples/circuit_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tachyon/zk/plonk/examples/circuit_test.cc b/tachyon/zk/plonk/examples/circuit_test.cc index adaf64f1b..657df1f39 100644 --- a/tachyon/zk/plonk/examples/circuit_test.cc +++ b/tachyon/zk/plonk/examples/circuit_test.cc @@ -155,14 +155,14 @@ void CircuitTest::LoadProvingKeyTest() { CreatePoly(base::ArrayToVector(TestData::kLFirst)); EXPECT_EQ(pkey.l_first(), expected_l_first); } else { - EXPECT_TRUE(pkey.l_first().empty()); + EXPECT_EQ(pkey.l_first().NumElements(), 0); } if constexpr (TestData::kLLastFlag) { Poly expected_l_last = CreatePoly(base::ArrayToVector(TestData::kLLast)); EXPECT_EQ(pkey.l_last(), expected_l_last); } else { - EXPECT_TRUE(pkey.l_last().empty()); + EXPECT_EQ(pkey.l_last().NumElements(), 0); } if constexpr (TestData::kLActiveRowFlag) { @@ -170,7 +170,7 @@ void CircuitTest::LoadProvingKeyTest() { CreatePoly(base::ArrayToVector(TestData::kLActiveRow)); EXPECT_EQ(pkey.l_active_row(), expected_l_active_row); } else { - EXPECT_TRUE(pkey.l_active_row().empty()); + EXPECT_EQ(pkey.l_active_row().NumElements(), 0); } if constexpr (TestData::kFixedColumnsFlag) { From 4a80a47420b395bbeb48d66dfa9a48315613ae2e Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 3 Jun 2024 16:03:03 +0900 Subject: [PATCH 25/31] docs: change all numbered list to 1 --- tachyon/zk/plonk/examples/tracking_testing.md | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/tachyon/zk/plonk/examples/tracking_testing.md b/tachyon/zk/plonk/examples/tracking_testing.md index d7cb6e24f..a1cc9a937 100644 --- a/tachyon/zk/plonk/examples/tracking_testing.md +++ b/tachyon/zk/plonk/examples/tracking_testing.md @@ -51,44 +51,44 @@ Refer to the following files to learn more about these variables: - [simple_lookup_circuit_test_data.h](simple_lookup_circuit_test_data.h) 1. :red_square: kN -2. :red_square: kPinnedConstraintSystem -3. :blue_square: kAssemblyFixedColumns -4. :blue_square: kAssemblyColumns -5. :blue_square: kCycleStoreMapping -6. :blue_square: kCycleStoreAux -7. :blue_square: kCycleStoreSizes -8. :red_square: kCycleStoreSelectors -9. :green_square: kUsableRows -10. :red_square: kPinnedVerifyingKey -11. :red_square: kTranscriptRepr -12. :blue_square: kLFirst -13. :blue_square: kLLast -14. :blue_square: kLActiveRow -15. :blue_square: kFixedColumns -16. :blue_square: kFixedPolys -17. :blue_square: kPermutationsColumns -18. :blue_square: kPermutationsPolys -19. :red_square: kProof -20. :blue_square: kAdviceCommitments -21. :blue_square: kChallenges -22. :red_square: kTheta -23. :blue_square: kPermutationProductCommitmentsPoints -24. :red_square: kBeta -25. :red_square: kGamma -26. :blue_square: kPermutationProductCommitments -27. :blue_square: kLookupProductCommitments -28. :red_square: kY -29. :blue_square: kVanishingHPolyCommitments -30. :red_square: kX -31. :blue_square: kAdviceEvals -32. :blue_square: kFixedEvals -33. :blue_square: kCommonPermutationEvals -34. :blue_square: kPermutationProductEvals -35. :blue_square: kPermutationProductNextEvals -36. :blue_square: kPermutationProductLastEvals -37. :blue_square: kLookupProductEvals -38. :blue_square: kLookupProductNextEvals -39. :blue_square: kLookupPermutedInputEvals -40. :blue_square: kLookupPermutedInputPrevEvals -41. :blue_square: kLookupPermutedTableEvals -42. :blue_square: kHEval +1. :red_square: kPinnedConstraintSystem +1. :blue_square: kAssemblyFixedColumns +1. :blue_square: kAssemblyColumns +1. :blue_square: kCycleStoreMapping +1. :blue_square: kCycleStoreAux +1. :blue_square: kCycleStoreSizes +1. :red_square: kCycleStoreSelectors +1. :green_square: kUsableRows +1. :red_square: kPinnedVerifyingKey +1. :red_square: kTranscriptRepr +1. :blue_square: kLFirst +1. :blue_square: kLLast +1. :blue_square: kLActiveRow +1. :blue_square: kFixedColumns +1. :blue_square: kFixedPolys +1. :blue_square: kPermutationsColumns +1. :blue_square: kPermutationsPolys +1. :red_square: kProof +1. :blue_square: kAdviceCommitments +1. :blue_square: kChallenges +1. :red_square: kTheta +1. :blue_square: kPermutationProductCommitmentsPoints +1. :red_square: kBeta +1. :red_square: kGamma +1. :blue_square: kPermutationProductCommitments +1. :blue_square: kLookupProductCommitments +1. :red_square: kY +1. :blue_square: kVanishingHPolyCommitments +1. :red_square: kX +1. :blue_square: kAdviceEvals +1. :blue_square: kFixedEvals +1. :blue_square: kCommonPermutationEvals +1. :blue_square: kPermutationProductEvals +1. :blue_square: kPermutationProductNextEvals +1. :blue_square: kPermutationProductLastEvals +1. :blue_square: kLookupProductEvals +1. :blue_square: kLookupProductNextEvals +1. :blue_square: kLookupPermutedInputEvals +1. :blue_square: kLookupPermutedInputPrevEvals +1. :blue_square: kLookupPermutedTableEvals +1. :blue_square: kHEval From 3211d4829f18fed4915e8ab36abb469e2cd4adb5 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 3 Jun 2024 16:03:48 +0900 Subject: [PATCH 26/31] chore(zk): fix inappropriate flag name --- tachyon/zk/plonk/examples/circuit_test.cc | 10 +++++----- tachyon/zk/plonk/examples/circuit_test_data.h | 2 +- .../plonk/examples/simple_lookup_circuit_test_data.h | 6 +++--- tachyon/zk/plonk/examples/tracking_testing.md | 3 ++- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tachyon/zk/plonk/examples/circuit_test.cc b/tachyon/zk/plonk/examples/circuit_test.cc index 657df1f39..aef30bed6 100644 --- a/tachyon/zk/plonk/examples/circuit_test.cc +++ b/tachyon/zk/plonk/examples/circuit_test.cc @@ -274,19 +274,19 @@ void CircuitTest::VerifyProofTest() { F expected_theta = *F::FromHexString(TestData::kTheta); EXPECT_EQ(proof.theta, expected_theta); - if constexpr (TestData::kPermutationProductCommitmentsPointsFlag) { + if constexpr (TestData::kLookupPermutedCommitmentsPointsFlag) { std::vector>> expected_lookup_permuted_commitments_vec{ CreateLookupPermutedCommitments( base::ArrayToVector( - TestData::kPermutationProductCommitmentsInputPoints[0]), + TestData::kLookupPermutedCommitmentsInputPoints[0]), base::ArrayToVector( - TestData::kPermutationProductCommitmentsTablePoints[0])), + TestData::kLookupPermutedCommitmentsTablePoints[0])), CreateLookupPermutedCommitments( base::ArrayToVector( - TestData::kPermutationProductCommitmentsInputPoints[1]), + TestData::kLookupPermutedCommitmentsInputPoints[1]), base::ArrayToVector( - TestData::kPermutationProductCommitmentsTablePoints[1])), + TestData::kLookupPermutedCommitmentsTablePoints[1])), }; EXPECT_EQ(proof.lookup_permuted_commitments_vec, expected_lookup_permuted_commitments_vec); diff --git a/tachyon/zk/plonk/examples/circuit_test_data.h b/tachyon/zk/plonk/examples/circuit_test_data.h index ab7a84a1c..b240a73fd 100644 --- a/tachyon/zk/plonk/examples/circuit_test_data.h +++ b/tachyon/zk/plonk/examples/circuit_test_data.h @@ -30,7 +30,7 @@ class CircuitTestData { constexpr static bool kPermutationsPolysFlag = false; constexpr static bool kAdviceCommitmentsFlag = false; constexpr static bool kChallengesFlag = false; - constexpr static bool kPermutationProductCommitmentsPointsFlag = false; + constexpr static bool kLookupPermutedCommitmentsPointsFlag = false; constexpr static bool kPermutationProductCommitmentsFlag = false; constexpr static bool kLookupProductCommitmentsFlag = false; constexpr static bool kVanishingHPolyCommitmentsFlag = false; diff --git a/tachyon/zk/plonk/examples/simple_lookup_circuit_test_data.h b/tachyon/zk/plonk/examples/simple_lookup_circuit_test_data.h index f8c7f9f98..c242111f0 100644 --- a/tachyon/zk/plonk/examples/simple_lookup_circuit_test_data.h +++ b/tachyon/zk/plonk/examples/simple_lookup_circuit_test_data.h @@ -27,7 +27,7 @@ class SimpleLookupTestData : public CircuitTestData { constexpr static bool kFixedColumnsFlag = true; constexpr static bool kFixedPolysFlag = true; constexpr static bool kAdviceCommitmentsFlag = true; - constexpr static bool kPermutationProductCommitmentsPointsFlag = true; + constexpr static bool kLookupPermutedCommitmentsPointsFlag = true; constexpr static bool kLookupProductCommitmentsFlag = true; constexpr static bool kVanishingHPolyCommitmentsFlag = true; constexpr static bool kAdviceEvalsFlag = true; @@ -566,7 +566,7 @@ class SimpleLookupTestData : public CircuitTestData { "0x19f2e881193a280d2d77a8bc0f9edf053732ec86f93279a580830fb2befeccd7"; // clang-format off - constexpr static Point kPermutationProductCommitmentsInputPoints[][1] = { + constexpr static Point kLookupPermutedCommitmentsInputPoints[][1] = { { {"0x0570bae08fb2d8f086ef87cdba76c74d323b3829e63be2b8b1a0140a7c8263a1", "0x0eb968ee1f6663417be8e37d714a7dec22a717d74bc3c8bc1f4a4bd58da49eed"}, @@ -577,7 +577,7 @@ class SimpleLookupTestData : public CircuitTestData { }, }; - constexpr static Point kPermutationProductCommitmentsTablePoints[][1] = { + constexpr static Point kLookupPermutedCommitmentsTablePoints[][1] = { { {"0x1f229d9bf8e868c447c012f97463d59ace9d0242b0a72731268ed1abd2a5126e", "0x29edba749b5dc16811d78ee18bce88c5c61cd56230ad68e73c578361062a317d"}, diff --git a/tachyon/zk/plonk/examples/tracking_testing.md b/tachyon/zk/plonk/examples/tracking_testing.md index a1cc9a937..ec39769fa 100644 --- a/tachyon/zk/plonk/examples/tracking_testing.md +++ b/tachyon/zk/plonk/examples/tracking_testing.md @@ -72,7 +72,8 @@ Refer to the following files to learn more about these variables: 1. :blue_square: kAdviceCommitments 1. :blue_square: kChallenges 1. :red_square: kTheta -1. :blue_square: kPermutationProductCommitmentsPoints +1. :blue_square: kLookupPermutedCommitmentsInputPoints +1. :blue_square: kLookupPermutedCommitmentsTablePoints 1. :red_square: kBeta 1. :red_square: kGamma 1. :blue_square: kPermutationProductCommitments From e8f81fc62ab07da2a60cb5831de41b21c455cea3 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Mon, 3 Jun 2024 16:04:33 +0900 Subject: [PATCH 27/31] test(zk): add circuit test flags for LogUp --- tachyon/zk/plonk/examples/circuit_test.cc | 54 ++++++++++++++----- tachyon/zk/plonk/examples/circuit_test_data.h | 5 ++ tachyon/zk/plonk/examples/tracking_testing.md | 5 ++ 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/tachyon/zk/plonk/examples/circuit_test.cc b/tachyon/zk/plonk/examples/circuit_test.cc index aef30bed6..43046de51 100644 --- a/tachyon/zk/plonk/examples/circuit_test.cc +++ b/tachyon/zk/plonk/examples/circuit_test.cc @@ -290,8 +290,15 @@ void CircuitTest::VerifyProofTest() { }; EXPECT_EQ(proof.lookup_permuted_commitments_vec, expected_lookup_permuted_commitments_vec); - } else { - EXPECT_TRUE(proof.lookup_permuted_commitments_vec[0].empty()); + } else if constexpr (TestData::kLookupMPolyCommitmentsFlag) { + std::vector> expected_lookup_m_poly_commitments_vec{ + CreateCommitments( + base::ArrayToVector(TestData::kLookupMPolyCommitments[0])), + CreateCommitments( + base::ArrayToVector(TestData::kLookupMPolyCommitments[1])), + }; + EXPECT_EQ(proof.lookup_m_poly_commitments_vec, + expected_lookup_m_poly_commitments_vec); } F expected_beta = *F::FromHexString(TestData::kBeta); @@ -324,8 +331,16 @@ void CircuitTest::VerifyProofTest() { }; EXPECT_EQ(proof.lookup_product_commitments_vec, expected_lookup_product_commitments_vec); - } else { - EXPECT_TRUE(proof.lookup_product_commitments_vec[0].empty()); + } else if constexpr (TestData::kLookupSumCommitmentsFlag) { + std::vector> + expected_lookup_sum_commitments_commitments_vec{ + CreateCommitments( + base::ArrayToVector(TestData::kLookupSumCommitments[0])), + CreateCommitments( + base::ArrayToVector(TestData::kLookupSumCommitments[1])), + }; + EXPECT_EQ(proof.lookup_sum_commitments_vec, + expected_lookup_sum_commitments_commitments_vec); } Commitment expected_vanishing_random_poly_commitment = @@ -425,8 +440,12 @@ void CircuitTest::VerifyProofTest() { }; EXPECT_EQ(proof.lookup_product_evals_vec, expected_lookup_product_evals_vec); - } else { - EXPECT_TRUE(proof.lookup_product_evals_vec[0].empty()); + } else if constexpr (TestData::kLookupSumEvalsFlag) { + std::vector> expected_lookup_sum_evals_vec{ + CreateEvals(base::ArrayToVector(TestData::kLookupSumEvals[0])), + CreateEvals(base::ArrayToVector(TestData::kLookupSumEvals[1])), + }; + EXPECT_EQ(proof.lookup_sum_evals_vec, expected_lookup_sum_evals_vec); } if constexpr (TestData::kLookupProductNextEvalsFlag) { @@ -436,8 +455,13 @@ void CircuitTest::VerifyProofTest() { }; EXPECT_EQ(proof.lookup_product_next_evals_vec, expected_lookup_product_next_evals_vec); - } else { - EXPECT_TRUE(proof.lookup_product_next_evals_vec[0].empty()); + } else if constexpr (TestData::kLookupSumNextEvalsFlag) { + std::vector> expected_lookup_sum_next_evals_vec{ + CreateEvals(base::ArrayToVector(TestData::kLookupSumNextEvals[0])), + CreateEvals(base::ArrayToVector(TestData::kLookupSumNextEvals[1])), + }; + EXPECT_EQ(proof.lookup_sum_next_evals_vec, + expected_lookup_sum_next_evals_vec); } if constexpr (TestData::kLookupPermutedInputEvalsFlag) { @@ -449,8 +473,6 @@ void CircuitTest::VerifyProofTest() { }; EXPECT_EQ(proof.lookup_permuted_input_evals_vec, expected_lookup_permuted_input_evals_vec); - } else { - EXPECT_TRUE(proof.lookup_permuted_input_evals_vec[0].empty()); } if constexpr (TestData::kLookupPermutedInputPrevEvalsFlag) { @@ -462,8 +484,6 @@ void CircuitTest::VerifyProofTest() { }; EXPECT_EQ(proof.lookup_permuted_input_prev_evals_vec, expected_lookup_permuted_input_prev_evals_vec); - } else { - EXPECT_TRUE(proof.lookup_permuted_input_prev_evals_vec[0].empty()); } if constexpr (TestData::kLookupPermutedTableEvalsFlag) { @@ -475,8 +495,14 @@ void CircuitTest::VerifyProofTest() { }; EXPECT_EQ(proof.lookup_permuted_table_evals_vec, expected_lookup_permuted_table_evals_vec); - } else { - EXPECT_TRUE(proof.lookup_permuted_table_evals_vec[0].empty()); + } + + if constexpr (TestData::kLookupMEvalsFlag) { + std::vector> expected_lookup_m_evals_vec{ + CreateEvals(base::ArrayToVector(TestData::kLookupMEvals[0])), + CreateEvals(base::ArrayToVector(TestData::kLookupMEvals[1])), + }; + EXPECT_EQ(proof.lookup_m_evals_vec, expected_lookup_m_evals_vec); } // TODO(ashjeong): get |h_eval| for fibonacci tests diff --git a/tachyon/zk/plonk/examples/circuit_test_data.h b/tachyon/zk/plonk/examples/circuit_test_data.h index b240a73fd..b2bdd21b1 100644 --- a/tachyon/zk/plonk/examples/circuit_test_data.h +++ b/tachyon/zk/plonk/examples/circuit_test_data.h @@ -31,8 +31,10 @@ class CircuitTestData { constexpr static bool kAdviceCommitmentsFlag = false; constexpr static bool kChallengesFlag = false; constexpr static bool kLookupPermutedCommitmentsPointsFlag = false; + constexpr static bool kLookupMPolyCommitmentsFlag = false; constexpr static bool kPermutationProductCommitmentsFlag = false; constexpr static bool kLookupProductCommitmentsFlag = false; + constexpr static bool kLookupSumCommitmentsFlag = false; constexpr static bool kVanishingHPolyCommitmentsFlag = false; constexpr static bool kAdviceEvalsFlag = false; constexpr static bool kFixedEvalsFlag = false; @@ -41,10 +43,13 @@ class CircuitTestData { constexpr static bool kPermutationProductNextEvalsFlag = false; constexpr static bool kPermutationProductLastEvalsFlag = false; constexpr static bool kLookupProductEvalsFlag = false; + constexpr static bool kLookupSumEvalsFlag = false; constexpr static bool kLookupProductNextEvalsFlag = false; + constexpr static bool kLookupSumNextEvalsFlag = false; constexpr static bool kLookupPermutedInputEvalsFlag = false; constexpr static bool kLookupPermutedInputPrevEvalsFlag = false; constexpr static bool kLookupPermutedTableEvalsFlag = false; + constexpr static bool kLookupMEvalsFlag = false; constexpr static base::Range kUsableRows = base::Range::Until(10); diff --git a/tachyon/zk/plonk/examples/tracking_testing.md b/tachyon/zk/plonk/examples/tracking_testing.md index ec39769fa..7c14534c3 100644 --- a/tachyon/zk/plonk/examples/tracking_testing.md +++ b/tachyon/zk/plonk/examples/tracking_testing.md @@ -74,10 +74,12 @@ Refer to the following files to learn more about these variables: 1. :red_square: kTheta 1. :blue_square: kLookupPermutedCommitmentsInputPoints 1. :blue_square: kLookupPermutedCommitmentsTablePoints +1. :blue_square: kLookupMPolyCommitments 1. :red_square: kBeta 1. :red_square: kGamma 1. :blue_square: kPermutationProductCommitments 1. :blue_square: kLookupProductCommitments +1. :blue_square: kLookupSumCommitments 1. :red_square: kY 1. :blue_square: kVanishingHPolyCommitments 1. :red_square: kX @@ -88,8 +90,11 @@ Refer to the following files to learn more about these variables: 1. :blue_square: kPermutationProductNextEvals 1. :blue_square: kPermutationProductLastEvals 1. :blue_square: kLookupProductEvals +1. :blue_square: kLookupSumEvals 1. :blue_square: kLookupProductNextEvals +1. :blue_square: kLookupSumNextEvals 1. :blue_square: kLookupPermutedInputEvals 1. :blue_square: kLookupPermutedInputPrevEvals 1. :blue_square: kLookupPermutedTableEvals +1. :blue_square: kLookupMEvals 1. :blue_square: kHEval From 5ce5f05cc9a25658b218c9611409c2d7a49ad80a Mon Sep 17 00:00:00 2001 From: Insun35 Date: Wed, 12 Jun 2024 16:18:03 +0900 Subject: [PATCH 28/31] build(zk): add missing deps --- tachyon/zk/plonk/examples/BUILD.bazel | 2 ++ tachyon/zk/plonk/examples/circuit_test_type_traits.h | 1 + 2 files changed, 3 insertions(+) diff --git a/tachyon/zk/plonk/examples/BUILD.bazel b/tachyon/zk/plonk/examples/BUILD.bazel index a9a2bb246..b429e13cf 100644 --- a/tachyon/zk/plonk/examples/BUILD.bazel +++ b/tachyon/zk/plonk/examples/BUILD.bazel @@ -26,6 +26,7 @@ tachyon_cc_library( tachyon_cc_library( name = "circuit_test_type_traits", + testonly = True, hdrs = ["circuit_test_type_traits.h"], deps = [ "//tachyon/math/elliptic_curves/bn/bn254", @@ -35,6 +36,7 @@ tachyon_cc_library( "//tachyon/zk/plonk/examples/fibonacci:fibonacci1_circuit", "//tachyon/zk/plonk/examples/fibonacci:fibonacci2_circuit", "//tachyon/zk/plonk/examples/fibonacci:fibonacci3_circuit", + "//tachyon/zk/plonk/halo2:prover_test", "//tachyon/zk/plonk/layout/floor_planner:simple_floor_planner", "//tachyon/zk/plonk/layout/floor_planner/v1:v1_floor_planner", ], diff --git a/tachyon/zk/plonk/examples/circuit_test_type_traits.h b/tachyon/zk/plonk/examples/circuit_test_type_traits.h index 61bfa0666..d10b66d4d 100644 --- a/tachyon/zk/plonk/examples/circuit_test_type_traits.h +++ b/tachyon/zk/plonk/examples/circuit_test_type_traits.h @@ -10,6 +10,7 @@ #include "tachyon/zk/plonk/examples/fibonacci/fibonacci1_circuit.h" #include "tachyon/zk/plonk/examples/fibonacci/fibonacci2_circuit.h" #include "tachyon/zk/plonk/examples/fibonacci/fibonacci3_circuit.h" +#include "tachyon/zk/plonk/halo2/prover_test.h" #include "tachyon/zk/plonk/layout/floor_planner/simple_floor_planner.h" #include "tachyon/zk/plonk/layout/floor_planner/v1/v1_floor_planner.h" From a241f2a5b7a313f3c5ad743193fa23a159685bb3 Mon Sep 17 00:00:00 2001 From: Insun35 Date: Thu, 13 Jun 2024 18:56:14 +0900 Subject: [PATCH 29/31] refac(zk): move circuit test logic to header --- tachyon/zk/plonk/examples/BUILD.bazel | 1 - tachyon/zk/plonk/examples/circuit_test.cc | 598 ---------------------- tachyon/zk/plonk/examples/circuit_test.h | 499 +++++++++++++++++- 3 files changed, 493 insertions(+), 605 deletions(-) delete mode 100644 tachyon/zk/plonk/examples/circuit_test.cc diff --git a/tachyon/zk/plonk/examples/BUILD.bazel b/tachyon/zk/plonk/examples/BUILD.bazel index b429e13cf..0dedf2886 100644 --- a/tachyon/zk/plonk/examples/BUILD.bazel +++ b/tachyon/zk/plonk/examples/BUILD.bazel @@ -45,7 +45,6 @@ tachyon_cc_library( tachyon_cc_library( name = "circuit_test", testonly = True, - srcs = ["circuit_test.cc"], hdrs = ["circuit_test.h"], deps = [ ":point", diff --git a/tachyon/zk/plonk/examples/circuit_test.cc b/tachyon/zk/plonk/examples/circuit_test.cc deleted file mode 100644 index 43046de51..000000000 --- a/tachyon/zk/plonk/examples/circuit_test.cc +++ /dev/null @@ -1,598 +0,0 @@ -#include "tachyon/zk/plonk/examples/circuit_test.h" - -#include -#include - -#include "gtest/gtest.h" - -#include "tachyon/base/array_to_vector.h" -#include "tachyon/zk/plonk/examples/circuit_test_type_traits.h" -#include "tachyon/zk/plonk/examples/fibonacci/fibonacci1_circuit.h" -#include "tachyon/zk/plonk/examples/fibonacci/fibonacci1_circuit_test_data.h" -#include "tachyon/zk/plonk/examples/fibonacci/fibonacci2_circuit.h" -#include "tachyon/zk/plonk/examples/fibonacci/fibonacci2_circuit_test_data.h" -#include "tachyon/zk/plonk/examples/fibonacci/fibonacci3_circuit.h" -#include "tachyon/zk/plonk/examples/fibonacci/fibonacci3_circuit_test_data.h" -#include "tachyon/zk/plonk/examples/shuffle_circuit.h" -#include "tachyon/zk/plonk/examples/shuffle_circuit_test_data.h" -#include "tachyon/zk/plonk/examples/simple_circuit.h" -#include "tachyon/zk/plonk/examples/simple_circuit_test_data.h" -#include "tachyon/zk/plonk/examples/simple_lookup_circuit.h" -#include "tachyon/zk/plonk/examples/simple_lookup_circuit_test_data.h" -#include "tachyon/zk/plonk/halo2/pinned_constraint_system.h" -#include "tachyon/zk/plonk/halo2/pinned_verifying_key.h" -#include "tachyon/zk/plonk/keys/proving_key.h" -#include "tachyon/zk/plonk/layout/floor_planner/simple_floor_planner.h" -#include "tachyon/zk/plonk/layout/floor_planner/v1/v1_floor_planner.h" - -namespace tachyon::zk::plonk { - -template -void CircuitTest::ConfigureTest() { - ConstraintSystem constraint_system(TestArguments::LS::type); - - auto config = Circuit::Configure(constraint_system); - - TestData::TestConfig(config); - - halo2::PinnedConstraintSystem pinned_constraint_system(constraint_system); - EXPECT_EQ(TestData::kPinnedConstraintSystem, - base::ToRustDebugString(pinned_constraint_system)); - - EXPECT_TRUE(constraint_system.selector_map().empty()); - EXPECT_TRUE(constraint_system.general_column_annotations().empty()); -} - -template -void CircuitTest::SynthesizeTest() { - CHECK(this->prover_->pcs().UnsafeSetup(TestData::kN, F(2))); - this->prover_->set_domain(Domain::Create(TestData::kN)); - const Domain* domain = this->prover_->domain(); - - ConstraintSystem constraint_system(TestArguments::LS::type); - - auto config = Circuit::Configure(constraint_system); - Assembly assembly = - VerifyingKey::template CreateAssembly( - domain, constraint_system); - - Circuit circuit = TestData::GetCircuit(); - typename Circuit::FloorPlanner floor_planner; - floor_planner.Synthesize(&assembly, circuit, std::move(config), - constraint_system.constants()); - - if constexpr (TestData::kAssemblyFixedColumnsFlag) { - std::vector expected_fixed_columns = CreateRationalColumns( - base::Array2DToVector2D(TestData::kAssemblyFixedColumns)); - EXPECT_EQ(assembly.fixed_columns(), expected_fixed_columns); - } else { - EXPECT_TRUE(assembly.fixed_columns().empty()); - } - - if constexpr (TestData::kAssemblyPermutationColumnsFlag) { - std::vector expected_columns = - base::ArrayToVector(TestData::kAssemblyPermutationColumns); - EXPECT_EQ(assembly.permutation().columns(), expected_columns); - } else { - EXPECT_TRUE(assembly.permutation().columns().empty()); - } - - const CycleStore& cycle_store = assembly.permutation().cycle_store(); - - if constexpr (TestData::kCycleStoreMappingFlag) { - CycleStore::Table