14#include <nlohmann/json.hpp>
17#ifdef ENABLE_AVM_TRANSPILER
19#include <avm_transpiler.h>
29std::vector<uint8_t> extract_bytecode(
const nlohmann::json& function)
31 if (!function.contains(
"bytecode")) {
35 const auto& base64_bytecode = function[
"bytecode"].get<std::string>();
42std::string compute_bytecode_hash(
const std::vector<uint8_t>& bytecode)
45 std::ostringstream oss;
46 for (
auto byte :
hash) {
47 oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(
byte);
55std::filesystem::path get_cache_dir()
61 std::filesystem::path cache_dir = std::filesystem::path(home) /
".bb" /
BB_VERSION_PLACEHOLDER /
"vk_cache";
62 std::filesystem::create_directories(cache_dir);
69bool is_private_constrained_function(
const nlohmann::json& function)
71 bool is_public =
false;
72 bool is_unconstrained =
false;
75 if (function.contains(
"custom_attributes") && function[
"custom_attributes"].is_array()) {
76 for (
const auto& attr : function[
"custom_attributes"]) {
77 if (attr.is_string() && attr.get<std::string>() ==
"public") {
85 if (function.contains(
"is_unconstrained") && function[
"is_unconstrained"].is_boolean()) {
86 is_unconstrained = function[
"is_unconstrained"].get<
bool>();
89 return !is_public && !is_unconstrained;
95std::vector<uint8_t> get_or_generate_cached_vk(
const std::filesystem::path& cache_dir,
96 const std::string& circuit_name,
97 const std::vector<uint8_t>& bytecode,
100 std::string hash_str = compute_bytecode_hash(bytecode);
101 std::filesystem::path vk_cache_path = cache_dir / (hash_str +
".vk");
104 if (!force && std::filesystem::exists(vk_cache_path)) {
105 info(
"Verification key already in cache: ", hash_str);
110 info(
"Generating verification key: ", hash_str);
112 bbapi::ClientIvcComputeStandaloneVk{ .circuit = { .name = circuit_name, .bytecode = bytecode } }.execute();
117 return response.bytes;
123void generate_vks_for_functions(
const std::filesystem::path& cache_dir,
129 auto* function = functions[i];
130 std::string fn_name = (*function)[
"name"].get<std::string>();
133 auto bytecode = extract_bytecode(*function);
136 get_or_generate_cached_vk(cache_dir, fn_name, bytecode, force);
140 for (
auto* function : functions) {
141 std::string fn_name = (*function)[
"name"].get<std::string>();
144 auto bytecode = extract_bytecode(*function);
147 std::string hash_str = compute_bytecode_hash(bytecode);
148 std::filesystem::path vk_cache_path = cache_dir / (hash_str +
".vk");
152 std::string encoded_vk =
base64_encode(vk_data.data(), vk_data.size(),
false);
153 (*function)[
"verification_key"] = encoded_vk;
162bool transpile_artifact([[maybe_unused]]
const std::string& input_path, [[maybe_unused]]
const std::string& output_path)
164#ifdef ENABLE_AVM_TRANSPILER
165 info(
"Transpiling: ", input_path,
" -> ", output_path);
167 auto result = avm_transpile_file(input_path.c_str(), output_path.c_str());
169 if (result.success == 0) {
170 if (result.error_message) {
171 std::string error_msg(result.error_message);
172 if (error_msg ==
"Contract already transpiled") {
174 if (input_path != output_path) {
175 std::filesystem::copy_file(
176 input_path, output_path, std::filesystem::copy_options::overwrite_existing);
179 info(
"Transpilation failed: ", error_msg);
180 avm_free_result(&result);
184 info(
"Transpilation failed");
185 avm_free_result(&result);
190 avm_free_result(&result);
192 info(
"Transpiled: ", input_path,
" -> ", output_path);
194 throw_or_abort(
"AVM Transpiler is not enabled. Please enable it to use bb aztec_process.");
206 if (!std::filesystem::exists(output_path)) {
211 auto cache_dir = get_cache_dir();
212 info(
"Generating verification keys for functions in ", std::filesystem::path(output_path).filename().
string());
213 info(
"Cache directory: ", cache_dir.string());
216 auto artifact_content =
read_file(output_path);
217 std::string artifact_str(artifact_content.begin(), artifact_content.end());
218 auto artifact_json = nlohmann::json::parse(artifact_str);
220 if (!artifact_json.contains(
"functions")) {
221 info(
"Warning: No functions found in artifact");
227 for (
auto& function : artifact_json[
"functions"]) {
228 if (is_private_constrained_function(function)) {
229 private_functions.push_back(&function);
233 if (private_functions.empty()) {
234 info(
"No private constrained functions found");
239 generate_vks_for_functions(cache_dir, private_functions, force);
242 std::ofstream out_file(output_path);
243 out_file << artifact_json.dump(2) <<
std::endl;
246 info(
"Successfully processed: ", input_path,
" -> ", output_path);
252 std::vector<std::string> artifacts;
255 for (
const auto& entry : std::filesystem::recursive_directory_iterator(search_path)) {
256 if (!entry.is_regular_file()) {
260 const auto& path = entry.path();
263 if (path.extension() !=
".json") {
268 std::string path_str = path.string();
269 if (path_str.find(
"/target/") == std::string::npos && path_str.find(
"\\target\\") == std::string::npos) {
274 if (path_str.find(
"/cache/") != std::string::npos || path_str.find(
"\\cache\\") != std::string::npos ||
275 path_str.find(
".function_artifact_") != std::string::npos) {
279 artifacts.push_back(path.string());
289 if (artifacts.empty()) {
290 info(
"No contract artifacts found. Please compile your contracts first with 'nargo compile'.");
294 info(
"Found ", artifacts.size(),
" contract artifact(s) to process");
296 bool all_success =
true;
297 for (
const auto& artifact : artifacts) {
305 info(
"Contract postprocessing complete!");
std::string base64_encode(unsigned char const *bytes_to_encode, size_t in_len, bool url)
ClientIVC-specific command definitions for the Barretenberg RPC API.
std::vector< uint8_t > decode_bytecode(const std::string &base64_bytecode)
void hash(State &state) noexcept
Sha256Hash sha256(const ByteContainer &input)
Entry point for Barretenberg command-line interface.
bool transpile_artifact(const std::string &input_path, const std::string &output_path)
Transpile the artifact file (or copy if transpiler not enabled)
const char *const BB_VERSION_PLACEHOLDER
bool process_all_artifacts(const std::string &search_path, bool force)
Process all discovered contract artifacts in a directory tree.
bool process_aztec_artifact(const std::string &input_path, const std::string &output_path, bool force)
Process Aztec contract artifacts: transpile and generate verification keys.
std::vector< std::string > find_contract_artifacts(const std::string &search_path)
Find all contract artifacts in target/ directories.
std::vector< uint8_t > read_file(const std::string &filename, size_t bytes=0)
void write_file(const std::string &filename, std::vector< uint8_t > const &data)
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
void throw_or_abort(std::string const &err)