diff --git a/include/nil/blueprint/basic_non_native_policy.hpp b/include/nil/blueprint/basic_non_native_policy.hpp index c591880da..1bdc2daca 100644 --- a/include/nil/blueprint/basic_non_native_policy.hpp +++ b/include/nil/blueprint/basic_non_native_policy.hpp @@ -28,70 +28,32 @@ #include #include - +#include #include +#include + namespace nil { namespace blueprint { namespace detail { + template - struct basic_non_native_policy_field_type; + struct basic_non_native_policy_field_type + : public basic_non_native_policy_field_type_base> { }; /* * Specialization for non-native Ed25519 base field element on Pallas base field */ template<> struct basic_non_native_policy_field_type { - - constexpr static const std::uint32_t ratio = 4; // 66,66,66,66 bits - using non_native_field_type = typename crypto3::algebra::curves::ed25519::base_field_type; - using native_field_type = typename crypto3::algebra::curves::pallas::base_field_type; - using var = crypto3::zk::snark::plonk_variable; - - typedef std::array non_native_var_type; - typedef std::array chopped_value_type; - - constexpr static const std::array chunk_sizes = {66, 66, 66, 66}; - - - static native_field_type::value_type get_i_th_chunk(non_native_field_type::value_type input, - std::size_t i_th) { - assert(i_th < ratio && "non-native type does not have that much chunks!"); - native_field_type::extended_integral_type result = native_field_type::extended_integral_type(input.data); - native_field_type::integral_type base = 1; - native_field_type::integral_type mask = (base << chunk_sizes[i_th]) - 1; - std::size_t shift = 0; - for (std::size_t i = 1; i <= i_th; i++) { - shift += chunk_sizes[i - 1]; - } - - return (result >> shift) & mask; - } - - - static chopped_value_type chop_non_native(non_native_field_type::value_type input) { - chopped_value_type result; - for (std::size_t i = 0; i < ratio; i++) { - result[i] = get_i_th_chunk(input, i); - } - return result; - } - - static non_native_field_type::value_type glue_non_native(chopped_value_type input) { - non_native_field_type::value_type result; - native_field_type::integral_type integral_input; - result = non_native_field_type::value_type(native_field_type::integral_type(input[0].data)); - for (std::size_t i = 1; i < ratio; i++) { - std::size_t shift = 0; - for (std::size_t j = 0; j < i; j++) { - shift += chunk_sizes[j]; - } - result += non_native_field_type::value_type(native_field_type::integral_type(input[i].data) << shift); - } - return result; - } + typename crypto3::algebra::curves::ed25519::base_field_type> + : public basic_non_native_policy_field_type_base< + typename crypto3::algebra::curves::pallas::base_field_type, + typename crypto3::algebra::curves::ed25519::base_field_type, + chopped_lengths_storage<58, 66, 66, 66>> { + using basic_non_native_policy_field_type_base::chopped_value_type; }; /* @@ -101,78 +63,30 @@ namespace nil { struct basic_non_native_policy_field_type { - constexpr static const std::uint32_t ratio = 1; - - typedef crypto3::zk::snark::plonk_variable - non_native_var_type; + using non_native_var_type = crypto3::zk::snark::plonk_variable< + typename crypto3::algebra::curves::pallas::base_field_type::value_type>; }; - /* - * Specialization for non-native Pallas scalar field element on Pallas base field - */ + // /* + // * Specialization for non-native Pallas scalar field element on Pallas base field + // */ template<> struct basic_non_native_policy_field_type { - - constexpr static const std::uint32_t ratio = 2; // 254, 1 bits - using non_native_field_type = typename crypto3::algebra::curves::pallas::scalar_field_type; - using native_field_type = typename crypto3::algebra::curves::pallas::base_field_type; - using var = crypto3::zk::snark::plonk_variable; - - typedef std::array non_native_var_type; - typedef std::array chopped_value_type; - - constexpr static const std::array chunk_sizes = {254, 1}; - - - static native_field_type::value_type get_i_th_chunk(non_native_field_type::value_type input, - std::size_t i_th) { - assert(i_th < ratio && "non-native type does not have that much chunks!"); - native_field_type::extended_integral_type result = native_field_type::extended_integral_type(input.data); - native_field_type::integral_type base = 1; - native_field_type::integral_type mask = (base << chunk_sizes[i_th]) - 1; - std::size_t shift = 0; - for (std::size_t i = 1; i <= i_th; i++) { - shift += chunk_sizes[i - 1]; - } - - return (result >> shift) & mask; - } - - - static chopped_value_type chop_non_native(non_native_field_type::value_type input) { - chopped_value_type result; - for (std::size_t i = 0; i < ratio; i++) { - result[i] = get_i_th_chunk(input, i); - } - return result; - } - - static non_native_field_type::value_type glue_non_native(chopped_value_type input) { - non_native_field_type::value_type result; - native_field_type::integral_type integral_input; - result = non_native_field_type::value_type(native_field_type::integral_type(input[0].data)); - for (std::size_t i = 1; i < ratio; i++) { - std::size_t shift = 0; - for (std::size_t j = 0; j < i; j++) { - shift += chunk_sizes[j]; - } - result += non_native_field_type::value_type(native_field_type::integral_type(input[i].data) << shift); - } - return result; - } + typename crypto3::algebra::curves::pallas::scalar_field_type> + : public basic_non_native_policy_field_type_base< + typename crypto3::algebra::curves::pallas::base_field_type, + typename crypto3::algebra::curves::pallas::scalar_field_type, chopped_lengths_storage<2, 254>> { + using basic_non_native_policy_field_type_base::chopped_value_type; }; - /* - * Native element type. - */ + // /* + // * Native element type. + // */ template struct basic_non_native_policy_field_type { - constexpr static const std::uint32_t ratio = 1; - - typedef crypto3::zk::snark::plonk_variable value_type; + using value_type = crypto3::zk::snark::plonk_variable; }; } // namespace detail @@ -189,8 +103,6 @@ namespace nil { using field = typename detail::basic_non_native_policy_field_type; }; - - } // namespace blueprint } // namespace nil diff --git a/include/nil/blueprint/detail/basic_non_native_policy.hpp b/include/nil/blueprint/detail/basic_non_native_policy.hpp new file mode 100644 index 000000000..819744bc8 --- /dev/null +++ b/include/nil/blueprint/detail/basic_non_native_policy.hpp @@ -0,0 +1,113 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2020-2022 Mikhail Komarov +// Copyright (c) 2020-2022 Nikita Kaskov +// +// 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. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BLUEPRINT_BASIC_NON_NATIVE_POLICY_DETAIL_HPP +#define CRYPTO3_BLUEPRINT_BASIC_NON_NATIVE_POLICY_DETAIL_HPP + +#include + +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace detail { + + template + struct chopped_lengths_storage { + static constexpr std::size_t values[] = {Ns...}; + }; + + template + struct basic_non_native_policy_field_type_base { + using non_native_field_t = OperatingFieldType; + using native_field_t = BlueprintFieldType; + using var_t = crypto3::zk::snark::plonk_variable; + + static constexpr std::size_t chopped_elements_amount = + sizeof(chopped_lengths_storage::values) / sizeof(std::size_t); + static_assert(chopped_elements_amount != 0, + "native_bit_lengths must be specialized for the field types"); + + using chopped_value_type = std::array; + using non_native_var_t = std::array; + + static chopped_value_type chop_non_native(typename non_native_field_t::value_type input) { + using unit_type = unsigned char; + nil::marshalling::status_type status; + + std::vector cv = marshalling::pack(input, status); + + // TODO: Check status here? + + chopping_field chopping_field_instance = marshalling::pack(input, status); + + // TODO: Check status here? + + auto &members = chopping_field_instance.value(); + return convert_to_chopped_value_type(members, std::make_index_sequence {}); + } + + private: + using be_field_base_t = marshalling::field_type; + + template + using intermediate_t = + crypto3::marshalling::types::pure_field_element>; + + // We need to reverse the lengths, because that's how the serialization works. Fields are written from + // right to left + template + using intermediate_for_index_t = + intermediate_t; + + template + static constexpr std::tuple...> + generate_bitfield_tuple(std::index_sequence) { + return {}; + } + + using chopping_field = nil::crypto3::marshalling::types::bitfield< + be_field_base_t, + decltype(generate_bitfield_tuple(std::make_index_sequence {}))>; + + template + static chopped_value_type + convert_to_chopped_value_type(const typename chopping_field::value_type &members, + std::index_sequence) { + return {std::get(members).value()...}; + } + }; + + } // namespace detail + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BLUEPRINT_BASIC_NON_NATIVE_POLICY_DETAIL_HPP diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a1647f8ce..b7755995d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -75,6 +75,7 @@ set(NON_NATIVE_TESTS_FILES "algebra/fields/plonk/non_native/comparison_flag" "algebra/fields/plonk/non_native/equality_flag" "algebra/fields/plonk/non_native/division_remainder" + "algebra/fields/plonk/non_native/non_native_policy" "non_native/plonk/bool_scalar_multiplication" "non_native/plonk/add_mul_zkllvm_compatible" "non_native/plonk/scalar_non_native_range" diff --git a/test/algebra/fields/plonk/non_native/addition.cpp b/test/algebra/fields/plonk/non_native/addition.cpp index f5a8f5c33..431b0ca11 100644 --- a/test/algebra/fields/plonk/non_native/addition.cpp +++ b/test/algebra/fields/plonk/non_native/addition.cpp @@ -44,7 +44,7 @@ #include #include -#include <../test/algebra/fields/plonk/non_native/chop_and_glue_non_native.hpp> +#include <../test/algebra/fields/plonk/non_native/glue_non_native.hpp> #include "../../../../test_plonk_component.hpp" @@ -95,10 +95,16 @@ void test_field_add(const std::vector & template void test_field_add_useable(typename NonNativeFieldType::value_type a, typename NonNativeFieldType::value_type b){ - using chunked_non_native_type = std::array; - chunked_non_native_type first = chop_non_native(a); - chunked_non_native_type second = chop_non_native(b); - chunked_non_native_type expected_result = chop_non_native(a + b); + using non_native_policy_type = + blueprint::detail::basic_non_native_policy_field_type< + FieldType, + NonNativeFieldType + >; + using chunked_non_native_type = typename non_native_policy_type::chopped_value_type; + + chunked_non_native_type first = non_native_policy_type::chop_non_native(a); + chunked_non_native_type second = non_native_policy_type::chop_non_native(b); + chunked_non_native_type expected_result = non_native_policy_type::chop_non_native(a + b); std::vector public_input = create_public_input(first, second); test_field_add(public_input, expected_result); } @@ -146,4 +152,4 @@ BOOST_AUTO_TEST_CASE(blueprint_non_native_addition_pallas) { test_field_add_all_cases(); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/algebra/fields/plonk/non_native/chop_and_glue_non_native.hpp b/test/algebra/fields/plonk/non_native/glue_non_native.hpp similarity index 67% rename from test/algebra/fields/plonk/non_native/chop_and_glue_non_native.hpp rename to test/algebra/fields/plonk/non_native/glue_non_native.hpp index eca34fedc..7c61c04a1 100644 --- a/test/algebra/fields/plonk/non_native/chop_and_glue_non_native.hpp +++ b/test/algebra/fields/plonk/non_native/glue_non_native.hpp @@ -1,29 +1,17 @@ -template -std::array chop_non_native(typename NonNativeFieldType::value_type input) { - typename NonNativeFieldType::integral_type input_integral = typename NonNativeFieldType::integral_type(input.data); - - std::array output; - - typename NonNativeFieldType::integral_type base = 1; - typename NonNativeFieldType::integral_type mask = (base << 66) - 1; +#include +#include +#include - output[0] = input_integral & mask; - output[1] = (input_integral >> 66) & mask; - output[2] = (input_integral >> 132) & mask; - output[3] = (input_integral >> 198) & mask; - - return output; -} template typename NonNativeFieldType::value_type glue_non_native(std::array input) { typename NonNativeFieldType::integral_type base = 1; - typename NonNativeFieldType::integral_type chunk_size = (base << 66); + typename NonNativeFieldType::integral_type chunk_non_reachable_value = (base << 66); std::array input_integral; for (std::size_t i = 0; i < input.size(); i++) { - assert(input[i] < chunk_size); + assert(input[i] < chunk_non_reachable_value); input_integral[i] = typename FieldType::integral_type(input[i].data); } @@ -56,4 +44,4 @@ std::vector public_input.push_back(b[i]); } return public_input; -} \ No newline at end of file +} diff --git a/test/algebra/fields/plonk/non_native/multiplication.cpp b/test/algebra/fields/plonk/non_native/multiplication.cpp index 20dafdb93..a9b9d4273 100644 --- a/test/algebra/fields/plonk/non_native/multiplication.cpp +++ b/test/algebra/fields/plonk/non_native/multiplication.cpp @@ -44,7 +44,7 @@ #include #include -#include <../test/algebra/fields/plonk/non_native/chop_and_glue_non_native.hpp> +#include <../test/algebra/fields/plonk/non_native/glue_non_native.hpp> #include "../../../../test_plonk_component.hpp" @@ -157,10 +157,15 @@ void test_field_mul_with_stretching(const std::vector void test_field_mul_useable(typename NonNativeFieldType::value_type a, typename NonNativeFieldType::value_type b) { - using chunked_non_native_type = std::array; - chunked_non_native_type first = chop_non_native(a); - chunked_non_native_type second = chop_non_native(b); - chunked_non_native_type expected_result = chop_non_native(a * b); + using non_native_policy_type = + blueprint::detail::basic_non_native_policy_field_type< + FieldType, + NonNativeFieldType + >; + using chunked_non_native_type = typename non_native_policy_type::chopped_value_type; + chunked_non_native_type first = non_native_policy_type::chop_non_native(a); + chunked_non_native_type second = non_native_policy_type::chop_non_native(b); + chunked_non_native_type expected_result = non_native_policy_type::chop_non_native(a * b); std::vector public_input = create_public_input(first, second); test_field_mul_with_stretching(public_input, expected_result); @@ -223,4 +228,4 @@ BOOST_AUTO_TEST_CASE(blueprint_non_native_multiplication_pallas) { test_field_mul_all_cases(); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/algebra/fields/plonk/non_native/non_native_policy.cpp b/test/algebra/fields/plonk/non_native/non_native_policy.cpp new file mode 100644 index 000000000..3340317cf --- /dev/null +++ b/test/algebra/fields/plonk/non_native/non_native_policy.cpp @@ -0,0 +1,45 @@ +#define BOOST_TEST_MODULE blueprint_algebra_fields_plonk_non_native_non_native_policy_test + +#include + +#include + +#include +#include <../test/algebra/fields/plonk/non_native/glue_non_native.hpp> + +using namespace nil; + +template +void test_chopping(const typename NonNativeFieldType::value_type &non_native_field_el) { + using non_native_policy_type = + blueprint::detail::basic_non_native_policy_field_type; + using chunked_non_native_type = typename non_native_policy_type::chopped_value_type; + + auto chopping_result = non_native_policy_type::chop_non_native(non_native_field_el); + std::cout << std::hex; + + for (std::size_t i = 0; i < 4; i++) { + std::cout << chopping_result[i].data << " "; + } + + assert((glue_non_native(chopping_result)) == non_native_field_el); +} + +BOOST_AUTO_TEST_SUITE(blueprint_non_native_policy_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_non_native_policy_25519) { + using non_native_field_type = typename crypto3::algebra::curves::ed25519::base_field_type; + using native_field_type = crypto3::algebra::curves::pallas::base_field_type; + test_chopping(0x0); + test_chopping( + 0x274dbce8d15179969bc0d49fa725bddf9de555e0ba6a693c6adb52fc9ee7a82c_cppui252); + test_chopping( + 0x5ce98c61b05f47fe2eae9a542bd99f6b2e78246231640b54595febfd51eb853_cppui252); + test_chopping( + 0x2ad46cbfb78773b6254adc1d80c6efa02f3bf948c37e5a2222136421d7bec942_cppui252); + test_chopping( + 0x14e9693f16d75f7065ce51e1f46ae6c60841ca1e0cf264eda26398e36ca2ed69_cppui252); + test_chopping(non_native_field_type::modulus - 1); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/algebra/fields/plonk/non_native/range.cpp b/test/algebra/fields/plonk/non_native/range.cpp index 24d306ec3..df9a83f20 100644 --- a/test/algebra/fields/plonk/non_native/range.cpp +++ b/test/algebra/fields/plonk/non_native/range.cpp @@ -40,7 +40,7 @@ #include #include -#include <../test/algebra/fields/plonk/non_native/chop_and_glue_non_native.hpp> +#include <../test/algebra/fields/plonk/non_native/glue_non_native.hpp> #include "../../../../test_plonk_component.hpp" @@ -99,21 +99,27 @@ BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) BOOST_AUTO_TEST_CASE(blueprint_non_native_range_test0) { using non_native_field_type = typename crypto3::algebra::fields::curve25519_base_field; using field_type = crypto3::algebra::curves::pallas::base_field_type; + using non_native_policy_type = + blueprint::detail::basic_non_native_policy_field_type< + field_type, + non_native_field_type + >; + using chunked_non_native_type = typename non_native_policy_type::chopped_value_type; test_field_range( {455245345345345, 523553453454343, 68753453534534689, 54355345344544}, true); test_field_range( create_public_input_1_value( - chop_non_native(1) + non_native_policy_type::chop_non_native(1) ), true); test_field_range( create_public_input_1_value( - chop_non_native(0) + non_native_policy_type::chop_non_native(0) ), true); test_field_range( create_public_input_1_value( - chop_non_native(-1) + non_native_policy_type::chop_non_native(-1) ), true); nil::crypto3::random::algebraic_engine rand; @@ -123,7 +129,7 @@ BOOST_AUTO_TEST_CASE(blueprint_non_native_range_test0) { for (std::size_t i = 0; i < 10; i++) { test_field_range( create_public_input_1_value( - chop_non_native(rand()) + non_native_policy_type::chop_non_native(rand()) ), true); } } @@ -141,4 +147,4 @@ BOOST_AUTO_TEST_CASE(blueprint_non_native_range_test_must_fail) { ); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/algebra/fields/plonk/non_native/subtraction.cpp b/test/algebra/fields/plonk/non_native/subtraction.cpp index abbe0a797..24487e992 100644 --- a/test/algebra/fields/plonk/non_native/subtraction.cpp +++ b/test/algebra/fields/plonk/non_native/subtraction.cpp @@ -42,7 +42,7 @@ #include #include -#include <../test/algebra/fields/plonk/non_native/chop_and_glue_non_native.hpp> +#include <../test/algebra/fields/plonk/non_native/glue_non_native.hpp> #include #include "../../../../test_plonk_component.hpp" @@ -125,10 +125,15 @@ BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) template void test_field_sub_useable(typename NonNativeFieldType::value_type a, typename NonNativeFieldType::value_type b){ - using chunked_non_native_type = std::array; - chunked_non_native_type first = chop_non_native(a); - chunked_non_native_type second = chop_non_native(b); - chunked_non_native_type expected_result = chop_non_native(a - b); + using non_native_policy_type = + blueprint::detail::basic_non_native_policy_field_type< + FieldType, + NonNativeFieldType + >; + using chunked_non_native_type = typename non_native_policy_type::chopped_value_type; + chunked_non_native_type first = non_native_policy_type::chop_non_native(a); + chunked_non_native_type second = non_native_policy_type::chop_non_native(b); + chunked_non_native_type expected_result = non_native_policy_type::chop_non_native(a - b); std::vector public_input = create_public_input(first, second); test_field_sub(public_input, expected_result); } @@ -182,4 +187,4 @@ BOOST_AUTO_TEST_CASE(blueprint_non_native_subtraction_pallas) { test_field_sub_all_cases(); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/non_native/plonk/bool_scalar_multiplication.cpp b/test/non_native/plonk/bool_scalar_multiplication.cpp index bec40d923..42b94f389 100644 --- a/test/non_native/plonk/bool_scalar_multiplication.cpp +++ b/test/non_native/plonk/bool_scalar_multiplication.cpp @@ -32,7 +32,7 @@ #include #include #include -#include <../test/algebra/fields/plonk/non_native/chop_and_glue_non_native.hpp> +#include <../test/algebra/fields/plonk/non_native/glue_non_native.hpp> #include @@ -157,14 +157,24 @@ void test_bool_scalar_multiplication(const std::vector void test_bool_scalar_multiplication_usable( - typename NonNativeCurveType::template g1_type::value_type point, + typename NonNativeCurveType::template g1_type< + crypto3::algebra::curves::coordinates::affine + >::value_type point, typename FieldType::value_type scalar_bool, - const bool expected_to_pass) { + const bool expected_to_pass +) { + + using non_native_policy_type = + blueprint::detail::basic_non_native_policy_field_type< + FieldType, + typename NonNativeCurveType::base_field_type + >; std::vector public_input = create_public_input( - chop_non_native(point.X), - chop_non_native(point.Y)); + non_native_policy_type::chop_non_native(point.X), + non_native_policy_type::chop_non_native(point.Y) + ); std::vector expected_res; if (scalar_bool == 1) { @@ -220,4 +230,4 @@ BOOST_AUTO_TEST_CASE(blueprint_non_native_bool_scalar_mul_must_fail) { test_bool_scalar_multiplication_usable(rand(), -1, false); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END()