Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
crs_factory.test.cpp
Go to the documentation of this file.
13#include "http_download.hpp"
14#include <gtest/gtest.h>
15#include <span>
16#include <utility>
17
18using namespace bb;
19using namespace bb::srs::factories;
20using namespace bb::curve;
21namespace fs = std::filesystem;
22
23namespace {
24// BN254 consistency checker
25void check_bn254_consistency(const fs::path& crs_download_path, size_t num_points, bool allow_download)
26{
27 NativeBn254CrsFactory file_crs(crs_download_path, allow_download);
28
29 // Use get_bn254_g1_data to load reference points (handles compressed/uncompressed automatically)
30 auto g1_points = bb::get_bn254_g1_data(bb::srs::bb_crs_path(), num_points, /*allow_download=*/false);
31
32 // read and verify G2 (SHA-256-pinned + subgroup-checked)
34
35 // build in-memory CRS
36 MemBn254CrsFactory mem_crs(g1_points, g2_point);
37
38 // prover CRS
39 auto f_prover = file_crs.get_crs(num_points);
40 auto m_prover = mem_crs.get_crs(num_points);
41 EXPECT_EQ(m_prover->get_monomial_size(), f_prover->get_monomial_size());
42 for (size_t i = 0; i < num_points; ++i) {
43 EXPECT_EQ(std::make_pair(i, m_prover->get_monomial_points()[i]),
44 std::make_pair(i, f_prover->get_monomial_points()[i]));
45 }
46 // verifier CRS
47 auto f_ver = file_crs.get_verifier_crs();
48 auto m_ver = mem_crs.get_verifier_crs();
49 EXPECT_EQ(m_ver->get_g2x(), f_ver->get_g2x());
50 EXPECT_EQ(0,
51 memcmp(m_ver->get_precomputed_g2_lines(),
52 f_ver->get_precomputed_g2_lines(),
53 sizeof(pairing::miller_lines) * 2));
54}
55
56// Grumpkin consistency checker
57void check_grumpkin_consistency(const fs::path& crs_download_path, size_t num_points, bool allow_download)
58{
59 NativeGrumpkinCrsFactory file_crs(crs_download_path, allow_download);
60
61 // read G1
62 std::vector<Grumpkin::AffineElement> points(num_points);
63 auto data =
64 read_file(bb::srs::bb_crs_path() / "grumpkin_g1_v2.flat.dat", num_points * sizeof(Grumpkin::AffineElement));
65
66 for (size_t i = 0; i < num_points; ++i) {
67 points[i] = from_buffer<Grumpkin::AffineElement>(data, i * sizeof(g1::affine_element));
68 }
69 MemGrumpkinCrsFactory mem_crs(points);
70
71 // prover CRS
72 auto f_prover = file_crs.get_crs(num_points);
73 auto m_prover = mem_crs.get_crs(num_points);
74 EXPECT_EQ(m_prover->get_monomial_size(), f_prover->get_monomial_size());
75 for (size_t i = 0; i < num_points; ++i) {
76 EXPECT_EQ(std::make_pair(i, m_prover->get_monomial_points()[i]),
77 std::make_pair(i, f_prover->get_monomial_points()[i]));
78 }
79}
80} // namespace
81
83{
84 check_bn254_consistency(bb::srs::bb_crs_path(), 1024, /*allow_download=*/false);
85 const std::filesystem::path& temp_crs_path = "barretenberg_srs_test_crs_bn254";
86 fs::remove_all(temp_crs_path);
87 fs::create_directories(temp_crs_path);
88 // Tiny download check to test the 'net CRS' path
89 ASSERT_ANY_THROW(check_bn254_consistency(temp_crs_path, 1, /*allow_download=*/false));
90 check_bn254_consistency(temp_crs_path, 1, /*allow_download=*/true);
91 fs::remove_all(temp_crs_path);
92}
93
94TEST(CrsFactory, grumpkin)
95{
96 check_grumpkin_consistency(bb::srs::bb_crs_path(), 1024, /*allow_download=*/false);
97 const std::filesystem::path& temp_crs_path = "barretenberg_srs_test_crs_grumpkin";
98 fs::remove_all(temp_crs_path);
99 fs::create_directories(temp_crs_path);
100 // Tiny download check to test the 'net CRS' path
101 ASSERT_ANY_THROW(check_grumpkin_consistency(temp_crs_path, 1, /*allow_download=*/false));
102 check_grumpkin_consistency(temp_crs_path, 1, /*allow_download=*/true);
103 fs::remove_all(temp_crs_path);
104}
105
106// TODO: Re-enable once g1_compressed.dat is deployed to S3 fallback
107TEST(CrsFactory, DISABLED_Bn254Fallback)
108{
109 // Test that fallback works when primary URL fails
110 const std::filesystem::path& temp_crs_path = "barretenberg_srs_test_crs_bn254_fallback";
111 fs::remove_all(temp_crs_path);
112 fs::create_directories(temp_crs_path);
113
114 // Use a bad primary URL that will fail, forcing fallback to the real S3 URL
115 std::string bad_primary = "http://nonexistent.invalid/g1_compressed.dat";
116 std::string good_fallback = "http://crs.aztec-labs.com/g1_compressed.dat";
117
118 // This should succeed by falling back to the working URL
119 auto points = bb::get_bn254_g1_data(temp_crs_path, 1, /*allow_download=*/true, bad_primary, good_fallback);
120 EXPECT_EQ(points.size(), 1);
121 // Verify the downloaded point matches the expected first element
122 EXPECT_EQ(points[0], bb::srs::BN254_G1_FIRST_ELEMENT);
123
124 fs::remove_all(temp_crs_path);
125}
126
127// The hardcoded `[x]_2` baked into the BB native binary must be a member of the BN254 G2 prime-order subgroup.
128TEST(CrsFactory, Bn254HardcodedG2IsInPrimeSubgroup)
129{
130 auto g2_point = bb::srs::get_bn254_g2_crs_element();
131 ASSERT_TRUE(g2_point.on_curve());
132 EXPECT_TRUE(g2_point.is_in_prime_subgroup());
133}
134
135// Locks `BN254_G2_ELEMENT_SHA256` to the actual hash of `BN254_G2_ELEMENT_BYTES`. If anyone edits
136// the bytes without recomputing the hash (or vice versa), this fails and forces them to fix it.
137TEST(CrsFactory, Bn254G2HashMatchesPinnedBytes)
138{
139 auto hash = bb::crypto::sha256(
141 EXPECT_EQ(hash, bb::srs::BN254_G2_ELEMENT_SHA256);
142}
143
144// Round-trip: the on-disk `bn254_g2.dat` provisioned by `barretenberg/crs/bootstrap.sh` must
145// match the pinned canonical bytes byte-for-byte and pass subgroup validation. This catches
146// corruption, accidental SRS swaps, or an outdated CDN payload.
147TEST(CrsFactory, Bn254G2DataLoadsAndVerifies)
148{
150 EXPECT_EQ(g2_point, bb::srs::get_bn254_g2_crs_element());
151}
152
153// A tampered `bn254_g2.dat` (corrupted single byte) must be rejected by the SHA-256 check.
154TEST(CrsFactory, Bn254G2CorruptionDetected)
155{
156 const std::filesystem::path temp_path = "barretenberg_srs_test_crs_g2_corruption";
157 fs::remove_all(temp_path);
158 fs::create_directories(temp_path);
159
160 auto corrupted =
161 std::vector<uint8_t>(bb::srs::BN254_G2_ELEMENT_BYTES.begin(), bb::srs::BN254_G2_ELEMENT_BYTES.end());
162 corrupted[64] ^= 0xFF;
163 bb::write_file(temp_path / "bn254_g2.dat", corrupted);
164
165 EXPECT_THROW_OR_ABORT(bb::get_bn254_g2_data(temp_path), "SHA-256 mismatch");
166
167 fs::remove_all(temp_path);
168}
169
170// Check that a `bn254_g2.dat` containing the point at infinity is rejected, even though it is technically on-curve.
171TEST(CrsFactory, Bn254G2InfinityRejected)
172{
173 const std::filesystem::path temp_path = "barretenberg_srs_test_crs_g2_infinity";
174 fs::remove_all(temp_path);
175 fs::create_directories(temp_path);
176
177 std::vector<uint8_t> infinity_bytes(128, 0xFF);
178 bb::write_file(temp_path / "bn254_g2.dat", infinity_bytes);
179
180 EXPECT_THROW_OR_ABORT(bb::get_bn254_g2_data(temp_path), "point at infinity");
181
182 fs::remove_all(temp_path);
183}
184
185TEST(CrsFactory, Bn254CompressedChunkHashFirstChunk)
186{
187 // Download the first chunk of compressed CRS from CDN and verify its hash.
188 // We don't require compressed data on disk; only uncompressed is cached.
190 "http://crs.aztec-cdn.foundation/g1_compressed.dat", 0, bb::srs::SRS_CHUNK_SIZE_BYTES - 1);
191 auto chunk = std::span<const uint8_t>(data.data(), data.size());
192 auto hash = bb::crypto::sha256(chunk);
193 EXPECT_EQ(hash, bb::srs::BN254_G1_CHUNK_HASHES[0]);
194}
195
196TEST(CrsFactory, Bn254CompressedChunkHashCorruptionDetected)
197{
198 // Download compressed data and verify that corruption is detected.
200 "http://crs.aztec-cdn.foundation/g1_compressed.dat", 0, bb::srs::SRS_CHUNK_SIZE_BYTES - 1);
201
202 data[bb::srs::SRS_CHUNK_SIZE_BYTES / 2] ^= 0xFF;
203 auto chunk = std::span<const uint8_t>(data.data(), data.size());
204 auto hash = bb::crypto::sha256(chunk);
205 EXPECT_NE(hash, bb::srs::BN254_G1_CHUNK_HASHES[0]);
206}
207
208// With `BB_VERIFY_CRS=1`, `get_bn254_g1_data` runs the chunk-hash check on cached compressed bytes
209// and rejects a corrupted file that would otherwise be silently decompressed and trusted.
210TEST(CrsFactory, Bn254CacheLoadRejectsCorruptionWhenEnvVarSet)
211{
212 constexpr size_t COMPRESSED_POINT_SIZE = 32;
213 const fs::path temp_path = "barretenberg_srs_test_env_var_corruption";
214 fs::remove_all(temp_path);
215 fs::create_directories(temp_path);
216
217 // Three points: garbage everywhere is fine — the partial-last-chunk SHA-256 check compares
218 // against BN254_G1_CHUNK_HASHES[0] (hash of a real 4MB chunk) and necessarily fails.
219 std::vector<uint8_t> bad_data(3 * COMPRESSED_POINT_SIZE, 0);
220 bb::write_file(temp_path / "bn254_g1_compressed.dat", bad_data);
221
222 setenv("BB_VERIFY_CRS", "1", /*overwrite=*/1);
223 EXPECT_THROW_OR_ABORT(bb::get_bn254_g1_data(temp_path, /*num_points=*/3, /*allow_download=*/false),
224 "CRS integrity check failed");
225 unsetenv("BB_VERIFY_CRS");
226
227 fs::remove_all(temp_path);
228}
#define EXPECT_THROW_OR_ABORT(statement, matcher)
Definition assert.hpp:223
typename Group::affine_element AffineElement
Definition grumpkin.hpp:64
Sha256Hash sha256(const ByteContainer &input)
SHA-256 hash function (FIPS 180-4)
Definition sha256.cpp:150
const size_t num_points
g2::affine_element get_bn254_g2_crs_element()
Reference BN254 G2 element from the trusted setup CRS.
std::vector< uint8_t > http_download(const std::string &url, size_t start_byte=0, size_t end_byte=0)
Download data from a URL with optional Range header support.
std::filesystem::path bb_crs_path()
constexpr std::array< uint8_t, 128 > BN254_G2_ELEMENT_BYTES
Raw 128-byte serialization of the BN254 G2 trusted-setup point [x]_2.
constexpr std::array< uint8_t, 32 > BN254_G2_ELEMENT_SHA256
SHA-256 hash of BN254_G2_ELEMENT_BYTES.
constexpr g1::affine_element BN254_G1_FIRST_ELEMENT
Expected first G1 element from BN254 CRS.
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
std::vector< g1::affine_element > get_bn254_g1_data(const std::filesystem::path &path, size_t num_points, bool allow_download, const std::string &primary_url, const std::string &fallback_url)
std::vector< uint8_t > read_file(const std::string &filename, size_t bytes=0)
Definition file_io.hpp:31
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
g2::affine_element get_bn254_g2_data(const std::filesystem::path &path)
void write_file(const std::string &filename, std::span< const uint8_t > data)
Definition file_io.hpp:101
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::byte * data