Skip to content

Commit 4642b61

Browse files
SarkoxedRumata888
andauthored
feat: creating an SMT verification module (#1932)
This PR adds a module to symbolically verify circuits in our codebase # Checklist: Remove the checklist to signal you've completed it. Enable auto-merge if the PR is ready to merge. - [ x] If the pull request requires a cryptography review (e.g. cryptographic algorithm implementations) I have added the 'crypto' tag. - [x ] I have reviewed my diff in github, line by line and removed unexpected formatting changes, testing logs, or commented-out code. - [ x] Every change is related to the PR description. - [x ] I have [linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) this pull request to relevant issues (if any exist). --------- Co-authored-by: Innokentii Sennovskii <isennovskiy@gmail.com>
1 parent e434a22 commit 4642b61

21 files changed

+2093
-0
lines changed

circuits/cpp/barretenberg/cpp/CMakePresets.json

+20
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,16 @@
8888
"FUZZING": "ON"
8989
}
9090
},
91+
{
92+
"name": "smt-verification",
93+
"displayName": "Build with smt verificaiton",
94+
"description": "Build default preset but with smt library included",
95+
"inherits": "clang16",
96+
"binaryDir": "build-smt",
97+
"cacheVariables": {
98+
"SMT": "ON"
99+
}
100+
},
91101
{
92102
"name": "coverage",
93103
"displayName": "Build with coverage",
@@ -190,6 +200,11 @@
190200
"inherits": "default",
191201
"configurePreset": "fuzzing"
192202
},
203+
{
204+
"name": "smt-verification",
205+
"inherits": "clang16",
206+
"configurePreset": "smt-verification"
207+
},
193208
{
194209
"name": "coverage",
195210
"inherits": "default",
@@ -258,6 +273,11 @@
258273
"inherits": "default",
259274
"configurePreset": "fuzzing"
260275
},
276+
{
277+
"name": "smt-verification",
278+
"inherits": "clang16",
279+
"configurePreset": "smt-verification"
280+
},
261281
{
262282
"name": "coverage",
263283
"inherits": "default",

circuits/cpp/barretenberg/cpp/src/CMakeLists.txt

+7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ endif()
3939

4040
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/msgpack-c/include)
4141

42+
4243
# I feel this should be limited to ecc, however it's currently used in headers that go across libraries,
4344
# and there currently isn't an easy way to inherit the DDISABLE_SHENANIGANS parameter.
4445
if(DISABLE_ASM)
@@ -69,6 +70,12 @@ add_subdirectory(barretenberg/wasi)
6970
add_subdirectory(barretenberg/grumpkin_srs_gen)
7071
add_subdirectory(barretenberg/bb)
7172

73+
74+
if(SMT)
75+
include_directories(${CMAKE_CURRENT_SOURCE_DIR} $ENV{HOME}/cvc5/tmp-lib/include)
76+
add_subdirectory(barretenberg/smt_verification)
77+
endif()
78+
7279
if(BENCHMARKS)
7380
add_subdirectory(barretenberg/benchmark)
7481
endif()

circuits/cpp/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp

+99
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
#include "barretenberg/ecc/curves/bn254/fr.hpp"
44
#include "barretenberg/proof_system/arithmetization/arithmetization.hpp"
55
#include "barretenberg/proof_system/arithmetization/gate_data.hpp"
6+
#include "barretenberg/serialize/cbind.hpp"
67
#include <utility>
78

9+
#include <unordered_map>
10+
811
namespace proof_system {
912
static constexpr uint32_t DUMMY_TAG = 0;
1013

@@ -26,6 +29,8 @@ template <typename Arithmetization> class CircuitBuilderBase {
2629

2730
std::vector<uint32_t> public_inputs;
2831
std::vector<FF> variables;
32+
std::unordered_map<uint32_t, std::string> variable_names;
33+
2934
// index of next variable in equivalence class (=REAL_VARIABLE if you're last)
3035
std::vector<uint32_t> next_var_index;
3136
// index of previous variable in equivalence class (=FIRST if you're in a cycle alone)
@@ -57,6 +62,7 @@ template <typename Arithmetization> class CircuitBuilderBase {
5762
: selector_names_(std::move(selector_names))
5863
{
5964
variables.reserve(size_hint * 3);
65+
variable_names.reserve(size_hint * 3);
6066
next_var_index.reserve(size_hint * 3);
6167
prev_var_index.reserve(size_hint * 3);
6268
real_variable_index.reserve(size_hint * 3);
@@ -187,6 +193,99 @@ template <typename Arithmetization> class CircuitBuilderBase {
187193
real_variable_tags.emplace_back(DUMMY_TAG);
188194
return index;
189195
}
196+
197+
/**
198+
* Assign a name to a variable(equivalence class). Should be one name per equivalence class.
199+
*
200+
* @param index Index of the variable you want to name.
201+
* @param name Name of the variable.
202+
*
203+
*/
204+
virtual void set_variable_name(uint32_t index, const std::string& name)
205+
{
206+
ASSERT(variables.size() > index);
207+
uint32_t first_idx = get_first_variable_in_class(index);
208+
209+
if (variable_names.contains(first_idx)) {
210+
failure("Attempted to assign a name to a variable that already has a name");
211+
return;
212+
}
213+
variable_names.insert({ first_idx, name });
214+
}
215+
216+
/**
217+
* After assert_equal() merge two class names if present.
218+
* Preserves the first name in class.
219+
*
220+
* @param index Index of the variable you have previously named and used in assert_equal.
221+
*
222+
*/
223+
virtual void update_variable_names(uint32_t index)
224+
{
225+
uint32_t first_idx = get_first_variable_in_class(index);
226+
227+
uint32_t cur_idx = next_var_index[first_idx];
228+
while (cur_idx != REAL_VARIABLE && !variable_names.contains(cur_idx)) {
229+
cur_idx = next_var_index[cur_idx];
230+
}
231+
232+
if (variable_names.contains(first_idx)) {
233+
if (cur_idx != REAL_VARIABLE) {
234+
variable_names.extract(cur_idx);
235+
}
236+
return;
237+
}
238+
239+
if (cur_idx != REAL_VARIABLE) {
240+
std::string var_name = variable_names.find(cur_idx)->second;
241+
variable_names.erase(cur_idx);
242+
variable_names.insert({ first_idx, var_name });
243+
return;
244+
}
245+
failure("No previously assigned names found");
246+
}
247+
248+
/**
249+
* After finishing the circuit can be called for automatic merging
250+
* all existing collisions.
251+
*
252+
*/
253+
virtual void finalize_variable_names()
254+
{
255+
std::vector<uint32_t> keys;
256+
std::vector<uint32_t> firsts;
257+
258+
for (auto& tup : variable_names) {
259+
keys.push_back(tup.first);
260+
firsts.push_back(get_first_variable_in_class(tup.first));
261+
}
262+
263+
for (size_t i = 0; i < keys.size() - 1; i++) {
264+
for (size_t j = i + 1; j < keys.size(); i++) {
265+
uint32_t first_idx_a = firsts[i];
266+
uint32_t first_idx_b = firsts[j];
267+
if (first_idx_a == first_idx_b) {
268+
std::string substr1 = variable_names[keys[i]];
269+
std::string substr2 = variable_names[keys[j]];
270+
failure("Variables from the same equivalence class have separate names: " + substr2 + ", " +
271+
substr2);
272+
update_variable_names(first_idx_b);
273+
}
274+
}
275+
}
276+
}
277+
278+
/**
279+
* Export the existing circuit as msgpack compatible buffer.
280+
*
281+
* @return msgpack compatible buffer
282+
*/
283+
virtual msgpack::sbuffer export_circuit()
284+
{
285+
info("not implemented");
286+
return { 0 };
287+
};
288+
190289
/**
191290
* Add a public variable to variables
192291
*

circuits/cpp/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.cpp

+53
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
#include <unordered_map>
55
#include <unordered_set>
66

7+
#include "barretenberg/serialize/cbind.hpp"
8+
#include "barretenberg/serialize/msgpack.hpp"
9+
710
using namespace barretenberg;
811

912
namespace proof_system {
@@ -507,6 +510,56 @@ template <typename FF> bool StandardCircuitBuilder_<FF>::check_circuit()
507510
}
508511
return true;
509512
}
513+
514+
/**
515+
* Export the existing circuit as msgpack compatible buffer.
516+
*
517+
* @return msgpack compatible buffer
518+
*/
519+
template <typename FF> msgpack::sbuffer StandardCircuitBuilder_<FF>::export_circuit()
520+
{
521+
using base = CircuitBuilderBase<arithmetization::Standard<FF>>;
522+
CircuitSchema cir;
523+
524+
uint64_t modulus[4] = {FF::Params::modulus_0, FF::Params::modulus_1, FF::Params::modulus_2, FF::Params::modulus_3};
525+
std::stringstream buf;
526+
buf << std::hex << std::setfill('0')
527+
<< std::setw(16) << modulus[3]
528+
<< std::setw(16) << modulus[2]
529+
<< std::setw(16) << modulus[1]
530+
<< std::setw(16) << modulus[0];
531+
532+
cir.modulus = buf.str();
533+
534+
for (uint32_t i = 0; i < this->get_num_public_inputs(); i++) {
535+
cir.public_inps.push_back(this->real_variable_index[this->public_inputs[i]]);
536+
}
537+
538+
for (auto& tup : base::variable_names) {
539+
cir.vars_of_interest.insert({ this->real_variable_index[tup.first], tup.second });
540+
}
541+
542+
for (auto var : this->variables) {
543+
cir.variables.push_back(var);
544+
}
545+
546+
for (size_t i = 0; i < this->num_gates; i++) {
547+
std::vector<FF> tmp_sel = { q_m[i], q_1[i], q_2[i], q_3[i], q_c[i] };
548+
std::vector<uint32_t> tmp_w = {
549+
this->real_variable_index[w_l[i]],
550+
this->real_variable_index[w_r[i]],
551+
this->real_variable_index[w_o[i]],
552+
};
553+
cir.selectors.push_back(tmp_sel);
554+
cir.wires.push_back(tmp_w);
555+
}
556+
557+
msgpack::sbuffer buffer;
558+
msgpack::pack(buffer, cir);
559+
return buffer;
560+
}
561+
510562
template class StandardCircuitBuilder_<barretenberg::fr>;
511563
template class StandardCircuitBuilder_<grumpkin::fr>;
564+
512565
} // namespace proof_system

circuits/cpp/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp

+13
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,19 @@ template <typename FF> class StandardCircuitBuilder_ : public CircuitBuilderBase
113113
size_t get_num_constant_gates() const override { return 0; }
114114

115115
bool check_circuit();
116+
117+
msgpack::sbuffer export_circuit() override;
118+
119+
private:
120+
struct CircuitSchema {
121+
std::string modulus;
122+
std::vector<uint32_t> public_inps;
123+
std::unordered_map<uint32_t, std::string> vars_of_interest;
124+
std::vector<FF> variables;
125+
std::vector<std::vector<FF>> selectors;
126+
std::vector<std::vector<uint32_t>> wires;
127+
MSGPACK_FIELDS(modulus, public_inps, vars_of_interest, variables, selectors, wires);
128+
} circuit_schema;
116129
};
117130

118131
extern template class StandardCircuitBuilder_<barretenberg::fr>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#barretenberg_module(smt_verification common ${CMAKE_SOURCE_DIR}/src/cvc5/tmp-lib/lib/libcvc5.so.1)
2+
barretenberg_module(smt_verification common proof_system stdlib_primitives $ENV{HOME}/cvc5/tmp-lib/lib/libcvc5.so.1)

0 commit comments

Comments
 (0)