diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec268c4..09c5754 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,3 +23,13 @@ jobs: - run: export CC="clang-10" && export CXX="clang++-10" && ./configure && make check - run: sudo make install - run: export CC="clang-10" && export CXX="clang++-10" && make distcheck && make distclean + + build-Linux-cmake: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v2 + - run: sudo apt-get install -y cmake || exit 1 + - run: cmake -B build -S . -DENABLE_TESTS:BOOL=TRUE + - run: cmake --build build + - run: ctest --test-dir build || exit 1 + - run: cmake --install build --prefix install-dir diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3056add --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,97 @@ +cmake_minimum_required(VERSION 3.15) +project(bc-ur + VERSION 0.3.0 + DESCRIPTION "UR reference library in C++" + LANGUAGES C CXX +) + +option(ENABLE_TESTS "Build bc-ur tests" FALSE) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) + +add_library(bc-ur) + +set(public_headers + src/bc-ur.hpp + src/bytewords.hpp + src/cbor-lite.hpp + src/fountain-decoder.hpp + src/fountain-encoder.hpp + src/fountain-utils.hpp + src/random-sampler.hpp + src/ur.hpp + src/ur-decoder.hpp + src/ur-encoder.hpp + src/utils.hpp + src/xoshiro256.hpp +) +set(sources + src/bytewords.cpp + src/crc32.c + src/crc32.h + src/fountain-decoder.cpp + src/fountain-encoder.cpp + src/fountain-utils.cpp + src/Makefile.in + src/memzero.c + src/memzero.h + src/random-sampler.cpp + src/sha2.c + src/sha2.h + src/ur.cpp + src/ur-decoder.cpp + src/ur-encoder.cpp + src/utils.cpp + src/xoshiro256.cpp +) + +target_sources(bc-ur PRIVATE ${public_headers} ${sources}) +target_include_directories(bc-ur + PUBLIC + "$" + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/src" +) +set_target_properties(bc-ur PROPERTIES + PUBLIC_HEADER "${public_headers}" + VERSION ${PROJECT_VERSION} +) + +if(ENABLE_TESTS) + enable_testing() + add_executable(bc-ur-test test/test.cpp test/test-utils.cpp) + target_include_directories(bc-ur-test PRIVATE test) + target_link_libraries(bc-ur-test bc-ur) + add_test(bc-ur-test ./bc-ur-test) +endif() + +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) +configure_package_config_file(cmake/bc-ur-config.cmake.in bc-ur-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/bc-ur +) +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/bc-ur-config-version.cmake + COMPATIBILITY SameMajorVersion +) +install(TARGETS bc-ur + EXPORT "bc-ur-export" + ARCHIVE + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/bc-ur +) +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/bc-ur-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/bc-ur-config-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/bc-ur +) +install(EXPORT "bc-ur-export" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/bc-ur + NAMESPACE ${PROJECT_NAME}:: + FILE bc-ur-targets.cmake +) + diff --git a/cmake/bc-ur-config.cmake.in b/cmake/bc-ur-config.cmake.in new file mode 100644 index 0000000..eab0b07 --- /dev/null +++ b/cmake/bc-ur-config.cmake.in @@ -0,0 +1,6 @@ +@PACKAGE_INIT@ + +set_and_check(BC-UR_LIB_DIR "@PACKAGE_LIB_INSTALL_DIR@") +include("${BCUR_LIB_DIR}/cmake/bc-urTargets.cmake") +set(bc-ur_COMPONENT_FOUND TRUE) +check_required_components(bc-ur) diff --git a/src/bytewords.cpp b/src/bytewords.cpp index 34e9d4e..365065f 100644 --- a/src/bytewords.cpp +++ b/src/bytewords.cpp @@ -21,13 +21,13 @@ uint8_t decode_word(const string& word, size_t word_len) { throw runtime_error("Invalid Bytewords."); } - static int16_t* array = NULL; + static int16_t* array = nullptr; const size_t dim = 26; // Since the first and last letters of each Byteword are unique, // we can use them as indexes into a two-dimensional lookup table. // This table is generated lazily. - if(array == NULL) { + if(array == nullptr) { const size_t array_len = dim * dim; array = (int16_t*)malloc(array_len * sizeof(int16_t)); for(size_t i = 0; i < array_len; i++) { @@ -69,21 +69,21 @@ uint8_t decode_word(const string& word, size_t word_len) { return value; } -static const string get_word(uint8_t index) { - auto p = &bytewords[index * 4]; - return string(p, p + 4); +static string get_word(uint8_t index) { + const auto *p = &bytewords[index * 4]; + return {p, p + 4}; } -static const string get_minimal_word(uint8_t index) { +static string get_minimal_word(uint8_t index) { string word; word.reserve(2); - auto p = &bytewords[index * 4]; + const auto *p = &bytewords[index * 4]; word.push_back(*p); word.push_back(*(p + 3)); return word; } -static const string encode(const ByteVector& buf, const string& separator) { +static string encode(const ByteVector& buf, const string& separator) { auto len = buf.size(); StringVector words; words.reserve(len); @@ -94,19 +94,19 @@ static const string encode(const ByteVector& buf, const string& separator) { return join(words, separator); } -static const ByteVector add_crc(const ByteVector& buf) { +static ByteVector add_crc(const ByteVector& buf) { auto crc_buf = crc32_bytes(buf); auto result = buf; append(result, crc_buf); return result; } -static const string encode_with_separator(const ByteVector& buf, const string& separator) { +static string encode_with_separator(const ByteVector& buf, const string& separator) { auto crc_buf = add_crc(buf); return encode(crc_buf, separator); } -static const string encode_minimal(const ByteVector& buf) { +static string encode_minimal(const ByteVector& buf) { string result; auto crc_buf = add_crc(buf); auto len = crc_buf.size(); @@ -117,7 +117,7 @@ static const string encode_minimal(const ByteVector& buf) { return result; } -static const ByteVector _decode(const string& s, char separator, size_t word_len) { +static ByteVector _decode(const string& s, char separator, size_t word_len) { StringVector words; if(word_len == 4) { words = split(s, separator); @@ -148,9 +148,8 @@ string Bytewords::encode(style style, const ByteVector& bytes) { return encode_with_separator(bytes, "-"); case minimal: return encode_minimal(bytes); - default: - assert(false); } + assert(false); } ByteVector Bytewords::decode(style style, const string& string) { @@ -161,9 +160,8 @@ ByteVector Bytewords::decode(style style, const string& string) { return _decode(string, '-', 4); case minimal: return _decode(string, 0, 2); - default: - assert(false); } + assert(false); } } diff --git a/src/fountain-encoder.cpp b/src/fountain-encoder.cpp index f7f6cf9..5f08bf1 100644 --- a/src/fountain-encoder.cpp +++ b/src/fountain-encoder.cpp @@ -6,7 +6,7 @@ // #include "fountain-encoder.hpp" -#include +#include #include #include #include diff --git a/src/ur-decoder.hpp b/src/ur-decoder.hpp index 132fa77..3b7f418 100644 --- a/src/ur-decoder.hpp +++ b/src/ur-decoder.hpp @@ -18,7 +18,7 @@ namespace ur { -class URDecoder final { +class URDecoder { public: typedef std::optional > Result; diff --git a/src/ur-encoder.hpp b/src/ur-encoder.hpp index 5b2dec4..db1291c 100644 --- a/src/ur-encoder.hpp +++ b/src/ur-encoder.hpp @@ -15,7 +15,7 @@ namespace ur { -class UREncoder final { +class UREncoder { public: // Encode a single-part UR. static std::string encode(const UR& ur); diff --git a/src/ur.cpp b/src/ur.cpp index 2227340..230d123 100644 --- a/src/ur.cpp +++ b/src/ur.cpp @@ -13,8 +13,8 @@ using namespace std; namespace ur { -UR::UR(const std::string &type, const ByteVector &cbor) - : type_(type), cbor_(cbor) +UR::UR(std::string type, ByteVector cbor) + : type_(std::move(type)), cbor_(std::move(cbor)) { if (!is_ur_type(type)) { throw invalid_type(); diff --git a/src/ur.hpp b/src/ur.hpp index c26943c..6a40f40 100644 --- a/src/ur.hpp +++ b/src/ur.hpp @@ -14,7 +14,7 @@ namespace ur { -class UR final { +class UR { private: std::string type_; ByteVector cbor_; @@ -24,7 +24,7 @@ class UR final { const std::string& type() const { return type_; } const ByteVector& cbor() const { return cbor_; } - UR(const std::string& type, const ByteVector& cbor); + UR(std::string type, ByteVector cbor); }; bool operator==(const UR& lhs, const UR& rhs); diff --git a/src/utils.cpp b/src/utils.cpp index 1f1c0e3..a10108c 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -14,6 +14,7 @@ extern "C" { } +#include #include #include #include @@ -24,28 +25,28 @@ using namespace std; namespace ur { ByteVector sha256(const ByteVector &buf) { - uint8_t digest[SHA256_DIGEST_LENGTH]; - sha256_Raw(&buf[0], buf.size(), digest); - return ByteVector(digest, digest + SHA256_DIGEST_LENGTH); + array digest; + sha256_Raw(buf.data(), buf.size(), digest.data()); + return {digest.begin(), digest.end()}; } ByteVector crc32_bytes(const ByteVector &buf) { - uint32_t checksum = ur_crc32n(&buf[0], buf.size()); - auto cbegin = (uint8_t*)&checksum; - auto cend = cbegin + sizeof(uint32_t); - return ByteVector(cbegin, cend); + uint32_t checksum = ur_crc32n(buf.data(), buf.size()); + auto *cbegin = (uint8_t*)&checksum; + auto *cend = cbegin + sizeof(uint32_t); + return {cbegin, cend}; } uint32_t crc32_int(const ByteVector &buf) { - return ur_crc32(&buf[0], buf.size()); + return ur_crc32(buf.data(), buf.size()); } ByteVector string_to_bytes(const string& s) { - return ByteVector(s.begin(), s.end()); + return {s.begin(), s.end()}; } string data_to_hex(const ByteVector& in) { - auto hex = "0123456789abcdef"; + const string hex = "0123456789abcdef"; string result; for(auto c: in) { result.append(1, hex[(c >> 4) & 0xF]); @@ -81,7 +82,7 @@ uint32_t bytes_to_int(const ByteVector& in) { string join(const StringVector &strings, const string &separator) { ostringstream result; bool first = true; - for(auto s: strings) { + for(const auto& s: strings) { if(!first) { result << separator; } @@ -104,7 +105,7 @@ StringVector split(const string& s, char separator) { } } - if(buf != "") { + if(!buf.empty()) { result.push_back(buf); } @@ -125,12 +126,12 @@ string take_first(const string &s, size_t count) { auto first = s.begin(); auto c = min(s.size(), count); auto last = first + c; - return string(first, last); + return {first, last}; } string drop_first(const string& s, size_t count) { if(count >= s.length()) { return ""; } - return string(s.begin() + count, s.end()); + return {s.begin() + count, s.end()}; } void xor_into(ByteVector& target, const ByteVector& source) { diff --git a/src/utils.hpp b/src/utils.hpp index 2e45e5c..fdf859d 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -17,8 +17,8 @@ namespace ur { -typedef std::vector ByteVector; -typedef std::vector StringVector; +using ByteVector = std::vector; +using StringVector = std::vector; ByteVector sha256(const ByteVector &buf); ByteVector crc32_bytes(const ByteVector &buf); diff --git a/src/xoshiro256.cpp b/src/xoshiro256.cpp index 7e87833..8fc471c 100644 --- a/src/xoshiro256.cpp +++ b/src/xoshiro256.cpp @@ -7,6 +7,7 @@ #include "xoshiro256.hpp" #include +#include /* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) @@ -129,7 +130,7 @@ void Xoshiro256::jump() { uint64_t s3 = 0; for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) for(int b = 0; b < 64; b++) { - if (JUMP[i] & UINT64_C(1) << b) { + if ((JUMP[i] & UINT64_C(1) << b) != 0u) { s0 ^= s[0]; s1 ^= s[1]; s2 ^= s[2]; @@ -150,13 +151,13 @@ void Xoshiro256::jump() { subsequences for parallel distributed computations. */ void Xoshiro256::long_jump() { - static const uint64_t LONG_JUMP[] = { 0x76e15d3efefdcbbf, 0xc5004e441c522fb3, 0x77710069854ee241, 0x39109bb02acbe635 }; + static const std::array LONG_JUMP = { 0x76e15d3efefdcbbf, 0xc5004e441c522fb3, 0x77710069854ee241, 0x39109bb02acbe635 }; uint64_t s0 = 0; uint64_t s1 = 0; uint64_t s2 = 0; uint64_t s3 = 0; - for(int i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++) + for(int i = 0; i < LONG_JUMP.size(); i++) for(int b = 0; b < 64; b++) { if (LONG_JUMP[i] & UINT64_C(1) << b) { s0 ^= s[0]; diff --git a/src/xoshiro256.hpp b/src/xoshiro256.hpp index 2654cbc..573a4c8 100644 --- a/src/xoshiro256.hpp +++ b/src/xoshiro256.hpp @@ -8,7 +8,7 @@ #ifndef XOSHIRO256_HPP #define XOSHIRO256_HPP -#include +#include #include #include #include "utils.hpp" @@ -34,7 +34,7 @@ class Xoshiro256 { void long_jump(); private: - uint64_t s[4]; + std::array s; void set_s(const std::array& a); void hash_then_set_s(const ByteVector& bytes);