Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
sparse_masking_poly.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <algorithm>
7#include <cstddef>
8#include <unordered_set>
9#include <vector>
10
11namespace bb {
12
13// Tail-halving support {E-1, E-2, N/2, N/2-1, N/4, N/4-1, ..., 2, 1}, de-duplicated
14// and tail-filled to min(2d, N) distinct entries (N = 2^d, E = round_up(extent, 2)).
15// See SHPLEMINI_ZK_MASKING.md for the rank argument.
16inline std::vector<size_t> tail_halving_support(size_t d, size_t extent)
17{
18 const size_t n = size_t{ 1 } << d;
19 BB_ASSERT_GT(extent, 0U);
20 BB_ASSERT_LTE(extent, n);
21 const size_t E = std::min(n, ((extent % 2) == 0) ? extent : extent + 1);
22 const size_t target = std::min(2 * d, n);
23
24 std::unordered_set<size_t> seen;
25 std::vector<size_t> support;
26 support.reserve(target);
27 const auto add = [&](size_t i) {
28 if (i < n && seen.insert(i).second) {
29 support.push_back(i);
30 }
31 };
32
33 // `add` de-dups. The only collision is when the top-pair entry E-2 lands on the
34 // level-1 anchor N/2, dropping one index; the tail-fill below then restores the
35 // support to the 2d distinct points the rank argument needs.
36 if (E >= 2) {
37 add(E - 1);
38 add(E - 2);
39 }
40 for (size_t level = 1; level < d; ++level) {
41 const size_t base = n >> level;
42 add(base);
43 add(base - 1);
44 }
45 for (size_t i = E - 1; support.size() < target; --i) {
46 add(i);
47 if (i == 0) {
48 break;
49 }
50 }
51 return support;
52}
53
54// 2d random scalars on the tail-halving support, zero elsewhere, virtual size dyadic_size.
55template <typename FF> Polynomial<FF> build_sparse_masking_poly(size_t d, size_t extent, size_t dyadic_size)
56{
57 BB_ASSERT_EQ(dyadic_size, size_t{ 1 } << d);
58 const auto support = tail_halving_support(d, extent);
59 BB_ASSERT_GT(support.size(), 0U);
60
61 const size_t length = *std::ranges::max_element(support) + 1;
62 Polynomial<FF> poly(length, dyadic_size, /*start_index=*/0);
63 for (size_t s : support) {
64 poly.at(s) = FF::random_element();
65 }
66 return poly;
67}
68
69// Below this log size the sparse rank argument does not apply (2d < N fails), so a
70// dense random mask is used instead: unconditionally hiding and cheap at these sizes.
71inline constexpr size_t SPARSE_MASKING_MIN_LOG_N = 4;
72
73template <typename FF> Polynomial<FF> build_gemini_masking_poly(size_t d, size_t extent, size_t dyadic_size)
74{
76 return Polynomial<FF>::random(extent, dyadic_size, /*start_index=*/0);
77 }
78 return build_sparse_masking_poly<FF>(d, extent, dyadic_size);
79}
80
81} // namespace bb
#define BB_ASSERT_GT(left, right,...)
Definition assert.hpp:113
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:158
static Polynomial random(size_t size, size_t start_index=0)
Fr & at(size_t index)
Our mutable accessor, unlike operator[]. We abuse precedent a bit to differentiate at() and operator[...
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
Polynomial< FF > build_gemini_masking_poly(size_t d, size_t extent, size_t dyadic_size)
constexpr size_t SPARSE_MASKING_MIN_LOG_N
std::vector< size_t > tail_halving_support(size_t d, size_t extent)
Polynomial< FF > build_sparse_masking_poly(size_t d, size_t extent, size_t dyadic_size)
std::vector< Instruction > target
static field random_element(numeric::RNG *engine=nullptr) noexcept