Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
private_execution_steps.cpp
Go to the documentation of this file.
5#include <libdeflate.h>
6
7namespace bb {
8
9std::vector<uint8_t> compress(const std::vector<uint8_t>& input)
10{
11 auto compressor =
12 std::unique_ptr<libdeflate_compressor, void (*)(libdeflate_compressor*)>{ libdeflate_alloc_compressor(6),
13 libdeflate_free_compressor };
14
15 // Worst case size for gzip compression
16 size_t max_compressed_size = libdeflate_gzip_compress_bound(compressor.get(), input.size());
17 std::vector<uint8_t> compressed(max_compressed_size);
18
19 size_t actual_compressed_size =
20 libdeflate_gzip_compress(compressor.get(), input.data(), input.size(), compressed.data(), compressed.size());
21
22 if (actual_compressed_size == 0) {
23 THROW std::runtime_error("Failed to compress data");
24 }
25
26 compressed.resize(actual_compressed_size);
27 return compressed;
28}
29
30std::vector<uint8_t> decompress(const void* bytes, size_t size)
31{
32 std::vector<uint8_t> content;
33 // initial size guess
34 content.resize(1024ULL * 128ULL);
35 for (;;) {
36 auto decompressor = std::unique_ptr<libdeflate_decompressor, void (*)(libdeflate_decompressor*)>{
37 libdeflate_alloc_decompressor(), libdeflate_free_decompressor
38 };
39 size_t actual_size = 0;
40 libdeflate_result decompress_result =
41 libdeflate_gzip_decompress(decompressor.get(), bytes, size, content.data(), content.size(), &actual_size);
42 if (decompress_result == LIBDEFLATE_INSUFFICIENT_SPACE) {
43 // need a bigger buffer
44 content.resize(content.size() * 2);
45 continue;
46 }
47 if (decompress_result == LIBDEFLATE_BAD_DATA) {
48 THROW std::invalid_argument("bad gzip data in bb main");
49 }
50 content.resize(actual_size);
51 break;
52 }
53 return content;
54}
55
56template <typename T> T unpack_from_file(const std::filesystem::path& filename)
57{
58 std::ifstream fin;
59 fin.open(filename, std::ios::ate | std::ios::binary);
60 if (!fin.is_open()) {
61 THROW std::invalid_argument("file not found");
62 }
63 if (fin.tellg() == -1) {
64 THROW std::invalid_argument("something went wrong");
65 }
66
67 size_t fsize = static_cast<size_t>(fin.tellg());
68 fin.seekg(0, std::ios_base::beg);
69
70 T result;
71 std::string encoded_data(fsize, '\0');
72 fin.read(encoded_data.data(), static_cast<std::streamsize>(fsize));
73 msgpack::unpack(encoded_data.data(), fsize).get().convert(result);
74 return result;
75}
76
77// TODO(#7371) we should not have so many levels of serialization here.
79{
80 BB_BENCH();
81 return unpack_from_file<std::vector<PrivateExecutionStepRaw>>(input_path);
82}
83
84// TODO(#7371) we should not have so many levels of serialization here.
90
91// TODO(#7371) we should not have so many levels of serialization here.
93 const std::filesystem::path& input_path)
94{
95 BB_BENCH();
96 auto raw_steps = load(input_path);
97 for (PrivateExecutionStepRaw& step : raw_steps) {
98 step.bytecode = decompress(step.bytecode.data(), step.bytecode.size());
99 step.witness = decompress(step.witness.data(), step.witness.size());
100 }
101 return raw_steps;
102}
103
105{
107 // Read with msgpack
108 msgpack::unpack(reinterpret_cast<const char*>(buf.data()), buf.size()).get().convert(raw_steps);
109 // Unlike load_and_decompress, we don't need to decompress the bytecode and witness fields
110 return raw_steps;
111}
112
114{
115 BB_BENCH();
116
117 // Preallocate space to write into diretly as push_back would not be thread safe
118 folding_stack.resize(steps.size());
119 precomputed_vks.resize(steps.size());
120 function_names.resize(steps.size());
121
122 // https://github.com/AztecProtocol/barretenberg/issues/1395 multithread this once bincode is thread-safe
123 for (size_t i = 0; i < steps.size(); i++) {
124 PrivateExecutionStepRaw step = std::move(steps[i]);
125
126 // TODO(#7371) there is a lot of copying going on in bincode. We need the generated bincode code to
127 // use spans instead of vectors.
130
131 folding_stack[i] = { std::move(constraints), std::move(witness) };
132 if (step.vk.empty()) {
133 // For backwards compatibility, but it affects performance and correctness.
134 precomputed_vks[i] = nullptr;
135 } else {
136 precomputed_vks[i] = from_buffer<std::shared_ptr<Chonk::MegaVerificationKey>>(step.vk);
137 }
139 }
140}
141
143{
144 auto ivc = std::make_shared<Chonk>(/*num_circuits=*/folding_stack.size());
145
146 const acir_format::ProgramMetadata metadata{ ivc };
147
148 for (auto& vk : precomputed_vks) {
149 if (vk == nullptr) {
150 info("DEPRECATED: Precomputed VKs expected for the given circuits.");
151 break;
152 }
153 }
154 // Accumulate the entire program stack into the IVC
155 for (auto [program, precomputed_vk, function_name] : zip_view(folding_stack, precomputed_vks, function_names)) {
156 // Construct a bberg circuit from the acir representation then accumulate it into the IVC
157 auto circuit = acir_format::create_circuit<MegaCircuitBuilder>(program, metadata);
158
159 info("Chonk: accumulating " + function_name);
160 // Do one step of ivc accumulator or, if there is only one circuit in the stack, prove that circuit. In this
161 // case, no work is added to the Goblin opqueue, but VM proofs for trivials inputs are produced.
162 ivc->accumulate(circuit, precomputed_vk);
163 }
164
165 return ivc;
166}
167
169 const std::filesystem::path& output_path)
170{
171 // First, compress the bytecode and witness fields of each step
172 for (PrivateExecutionStepRaw& step : steps) {
173 step.bytecode = compress(step.bytecode);
174 step.witness = compress(step.witness);
175 }
176
177 // Serialize to msgpack
178 std::stringstream ss;
179 msgpack::pack(ss, steps);
180 std::string packed_data = ss.str();
181
182 // Write to file
183 std::ofstream file(output_path, std::ios::binary);
184 if (!file) {
185 THROW std::runtime_error("Failed to open file for writing: " + output_path.string());
186 }
187 file.write(packed_data.data(), static_cast<std::streamsize>(packed_data.size()));
188 file.close();
189}
190} // namespace bb
#define BB_BENCH()
Definition bb_bench.hpp:223
void info(Args... args)
Definition log.hpp:75
uint8_t const * buf
Definition data_store.hpp:9
WitnessVector witness_buf_to_witness_vector(std::vector< uint8_t > &&buf)
Convert a buffer representing a witness vector into Barretenberg's internal WitnessVector format.
std::vector< bb::fr > WitnessVector
AcirFormat circuit_buf_to_acir_format(std::vector< uint8_t > &&buf)
Convert a buffer representing a circuit into Barretenberg's internal AcirFormat representation.
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
std::vector< uint8_t > compress(const std::vector< uint8_t > &input)
std::vector< uint8_t > decompress(const void *bytes, size_t size)
T unpack_from_file(const std::filesystem::path &filename)
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
This is the msgpack encoding of the objects returned by the following typescript: const stepToStruct ...
static void compress_and_save(std::vector< PrivateExecutionStepRaw > &&steps, const std::filesystem::path &output_path)
static std::vector< PrivateExecutionStepRaw > load_and_decompress(const std::filesystem::path &input_path)
static std::vector< PrivateExecutionStepRaw > parse_uncompressed(const std::vector< uint8_t > &buf)
static std::vector< PrivateExecutionStepRaw > load(const std::filesystem::path &input_path)
std::shared_ptr< Chonk > accumulate()
std::vector< std::shared_ptr< Chonk::MegaVerificationKey > > precomputed_vks
void parse(std::vector< PrivateExecutionStepRaw > &&steps)
std::vector< acir_format::AcirProgram > folding_stack
std::vector< std::string > function_names
#define THROW