66#ifndef VENDORS_CIRCOM_CIRCOMLIB_CIRCUIT_QUADRATIC_ARITHMETIC_PROGRAM_H_
77#define VENDORS_CIRCOM_CIRCOMLIB_CIRCUIT_QUADRATIC_ARITHMETIC_PROGRAM_H_
88
9- #include < memory>
109#include < utility>
1110#include < vector>
1211
12+ #include " circomlib/zkey/coefficient.h"
1313#include " tachyon/base/logging.h"
1414#include " tachyon/zk/r1cs/constraint_system/quadratic_arithmetic_program.h"
1515
@@ -20,55 +20,46 @@ class QuadraticArithmeticProgram {
2020 public:
2121 QuadraticArithmeticProgram () = delete ;
2222
23- template <typename Domain>
24- static zk::r1cs::QAPInstanceMapResult<F> InstanceMap (
25- const Domain* domain, const zk::r1cs::ConstraintSystem<F>& cs,
26- const F& x) {
27- return zk::r1cs::QuadraticArithmeticProgram<F>::InstanceMap (domain, cs, x);
28- }
29-
3023 template <typename Domain>
3124 static std::vector<F> WitnessMapFromMatrices (
32- const Domain* domain, const zk::r1cs::ConstraintMatrices<F>& matrices ,
25+ const Domain* domain, absl::Span< const Coefficient<F>> coefficients ,
3326 absl::Span<const F> full_assignments) {
3427 using Evals = typename Domain::Evals;
3528 using DensePoly = typename Domain::DensePoly;
3629
37- CHECK_GE (domain->size (), matrices.num_constraints );
38-
3930 std::vector<F> a (domain->size ());
4031 std::vector<F> b (domain->size ());
4132 std::vector<F> c (domain->size ());
4233
43- // clang-format off
44- // |a[i]| = Σⱼ₌₀..ₘ (xⱼ * Aᵢ,ⱼ) (if i < |num_constraints|)
45- // = x[i - num_constraints] (otherwise)
46- // |b[i]| = Σⱼ₌₀..ₘ (xⱼ * Bᵢ,ⱼ) (if i < |num_constraints|)
47- // = 0 (otherwise)
48- // |c[i]| = |a[i]|* |b[i]| (if i < |num_constraints|)
49- // = 0 (otherwise)
50- // where x is |full_assignments|.
51- // clang-format on
52- OMP_PARALLEL {
53- OMP_FOR_NOWAIT
54- for (size_t i = 0 ; i < matrices.num_constraints ; ++i) {
55- a[i] = zk::r1cs::EvaluateConstraint (matrices.a [i], full_assignments);
56- }
57-
58- OMP_FOR
59- for (size_t i = 0 ; i < matrices.num_constraints ; ++i) {
60- b[i] = zk::r1cs::EvaluateConstraint (matrices.b [i], full_assignments);
61- }
62-
63- OMP_FOR
64- for (size_t i = 0 ; i < matrices.num_constraints ; ++i) {
65- c[i] = a[i] * b[i];
34+ // See
35+ // https://github.com/iden3/rapidsnark/blob/b17e6fed08e9ceec3518edeffe4384313f91e9ad/src/groth16.cpp#L116-L156.
36+ #if defined(TACHYON_HAS_OPENMP)
37+ constexpr size_t kNumLocks = 1024 ;
38+ omp_lock_t locks[kNumLocks ];
39+ for (size_t i = 0 ; i < kNumLocks ; i++) omp_init_lock (&locks[i]);
40+ #endif
41+ OPENMP_PARALLEL_FOR (size_t i = 0 ; i < coefficients.size (); i++) {
42+ const Coefficient<F>& c = coefficients[i];
43+ std::vector<F>& ab = (c.matrix == 0 ) ? a : b;
44+
45+ #if defined(TACHYON_HAS_OPENMP)
46+ omp_set_lock (&locks[c.constraint % kNumLocks ]);
47+ #endif
48+ if (c.value .IsOne ()) {
49+ ab[c.constraint ] += full_assignments[c.signal ];
50+ } else {
51+ ab[c.constraint ] += c.value * full_assignments[c.signal ];
6652 }
53+ #if defined(TACHYON_HAS_OPENMP)
54+ omp_unset_lock (&locks[c.constraint % kNumLocks ]);
55+ #endif
6756 }
57+ #if defined(TACHYON_HAS_OPENMP)
58+ for (size_t i = 0 ; i < kNumLocks ; i++) omp_destroy_lock (&locks[i]);
59+ #endif
6860
69- for (size_t i = matrices.num_constraints ;
70- i < matrices.num_constraints + matrices.num_instance_variables ; ++i) {
71- a[i] = full_assignments[i - matrices.num_constraints ];
61+ OPENMP_PARALLEL_FOR (size_t i = 0 ; i < domain->size (); ++i) {
62+ c[i] = a[i] * b[i];
7263 }
7364
7465 Evals a_evals (std::move (a));
@@ -79,11 +70,8 @@ class QuadraticArithmeticProgram {
7970 DensePoly c_poly = domain->IFFT (std::move (c_evals));
8071
8172 F root_of_unity;
82- {
83- std::unique_ptr<Domain> extended_domain =
84- Domain::Create (2 * domain->size ());
85- root_of_unity = extended_domain->GetElement (1 );
86- }
73+ CHECK (F::GetRootOfUnity (2 * domain->size (), &root_of_unity));
74+
8775 Domain::DistributePowers (a_poly, root_of_unity);
8876 Domain::DistributePowers (b_poly, root_of_unity);
8977 Domain::DistributePowers (c_poly, root_of_unity);
@@ -101,26 +89,6 @@ class QuadraticArithmeticProgram {
10189
10290 return std::move (a_evals).TakeEvaluations ();
10391 }
104-
105- template <typename Domain>
106- static std::vector<F> ComputeHQuery (const Domain* domain, const F& t_x,
107- const F& x, const F& delta_inverse) {
108- using Evals = typename Domain::Evals;
109- using DensePoly = typename Domain::DensePoly;
110-
111- // The usual H query has domain - 1 powers. Z has domain powers. So HZ has
112- // 2 * domain - 1 powers.
113- std::unique_ptr<Domain> extended_domain =
114- Domain::Create (domain->size () * 2 + 1 );
115- Evals evals (
116- F::GetSuccessivePowers (extended_domain->size (), t_x, delta_inverse));
117- DensePoly poly = extended_domain->IFFT (std::move (evals));
118- std::vector<F> ret (domain->size ());
119- OPENMP_PARALLEL_FOR (size_t i = 0 ; i < domain->size (); ++i) {
120- ret[i] = poly[2 * i + 1 ];
121- }
122- return ret;
123- }
12492};
12593
12694} // namespace tachyon::circom
0 commit comments