Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
biggroup_edgecase_handling.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Suyash], commit: 553c5eb82901955c638b943065acd3e47fc918c0}
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
13
15
25template <typename C, class Fq, class Fr, class G>
27{
28 constexpr typename G::affine_element offset_generator =
29 get_precomputed_generators<G, "biggroup table offset generator", 1>()[0];
30
31 return offset_generator;
32}
33
43template <typename C, class Fq, class Fr, class G>
45 const std::vector<element>& _points, const std::vector<Fr>& _scalars, const Fr& masking_scalar)
46{
48 std::vector<Fr> scalars;
49 BB_ASSERT_EQ(_points.size(), _scalars.size());
50
51 BB_ASSERT_LTE(uint256_t(masking_scalar.get_value()).get_msb() + 1ULL,
52 128ULL,
53 "biggroup mask_points: masking_scalar must ≤ 128 bits");
54
55 // Get the offset generator G_offset in native and in-circuit form
56 const typename G::affine_element native_offset_generator = element::compute_table_offset_generator();
57 C* builder = validate_context<C>(validate_context<C>(_points), validate_context<C>(_scalars));
58 const element offset_generator_element = element::from_witness(builder, native_offset_generator);
59 auto empty_tag = OriginTag::constant(); // Disable origin checking during intermediate operations
60 offset_generator_element.set_origin_tag(empty_tag);
61
62 // Compute initial point to be added: (δ)⋅G_offset
63 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1585): do we really need to multiply by δ here?
64 element running_point = offset_generator_element.scalar_mul(masking_scalar, 128);
65
66 // Start the running scalar at 1
67 Fr running_scalar = Fr(1);
68 Fr last_scalar = Fr(0);
69
70 // For each point and scalar
71 for (size_t i = 0; i < _points.size(); i++) {
72 scalars.push_back(_scalars[i]);
73
74 // Convert point into point + (2ⁱ)⋅(δG_offset)
75 points.push_back(_points[i].add_internal(running_point));
76
77 // Add 2ⁱ⋅scalar_i to the last scalar
78 last_scalar += _scalars[i] * running_scalar;
79
80 // Double the running scalar and point for next iteration
81 running_scalar += running_scalar;
82 running_point = running_point.dbl_internal();
83 }
84
85 // Add a scalar -(<δ(1, 2, 2²,...,2ⁿ⁻¹),(scalar₀,...,scalarₙ₋₁)> / 2ⁿ)
86 const uint32_t n = static_cast<uint32_t>(_points.size());
87 const Fr two_power_n = Fr(2).pow(n);
88 const Fr two_power_n_inverse = two_power_n.invert();
89 last_scalar *= two_power_n_inverse;
90 scalars.push_back(-last_scalar);
91 if constexpr (Fr::is_composite) {
92 scalars.back().self_reduce();
93 }
94 // Add in-circuit 2ⁿ.(δ.G_offset) to points
95 points.push_back(running_point);
96
97 return { points, scalars };
98}
99
104template <typename C, class Fq, class Fr, class G>
106 const std::vector<element>& _points, const std::vector<Fr>& _scalars)
107{
108 C* builder = validate_context<C>(validate_context<C>(_points), validate_context<C>(_scalars));
110 std::vector<Fr> scalars;
111 element one = element::one(builder);
112
113 for (auto [_point, _scalar] : zip_view(_points, _scalars)) {
114 bool_ct is_point_at_infinity = _point.is_point_at_infinity();
115 if (is_point_at_infinity.get_value() && static_cast<bool>(is_point_at_infinity.is_constant())) {
116 // if point is at infinity and a circuit constant we can just skip.
117 continue;
118 }
119 if (_scalar.get_value() == 0 && _scalar.is_constant()) {
120 // if scalar multiplier is 0 and also a constant, we can skip
121 continue;
122 }
123
124 // Select either the point at infinity or the fixed generator
125 element point = _point.conditional_select(one, is_point_at_infinity);
126
127 Fr scalar;
128 if constexpr (!Fr::is_composite) {
129 // For field_t (non-composite), use internal version to avoid premature normalization
130 scalar = Fr::conditional_assign_internal(is_point_at_infinity, 0, _scalar);
131 } else {
132 // For bigfield (composite), conditional_assign doesn't normalize anyway
133 scalar = Fr::conditional_assign(is_point_at_infinity, 0, _scalar);
134 }
135
136 // Push the selected point and scalar to their respective vectors
137 points.push_back(point);
138 scalars.push_back(scalar);
139 }
140
141 return { points, scalars };
142}
143} // namespace bb::stdlib::element_default
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:158
constexpr uint64_t get_msb() const
Implements boolean logic in-circuit.
Definition bool.hpp:60
bool get_value() const
Definition bool.hpp:125
bool is_constant() const
Definition bool.hpp:127
void set_origin_tag(OriginTag tag) const
Definition biggroup.hpp:409
element dbl_internal() const
Internal implementation of point doubling.
element scalar_mul(const Fr &scalar, const size_t max_num_bits=0) const
Implements scalar multiplication that supports short scalars. For multiple scalar multiplication use ...
element conditional_select(const element &other, const bool_ct &predicate) const
Selects this if predicate is false, other if predicate is true.
Definition biggroup.hpp:237
AluTraceBuilder builder
Definition alu.test.cpp:124
#define G(r, i, a, b, c, d)
Definition blake2s.cpp:116
constexpr std::span< const typename Group::affine_element > get_precomputed_generators()
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::ScalarField Fr
static OriginTag constant()
BB_INLINE constexpr field pow(const uint256_t &exponent) const noexcept
constexpr field invert() const noexcept