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: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
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 const size_t num_precompute_rows = num_rows_per_scalar * ecc_muls.size() + 1;
58 std::vector<PointTablePrecomputationRow> precompute_state(num_precompute_rows);
59
60 // start with empty row (shiftable polynomials must have 0 as first coefficient)
61 precompute_state[0] = PointTablePrecomputationRow{};
62
63 // current impl doesn't work if not 4
64 static_assert(WNAF_DIGITS_PER_ROW == 4);
65
66 parallel_for_range(ecc_muls.size(), [&](size_t start, size_t end) {
67 for (size_t j = start; j < end; j++) {
68 const auto& entry = ecc_muls[j];
69 const auto& slices = entry.wnaf_digits;
70 uint256_t scalar_sum = 0;
71
72 for (size_t i = 0; i < num_rows_per_scalar; ++i) {
73 PointTablePrecomputationRow row;
74 const int slice0 = slices[i * WNAF_DIGITS_PER_ROW];
75 const int slice1 = slices[i * WNAF_DIGITS_PER_ROW + 1];
76 const int slice2 = slices[i * WNAF_DIGITS_PER_ROW + 2];
77 const int slice3 = slices[i * WNAF_DIGITS_PER_ROW + 3];
78
79 // {-15, -13. ..., 13, 15} --> {0, 1, ..., 15}
80 const int slice0base2 = (slice0 + 15) / 2;
81 const int slice1base2 = (slice1 + 15) / 2;
82 const int slice2base2 = (slice2 + 15) / 2;
83 const int slice3base2 = (slice3 + 15) / 2;
84
85 // convert into 2-bit chunks
86 row.s1 = slice0base2 >> 2;
87 row.s2 = slice0base2 & 3;
88 row.s3 = slice1base2 >> 2;
89 row.s4 = slice1base2 & 3;
90 row.s5 = slice2base2 >> 2;
91 row.s6 = slice2base2 & 3;
92 row.s7 = slice3base2 >> 2;
93 row.s8 = slice3base2 & 3;
94 bool last_row = (i == num_rows_per_scalar - 1);
95
96 row.skew = last_row ? entry.wnaf_skew : false;
97
98 row.scalar_sum = scalar_sum;
99
100 // N.B. we apply a constraint that requires slice1 to be positive for the 1st row of each scalar
101 // sum. This ensures we do not have WNAF representations of negative values
102 const int row_chunk = slice3 + slice2 * (1 << 4) + slice1 * (1 << 8) + slice0 * (1 << 12);
103
104 bool chunk_negative = row_chunk < 0;
105
106 scalar_sum = scalar_sum << (NUM_WNAF_DIGIT_BITS * WNAF_DIGITS_PER_ROW);
107 if (chunk_negative) {
108 scalar_sum -= static_cast<uint64_t>(-row_chunk);
109 } else {
110 scalar_sum += static_cast<uint64_t>(row_chunk);
111 }
112 row.round = static_cast<uint32_t>(i);
113 row.point_transition = last_row;
114 row.pc = entry.pc;
115
116 if (last_row) {
117 ASSERT(scalar_sum - entry.wnaf_skew, entry.scalar);
118 }
119 // the last element of the `precomputed_table` field of a `ScalarMul` is the double of the point.
120 row.precompute_double = entry.precomputed_table[bb::eccvm::POINT_TABLE_SIZE];
121 // fill accumulator in reverse order i.e. first row = 15[P], then 13[P], ..., 1[P]
122 // note that this reflects a coincidence: the number of rows (per scalar multiplication) is
123 // the number of multiples that we need to precompute. Indeed, the latter is 2ʷ⁻¹, while the former
124 // depends both on w and on `NUM_SCALAR_BITS`.
125 row.precompute_accumulator = entry.precomputed_table[bb::eccvm::POINT_TABLE_SIZE - 1 - i];
126 precompute_state[j * num_rows_per_scalar + i + 1] = (row);
127 }
128 }
129 });
130 return precompute_state;
131 }
132};
133} // 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:36
group_elements::affine_element< Fq, Fr, Params > affine_element
Definition group.hpp:42
group_elements::element< Fq, Fr, Params > element
Definition group.hpp:41
Entry point for Barretenberg command-line interface.
group< fq, fr, Bn254G1Params > g1
Definition g1.hpp:33
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:102
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13