Skip to content

Commit f02123d

Browse files
SarkoxedRumata888
andauthored
feat: SMT verification module updates (#13551)
This pr mostly consists of code refactoring/renames ## Cmake `cvc5` build is now multi-threaded ## Circuit Builders `CircuitBuilderBase` - added `circuit_finalized` into msgpack schema `UltraCircuitBuilder` - zero is now force renamed during circuit export ## smt_subcircuits switched `0xabbba` to `0` since it produced failures duirng circuit creations ## Solver - Added new method `get` and `operator[]`. These two methods extract the value of the variable from solver. Added a test - fixed the incorrectly placed `BITVECTOR_UDIV` - renamed `getValue` to `get_symbolic_value` to avoid confusion ## Terms - New constructor, based on `bb::fr` value - Got rid of `isFiniteField` like members. Useless - Added `normalize` method, for more readability - Refactored the operators ## SMT_Util - add `is_signed` flag in `string_to_fr()` to avoid overflows ## Tests For most part it's either a rename, engine switch or new `operator[]` refactoring Also - fixed an incorrect `extract_bit` test - All the current changes are reflected in `README.md` --------- Co-authored-by: Innokentii Sennovskii <[email protected]>
1 parent 70c58ab commit f02123d

23 files changed

+426
-396
lines changed

barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ ExternalProject_Add(
1313
GIT_TAG main
1414
BUILD_IN_SOURCE YES
1515
CONFIGURE_COMMAND ${SHELL} ./configure.sh production --gpl --auto-download --cocoa --cryptominisat --kissat -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ --prefix=${CVC5_BUILD}
16-
BUILD_COMMAND make -C build
16+
BUILD_COMMAND make -C build -j8
1717
INSTALL_COMMAND make -C build install
1818
UPDATE_COMMAND "" # No update step
1919
# needed by ninja

barretenberg/cpp/src/barretenberg/smt_verification/README.md

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Then just build with `smt-verification` preset.
1212

1313
- ```set_variable_name(u32 index, str name)``` - assignes a name to a variable. Specifically, binds a name with the first index of an equivalence class.
1414

15-
**!Note that you don't have to name a zero or one(in standard). It has the name `zero` by default.**
15+
**!NOTE that somtimes you may encounter variables that are set to be `assert_equal` to `zero`. Their name will be erased no matter what first variable in class says.**
1616

1717
- ```update_variable_names(u32 idx)``` - in case you've called ```assert_equal``` and ```update_real_variable_indices``` somewhere and you know that two or more variables from the equivalence class have separate names, call this method. Idx is the index of one of the variables of this class. The name of the first variable in class will remain.
1818

@@ -179,8 +179,14 @@ To store it on the disk just do the following
179179
After generating all the constrains you should call `bool res = solver.check()` and depending on your goal it could be `true` or `false`.
180180

181181
In case you expected `false` but `true` was returned you can then check what went wrong.
182-
You should generate an unordered map with `str->term` values and ask the solver to obtain `unoredered_map<str, str> res = solver.model(unordered_map<str, FFTerm> terms)`.
183-
Or you can provide a vector of terms that you want to check and the return map will contain their symbolic names that are given during initialization. Specifically either it's the name that you set or `var_{i}`.
182+
You have three choices:
183+
- You can access each of the terms directly by calling `solver[term]`, or `solver.get(term)`
184+
- You can generate an unordered map with `str->term` values and ask the solver to obtain `unordered_map<str, str> res = solver.model(unordered_map<str, FFTerm> terms)`.
185+
- You can generate a vector of terms and pass them to `unordered_map<str, str> res = solver.model(vector<FFTerm> terms)`. In this case the mapping name will be taken directly from solver. Specifically either it's the name that you have set or `var_{i}`.
186+
187+
**!Note that the resulting values are strings and you can't use them to generate further constraints.**
188+
In case you want such a behavior use `sym_val = solver.get_value(term)`
189+
You can then create `STerm(sym_val, &solver, Type)` and use it in operations as a constant
184190

185191
Now you have the values of the specified terms, which resulted into `true` result.
186192
**!Note that the return values are decimal strings/binary strings**, so if you want to use them later you should use `FFConst` with base 10, etc.
@@ -246,7 +252,28 @@ Besides already mentioned `smt_timer`, `default_model` and `default_model_single
246252
```
247253
Where `add_unique_output` is a witness obtained by the solver.
248254
249-
## 6. Simple examples
255+
## 6. Tests
256+
257+
Avalaible test suits in `smt_verification_tests`:
258+
259+
- `Solver*`
260+
---
261+
262+
- `FFTerm*`
263+
- `FFITerm*`
264+
- `ITerm*`
265+
- `BVTerm*`
266+
---
267+
268+
- `Subcircuits*`
269+
- `Standard_circuit*`
270+
- `Ultra_circuit*`
271+
---
272+
273+
- `SMT_Example*`
274+
- `Polynomial_evaluation*`
275+
276+
## 7. Simple examples
250277
251278
### Function Equality
252279
```cpp

barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit_schema.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ struct CircuitSchema {
4343
real_variable_index,
4444
lookup_tables,
4545
real_variable_tags,
46-
range_tags);
46+
range_tags,
47+
circuit_finalized);
4748
};
4849

4950
CircuitSchema unpack_from_buffer(const msgpack::sbuffer& buf);

barretenberg/cpp/src/barretenberg/smt_verification/circuit/standard_circuit.test.cpp

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ using namespace bb;
1515
using namespace smt_circuit;
1616

1717
namespace {
18-
auto& engine = numeric::get_debug_randomness();
18+
auto& engine = numeric::get_randomness();
1919
}
2020

2121
using field_t = stdlib::field_t<StandardCircuitBuilder>;
2222
using witness_t = stdlib::witness_t<StandardCircuitBuilder>;
2323
using pub_witness_t = stdlib::public_witness_t<StandardCircuitBuilder>;
2424
using uint_ct = stdlib::uint32<StandardCircuitBuilder>;
2525

26-
TEST(standard_circuit, assert_equal)
26+
TEST(Standard_circuit, assert_equal)
2727
{
2828
StandardCircuitBuilder builder = StandardCircuitBuilder();
2929

@@ -62,7 +62,7 @@ TEST(standard_circuit, assert_equal)
6262
ASSERT_EQ(circuit[i.get_witness_index()].term, circuit[j.get_witness_index()].term);
6363
}
6464

65-
TEST(standard_circuit, cached_subcircuits)
65+
TEST(Standard_circuit, cached_subcircuits)
6666
{
6767
StandardCircuitBuilder builder = StandardCircuitBuilder();
6868
field_t a(witness_t(&builder, fr::zero()));
@@ -75,11 +75,11 @@ TEST(standard_circuit, cached_subcircuits)
7575
auto buf = builder.export_circuit();
7676
CircuitSchema circuit_info = unpack_from_buffer(buf);
7777
Solver s(circuit_info.modulus);
78-
StandardCircuit circuit(circuit_info, &s, TermType::FFITerm);
78+
StandardCircuit circuit(circuit_info, &s, TermType::BVTerm);
7979
s.print_assertions();
8080
}
8181

82-
TEST(standard_circuit, range_relaxation_assertions)
82+
TEST(Standard_circuit, range_relaxation_assertions)
8383
{
8484
StandardCircuitBuilder builder = StandardCircuitBuilder();
8585
field_t a(witness_t(&builder, fr(120)));
@@ -100,7 +100,7 @@ TEST(standard_circuit, range_relaxation_assertions)
100100
s.print_assertions();
101101
}
102102

103-
TEST(standard_circuit, range_relaxation)
103+
TEST(Standard_circuit, range_relaxation)
104104
{
105105
for (size_t i = 2; i < 256; i++) {
106106
StandardCircuitBuilder builder = StandardCircuitBuilder();
@@ -110,11 +110,11 @@ TEST(standard_circuit, range_relaxation)
110110
auto buf = builder.export_circuit();
111111
CircuitSchema circuit_info = unpack_from_buffer(buf);
112112
Solver s(circuit_info.modulus);
113-
StandardCircuit circuit(circuit_info, &s, TermType::FFITerm);
113+
StandardCircuit circuit(circuit_info, &s, TermType::BVTerm);
114114
}
115115
}
116116

117-
TEST(standard_circuit, xor_relaxation_assertions)
117+
TEST(Standard_circuit, xor_relaxation_assertions)
118118
{
119119
StandardCircuitBuilder builder = StandardCircuitBuilder();
120120
uint_ct a(witness_t(&builder, static_cast<uint32_t>(fr(120))));
@@ -132,7 +132,7 @@ TEST(standard_circuit, xor_relaxation_assertions)
132132
s.print_assertions();
133133
}
134134

135-
TEST(standard_circuit, xor_relaxation)
135+
TEST(Standard_circuit, xor_relaxation)
136136
{
137137
for (size_t i = 2; i < 256; i += 2) {
138138
StandardCircuitBuilder builder = StandardCircuitBuilder();
@@ -147,7 +147,7 @@ TEST(standard_circuit, xor_relaxation)
147147
}
148148
}
149149

150-
TEST(standard_circuit, and_relaxation_assertions)
150+
TEST(Standard_circuit, and_relaxation_assertions)
151151
{
152152
StandardCircuitBuilder builder = StandardCircuitBuilder();
153153
uint_ct a(witness_t(&builder, static_cast<uint32_t>(fr(120))));
@@ -165,7 +165,7 @@ TEST(standard_circuit, and_relaxation_assertions)
165165
s.print_assertions();
166166
}
167167

168-
TEST(standard_circuit, ror_relaxation_assertions)
168+
TEST(Standard_circuit, ror_relaxation_assertions)
169169
{
170170
StandardCircuitBuilder builder = StandardCircuitBuilder();
171171
uint_ct a(witness_t(&builder, static_cast<uint32_t>(fr(120))));
@@ -181,7 +181,7 @@ TEST(standard_circuit, ror_relaxation_assertions)
181181
s.print_assertions();
182182
}
183183

184-
TEST(standard_circuit, ror_relaxation)
184+
TEST(Standard_circuit, ror_relaxation)
185185
{
186186
for (size_t i = 1; i < 8; i++) {
187187
using uint_ct = stdlib::uint8<StandardCircuitBuilder>;
@@ -229,7 +229,7 @@ TEST(standard_circuit, ror_relaxation)
229229
}
230230
}
231231

232-
TEST(standard_circuit, shl_relaxation_assertions)
232+
TEST(Standard_circuit, shl_relaxation_assertions)
233233
{
234234
StandardCircuitBuilder builder = StandardCircuitBuilder();
235235
uint_ct a(witness_t(&builder, static_cast<uint32_t>(fr(120))));
@@ -245,7 +245,7 @@ TEST(standard_circuit, shl_relaxation_assertions)
245245
s.print_assertions();
246246
}
247247

248-
TEST(standard_circuit, shl_relaxation)
248+
TEST(Standard_circuit, shl_relaxation)
249249
{
250250
for (size_t i = 1; i < 8; i++) {
251251
using uint_ct = stdlib::uint8<StandardCircuitBuilder>;
@@ -293,7 +293,7 @@ TEST(standard_circuit, shl_relaxation)
293293
}
294294
}
295295

296-
TEST(standard_circuit, shr_relaxation_assertions)
296+
TEST(Standard_circuit, shr_relaxation_assertions)
297297
{
298298
StandardCircuitBuilder builder = StandardCircuitBuilder();
299299
uint_ct a(witness_t(&builder, static_cast<uint32_t>(fr(120))));
@@ -309,7 +309,7 @@ TEST(standard_circuit, shr_relaxation_assertions)
309309
s.print_assertions();
310310
}
311311

312-
TEST(standard_circuit, shr_relaxation)
312+
TEST(Standard_circuit, shr_relaxation)
313313
{
314314
for (size_t i = 1; i < 8; i += 2) {
315315
using uint_ct = stdlib::uint8<StandardCircuitBuilder>;
@@ -357,7 +357,7 @@ TEST(standard_circuit, shr_relaxation)
357357
}
358358
}
359359

360-
TEST(standard_circuit, check_double_xor_bug)
360+
TEST(Standard_circuit, check_double_xor_bug)
361361
{
362362
StandardCircuitBuilder builder;
363363
uint_ct a = witness_t(&builder, 10);
@@ -379,7 +379,7 @@ TEST(standard_circuit, check_double_xor_bug)
379379

380380
// Check that witness provided by the solver is the same as builder's witness
381381
// Check that all the optimized out values are initialized and computed properly during post proccessing
382-
TEST(standard_circuit, optimized_range_witness)
382+
TEST(Standard_circuit, optimized_range_witness)
383383
{
384384
uint32_t rbit = engine.get_random_uint8() & 1;
385385
uint32_t num_bits = 32 + rbit;
@@ -398,7 +398,7 @@ TEST(standard_circuit, optimized_range_witness)
398398

399399
bool res = smt_timer(&s);
400400
ASSERT_TRUE(res);
401-
auto model_witness = default_model_single({ "a" }, circuit, "optimized_range_check.out");
401+
auto model_witness = default_model_single({ "a" }, circuit, "tmp.out");
402402

403403
ASSERT_EQ(model_witness.size(), builder.get_num_variables());
404404
for (size_t i = 0; i < model_witness.size(); i++) {
@@ -408,7 +408,7 @@ TEST(standard_circuit, optimized_range_witness)
408408

409409
// Check that witness provided by the solver is the same as builder's witness
410410
// Check that all the optimized out values are initialized and computed properly during post proccessing
411-
TEST(standard_circuit, optimized_logic_witness)
411+
TEST(Standard_circuit, optimized_logic_witness)
412412
{
413413
StandardCircuitBuilder builder;
414414
uint_ct a = witness_t(&builder, engine.get_random_uint32());
@@ -429,7 +429,7 @@ TEST(standard_circuit, optimized_logic_witness)
429429

430430
bool res = smt_timer(&s);
431431
ASSERT_TRUE(res);
432-
auto model_witness = default_model_single({ "a", "b", "c", "d" }, circuit, "optimized_xor_check.out");
432+
auto model_witness = default_model_single({ "a", "b", "c", "d" }, circuit, "tmp.out");
433433

434434
ASSERT_EQ(model_witness.size(), builder.get_num_variables());
435435
for (size_t i = 0; i < model_witness.size(); i++) {
@@ -439,7 +439,7 @@ TEST(standard_circuit, optimized_logic_witness)
439439

440440
// Check that witness provided by the solver is the same as builder's witness
441441
// Check that all the optimized out values are initialized and computed properly during post proccessing
442-
TEST(standard_circuit, optimized_shr_witness)
442+
TEST(Standard_circuit, optimized_shr_witness)
443443
{
444444
StandardCircuitBuilder builder;
445445
uint_ct a = witness_t(&builder, engine.get_random_uint32());
@@ -456,7 +456,7 @@ TEST(standard_circuit, optimized_shr_witness)
456456
circuit["a"] == a.get_value();
457457
bool res = smt_timer(&s);
458458
ASSERT_TRUE(res);
459-
auto model_witness = default_model_single({ "a" }, circuit, "optimized_xor_check.out");
459+
auto model_witness = default_model_single({ "a" }, circuit, "tmp.out");
460460

461461
ASSERT_EQ(model_witness.size(), builder.get_num_variables());
462462
for (size_t i = 0; i < model_witness.size(); i++) {
@@ -466,7 +466,7 @@ TEST(standard_circuit, optimized_shr_witness)
466466

467467
// Check that witness provided by the solver is the same as builder's witness
468468
// Check that all the optimized out values are initialized and computed properly during post proccessing
469-
TEST(standard_circuit, optimized_shl_witness)
469+
TEST(Standard_circuit, optimized_shl_witness)
470470
{
471471
StandardCircuitBuilder builder;
472472
uint_ct a = witness_t(&builder, engine.get_random_uint32());
@@ -483,7 +483,7 @@ TEST(standard_circuit, optimized_shl_witness)
483483
circuit[a.get_witness_index()] == a.get_value();
484484
bool res = smt_timer(&s);
485485
ASSERT_TRUE(res);
486-
auto model_witness = default_model_single({ "a" }, circuit, "optimized_xor_check.out");
486+
auto model_witness = default_model_single({ "a" }, circuit, "tmp.out");
487487

488488
ASSERT_EQ(model_witness.size(), builder.get_num_variables());
489489
for (size_t i = 0; i < model_witness.size(); i++) {
@@ -493,7 +493,7 @@ TEST(standard_circuit, optimized_shl_witness)
493493

494494
// Check that witness provided by the solver is the same as builder's witness
495495
// Check that all the optimized out values are initialized and computed properly during post proccessing
496-
TEST(standard_circuit, optimized_ror_witness)
496+
TEST(Standard_circuit, optimized_ror_witness)
497497
{
498498
StandardCircuitBuilder builder;
499499
uint_ct a = witness_t(&builder, engine.get_random_uint32());
@@ -510,10 +510,10 @@ TEST(standard_circuit, optimized_ror_witness)
510510
circuit[a.get_witness_index()] == a.get_value();
511511
bool res = smt_timer(&s);
512512
ASSERT_TRUE(res);
513-
auto model_witness = default_model_single({ "a" }, circuit, "optimized_xor_check.out");
513+
auto model_witness = default_model_single({ "a" }, circuit, "tmp.out");
514514

515515
ASSERT_EQ(model_witness.size(), builder.get_num_variables());
516516
for (size_t i = 0; i < model_witness.size(); i++) {
517517
EXPECT_EQ(model_witness[i], builder.variables[i]);
518518
}
519-
}
519+
}

barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace smt_subcircuits {
55
CircuitProps get_standard_range_constraint_circuit(size_t n)
66
{
77
bb::StandardCircuitBuilder builder = bb::StandardCircuitBuilder();
8-
uint32_t a_idx = builder.add_variable(bb::fr(0xabbba));
8+
uint32_t a_idx = builder.add_variable(bb::fr(0));
99
builder.set_variable_name(a_idx, "a");
1010

1111
size_t start_gate = builder.get_estimated_num_finalized_gates();

barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.test.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,9 @@
1010

1111
using namespace bb;
1212

13-
namespace {
14-
auto& engine = numeric::get_debug_randomness();
15-
}
16-
1713
// Check that all the relative offsets are calculated correctly.
1814
// I.e. I can find an operand at the index, given by get_standard_range_constraint_circuit
19-
TEST(subcircuits, range_circuit)
15+
TEST(Subcircuits, range_circuit)
2016
{
2117
for (size_t i = 1; i < 255; i++) {
2218
smt_subcircuits::CircuitProps range_props = smt_subcircuits::get_standard_range_constraint_circuit(i);
@@ -42,7 +38,7 @@ TEST(subcircuits, range_circuit)
4238
}
4339
// Check that all the relative offsets are calculated correctly.
4440
// I.e. I can find all three operands at the indices, given by get_standard_logic_circuit
45-
TEST(subcircuits, logic_circuit)
41+
TEST(Subcircuits, logic_circuit)
4642
{
4743
for (size_t i = 2; i < 256; i += 2) {
4844
smt_subcircuits::CircuitProps logic_props = smt_subcircuits::get_standard_logic_circuit(i, true);
@@ -71,7 +67,7 @@ TEST(subcircuits, logic_circuit)
7167

7268
// Check that all the relative offsets are calculated correctly.
7369
// I.e. I can find all three operands at the indices, given by get_standard_logic_circuit
74-
TEST(subcircuits, ror_circuit)
70+
TEST(Subcircuits, ror_circuit)
7571
{
7672
for (uint32_t r = 1; r < 8; r += 1) {
7773
unsigned char n = 8;
@@ -149,7 +145,7 @@ TEST(subcircuits, ror_circuit)
149145

150146
// Check that all the relative offsets are calculated correctly.
151147
// I.e. I can find all three operands at the indices, given by get_standard_logic_circuit
152-
TEST(subcircuits, shl_circuit)
148+
TEST(Subcircuits, shl_circuit)
153149
{
154150
for (uint32_t r = 1; r < 8; r += 1) {
155151
unsigned char n = 8;
@@ -230,7 +226,7 @@ TEST(subcircuits, shl_circuit)
230226
// I can't check the position of the lhs here, since shr doesn't use the witness directly but
231227
// it's accumulators.
232228
// However, according to standard_circuit test they seem fine.
233-
TEST(subcircuits, shr_circuit)
229+
TEST(Subcircuits, shr_circuit)
234230
{
235231
for (uint32_t r = 1; r < 8; r += 2) {
236232
unsigned char n = 8;

0 commit comments

Comments
 (0)