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.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Sergei], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
12#include <libdeflate.h>
13
14namespace bb {
15
19std::vector<uint8_t> compress(const std::vector<uint8_t>& input)
20{
21 auto compressor =
22 std::unique_ptr<libdeflate_compressor, void (*)(libdeflate_compressor*)>{ libdeflate_alloc_compressor(6),
23 libdeflate_free_compressor };
24
25 // Worst case size for gzip compression
26 size_t max_compressed_size = libdeflate_gzip_compress_bound(compressor.get(), input.size());
27 std::vector<uint8_t> compressed(max_compressed_size);
28
29 size_t actual_compressed_size =
30 libdeflate_gzip_compress(compressor.get(), input.data(), input.size(), compressed.data(), compressed.size());
31
32 if (actual_compressed_size == 0) {
33 THROW std::runtime_error("Failed to compress data");
34 }
35
36 compressed.resize(actual_compressed_size);
37 return compressed;
38}
39
43std::vector<uint8_t> decompress(const void* bytes, size_t size)
44{
45 std::vector<uint8_t> content;
46 // initial size guess
47 content.resize(1024ULL * 128ULL);
48 for (;;) {
49 auto decompressor = std::unique_ptr<libdeflate_decompressor, void (*)(libdeflate_decompressor*)>{
50 libdeflate_alloc_decompressor(), libdeflate_free_decompressor
51 };
52 size_t actual_size = 0;
53 libdeflate_result decompress_result =
54 libdeflate_gzip_decompress(decompressor.get(), bytes, size, content.data(), content.size(), &actual_size);
55 if (decompress_result == LIBDEFLATE_INSUFFICIENT_SPACE) {
56 // need a bigger buffer
57 content.resize(content.size() * 2);
58 continue;
59 }
60 if (decompress_result == LIBDEFLATE_BAD_DATA) {
61 THROW std::invalid_argument("bad gzip data in bb main");
62 }
63 content.resize(actual_size);
64 break;
65 }
66 return content;
67}
68
72template <typename T> T unpack_from_file(const std::filesystem::path& filename)
73{
74 std::ifstream fin;
75 fin.open(filename, std::ios::ate | std::ios::binary);
76 if (!fin.is_open()) {
77 THROW std::invalid_argument("file not found");
78 }
79 if (fin.tellg() == -1) {
80 THROW std::invalid_argument("something went wrong");
81 }
82
83 size_t fsize = static_cast<size_t>(fin.tellg());
84 fin.seekg(0, std::ios_base::beg);
85
86 T result;
87 std::string encoded_data(fsize, '\0');
88 fin.read(encoded_data.data(), static_cast<std::streamsize>(fsize));
90 msgpack::unpack(encoded_data.data(), fsize, offset).get().convert(result);
91 if (offset != fsize) {
92 THROW std::invalid_argument("msgpack input has trailing data (" + std::to_string(fsize - offset) +
93 " extra bytes)");
94 }
95 return result;
96}
97
98// TODO(#7371) we should not have so many levels of serialization here.
100{
101 BB_BENCH();
102 return unpack_from_file<std::vector<PrivateExecutionStepRaw>>(input_path);
103}
104
105// TODO(#7371) we should not have so many levels of serialization here.
111
112// TODO(#7371) we should not have so many levels of serialization here.
114 const std::filesystem::path& input_path)
115{
116 BB_BENCH();
117 auto raw_steps = load(input_path);
118 parallel_for(raw_steps.size(), [&](size_t i) {
119 raw_steps[i].bytecode = decompress(raw_steps[i].bytecode.data(), raw_steps[i].bytecode.size());
120 raw_steps[i].witness = decompress(raw_steps[i].witness.data(), raw_steps[i].witness.size());
121 });
122 return raw_steps;
123}
124
126{
128 // Read with msgpack
130 msgpack::unpack(reinterpret_cast<const char*>(buf.data()), buf.size(), offset).get().convert(raw_steps);
131 if (offset != buf.size()) {
132 THROW std::invalid_argument("msgpack input has trailing data (" + std::to_string(buf.size() - offset) +
133 " extra bytes)");
134 }
135 // Unlike load_and_decompress, we don't need to decompress the bytecode and witness fields
136 return raw_steps;
137}
138
140{
141 BB_BENCH();
142
143 // Preallocate space to write into diretly as push_back would not be thread safe
144 folding_stack.resize(steps.size());
145 precomputed_vks.resize(steps.size());
146 function_names.resize(steps.size());
147
148 // Parse each step's bytecode/witness in parallel (thread-safe with msgpack format)
149 parallel_for(steps.size(), [&](size_t i) {
150 PrivateExecutionStepRaw step = std::move(steps[i]);
151
152 acir_format::AcirFormat constraints = acir_format::circuit_buf_to_acir_format(std::move(step.bytecode));
153 acir_format::WitnessVector witness = acir_format::witness_buf_to_witness_vector(std::move(step.witness));
154
155 folding_stack[i] = { std::move(constraints), std::move(witness) };
156 if (step.vk.empty()) {
157 // For backwards compatibility, but it affects performance and correctness.
158 precomputed_vks[i] = nullptr;
159 } else {
160 precomputed_vks[i] = from_buffer<std::shared_ptr<Chonk::MegaVerificationKey>>(step.vk);
161 }
162 function_names[i] = std::move(step.function_name);
163 });
164}
165
166std::shared_ptr<Chonk> PrivateExecutionSteps::accumulate()
167{
168 auto ivc = std::make_shared<Chonk>(/*num_circuits=*/folding_stack.size());
169
170 const acir_format::ProgramMetadata metadata{ ivc };
171
172 for (auto& vk : precomputed_vks) {
173 if (vk == nullptr) {
174 info("DEPRECATED: Precomputed VKs expected for the given circuits.");
175 break;
176 }
177 }
178 // Accumulate the entire program stack into the IVC
179 for (auto [program, precomputed_vk, function_name] : zip_view(folding_stack, precomputed_vks, function_names)) {
180 // Construct a bberg circuit from the acir representation then accumulate it into the IVC
181 auto circuit = acir_format::create_circuit<MegaCircuitBuilder>(program, metadata);
182
183 info("Chonk: accumulating " + function_name);
184 // Do one step of ivc accumulator or, if there is only one circuit in the stack, prove that circuit. In this
185 // case, no work is added to the Goblin opqueue, but VM proofs for trivials inputs are produced.
186 ivc->accumulate(circuit, precomputed_vk);
187 }
188
189 return ivc;
190}
191
192void PrivateExecutionStepRaw::compress_and_save(std::vector<PrivateExecutionStepRaw>&& steps,
193 const std::filesystem::path& output_path)
194{
195 // First, compress the bytecode and witness fields of each step
196 for (PrivateExecutionStepRaw& step : steps) {
197 step.bytecode = compress(step.bytecode);
198 step.witness = compress(step.witness);
199 }
200
201 // Serialize to msgpack
202 std::stringstream ss;
203 msgpack::pack(ss, steps);
204 std::string packed_data = ss.str();
205
206 // Write to file
207 std::ofstream file(output_path, std::ios::binary);
208 if (!file) {
209 THROW std::runtime_error("Failed to open file for writing: " + output_path.string());
210 }
211 file.write(packed_data.data(), static_cast<std::streamsize>(packed_data.size()));
212 file.close();
213}
214} // namespace bb
#define BB_BENCH()
Definition bb_bench.hpp:268
#define info(...)
Definition log.hpp:93
ssize_t offset
Definition engine.cpp:62
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
std::vector< uint8_t > compress(const std::vector< uint8_t > &input)
Save modified ivc-inputs.msgpack when VKs are rewritten.
std::vector< uint8_t > decompress(const void *bytes, size_t size)
Decompress bytecode and witness fields from ivc-inputs.msgpack.
T unpack_from_file(const std::filesystem::path &filename)
Deserialize msgpack data from file.
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
Metadata required to create a circuit.
This is the msgpack encoding of the objects returned by the following typescript: const stepToStruct ...
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::vector< std::shared_ptr< Chonk::MegaVerificationKey > > precomputed_vks
Precomputed VKs (performance)
void parse(std::vector< PrivateExecutionStepRaw > &&steps)
Converts PrivateExecutionStepRaw entries (which contain raw bytecode/witness bytes) into structured A...
std::vector< acir_format::AcirProgram > folding_stack
ACIR programs with witnesses.
std::vector< std::string > function_names
Function names for logging.
#define THROW