From d53507ef75c04601e439725673aaab218e83bae3 Mon Sep 17 00:00:00 2001 From: Alexander Wu Date: Sun, 18 Apr 2021 00:46:12 -0700 Subject: [PATCH 1/7] Update profiling functions to be compatible with libiop --- libff/common/profiling.cpp | 15 ++++++++++----- libff/common/profiling.hpp | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libff/common/profiling.cpp b/libff/common/profiling.cpp index 0e4c7f9f..5d69befc 100755 --- a/libff/common/profiling.cpp +++ b/libff/common/profiling.cpp @@ -108,7 +108,7 @@ void print_cumulative_time_entry(const std::string &key, const long long factor) const double total_ms = (cumulative_times.at(key) * 1e-6); const size_t cnt = invocation_counts.at(key); const double avg_ms = total_ms / cnt; - printf(" %-45s: %12.5fms = %0.5f * %0.5fms (%zu invocations, %0.5fms = %lld * %0.5fms per invocation)\n", key.c_str(), total_ms, factor, total_ms/ (double) factor, cnt, avg_ms, factor, avg_ms/ (double) factor); + printf(" %-45s: %12.5fms = %lld * %0.5fms (%zu invocations, %0.5fms = %lld * %0.5fms per invocation)\n", key.c_str(), total_ms, factor, total_ms/ (double) factor, cnt, avg_ms, factor, avg_ms/ (double) factor); } void print_cumulative_times(const long long factor) @@ -186,14 +186,14 @@ static void print_times_from_last_and_start(long long now, long long las long long cpu_time_from_last = cpu_now - cpu_last; if (time_from_last != 0) { - long long parallelism_from_last = (long long) 1.0 * cpu_time_from_last / time_from_last; - printf("[%0.4fs x%0.2f]", (double) time_from_last * 1e-9, parallelism_from_last); + double parallelism_from_last = 1.0 * cpu_time_from_last / time_from_last; + printf("[%0.4fs x%0.2f]", time_from_last * 1e-9, parallelism_from_last); } else { printf("[ ]"); } if (time_from_start != 0) { - double parallelism_from_start = 1.0 * (double) cpu_time_from_start / (double) time_from_start; - printf("\t(%0.4fs x%0.2f from start)", (double) time_from_start * 1e-9, parallelism_from_start); + double parallelism_from_start = 1.0 * cpu_time_from_start / time_from_start; + printf("\t(%0.4fs x%0.2f from start)", time_from_start * 1e-9, parallelism_from_start); } } @@ -226,6 +226,11 @@ void print_header(const char *msg) printf("================================================================================\n\n"); } +void print_separator() +{ + printf("\n================================================================================\n\n"); +} + void print_indent() { for (size_t i = 0; i < indentation; ++i) diff --git a/libff/common/profiling.hpp b/libff/common/profiling.hpp index 30edefe0..27dde838 100755 --- a/libff/common/profiling.hpp +++ b/libff/common/profiling.hpp @@ -22,6 +22,7 @@ void start_profiling(); long long get_nsec_time(); void print_time(const char* msg); void print_header(const char* msg); +void print_separator(); void print_indent(); From 5f48c31b5e66aec1312c7703cd8d51b74ef23916 Mon Sep 17 00:00:00 2001 From: Alexander Wu Date: Mon, 19 Apr 2021 18:19:35 -0700 Subject: [PATCH 2/7] Move common utils from libiop to libff --- libff/common/utils.cpp | 11 +++++++++++ libff/common/utils.hpp | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/libff/common/utils.cpp b/libff/common/utils.cpp index 22b3e4c6..9fbb34a2 100755 --- a/libff/common/utils.cpp +++ b/libff/common/utils.cpp @@ -35,6 +35,17 @@ size_t get_power_of_two(size_t n) return n; } +/* If n is a power of 2, returns n */ +size_t round_to_next_power_of_2(const size_t n) +{ + return (1ull << log2(n)); +} + +bool is_power_of_2(const size_t n) +{ + return ((n != 0) && ((n & (n-1)) == 0)); +} + size_t log2(size_t n) /* returns ceil(log2(n)), so 1ul< bit_vector; +template +struct enable_if { typedef void* type; }; + +template +struct enable_if { typedef T type; }; + std::size_t get_power_of_two(std::size_t n); +std::size_t round_to_next_power_of_2(const std::size_t n); +bool is_power_of_2(const std::size_t n); + /// returns ceil(log2(n)), so 1ul< std::size_t ceil_size_in_bits(const std::vector &v); +/* Print a vector in the form { elem0 elem1 elem2 ... }, with a newline at the end +template +void print_vector(std::vector &vec); +template +void print_vector(std::vector vec);*/ + +template +void print_vector(std::vector &vec) +{ + printf("{ "); + for (auto const& elem : vec) + { + std::cout << elem << " "; + } + printf("}\n"); +} + +template +void print_vector(std::vector vec) +{ + printf("{ "); + for (auto const& elem : vec) + { + std::cout << elem << " "; + } + printf("}\n"); +} + /** * Returns a random element of T that is not zero or one. * T can be a field or elliptic curve group. From 2396be5356d1078021a068d670d3400eca526395 Mon Sep 17 00:00:00 2001 From: Alexander Wu Date: Mon, 19 Apr 2021 19:16:16 -0700 Subject: [PATCH 3/7] Add tests for log2 --- libff/CMakeLists.txt | 44 +++++++++++++++++++++--------- libff/common/tests/test_common.cpp | 39 ++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 libff/common/tests/test_common.cpp diff --git a/libff/CMakeLists.txt b/libff/CMakeLists.txt index 6039c14b..00c8ded9 100755 --- a/libff/CMakeLists.txt +++ b/libff/CMakeLists.txt @@ -191,17 +191,30 @@ if ("${IS_LIBFF_PARENT}") ) add_executable( - algebra_binary_fields_test - EXCLUDE_FROM_ALL + algebra_binary_fields_test + EXCLUDE_FROM_ALL + + algebra/fields/tests/test_binary_fields.cpp + ) + target_link_libraries( + algebra_binary_fields_test + + ff + gtest_main + ) + + add_executable( + common_test + EXCLUDE_FROM_ALL - algebra/fields/tests/test_binary_fields.cpp - ) - target_link_libraries( - algebra_binary_fields_test + common/tests/test_common.cpp + ) + target_link_libraries( + common_test - ff - gtest_main - ) + ff + gtest_main + ) include(CTest) add_test( @@ -224,10 +237,14 @@ if ("${IS_LIBFF_PARENT}") NAME algebra_fpn_fields_test COMMAND algebra_fpn_fields_test ) - add_test( - NAME algebra_binary_fields_test - COMMAND algebra_binary_fields_test - ) + add_test( + NAME algebra_binary_fields_test + COMMAND algebra_binary_fields_test + ) + add_test( + NAME common_test + COMMAND common_test + ) add_dependencies(check algebra_bilinearity_test) add_dependencies(check algebra_groups_test) @@ -235,6 +252,7 @@ if ("${IS_LIBFF_PARENT}") add_dependencies(check algebra_all_fields_test) add_dependencies(check algebra_fpn_fields_test) add_dependencies(check algebra_binary_fields_test) + add_dependencies(check common_test) find_package(OpenSSL REQUIRED) INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) diff --git a/libff/common/tests/test_common.cpp b/libff/common/tests/test_common.cpp new file mode 100644 index 00000000..7b8440f8 --- /dev/null +++ b/libff/common/tests/test_common.cpp @@ -0,0 +1,39 @@ +/** + ***************************************************************************** + Some tests for the functions in this directory. + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include + +#include "libff/common/utils.hpp" + +using namespace libff; + +TEST(Log2Test, SimpleTest) { + // There seems to be a second log2 function that operates on floats so we added libff::. + EXPECT_EQ(libff::log2(0), 0ull); + EXPECT_EQ(libff::log2(1), 0ull); + EXPECT_EQ(libff::log2(2), 1ull); + EXPECT_EQ(libff::log2(3), 2ull); + EXPECT_EQ(libff::log2(4), 2ull); + EXPECT_EQ(libff::log2(5), 3ull); + EXPECT_EQ(libff::log2(6), 3ull); + EXPECT_EQ(libff::log2(7), 3ull); + EXPECT_EQ(libff::log2(8), 3ull); + EXPECT_EQ(libff::log2(9), 4ull); +} + +TEST(Log2Test, PowersOfTwo) { + for (std::size_t i = 10; i < 20; ++i) + { + const std::size_t k = (1ull< Date: Mon, 19 Apr 2021 21:47:14 -0700 Subject: [PATCH 4/7] Add field utils from libiop --- libff/algebra/field_utils/field_utils.hpp | 85 ++++++++++++++++++++++- libff/algebra/field_utils/field_utils.tcc | 69 +++++++++++++++++- 2 files changed, 148 insertions(+), 6 deletions(-) diff --git a/libff/algebra/field_utils/field_utils.hpp b/libff/algebra/field_utils/field_utils.hpp index b11d5641..37cd5c14 100755 --- a/libff/algebra/field_utils/field_utils.hpp +++ b/libff/algebra/field_utils/field_utils.hpp @@ -9,12 +9,91 @@ #define FIELD_UTILS_HPP_ #include -#include -#include -#include +#include "libff/algebra/field_utils/bigint.hpp" +#include "libff/common/double.hpp" +#include "libff/common/utils.hpp" + +#include "libff/algebra/fields/binary/gf64.hpp" +#include "libff/algebra/fields/binary/gf128.hpp" +#include "libff/algebra/fields/binary/gf192.hpp" +#include "libff/algebra/fields/binary/gf256.hpp" +#include "libff/algebra/fields/prime_base/fp.hpp" namespace libff { +template +struct is_additive { + static const bool value = false; +}; + +template<> +struct is_additive { + static const bool value = true; +}; + +template<> +struct is_additive { + static const bool value = true; +}; + +template<> +struct is_additive { + static const bool value = true; +}; + +template<> +struct is_additive { + static const bool value = true; +}; + +template +struct is_multiplicative { + static const bool value = false; +}; + +template& modulus> +struct is_multiplicative> { + static const bool value = true; +}; + +enum field_type { + multiplicative_field_type = 1, + additive_field_type = 2 +}; + +template +field_type get_field_type(const typename enable_if::value, FieldT>::type elem); + +template +field_type get_field_type(const typename enable_if::value, FieldT>::type elem); + +template +std::size_t log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem); + +template +std::size_t log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem); + +template +std::size_t soundness_log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem); + +template +std::size_t soundness_log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem); + +template +std::size_t get_word_of_field_elem( + typename enable_if::value, FieldT>::type field_elem, size_t word); + +template +std::size_t get_word_of_field_elem( + typename enable_if::value, FieldT>::type field_elem, size_t word); + +template +FieldT coset_shift(); + // returns root of unity of order n (for n a power of 2), if one exists template typename std::enable_if::value, FieldT>::type diff --git a/libff/algebra/field_utils/field_utils.tcc b/libff/algebra/field_utils/field_utils.tcc index f0c674e6..040c5a83 100755 --- a/libff/algebra/field_utils/field_utils.tcc +++ b/libff/algebra/field_utils/field_utils.tcc @@ -13,13 +13,76 @@ #include #include -#include -#include - namespace libff { using std::size_t; +template +field_type get_field_type(const typename enable_if::value, FieldT>::type elem) +{ + UNUSED(elem); // only to identify field type + return multiplicative_field_type; +} + +template +field_type get_field_type(const typename enable_if::value, FieldT>::type elem) +{ + UNUSED(elem); // only to identify field type + return additive_field_type; +} + +template +std::size_t log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem) +{ + UNUSED(field_elem); + return FieldT::ceil_size_in_bits(); +} + +template +std::size_t log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem) +{ + UNUSED(field_elem); + return FieldT::extension_degree(); +} + +template +std::size_t soundness_log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem) +{ + UNUSED(field_elem); + /** size in bits is the number of bits needed to represent a field element. + * However there isn't perfect alignment between the number of bits and the number of field elements, + * there could be a factor of two difference. + * For calculating soundness, we use the log of field size as number of bits - 1, + * as (2 << returned) size lower bounds the actual size. + */ + return FieldT::ceil_size_in_bits() - 1; +} + +template +std::size_t soundness_log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem) +{ + UNUSED(field_elem); + return FieldT::extension_degree(); +} + +template +std::size_t get_word_of_field_elem( + typename enable_if::value, FieldT>::type field_elem, size_t word) +{ + return field_elem.to_words()[word]; +} + +template +std::size_t get_word_of_field_elem( + typename enable_if::value, FieldT>::type field_elem, size_t word) +{ + return field_elem.as_bigint().data[word]; +} + template FieldT coset_shift() { From 372555affcf4c8eb144c128cc967e2acaea567c8 Mon Sep 17 00:00:00 2001 From: Alexander Wu Date: Tue, 20 Apr 2021 15:59:30 -0700 Subject: [PATCH 5/7] Fix infinite recursion in double --- libff/common/double.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libff/common/double.cpp b/libff/common/double.cpp index 8a8130ec..e19671ec 100755 --- a/libff/common/double.cpp +++ b/libff/common/double.cpp @@ -117,7 +117,7 @@ bool Double::operator==(const Double &other) const bool Double::operator!=(const Double &other) const { - return Double(val) != other; + return !(*this == other); } bool Double::operator<(const Double &other) const From ea0ee273d26fd1463e15f125e1b0ff9929f24f32 Mon Sep 17 00:00:00 2001 From: Alexander Wu Date: Fri, 23 Apr 2021 17:03:19 -0700 Subject: [PATCH 6/7] Add power as well as its tests from libiop --- libff/algebra/field_utils/algorithms.hpp | 10 ++++ libff/algebra/field_utils/algorithms.tcc | 52 +++++++++++++++++++ .../field_utils/tests/test_field_utils.cpp | 40 +++++++++++++- 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/libff/algebra/field_utils/algorithms.hpp b/libff/algebra/field_utils/algorithms.hpp index f573a271..f0829b82 100755 --- a/libff/algebra/field_utils/algorithms.hpp +++ b/libff/algebra/field_utils/algorithms.hpp @@ -25,6 +25,16 @@ FieldT power(const FieldT &base, const bigint &exponent); template FieldT power(const FieldT &base, const unsigned long exponent); +/** + * The unsigned long long versions exist because libiop tends to use size_t instead + * of unsigned long, and size_t may be the same size as ul or ull. + */ +template +FieldT power(const FieldT &base, const unsigned long long exponent); + +template +FieldT power(const FieldT &base, const std::vector exponent); + /** * Tonelli-Shanks square root with given s, t, and quadratic non-residue. * Only terminates if there is a square root. Only works if required parameters diff --git a/libff/algebra/field_utils/algorithms.tcc b/libff/algebra/field_utils/algorithms.tcc index 2b6c9169..0109a000 100755 --- a/libff/algebra/field_utils/algorithms.tcc +++ b/libff/algebra/field_utils/algorithms.tcc @@ -47,6 +47,58 @@ FieldT power(const FieldT &base, const unsigned long exponent) return power(base, bigint<1>(exponent)); } +template +FieldT power(const FieldT &base, const unsigned long long exponent) +{ + FieldT result = FieldT::one(); + + bool found_one = false; + + for (long i = 8 * sizeof(exponent) - 1; i >= 0; --i) + { + if (found_one) + { + result = result.squared(); + } + + if (exponent & (1ull << i)) + { + found_one = true; + result *= base; + } + } + + return result; +} + +template +FieldT power(const FieldT &base, const std::vector exponent) +{ + FieldT result = FieldT::one(); + + bool found_one = false; + + for (unsigned long long j = 0; j < exponent.size(); j++) + { + unsigned long long cur_exp = exponent[j]; + for (long i = 8 * sizeof(cur_exp) - 1; i >= 0; --i) + { + if (found_one) + { + result = result.squared(); + } + + if (cur_exp & (1ull << i)) + { + found_one = true; + result *= base; + } + } + } + + return result; +} + template FieldT tonelli_shanks_sqrt(const FieldT &value) { diff --git a/libff/algebra/field_utils/tests/test_field_utils.cpp b/libff/algebra/field_utils/tests/test_field_utils.cpp index 3b293f03..33143724 100644 --- a/libff/algebra/field_utils/tests/test_field_utils.cpp +++ b/libff/algebra/field_utils/tests/test_field_utils.cpp @@ -1,16 +1,54 @@ /** ***************************************************************************** - Basic tests for some of the field utils in this directory, mainly bigint. + Basic tests for some of the field utils in this directory, mainly bigint + and power. ***************************************************************************** * @author This file is part of libff, developed by SCIPR Lab * and contributors (see AUTHORS). * @copyright MIT license (see LICENSE file) *****************************************************************************/ #include "libff/algebra/field_utils/bigint.hpp" +#include "libff/algebra/field_utils/algorithms.hpp" +#include "libff/algebra/fields/binary/gf64.hpp" #include using namespace libff; +template +FieldT power_naive(const FieldT &base, const std::size_t exponent) +{ + FieldT result = FieldT::one(); + + for (std::size_t i = 1; i <= exponent; ++i) + { + result *= base; + } + + return result; +} + + +TEST(ExponentiationTest, SimpleTest) { + typedef gf64 FieldT; + + const unsigned long max_power = 3000; + FieldT X = FieldT::random_element(); + + FieldT X_i = FieldT::one(); + for (unsigned long i = 0 ; i < max_power; ++i) + { + const FieldT X_i_naive = power_naive(X, i); + const FieldT X_i_square_and_multiply_ul = power(X, i); + const FieldT X_i_square_and_multiply_ull = power(X, (unsigned long long) i); + + EXPECT_EQ(X_i, X_i_naive); + EXPECT_EQ(X_i, X_i_square_and_multiply_ul); + EXPECT_EQ(X_i, X_i_square_and_multiply_ull); + + X_i *= X; + } +} + TEST(FieldUtilsTest, BigintTest) { bigint<3> zero = bigint<3>("0"); From 31cbad4a4724a12940b9bd90159f7450dc615b40 Mon Sep 17 00:00:00 2001 From: Alexander Wu Date: Fri, 23 Apr 2021 17:43:12 -0700 Subject: [PATCH 7/7] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f574f73d..8aebad38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This update introduces new field and curve API's, and enforces they are used con - #83 Make run-clang-tidy return an error when linting fails - #85 Add more unit tests for fields (Thanks @alexander-zw) - #86 Add binary fields from [libiop](https://github.com/scipr-lab/libiop) +- #100 Move utils in from [libiop](https://github.com/scipr-lab/libiop) ### Bug fixes - #75 Get rid of warning for unused constant PI, in complex field