Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
biggroup_goblin.test.cpp
Go to the documentation of this file.
2#include <type_traits>
3
4#include "../biggroup/biggroup.hpp"
7
9
11#include <memory>
12
13using namespace bb;
14
15namespace {
17}
18
19template <typename Curve> class stdlib_biggroup_goblin : public testing::Test {
20 using element_ct = typename Curve::Element;
21 using scalar_ct = typename Curve::ScalarField;
22
23 using fq = typename Curve::BaseFieldNative;
24 using fr = typename Curve::ScalarFieldNative;
25 using g1 = typename Curve::GroupNative;
27 using element = typename g1::element;
28
29 using Builder = typename Curve::Builder;
30
31 static constexpr auto EXPECT_CIRCUIT_CORRECTNESS = [](Builder& builder, bool expected_result = true) {
32 info("builder gates = ", builder.get_num_finalized_gates_inefficient());
34 };
35
36 public:
43 {
44 const size_t num_points = 5;
45 const size_t edge_case_points = 3;
47
49 std::vector<fr> scalars;
50 for (size_t i = 0; i < num_points; ++i) {
51 points.push_back(affine_element(element::random_element()));
52 scalars.push_back(fr::random_element());
53 }
54 points.push_back(g1::affine_point_at_infinity);
55 scalars.push_back(fr::random_element());
56 points.push_back(g1::affine_point_at_infinity);
57 scalars.push_back(0);
58 points.push_back(element::random_element());
59 scalars.push_back(0);
60
61 std::vector<element_ct> circuit_points;
62 std::vector<scalar_ct> circuit_scalars;
63 for (size_t i = 0; i < num_points + edge_case_points; ++i) {
64 circuit_points.push_back(element_ct::from_witness(&builder, points[i]));
65 circuit_scalars.push_back(scalar_ct::from_witness(&builder, scalars[i]));
66 }
67
68 element_ct result_point = element_ct::batch_mul(circuit_points, circuit_scalars);
69
70 element expected_point = g1::one;
71 expected_point.self_set_infinity();
72 for (size_t i = 0; i < num_points + edge_case_points; ++i) {
73 expected_point += (element(points[i]) * scalars[i]);
74 }
75
76 expected_point = expected_point.normalize();
77 fq result_x(result_point.x().get_value().lo);
78 fq result_y(result_point.y().get_value().lo);
79
80 EXPECT_EQ(result_x, expected_point.x);
81 EXPECT_EQ(result_y, expected_point.y);
82
84 }
85
87 {
88 const size_t num_points = 5;
90
92 std::vector<fr> scalars;
93 for (size_t i = 0; i < num_points; ++i) {
94 points.push_back(affine_element(element::random_element()));
95 scalars.push_back(fr::random_element());
96 }
97 for (size_t i = 0; i < num_points; ++i) {
98 points.push_back(points[i]);
99 scalars.push_back(-scalars[i]);
100 }
101 std::vector<element_ct> circuit_points;
102 std::vector<scalar_ct> circuit_scalars;
103 for (size_t i = 0; i < num_points * 2; ++i) {
104 circuit_points.push_back(element_ct::from_witness(&builder, points[i]));
105 circuit_scalars.push_back(scalar_ct::from_witness(&builder, scalars[i]));
106 }
107
108 element_ct result_point = element_ct::batch_mul(circuit_points, circuit_scalars);
109
110 EXPECT_EQ(result_point.get_value(), g1::affine_point_at_infinity);
112 }
113
120 {
122
123 for (size_t i = 0; i < 100; ++i) {
124
125 affine_element lhs(element::random_element());
126 affine_element rhs(element::random_element());
127
128 affine_element expected = affine_element(element(lhs) - element(rhs));
129
130 element_ct lhs_ct = element_ct::from_witness(&builder, lhs);
131 element_ct lhs2_ct = element_ct::from_witness(&builder, lhs);
132
133 element_ct rhs_ct = element_ct::from_witness(&builder, rhs);
134 element_ct out_ct = lhs_ct - rhs_ct;
135 EXPECT_EQ(out_ct.get_value(), expected);
136
137 element_ct zero_ct = lhs_ct - lhs_ct;
138 EXPECT_TRUE(zero_ct.get_value().is_point_at_infinity());
139
140 element_ct zero_ct2 = lhs_ct - lhs2_ct;
141 EXPECT_TRUE(zero_ct2.get_value().is_point_at_infinity());
142
143 element_ct out2_ct = element_ct::constant_infinity(&builder) - rhs_ct;
144 EXPECT_EQ(out2_ct.get_value(), -rhs);
145
146 element_ct out3_ct = lhs_ct - element_ct::constant_infinity(&builder);
147 EXPECT_EQ(out3_ct.get_value(), lhs);
148
149 auto lhs_infinity_ct = element_ct::constant_infinity(&builder);
150 auto rhs_infinity_ct = element_ct::constant_infinity(&builder);
151 element_ct out4_ct = lhs_infinity_ct - rhs_infinity_ct;
152 EXPECT_TRUE(out4_ct.get_value().is_point_at_infinity());
153 }
155 }
156
167 {
168 // clang-format off
169 // Boundary scalars k = ceil(m * 2^256 / endo_g2) from endomorphism_scalars.py.
170 // These are the smallest scalars where c1 ticks up, making k2 negative.
171 const std::array<std::array<uint64_t, 4>, 3> boundary_cases = {{
172 {{ 0x01624731e1195570, 0x3ba491482db4da14, 0x59e26bcea0d48bac, 0x0 }}, // m=1
173 {{ 0x02c48e63c232aadf, 0x774922905b69b428, 0xb3c4d79d41a91758, 0x0 }}, // m=2
174 {{ 0x0426d595a34c004e, 0xb2edb3d8891e8e3c, 0x0da7436be27da304, 0x1 }}, // m=3
175 }};
176 // clang-format on
177
178 for (const auto& limbs : boundary_cases) {
179 fr base_scalar(uint256_t{ limbs[0], limbs[1], limbs[2], limbs[3] });
180
181 // The negative-k2 band extends ~2^{123}-2^{126} above each boundary scalar.
182 // A random 122-bit positive perturbation lands inside this band, where the
183 // original (unfixed) k2 is still negative. We therefore test two scalars: the original boundary case and a
184 // 122-bit perturbation.
185 uint256_t rand_bits(fr::random_element());
186 uint256_t offset = rand_bits & ((uint256_t(1) << 122) - 1);
187 std::array<fr, 2> scalars = { base_scalar, base_scalar + fr(offset) };
188
189 // Test via batch_mul
190 for (const auto& scalar : scalars) {
192 element_ct pt = element_ct::from_witness(&builder, affine_element::one());
193 scalar_ct sc = scalar_ct::from_witness(&builder, scalar);
194 element_ct result = element_ct::batch_mul({ pt }, { sc });
195 (void)result;
197 }
198
199 // Test via operator* (delegates to batch_mul)
200 for (const auto& scalar : scalars) {
202 element_ct pt = element_ct::from_witness(&builder, affine_element::one());
203 scalar_ct sc = scalar_ct::from_witness(&builder, scalar);
204 element_ct result = pt * sc;
205 (void)result;
207 }
208 }
209 }
210
215 {
217 affine_element lhs(element::random_element());
218
219 affine_element expected = -lhs;
220
221 element_ct lhs_ct = element_ct::from_witness(&builder, lhs);
222
223 element_ct result_ct = -lhs_ct;
224 EXPECT_EQ(result_ct.get_value(), expected);
225
226 element_ct infinity = element_ct::constant_infinity(&builder);
227 element_ct result2_ct = -infinity;
228 EXPECT_EQ(result2_ct.get_value(), g1::affine_point_at_infinity);
230 }
231};
232
233using TestTypes = testing::Types<stdlib::bn254<bb::MegaCircuitBuilder>>;
234
236
238{
239 TestFixture::test_goblin_style_batch_mul();
240}
241
242TYPED_TEST(stdlib_biggroup_goblin, batch_mul_equals_zero)
243{
244 TestFixture::test_goblin_style_batch_mul_to_zero();
245}
246
248{
249 TestFixture::test_goblin_style_sub();
250}
251
253{
254 TestFixture::test_goblin_style_neg();
255}
256
257TYPED_TEST(stdlib_biggroup_goblin, endomorphism_negative_k2_regression)
258{
259 TestFixture::test_endomorphism_negative_k2_regression();
260}
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
typename Group::element Element
Definition grumpkin.hpp:64
BB_INLINE constexpr void self_set_infinity() noexcept
group_elements::affine_element< Fq, Fr, Params > affine_element
Definition group.hpp:42
static constexpr element one
Definition group.hpp:46
group_elements::element< Fq, Fr, Params > element
Definition group.hpp:41
static constexpr affine_element affine_point_at_infinity
Definition group.hpp:49
static void test_goblin_style_neg()
Check goblin-style negate works as intended, including with points at infinity.
static constexpr auto EXPECT_CIRCUIT_CORRECTNESS
static void test_goblin_style_sub()
Test goblin-style sub.
typename Curve::ScalarField scalar_ct
typename Curve::ScalarFieldNative fr
typename Curve::Element element_ct
static void test_goblin_style_batch_mul()
Test goblin-style batch mul.
typename g1::element element
typename g1::affine_element affine_element
static void test_endomorphism_negative_k2_regression()
Regression test: negative-k2 edge-case scalar through the stdlib biggroup path.
typename Curve::GroupNative g1
typename Curve::Builder Builder
static void test_goblin_style_batch_mul_to_zero()
typename Curve::BaseFieldNative fq
#define info(...)
Definition log.hpp:93
AluTraceBuilder builder
Definition alu.test.cpp:124
bool expected_result
numeric::RNG & engine
ssize_t offset
Definition engine.cpp:52
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:217
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TYPED_TEST_SUITE(CommitmentKeyTest, Curves)
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
testing::Types< VKTestParams< UltraFlavor, stdlib::recursion::honk::DefaultIO< UltraCircuitBuilder > >, VKTestParams< UltraFlavor, stdlib::recursion::honk::RollupIO >, VKTestParams< UltraKeccakFlavor, stdlib::recursion::honk::DefaultIO< UltraCircuitBuilder > >, VKTestParams< MegaFlavor, stdlib::recursion::honk::DefaultIO< MegaCircuitBuilder > > > TestTypes
static field random_element(numeric::RNG *engine=nullptr) noexcept