Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
wnaf.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
9#include <cstdint>
10
11// NOLINTBEGIN(readability-implicit-bool-conversion)
12
38namespace bb::wnaf {
39constexpr size_t SCALAR_BITS = 127;
40
41#define WNAF_SIZE(x) ((bb::wnaf::SCALAR_BITS + (x) - 1) / (x)) // NOLINT(cppcoreguidelines-macro-usage)
42
59template <size_t bits, size_t bit_position> inline uint64_t get_wnaf_bits_const(const uint64_t* scalar) noexcept
60{
61 if constexpr (bits == 0) {
62 return 0ULL;
63 } else {
64 constexpr size_t lo_limb_idx = bit_position / 64;
65 constexpr size_t hi_limb_idx = (bit_position + bits - 1) / 64;
66 constexpr uint64_t lo_shift = bit_position & 63UL;
67 constexpr uint64_t bit_mask = (1UL << static_cast<uint64_t>(bits)) - 1UL;
68
69 uint64_t lo = (scalar[lo_limb_idx] >> lo_shift);
70 if constexpr (lo_limb_idx == hi_limb_idx) {
71 return lo & bit_mask;
72 } else {
73 constexpr uint64_t hi_shift = 64UL - (bit_position & 63UL);
74 uint64_t hi = ((scalar[hi_limb_idx] << (hi_shift)));
75 return (lo | hi) & bit_mask;
76 }
77 }
78}
79
88inline uint64_t get_wnaf_bits(const uint64_t* scalar, const uint64_t bits, const uint64_t bit_position) noexcept
89{
90
91 const auto lo_limb_idx = static_cast<size_t>(bit_position >> 6);
92 const auto hi_limb_idx = static_cast<size_t>((bit_position + bits - 1) >> 6);
93 const uint64_t lo_shift = bit_position & 63UL;
94 const uint64_t bit_mask = (1UL << static_cast<uint64_t>(bits)) - 1UL;
95
96 const uint64_t lo = (scalar[lo_limb_idx] >> lo_shift);
97 const uint64_t hi_shift = bit_position ? 64UL - (bit_position & 63UL) : 0;
98 const uint64_t hi = ((scalar[hi_limb_idx] << (hi_shift)));
99 const uint64_t hi_mask = bit_mask & (0ULL - (lo_limb_idx != hi_limb_idx));
100
101 return (lo & bit_mask) | (hi & hi_mask);
102}
103
117inline void fixed_wnaf(const uint64_t* scalar,
118 uint64_t* wnaf,
119 bool& skew_map,
120 const uint64_t point_index,
121 const uint64_t num_points,
122 const size_t wnaf_bits) noexcept
123{
124 // If the scalar is even, we set the skew map to true. The skew is used to subtract a base point from the msm result
125 // in case scalar is even.
126 skew_map = ((scalar[0] & 1) == 0);
127 // The first slice is the least significant slice of the scalar.
128 uint64_t previous = get_wnaf_bits(scalar, wnaf_bits, 0) + static_cast<uint64_t>(skew_map);
129 const size_t wnaf_entries = (SCALAR_BITS + wnaf_bits - 1) / wnaf_bits;
130
131 // For the rest we start a rolling window of wnaf_bits bits, and compute the wnaf slice.
132 for (size_t round_i = 1; round_i < wnaf_entries - 1; ++round_i) {
133 uint64_t slice = get_wnaf_bits(scalar, wnaf_bits, round_i * wnaf_bits);
134 // Check if the slice is even. This will be used to borrow from the previous slice.
135 uint64_t predicate = ((slice & 1UL) == 0UL);
136 // If the current slice is odd (predicate=0), the WNAF digit is simply `previous`.
137 // If even (predicate=1), we borrow: subtract 2^wnaf_bits from `previous` to get a
138 // negative value, then negate via XOR with all-ones (two's complement identity:
139 // -x = ~x + 1, but we immediately shift right by 1, absorbing the +1 since the
140 // result is guaranteed odd). The >> 1 converts from the raw odd value to a bucket
141 // index (e.g., value 5 → bucket 2, value 7 → bucket 3). Bit 31 stores the sign
142 // (1 = negative), and the upper bits carry point_index for multi-scalar indexing.
143 wnaf[(wnaf_entries - round_i) * num_points] =
144 ((((previous - (predicate << wnaf_bits)) ^ (0UL - predicate)) >> 1UL) | (predicate << 31UL)) |
145 (point_index);
146 // Carry the borrow into the next window: if we borrowed, add 1 to the current slice.
147 previous = slice + predicate;
148 }
149 size_t final_bits = SCALAR_BITS - (wnaf_bits * (wnaf_entries - 1));
150 uint64_t slice = get_wnaf_bits(scalar, final_bits, (wnaf_entries - 1) * wnaf_bits);
151 uint64_t predicate = ((slice & 1UL) == 0UL);
152
153 wnaf[num_points] =
154 ((((previous - (predicate << (wnaf_bits))) ^ (0UL - predicate)) >> 1UL) | (predicate << 31UL)) | (point_index);
155 wnaf[0] = ((slice + predicate) >> 1UL) | (point_index);
156}
157
167template <size_t num_points, size_t wnaf_bits, size_t round_i>
168inline void wnaf_round(uint64_t* scalar, uint64_t* wnaf, const uint64_t point_index, const uint64_t previous) noexcept
169{
170 constexpr size_t wnaf_entries = (SCALAR_BITS + wnaf_bits - 1) / wnaf_bits;
171 constexpr auto log2_num_points = static_cast<size_t>(numeric::get_msb(static_cast<uint32_t>(num_points)));
172
173 if constexpr (round_i < wnaf_entries - 1) {
174 uint64_t slice = get_wnaf_bits(scalar, wnaf_bits, round_i * wnaf_bits);
175 uint64_t predicate = ((slice & 1UL) == 0UL);
176 wnaf[(wnaf_entries - round_i) << log2_num_points] =
177 ((((previous - (predicate << wnaf_bits)) ^ (0UL - predicate)) >> 1UL) | (predicate << 31UL)) |
178 (point_index << 32UL);
179 wnaf_round<num_points, wnaf_bits, round_i + 1>(scalar, wnaf, point_index, slice + predicate);
180 } else {
181 constexpr size_t final_bits = SCALAR_BITS - (SCALAR_BITS / wnaf_bits) * wnaf_bits;
182 uint64_t slice = get_wnaf_bits(scalar, final_bits, (wnaf_entries - 1) * wnaf_bits);
183 uint64_t predicate = ((slice & 1UL) == 0UL);
184 wnaf[num_points] =
185 ((((previous - (predicate << wnaf_bits)) ^ (0UL - predicate)) >> 1UL) | (predicate << 31UL)) |
186 (point_index << 32UL);
187 wnaf[0] = ((slice + predicate) >> 1UL) | (point_index << 32UL);
188 }
189}
190
200template <size_t scalar_bits, size_t num_points, size_t wnaf_bits, size_t round_i>
201inline void wnaf_round(uint64_t* scalar, uint64_t* wnaf, const uint64_t point_index, const uint64_t previous) noexcept
202{
203 constexpr size_t wnaf_entries = (scalar_bits + wnaf_bits - 1) / wnaf_bits;
204 constexpr auto log2_num_points = static_cast<uint64_t>(numeric::get_msb(static_cast<uint32_t>(num_points)));
205
206 if constexpr (round_i < wnaf_entries - 1) {
207 uint64_t slice = get_wnaf_bits_const<wnaf_bits, round_i * wnaf_bits>(scalar);
208 uint64_t predicate = ((slice & 1UL) == 0UL);
209 wnaf[(wnaf_entries - round_i) << log2_num_points] =
210 ((((previous - (predicate << wnaf_bits)) ^ (0UL - predicate)) >> 1UL) | (predicate << 31UL)) |
211 (point_index << 32UL);
212 wnaf_round<scalar_bits, num_points, wnaf_bits, round_i + 1>(scalar, wnaf, point_index, slice + predicate);
213 } else {
214 constexpr size_t final_bits = ((scalar_bits / wnaf_bits) * wnaf_bits == scalar_bits)
215 ? wnaf_bits
216 : scalar_bits - (scalar_bits / wnaf_bits) * wnaf_bits;
217 uint64_t slice = get_wnaf_bits_const<final_bits, (wnaf_entries - 1) * wnaf_bits>(scalar);
218 uint64_t predicate = ((slice & 1UL) == 0UL);
219 wnaf[num_points] =
220 ((((previous - (predicate << wnaf_bits)) ^ (0UL - predicate)) >> 1UL) | (predicate << 31UL)) |
221 (point_index << 32UL);
222 wnaf[0] = ((slice + predicate) >> 1UL) | (point_index << 32UL);
223 }
224}
225
226template <size_t num_points, size_t wnaf_bits>
227inline void fixed_wnaf(uint64_t* scalar, uint64_t* wnaf, bool& skew_map, const size_t point_index) noexcept
228{
229 skew_map = ((scalar[0] & 1) == 0);
230 uint64_t previous = get_wnaf_bits_const<wnaf_bits, 0>(scalar) + static_cast<uint64_t>(skew_map);
231 wnaf_round<num_points, wnaf_bits, 1UL>(scalar, wnaf, point_index, previous);
232}
233
234template <size_t num_bits, size_t num_points, size_t wnaf_bits>
235inline void fixed_wnaf(uint64_t* scalar, uint64_t* wnaf, bool& skew_map, const size_t point_index) noexcept
236{
237 skew_map = ((scalar[0] & 1) == 0);
238 uint64_t previous = get_wnaf_bits_const<wnaf_bits, 0>(scalar) + static_cast<uint64_t>(skew_map);
239 wnaf_round<num_bits, num_points, wnaf_bits, 1UL>(scalar, wnaf, point_index, previous);
240}
241
242} // namespace bb::wnaf
243
244// NOLINTEND(readability-implicit-bool-conversion)
constexpr T get_msb(const T in)
Definition get_msb.hpp:49
Fixed-window non-adjacent form (WNAF) scalar decomposition for elliptic curve scalar multiplication.
Definition wnaf.hpp:38
void fixed_wnaf(const uint64_t *scalar, uint64_t *wnaf, bool &skew_map, const uint64_t point_index, const uint64_t num_points, const size_t wnaf_bits) noexcept
Performs fixed-window non-adjacent form (WNAF) computation for scalar multiplication.
Definition wnaf.hpp:117
constexpr size_t SCALAR_BITS
Definition wnaf.hpp:39
uint64_t get_wnaf_bits_const(const uint64_t *scalar) noexcept
Extract a window of bits consecutive bits starting at bit_position from a 128-bit scalar.
Definition wnaf.hpp:59
void wnaf_round(uint64_t *scalar, uint64_t *wnaf, const uint64_t point_index, const uint64_t previous) noexcept
Recursive WNAF round for a fixed 127-bit scalar (SCALAR_BITS).
Definition wnaf.hpp:168
uint64_t get_wnaf_bits(const uint64_t *scalar, const uint64_t bits, const uint64_t bit_position) noexcept
A variant of the previous function that the bit position and number of bits are provided at runtime.
Definition wnaf.hpp:88
C slice(C const &container, size_t start)
Definition container.hpp:9