Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
precomputed_tables_builder.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Raju], commit: 2a49eb6 }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
8
11
12namespace bb {
13
15 public:
18 using Element = typename CycleGroup::element;
20
21 static constexpr size_t NUM_WNAF_DIGITS_PER_SCALAR = bb::eccvm::NUM_WNAF_DIGITS_PER_SCALAR;
22 static constexpr size_t WNAF_DIGITS_PER_ROW = bb::eccvm::WNAF_DIGITS_PER_ROW;
23 static constexpr size_t NUM_WNAF_DIGIT_BITS = bb::eccvm::NUM_WNAF_DIGIT_BITS;
24 // Note that our implementation takes advantage of a numerical coincidence:
25 // `NUM_WNAF_DIGITS_PER_SCALAR`/`WNAF_DIGITS_PER_ROW`, the number of rows per scalar multiplication, is the same as
26 // |{P, 3P, ..., (2ʷ-1)P}| = 2ʷ⁻¹ == 8, which is basically the number of multiples of P we need to precompute. (To
27 // be precise, we also compute 2P, but this occurs on every row.)
29 // s1, ..., s8 are each 2 bits, so they jointly encode 16 bits of information, which corresponds precisely to
30 // the data of 4 wNAF digits. they are ordered from "highest order" to "lowest order". this means that s1s2
31 // encodes the first (highest order) wNAF digit in consideration, and so on. the explicit encoding is: the
32 // concatenation, s_{2i}s_{2i+1}, is naturally a number in {0, 1, ..., 15}; to obtain the corresponding wNAF
33 // digit, multiply by 2 and subtract 15.
34 int s1 = 0;
35 int s2 = 0;
36 int s3 = 0;
37 int s4 = 0;
38 int s5 = 0;
39 int s6 = 0;
40 int s7 = 0;
41 int s8 = 0;
42 bool skew = false;
43 bool point_transition = false;
44 uint32_t pc = 0;
45 uint32_t round = 0;
48 0, 0
49 }; // contains a precomputed element, i.e., something in {P, 3P, ..., 15P}.
51 };
52
54 const std::vector<bb::eccvm::ScalarMul<CycleGroup>>& ecc_muls)
55 {
56 static constexpr size_t num_rows_per_scalar = NUM_WNAF_DIGITS_PER_SCALAR / WNAF_DIGITS_PER_ROW;
57 static_assert(num_rows_per_scalar == bb::eccvm::POINT_TABLE_SIZE / 2,
58 "precompute_accumulator fill loop assumes num_rows_per_scalar == POINT_TABLE_SIZE / 2");
59 const size_t num_precompute_rows = num_rows_per_scalar * ecc_muls.size() + 1;
60 std::vector<PointTablePrecomputationRow> precompute_state(num_precompute_rows);
61
62 // start with empty row (shiftable polynomials must have 0 as first coefficient)
63 precompute_state[0] = PointTablePrecomputationRow{};
64
65 // current impl doesn't work if not 4
66 static_assert(WNAF_DIGITS_PER_ROW == 4);
67
68 parallel_for_range(ecc_muls.size(), [&](size_t start, size_t end) {
69 for (size_t j = start; j < end; j++) {
70 const auto& entry = ecc_muls[j];
71 const auto& slices = entry.wnaf_digits;
72 uint256_t scalar_sum = 0;
73
74 for (size_t i = 0; i < num_rows_per_scalar; ++i) {
75 PointTablePrecomputationRow row;
76 const int slice0 = slices[i * WNAF_DIGITS_PER_ROW];
77 const int slice1 = slices[i * WNAF_DIGITS_PER_ROW + 1];
78 const int slice2 = slices[i * WNAF_DIGITS_PER_ROW + 2];
79 const int slice3 = slices[i * WNAF_DIGITS_PER_ROW + 3];
80
81 // {-15, -13. ..., 13, 15} --> {0, 1, ..., 15}
82 const int slice0base2 = (slice0 + 15) / 2;
83 const int slice1base2 = (slice1 + 15) / 2;
84 const int slice2base2 = (slice2 + 15) / 2;
85 const int slice3base2 = (slice3 + 15) / 2;
86
87 // convert into 2-bit chunks
88 row.s1 = slice0base2 >> 2;
89 row.s2 = slice0base2 & 3;
90 row.s3 = slice1base2 >> 2;
91 row.s4 = slice1base2 & 3;
92 row.s5 = slice2base2 >> 2;
93 row.s6 = slice2base2 & 3;
94 row.s7 = slice3base2 >> 2;
95 row.s8 = slice3base2 & 3;
96 bool last_row = (i == num_rows_per_scalar - 1);
97
98 row.skew = last_row ? entry.wnaf_skew : false;
99
100 row.scalar_sum = scalar_sum;
101
102 // N.B. we apply a constraint that requires slice1 to be positive for the 1st row of each scalar
103 // sum. This ensures we do not have WNAF representations of negative values
104 const int row_chunk = slice3 + slice2 * (1 << 4) + slice1 * (1 << 8) + slice0 * (1 << 12);
105
106 bool chunk_negative = row_chunk < 0;
107
108 scalar_sum = scalar_sum << (NUM_WNAF_DIGIT_BITS * WNAF_DIGITS_PER_ROW);
109 if (chunk_negative) {
110 scalar_sum -= static_cast<uint64_t>(-row_chunk);
111 } else {
112 scalar_sum += static_cast<uint64_t>(row_chunk);
113 }
114 row.round = static_cast<uint32_t>(i);
115 row.point_transition = last_row;
116 row.pc = entry.pc;
117
118 if (last_row) {
119 BB_ASSERT_EQ(scalar_sum - entry.wnaf_skew, entry.scalar);
120 }
121 // the last element of the `precomputed_table` field of a `ScalarMul` is the double of the point.
122 row.precompute_double = entry.precomputed_table[bb::eccvm::POINT_TABLE_SIZE];
123 // fill accumulator in reverse order i.e. first row = 15[P], then 13[P], ..., 1[P]
124 // note that this reflects a coincidence: the number of rows (per scalar multiplication) is
125 // the number of multiples that we need to precompute. Indeed, the latter is 2ʷ⁻¹, while the former
126 // depends both on w and on `NUM_SCALAR_BITS`.
127 row.precompute_accumulator = entry.precomputed_table[bb::eccvm::POINT_TABLE_SIZE - 1 - i];
128 precompute_state[j * num_rows_per_scalar + i + 1] = (row);
129 }
130 }
131 });
132 return precompute_state;
133 }
134};
135} // namespace bb
static std::vector< PointTablePrecomputationRow > compute_rows(const std::vector< bb::eccvm::ScalarMul< CycleGroup > > &ecc_muls)
typename CycleGroup::affine_element AffineElement
group class. Represents an elliptic curve group element. Group is parametrised by Fq and Fr
Definition group.hpp:38
group_elements::affine_element< Fq, Fr, Params > affine_element
Definition group.hpp:44
group_elements::element< Fq, Fr, Params > element
Definition group.hpp:43
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
group< fq, fr, Bn254G1Params > g1
Definition g1.hpp:34
void parallel_for_range(size_t num_points, const std::function< void(size_t, size_t)> &func, size_t no_multhreading_if_less_or_equal)
Split a loop into several loops running in parallel.
Definition thread.cpp:141
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13