Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
api_ultra_honk.test.cpp
Go to the documentation of this file.
1#include "api_ultra_honk.hpp"
12#include <chrono>
13#include <cstddef>
14#include <cstdlib>
15#include <filesystem>
16#include <gtest/gtest.h>
17#include <math.h>
18#include <sstream>
19#include <string_view>
20
21namespace bb {
22std::vector<uint8_t> compress(const std::vector<uint8_t>& input);
23std::vector<uint8_t> decompress(const void* bytes, size_t size);
24} // namespace bb
25
26using namespace bb;
27
28namespace {
29// Create a unique temporary directory for each test run
30// Uniqueness needed because tests are run in parallel and write to same file names.
31std::filesystem::path get_test_dir(const std::string_view& test_name)
32{
33 std::filesystem::path temp_dir = "tmp_api_ultra_honk_test";
34 std::filesystem::create_directories(temp_dir);
35 std::filesystem::create_directories(temp_dir / test_name);
36 return temp_dir / test_name;
37}
38
39// Create test data
40std::pair<std::filesystem::path, std::filesystem::path> create_test_circuit_files(const std::filesystem::path& test_dir)
41{
42 auto [bytecode, witness] = acir_bincode_mocks::create_simple_circuit_bytecode();
43
44 auto bytecode_path = test_dir / "circuit.gz";
45 auto witness_path = test_dir / "witness.gz";
46
47 write_file(bytecode_path, bb::compress(bytecode));
48 write_file(witness_path, bb::compress(witness));
49
50 return { bytecode_path, witness_path };
51}
52
53} // namespace
54
55class ApiUltraHonkTest : public ::testing::Test {
56 protected:
58
59 void SetUp() override
60 {
61 const auto* info = ::testing::UnitTest::GetInstance()->current_test_info();
62 test_dir = get_test_dir(info->name());
63 }
64
65 void TearDown() override
66 {
67 if (std::filesystem::exists(test_dir)) {
68 std::filesystem::remove_all(test_dir);
69 }
70 }
71
72 std::filesystem::path test_dir;
73};
74
75TEST_F(ApiUltraHonkTest, ProveAndVerify)
76{
77 auto [bytecode_path, witness_path] = create_test_circuit_files(test_dir);
78
79 API::Flags flags;
80 flags.oracle_hash_type = "poseidon2"; // Set default oracle hash type
81
82 UltraHonkAPI api;
83
84 // Generate VK first
85 auto vk_output_path = test_dir / "vk";
86 std::filesystem::create_directories(vk_output_path);
87 api.write_vk(flags, bytecode_path, vk_output_path);
88 EXPECT_TRUE(std::filesystem::exists(vk_output_path / "vk"));
89
90 // Generate proof
91 auto proof_output_dir = test_dir / "proof";
92 std::filesystem::create_directories(proof_output_dir);
93 api.prove(flags, bytecode_path, witness_path, vk_output_path / "vk", proof_output_dir);
94
95 // Check that proof files were created
96 EXPECT_TRUE(std::filesystem::exists(proof_output_dir / "proof"));
97 EXPECT_TRUE(std::filesystem::exists(proof_output_dir / "public_inputs"));
98
99 // Verify the proof
100 bool verified =
101 api.verify(flags, proof_output_dir / "public_inputs", proof_output_dir / "proof", vk_output_path / "vk");
102 EXPECT_TRUE(verified);
103}
104
105TEST_F(ApiUltraHonkTest, ProveWithWriteVk)
106{
107 auto [bytecode_path, witness_path] = create_test_circuit_files(test_dir);
108
109 API::Flags flags;
110 flags.oracle_hash_type = "poseidon2";
111 flags.write_vk = true;
112
113 UltraHonkAPI api;
114
115 // Generate proof with write_vk flag (will compute and write VK)
116 auto proof_output_dir = test_dir / "proof";
117 std::filesystem::create_directories(proof_output_dir);
118 api.prove(flags, bytecode_path, witness_path, "", proof_output_dir);
119
120 // Check that proof and VK files were created
121 EXPECT_TRUE(std::filesystem::exists(proof_output_dir / "proof"));
122 EXPECT_TRUE(std::filesystem::exists(proof_output_dir / "public_inputs"));
123 EXPECT_TRUE(std::filesystem::exists(proof_output_dir / "vk"));
124 EXPECT_TRUE(std::filesystem::exists(proof_output_dir / "vk_hash"));
125
126 // Verify the proof
127 bool verified =
128 api.verify(flags, proof_output_dir / "public_inputs", proof_output_dir / "proof", proof_output_dir / "vk");
129 EXPECT_TRUE(verified);
130}
131
132TEST_F(ApiUltraHonkTest, ProveAndVerifyWithFields)
133{
134 auto [bytecode_path, witness_path] = create_test_circuit_files(test_dir);
135
136 // First generate VK for the prove step
137 API::Flags vk_flags;
138 vk_flags.oracle_hash_type = "poseidon2";
139
140 UltraHonkAPI api;
141
142 auto vk_output_path = test_dir / "vk";
143 std::filesystem::create_directories(vk_output_path);
144 api.write_vk(vk_flags, bytecode_path, vk_output_path);
145 EXPECT_TRUE(std::filesystem::exists(vk_output_path / "vk"));
146
147 // Now test proof generation
148 API::Flags flags;
149 flags.oracle_hash_type = "poseidon2";
150
151 // Generate proof
152 auto proof_output_dir = test_dir / "proof";
153 std::filesystem::create_directories(proof_output_dir);
154 api.prove(flags, bytecode_path, witness_path, vk_output_path / "vk", proof_output_dir);
155
156 // Check that proof files were created
157 EXPECT_TRUE(std::filesystem::exists(proof_output_dir / "proof"));
158 EXPECT_TRUE(std::filesystem::exists(proof_output_dir / "public_inputs"));
159}
160
161TEST_F(ApiUltraHonkTest, ProveWithDifferentSettings)
162{
163 auto [bytecode_path, witness_path] = create_test_circuit_files(test_dir);
164
165 // Test different oracle hash types
166 const std::vector<std::pair<std::string, bool>> test_cases = { { "poseidon2",
167 false }, // oracle_hash_type, disable_zk
168 { "poseidon2", true },
169 { "keccak", false },
170 { "keccak", true } };
171
172 for (const auto& [oracle_hash_type, disable_zk] : test_cases) {
173 API::Flags flags;
174 flags.oracle_hash_type = oracle_hash_type;
175 flags.disable_zk = disable_zk;
176 flags.write_vk = true;
177
178 auto case_dir = test_dir / (oracle_hash_type + "_" + (disable_zk ? "no_zk" : "zk"));
179 std::filesystem::create_directories(case_dir);
180
181 UltraHonkAPI api;
182
183 // Generate proof
184 api.prove(flags, bytecode_path, witness_path, "", case_dir);
185
186 // Verify the proof
187 bool verified = api.verify(flags, case_dir / "public_inputs", case_dir / "proof", case_dir / "vk");
188 EXPECT_TRUE(verified) << "Failed with oracle_hash_type=" << oracle_hash_type << ", disable_zk=" << disable_zk;
189 }
190}
191
193{
194 auto [bytecode_path, witness_path] = create_test_circuit_files(test_dir);
195 API::Flags flags;
196 flags.oracle_hash_type = "poseidon2";
197
198 UltraHonkAPI api;
199 api.write_vk(flags, bytecode_path, test_dir);
200
201 // Test against bbapi::CircuitComputeVk
202 auto bytecode = read_file(bytecode_path);
203 auto expected_vk =
204 bbapi::CircuitComputeVk({ .circuit = { .bytecode = bb::decompress(bytecode.data(), bytecode.size()) },
205 .settings = { .oracle_hash_type = flags.oracle_hash_type } })
206 .execute();
207
208 info("after write_vk, expected_vk size: {}", expected_vk.bytes.size());
209 EXPECT_EQ(expected_vk.bytes, read_file(test_dir / "vk"));
210 EXPECT_EQ(expected_vk.hash, read_file(test_dir / "vk_hash"));
211
212 // Verify round-trip: decode the VK and check that to_field_elements() matches
213 auto vk_from_bytes = from_buffer<UltraFlavor::VerificationKey>(expected_vk.bytes);
214 auto vk_from_file = from_buffer<UltraFlavor::VerificationKey>(read_file(test_dir / "vk"));
215 EXPECT_EQ(vk_from_bytes.to_field_elements(), vk_from_file.to_field_elements());
216}
217
218// NOTE: very light test
219TEST_F(ApiUltraHonkTest, GatesWithOpcodesSmokeTest)
220{
221 auto [bytecode_path, witness_path] = create_test_circuit_files(test_dir);
222
223 // Capture stdout
224 testing::internal::CaptureStdout();
225
226 API::Flags flags;
227 flags.oracle_hash_type = "poseidon2";
228 flags.include_gates_per_opcode = true;
229 UltraHonkAPI api;
230 api.gates(flags, bytecode_path);
231
232 std::string output = testing::internal::GetCapturedStdout();
233
234 // Check that output contains per-opcode information
235 EXPECT_TRUE(output.find("gates_per_opcode") != std::string::npos);
236}
TEST_F(ApiUltraHonkTest, ProveAndVerify)
UltraHonk-specific command definitions for the Barretenberg RPC API.
void TearDown() override
static void SetUpTestSuite()
std::filesystem::path test_dir
void prove(const Flags &flags, const std::filesystem::path &bytecode_path, const std::filesystem::path &witness_path, const std::filesystem::path &vk_path, const std::filesystem::path &output_dir)
void write_vk(const Flags &flags, const std::filesystem::path &bytecode_path, const std::filesystem::path &output_path) override
bool verify(const Flags &flags, const std::filesystem::path &public_inputs_path, const std::filesystem::path &proof_path, const std::filesystem::path &vk_path) override
void gates(const Flags &flags, const std::filesystem::path &bytecode_path) override
void info(Args... args)
Definition log.hpp:74
std::pair< std::vector< uint8_t >, std::vector< uint8_t > > create_simple_circuit_bytecode(size_t num_constraints=1)
Helper function to create a minimal circuit bytecode and witness for testing.
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
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)
std::vector< uint8_t > read_file(const std::string &filename, size_t bytes=0)
Definition file_io.hpp:29
void write_file(const std::string &filename, std::vector< uint8_t > const &data)
Definition file_io.hpp:58
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
bool include_gates_per_opcode
Definition api.hpp:23
bool write_vk
Definition api.hpp:22
bool disable_zk
Definition api.hpp:13
std::string oracle_hash_type
Definition api.hpp:19