diff --git a/.github/workflows/wide_integer_fuzzing.yml b/.github/workflows/wide_integer_fuzzing.yml new file mode 100644 index 0000000..a945329 --- /dev/null +++ b/.github/workflows/wide_integer_fuzzing.yml @@ -0,0 +1,49 @@ +# ------------------------------------------------------------------------------ +# Copyright Christopher Kormanyos 2024. +# Distributed under the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt +# or copy at http://www.boost.org/LICENSE_1_0.txt) +# ------------------------------------------------------------------------------ + +name: wide_integer_fuzzing +on: + push: + branches: + - '**' + pull_request: + schedule: + - cron: '15 2 * * *' # run at 2:15 AM UTC +jobs: + clang-fuzzing: + runs-on: ubuntu-latest + defaults: + run: + shell: bash + strategy: + fail-fast: false + matrix: + tcase: [ add, sub, mul, div ] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: '0' + - name: update-tools + run: sudo apt install llvm lld + - name: clone-submods-bootstrap-headers-boost-develop + run: | + git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root + cd ../boost-root + git submodule update --init tools + git submodule update --init libs/config + git submodule update --init libs/multiprecision + ./bootstrap.sh + ./b2 headers + - name: clang-fuzzing + run: | + grep BOOST_VERSION ../boost-root/boost/version.hpp + echo "compile and instrument fuzzing test" + clang++ -v + clang++ -g -O2 -fsanitize=fuzzer,address,undefined -I. -I../boost-root test/fuzzing/test_fuzzing_${{ matrix.tcase }}.cpp -o test_fuzzing_${{ matrix.tcase }} + echo "ls test_fuzzing_${{ matrix.tcase }}" + ls -la test_fuzzing_${{ matrix.tcase }} + ./test_fuzzing_${{ matrix.tcase }} -max_total_time=240 diff --git a/README.md b/README.md index 1fb7f41..3132a50 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@

Build Status + + Build Status Issues @@ -340,6 +342,8 @@ as well as in offline checks to improve static code quality. GCC's run-time [sanitizers](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html) are used in CI in order to help assure dynamic quality. +This effort also includes _fuzzing_ with +[libFuzzer](https://llvm.org/docs/LibFuzzer.html). Additional quality checks are performed on pull-request and merge to master using modern third party open-source services. diff --git a/test/fuzzing/test_fuzzing_add.cpp b/test/fuzzing/test_fuzzing_add.cpp new file mode 100644 index 0000000..b2d11e1 --- /dev/null +++ b/test/fuzzing/test_fuzzing_add.cpp @@ -0,0 +1,127 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer +// clang++ -g -O2 -fsanitize=fuzzer,address,undefined -I. -I/mnt/c/boost/boost_1_85_0 test/fuzzing/test_fuzzing_add.cpp -o test_fuzzing_add +// ./test_fuzzing_add -max_total_time=180 + +#include + +#include + +#include +#include +#include +#include +#include + +namespace fuzzing +{ + using boost_uint_backend_type = + boost::multiprecision::cpp_int_backend(UINT32_C(256)), + static_cast(UINT32_C(256)), + boost::multiprecision::unsigned_magnitude>; + + using boost_uint_type = boost::multiprecision::number; + + using local_uint_type = ::math::wide_integer::uint256_t; + + auto eval_add(const std::uint8_t* data, std::size_t size) -> bool; +} + +auto fuzzing::eval_add(const std::uint8_t* data, std::size_t size) -> bool +{ + const std::size_t + max_size + { + static_cast + ( + std::numeric_limits::digits / 8 + ) + }; + + bool result_is_ok { true }; + + if((size > std::size_t { UINT8_C(1) }) && (size <= std::size_t { max_size * 2U })) + { + local_uint_type a_local { }; + local_uint_type b_local { }; + + boost_uint_type a_boost { }; + boost_uint_type b_boost { }; + + // Import data into their respective uintwide_t a and b values. + import_bits + ( + a_local, + data, + data + std::size_t { size / 2U }, + 8U + ); + + import_bits + ( + b_local, + data + std::size_t { size / 2U }, + data + size, + 8U + ); + + // Import data into their respective boost-based a and b values. + import_bits + ( + a_boost, + data, + data + std::size_t { size / 2U }, + 8U + ); + + import_bits + ( + b_boost, + data + std::size_t { size / 2U }, + data + size, + 8U + ); + + local_uint_type result_local { a_local + b_local }; + boost_uint_type result_boost { a_boost + b_boost }; + + std::vector result_data_local(max_size, UINT8_C(0)); + std::vector result_data_boost(result_data_local.size(), UINT8_C(0)); + + export_bits(result_local, result_data_local.data(), 8U); + export_bits(result_boost, result_data_boost.data(), 8U); + + // Verify that both uintwide_t as well as boost obtain the same result. + const bool result_add_is_ok = + std::equal + ( + result_data_local.cbegin(), + result_data_local.cend(), + result_data_boost.cbegin(), + result_data_boost.cend() + ); + + result_is_ok = (result_add_is_ok && result_is_ok); + } + + // Assert the correct result. + assert(result_is_ok); + + return result_is_ok; +} + +// The fuzzing entry point. +extern "C" +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + const bool result_one_add_is_ok { fuzzing::eval_add(data, size) }; + + return (result_one_add_is_ok ? 0 : -1); +} diff --git a/test/fuzzing/test_fuzzing_div.cpp b/test/fuzzing/test_fuzzing_div.cpp new file mode 100644 index 0000000..85c497c --- /dev/null +++ b/test/fuzzing/test_fuzzing_div.cpp @@ -0,0 +1,136 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer +// clang++ -g -O2 -fsanitize=fuzzer,address,undefined -I. -I/mnt/c/boost/boost_1_85_0 test/fuzzing/test_fuzzing_div.cpp -o test_fuzzing_div +// ./test_fuzzing_div -max_total_time=180 + +#include + +#include + +#include +#include +#include +#include +#include + +namespace fuzzing +{ + using boost_uint_backend_type = + boost::multiprecision::cpp_int_backend(UINT32_C(256)), + static_cast(UINT32_C(256)), + boost::multiprecision::unsigned_magnitude>; + + using boost_uint_type = boost::multiprecision::number; + + using local_uint_type = ::math::wide_integer::uint256_t; + + auto eval_div(const std::uint8_t* data, std::size_t size) -> bool; +} + +auto fuzzing::eval_div(const std::uint8_t* data, std::size_t size) -> bool +{ + const std::size_t + max_size + { + static_cast + ( + std::numeric_limits::digits / 8 + ) + }; + + bool result_is_ok { true }; + + if((size > std::size_t { UINT8_C(1) }) && (size <= std::size_t { max_size * 2U })) + { + local_uint_type a_local { }; + local_uint_type b_local { }; + + boost_uint_type a_boost { }; + boost_uint_type b_boost { }; + + // Import data into their respective uintwide_t a and b values. + import_bits + ( + a_local, + data, + data + std::size_t { size / 2U }, + 8U + ); + + import_bits + ( + b_local, + data + std::size_t { size / 2U }, + data + size, + 8U + ); + + // Import data into their respective boost-based a and b values. + import_bits + ( + a_boost, + data, + data + std::size_t { size / 2U }, + 8U + ); + + import_bits + ( + b_boost, + data + std::size_t { size / 2U }, + data + size, + 8U + ); + + if(a_local < b_local) + { + std::swap(a_local, b_local); + std::swap(a_boost, b_boost); + } + + if(b_local != 0U) + { + local_uint_type result_local { a_local / b_local }; + boost_uint_type result_boost { a_boost / b_boost }; + + std::vector result_data_local(max_size, UINT8_C(0)); + std::vector result_data_boost(result_data_local.size(), UINT8_C(0)); + + export_bits(result_local, result_data_local.data(), 8U); + export_bits(result_boost, result_data_boost.data(), 8U); + + // Verify that both uintwide_t as well as boost obtain the same result. + const bool result_div_is_ok = + std::equal + ( + result_data_local.cbegin(), + result_data_local.cend(), + result_data_boost.cbegin(), + result_data_boost.cend() + ); + + result_is_ok = (result_div_is_ok && result_is_ok); + } + } + + // Assert the correct result. + assert(result_is_ok); + + return result_is_ok; +} + +// The fuzzing entry point. +extern "C" +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + const bool result_one_div_is_ok { fuzzing::eval_div(data, size) }; + + return (result_one_div_is_ok ? 0 : -1); +} diff --git a/test/fuzzing/test_fuzzing_mul.cpp b/test/fuzzing/test_fuzzing_mul.cpp new file mode 100644 index 0000000..eb0b6fc --- /dev/null +++ b/test/fuzzing/test_fuzzing_mul.cpp @@ -0,0 +1,127 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer +// clang++ -g -O2 -fsanitize=fuzzer,address,undefined -I. -I/mnt/c/boost/boost_1_85_0 test/fuzzing/test_fuzzing_mul.cpp -o test_fuzzing_mul +// ./test_fuzzing_mul -max_total_time=180 + +#include + +#include + +#include +#include +#include +#include +#include + +namespace fuzzing +{ + using boost_uint_backend_type = + boost::multiprecision::cpp_int_backend(UINT32_C(256)), + static_cast(UINT32_C(256)), + boost::multiprecision::unsigned_magnitude>; + + using boost_uint_type = boost::multiprecision::number; + + using local_uint_type = ::math::wide_integer::uint256_t; + + auto eval_mul(const std::uint8_t* data, std::size_t size) -> bool; +} + +auto fuzzing::eval_mul(const std::uint8_t* data, std::size_t size) -> bool +{ + const std::size_t + max_size + { + static_cast + ( + std::numeric_limits::digits / 8 + ) + }; + + bool result_is_ok { true }; + + if((size > std::size_t { UINT8_C(1) }) && (size <= std::size_t { max_size * 2U })) + { + local_uint_type a_local { }; + local_uint_type b_local { }; + + boost_uint_type a_boost { }; + boost_uint_type b_boost { }; + + // Import data into their respective uintwide_t a and b values. + import_bits + ( + a_local, + data, + data + std::size_t { size / 2U }, + 8U + ); + + import_bits + ( + b_local, + data + std::size_t { size / 2U }, + data + size, + 8U + ); + + // Import data into their respective boost-based a and b values. + import_bits + ( + a_boost, + data, + data + std::size_t { size / 2U }, + 8U + ); + + import_bits + ( + b_boost, + data + std::size_t { size / 2U }, + data + size, + 8U + ); + + local_uint_type result_local { a_local * b_local }; + boost_uint_type result_boost { a_boost * b_boost }; + + std::vector result_data_local(max_size, UINT8_C(0)); + std::vector result_data_boost(result_data_local.size(), UINT8_C(0)); + + export_bits(result_local, result_data_local.data(), 8U); + export_bits(result_boost, result_data_boost.data(), 8U); + + // Verify that both uintwide_t as well as boost obtain the same result. + const bool result_mul_is_ok = + std::equal + ( + result_data_local.cbegin(), + result_data_local.cend(), + result_data_boost.cbegin(), + result_data_boost.cend() + ); + + result_is_ok = (result_mul_is_ok && result_is_ok); + } + + // Assert the correct result. + assert(result_is_ok); + + return result_is_ok; +} + +// The fuzzing entry point. +extern "C" +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + const bool result_one_mul_is_ok { fuzzing::eval_mul(data, size) }; + + return (result_one_mul_is_ok ? 0 : -1); +} diff --git a/test/fuzzing/test_fuzzing_sub.cpp b/test/fuzzing/test_fuzzing_sub.cpp new file mode 100644 index 0000000..d57574d --- /dev/null +++ b/test/fuzzing/test_fuzzing_sub.cpp @@ -0,0 +1,127 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer +// clang++ -g -O2 -fsanitize=fuzzer,address,undefined -I. -I/mnt/c/boost/boost_1_85_0 test/fuzzing/test_fuzzing_sub.cpp -o test_fuzzing_sub +// ./test_fuzzing_sub -max_total_time=180 + +#include + +#include + +#include +#include +#include +#include +#include + +namespace fuzzing +{ + using boost_uint_backend_type = + boost::multiprecision::cpp_int_backend(UINT32_C(256)), + static_cast(UINT32_C(256)), + boost::multiprecision::unsigned_magnitude>; + + using boost_uint_type = boost::multiprecision::number; + + using local_uint_type = ::math::wide_integer::uint256_t; + + auto eval_sub(const std::uint8_t* data, std::size_t size) -> bool; +} + +auto fuzzing::eval_sub(const std::uint8_t* data, std::size_t size) -> bool +{ + const std::size_t + max_size + { + static_cast + ( + std::numeric_limits::digits / 8 + ) + }; + + bool result_is_ok { true }; + + if((size > std::size_t { UINT8_C(1) }) && (size <= std::size_t { max_size * 2U })) + { + local_uint_type a_local { }; + local_uint_type b_local { }; + + boost_uint_type a_boost { }; + boost_uint_type b_boost { }; + + // Import data into their respective uintwide_t a and b values. + import_bits + ( + a_local, + data, + data + std::size_t { size / 2U }, + 8U + ); + + import_bits + ( + b_local, + data + std::size_t { size / 2U }, + data + size, + 8U + ); + + // Import data into their respective boost-based a and b values. + import_bits + ( + a_boost, + data, + data + std::size_t { size / 2U }, + 8U + ); + + import_bits + ( + b_boost, + data + std::size_t { size / 2U }, + data + size, + 8U + ); + + local_uint_type result_local { a_local - b_local }; + boost_uint_type result_boost { a_boost - b_boost }; + + std::vector result_data_local(max_size, UINT8_C(0)); + std::vector result_data_boost(result_data_local.size(), UINT8_C(0)); + + export_bits(result_local, result_data_local.data(), 8U); + export_bits(result_boost, result_data_boost.data(), 8U); + + // Verify that both uintwide_t as well as boost obtain the same result. + const bool result_sub_is_ok = + std::equal + ( + result_data_local.cbegin(), + result_data_local.cend(), + result_data_boost.cbegin(), + result_data_boost.cend() + ); + + result_is_ok = (result_sub_is_ok && result_is_ok); + } + + // Assert the correct result. + assert(result_is_ok); + + return result_is_ok; +} + +// The fuzzing entry point. +extern "C" +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + const bool result_one_sub_is_ok { fuzzing::eval_sub(data, size) }; + + return (result_one_sub_is_ok ? 0 : -1); +} diff --git a/test/test.cpp b/test/test.cpp index 8a1044d..5873b7c 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -6,7 +6,7 @@ /////////////////////////////////////////////////////////////////// // On Windows subsystem for LINUX -// cd /mnt/c/Users/User/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer +// cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // When using local Boost-develop branch, use specific include paths. // -I/mnt/c/boost/modular_boost/boost/libs/config/include -I/mnt/c/boost/modular_boost/boost/libs/multiprecision/include @@ -23,7 +23,7 @@ // make prepare -f make_gcov_01_generic.gmk MY_ALL_COV=0 MY_BOOST_ROOT=/mnt/c/boost/boost_1_85_0 MY_CC=g++ // make gcov -f make_gcov_01_generic.gmk --jobs=8 MY_ALL_COV=0 MY_BOOST_ROOT=/mnt/c/boost/boost_1_85_0 MY_CC=g++ -// cd /mnt/c/Users/User/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer +// cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // PATH=/home/chris/coverity/cov-analysis-linux64-2023.6.2/bin:$PATH // cov-build --dir cov-int g++ -finline-functions -march=native -mtune=native -O3 -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -std=c++14 -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -DWIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL -I. -I/mnt/c/boost/boost_1_85_0 -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp examples/example000a_builtin_convert.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe // tar caf wide-integer.bz2 cov-int diff --git a/wide_integer_vs2022.vcxproj b/wide_integer_vs2022.vcxproj index 9d2d373..834f3e1 100644 --- a/wide_integer_vs2022.vcxproj +++ b/wide_integer_vs2022.vcxproj @@ -232,6 +232,30 @@ true + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + @@ -262,6 +286,7 @@ + diff --git a/wide_integer_vs2022.vcxproj.filters b/wide_integer_vs2022.vcxproj.filters index 730f0ec..5955d64 100644 --- a/wide_integer_vs2022.vcxproj.filters +++ b/wide_integer_vs2022.vcxproj.filters @@ -68,6 +68,9 @@ {d0da75c7-dd48-4e37-b1ee-283464e3ce9d} + + {597ab5f0-b045-443a-8da2-1b929052b42f} + @@ -222,6 +225,18 @@ Source Files\examples + + Source Files\test\fuzzing + + + Source Files\test\fuzzing + + + Source Files\test\fuzzing + + + Source Files\test\fuzzing + @@ -266,6 +281,9 @@ .github\workflows + + .github\workflows +