Skip to content

Commit

Permalink
Moved precomputed lookup tables into the binaries.
Browse files Browse the repository at this point in the history
  • Loading branch information
Iluvmagick committed Jan 20, 2024
1 parent b0ece6e commit 1357916
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 103 deletions.
4 changes: 0 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,6 @@ cm_deploy(TARGETS ${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME}
INCLUDE include
NAMESPACE ${CMAKE_WORKSPACE_NAME}::)


set(BLUEPRINT_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
target_compile_definitions(${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME} INTERFACE BLUEPRINT_PATH="${BLUEPRINT_PATH}")

if(BUILD_TESTS)
add_subdirectory(test)
endif()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@
// SOFTWARE.
//---------------------------------------------------------------------------//


#include <nil/blueprint/components/hashes/sha2/plonk/detail/split_functions.hpp>
#include <nil/crypto3/marshalling/zk/types/commitments/fri.hpp>

#include <array>
#include <string>
#include <vector>
Expand All @@ -36,8 +32,18 @@
#include <mutex>
#include <unordered_set>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <nil/blueprint/components/hashes/sha2/plonk/detail/split_functions.hpp>

#include <nil/crypto3/multiprecision/cpp_int.hpp>

#include <nil/marshalling/status_type.hpp>
#include <nil/marshalling/field_type.hpp>
#include <nil/marshalling/endianness.hpp>
#include <nil/marshalling/field_type.hpp>
#include <nil/crypto3/algebra/marshalling.hpp>
#include <nil/crypto3/marshalling/zk/types/plonk/constraint_system.hpp>
#include <nil/crypto3/marshalling/zk/types/plonk/assignment_table.hpp>


namespace nil {
namespace blueprint {
Expand All @@ -62,7 +68,7 @@ namespace nil {
using value_type = typename BlueprintFieldType::value_type;
using Endianness = nil::marshalling::option::big_endian;
using TTypeBase = nil::marshalling::field_type<Endianness>;
using marshalling_value_type = nil::crypto3::marshalling::types::field_element<TTypeBase, value_type>;
using marshalling_value_type = crypto3::marshalling::types::field_element<TTypeBase, value_type>;
stream << input.size() << std::endl;
for (const auto &[preimage, image] : input) {
std::vector<marshalling_value_type> pair = {
Expand Down Expand Up @@ -335,83 +341,7 @@ namespace nil {
std::cerr << "Time elapsed: " << duration.count() << " seconds" << std::endl;
std::cerr << "Total size: " << std::dec << output_set.size() << std::endl;
}

template<typename Iterator, typename BlueprintFieldType>
struct value_pair_parser : boost::spirit::qi::grammar<Iterator,
std::pair<typename BlueprintFieldType::value_type,
typename BlueprintFieldType::value_type>(),
boost::spirit::qi::ascii::space_type> {
using value_type = typename BlueprintFieldType::value_type;
using integral_type = typename BlueprintFieldType::integral_type;
using return_type = std::pair<value_type, value_type>;

value_pair_parser() : value_pair_parser::base_type(start) {
using boost::spirit::qi::uint_parser;
using boost::spirit::qi::_val;
using boost::spirit::qi::_1;
using boost::spirit::qi::_2;
using boost::phoenix::construct;
using boost::phoenix::val;
auto nubmer = uint_parser<integral_type, 16, 1,
(BlueprintFieldType::modulus_bits + 16 - 1) / 16>();
start = (nubmer >> nubmer)
[_val = construct<std::pair<value_type, value_type>>(_1, _2)];

boost::spirit::qi::on_error<boost::spirit::qi::fail>(
start,
std::cerr << val("Error! Expecting ") << boost::spirit::qi::_4 << val(" here: \"")
<< construct<std::string>(boost::spirit::_3, boost::spirit::_2) << val("\"\n")
);
}

boost::spirit::qi::rule<Iterator, return_type(), boost::spirit::qi::ascii::space_type> start;
};

// Loads the table from file, trying multiple different filen paths if one fails
template <typename BlueprintFieldType>
std::vector<std::vector<typename BlueprintFieldType::value_type>> load_sha_table(
const std::set<std::string> &candidate_file_paths) {
using value_type = typename BlueprintFieldType::value_type;
std::vector<std::vector<value_type>> result;
result.resize(2);
for (const auto &path : candidate_file_paths) {
// try opening the file
std::ifstream file(path);
if (!file.is_open()) {
continue;
}
std::string line;
// Get the table size
std::getline(file, line);
std::size_t table_size = std::stoull(line);
result[0].resize(table_size);
result[1].resize(table_size);
bool parsing_failed = false;
for (std::size_t i = 0; i < table_size; i++) {
std::getline(file, line);
std::pair<value_type, value_type> pair;
value_pair_parser<decltype(line.begin()), BlueprintFieldType> parser;
boost::spirit::qi::ascii::space_type space;
bool parsing_result =
boost::spirit::qi::phrase_parse(line.begin(), line.end(), parser, space, pair);
if (!parsing_result) {
std::cerr << "Failed to parse file " << path << " as table, retrying..." << std::endl;
parsing_failed = true;
break;
}
result[0][i] = pair.first;
result[1][i] = pair.second;
}
if (!parsing_failed) {
return result;
}
}
// if all the attempts failed, return empty vector
result.resize(0);
return result;
}

} // namespace detail
} // namespace components
} // namespace blueprint
} // namespace nil
} // namespace nil
145 changes: 145 additions & 0 deletions include/nil/blueprint/detail/lookup_table_loaders.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2023 Dmitrii Tabalin <d.tabalin@nil.foundation>
//
// MIT License
//
// 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 <optional>
#include <iostream>
#include <fstream>
#include <sstream>

#include <nil/blueprint/detail/lookup_table_precomputes.hpp>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace nil {
namespace blueprint {
namespace components {
namespace detail {

template<typename Iterator, typename BlueprintFieldType>
struct value_vector_parser : boost::spirit::qi::grammar<Iterator,
std::vector<typename BlueprintFieldType::value_type>(),
boost::spirit::qi::ascii::space_type> {
using value_type = typename BlueprintFieldType::value_type;
using integral_type = typename BlueprintFieldType::integral_type;
using return_type = std::vector<value_type>;

value_vector_parser(std::size_t size) : value_vector_parser::base_type(start) {
using boost::spirit::qi::uint_parser;
using boost::spirit::qi::_val;
using boost::spirit::qi::_1;
using boost::spirit::qi::_2;
using boost::spirit::qi::repeat;
using boost::phoenix::construct;
using boost::phoenix::val;
auto number = uint_parser<integral_type, 16, 1,
(BlueprintFieldType::modulus_bits + 16 - 1) / 16>();
start = repeat(size)[number];

boost::spirit::qi::on_error<boost::spirit::qi::fail>(
start,
std::cerr << val("Error! Expecting ") << boost::spirit::qi::_4 << val(" here: \"")
<< construct<std::string>(boost::spirit::_3, boost::spirit::_2) << val("\"\n")
);
}

boost::spirit::qi::rule<Iterator, return_type(), boost::spirit::qi::ascii::space_type> start;
};

template <typename BlueprintFieldType>
bool parse_lookup_table(
std::istream &ist,
const std::size_t line_size,
std::vector<std::vector<typename BlueprintFieldType::value_type>> &result) {
using value_type = typename BlueprintFieldType::value_type;
std::string line;
// Get the table size
std::getline(ist, line);
std::size_t table_size = std::stoull(line);
result.resize(line_size);
for (auto &column : result) {
column.resize(table_size);
}
for (std::size_t i = 0; i < table_size; i++) {
std::getline(ist, line);
std::vector<value_type> row;
value_vector_parser<decltype(line.begin()), BlueprintFieldType> parser(line_size);
boost::spirit::qi::ascii::space_type space;
bool parsing_result =
boost::spirit::qi::phrase_parse(line.begin(), line.end(), parser, space, row);
if (!parsing_result) {
return false;
}
for (std::size_t j = 0; j < line_size; j++) {
result[j][i] = row[j];
}
}
return true;
}

// Loads the table from file, trying multiple different filen paths if one fails
template <typename BlueprintFieldType>
bool load_lookup_table(
const std::set<std::string> &candidate_file_paths,
const std::size_t line_size,
std::vector<std::vector<typename BlueprintFieldType::value_type>> &result) {

for (const auto &path : candidate_file_paths) {
// try opening the file
std::ifstream file(path);
if (!file.is_open()) {
continue;
}
auto status = parse_lookup_table<BlueprintFieldType>(file, line_size, result);
if (status) {
return true;
}
}
return false;
}

// This forcefully includes the table in the binary
// It's not in binary form here because for current tables the ASCII form is actually smaller
// due to the advanced compression stratgy of "we don't have to write leading zeroes"
template <typename BlueprintFieldType>
bool load_lookup_table_from_bin(
std::string table_name,
std::vector<std::vector<typename BlueprintFieldType::value_type>> &result) {

if (table_name == "8_split_4") {
const std::string table_data = _8_SPLIT_4;
std::stringstream ss(table_data);
return parse_lookup_table<BlueprintFieldType>(ss, 2, result);
} else if (table_name == "8_split_7") {
const std::string table_data = _8_SPLIT_7;
std::stringstream ss(table_data);
return parse_lookup_table<BlueprintFieldType>(ss, 2, result);
} else {
return false;
}
}
} // namespace detail
} // namespace components
} // namespace blueprint
} // namespace nil
27 changes: 27 additions & 0 deletions include/nil/blueprint/detail/lookup_table_precomputes.hpp

Large diffs are not rendered by default.

26 changes: 11 additions & 15 deletions include/nil/blueprint/lookup_library.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

#include <nil/crypto3/zk/snark/arithmetization/plonk/lookup_table_definition.hpp>
#include <nil/blueprint/components/hashes/sha2/plonk/detail/split_functions.hpp>
#include <nil/blueprint/components/hashes/sha2/plonk/detail/sha_table_generators.hpp>
#include <nil/blueprint/detail/lookup_table_loaders.hpp>
#include <nil/blueprint/manifest.hpp>
#include <nil/blueprint/assert.hpp>

Expand Down Expand Up @@ -137,13 +137,11 @@ namespace nil {
};

virtual void generate() {
std::string blueprint_path = BLUEPRINT_PATH;
this->_table = components::detail::load_sha_table<BlueprintFieldType>(
{blueprint_path + "/include/nil/blueprint/components/hashes/sha2/plonk/detail/8_split_4.txt"});
if (this->_table.size() == 0 || this->_table[0].size() == 0) {
std::cerr << "Failed to load table 8_split_4.txt!"
" Please check the paths and generate the table."
<< std::endl;
bool status = components::detail::load_lookup_table_from_bin<BlueprintFieldType>(
"8_split_4",
this->_table);
if (!status) {
std::cerr << "Failed to load table 8_split_4 from binary!" << std::endl;
BLUEPRINT_RELEASE_ASSERT(0);
}
}
Expand Down Expand Up @@ -186,13 +184,11 @@ namespace nil {
this->subtables["full"] = {{0,1}, 0, 43903};
};
virtual void generate() {
std::string blueprint_path = BLUEPRINT_PATH;
this->_table = components::detail::load_sha_table<BlueprintFieldType>(
{blueprint_path + "/include/nil/blueprint/components/hashes/sha2/plonk/detail/8_split_7.txt"});
if (this->_table.size() == 0 || this->_table[0].size() == 0) {
std::cerr << "Failed to load table 8_split_7.txt!"
" Please check the paths and generate the table."
<< std::endl;
bool status = components::detail::load_lookup_table_from_bin<BlueprintFieldType>(
"8_split_7",
this->_table);
if (!status) {
std::cerr << "Failed to load table 8_split_7 from binary!" << std::endl;
BLUEPRINT_RELEASE_ASSERT(0);
}
}
Expand Down

0 comments on commit 1357916

Please sign in to comment.