barretenberg
Loading...
Searching...
No Matches
io.hpp
1#pragma once
2#include "../ecc/curves/bn254/bn254.hpp"
3#include "../ecc/curves/grumpkin/grumpkin.hpp"
4#include <concepts>
5#include <cstdint>
6#include <fstream>
7#include <string>
8#include <sys/stat.h>
9
10namespace barretenberg::srs {
38struct Manifest {
39 uint32_t transcript_number;
40 uint32_t total_transcripts;
41 uint32_t total_g1_points;
42 uint32_t total_g2_points;
43 uint32_t num_g1_points;
44 uint32_t num_g2_points;
45 uint32_t start_from;
46};
47
48// Detect whether a curve has a G2AffineElement defined
49template <typename Curve>
50concept HasG2 = requires { typename Curve::G2AffineElement; };
51
52// If Curve has a G2AffineElement type, check whether T is this type.
53template <typename Curve, typename T>
54concept GivingG2AffineElementType = std::same_as<T, typename Curve::G2AffineElement>;
55
56// If Curve has a G2AffineElement type, check whether T is this type.
57template <typename Curve, typename T>
58concept GivingG1AffineElementType = std::same_as<T, typename Curve::AffineElement>;
59
60template <typename Curve> class IO {
61 using Fq = typename Curve::BaseField;
62 using Fr = typename Curve::ScalarField;
63 using Element = typename Curve::Element;
64 using AffineElement = typename Curve::AffineElement;
65
66 static constexpr size_t BLAKE2B_CHECKSUM_LENGTH = 64;
67
68 static size_t get_transcript_size(const Manifest& manifest)
69 {
70 const size_t manifest_size = sizeof(Manifest);
71 const size_t g1_buffer_size = sizeof(Fq) * 2 * manifest.num_g1_points;
72 size_t result = manifest_size + g1_buffer_size + BLAKE2B_CHECKSUM_LENGTH;
73
74 if constexpr (HasG2<Curve>) {
75 const size_t g2_buffer_size = 2 * sizeof(Fq) * 2 * manifest.num_g2_points;
76 info(g2_buffer_size);
77 result += g2_buffer_size;
78 }
79
80 return result;
81 }
82
83 static void read_manifest(std::string const& filename, Manifest& manifest)
84 {
85 std::ifstream file;
86 file.open(filename, std::ifstream::binary);
87 file.read((char*)&manifest, sizeof(Manifest));
88 if (!file) {
89 ptrdiff_t read = file.gcount();
90 throw_or_abort(format("Only read ", read, " bytes from file but expected ", sizeof(Manifest), "."));
91 }
92 file.close();
93
94 manifest.transcript_number = ntohl(manifest.transcript_number);
95 manifest.total_transcripts = ntohl(manifest.total_transcripts);
96 manifest.total_g1_points = ntohl(manifest.total_g1_points);
97 manifest.total_g2_points = ntohl(manifest.total_g2_points);
98 manifest.num_g1_points = ntohl(manifest.num_g1_points);
99 manifest.num_g2_points = ntohl(manifest.num_g2_points);
100 manifest.start_from = ntohl(manifest.start_from);
101 }
102
103 static void write_buffer_to_file(std::string const& filename, char const* buffer, size_t buffer_size)
104 {
105 std::ofstream file;
106 file.open(filename);
107 file.write(&buffer[0], (int)(buffer_size));
108 file.close();
109 }
110
111 static size_t get_file_size(std::string const& filename)
112 {
113 struct stat st;
114 if (stat(filename.c_str(), &st) != 0) {
115 return 0;
116 }
117 return (size_t)st.st_size;
118 }
119
120 static void read_file_into_buffer(
121 char* buffer, size_t& size, std::string const& filename, size_t offset = 0, size_t amount = 0)
122 {
123 size = amount ? amount : get_file_size(filename) - offset;
124
125 std::ifstream file;
126 file.open(filename, std::ifstream::binary);
127 file.seekg((int)offset);
128
129 // Read the desired size, but return the actual size read
130 file.read(buffer, (int)size);
131 if (!file) {
132 ptrdiff_t read = file.gcount();
133 throw_or_abort(format("Only read ", read, " bytes from file but expected ", size, "."));
134 }
135
136 file.close();
137 }
138
139 static std::string get_transcript_path(std::string const& dir, size_t num)
140 {
141 return format(dir, "/monomial/transcript", (num < 10) ? "0" : "", std::to_string(num), ".dat");
142 };
143
144 static bool is_file_exist(std::string const& fileName)
145 {
146 std::ifstream infile(fileName);
147 return infile.good();
148 }
149
150 template <typename AffineElementType>
151 static void write_elements_to_buffer(AffineElementType const* elements, char* buffer, size_t num_elements)
152 {
154 uint64_t temp_x[4];
155 uint64_t temp_y[4];
156 Fq temp_x_g1;
157 Fq temp_y_g1;
158
159 if (is_little_endian()) {
160 for (size_t i = 0; i < num_elements; ++i) {
161 size_t byte_position_1 = sizeof(Fq) * i * 2;
162 size_t byte_position_2 = sizeof(Fq) * (i * 2 + 1);
163
164 temp_x_g1 = elements[i].x.from_montgomery_form();
165 temp_y_g1 = elements[i].y.from_montgomery_form();
166
167 temp_x[0] = __builtin_bswap64(temp_x_g1.data[0]);
168 temp_x[1] = __builtin_bswap64(temp_x_g1.data[1]);
169 temp_x[2] = __builtin_bswap64(temp_x_g1.data[2]);
170 temp_x[3] = __builtin_bswap64(temp_x_g1.data[3]);
171 temp_y[0] = __builtin_bswap64(temp_y_g1.data[0]);
172 temp_y[1] = __builtin_bswap64(temp_y_g1.data[1]);
173 temp_y[2] = __builtin_bswap64(temp_y_g1.data[2]);
174 temp_y[3] = __builtin_bswap64(temp_y_g1.data[3]);
175
176 memcpy((void*)(buffer + byte_position_1), (void*)temp_x, sizeof(Fq));
177 memcpy((void*)(buffer + byte_position_2), (void*)temp_y, sizeof(Fq));
178 }
179 }
181 uint64_t temp_x[8];
182 uint64_t temp_y[8];
183 Fq temp_x_g2_1;
184 Fq temp_x_g2_2;
185 Fq temp_y_g2_1;
186 Fq temp_y_g2_2;
187
188 if (is_little_endian()) {
189 for (size_t i = 0; i < num_elements; ++i) {
190 size_t byte_position_1 = sizeof(Fq) * (4 * i);
191 size_t byte_position_2 = sizeof(Fq) * (4 * i + 2);
192
193 temp_x_g2_1 = elements[i].x.c0.from_montgomery_form();
194 temp_x_g2_2 = elements[i].x.c1.from_montgomery_form();
195 temp_y_g2_1 = elements[i].y.c0.from_montgomery_form();
196 temp_y_g2_2 = elements[i].y.c1.from_montgomery_form();
197
198 temp_x[0] = __builtin_bswap64(temp_x_g2_1.data[0]);
199 temp_x[1] = __builtin_bswap64(temp_x_g2_1.data[1]);
200 temp_x[2] = __builtin_bswap64(temp_x_g2_1.data[2]);
201 temp_x[3] = __builtin_bswap64(temp_x_g2_1.data[3]);
202 temp_x[4] = __builtin_bswap64(temp_x_g2_2.data[0]);
203 temp_x[5] = __builtin_bswap64(temp_x_g2_2.data[1]);
204 temp_x[6] = __builtin_bswap64(temp_x_g2_2.data[2]);
205 temp_x[7] = __builtin_bswap64(temp_x_g2_2.data[3]);
206
207 temp_y[0] = __builtin_bswap64(temp_y_g2_1.data[0]);
208 temp_y[1] = __builtin_bswap64(temp_y_g2_1.data[1]);
209 temp_y[2] = __builtin_bswap64(temp_y_g2_1.data[2]);
210 temp_y[3] = __builtin_bswap64(temp_y_g2_1.data[3]);
211 temp_y[4] = __builtin_bswap64(temp_y_g2_2.data[0]);
212 temp_y[5] = __builtin_bswap64(temp_y_g2_2.data[1]);
213 temp_y[6] = __builtin_bswap64(temp_y_g2_2.data[2]);
214 temp_y[7] = __builtin_bswap64(temp_y_g2_2.data[3]);
215
216 memcpy((void*)(buffer + byte_position_1), (void*)temp_x, 2 * sizeof(Fq));
217 memcpy((void*)(buffer + byte_position_2), (void*)temp_y, 2 * sizeof(Fq));
218 }
219 }
220 }
221 }
222
223 public:
224 template <typename AffineElementType> static void byteswap(AffineElementType* elements, size_t elements_size)
225 {
227 constexpr size_t bytes_per_element = sizeof(AffineElementType);
228 size_t num_elements = elements_size / bytes_per_element;
229
230 if (is_little_endian()) {
231 for (size_t i = 0; i < num_elements; ++i) {
232 elements[i].x.data[0] = __builtin_bswap64(elements[i].x.data[0]);
233 elements[i].x.data[1] = __builtin_bswap64(elements[i].x.data[1]);
234 elements[i].x.data[2] = __builtin_bswap64(elements[i].x.data[2]);
235 elements[i].x.data[3] = __builtin_bswap64(elements[i].x.data[3]);
236 elements[i].y.data[0] = __builtin_bswap64(elements[i].y.data[0]);
237 elements[i].y.data[1] = __builtin_bswap64(elements[i].y.data[1]);
238 elements[i].y.data[2] = __builtin_bswap64(elements[i].y.data[2]);
239 elements[i].y.data[3] = __builtin_bswap64(elements[i].y.data[3]);
240 elements[i].x.self_to_montgomery_form();
241 elements[i].y.self_to_montgomery_form();
242 }
243 }
245 constexpr size_t bytes_per_element = sizeof(AffineElementType);
246 size_t num_elements = elements_size / bytes_per_element;
247
248 if (is_little_endian()) {
249 for (size_t i = 0; i < num_elements; ++i) {
250 elements[i].x.c0.data[0] = __builtin_bswap64(elements[i].x.c0.data[0]);
251 elements[i].x.c0.data[1] = __builtin_bswap64(elements[i].x.c0.data[1]);
252 elements[i].x.c0.data[2] = __builtin_bswap64(elements[i].x.c0.data[2]);
253 elements[i].x.c0.data[3] = __builtin_bswap64(elements[i].x.c0.data[3]);
254 elements[i].y.c0.data[0] = __builtin_bswap64(elements[i].y.c0.data[0]);
255 elements[i].y.c0.data[1] = __builtin_bswap64(elements[i].y.c0.data[1]);
256 elements[i].y.c0.data[2] = __builtin_bswap64(elements[i].y.c0.data[2]);
257 elements[i].y.c0.data[3] = __builtin_bswap64(elements[i].y.c0.data[3]);
258 elements[i].x.c1.data[0] = __builtin_bswap64(elements[i].x.c1.data[0]);
259 elements[i].x.c1.data[1] = __builtin_bswap64(elements[i].x.c1.data[1]);
260 elements[i].x.c1.data[2] = __builtin_bswap64(elements[i].x.c1.data[2]);
261 elements[i].x.c1.data[3] = __builtin_bswap64(elements[i].x.c1.data[3]);
262 elements[i].y.c1.data[0] = __builtin_bswap64(elements[i].y.c1.data[0]);
263 elements[i].y.c1.data[1] = __builtin_bswap64(elements[i].y.c1.data[1]);
264 elements[i].y.c1.data[2] = __builtin_bswap64(elements[i].y.c1.data[2]);
265 elements[i].y.c1.data[3] = __builtin_bswap64(elements[i].y.c1.data[3]);
266 elements[i].x.c0.self_to_montgomery_form();
267 elements[i].x.c1.self_to_montgomery_form();
268 elements[i].y.c0.self_to_montgomery_form();
269 elements[i].y.c1.self_to_montgomery_form();
270 }
271 }
272 }
273 }
274
275 template <typename AffineElementType>
276 static void read_affine_elements_from_buffer(AffineElementType* elements, char const* buffer, size_t buffer_size)
277 {
278 memcpy((void*)elements, (void*)buffer, buffer_size);
279 byteswap<>(elements, buffer_size);
280 }
281
282 static void read_transcript_g1(AffineElement* monomials, size_t degree, std::string const& dir)
283 {
284 size_t num = 0;
285 size_t num_read = 0;
286 std::string path = get_transcript_path(dir, num);
287
288 while (is_file_exist(path) && num_read < degree) {
289 Manifest manifest;
290 read_manifest(path, manifest);
291
292 auto offset = sizeof(Manifest);
293 const size_t num_to_read = std::min((size_t)manifest.num_g1_points, degree - num_read);
294 const size_t g1_buffer_size = sizeof(Fq) * 2 * num_to_read;
295
296 char* buffer = (char*)&monomials[num_read];
297 size_t size = 0;
298
299 // We must pass the size actually read to the second call, not the desired
300 // g1_buffer_size as the file may have been smaller than this.
301 read_file_into_buffer(buffer, size, path, offset, g1_buffer_size);
302 srs::IO<Curve>::byteswap(&monomials[num_read], size);
303
304 num_read += num_to_read;
305 path = get_transcript_path(dir, ++num);
306 }
307
308 const bool monomial_srs_condition = num_read < degree;
309 if (monomial_srs_condition) {
310 throw_or_abort(
311 format("Only read ",
312 num_read,
313 " points from ",
314 path,
315 ", but require ",
316 degree,
317 ". Is your srs large enough? Either run bootstrap.sh to download the transcript.dat "
318 "files to `srs_db/ignition/`, or you might need to download extra transcript.dat files "
319 "by editing `srs_db/download_ignition.sh` (but be careful, as this suggests you've "
320 "just changed a circuit to exceed a new 'power of two' boundary)."));
321 }
322 }
323
324 static void read_transcript_g2(auto& g2_x, std::string const& dir)
325 requires HasG2<Curve>
326 {
327 const size_t g2_size = sizeof(typename Curve::G2BaseField) * 2;
328 std::string path = format(dir, "/g2.dat");
329
330 if (is_file_exist(path)) {
331 char* buffer = (char*)&g2_x;
332 size_t size = 0;
333
334 // Again, size passed to second function should be size actually read
335 read_file_into_buffer(buffer, size, path, 0, g2_size);
336 byteswap(&g2_x, size);
337
338 return;
339 }
340
341 // Get transcript starting at g0.dat
342 path = get_transcript_path(dir, 0);
343
344 Manifest manifest;
345 read_manifest(path, manifest);
346
347 const size_t g2_buffer_offset = sizeof(Fq) * 2 * manifest.num_g1_points;
348 auto offset = sizeof(Manifest) + g2_buffer_offset;
349
350 char* buffer = (char*)&g2_x;
351 size_t size = 0;
352
353 // Again, size passed to second function should be size actually read
354 read_file_into_buffer(buffer, size, path, offset, g2_size);
355 byteswap(&g2_x, size);
356 }
357
358 static void read_transcript(AffineElement* monomials, auto& g2_x, size_t degree, std::string const& path)
359 requires HasG2<Curve>
360 {
361 read_transcript_g1(monomials, degree, path);
362 read_transcript_g2(g2_x, path);
363 }
364
365 static void read_transcript(AffineElement* monomials, size_t degree, std::string const& path)
366 {
367 read_transcript_g1(monomials, degree, path);
368 }
369
370 // This function is a vestige of the Lagrange form transcript work, and it is not used anywhere.
371 static void write_transcript(AffineElement const* g1_x,
372 auto const* g2_x,
373 Manifest const& manifest,
374 std::string const& dir)
375 requires HasG2<Curve>
376 {
377 const size_t num_g1_x = manifest.num_g1_points;
378 const size_t num_g2_x = manifest.num_g2_points;
379 const size_t transcript_num = manifest.transcript_number;
380 const size_t manifest_size = sizeof(Manifest);
381 const size_t g1_buffer_size = sizeof(Fq) * 2 * num_g1_x;
382 const size_t g2_buffer_size = sizeof(Fq) * 4 * num_g2_x;
383 const size_t transcript_size = manifest_size + g1_buffer_size + g2_buffer_size;
384 std::string path = get_transcript_path(dir, transcript_num);
385 std::vector<char> buffer(transcript_size);
386
387 Manifest net_manifest;
388 net_manifest.transcript_number = htonl(manifest.transcript_number);
389 net_manifest.total_transcripts = htonl(manifest.total_transcripts);
390 net_manifest.total_g1_points = htonl(manifest.total_g1_points);
391 net_manifest.total_g2_points = htonl(manifest.total_g2_points);
392 net_manifest.num_g1_points = htonl(manifest.num_g1_points);
393 net_manifest.num_g2_points = htonl(manifest.num_g2_points);
394 net_manifest.start_from = htonl(manifest.start_from);
395
396 std::copy(&net_manifest, &net_manifest + 1, (Manifest*)&buffer[0]);
397
398 write_g1_elements_to_buffer(g1_x, &buffer[manifest_size], num_g1_x);
399 write_g2_elements_to_buffer(g2_x, &buffer[manifest_size + g1_buffer_size], num_g2_x);
400 write_buffer_to_file(path, &buffer[0], transcript_size);
401 }
402
403 static void write_transcript(AffineElement const* g1_x, Manifest const& manifest, std::string const& dir)
404 {
405 const size_t num_g1_x = manifest.num_g1_points;
406 const size_t transcript_num = manifest.transcript_number;
407 const size_t manifest_size = sizeof(Manifest);
408 const size_t g1_buffer_size = sizeof(Fq) * 2 * num_g1_x;
409 const size_t transcript_size = manifest_size + g1_buffer_size;
410 std::string path = get_transcript_path(dir, transcript_num);
411 std::vector<char> buffer(transcript_size);
412
413 Manifest net_manifest;
414 net_manifest.transcript_number = htonl(manifest.transcript_number);
415 net_manifest.total_transcripts = htonl(manifest.total_transcripts);
416 net_manifest.total_g1_points = htonl(manifest.total_g1_points);
417 net_manifest.total_g2_points = htonl(0);
418 net_manifest.num_g1_points = htonl(manifest.num_g1_points);
419 net_manifest.num_g2_points = htonl(0);
420 net_manifest.start_from = htonl(manifest.start_from);
421
422 std::copy(&net_manifest, &net_manifest + 1, (Manifest*)&buffer[0]);
423
424 write_elements_to_buffer<AffineElement>(g1_x, &buffer[manifest_size], num_g1_x);
425 write_buffer_to_file(path, &buffer[0], transcript_size);
426 }
427};
428
429} // namespace barretenberg::srs
Definition: io.hpp:60
Definition: io.hpp:50
The manifest structure holds the header of a transcript file.
Definition: io.hpp:38