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.
4#include <libdeflate.h>
5
6namespace bb {
7
8std::vector<uint8_t> compress(const std::vector<uint8_t>& input)
9{
10 auto compressor =
11 std::unique_ptr<libdeflate_compressor, void (*)(libdeflate_compressor*)>{ libdeflate_alloc_compressor(6),
12 libdeflate_free_compressor };
13
14 // Worst case size for gzip compression
15 size_t max_compressed_size = libdeflate_gzip_compress_bound(compressor.get(), input.size());
16 std::vector<uint8_t> compressed(max_compressed_size);
17
18 size_t actual_compressed_size =
19 libdeflate_gzip_compress(compressor.get(), input.data(), input.size(), compressed.data(), compressed.size());
20
21 if (actual_compressed_size == 0) {
22 THROW std::runtime_error("Failed to compress data");
23 }
24
25 compressed.resize(actual_compressed_size);
26 return compressed;
27}
28
29std::vector<uint8_t> decompress(const void* bytes, size_t size)
30{
31 std::vector<uint8_t> content;
32 // initial size guess
33 content.resize(1024ULL * 128ULL);
34 for (;;) {
35 auto decompressor = std::unique_ptr<libdeflate_decompressor, void (*)(libdeflate_decompressor*)>{
36 libdeflate_alloc_decompressor(), libdeflate_free_decompressor
37 };
38 size_t actual_size = 0;
39 libdeflate_result decompress_result =
40 libdeflate_gzip_decompress(decompressor.get(), bytes, size, content.data(), content.size(), &actual_size);
41 if (decompress_result == LIBDEFLATE_INSUFFICIENT_SPACE) {
42 // need a bigger buffer
43 content.resize(content.size() * 2);
44 continue;
45 }
46 if (decompress_result == LIBDEFLATE_BAD_DATA) {
47 THROW std::invalid_argument("bad gzip data in bb main");
48 }
49 content.resize(actual_size);
50 break;
51 }
52 return content;
53}
54
55template <typename T> T unpack_from_file(const std::filesystem::path& filename)
56{
57 std::ifstream fin;
58 fin.open(filename, std::ios::ate | std::ios::binary);
59 if (!fin.is_open()) {
60 THROW std::invalid_argument("file not found");
61 }
62 if (fin.tellg() == -1) {
63 THROW std::invalid_argument("something went wrong");
64 }
65
66 size_t fsize = static_cast<size_t>(fin.tellg());
67 fin.seekg(0, std::ios_base::beg);
68
69 T result;
70 std::string encoded_data(fsize, '\0');
71 fin.read(encoded_data.data(), static_cast<std::streamsize>(fsize));
72 msgpack::unpack(encoded_data.data(), fsize).get().convert(result);
73 return result;
74}
75
76// TODO(#7371) we should not have so many levels of serialization here.
78{
80 return unpack_from_file<std::vector<PrivateExecutionStepRaw>>(input_path);
81}
82
83// TODO(#7371) we should not have so many levels of serialization here.
89
90// TODO(#7371) we should not have so many levels of serialization here.
92 const std::filesystem::path& input_path)
93{
95 auto raw_steps = load(input_path);
96 for (PrivateExecutionStepRaw& step : raw_steps) {
97 step.bytecode = decompress(step.bytecode.data(), step.bytecode.size());
98 step.witness = decompress(step.witness.data(), step.witness.size());
99 }
100 return raw_steps;
101}
102
104{
106 // Read with msgpack
107 msgpack::unpack(reinterpret_cast<const char*>(buf.data()), buf.size()).get().convert(raw_steps);
108 // Unlike load_and_decompress, we don't need to decompress the bytecode and witness fields
109 return raw_steps;
110}
111
113{
114 PROFILE_THIS();
115
116 // Preallocate space to write into diretly as push_back would not be thread safe
117 folding_stack.resize(steps.size());
118 precomputed_vks.resize(steps.size());
119 function_names.resize(steps.size());
120
121 // https://github.com/AztecProtocol/barretenberg/issues/1395 multithread this once bincode is thread-safe
122 for (size_t i = 0; i < steps.size(); i++) {
123 PrivateExecutionStepRaw step = std::move(steps[i]);
124
125 // TODO(#7371) there is a lot of copying going on in bincode. We need the generated bincode code to
126 // use spans instead of vectors.
129
130 folding_stack[i] = { std::move(constraints), std::move(witness) };
131 if (step.vk.empty()) {
132 // For backwards compatibility, but it affects performance and correctness.
133 precomputed_vks[i] = nullptr;
134 } else {
135 auto vk = from_buffer<std::shared_ptr<ClientIVC::MegaVerificationKey>>(step.vk);
136 precomputed_vks[i] = 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 step.vk = step.vk;
177 step.function_name = step.function_name;
178 }
179
180 // Serialize to msgpack
181 std::stringstream ss;
182 msgpack::pack(ss, steps);
183 std::string packed_data = ss.str();
184
185 // Write to file
186 std::ofstream file(output_path, std::ios::binary);
187 if (!file) {
188 THROW std::runtime_error("Failed to open file for writing: " + output_path.string());
189 }
190 file.write(packed_data.data(), static_cast<std::streamsize>(packed_data.size()));
191 file.close();
192}
193} // namespace bb
void info(Args... args)
Definition log.hpp:70
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
#define PROFILE_THIS()
Definition op_count.hpp:15
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