From 382ecff12053b3e4564f8fd1db884bff1b5f074c Mon Sep 17 00:00:00 2001 From: Iluvmagick Date: Wed, 9 Oct 2024 01:20:45 +0400 Subject: [PATCH] 63 move excalibur to this repository (#71) * Updated excalibur to work with the main repo. * Updated excalibur to consume proof system output format. * Moved excalibur to debug-tools. --- .envrc | 1 + .gitignore | 1 + crypto3/crypto3.nix | 5 +- debug-tools/CMakeLists.txt | 3 +- debug-tools/bin/excalibur/CMakeLists.txt | 5 + debug-tools/bin/excalibur/README.md | 33 + debug-tools/bin/excalibur/schema-locator.sh | 3 + debug-tools/bin/excalibur/src/CMakeLists.txt | 75 + debug-tools/bin/excalibur/src/main.cpp | 165 +++ debug-tools/bin/excalibur/src/parsers.hpp | 327 +++++ debug-tools/bin/excalibur/src/table.hpp | 1307 ++++++++++++++++++ debug-tools/debug-tools.nix | 26 +- evm-assigner/evm-assigner.nix | 5 +- flake.nix | 4 +- parallel-crypto3/parallel-crypto3.nix | 5 +- proof-producer/proof-producer.nix | 5 +- transpiler/transpiler.nix | 44 + zkevm-framework/zkevm-framework.nix | 5 +- 18 files changed, 2005 insertions(+), 14 deletions(-) create mode 100644 .envrc create mode 100644 debug-tools/bin/excalibur/CMakeLists.txt create mode 100644 debug-tools/bin/excalibur/README.md create mode 100755 debug-tools/bin/excalibur/schema-locator.sh create mode 100644 debug-tools/bin/excalibur/src/CMakeLists.txt create mode 100644 debug-tools/bin/excalibur/src/main.cpp create mode 100644 debug-tools/bin/excalibur/src/parsers.hpp create mode 100644 debug-tools/bin/excalibur/src/table.hpp create mode 100644 transpiler/transpiler.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000..8392d159f2 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake \ No newline at end of file diff --git a/.gitignore b/.gitignore index cd6a5735a7..6655d0051b 100644 --- a/.gitignore +++ b/.gitignore @@ -353,6 +353,7 @@ compile_commands.json CTestTestfile.cmake build result +CheckSSE.cmake ### LaTeX ### ## Core latex/pdflatex auxiliary files: diff --git a/crypto3/crypto3.nix b/crypto3/crypto3.nix index 7494015b8b..612aac97ab 100644 --- a/crypto3/crypto3.nix +++ b/crypto3/crypto3.nix @@ -5,6 +5,7 @@ cmake, boost, gdb, + lldb, cmake_modules, enableDebugging, enableDebug ? false, @@ -18,7 +19,9 @@ in stdenv.mkDerivation { src = lib.sourceByRegex ./. [ ".*" ]; - nativeBuildInputs = [ cmake ninja pkg-config ] ++ (lib.optional (!stdenv.isDarwin) gdb); + nativeBuildInputs = [ cmake ninja pkg-config ] ++ + (lib.optional (!stdenv.isDarwin) gdb) ++ + (lib.optional (stdenv.isDarwin) lldb); # enableDebugging will keep debug symbols in boost propagatedBuildInputs = [ (if enableDebug then (enableDebugging boost) else boost) ]; diff --git a/debug-tools/CMakeLists.txt b/debug-tools/CMakeLists.txt index 2fe1bdd264..2271eec703 100644 --- a/debug-tools/CMakeLists.txt +++ b/debug-tools/CMakeLists.txt @@ -39,7 +39,7 @@ endif () # If Nix is used, LSP could not guess the locations of implicit include # directories, so we need to include them explicitly. if(CMAKE_EXPORT_COMPILE_COMMANDS) - set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES + set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) endif() @@ -85,6 +85,7 @@ endif() set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/bin/circgen") +add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/bin/excalibur") include(CPack) diff --git a/debug-tools/bin/excalibur/CMakeLists.txt b/debug-tools/bin/excalibur/CMakeLists.txt new file mode 100644 index 0000000000..6138a9a66c --- /dev/null +++ b/debug-tools/bin/excalibur/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.21 FATAL_ERROR) + +project(excalibur-gui) + +add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/src/") diff --git a/debug-tools/bin/excalibur/README.md b/debug-tools/bin/excalibur/README.md new file mode 100644 index 0000000000..a184a30489 --- /dev/null +++ b/debug-tools/bin/excalibur/README.md @@ -0,0 +1,33 @@ +A simple circuit visualizer for Placeholder proof system. + +# Building and running +1. Do a `nix develop .#debug-test-tools` in the main placeholder directory +2. Run `eval $configurePhase` in debug-tools directory +3. `ninja excalibur` +4. If you encounter an error while trying to open a file, you need to compile the GTK schema used in the dialog, and link the environment variable. In order to do that, find you gtk installation in `/nix/store/`. + +The best way of doing this is via `nix-locate org.gtk.gtk4.Settings.FileChooser.gschema.xml` if you have [nix-index](https://github.com/nix-community/nix-index) installed. + +Alternatively, run `schema-locator.sh`. If you have multiple versions of gtk4 in the store, use the latest one. + +After finding the file, run `glib-compile-schemas --targetdir=. /path/to/schema/directory`. +Note that you need to pass *directory*, and not the file path. +This should create `gschemas.compiled` file in current (build) directory. + +Export the `gschemas.compiled` directory via `export GSETTINGS_SCHEMA_DIR=/path/to/compiled/schema/dir`. + +Run `./bin/excalibur/src/excalibur --vesta` (or `--pallas`, or one of the other supporting curves). + +# FAQ +I get the following error while running the tool: +``` +(excalibur:24987): GLib-GIO-ERROR **: 18:39:52.016: Settings schema 'org.gtk.gtk4.Settings.FileChooser' is not installed +Trace/breakpoint trap +``` +Check that you've done step 4 above. Export has to be redone each shell session, unless you modify `.bashrc` or do something similar. + +How do I export my circuit/assignment table from blueprint? + +Use the functions in "test_plonk_component.hpp" + +Lookup constraints support is not implemented yet. diff --git a/debug-tools/bin/excalibur/schema-locator.sh b/debug-tools/bin/excalibur/schema-locator.sh new file mode 100755 index 0000000000..9ff14b6bc9 --- /dev/null +++ b/debug-tools/bin/excalibur/schema-locator.sh @@ -0,0 +1,3 @@ +for dir in $(ls /nix/store | grep gtk4); do + find /nix/store/$dir -name "org.gtk.gtk4.Settings.FileChooser.gschema.xml" +done diff --git a/debug-tools/bin/excalibur/src/CMakeLists.txt b/debug-tools/bin/excalibur/src/CMakeLists.txt new file mode 100644 index 0000000000..a52dca836b --- /dev/null +++ b/debug-tools/bin/excalibur/src/CMakeLists.txt @@ -0,0 +1,75 @@ +cmake_minimum_required(VERSION 3.21) + +set(CMAKE_EXPORT_COMPILE_COMMANDS true) + +message (STATUS "PKG_CONFIG_PATH=$ENV{PKG_CONFIG_PATH}") + +# get header files; only needed by CMake generators, +# expr.g., for creating proper Xcode projects +set(${CMAKE_PROJECT_NAME}_HEADERS) + +set(C3_TARGET "excalibur") + +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + add_compile_options(-pg) + link_libraries(-pg) +endif() + +# list cpp files excluding platform-dependent files +list(APPEND ${CMAKE_PROJECT_NAME}_SOURCES main.cpp) + +find_package(Boost COMPONENTS random) +find_package(PkgConfig REQUIRED) + +pkg_check_modules(GTK REQUIRED gtk4) + +if(NOT GTK_FOUND) + message(FATAL_ERROR "GTK4 not found!") +endif() + +pkg_check_modules(GTKMM REQUIRED gtkmm-4.0) + +if (NOT GTKMM_FOUND) + message(FATAL_ERROR "GTKMM not found!") +endif() + +pkg_check_modules(PANGO REQUIRED pango) + +if (NOT PANGO_FOUND) + message(FATAL_ERROR "Pango not found!") +endif() + +pkg_check_modules(PANGOMM REQUIRED pangomm-1.4) + +if(NOT PANGOMM_FOUND) + message(FATAL_ERROR "PANGOMM not found!") +endif() + +find_package(crypto3 REQUIRED) + +include_directories( + ${GTKMM_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS} ${PANGO_INCLUDE_DIRS} ${PANGOMM_INCLUDE_DIRS}) +link_directories( + ${GTKMM_LIBRARY_DIRS} ${GTK_LIBRARY_DIRS} ${PANGO_LIBRARY_DIRS} ${PANGOMM_LIBRARY_DIRS}) + +add_executable(${C3_TARGET} + ${${CMAKE_PROJECT_NAME}_HEADERS} + ${${CMAKE_PROJECT_NAME}_SOURCES}) + +set_target_properties(${C3_TARGET} PROPERTIES + LINKER_LANGUAGE CXX + EXPORT_NAME ${CMAKE_PROJECT_NAME} + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED TRUE) + +target_link_directories( + ${C3_TARGET} PRIVATE ${GTKMM_LIBRARY_DIRS} + ${GTK_LIBRARY_DIRS} ${PANGO_LIBRARY_DIRS} ${PANGOMM_LIBRARY_DIRS}) + +target_link_libraries(${C3_TARGET} + crypto3::all + ${Boost_LIBRARIES} + ${GTKMM_LIBRARIES} + ${GTK_LIBRARIES} + ${PANGOMM_LIBRARIES} + ${PANGO_LIBRARIES}) diff --git a/debug-tools/bin/excalibur/src/main.cpp b/debug-tools/bin/excalibur/src/main.cpp new file mode 100644 index 0000000000..0492566ad1 --- /dev/null +++ b/debug-tools/bin/excalibur/src/main.cpp @@ -0,0 +1,165 @@ +// MIT License +// +// Copyright (c) 2023 Dmitrii Tabalin +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "table.hpp" + +int main(int argc, char* argv[]) { + auto app = Gtk::Application::create("foundation.nil.excalibur"); + + using vesta_curve_type = nil::crypto3::algebra::curves::vesta::base_field_type; + using pallas_curve_type = nil::crypto3::algebra::curves::pallas::base_field_type; + using bls12_fr_381_curve_type = nil::crypto3::algebra::fields::bls12_fr<381>; + using bls12_fq_381_curve_type = nil::crypto3::algebra::fields::bls12_fq<381>; + using mnt4_curve_type = nil::crypto3::algebra::fields::mnt4_fq<298>; + using mnt6_curve_type = nil::crypto3::algebra::fields::mnt6_fq<298>; + using goldilocks64_field_type = nil::crypto3::algebra::fields::goldilocks64; + using bn_base_field_type = nil::crypto3::algebra::fields::alt_bn128<254>; + using bn_scalar_field_type = nil::crypto3::algebra::fields::alt_bn128_scalar_field<254>; + + Glib::OptionGroup::vecustrings main_option_vector; + Glib::OptionGroup main_group("curves", "Curves", "Curve used in the program"); + + bool vesta = false, pallas = false, bls12_fr_381 = false, bls12_fq_381 = false, + mnt4 = false, mnt6 = false, goldilocks64 = false, bn_base = false, bn_scalar = false; + Glib::OptionEntry vesta_entry, pallas_entry, bls12_fr_381_entry, bls12_fq_381_entry, + mnt4_entry, mnt6_entry, goldilocks64_entry, bn_entry; + + vesta_entry.set_long_name("vesta"); + vesta_entry.set_short_name('v'); + vesta_entry.set_description("Use Vesta curve"); + main_group.add_entry(vesta_entry, vesta); + + pallas_entry.set_long_name("pallas"); + pallas_entry.set_short_name('p'); + pallas_entry.set_description("Use Pallas curve"); + main_group.add_entry(pallas_entry, pallas); + + bls12_fr_381_entry.set_long_name("bls12_fr_381"); + bls12_fr_381_entry.set_short_name('b'); + bls12_fr_381_entry.set_description("Use BLS12_fr_381 curve"); + main_group.add_entry(bls12_fr_381_entry, bls12_fr_381); + + bls12_fq_381_entry.set_long_name("bls12_fq_381"); + bls12_fq_381_entry.set_short_name('q'); + bls12_fq_381_entry.set_description("Use BLS12_fq_381 curve"); + main_group.add_entry(bls12_fq_381_entry, bls12_fq_381); + + mnt4_entry.set_long_name("mnt4"); + mnt4_entry.set_short_name('4'); + mnt4_entry.set_description("Use mnt4 curve"); + main_group.add_entry(mnt4_entry, mnt4); + + mnt6_entry.set_long_name("mnt6"); + mnt6_entry.set_short_name('6'); + mnt6_entry.set_description("Use mnt6 curve"); + main_group.add_entry(mnt6_entry, mnt6); + + goldilocks64_entry.set_long_name("goldilocks64"); + goldilocks64_entry.set_short_name('g'); + goldilocks64_entry.set_description("Use Goldilocks64 curve"); + main_group.add_entry(goldilocks64_entry, goldilocks64); + + bn_entry.set_long_name("bn"); + bn_entry.set_short_name('n'); + bn_entry.set_description("Use BN curve base field"); + main_group.add_entry(bn_entry, bn_base); + + bn_entry.set_long_name("bn_scalar"); + bn_entry.set_short_name('s'); + bn_entry.set_description("Use BN curve scalar field"); + main_group.add_entry(bn_entry, bn_scalar); + + // Add the main group to the context + Glib::OptionContext context; + context.set_main_group(main_group); + context.set_help_enabled(true); + context.set_ignore_unknown_options(true); + context.parse(argc, argv); + + // check that only a single curve is selected + std::vector curve_selections = { + vesta, pallas, bls12_fr_381, bls12_fq_381,mnt4, mnt6, goldilocks64, + bn_base, bn_scalar}; + uint8_t curve_count = std::accumulate(curve_selections.begin(), curve_selections.end(), 0); + if (curve_count > 1) { + std::cerr << "Error: only one curve can be used at a time." << std::endl; + return 1; + } + // check that at least one curve is selected + if (curve_count == 0) { + std::cerr << "Error: no curve selected. Use --vesta or --pallas or --bls12_fr_381, or --bls12_fq_381" + << " or --mnt4 or --mnt6 or --goldilocks64, or --bn, or --bn_scalar." + << std::endl; + return 1; + } + + if (vesta) { + return app->make_window_and_run>(argc, argv); + } + if (pallas) { + return app->make_window_and_run>(argc, argv); + } + if (bls12_fr_381) { + return app->make_window_and_run>(argc, argv); + } + if (bls12_fq_381) { + return app->make_window_and_run>(argc, argv); + } + if (mnt4) { + return app->make_window_and_run>(argc, argv); + } + if (mnt6) { + return app->make_window_and_run>(argc, argv); + } + if (goldilocks64) { + return app->make_window_and_run>(argc, argv); + } + if (bn_base) { + return app->make_window_and_run>(argc, argv); + } + if (bn_scalar) { + return app->make_window_and_run>(argc, argv); + } +} diff --git a/debug-tools/bin/excalibur/src/parsers.hpp b/debug-tools/bin/excalibur/src/parsers.hpp new file mode 100644 index 0000000000..c0d3046710 --- /dev/null +++ b/debug-tools/bin/excalibur/src/parsers.hpp @@ -0,0 +1,327 @@ +// MIT License +// +// Copyright (c) 2023 Dmitrii Tabalin +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// Do #define BOOST_SPIRIT_DEBUG in table.hpp, as it also includes qi. + +#include +#include + +#include +#include +#include +#include +#include + +struct table_sizes { + uint32_t witnesses_size, + public_inputs_size, + constants_size, + selectors_size, + max_size; +}; + +BOOST_FUSION_ADAPT_STRUCT( + table_sizes, + (uint32_t, witnesses_size) + (uint32_t, public_inputs_size) + (uint32_t, constants_size) + (uint32_t, selectors_size) + (uint32_t, max_size) +) + +struct circuit_sizes { + uint32_t gates_size, + copy_constraints_size, + lookup_gates_size; +}; + +BOOST_FUSION_ADAPT_STRUCT( + circuit_sizes, + (uint32_t, gates_size) + (uint32_t, copy_constraints_size) + (uint32_t, lookup_gates_size) +) + +struct gate_header { + uint32_t selector_index, + constraints_size; +}; + +BOOST_FUSION_ADAPT_STRUCT( + gate_header, + (uint32_t, selector_index) + (uint32_t, constraints_size) +) + +template +struct var_constructor_impl { + using var = nil::crypto3::zk::snark::plonk_variable; + typedef var result_type; + + template + var operator()(Arg1 index, Arg2 rotation, Arg3 typed_var) const { + typed_var.index = index; + typed_var.rotation = rotation; + return typed_var; + } + +}; + +template +struct pow_constructor_impl { + using var = nil::crypto3::zk::snark::plonk_variable; + using expression = nil::crypto3::math::expression; + using pow_operation = nil::crypto3::math::pow_operation; + + typedef expression result_type; + + template + expression operator()(Arg1 base, Arg2 exponent) const { + return base.pow(exponent); + } +}; + +template +struct copy_constraint_constructor { + using var = nil::crypto3::zk::snark::plonk_variable; + using plonk_copy_constraint_type = nil::crypto3::zk::snark::plonk_copy_constraint; + + typedef plonk_copy_constraint_type result_type; + + template + plonk_copy_constraint_type operator()(Arg1 var1, Arg2 var2) const { + return plonk_copy_constraint_type(var1, var2); + } +}; + +template +struct table_sizes_parser : boost::spirit::qi::grammar { + table_sizes_parser() : table_sizes_parser::base_type(start) { + using boost::spirit::qi::uint_; + using boost::spirit::qi::lit; + using boost::phoenix::val; + using boost::phoenix::construct; + + start = lit("witnesses_size:") > uint_ > + lit("public_inputs_size:") > uint_ > + lit("constants_size:") > uint_ > + lit("selectors_size:") > uint_ > + lit("max_size:") > uint_; + + boost::spirit::qi::on_error( + start, + std::cerr << val("Error! Expecting ") << boost::spirit::qi::_4 << val(" here: \"") + << construct(boost::spirit::_3, boost::spirit::_2) << val("\"\n") + ); + } + + boost::spirit::qi::rule start; +}; + +template +struct table_row_parser : boost::spirit::qi::grammar, + boost::spirit::qi::ascii::space_type> { + table_row_parser(table_sizes sizes) : table_row_parser::base_type(start) { + using boost::spirit::qi::lit; + using boost::spirit::qi::repeat; + using boost::spirit::qi::uint_parser; + using boost::spirit::qi::uint_; + using boost::phoenix::val; + using boost::phoenix::construct; + + auto hex_rule = uint_parser(); + start = repeat(sizes.witnesses_size)[hex_rule] > lit('|') > + repeat(sizes.public_inputs_size)[hex_rule] > lit('|') > + repeat(sizes.constants_size)[hex_rule] > lit('|') > + repeat(sizes.selectors_size)[hex_rule]; + + boost::spirit::qi::on_error( + start, + std::cerr << val("Error! Expecting ") << boost::spirit::qi::_4 << val(" here: \"") + << construct(boost::spirit::_3, boost::spirit::_2) << val("\"\n") + ); + } + + boost::spirit::qi::rule, + boost::spirit::qi::ascii::space_type> start; +}; + +template +struct circuit_sizes_parser : boost::spirit::qi::grammar { + circuit_sizes_parser() : circuit_sizes_parser::base_type(start) { + using boost::spirit::qi::uint_; + using boost::spirit::qi::lit; + using boost::phoenix::val; + using boost::phoenix::construct; + + start = lit("gates_size:") > uint_ > + lit("copy_constraints_size:") > uint_ > + lit("lookup_gates_size:") > uint_; + + boost::spirit::qi::on_error( + start, + std::cerr << val("Error! Expecting ") << boost::spirit::qi::_4 << val(" here: \"") + << construct(boost::spirit::_3, boost::spirit::_2) << val("\"\n") + ); + } + + boost::spirit::qi::rule start; +}; + +template +struct gate_header_parser : boost::spirit::qi::grammar { + gate_header_parser() : gate_header_parser::base_type(start) { + using boost::spirit::qi::uint_; + using boost::spirit::qi::lit; + using boost::phoenix::val; + using boost::phoenix::construct; + + start = lit("selector:") > uint_ > lit("constraints_size:") > uint_; + + boost::spirit::qi::on_error( + start, + std::cerr << val("Error! Expecting ") << boost::spirit::qi::_4 << val(" here: \"") + << construct(boost::spirit::_3, boost::spirit::_2) << val("\"\n") + ); + } + + boost::spirit::qi::rule start; +}; + +template +struct gate_constraint_parser : boost::spirit::qi::grammar(), + boost::spirit::qi::ascii::space_type> { + using plonk_constraint_type = nil::crypto3::zk::snark::plonk_constraint; + using plonk_gate_type = nil::crypto3::zk::snark::plonk_gate; + using var = nil::crypto3::zk::snark::plonk_variable; + using term = nil::crypto3::math::term; + + gate_constraint_parser() : gate_constraint_parser::base_type(start) { + using boost::spirit::qi::uint_; + using boost::spirit::qi::int_; + using boost::spirit::qi::lit; + using boost::spirit::qi::char_; + using boost::spirit::qi::_1; + using boost::spirit::qi::_2; + using boost::spirit::qi::_3; + using boost::spirit::qi::_val; + using boost::phoenix::val; + using boost::phoenix::construct; + using boost::phoenix::function; + using boost::spirit::qi::int_parser; + + function> var_constructor; + function> pow_constructor; + auto constant = int_parser(); + variable = ((lit("w")[_val = construct(0, 0, true, var::column_type::witness)] | + lit("pub")[_val = construct(0, 0, true, var::column_type::public_input)] | + lit("c")[_val = construct(0, 0, true, var::column_type::constant)] | + lit("sel")[_val = construct(0, 0, true, var::column_type::selector)]) > + lit("_") > uint_ > -(lit("_rot(") > int_ > lit(")"))) + [_val = if_else(_2, + var_constructor(_1, *_2, _val), + var_constructor(_1, 0, _val))]; + // This is a bit confusing, as atom has the type of term. + atom = variable | constant; + expression = term_[_val = construct(_1)] + >> *(('+' > term_)[_val = _val + _1] | ('-' > term_)[_val = _val - _1]); + term_ = exponent[_val = construct(_1)] >> *(('*' > exponent)[_val = _val * _1]); + // uint_ is used here, because the expression does not support arbitrary exponents + // The pow function only takes size_t. + exponent = factor[_val = construct(_1)] + >> -(('^' > uint_)[_val = pow_constructor(_val, _1)]); + factor = atom | (lit("(") > expression > lit(")")) | (lit("-") >> factor); + start = expression; + + //BOOST_SPIRIT_DEBUG_NODES((start)(expression)(term_)(factor)(atom)(variable)); + + boost::spirit::qi::on_error( + start, + std::cerr << val("Error! Expecting ") << boost::spirit::qi::_4 << val(" here: \"") + << construct(boost::spirit::_3, boost::spirit::_2) << val("\"\n") + ); + } + + boost::spirit::qi::rule start; + boost::spirit::qi::rule atom; + boost::spirit::qi::rule variable; + boost::spirit::qi::rule constant; + boost::spirit::qi::rule expression; + boost::spirit::qi::rule factor; + boost::spirit::qi::rule exponent; + boost::spirit::qi::rule term_; +}; + +template +struct copy_constraint_parser : boost::spirit::qi::grammar(), + boost::spirit::qi::ascii::space_type> { + using plonk_copy_constraint_type = nil::crypto3::zk::snark::plonk_copy_constraint; + using var = nil::crypto3::zk::snark::plonk_variable; + + copy_constraint_parser() : copy_constraint_parser::base_type(start) { + using boost::spirit::qi::uint_; + using boost::spirit::qi::int_; + using boost::spirit::qi::lit; + using boost::spirit::qi::char_; + using boost::spirit::qi::_1; + using boost::spirit::qi::_2; + using boost::spirit::qi::_3; + using boost::spirit::qi::_val; + using boost::phoenix::val; + using boost::phoenix::construct; + using boost::phoenix::function; + using boost::spirit::qi::int_parser; + + function> var_constructor; + function> copy_constraint_constructor; + auto constant = int_parser(); + variable = ((lit("w")[_val = construct(0, 0, false, var::column_type::witness)] | + lit("pub")[_val = construct(0, 0, false, var::column_type::public_input)] | + lit("c")[_val = construct(0, 0, false, var::column_type::constant)] | + lit("sel")[_val = construct(0, 0, true, var::column_type::selector)]) > + lit("_") > uint_ > lit("_abs") > -(lit("_rot(") > int_ > lit(")"))) + [_val = if_else(_2, + var_constructor(_1, *_2, _val), + var_constructor(_1, 0, _val))]; + start = (variable > variable)[_val = copy_constraint_constructor(_1, _2)]; + + boost::spirit::qi::on_error( + start, + std::cerr << val("Error! Expecting ") << boost::spirit::qi::_4 << val(" here: \"") + << construct(boost::spirit::_3, boost::spirit::_2) << val("\"\n") + ); + } + + boost::spirit::qi::rule start; + boost::spirit::qi::rule variable; +}; \ No newline at end of file diff --git a/debug-tools/bin/excalibur/src/table.hpp b/debug-tools/bin/excalibur/src/table.hpp new file mode 100644 index 0000000000..4f93a7f7cc --- /dev/null +++ b/debug-tools/bin/excalibur/src/table.hpp @@ -0,0 +1,1307 @@ +// MIT License +// +// Copyright (c) 2023 Dmitrii Tabalin +// Copyright (c) 2024 Elena Tatuzova +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +//#define BOOST_SPIRIT_DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "parsers.hpp" + +template +std::optional> load_circuit_from_file( + Glib::RefPtr stream, + std::size_t file_size +){ + using ConstraintSystemType = nil::crypto3::zk::snark::plonk_constraint_system; + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + + ConstraintSystemType constraint_system; + { + std::vector v(file_size); + stream->read(reinterpret_cast(v.data()), file_size); + if (!stream) { + std::cerr << "Cannot parse input file: unable to read data." << std::endl; + return std::nullopt; + } + + nil::crypto3::marshalling::types::plonk_constraint_system marshalled_data; + auto read_iter = v.begin(); + auto status = marshalled_data.read(read_iter, v.size()); + constraint_system = + nil::crypto3::marshalling::types::make_plonk_constraint_system( + marshalled_data + ); + } + + return constraint_system; +} + +template +std::optional, + nil::crypto3::zk::snark::plonk_table> +>> load_table_from_file( + Glib::RefPtr stream, + std::size_t file_size +){ + using ColumnType = nil::crypto3::zk::snark::plonk_column; + using AssignmentTableType = nil::crypto3::zk::snark::plonk_table; + using TableDescriptionType = nil::crypto3::zk::snark::plonk_table_description; + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + + AssignmentTableType assignment_table; + TableDescriptionType desc(0,0,0,0); + { + std::vector v(file_size); + stream->read(reinterpret_cast(v.data()), file_size); + if (!stream) { + std::cerr << "Cannot parse input file: read failed." << std::endl; + return std::nullopt; + } + nil::crypto3::marshalling::types::plonk_assignment_table + marshalled_table_data; + auto read_iter = v.begin(); + auto status = marshalled_table_data.read(read_iter, v.size()); + std::tie(desc, assignment_table) = + nil::crypto3::marshalling::types::make_assignment_table( + marshalled_table_data + ); + } + return std::make_tuple(desc, assignment_table); +} + + +std::string read_line_from_gstream(Glib::RefPtr stream, + gsize predicted_line_size, + gsize file_size, + char* buffer) { + std::string line; + auto pos = stream->tell(); + gsize total_read_size = pos; + if (pos + predicted_line_size >= file_size) { + predicted_line_size = file_size - pos; + } + char* newline = nullptr; + while (newline == nullptr && total_read_size != file_size) { + auto read_size = stream->read(buffer, predicted_line_size); + total_read_size += read_size; + buffer[read_size] = '\0'; + if (read_size != predicted_line_size && total_read_size != file_size) { + return std::string(""); + } + newline = strchr(buffer, '\n'); + if (newline != nullptr) { + *newline = '\0'; + stream->seek(total_read_size + (newline - buffer) + 1 - read_size, Glib::SeekType::SET); + } + line += buffer; + } + + return line; +} + +// Use this to debug in case you have no idea where a widget is +void print_widget_hierarchy(const Gtk::Widget& widget, int depth = 0) { + std::string indent(depth * 2, ' '); // Indentation based on depth + std::cout << indent << widget.get_name() << std::endl; + + const Gtk::Widget* child = widget.get_first_child(); + while(child != nullptr) { + print_widget_hierarchy(*child, depth + 1); + child = child->get_next_sibling(); + } +} + + +void print_list_item_hierarchy(const Gtk::ListItem &list_item) { + const Gtk::Widget* child = list_item.get_child(); + while(child != nullptr) { + print_widget_hierarchy(*child, 1); + child = child->get_next_sibling(); + } +} + +struct CellState { + CellState() : state(CellStateFlags::NORMAL) {} + CellState(uint8_t state_) : state(state_) {} + enum CellStateFlags : uint8_t { + NORMAL = 0, + SELECTED = 1 << 1, + COPY_CONSTRAINED_SATISFIED = 1 << 2, + COPY_CONSTRAINED_FAILURE = 1 << 3, + GATE_CONSTRAINED_SATISFIED = 1 << 4, + GATE_CONSTRAINED_FAILURE = 1 << 5, + LOOKUP_CONSTRAINED_SATISFIED = 1 << 6, + LOOKUP_CONSTRAINED_FAILURE = 1 << 7 + }; + + void clear() { + state = NORMAL; + } + + void select() { + state |= SELECTED; + } + + void deselect() { + state &= ~SELECTED; + } + + bool is_selected() const { + return state & SELECTED; + } + + void remove_copy_constraint_state() { + state &= ~(COPY_CONSTRAINED_SATISFIED | COPY_CONSTRAINED_FAILURE); + } + + void copy_constraint_satisfied() { + state |= COPY_CONSTRAINED_SATISFIED; + state &= ~COPY_CONSTRAINED_FAILURE; + } + + bool is_copy_constraint_satisfied() const { + return state & COPY_CONSTRAINED_SATISFIED; + } + + void copy_constraint_unsatisfied() { + state |= COPY_CONSTRAINED_FAILURE; + state &= ~COPY_CONSTRAINED_SATISFIED; + } + + bool is_copy_constraint_unsatisfied() const { + return state & COPY_CONSTRAINED_FAILURE; + } + + void remove_gate_constraint_state() { + state &= ~(GATE_CONSTRAINED_SATISFIED | GATE_CONSTRAINED_FAILURE); + } + + void gate_constraint_satisfied() { + state |= GATE_CONSTRAINED_SATISFIED; + state &= ~GATE_CONSTRAINED_FAILURE; + } + + void gate_constraint_unsatisfied() { + state |= GATE_CONSTRAINED_FAILURE; + state &= ~GATE_CONSTRAINED_SATISFIED; + } + + bool is_gate_constraint_satisfied() const { + return state & GATE_CONSTRAINED_SATISFIED; + } + + bool is_gate_constraint_unsatisfied() const { + return state & GATE_CONSTRAINED_FAILURE; + } + + uint8_t state; +}; + +template +struct cached_constraint { + using plonk_constraint_type = nil::crypto3::zk::snark::plonk_constraint; + + cached_constraint() : constraint(nullptr), row(0), selector(0), constraint_num(0) {} + cached_constraint(plonk_constraint_type* constraint_, std::size_t row_, + std::size_t selector_, std::size_t constraint_num_) + : constraint(constraint_), row(row_), selector(selector_), constraint_num(constraint_num_) {} + + plonk_constraint_type* constraint; + std::size_t row; + std::size_t selector; + std::size_t constraint_num; +}; + +template +class row_object : public Glib::Object { +public: + // We have to roll a custom container for this because ArithmetizationParams are constexpr in the assignment table. + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using plonk_copy_constraint_type = nil::crypto3::zk::snark::plonk_copy_constraint; + using plonk_constraint_type = nil::crypto3::zk::snark::plonk_constraint; + using var = nil::crypto3::zk::snark::plonk_variable; + + static Glib::RefPtr create(const std::vector& row_, std::size_t row_index_) { + return Glib::make_refptr_for_instance(new row_object(row_, row_index_)); + } + + const Glib::ustring& to_string(std::size_t index) const { + return string_cache[index]; + } + + std::size_t get_row_index() const { + return row_index; + } + + const value_type get_row_item(std::size_t column_index) const { + return row[column_index]; + } + + void set_row_item(const value_type& v, std::size_t column_index) { + row[column_index] = v; + + std::stringstream ss; + if (column_index != 0) { + ss << std::hex; + } else { + ss << std::dec; + } + ss << row[column_index].data; + string_cache[column_index] = ss.str(); + } + + void set_cell_state(std::size_t column_index, CellState state) { + cell_states[column_index] = state; + } + + CellState get_cell_state(std::size_t column_index) const { + return cell_states[column_index]; + } + + CellState& get_cell_state(std::size_t column_index) { + return cell_states[column_index]; + } + + void set_widget(std::size_t column_index, Gtk::Button* widget) { + widgets[column_index] = widget; + } + + Gtk::Button* get_widget(std::size_t column_index) const { + return widgets[column_index]; + } + + bool get_widget_loaded(std::size_t column_index) const { + return widget_loaded[column_index]; + } + + void set_widget_loaded(std::size_t column_index, bool loaded) { + widget_loaded[column_index] = loaded; + } + + static std::size_t get_actual_column_index(var variable, table_sizes &sizes) { + switch (variable.type) { + case var::column_type::witness: + return variable.index + 1; + break; + case var::column_type::public_input: + return variable.index + 1 + sizes.witnesses_size; + break; + case var::column_type::constant: + return variable.index + 1 + sizes.witnesses_size + sizes.public_inputs_size; + break; + case var::column_type::selector: + return variable.index + 1 + sizes.witnesses_size + sizes.public_inputs_size + sizes.constants_size; + break; + case var::column_type::uninitialized: + throw std::runtime_error("Attempted to get actual column index of uninitialized variable"); + } + } + + void add_copy_constraint_to_cache(var variable, std::size_t constraint_num, + plonk_copy_constraint_type* constraint, + table_sizes &sizes) { + if (variable.rotation != row_index) { + std::cerr << "Attempted to add copy constraint to wrong row" << std::endl; + return; + } + std::size_t actual_column_index = get_actual_column_index(variable, sizes); + copy_constraints_cache[actual_column_index].push_back(std::make_pair(constraint_num, constraint)); + } + + std::size_t get_copy_constraints_size(std::size_t column_index) const { + return copy_constraints_cache[column_index].size(); + } + + std::pair get_copy_constraint(std::size_t column_index, + std::size_t index) const { + return copy_constraints_cache[column_index][index]; + } + + std::size_t get_constraints_size(std::size_t column_index) const { + return constraints_cache[column_index].size(); + } + + cached_constraint get_constraint(std::size_t column_index, std::size_t index) const { + return constraints_cache[column_index][index]; + } + + void add_constraint_to_cache(row_object* previous_row, + row_object* next_row, + var variable, std::size_t selector, std::size_t constraint_num, std::size_t row, + plonk_constraint_type* constraint, table_sizes &sizes) { + if (variable.rotation == 1) { + variable.rotation = 0; + if (next_row == nullptr) { + std::cerr << "Attempted to add constraint " << constraint_num << " from selector " + << selector << " to non-existent row " << row + 1 << std::endl; + return; + } + next_row->add_constraint_to_cache(nullptr, nullptr, variable, selector, constraint_num, row, constraint, sizes); + return; + } else if (variable.rotation == -1) { + variable.rotation = 0; + if (previous_row == nullptr) { + std::cerr << "Attempted to add constraint " << constraint_num << " from selector " + << selector << " to non-existent row " << row - 1 << std::endl; + return; + } + previous_row->add_constraint_to_cache(nullptr, nullptr, variable, selector, + constraint_num, row, constraint, sizes); + return; + } + std::size_t actual_column_index = get_actual_column_index(variable, sizes); + constraints_cache[actual_column_index].push_back( + cached_constraint(constraint, row, selector, constraint_num)); + } + + bool selector_enabled(std::size_t selector_num, table_sizes &sizes) { + return row[1 + sizes.witnesses_size + sizes.public_inputs_size + sizes.constants_size + selector_num] != 0; + } + +protected: + row_object(const std::vector& row_, std::size_t row_index_) : + row_index(row_index_), cell_states(row_.size(), CellState::CellStateFlags::NORMAL), + widgets(row_.size(), nullptr), widget_loaded(row_.size(), false), + copy_constraints_cache(row_.size()), constraints_cache(row_.size()), + row(row_), previous(nullptr), next(nullptr) { + string_cache.reserve(row.size()); + + for (std::size_t i = 0; i < row.size(); ++i) { + std::stringstream ss; + if (i != 0) { + ss << std::hex; + } else { + ss << std::dec; + } + ss << row[i].data; + string_cache.push_back(ss.str()); + } + } +private: + std::size_t row_index; + std::vector cell_states; + std::vector widgets; + std::vector widget_loaded; + // Stores all copy constraints which affect the i'th item + // The size element in pair is for constraint num in container. + std::vector>> copy_constraints_cache; + // Stores all constraints which affect the i'th item, with their selectors and constraint numbers. + std::vector>> constraints_cache; + std::vector string_cache; + std::vector row; + // Using the model to traverse for gate constraints is annoying, we use previous/next pointers to make it easier. + row_object *previous, *next; +}; + +template +struct circuit_container { + using plonk_constraint_type = nil::crypto3::zk::snark::plonk_constraint; + using plonk_gate_type = nil::crypto3::zk::snark::plonk_gate; + using plonk_copy_constraint_type = nil::crypto3::zk::snark::plonk_copy_constraint; + + std::vector gates; + std::vector copy_constraints; + // TODO: add lookup gates + + // This is used in order to be able to travers from copy constraint to the underlying variable and it's cell. + // We can utilise this in tandem with links from row_object to constraints to traverse and colour. + std::vector*, row_object*>> copy_constraints_links; +}; + +template +struct constraint_object : public Glib::Object { + // A wrapper for displaying a constraint in a view. + using plonk_constraint_type = nil::crypto3::zk::snark::plonk_constraint; + using plonk_copy_constraint_type = nil::crypto3::zk::snark::plonk_copy_constraint; + + static Glib::RefPtr create(plonk_constraint_type* constraint_, std::size_t row_, + std::size_t selector, std::size_t num) { + return Glib::make_refptr_for_instance( + new constraint_object(constraint_, row_, selector, num)); + } + + static Glib::RefPtr create(plonk_copy_constraint_type* constraint_) { + return Glib::make_refptr_for_instance(new constraint_object(constraint_)); + } + + constraint_object(plonk_constraint_type* constraint_, std::size_t row_, std::size_t selector, std::size_t num) : + constraint(constraint_), loaded(false), row(row_), button(nullptr) { + std::stringstream ss; + ss << "cons " << selector << " " << num << ": "; + ss << *constraint_; + cached_string = ss.str(); + } + + constraint_object(plonk_copy_constraint_type* constraint_) + : constraint(constraint_), loaded(false), row(-1), button(nullptr) { + std::stringstream ss; + ss << "copy " << constraint_->first << " " << constraint_->second; + cached_string = ss.str(); + } + + Glib::ustring to_string() const { + return cached_string; + } + + void select() { + state.select(); + } + + void deselect() { + state.deselect(); + } + + bool is_selected() const { + return state.is_selected(); + } + + boost::variant constraint; + Glib::ustring cached_string; + CellState state; + bool loaded; + // Used for gate constraints to access the correct row for highlighting. + std::size_t row; + Gtk::Button* button; +}; + +template +struct CellTracker { + CellTracker() : row(-1), column(-1), tracked_object(nullptr) {} + CellTracker(std::size_t row_, std::size_t column_, TrackedType* tracked_object_) : + row(row_), column(column_), tracked_object(tracked_object_) {} + + void clear() { + row = column = -1; + tracked_object = nullptr; + } + + std::size_t row, column; + TrackedType* tracked_object; +}; + + +template +class ExcaliburWindow : public Gtk::ApplicationWindow { +public: + using integral_type = typename BlueprintFieldType::integral_type; + using value_type = typename BlueprintFieldType::value_type; + using plonk_copy_constraint_type = nil::crypto3::zk::snark::plonk_copy_constraint; + using plonk_constraint_type = nil::crypto3::zk::snark::plonk_constraint; + using plonk_gate_type = nil::crypto3::zk::snark::plonk_gate; + using var = nil::crypto3::zk::snark::plonk_variable; + + ExcaliburWindow() : table_view(), element_entry(), vbox_prime(), vbox_controls(), table_window(), + open_table_button("Open Table"), open_circuit_button("Open Circuit"), + //save_table_button("Save"), + constraints_view(), constraints_window() { + set_title("Excalibur Circuit Viewer: pull the bugs from the stone"); + set_resizable(true); + + auto css_provider = Gtk::CssProvider::create(); + Glib::ustring css_style = + "* { font: 24px Courier; text-shadow: none; box-shadow: none; }" + "button { margin: 0px; padding: 0px; }" + "button.selected { background: deepskyblue; }" + "button.copy_satisfied { background: #58D68D; }" + "button.copy_unsatisfied { background: crimson; }" + "button.gate_satisfied { background: limegreen; }" + "button.gate_unsatisfied { background: darkred; }"; + css_provider->load_from_data(css_style); + Gtk::StyleProvider::add_provider_for_display( + Gdk::Display::get_default(), css_provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + element_entry.set_placeholder_text("00000000000000000000000000000000000000000000000000000000000000"); + element_entry.set_max_length((BlueprintFieldType::modulus_bits + 3 - 1) / 3); + element_entry.set_size_request(800, -1); + vbox_prime.set_orientation(Gtk::Orientation::VERTICAL); + vbox_prime.set_spacing(10); + + vbox_controls.set_spacing(10); + vbox_controls.set_orientation(Gtk::Orientation::HORIZONTAL); + vbox_controls.append(open_table_button); + //vbox_controls.append(save_table_button); + vbox_controls.append(open_circuit_button); + vbox_controls.append(element_entry); + vbox_prime.append(vbox_controls); + + table_window.set_child(table_view); + table_window.set_size_request(800, 600); + table_window.set_vexpand(true); + vbox_prime.append(table_window); + + constraints_window.set_child(constraints_view); + constraints_window.set_size_request(-1, 128); + vbox_prime.append(constraints_window); + vbox_prime.set_vexpand(true); + + set_child(vbox_prime); + + auto key_controller = Gtk::EventControllerKey::create(); + // This is a hack: I have no idea how to catch the key press event. + key_controller->signal_key_released().connect( + sigc::mem_fun(*this, &ExcaliburWindow::on_entry_key_released), true); + element_entry.add_controller(key_controller); + + open_table_button.signal_clicked().connect(sigc::mem_fun(*this, &ExcaliburWindow::on_action_table_file_open)); + open_circuit_button.signal_clicked().connect( + sigc::mem_fun(*this, &ExcaliburWindow::on_action_circuit_file_open)); + //save_table_button.signal_clicked().connect( + // sigc::bind<0>(sigc::mem_fun(*this, &ExcaliburWindow::on_action_table_file_save), false)); + } + + ~ExcaliburWindow() override {}; + + template + void setup_constraint_view_from_store(const Glib::RefPtr> &store) { + // You might be wondering why don't I use the SingleSelect selection mechanism here, and create a button. + // It's signal is very questionable, and forces me to manually find out which constraint got selected + // and also what state it used to be in -- so I have to implement the selection tracking mechanism + // myself regardless. SingleSelection is a trap. + constraints_view.set_model(Gtk::NoSelection::create(store)); + auto factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect( + sigc::mem_fun(*this, &ExcaliburWindow::on_setup_constraint), false); + factory->signal_bind().connect( + sigc::mem_fun(*this, &ExcaliburWindow::on_bind_constraint), false); + factory->signal_unbind().connect( + sigc::mem_fun(*this, &ExcaliburWindow::on_unbind_constraint), false); + constraints_view.set_factory(factory); + } + + void clear_highlights() { + for (auto &cell : highlighted_cells) { + auto row = cell.tracked_object; + CellState &row_state = row->get_cell_state(cell.column); + row_state.remove_copy_constraint_state(); + if (row->get_widget_loaded(cell.column)) { + auto button = row->get_widget(cell.column); + button->remove_css_class("copy_satisfied"); + button->remove_css_class("copy_unsatisfied"); + button->remove_css_class("gate_satisfied"); + button->remove_css_class("gate_unsatisfied"); + } + } + } + + void highlight_constraint(constraint_object* constraint_item) { + auto selection_model = dynamic_cast(&*table_view.get_model()); + auto model = selection_model->get_model(); + auto constraint = constraint_item->constraint; + if (constraint.which() == 0) { // gate constraint + std::size_t row_idx = constraint_item->row; + auto gate_constraint = + boost::get*>(constraint); + auto previous_row = (row_idx > 0) ? + dynamic_cast*>(&*model->get_object(row_idx - 1)) + : nullptr; + auto curent_row = dynamic_cast*>(&*model->get_object(row_idx)); + auto next_row = (row_idx < sizes.max_size) ? + dynamic_cast*>(&*model->get_object(row_idx + 1)) + : nullptr; + std::set variable_set; + std::function variable_extractor = + [&variable_set](var variable) { variable_set.insert(variable); }; + nil::crypto3::math::expression_for_each_variable_visitor visitor(variable_extractor); + visitor.visit(*gate_constraint); + + std::map, typename var::assignment_type> + evaluation_map; + for (const var &variable : variable_set) { + row_object *var_row = variable.rotation == -1 ? previous_row : + variable.rotation == 0 ? curent_row : next_row; + auto column = var_row->get_actual_column_index(variable, sizes); + evaluation_map[std::make_tuple(variable.index, variable.rotation, variable.type)] = + var_row->get_row_item(column); + } + bool satisfied = gate_constraint->evaluate(evaluation_map) == 0; + + for (const var &variable : variable_set) { + row_object *var_row = variable.rotation == -1 ? previous_row : + variable.rotation == 0 ? curent_row : next_row; + std::size_t var_row_idx = variable.rotation == -1 ? row_idx - 1 : + variable.rotation == 0 ? row_idx : row_idx + 1; + auto column = var_row->get_actual_column_index(variable, sizes); + CellState &row_state = var_row->get_cell_state(column); + if (satisfied) { + row_state.gate_constraint_satisfied(); + } else { + row_state.gate_constraint_unsatisfied(); + } + if (var_row->get_widget_loaded(column)) { + auto button = var_row->get_widget(column); + if (satisfied) { + button->add_css_class("gate_satisfied"); + } else { + button->add_css_class("gate_unsatisfied"); + } + } + highlighted_cells.push_back(CellTracker>( + var_row_idx, column, var_row)); + } + } else if (constraint.which() == 1) { // copy constraint + auto copy_constraint = + boost::get*>(constraint); + std::array vars = {copy_constraint->first, copy_constraint->second}; + std::array values; + for (std::size_t i = 0; i < 2; i++) { + auto row_index = vars[i].rotation; + auto row = dynamic_cast*>(&*model->get_object(row_index)); + if (!row) { + std::cerr << "Failed to get row" << std::endl; + return; + } + auto column = row->get_actual_column_index(vars[i], sizes); + values[i] = row->get_row_item(column); + } + for (std::size_t i = 0; i < 2; i++) { + auto row_index = vars[i].rotation; + auto row = dynamic_cast*>(&*model->get_object(row_index)); + if (!row) { + std::cerr << "Failed to get row" << std::endl; + return; + } + auto column = row->get_actual_column_index(vars[i], sizes); + CellState &row_state = row->get_cell_state(column); + if (values[0] == values[1]) { + row_state.copy_constraint_satisfied(); + if (row->get_widget_loaded(column)) { + auto button = row->get_widget(column); + button->add_css_class("copy_satisfied"); + } + } else { + row_state.copy_constraint_unsatisfied(); + if (row->get_widget_loaded(column)) { + auto button = row->get_widget(column); + button->add_css_class("copy_unsatisfied"); + } + } + highlighted_cells.push_back(CellTracker>( + vars[i].rotation, column, row)); + } + } else { + std::cerr << "Unimplemented constraint type" << std::endl; + } + } + + void on_action_table_file_open() { + auto file_dialog = Gtk::FileDialog::create(); + file_dialog->set_modal(true); + file_dialog->set_title("Open table file"); + file_dialog->set_initial_folder(Gio::File::create_for_path( + std::string(std::filesystem::current_path()))); + file_dialog->open(*this, + sigc::bind<0>(sigc::mem_fun(*this, + &ExcaliburWindow::on_table_file_open_dialog_response), + file_dialog)); + } + + void on_action_circuit_file_open() { + auto file_dialog = Gtk::FileDialog::create(); + file_dialog->set_modal(true); + file_dialog->set_title("Open circuit file"); + file_dialog->set_initial_folder(Gio::File::create_for_path( + std::string(std::filesystem::current_path()))); + file_dialog->open(*this, + sigc::bind<0>(sigc::mem_fun(*this, + &ExcaliburWindow::on_circuit_file_open_dialog_response), + file_dialog)); + } + + /*void on_action_table_file_save(bool wide_export) { + auto file_dialog = Gtk::FileDialog::create(); + file_dialog->set_modal(true); + file_dialog->set_title("Save table file"); + file_dialog->save(*this, + sigc::bind<0>(sigc::bind<0>(sigc::mem_fun(*this, &ExcaliburWindow::on_table_file_save_dialog_response), + file_dialog), + wide_export)); + }*/ + + void on_setup_column_item(std::size_t column, const Glib::RefPtr &list_item) { + auto button = Gtk::make_managed(); + auto label = Gtk::make_managed(); + + label->set_ellipsize(Pango::EllipsizeMode::START); + label->set_halign(Gtk::Align::END); + button->set_child(*label); + list_item->set_child(*button); + + if (column == 0) { + return; + } + button->signal_clicked().connect( + sigc::bind<0>(sigc::bind<0>( + sigc::mem_fun(*this, &ExcaliburWindow::on_cell_clicked), + column), + list_item)); + } + + void on_bind_column_item(std::size_t column, const Glib::RefPtr &list_item) { + auto button = dynamic_cast(list_item->get_child()); + if (!button) { + return; + } + auto label = dynamic_cast(button->get_child()); + if (!label) { + return; + } + + auto item = list_item->get_item(); + auto mitem = dynamic_cast*>(&*item); + if (!mitem) { + return; + } + mitem->set_widget(column, button); + mitem->set_widget_loaded(column, true); + label->set_text(mitem->to_string(column)); + CellState state = mitem->get_cell_state(column); + if (state.is_selected()) { + button->add_css_class("selected"); + } + if (state.is_copy_constraint_satisfied()) { + button->add_css_class("copy_satisfied"); + } + if (state.is_copy_constraint_unsatisfied()) { + button->add_css_class("copy_unsatisfied"); + } + if (state.is_gate_constraint_satisfied()) { + button->add_css_class("gate_satisfied"); + } + if (state.is_gate_constraint_unsatisfied()) { + button->add_css_class("gate_unsatisfied"); + } + } + + void on_unbind_column_item(std::size_t column, const Glib::RefPtr &list_item) { + auto item = list_item->get_item(); + auto mitem = dynamic_cast*>(&*item); + if (!mitem) { + return; + } + mitem->set_widget_loaded(column, false); + } + + void on_setup_constraint(const Glib::RefPtr &list_item) { + auto button = Gtk::make_managed(); + auto label = Gtk::make_managed(); + label->set_halign(Gtk::Align::START); + button->set_child(*label); + list_item->set_child(*button); + + button->signal_clicked().connect( + sigc::bind<0>( + sigc::mem_fun(*this, &ExcaliburWindow::on_constraint_clicked), + list_item)); + } + + void on_bind_constraint(const Glib::RefPtr &list_item) { + auto item = list_item->get_item(); + auto mitem = dynamic_cast*>(&*item); + if (!mitem) { + return; + } + auto button = dynamic_cast(list_item->get_child()); + if (!button) { + return; + } + auto label = dynamic_cast(button->get_child()); + if (!label) { + return; + } + label->set_text(mitem->to_string()); + if (mitem->is_selected()) { + button->add_css_class("selected"); + } + mitem->loaded = true; + mitem->button = button; + } + + void on_unbind_constraint(const Glib::RefPtr &list_item) { + auto item = list_item->get_item(); + auto mitem = dynamic_cast*>(&*item); + if (!mitem) { + return; + } + mitem->loaded = false; + } + + void on_table_file_open_dialog_response(Glib::RefPtr file_dialog, + std::shared_ptr &res) { + auto result = file_dialog->open_finish(res); + auto stream = result->read(); + auto file_info = result->query_info(); + auto file_size = file_info->get_size(); + + auto desc_table_pair = + load_table_from_file(stream, file_size); + + stream->close(); + if (!desc_table_pair) { + return; + } + + const auto &desc = std::get<0>(*desc_table_pair); + const auto &loaded_table = std::get<1>(*desc_table_pair); + sizes.witnesses_size = desc.witness_columns; + sizes.public_inputs_size = desc.public_input_columns; + sizes.constants_size = desc.constant_columns; + sizes.selectors_size = desc.selector_columns; + sizes.max_size = desc.rows_amount; + const std::size_t row_size = sizes.witnesses_size + sizes.public_inputs_size + + sizes.constants_size + sizes.selectors_size + 1; + + auto store = Gio::ListStore>::create(); + + for (std::uint32_t i = 0; i < sizes.max_size; i++) { + std::vector row(row_size); + for (std::size_t j = 0; j < row_size; j++) { + if (j == 0) { + row[j] = value_type(i); + } else if (j < sizes.witnesses_size + 1) { + row[j] = loaded_table.witness(j - 1)[i]; + } else if (j < sizes.witnesses_size + sizes.public_inputs_size + 1) { + row[j] = loaded_table.public_input(j - sizes.witnesses_size - 1)[i]; + } else if (j < sizes.witnesses_size + sizes.public_inputs_size + sizes.constants_size + 1) { + row[j] = loaded_table.constant(j - sizes.witnesses_size - sizes.public_inputs_size - 1)[i]; + } else { + row[j] = + loaded_table.selector( + j - sizes.witnesses_size - sizes.public_inputs_size - sizes.constants_size - 1)[i]; + } + } + store->append(row_object::create(row, i)); + } + + auto get_column_name = [](const table_sizes &sizes, std::size_t i) { + if (i == 0) { + return std::string("Row"); + } + std::stringstream ss; + auto fixed_width_size = [&ss](std::size_t j) { + ss << std::setfill('0') << std::setw(4) << j; + return ss.str(); + }; + + if (i < sizes.witnesses_size + 1) { + return "W" + fixed_width_size(i - 1); + } else if (i < sizes.witnesses_size + sizes.public_inputs_size + 1) { + return "P" + fixed_width_size(i - sizes.witnesses_size - 1); + } else if (i < sizes.witnesses_size + sizes.public_inputs_size + sizes.constants_size + 1) { + return "C" + fixed_width_size(i - sizes.witnesses_size - sizes.public_inputs_size - 1); + } else { + return "S" + fixed_width_size(i - sizes.witnesses_size - sizes.public_inputs_size + - sizes.constants_size - 1); + } + + }; + // Carefully remove the already existing columns + while (table_view.get_columns()->get_n_items() != 0) { + auto current_columns = table_view.get_columns(); + table_view.remove_column( + std::dynamic_pointer_cast(current_columns->get_object(0))); + } + // Clear selections as they are no longer relevant + selected_cell.clear(); + selected_constraint.clear(); + // Clear constraint view + auto constraint_store = Gio::ListStore>::create(); + setup_constraint_view_from_store(constraint_store); + + for (std::size_t i = 0; i < row_size; i++) { + auto factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect( + sigc::bind<0>(sigc::mem_fun(*this, &ExcaliburWindow::on_setup_column_item), i)); + factory->signal_bind().connect( + sigc::bind<0>(sigc::mem_fun(*this, &ExcaliburWindow::on_bind_column_item), i)); + factory->signal_unbind().connect( + sigc::bind<0>(sigc::mem_fun(*this, &ExcaliburWindow::on_unbind_column_item), i)); + + auto column = Gtk::ColumnViewColumn::create(get_column_name(sizes, i), factory); + column->set_resizable(true); + table_view.append_column(column); + } + + auto model = Gtk::NoSelection::create(store); + table_view.set_model(model); + } + + void on_circuit_file_open_dialog_response(Glib::RefPtr file_dialog, + std::shared_ptr &res) { + + auto result = file_dialog->open_finish(res); + if (table_view.get_columns()->get_n_items() == 0) { + std::cerr << "Please open the table before opening the circuit!" << std::endl; + return; + } + auto stream = result->read(); + auto file_info = result->query_info(); + auto file_size = file_info->get_size(); + + const auto loaded_circuit = load_circuit_from_file(stream, file_size); + if (!loaded_circuit) { + return; + } + + circuit.gates.clear(); + circuit.gates.reserve(loaded_circuit->gates().size()); + for (std::size_t i = 0; i < loaded_circuit->gates().size(); i++) { + auto gate = &loaded_circuit->gates()[i]; + circuit.gates.push_back(*gate); + } + + std::sort(circuit.gates.begin(), circuit.gates.end(), + [](const plonk_gate_type& a, const plonk_gate_type& b) + { return a.selector_index < b.selector_index; }); + + circuit.copy_constraints.clear(); + circuit.copy_constraints.reserve(loaded_circuit->copy_constraints().size()); + for (std::size_t i = 0; i < loaded_circuit->copy_constraints().size(); i++) { + auto copy_constraint = &loaded_circuit->copy_constraints()[i]; + circuit.copy_constraints.push_back(*copy_constraint); + } + + // Constraint cache building + auto selection_model = dynamic_cast(&*table_view.get_model()); + if (!selection_model) { + std::cerr << "Failed to get selection model" << std::endl; + return; + } + auto model = selection_model->get_model(); + for (std::size_t i = 0; i < circuit.copy_constraints.size(); i++) { + auto constraint = &circuit.copy_constraints[i]; + std::array variables = {constraint->first, constraint->second}; + for (auto &variable : variables) { + auto row = dynamic_cast*>(&*model->get_object(variable.rotation)); + row->add_copy_constraint_to_cache(variable, i, constraint, sizes); + } + } + // Gate cache building + for (std::size_t i = 0; i < circuit.gates.size(); i++) { + auto gate = &circuit.gates[i]; + for (std::size_t j = 0; j < gate->constraints.size(); j++) { + std::set variable_set; + std::function variable_extractor = + [&variable_set](var variable) { variable_set.insert(variable); }; + nil::crypto3::math::expression_for_each_variable_visitor visitor(variable_extractor); + visitor.visit(gate->constraints[j]); + + row_object *previous_row = nullptr, *current_row = nullptr, *next_row = nullptr; + current_row = dynamic_cast*>(&*model->get_object(0)); + next_row = (sizes.max_size > 1) ? + dynamic_cast*>(&*model->get_object(1)) + : nullptr; + for (std::size_t k = 0; k < sizes.max_size; + k++, previous_row = current_row, current_row = next_row, + next_row = (k + 1 < sizes.max_size) ? + dynamic_cast*>(&*model->get_object(k + 1)) + : nullptr) { + if (!current_row->selector_enabled(gate->selector_index, sizes)) { + continue; + } + auto current_row_idx = current_row->get_row_index(); + for (auto &variable : variable_set) { + current_row->add_constraint_to_cache(previous_row, next_row, variable, + i, j, current_row_idx, &gate->constraints[j], sizes); + } + var selector = var(gate->selector_index, 0, false, var::column_type::selector); + current_row->add_constraint_to_cache(nullptr, nullptr, selector, + i, j, current_row_idx, &gate->constraints[j], sizes); + } + } + } + } + + void on_table_file_save_dialog_response(Glib::RefPtr file_dialog, + bool wide_export, + std::shared_ptr &res) { + auto result = file_dialog->save_finish(res); + if (table_view.get_columns()->get_n_items() == 0) { + std::cerr << "No table to save" << std::endl; + return; + } + auto stream = result->replace(); + if (stream->is_closed()) { + std::cerr << "Failed to open the file for writing" << std::endl; + return; + } + // Write the header + std::stringstream header; + header << "witnesses_size: " << sizes.witnesses_size << " public_inputs_size: " << sizes.public_inputs_size + << " constants_size: " << sizes.constants_size << " selectors_size: " << sizes.selectors_size + << " max_size: " << sizes.max_size << "\n"; + stream->write(header.str().c_str(), header.str().size()); + auto model = dynamic_cast(&*table_view.get_model()); + if (!model) { + std::cerr << "No model" << std::endl; + stream->close(); + return; + } + auto list_model = model->get_model(); + std::uint32_t width = wide_export ? (BlueprintFieldType::modulus_bits + 4 - 1) / 4 : 0; + for (std::size_t i = 0; i < sizes.max_size; i++) { + std::stringstream row_stream; + row_stream << std::hex << std::setfill('0'); + auto object_row = model->get_object(i); + if (!object_row) { + std::cerr << "No object" << std::endl; + stream->close(); + return; + } + auto row = dynamic_cast*>(&*object_row); + if (!row) { + std::cerr << "No row" << std::endl; + stream->close(); + return; + } + std::size_t curr_idx = 1; + for (std::size_t j = 0; j < sizes.witnesses_size; j++) { + row_stream << std::setw(width) << row->get_row_item(curr_idx++).data << " "; + } + row_stream << "| "; + for (std::size_t j = 0; j < sizes.public_inputs_size; j++) { + row_stream << std::setw(width) << row->get_row_item(curr_idx++).data << " "; + } + row_stream << "| "; + for (std::size_t j = 0; j < sizes.constants_size; j++) { + row_stream << std::setw(width) + << row->get_row_item(curr_idx++).data + << " "; + } + row_stream << "| "; + for (std::size_t j = 0; j < sizes.selectors_size - 1; j++) { + row_stream << row->get_row_item(curr_idx++).data << " "; + } + row_stream << row->get_row_item(curr_idx).data << "\n"; + stream->write(row_stream.str().c_str(), row_stream.str().size()); + } + stream->close(); + } + + void on_cell_clicked(std::size_t column, const Glib::RefPtr &list_item) { + auto item = list_item->get_item(); + auto mitem = dynamic_cast*>(&*item); + if (!mitem) { + return; + } + std::size_t row = mitem->get_row_index(); + auto button = dynamic_cast(&*list_item->get_child()); + + if ((selected_cell.row == row && selected_cell.column == column) || button == nullptr) { + return; + } + + if (selected_cell.tracked_object != nullptr) { + auto old_row = selected_cell.tracked_object; + CellState& old_row_state = old_row->get_cell_state(selected_cell.column); + old_row_state.deselect(); + if (old_row->get_widget_loaded(selected_cell.column)) { + auto button = old_row->get_widget(selected_cell.column); + button->remove_css_class("selected"); + } + } + + selected_cell.row = row; + selected_cell.column = column; + selected_cell.tracked_object = mitem; + + button->add_css_class("selected"); + CellState &row_state = mitem->get_cell_state(column); + row_state.select(); + + element_entry.set_text(mitem->to_string(column)); + + clear_highlights(); + + if (selected_constraint.tracked_object != nullptr) { + selected_constraint.tracked_object->deselect(); + selected_constraint.tracked_object = nullptr; + } + + auto store = Gio::ListStore>::create(); + for (std::size_t i = 0; i < mitem->get_copy_constraints_size(column); i++) { + auto copy_constraint = mitem->get_copy_constraint(column, i); + store->append(constraint_object::create(copy_constraint.second)); + } + for (std::size_t i = 0; i < mitem->get_constraints_size(column); i++) { + auto constraint = mitem->get_constraint(column, i); + store->append(constraint_object::create( + constraint.constraint, constraint.row, constraint.selector, constraint.constraint_num)); + } + setup_constraint_view_from_store(store); + } + + void on_constraint_clicked(const Glib::RefPtr &list_item) { + auto item = list_item->get_item(); + auto mitem = dynamic_cast*>(&*item); + if (selected_constraint.tracked_object == mitem) { + return; + } + if (!mitem) { + return; + } + auto button = dynamic_cast(&*list_item->get_child()); + + if (selected_constraint.tracked_object != nullptr) { + auto old_constraint = selected_constraint.tracked_object; + CellState &old_constraint_state = old_constraint->state; + old_constraint_state.deselect(); + if (old_constraint->loaded) { + old_constraint->button->remove_css_class("selected"); + } + } + + button->add_css_class("selected"); + + selected_constraint.tracked_object = mitem; + + clear_highlights(); + highlight_constraint(mitem); + } + + void on_entry_key_released(guint keyval, guint keycode, Gdk::ModifierType state) { + // Didn't select any cell or keyval != enter + if (keyval != 65293 || selected_cell.tracked_object == nullptr) { + return; + } + std::stringstream ss; + ss << std::hex << element_entry.get_text(); + integral_type integral_value; + ss >> integral_value; + if (ss.fail()) { + std::cerr << "Failed to parse the value" << std::endl; + return; + } + value_type value = integral_value; + auto selection_model = table_view.get_model(); + auto model = dynamic_cast(&*selection_model); + if (!model) { + std::cerr << "No model" << std::endl; + return; + } + + auto object_row = model->get_object(selected_cell.row); + if (!object_row) { + std::cerr << "No object" << std::endl; + return; + } + auto row = dynamic_cast*>(&*object_row); + if (!row) { + std::cerr << "Failed cast to row" << std::endl; + return; + } + row->set_row_item(value, selected_cell.column); + + if (row->get_widget_loaded(selected_cell.column)) { + auto button = row->get_widget(selected_cell.column); + auto label = dynamic_cast(&*button->get_child()); + if (!label) { + std::cerr << "Failed cast to label" << std::endl; + return; + } + std::stringstream sse; + sse << std::hex << value.data; + label->set_text(sse.str()); + } + + if (selected_constraint.tracked_object != nullptr) { + clear_highlights(); + highlight_constraint(selected_constraint.tracked_object); + } + } + +protected: + Gtk::ColumnView table_view; + Gtk::Entry element_entry; + Gtk::Box vbox_prime, vbox_controls; + Gtk::ScrolledWindow table_window; + Gtk::Button open_table_button, open_circuit_button;/*, save_table_button;*/ + Gtk::ListView constraints_view; + Gtk::ScrolledWindow constraints_window; +private: + table_sizes sizes; + CellTracker> selected_cell; + CellTracker> selected_constraint; + std::vector>> highlighted_cells; + circuit_container circuit; +}; diff --git a/debug-tools/debug-tools.nix b/debug-tools/debug-tools.nix index 77efa79da4..10dcd883ea 100644 --- a/debug-tools/debug-tools.nix +++ b/debug-tools/debug-tools.nix @@ -1,12 +1,22 @@ { lib, stdenv, - ninja, - pkg-config, cmake, - crypto3, + cmake_modules, + pkg-config, boost, + clang, + clang-tools, + gtk4, + gtkmm4, + glibmm, + pcre2, + glib, gdb, - cmake_modules, + lldb, + ninja, + pango, + pangomm, + crypto3, }: let inherit (lib) optional; @@ -15,9 +25,13 @@ in stdenv.mkDerivation { src = lib.sourceByRegex ./. [ ".*" ]; - nativeBuildInputs = [ cmake ninja pkg-config ] ++ (lib.optional (!stdenv.isDarwin) gdb); + nativeBuildInputs = [ cmake ninja pkg-config ] ++ + (lib.optional (!stdenv.isDarwin) gdb) ++ + (lib.optional (stdenv.isDarwin) lldb); + + propagatedBuildInputs = [ boost crypto3 gtk4 gtkmm4 glibmm pcre2 glib pango pangomm ]; - buildInputs = [ cmake_modules crypto3 ]; + buildInputs = [ cmake_modules ]; cmakeFlags = [ diff --git a/evm-assigner/evm-assigner.nix b/evm-assigner/evm-assigner.nix index cc65a3c3ab..41df52695d 100644 --- a/evm-assigner/evm-assigner.nix +++ b/evm-assigner/evm-assigner.nix @@ -7,6 +7,7 @@ # We'll use boost183 by default, but you can override it boost_lib ? boost183, gdb, + lldb, ethash, intx, gtest, @@ -22,7 +23,9 @@ in stdenv.mkDerivation rec { src = lib.sourceByRegex ./. [ ".*" ]; - nativeBuildInputs = [ cmake ninja pkg-config ] ++ (lib.optional (!stdenv.isDarwin) gdb); + nativeBuildInputs = [ cmake ninja pkg-config ] ++ + (lib.optional (!stdenv.isDarwin) gdb) ++ + (lib.optional (stdenv.isDarwin) lldb); # enableDebugging will keep debug symbols in boost propagatedBuildInputs = [ (if enableDebug then (enableDebugging boost_lib) else boost_lib) ]; diff --git a/flake.nix b/flake.nix index caeb46ee4a..2e79fc249c 100644 --- a/flake.nix +++ b/flake.nix @@ -44,7 +44,7 @@ runTests = false; enableDebug = true; }); - + parallel-crypto3 = (pkgs.callPackage ./parallel-crypto3/parallel-crypto3.nix { runTests = false; enableDebug = false; @@ -161,7 +161,7 @@ name = "all"; paths = [ crypto3 evm-assigner zkevm-framework proof-producer]; }; - default = all; + default = all; }; checks = rec { diff --git a/parallel-crypto3/parallel-crypto3.nix b/parallel-crypto3/parallel-crypto3.nix index 189efbc710..3f63e62d74 100644 --- a/parallel-crypto3/parallel-crypto3.nix +++ b/parallel-crypto3/parallel-crypto3.nix @@ -5,6 +5,7 @@ cmake, boost, gdb, + lldb, cmake_modules, crypto3, enableDebugging, @@ -18,7 +19,9 @@ in stdenv.mkDerivation { src = lib.sourceByRegex ./. [ ".*" ]; - nativeBuildInputs = [ cmake ninja pkg-config ] ++ (lib.optional (!stdenv.isDarwin) gdb); + nativeBuildInputs = [ cmake ninja pkg-config ] ++ + (lib.optional (!stdenv.isDarwin) gdb) ++ + (lib.optional (stdenv.isDarwin) lldb); # enableDebugging will keep debug symbols in boost propagatedBuildInputs = [ (if enableDebug then (enableDebugging boost) else boost) ]; diff --git a/proof-producer/proof-producer.nix b/proof-producer/proof-producer.nix index 47ba50f764..19d10fa626 100644 --- a/proof-producer/proof-producer.nix +++ b/proof-producer/proof-producer.nix @@ -7,6 +7,7 @@ parallel-crypto3, boost, gdb, + lldb, cmake_modules, enableDebugging, enableDebug ? false, @@ -19,7 +20,9 @@ in stdenv.mkDerivation { src = lib.sourceByRegex ./. [ ".*" ]; - nativeBuildInputs = [ cmake ninja pkg-config ] ++ (lib.optional (!stdenv.isDarwin) gdb); + nativeBuildInputs = [ cmake ninja pkg-config ] ++ + (lib.optional (!stdenv.isDarwin) gdb) ++ + (lib.optional (stdenv.isDarwin) lldb); # enableDebugging will keep debug symbols in boost propagatedBuildInputs = [ (if enableDebug then (enableDebugging boost) else boost) ]; diff --git a/transpiler/transpiler.nix b/transpiler/transpiler.nix new file mode 100644 index 0000000000..97b1d97840 --- /dev/null +++ b/transpiler/transpiler.nix @@ -0,0 +1,44 @@ +{ lib, + stdenv, + ninja, + pkg-config, + cmake, + crypto3, + boost, + gdb, + lldb, + cmake_modules, + enableDebugging, + enableDebug ? false, + runTests ? false, + }: +let + inherit (lib) optional; +in stdenv.mkDerivation { + name = "Transpiler"; + + src = lib.sourceByRegex ./. [ ".*" ]; + + nativeBuildInputs = [ cmake ninja pkg-config ] ++ + (lib.optional (!stdenv.isDarwin) gdb) ++ + (lib.optional (stdenv.isDarwin) lldb); + + # enableDebugging will keep debug symbols in boost + propagatedBuildInputs = [ (if enableDebug then (enableDebugging boost) else boost) ]; + + buildInputs = [cmake_modules crypto3]; + + cmakeFlags = + [ + (if runTests then "-DBUILD_TESTS=TRUE" else "-DBUILD_TESTS=False") + (if enableDebug then "-DCMAKE_BUILD_TYPE=Debug" else "-DCMAKE_BUILD_TYPE=Release") + "-G Ninja" + ]; + + doCheck = runTests; + + shellHook = '' + PS1="\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ " + echo "Welcome to Transpiler development environment!" + ''; +} diff --git a/zkevm-framework/zkevm-framework.nix b/zkevm-framework/zkevm-framework.nix index 1b569e3ceb..4e62078bee 100644 --- a/zkevm-framework/zkevm-framework.nix +++ b/zkevm-framework/zkevm-framework.nix @@ -5,6 +5,7 @@ cmake, boost, gdb, + lldb, crypto3, ethash, intx, @@ -25,7 +26,9 @@ in stdenv.mkDerivation rec { src = lib.sourceByRegex ./. [ ".*" ]; - nativeBuildInputs = [ cmake ninja pkg-config ] ++ (lib.optional (!stdenv.isDarwin) gdb); + nativeBuildInputs =[ cmake ninja pkg-config ] ++ + (lib.optional (!stdenv.isDarwin) gdb) ++ + (lib.optional (stdenv.isDarwin) lldb); # enableDebugging will keep debug symbols in boost propagatedBuildInputs = [ (if enableDebug then (enableDebugging boost) else boost) ];