2#include "../curves/bn254/fr.hpp"
6#include <gtest/gtest.h>
18void recover_fixed_wnaf(
const uint64_t* wnaf,
bool skew, uint64_t& hi, uint64_t& lo,
size_t wnaf_bits)
20 const size_t wnaf_entries = (127 + wnaf_bits - 1) / wnaf_bits;
21 const uint64_t max_table_index = (1UL << (wnaf_bits - 1)) - 1;
23 for (
size_t i = 0; i < wnaf_entries; ++i) {
24 uint64_t entry = wnaf[i];
25 uint64_t table_index = entry & 0x7fffffffUL;
26 bool sign = ((entry >> 31) & 1) != 0U;
27 uint64_t point_index_bits = entry >> 32;
29 EXPECT_LE(table_index, max_table_index)
30 <<
"entry " << i <<
": table_index " << table_index <<
" exceeds max " << max_table_index;
34 EXPECT_FALSE(sign) <<
"entry 0 (most significant digit) must be positive";
38 EXPECT_EQ(point_index_bits, 0UL) <<
"entry " << i <<
": unexpected non-zero point_index bits";
43 for (
size_t i = 0; i < wnaf_entries; ++i) {
44 uint64_t entry_formatted = wnaf[i];
45 bool negative = ((entry_formatted >> 31) & 1) != 0U;
46 uint64_t digit = ((entry_formatted & 0x7fffffffUL) << 1) + 1;
47 auto shift =
static_cast<uint128_t>(wnaf_bits * (wnaf_entries - 1 - i));
49 scalar -=
static_cast<uint128_t>(digit) << shift;
51 scalar +=
static_cast<uint128_t>(digit) << shift;
55 hi =
static_cast<uint64_t
>(scalar >>
static_cast<uint128_t>(64));
56 lo =
static_cast<uint64_t
>(scalar &
static_cast<uint128_t>(0xffff'ffff'ffff'ffff));
60uint32_t compute_booth_packed_digit_bit_by_bit(
const uint64_t* scalar,
size_t bit_offset,
size_t window_bits)
63 for (
size_t i = 0; i <= window_bits; ++i) {
64 if (bit_offset == 0 && i == 0) {
67 const size_t bit = bit_offset + i - 1;
68 raw |=
static_cast<uint32_t
>((scalar[bit / 64] >> (bit & 63)) & 1ULL) << i;
70 const uint32_t neg = (raw >> window_bits) & uint32_t{ 1 };
71 const uint32_t neg_mask = uint32_t{ 0 } - neg;
72 const uint32_t val_mask = (uint32_t{ 1 } << window_bits) - 1;
73 const uint32_t encode = (raw + 1) >> 1;
74 const uint32_t magnitude = ((encode + neg_mask) ^ neg_mask) & val_mask;
75 return (neg << 31) | magnitude;
79TEST(wnaf, GetWnafBitsConstLimbBoundary)
85 const uint64_t scalar[2] = { 0xA800000000000000ULL, 0x0000000000000015ULL };
89 EXPECT_EQ((wnaf::get_wnaf_bits_const<5, 63>(scalar)), 11ULL);
93 EXPECT_EQ((wnaf::get_wnaf_bits_const<5, 64>(scalar)), 21ULL);
97 EXPECT_EQ((wnaf::get_wnaf_bits_const<5, 65>(scalar)), 10ULL);
100TEST(booth_recode, PackedDigitMatchesReference)
102 const uint64_t scalar[2] = { 0xf0e1d2c3b4a59687ULL, 0x8070605040302010ULL };
104 for (
const size_t window_bits : {
size_t{ 2 },
size_t{ 4 } }) {
105 for (
const size_t bit_offset : {
size_t{ 0 },
116 compute_booth_packed_digit_bit_by_bit(scalar, bit_offset, window_bits))
117 <<
"window_bits=" << window_bits <<
", bit_offset=" << bit_offset;
122TEST(booth_recode, TopWindowClampsHighLimb)
124 const uint64_t scalar[2] = { 0, 1ULL << 63 };
127 EXPECT_EQ(params.lo_limb, 1U);
128 EXPECT_EQ(params.hi_limb, 1U);
129 EXPECT_EQ(params.hi_mask, 0U);
130 EXPECT_TRUE(params.slice_localised_to_one_u64);
134TEST(EndomorphismSplit, SmallScalarFastPathBoundaries)
140 std::pair{
fr{ ~uint64_t{ 0 }, (1ULL << 63) - 1, 0, 0 },
144 for (
const auto& [scalar, expected_k1] : test_cases) {
146 EXPECT_EQ(k1, expected_k1);
151TEST(EndomorphismSplit, BoundaryAtTwoTo127UsesGeneralPath)
153 const fr scalar{ 0, 1ULL << 63, 0, 0 };
158 fr k1_field{ k1[0], k1[1], 0, 0 };
159 fr k2_field{ k2[0], k2[1], 0, 0 };
161 EXPECT_EQ(recovered, scalar);
168 auto test_power_of_two_scalar = [](uint64_t lo, uint64_t hi) {
169 uint64_t
buffer[2] = { lo, hi };
172 wnaf::fixed_wnaf<1, 5>(
buffer, wnaf_out, skew, 0);
174 uint64_t recovered_hi = 0;
175 uint64_t recovered_lo = 0;
176 recover_fixed_wnaf(wnaf_out, skew, recovered_hi, recovered_lo, 5);
177 EXPECT_EQ(lo, recovered_lo);
178 EXPECT_EQ(hi, recovered_hi);
181 test_power_of_two_scalar(2ULL, 0ULL);
182 test_power_of_two_scalar(1ULL << 32, 0ULL);
183 test_power_of_two_scalar(0ULL, 1ULL);
184 test_power_of_two_scalar(0ULL, 1ULL << 62);
189 uint64_t
buffer[2]{ 0, 0 };
192 wnaf::fixed_wnaf<1, 5>(
buffer, wnaf, skew, 0);
193 uint64_t recovered_hi = 0;
194 uint64_t recovered_lo = 0;
195 recover_fixed_wnaf(wnaf, skew, recovered_hi, recovered_lo, 5);
196 EXPECT_EQ(recovered_lo, 0UL);
197 EXPECT_EQ(recovered_hi, 0UL);
198 EXPECT_EQ(
buffer[0], recovered_lo);
199 EXPECT_EQ(
buffer[1], recovered_hi);
208 constexpr uint32_t window = 2;
209 constexpr uint32_t num_bits = 254;
210 constexpr uint32_t num_quads = (num_bits >> 1) + 1;
211 uint64_t wnaf[num_quads] = { 0 };
213 wnaf::fixed_wnaf<256, 1, window>(&input.
data[0], wnaf, skew, 0);
241 for (uint64_t i : wnaf) {
242 int extracted = 2 * (
static_cast<int>(i) & 1) + 1;
243 bool sign = (i >> 31) == 0;
246 recovered +=
uint256_t(
static_cast<uint64_t
>(extracted)) * four_power;
248 recovered -=
uint256_t(
static_cast<uint64_t
>(extracted)) * four_power;
252 recovered -=
static_cast<uint64_t
>(skew);
253 EXPECT_EQ(recovered, input);
262 wnaf::fixed_wnaf<1, 5>(&
buffer.data[0], wnaf, skew, 0);
263 uint64_t recovered_hi = 0;
264 uint64_t recovered_lo = 0;
265 recover_fixed_wnaf(wnaf, skew, recovered_hi, recovered_lo, 5);
266 EXPECT_EQ(
buffer.data[0], recovered_lo);
267 EXPECT_EQ(
buffer.data[1], recovered_hi);
272 uint64_t rand_buffer[2]{ 1, 0 };
275 wnaf::fixed_wnaf<1, 5>(rand_buffer, wnaf, skew, 0);
276 uint64_t recovered_hi = 0;
277 uint64_t recovered_lo = 0;
278 recover_fixed_wnaf(wnaf, skew, recovered_hi, recovered_lo, 5);
279 EXPECT_EQ(rand_buffer[0], recovered_lo);
280 EXPECT_EQ(rand_buffer[1], recovered_hi);
285 uint64_t rand_buffer[2] = { 0, 1 };
288 wnaf::fixed_wnaf<1, 5>(rand_buffer, wnaf, skew, 0);
289 uint64_t recovered_hi = 0;
290 uint64_t recovered_lo = 0;
291 recover_fixed_wnaf(wnaf, skew, recovered_hi, recovered_lo, 5);
292 EXPECT_EQ(rand_buffer[0], recovered_lo);
293 EXPECT_EQ(rand_buffer[1], recovered_hi);
296TEST(wnaf, WnafFixedWithEndoSplit)
299 k.
data[3] &= 0x0fffffffffffffffUL;
306 uint64_t endo_wnaf[
WNAF_SIZE(5)] = { 0 };
308 bool endo_skew =
false;
309 wnaf::fixed_wnaf<1, 5>(&k1.data[0], wnaf, skew, 0);
310 wnaf::fixed_wnaf<1, 5>(&k2.data[0], endo_wnaf, endo_skew, 0);
312 fr k1_recovered{ 0, 0, 0, 0 };
313 fr k2_recovered{ 0, 0, 0, 0 };
315 recover_fixed_wnaf(wnaf, skew, k1_recovered.data[1], k1_recovered.data[0], 5);
316 recover_fixed_wnaf(endo_wnaf, endo_skew, k2_recovered.data[1], k2_recovered.data[0], 5);
320 result = k2_recovered * lambda;
321 result = k1_recovered - result;
323 EXPECT_EQ(result, k);
virtual uint256_t get_random_uint256()=0
std::unique_ptr< uint8_t[]> buffer
BoothSliceParams compute_booth_slice_params(size_t bit_offset, size_t window_bits, size_t num_uint64_limbs) noexcept
uint32_t booth_packed_digit(const uint64_t *s, const BoothSliceParams &sp, size_t window_bits) noexcept
Read a (window_bits+1)-bit window from s[] (uint64 limbs) and apply Constantine's signedWindowEncodin...
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Entry point for Barretenberg command-line interface.
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
unsigned __int128 uint128_t
static constexpr field cube_root_of_unity()
static void split_into_endomorphism_scalars(const field &k, field &k1, field &k2)
Full-width endomorphism decomposition: k ≡ k1 - k2·λ (mod r). Modifies the field elements k1 and k2.
static field random_element(numeric::RNG *engine=nullptr) noexcept