Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
memory_relation.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Luke, Raju], commit: 05a381f8b31ae4648e480f1369e911b148216e8b}
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
10
11namespace bb {
12
43template <typename FF_> class MemoryRelationImpl {
44 public:
45 using FF = FF_;
46
47 static constexpr std::array<size_t, 8> SUBRELATION_PARTIAL_LENGTHS{
48 6, // memory sub-relation;
49 6, // ROM consistency sub-relation 1
50 6, // ROM consistency sub-relation 2
51 6, // RAM consistency sub-relation 1
52 6, // RAM consistency sub-relation 2
53 6, // RAM consistency sub-relation 3
54 6, // ROM-LogUp inverse correctness (per-row vanishing)
55 6 // ROM-LogUp sum identity (linearly dependent: summed across the trace)
56 };
57
58 // Subrelation 7 (ROM-LogUp sum) is linearly dependent: it asserts that a sum across all rows is zero rather
59 // than a per-row identity, so it must not be multiplied by `scaling_factor` in the accumulation step.
60 static constexpr std::array<bool, 8> SUBRELATION_LINEARLY_INDEPENDENT{ true, true, true, true,
61 true, true, true, false };
62
67 template <typename AllEntities> inline static bool skip(const AllEntities& in)
68 {
69 return in[AllEntities::EntityId::q_memory].is_zero();
70 }
71
78 template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
79 inline static void accumulate(ContainerOverSubrelations& accumulators,
80 const AllEntities& in,
81 const Parameters& params,
82 const FF& scaling_factor)
83 {
84 // all accumulators are of the same length, so we set our accumulator type to (arbitrarily) be the first one.
85 // if there were one that were shorter, we could also profitably use a `ShortAccumulator` type. however,
86 // that is not the case here.
88 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
89
90 using ParameterCoefficientAccumulator = typename Parameters::DataType::CoefficientAccumulator;
91
92 const auto& eta_m = ParameterCoefficientAccumulator(params.eta);
93 const auto& eta_two_m = ParameterCoefficientAccumulator(params.eta_two);
94 const auto& eta_three_m = ParameterCoefficientAccumulator(params.eta_three);
95 const auto& rom_logup_gamma_m = ParameterCoefficientAccumulator(params.rom_logup_gamma);
96
97 auto w_1_m = CoefficientAccumulator(in[AllEntities::EntityId::w_l]);
98 auto w_2_m = CoefficientAccumulator(in[AllEntities::EntityId::w_r]);
99 auto w_3_m = CoefficientAccumulator(in[AllEntities::EntityId::w_o]);
100 auto w_4_m = CoefficientAccumulator(in[AllEntities::EntityId::w_4]);
101 auto w_1_shift_m = CoefficientAccumulator(in[AllEntities::EntityId::w_l_shift]);
102 auto w_2_shift_m = CoefficientAccumulator(in[AllEntities::EntityId::w_r_shift]);
103 auto w_3_shift_m = CoefficientAccumulator(in[AllEntities::EntityId::w_o_shift]);
104 auto w_4_shift_m = CoefficientAccumulator(in[AllEntities::EntityId::w_4_shift]);
105
106 auto q_1_m = CoefficientAccumulator(in[AllEntities::EntityId::q_l]);
107 auto q_2_m = CoefficientAccumulator(in[AllEntities::EntityId::q_r]);
108 auto q_3_m = CoefficientAccumulator(in[AllEntities::EntityId::q_o]);
109 auto q_4_m = CoefficientAccumulator(in[AllEntities::EntityId::q_4]);
110 auto q_m_m = CoefficientAccumulator(in[AllEntities::EntityId::q_m]);
111 auto q_c_m = CoefficientAccumulator(in[AllEntities::EntityId::q_c]);
112
113 auto q_memory_m = CoefficientAccumulator(in[AllEntities::EntityId::q_memory]);
114
156 auto memory_record_check_m = w_3_m * eta_three_m; // degree 1
157 memory_record_check_m += w_2_m * eta_two_m;
158 memory_record_check_m += w_1_m * eta_m;
159 memory_record_check_m += q_c_m;
160 auto partial_record_check_m = memory_record_check_m; // degree 1. used later in RAM consistency check
161 memory_record_check_m = memory_record_check_m - w_4_m;
162 auto memory_record_check = Accumulator(memory_record_check_m);
180 auto neg_index_delta_m = w_1_m - w_1_shift_m;
181 auto index_delta_is_zero_m = neg_index_delta_m + FF(1); // deg 1
182 auto record_delta_m = w_4_shift_m - w_4_m;
183
184 Accumulator index_increases_by_zero_or_one(neg_index_delta_m.sqr() +
185 neg_index_delta_m); // check if next index minus current index is
186 // boolean. applies to both ROM and RAM. deg 2
187
188 auto adjacent_values_match_if_adjacent_indices_match =
189 Accumulator(index_delta_is_zero_m * record_delta_m); // deg 2
190
191 auto q_memory_by_scaling_m = q_memory_m * scaling_factor; // deg 1
192 auto q_memory_by_scaling = Accumulator(q_memory_by_scaling_m);
193 auto q_one_by_two_m = q_1_m * q_2_m; // deg 2
194 auto q_one_by_two = Accumulator(q_one_by_two_m);
195 auto q_one_by_two_by_memory_by_scaling = q_one_by_two * q_memory_by_scaling; // deg 3
196 // witnesses that for consecutive ROM gates, values match if indices match.
197 std::get<1>(accumulators) +=
198 adjacent_values_match_if_adjacent_indices_match * q_one_by_two_by_memory_by_scaling; // deg 5
199 // witnesses that index increases by {0, 1} for sorted ROM gates.
200 std::get<2>(accumulators) += index_increases_by_zero_or_one * q_one_by_two_by_memory_by_scaling; // deg 5
201
202 auto ROM_consistency_check_identity = memory_record_check * q_one_by_two; // deg 3
203
228 auto neg_access_type_m = (partial_record_check_m - w_4_m); // will be boolean for honest Prover; degree 1.
229 Accumulator neg_access_type(neg_access_type_m);
230 auto access_check = neg_access_type.sqr() + neg_access_type; // check value is boolean; degree 2.
231
232 auto neg_next_gate_access_type_m = w_3_shift_m * eta_three_m; // degree 1
233 neg_next_gate_access_type_m += w_2_shift_m * eta_two_m;
234 neg_next_gate_access_type_m += w_1_shift_m * eta_m;
235 neg_next_gate_access_type_m = neg_next_gate_access_type_m - w_4_shift_m;
236 Accumulator neg_next_gate_access_type(neg_next_gate_access_type_m); // degree 1
237 auto value_delta_m = w_3_shift_m - w_3_m; // degree 1
238 auto adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation =
239 Accumulator(index_delta_is_zero_m * value_delta_m) *
240 Accumulator(neg_next_gate_access_type_m + FF(1)); // deg 3
241
242 // We can't apply the RAM consistency check identity on the final entry in the sorted list: the wires in the
243 // next gate would make the identity fail. We need to validate that its 'access type' bool is correct. Can't
244 // do with an arithmetic gate because of the `eta` factors.
245 // Our solution is that we have the final sorted RAM record be unconstrained (i.e., none of the
246 // `MEMORY_SELECTORS` are turned on); then, we may _uniformly_ check that the *next* gate's access type is
247 // correct, to cover this edge case.
248 auto next_gate_access_type_is_boolean = neg_next_gate_access_type.sqr() + neg_next_gate_access_type; // deg 2
249
250 auto q_3_by_memory_and_scaling = Accumulator(q_3_m * q_memory_by_scaling_m);
251 // For RAM entries, if adjacent indices match and the next access is a read, then
252 // values must be equal.
253 std::get<3>(accumulators) +=
254 adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation *
255 q_3_by_memory_and_scaling; // deg 5
256 std::get<4>(accumulators) += index_increases_by_zero_or_one * q_3_by_memory_and_scaling; // deg 4
257 std::get<5>(accumulators) += next_gate_access_type_is_boolean * q_3_by_memory_and_scaling; // deg 4
258
259 auto RAM_consistency_check_identity = access_check * q_3_by_memory_and_scaling; // deg 4
260
280 auto timestamp_delta_m = w_2_shift_m - w_2_m; // deg 1
281 auto RAM_timestamp_check_identity_m = index_delta_is_zero_m * timestamp_delta_m - w_3_m; // deg 2
282 Accumulator RAM_timestamp_check_identity(RAM_timestamp_check_identity_m);
288 // degree 5
289 auto memory_identity = ROM_consistency_check_identity;
290 memory_identity += RAM_timestamp_check_identity * Accumulator(q_4_m * q_1_m); // deg 4
291 memory_identity += memory_record_check * Accumulator(q_m_m * q_1_m); // deg 4
292
293 memory_identity *= q_memory_by_scaling; // deg 5
294 memory_identity += RAM_consistency_check_identity; // deg 5
295 std::get<0>(accumulators) += memory_identity; // deg 5
296
340 auto one_minus_q_1_m = -q_1_m + FF(1); // deg 1
341 Accumulator q_logup_table(q_2_m * one_minus_q_1_m); // deg 2
342 Accumulator q_logup_read(q_4_m * one_minus_q_1_m); // deg 2
343 Accumulator q_logup_any = q_logup_table + q_logup_read;
344
345 // Fingerprint denominator: w_l + eta * w_r + eta_two * q_c + rom_logup_gamma. Degree 1.
346 Accumulator denom(w_1_m + w_2_m * eta_m + q_c_m * eta_two_m + rom_logup_gamma_m);
347
348 Accumulator w_4_acc(w_4_m);
349
350 // Subrelation 6: q_memory * q_logup_any * (w_4 * denom - 1) = 0. Per-row vanishing; deg 5.
351 std::get<6>(accumulators) += q_memory_by_scaling * q_logup_any * (w_4_acc * denom - FF(1));
352
353 // Subrelation 7: sum over the trace of q_memory * (q_logup_read - q_logup_table * w_o) * w_4 = 0.
354 // Linearly dependent, hence no scaling_factor; deg 5.
355 Accumulator logup_sum_contribution = q_logup_read - q_logup_table * Accumulator(w_3_m);
356 logup_sum_contribution *= w_4_acc;
357 logup_sum_contribution *= Accumulator(q_memory_m);
358 std::get<7>(accumulators) += logup_sum_contribution;
359 };
360};
361
362template <typename FF> using MemoryRelation = Relation<MemoryRelationImpl<FF>>;
363} // namespace bb
RAM/ROM memory relation.
static bool skip(const AllEntities &in)
Returns true if the contribution from all subrelations for the provided inputs is identically zero.
static constexpr std::array< size_t, 8 > SUBRELATION_PARTIAL_LENGTHS
static constexpr std::array< bool, 8 > SUBRELATION_LINEARLY_INDEPENDENT
static void accumulate(ContainerOverSubrelations &accumulators, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
A wrapper for Relations to expose methods used by the Sumcheck prover or verifier to add the contribu...
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13