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
11#include <libdeflate.h>
12
13namespace bb {
14
18std::vector<uint8_t> compress(const std::vector<uint8_t>& input)
19{
20 auto compressor =
21 std::unique_ptr<libdeflate_compressor, void (*)(libdeflate_compressor*)>{ libdeflate_alloc_compressor(6),
22 libdeflate_free_compressor };
23
24 // Worst case size for gzip compression
25 size_t max_compressed_size = libdeflate_gzip_compress_bound(compressor.get(), input.size());
26 std::vector<uint8_t> compressed(max_compressed_size);
27
28 size_t actual_compressed_size =
29 libdeflate_gzip_compress(compressor.get(), input.data(), input.size(), compressed.data(), compressed.size());
30
31 if (actual_compressed_size == 0) {
32 THROW std::runtime_error("Failed to compress data");
33 }
34
35 compressed.resize(actual_compressed_size);
36 return compressed;
37}
38
42std::vector<uint8_t> decompress(const void* bytes, size_t size)
43{
44 std::vector<uint8_t> content;
45 // initial size guess
46 content.resize(1024ULL * 128ULL);
47 for (;;) {
48 auto decompressor = std::unique_ptr<libdeflate_decompressor, void (*)(libdeflate_decompressor*)>{
49 libdeflate_alloc_decompressor(), libdeflate_free_decompressor
50 };
51 size_t actual_size = 0;
52 libdeflate_result decompress_result =
53 libdeflate_gzip_decompress(decompressor.get(), bytes, size, content.data(), content.size(), &actual_size);
54 if (decompress_result == LIBDEFLATE_INSUFFICIENT_SPACE) {
55 // need a bigger buffer
56 content.resize(content.size() * 2);
57 continue;
58 }
59 if (decompress_result == LIBDEFLATE_BAD_DATA) {
60 THROW std::invalid_argument("bad gzip data in bb main");
61 }
62 content.resize(actual_size);
63 break;
64 }
65 return content;
66}
67
71template <typename T> T unpack_from_file(const std::filesystem::path& filename)
72{
73 std::ifstream fin;
74 fin.open(filename, std::ios::ate | std::ios::binary);
75 if (!fin.is_open()) {
76 THROW std::invalid_argument("file not found");
77 }
78 if (fin.tellg() == -1) {
79 THROW std::invalid_argument("something went wrong");
80 }
81
82 size_t fsize = static_cast<size_t>(fin.tellg());
83 fin.seekg(0, std::ios_base::beg);
84
85 T result;
86 std::string encoded_data(fsize, '\0');
87 fin.read(encoded_data.data(), static_cast<std::streamsize>(fsize));
88 msgpack::unpack(encoded_data.data(), fsize).get().convert(result);
89 return result;
90}
91
92// TODO(#7371) we should not have so many levels of serialization here.
94{
95 BB_BENCH();
96 return unpack_from_file<std::vector<PrivateExecutionStepRaw>>(input_path);
97}
98
99// TODO(#7371) we should not have so many levels of serialization here.
105
106// TODO(#7371) we should not have so many levels of serialization here.
108 const std::filesystem::path& input_path)
109{
110 BB_BENCH();
111 auto raw_steps = load(input_path);
112 for (PrivateExecutionStepRaw& step : raw_steps) {
113 step.bytecode = decompress(step.bytecode.data(), step.bytecode.size());
114 step.witness = decompress(step.witness.data(), step.witness.size());
115 }
116 return raw_steps;
117}
118
120{
122 // Read with msgpack
123 msgpack::unpack(reinterpret_cast<const char*>(buf.data()), buf.size()).get().convert(raw_steps);
124 // Unlike load_and_decompress, we don't need to decompress the bytecode and witness fields
125 return raw_steps;
126}
127
129{
130 BB_BENCH();
131
132 // Preallocate space to write into diretly as push_back would not be thread safe
133 folding_stack.resize(steps.size());
134 precomputed_vks.resize(steps.size());
135 function_names.resize(steps.size());
136
137 // https://github.com/AztecProtocol/barretenberg/issues/1395 multithread this once bincode is thread-safe
138 for (size_t i = 0; i < steps.size(); i++) {
139 PrivateExecutionStepRaw step = std::move(steps[i]);
140
141 // TODO(#7371) there is a lot of copying going on in bincode. We need the generated bincode code to
142 // use spans instead of vectors.
145
146 folding_stack[i] = { std::move(constraints), std::move(witness) };
147 if (step.vk.empty()) {
148 // For backwards compatibility, but it affects performance and correctness.
149 precomputed_vks[i] = nullptr;
150 } else {
151 precomputed_vks[i] = from_buffer<std::shared_ptr<Chonk::MegaVerificationKey>>(step.vk);
152 }
154 }
155}
156
158{
159 auto ivc = std::make_shared<Chonk>(/*num_circuits=*/folding_stack.size());
160
161 const acir_format::ProgramMetadata metadata{ ivc };
162
163 for (auto& vk : precomputed_vks) {
164 if (vk == nullptr) {
165 info("DEPRECATED: Precomputed VKs expected for the given circuits.");
166 break;
167 }
168 }
169 // Accumulate the entire program stack into the IVC
170 for (auto [program, precomputed_vk, function_name] : zip_view(folding_stack, precomputed_vks, function_names)) {
171 // Construct a bberg circuit from the acir representation then accumulate it into the IVC
172 auto circuit = acir_format::create_circuit<MegaCircuitBuilder>(program, metadata);
173
174 info("Chonk: accumulating " + function_name);
175 // Do one step of ivc accumulator or, if there is only one circuit in the stack, prove that circuit. In this
176 // case, no work is added to the Goblin opqueue, but VM proofs for trivials inputs are produced.
177 ivc->accumulate(circuit, precomputed_vk);
178 }
179
180 return ivc;
181}
182
184 const std::filesystem::path& output_path)
185{
186 // First, compress the bytecode and witness fields of each step
187 for (PrivateExecutionStepRaw& step : steps) {
188 step.bytecode = compress(step.bytecode);
189 step.witness = compress(step.witness);
190 }
191
192 // Serialize to msgpack
193 std::stringstream ss;
194 msgpack::pack(ss, steps);
195 std::string packed_data = ss.str();
196
197 // Write to file
198 std::ofstream file(output_path, std::ios::binary);
199 if (!file) {
200 THROW std::runtime_error("Failed to open file for writing: " + output_path.string());
201 }
202 file.write(packed_data.data(), static_cast<std::streamsize>(packed_data.size()));
203 file.close();
204}
205} // namespace bb
#define BB_BENCH()
Definition bb_bench.hpp:223
void info(Args... args)
Definition log.hpp:89
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)
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.
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Barretenberg's representation of ACIR constraints.
Metadata required to create a circuit.
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()
Creates a Chonk instance and accumulates each circuit in the folding stack. Uses precomputed VKs when...
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