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<ClientIVC::MegaVerificationKey>>(step.vk);
137 }
139 }
140}
141
143{
144 TraceSettings trace_settings{ AZTEC_TRACE_STRUCTURE };
145 auto ivc = std::make_shared<ClientIVC>(/*num_circuits=*/folding_stack.size(), trace_settings);
146
147 const acir_format::ProgramMetadata metadata{ ivc };
148
149 for (auto& vk : precomputed_vks) {
150 if (vk == nullptr) {
151 info("DEPRECATED: Precomputed VKs expected for the given circuits.");
152 break;
153 }
154 }
155 // Accumulate the entire program stack into the IVC
156 for (auto [program, precomputed_vk, function_name] : zip_view(folding_stack, precomputed_vks, function_names)) {
157 // Construct a bberg circuit from the acir representation then accumulate it into the IVC
158 auto circuit = acir_format::create_circuit<MegaCircuitBuilder>(program, metadata);
159
160 info("ClientIVC: accumulating " + function_name);
161 // Do one step of ivc accumulator or, if there is only one circuit in the stack, prove that circuit. In this
162 // case, no work is added to the Goblin opqueue, but VM proofs for trivials inputs are produced.
163 ivc->accumulate(circuit, precomputed_vk);
164 }
165
166 return ivc;
167}
168
170 const std::filesystem::path& output_path)
171{
172 // First, compress the bytecode and witness fields of each step
173 for (PrivateExecutionStepRaw& step : steps) {
174 step.bytecode = compress(step.bytecode);
175 step.witness = compress(step.witness);
176 }
177
178 // Serialize to msgpack
179 std::stringstream ss;
180 msgpack::pack(ss, steps);
181 std::string packed_data = ss.str();
182
183 // Write to file
184 std::ofstream file(output_path, std::ios::binary);
185 if (!file) {
186 THROW std::runtime_error("Failed to open file for writing: " + output_path.string());
187 }
188 file.write(packed_data.data(), static_cast<std::streamsize>(packed_data.size()));
189 file.close();
190}
191} // namespace bb
#define BB_BENCH()
Definition bb_bench.hpp:222
void info(Args... args)
Definition log.hpp:74
uint8_t const * buf
Definition data_store.hpp:9
WitnessVector witness_buf_to_witness_data(std::vector< uint8_t > &&buf)
Converts from the ACIR-native WitnessStack format to Barretenberg's internal WitnessVector format.
AcirFormat circuit_buf_to_acir_format(std::vector< uint8_t > &&buf)
bb::SlabVector< bb::fr > WitnessVector
Entry point for Barretenberg command-line interface.
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::vector< std::shared_ptr< ClientIVC::MegaVerificationKey > > precomputed_vks
std::shared_ptr< ClientIVC > accumulate()
void parse(std::vector< PrivateExecutionStepRaw > &&steps)
std::vector< acir_format::AcirProgram > folding_stack
std::vector< std::string > function_names
#define THROW