├── .clang-format ├── .gitignore ├── .gitmodules ├── .tm_properties ├── CMakeLists.txt ├── LICENSE ├── README.md ├── checksum.cpp ├── cmake ├── colors.cmake ├── coverage.cmake └── pedantic.cmake ├── default.profraw ├── example.cpp ├── examples ├── CMakeLists.txt ├── playground.cpp ├── sha256.cpp ├── sha3.cpp ├── shake128.cpp └── xxhash.cpp ├── include ├── CMakeLists.txt ├── cthash-single-header.hpp └── cthash │ ├── cthash.hpp │ ├── encoding │ ├── base.hpp │ ├── bit-buffer.hpp │ ├── chunk-of-bits.hpp │ ├── concepts.hpp │ └── encodings.hpp │ ├── fixed-string.hpp │ ├── hasher.hpp │ ├── internal │ ├── algorithm.hpp │ ├── assert.hpp │ ├── bit.hpp │ ├── concepts.hpp │ ├── convert.hpp │ ├── deduce.hpp │ └── hexdec.hpp │ ├── sha2 │ ├── common.hpp │ ├── sha224.hpp │ ├── sha256.hpp │ ├── sha384.hpp │ ├── sha512.hpp │ └── sha512 │ │ └── t.hpp │ ├── sha3 │ ├── common.hpp │ ├── keccak.hpp │ ├── sha3-224.hpp │ ├── sha3-256.hpp │ ├── sha3-384.hpp │ ├── sha3-512.hpp │ ├── shake128.hpp │ └── shake256.hpp │ ├── simple.hpp │ ├── value.hpp │ └── xxhash.hpp └── tests ├── CMakeLists.txt ├── benchmark ├── sha256.cpp ├── sha3-256.cpp └── sha512.cpp ├── encoding ├── base.cpp ├── bit-buffer.cpp ├── chunk-of-bits.cpp └── selection.cpp ├── hexdec.cpp ├── internal └── support.hpp ├── keccak.cpp ├── sha2 ├── sha224.cpp ├── sha256.cpp ├── sha384.cpp ├── sha512.cpp └── sha512t.cpp ├── sha3 ├── sha3-224.cpp ├── sha3-256.cpp ├── sha3-384.cpp ├── sha3-512.cpp ├── shake128.cpp ├── shake256.cpp └── xor-overwrite.cpp ├── value.cpp └── xxhash └── basics.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: WebKit 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: DontAlign 6 | AlignConsecutiveMacros: None 7 | AlignConsecutiveAssignments: None 8 | AlignConsecutiveBitFields: None 9 | AlignConsecutiveDeclarations: None 10 | AlignEscapedNewlines: Right 11 | AlignOperands: DontAlign 12 | AlignTrailingComments: true 13 | AllowAllArgumentsOnNextLine: true 14 | AllowAllConstructorInitializersOnNextLine: true 15 | AllowAllParametersOfDeclarationOnNextLine: true 16 | AllowShortEnumsOnASingleLine: true 17 | AllowShortBlocksOnASingleLine: Always 18 | AllowShortCaseLabelsOnASingleLine: false 19 | AllowShortFunctionsOnASingleLine: All 20 | AllowShortLambdasOnASingleLine: All 21 | AllowShortIfStatementsOnASingleLine: Always 22 | AllowShortLoopsOnASingleLine: true 23 | AlwaysBreakAfterDefinitionReturnType: None 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakBeforeMultilineStrings: true 26 | AlwaysBreakTemplateDeclarations: No 27 | AttributeMacros: 28 | - __capability 29 | BinPackArguments: true 30 | BinPackParameters: true 31 | BraceWrapping: 32 | AfterCaseLabel: false 33 | AfterClass: false 34 | AfterControlStatement: Never 35 | AfterEnum: false 36 | AfterFunction: false 37 | AfterNamespace: false 38 | AfterObjCDeclaration: false 39 | AfterStruct: false 40 | AfterUnion: false 41 | AfterExternBlock: false 42 | BeforeCatch: false 43 | BeforeElse: false 44 | BeforeLambdaBody: false 45 | BeforeWhile: false 46 | IndentBraces: false 47 | SplitEmptyFunction: false 48 | SplitEmptyRecord: false 49 | SplitEmptyNamespace: false 50 | BreakBeforeBinaryOperators: All 51 | BreakBeforeConceptDeclarations: false 52 | BreakBeforeBraces: Attach 53 | BreakBeforeInheritanceComma: false 54 | BreakInheritanceList: BeforeColon 55 | BreakBeforeTernaryOperators: true 56 | BreakConstructorInitializersBeforeComma: false 57 | BreakAfterJavaFieldAnnotations: false 58 | BreakStringLiterals: true 59 | ColumnLimit: 0 60 | CommentPragmas: '^ IWYU pragma:' 61 | CompactNamespaces: false 62 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 63 | ConstructorInitializerIndentWidth: 4 64 | ContinuationIndentWidth: 4 65 | Cpp11BracedListStyle: true 66 | DeriveLineEnding: true 67 | DerivePointerAlignment: false 68 | DisableFormat: false 69 | EmptyLineBeforeAccessModifier: LogicalBlock 70 | ExperimentalAutoDetectBinPacking: false 71 | FixNamespaceComments: true 72 | ForEachMacros: 73 | - foreach 74 | - Q_FOREACH 75 | - BOOST_FOREACH 76 | StatementAttributeLikeMacros: 77 | - Q_EMIT 78 | IncludeBlocks: Merge 79 | IncludeCategories: 80 | - Regex: '^$' 81 | Priority: 3 82 | SortPriority: 0 83 | CaseSensitive: false 84 | - Regex: '^$' 85 | Priority: 0 86 | SortPriority: 0 87 | CaseSensitive: false 88 | - Regex: '^".+/.+"$' 89 | Priority: 2 90 | SortPriority: 0 91 | CaseSensitive: false 92 | - Regex: '^".+"$' 93 | Priority: 1 94 | SortPriority: 0 95 | CaseSensitive: false 96 | - Regex: '^$' 97 | Priority: 4 98 | SortPriority: 0 99 | CaseSensitive: false 100 | - Regex: '^$' 101 | Priority: 6 102 | SortPriority: 0 103 | CaseSensitive: false 104 | - Regex: '^$' 105 | Priority: 5 106 | SortPriority: 0 107 | CaseSensitive: false 108 | - Regex: '^<(c[^.]+|.+\.h)>$' 109 | Priority: 8 110 | SortPriority: 0 111 | CaseSensitive: false 112 | - Regex: '^<.+>$' 113 | Priority: 7 114 | SortPriority: 0 115 | CaseSensitive: false 116 | IncludeIsMainRegex: '(Test)?$' 117 | IncludeIsMainSourceRegex: '' 118 | IndentCaseLabels: false 119 | IndentCaseBlocks: false 120 | IndentGotoLabels: true 121 | IndentPPDirectives: None 122 | IndentExternBlock: AfterExternBlock 123 | IndentRequires: false 124 | IndentWidth: 4 125 | IndentWrappedFunctionNames: false 126 | InsertTrailingCommas: None 127 | JavaScriptQuotes: Leave 128 | JavaScriptWrapImports: true 129 | KeepEmptyLinesAtTheStartOfBlocks: false 130 | LambdaBodyIndentation: OuterScope 131 | MacroBlockBegin: '' 132 | MacroBlockEnd: '' 133 | MaxEmptyLinesToKeep: 1 134 | NamespaceIndentation: Inner 135 | PenaltyBreakAssignment: 2 136 | PenaltyBreakBeforeFirstCallParameter: 19 137 | PenaltyBreakComment: 300 138 | PenaltyBreakFirstLessLess: 120 139 | PenaltyBreakString: 1000 140 | PenaltyBreakTemplateDeclaration: 10 141 | PenaltyExcessCharacter: 1000000 142 | PenaltyReturnTypeOnItsOwnLine: 60 143 | PenaltyIndentedWhitespace: 0 144 | PointerAlignment: Middle 145 | ReflowComments: true 146 | RequiresClausePosition: SingleLine 147 | SortIncludes: true 148 | SortJavaStaticImport: Before 149 | SortUsingDeclarations: true 150 | SpaceAfterCStyleCast: false 151 | SpaceAfterLogicalNot: false 152 | SpaceAfterTemplateKeyword: true 153 | SpaceBeforeAssignmentOperators: true 154 | SpaceBeforeCaseColon: false 155 | SpaceBeforeCpp11BracedList: false 156 | SpaceBeforeCtorInitializerColon: false 157 | SpaceBeforeInheritanceColon: false 158 | SpaceBeforeParens: ControlStatements 159 | SpaceAroundPointerQualifiers: Both 160 | SpaceBeforeRangeBasedForLoopColon: false 161 | SpaceInEmptyBlock: true 162 | SpaceInEmptyParentheses: false 163 | SpacesBeforeTrailingComments: 1 164 | SpacesInAngles: false 165 | SpacesInConditionalStatement: false 166 | SpacesInContainerLiterals: false 167 | SpacesInCStyleCastParentheses: false 168 | SpacesInParentheses: false 169 | SpacesInSquareBrackets: false 170 | SpaceBeforeSquareBrackets: false 171 | BitFieldColonSpacing: After 172 | Standard: c++20 173 | TabWidth: 4 174 | UseCRLF: false 175 | UseTab: Always 176 | WhitespaceSensitiveMacros: [] 177 | 178 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/catch2"] 2 | path = external/catch2 3 | url = https://github.com/catchorg/Catch2.git 4 | branch = devel 5 | -------------------------------------------------------------------------------- /.tm_properties: -------------------------------------------------------------------------------- 1 | CLANG_FORMAT_ON_SAVE = true 2 | 3 | excludeDirectories = "{$excludeDirectories,build}" 4 | includeDirectories = "{$includeDirectories}" 5 | include = "{$include,.gitignore,.gitattributes,.clang-format,.github}" 6 | excludeInFolderSearch = "{$excludeInFolderSearch,build,external,*-single-header.hpp}" 7 | includeInFolderSearch = "{$includeInFolderSearch}" 8 | excludeInFileChooser = "{$excludeInFileChooser}" 9 | softTabs = false 10 | tabSize = 4 11 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.21) 2 | 3 | project(cthash VERSION 1.0 LANGUAGES CXX) 4 | 5 | if (PROJECT_IS_TOP_LEVEL) 6 | list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 7 | 8 | include(colors) 9 | 10 | option(CTHASH_TESTS "Enable CTHASH testing" OFF) 11 | 12 | if (CTHASH_TESTS) 13 | if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/external/catch2/CMakeLists.txt) 14 | message(STATUS "Using local copy of catch2") 15 | #set(CATCH_CONFIG_FAST_COMPILE ON) 16 | add_subdirectory(external/catch2 EXCLUDE_FROM_ALL SYSTEM) 17 | endif() 18 | 19 | option(CTHASH_COVERAGE "Enable CTHASH test-coverage" ON) 20 | 21 | if (CTHASH_COVERAGE) 22 | include(coverage) 23 | enable_coverage() 24 | else() 25 | message(STATUS "Test coverage measurement is OFF") 26 | endif() 27 | 28 | add_subdirectory(tests) 29 | else() 30 | message(STATUS "Tests are disabled") 31 | endif() 32 | 33 | include(pedantic) 34 | 35 | option(CTHASH_EXAMPLES "Build CTHASH examples" ON) 36 | 37 | if (CTHASH_EXAMPLES) 38 | add_subdirectory(examples) 39 | 40 | add_executable(example example.cpp) 41 | target_link_libraries(example cthash) 42 | 43 | add_executable(checksum checksum.cpp) 44 | target_link_libraries(checksum cthash) 45 | endif() 46 | 47 | endif() 48 | 49 | add_subdirectory(include) 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CTHASH (Compile Time Hash) 2 | 3 | This library is constexpr implementation of SHA-2, SHA-3, and xxhash family of hashes. 4 | 5 | ## Supported hash function 6 | 7 | The library also implements hash_value literals in namespace `cthash::literals` (suffixes in parenthesis for each hash function type). This literal types doesn't compute hash value of its content, but are merely strong typed value from specified hash algorithm (eg. so you won't mix up SHA-256 and SHA3-256 results). 8 | 9 | * SHA-224 (`_sha224`) 10 | * SHA-256 (`_sha256`) 11 | * SHA-384 (`_sha384`) 12 | * SHA-512 (`_sha512`) 13 | * SHA-512/t (only for T dividable by 8) (`_sha512_224`, `_sha512_256`) 14 | 15 | * SHA3-224 (`_sha3_224`) 16 | * SHA3-256 (`_sha3_256`) 17 | * SHA3-384 (`_sha3_384`) 18 | * SHA3-512 (`_sha3_512`) 19 | 20 | * SHAKE-128 (`_shake128`) 21 | * SHAKE-256 (`_shake256`) 22 | 23 | * XXHASH-32 (`_xxh32`) 24 | * XXHASH-64 (`_xxh64`) 25 | 26 | ## Example 27 | 28 | SHA256: 29 | ```c++ 30 | using namespace cthash::literals; 31 | 32 | constexpr auto my_hash = cthash::sha256{}.update("hello there!").final(); 33 | // or 34 | constexpr auto my_hash = cthash::simple("hello there!"); 35 | 36 | static_assert(my_hash == "c69509590d81db2f37f9d75480c8efedf79a77933db5a8319e52e13bfd9874a3"_sha256); 37 | ``` 38 | 39 | SHA-3: 40 | ```c++ 41 | using namespace cthash::literals; 42 | 43 | constexpr auto my_hash = cthash::sha3_256{}.update("hello there!").final(); 44 | // or 45 | constexpr auto my_hash = cthash::simple("hello there!"); 46 | 47 | static_assert(my_hash == "c7fd85f649fba4bd6fb605038ae8530cf2239152bbbcb9d91d260cc2a90a9fea"_sha3_256); 48 | ``` 49 | 50 | SHAKE128 (d=1024) (with compile time set `d` bits): 51 | ```c++ 52 | using namespace cthash::literals; 53 | 54 | constexpr auto my_hash = cthash::shake128{}.update("hello there!").final<1024>(); 55 | 56 | static_assert(my_hash == "86089a77e15628597e45caf70c8ef271def6775c54d42d61fb45b9cd6d3b288e5fbd0042241a4aa9180c1bfe94542e16765b3a48d549771202e50aebf8d4f51bd00be2a427f81b7b58aaebc97f89559bca1ea21fec5047de70d075e14e5a3c95c002fd9f81925672d408d4b60c0105e5858df25b64af9b20cec973d66616da81"_shake128); 57 | ``` 58 | 59 | Also look at [runtime example](example.cpp). 60 | 61 | ### Including library 62 | 63 | You can include specific hash function only by `#include ` or you can include whole library by `#include ` 64 | 65 | #### Specific include for SHA-512/t 66 | 67 | Just include `#include `. 68 | 69 | ## Implementation note 70 | 71 | There is no allocation at all, everything is done as a value type from user's perspective. No explicit optimizations were done (for now). 72 | 73 | ## Compiler support 74 | 75 | You need a C++20 compiler. 76 | 77 | * Clang 15.0.7+ 78 | * GCC 12.2+ 79 | -------------------------------------------------------------------------------- /checksum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct mapped_file { 9 | static constexpr int invalid = -1; 10 | 11 | int fd{invalid}; 12 | size_t sz{0}; 13 | void * ptr{nullptr}; 14 | 15 | static size_t get_size(int fd) { 16 | if (fd == invalid) { 17 | return 0; 18 | } 19 | 20 | return (size_t)lseek(fd, 0, SEEK_END); 21 | } 22 | 23 | mapped_file(const char * path): fd{open(path, O_RDONLY)}, sz{get_size(fd)}, ptr{mmap(nullptr, sz, PROT_READ, MAP_PRIVATE, fd, 0)} { } 24 | 25 | mapped_file(const mapped_file &) = delete; 26 | mapped_file(mapped_file &&) = delete; 27 | 28 | ~mapped_file() { 29 | if (ptr && fd != invalid) { 30 | munmap(ptr, sz); 31 | close(fd); 32 | } 33 | } 34 | 35 | auto get_span() const noexcept { 36 | return std::span(reinterpret_cast(ptr), sz); 37 | } 38 | }; 39 | 40 | int main(int argc, char ** argv) { 41 | if (argc < 3) { 42 | std::cerr << argv[0] << " hash file\n"; 43 | std::cerr << "hash is one of: sha-224, sha-256, sha-384, sha-512, sha-512/223, sha-512/256, sha3-224, sha3-256, sha3-384, sha3-512, \n"; 44 | std::cerr << " shake-128/n, shake-256/n (where n is 32/64/128/256/512/1024/2048),\n"; 45 | std::cerr << " xxhash32, xxhash64\n"; 46 | return 1; 47 | } 48 | 49 | const auto h = std::string_view(argv[1]); 50 | const auto f = mapped_file(argv[2]); 51 | 52 | if (f.fd == mapped_file::invalid) { 53 | std::cerr << "can't open file!\n"; 54 | return 1; 55 | } 56 | 57 | const auto start = std::chrono::high_resolution_clock::now(); 58 | 59 | if (h == "sha-224") { 60 | std::cout << cthash::sha224{}.update(f.get_span()).final() << "\n"; 61 | } else if (h == "sha-256") { 62 | std::cout << cthash::sha256{}.update(f.get_span()).final() << "\n"; 63 | } else if (h == "sha-384") { 64 | std::cout << cthash::sha384{}.update(f.get_span()).final() << "\n"; 65 | } else if (h == "sha-512") { 66 | std::cout << cthash::sha512{}.update(f.get_span()).final() << "\n"; 67 | } else if (h == "sha-512/224") { 68 | std::cout << cthash::sha512t<224>{}.update(f.get_span()).final() << "\n"; 69 | } else if (h == "sha-512/256") { 70 | std::cout << cthash::sha512t<256>{}.update(f.get_span()).final() << "\n"; 71 | } else if (h == "sha3-224") { 72 | std::cout << cthash::sha3_224{}.update(f.get_span()).final() << "\n"; 73 | } else if (h == "sha3-256") { 74 | std::cout << cthash::sha3_256{}.update(f.get_span()).final() << "\n"; 75 | } else if (h == "sha3-384") { 76 | std::cout << cthash::sha3_384{}.update(f.get_span()).final() << "\n"; 77 | } else if (h == "sha3-512") { 78 | std::cout << cthash::sha3_512{}.update(f.get_span()).final() << "\n"; 79 | } else if (h == "shake-128/32") { 80 | std::cout << cthash::shake128{}.update(f.get_span()).final<32>() << "\n"; 81 | } else if (h == "shake-128/64") { 82 | std::cout << cthash::shake128{}.update(f.get_span()).final<64>() << "\n"; 83 | } else if (h == "shake-128/128") { 84 | std::cout << cthash::shake128{}.update(f.get_span()).final<128>() << "\n"; 85 | } else if (h == "shake-128/256") { 86 | std::cout << cthash::shake128{}.update(f.get_span()).final<256>() << "\n"; 87 | } else if (h == "shake-128/512") { 88 | std::cout << cthash::shake128{}.update(f.get_span()).final<512>() << "\n"; 89 | } else if (h == "shake-128/1024") { 90 | std::cout << cthash::shake128{}.update(f.get_span()).final<1024>() << "\n"; 91 | } else if (h == "shake-128/2048") { 92 | std::cout << cthash::shake128{}.update(f.get_span()).final<2048>() << "\n"; 93 | } else if (h == "shake-256/32") { 94 | std::cout << cthash::shake256{}.update(f.get_span()).final<32>() << "\n"; 95 | } else if (h == "shake-256/64") { 96 | std::cout << cthash::shake256{}.update(f.get_span()).final<64>() << "\n"; 97 | } else if (h == "shake-256/128") { 98 | std::cout << cthash::shake256{}.update(f.get_span()).final<128>() << "\n"; 99 | } else if (h == "shake-256/256") { 100 | std::cout << cthash::shake256{}.update(f.get_span()).final<256>() << "\n"; 101 | } else if (h == "shake-256/512") { 102 | std::cout << cthash::shake256{}.update(f.get_span()).final<512>() << "\n"; 103 | } else if (h == "shake-256/1024") { 104 | std::cout << cthash::shake256{}.update(f.get_span()).final<1024>() << "\n"; 105 | } else if (h == "shake-256/2048") { 106 | std::cout << cthash::shake256{}.update(f.get_span()).final<2048>() << "\n"; 107 | } else if (h == "xxhash32") { 108 | std::cout << cthash::xxhash32{}.update(f.get_span()).final() << "\n"; 109 | } else if (h == "xxhash64") { 110 | std::cout << cthash::xxhash64{}.update(f.get_span()).final() << "\n"; 111 | } else { 112 | std::cerr << "unknown hash function!\n"; 113 | return 1; 114 | } 115 | 116 | const auto end = std::chrono::high_resolution_clock::now(); 117 | const auto dur = end - start; 118 | 119 | std::cerr << "and it took " << std::chrono::duration_cast(dur).count() << " ms\n"; 120 | } -------------------------------------------------------------------------------- /cmake/colors.cmake: -------------------------------------------------------------------------------- 1 | option (FORCE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." ON) 2 | if (${FORCE_COLORED_OUTPUT}) 3 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 4 | add_compile_options ($<$:-fdiagnostics-color=always>) 5 | add_compile_options ($<$:-fdiagnostics-color=always>) 6 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 7 | add_compile_options ($<$:-fcolor-diagnostics>) 8 | add_compile_options ($<$:-fcolor-diagnostics>) 9 | endif () 10 | endif () -------------------------------------------------------------------------------- /cmake/coverage.cmake: -------------------------------------------------------------------------------- 1 | SET(test_source "int main() { }") 2 | 3 | try_compile(COVERAGE_WORKS SOURCE_FROM_VAR test.cpp test_source LINK_OPTIONS -fprofile-instr-generate -fcoverage-mapping) 4 | 5 | if (NOT COVERAGE_WORKS) 6 | function(enable_coverage) 7 | endfunction() 8 | 9 | function(coverage_report_after EVENT TARGET) 10 | add_custom_target(coverage DEPENDS ${EVENT}) 11 | endfunction() 12 | 13 | unset(LLVM_COV) 14 | return() 15 | endif() 16 | 17 | cmake_path(GET CMAKE_CXX_COMPILER PARENT_PATH COMPILER_HINT_PATH) 18 | 19 | find_program(LLVM_PROFDATA llvm-profdata HINTS ${COMPILER_HINT_PATH}) 20 | find_program(LLVM_COV llvm-cov HINTS ${COMPILER_HINT_PATH}) 21 | 22 | if (LLVM_PROFDATA AND LLVM_COV) 23 | set(LLVM_PROFDATA "${LLVM_PROFDATA}" CACHE INTERNAL "path to llvm-profdata") 24 | set(LLVM_COV "${LLVM_COV}" CACHE INTERNAL "path to llvm-cov") 25 | else() 26 | find_program(XCRUN xcrun) 27 | if (XCRUN) 28 | set(LLVM_PROFDATA "${XCRUN} llvm-profdata" CACHE INTERNAL "path to llvm-profdata") 29 | set(LLVM_COV "${XCRUN} llvm-cov" CACHE INTERNAL "path to llvm-cov") 30 | endif() 31 | endif() 32 | 33 | find_program(OPEN_UTILITY open) 34 | set(OPEN_UTILITY "${OPEN_UTILITY}" CACHE INTERNAL "path to open utility") 35 | 36 | function(enable_coverage) 37 | 38 | if (NOT COVERAGE_WORKS) 39 | message(FATAL_ERROR "Source level code coverage is not supporter!") 40 | endif() 41 | 42 | if (NOT LLVM_COV) 43 | message(FATAL_ERROR "Source level code coverage is supported only for Clang compiler! (CMAKE_CXX_COMPILER_ID = ${CMAKE_CXX_COMPILER_ID})") 44 | endif() 45 | 46 | message(STATUS "Enabling Clang source code-coverage (llvm-cov=${LLVM_COV})") 47 | 48 | # add flags to emit coverage 49 | add_compile_options("-fprofile-instr-generate" "-fcoverage-mapping" "-g") 50 | add_link_options("-fprofile-instr-generate" "-fcoverage-mapping") 51 | add_compile_options("-ffile-prefix-map=${CMAKE_SOURCE_DIR}/=/") 52 | endfunction() 53 | 54 | function(coverage_report_after EVENT TARGET) 55 | if (NOT LLVM_COV) 56 | add_custom_target(coverage DEPENDS ${EVENT}) 57 | return() 58 | endif() 59 | 60 | SET(coverage_data_name "default.profraw") 61 | add_custom_command(TARGET ${EVENT} POST_BUILD 62 | COMMAND ${LLVM_PROFDATA} merge -sparse ${coverage_data_name} -o coverage.profdata 63 | COMMAND ${LLVM_COV} show $ -format html -instr-profile=coverage.profdata "-ignore-filename-regex=\"(external/.*|tests/.*|cthash/internal/assert[.]hpp)\"" -output-dir ${CMAKE_BINARY_DIR}/report -show-instantiations=true -show-expansions=false -show-line-counts --show-line-counts-or-regions -Xdemangler c++filt -Xdemangler -n -show-branches=percent -tab-size=4 -path-equivalence=/,${CMAKE_SOURCE_DIR} 64 | COMMAND cd ${CMAKE_BINARY_DIR} && zip -q -r -9 report.zip report BYPRODUCTS ${CMAKE_BINARY_DIR}/report.zip COMMENT "Generating Code-Coverage report" 65 | ) 66 | 67 | add_custom_target(coverage DEPENDS ${CMAKE_BINARY_DIR}/report.zip) 68 | 69 | if (OPEN_UTILITY) 70 | add_custom_command(TARGET coverage POST_BUILD COMMAND ${OPEN_UTILITY} ${CMAKE_BINARY_DIR}/report/index.html DEPENDS ${CMAKE_BINARY_DIR}/report.zip) 71 | endif() 72 | endfunction() 73 | -------------------------------------------------------------------------------- /cmake/pedantic.cmake: -------------------------------------------------------------------------------- 1 | macro(add_c_and_cxx_compile_options NAME) 2 | add_compile_options("$<$:${NAME}>") 3 | add_compile_options("$<$:${NAME}>") 4 | endmacro() 5 | 6 | macro(add_c_and_cxx_compile_definitions NAME) 7 | add_compile_definitions("$<$:${NAME}>") 8 | add_compile_definitions("$<$:${NAME}>") 9 | endmacro() 10 | 11 | if (MSVC) 12 | add_c_and_cxx_compile_options("/W4") 13 | add_c_and_cxx_compile_options("/WX") 14 | else() 15 | add_c_and_cxx_compile_options("-Wall") 16 | add_c_and_cxx_compile_options("-Wextra") 17 | add_c_and_cxx_compile_options("-pedantic") 18 | add_c_and_cxx_compile_options("-Wshadow") 19 | add_c_and_cxx_compile_options("-Wconversion") 20 | add_c_and_cxx_compile_options("-Werror") 21 | 22 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 23 | add_c_and_cxx_compile_definitions("_LIBCPP_ENABLE_NODISCARD") 24 | 25 | if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0) 26 | add_c_and_cxx_compile_options("-Wno-missing-braces") 27 | endif() 28 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") 29 | add_c_and_cxx_compile_definitions("_LIBCPP_ENABLE_NODISCARD") 30 | add_c_and_cxx_compile_options("-Wno-missing-braces") 31 | endif() 32 | endif() 33 | -------------------------------------------------------------------------------- /default.profraw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanickadot/cthash/8520c044aad3a50085140107a4dfb18ddccd585c/default.profraw -------------------------------------------------------------------------------- /example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char ** argv) { 5 | if (argc < 2) { 6 | return 1; 7 | } 8 | 9 | const auto in = std::string_view(argv[1]); 10 | 11 | std::print(" sha224 = {:hexdec}\n", cthash::sha224{}.update(in).final()); 12 | std::print(" sha256 = {:hexdec}\n", cthash::sha256{}.update(in).final()); 13 | std::print(" sha384 = {:hexdec}\n", cthash::sha384{}.update(in).final()); 14 | std::print(" sha512 = {:hexdec}\n", cthash::sha512{}.update(in).final()); 15 | std::print(" sha512/224 = {:hexdec}\n", cthash::sha512t<224>{}.update(in).final()); 16 | std::print(" sha512/256 = {:hexdec}\n", cthash::sha512t<256>{}.update(in).final()); 17 | 18 | std::print(" sha3-224 = {:hexdec}\n", cthash::sha3_224{}.update(in).final()); 19 | std::print(" sha3-256 = {:hexdec}\n", cthash::sha3_256{}.update(in).final()); 20 | std::print(" sha3-384 = {:base64url}\n", cthash::sha3_384{}.update(in).final()); 21 | std::print(" sha3-512 = {:base64url}\n", cthash::sha3_512{}.update(in).final()); 22 | 23 | std::print("shake-128/64 = {:base64url}\n", cthash::shake128{}.update(in).final<64>()); 24 | std::print("shake-128/128 = {:base64url}\n", cthash::shake128{}.update(in).final<128>()); 25 | std::print("shake-128/1024 = {:base64url}\n", cthash::shake128{}.update(in).final<1024>()); 26 | 27 | std::print("shake-256/64 = {:base64url}\n", cthash::shake256{}.update(in).final<64>()); 28 | std::print("shake-256/128 = {:base64url}\n", cthash::shake256{}.update(in).final<128>()); 29 | std::print("shake-256/1024 = {:base64url}\n", cthash::shake256{}.update(in).final<1024>()); 30 | 31 | std::print(" xxhash32 = {:hexdec}\n", cthash::xxhash32{}.update(in).final()); 32 | std::print(" xxhash64 = {:hexdec}\n", cthash::xxhash64{}.update(in).final()); 33 | } -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(sha3 sha3.cpp) 2 | target_link_libraries(sha3 cthash) 3 | 4 | add_executable(sha256 sha256.cpp) 5 | target_link_libraries(sha256 cthash) 6 | 7 | add_executable(shake128 shake128.cpp) 8 | target_link_libraries(shake128 cthash) 9 | 10 | add_executable(xxhash xxhash.cpp) 11 | target_link_libraries(xxhash cthash) 12 | 13 | add_executable(playground playground.cpp) 14 | target_link_libraries(playground cthash) -------------------------------------------------------------------------------- /examples/playground.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace cthash::literals; 5 | 6 | template struct identify; 7 | 8 | int main() { 9 | const auto r = cthash::sha256{}.update("hello").update("there").final(); 10 | std::cout << r << "\n"; 11 | } -------------------------------------------------------------------------------- /examples/sha256.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace cthash::literals; 5 | 6 | int main() { 7 | constexpr auto a = cthash::sha256{}.update("hello there!").final(); 8 | 9 | std::print("{}", a); 10 | } 11 | -------------------------------------------------------------------------------- /examples/sha3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace cthash::literals; 5 | 6 | int main() { 7 | constexpr auto a = cthash::sha3_256{}.update("hello there!").final(); 8 | 9 | std::print("{:HEXDEC}", a); 10 | } 11 | -------------------------------------------------------------------------------- /examples/shake128.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace cthash::literals; 4 | 5 | int main() { 6 | constexpr auto expected = "86089a77e15628597e45caf70c8ef271def6775c54d42d61fb45b9cd6d3b288e5fbd0042241a4aa9180c1bfe94542e16765b3a48d549771202e50aebf8d4f51bd00be2a427f81b7b58aaebc97f89559bca1ea21fec5047de70d075e14e5a3c95c002fd9f81925672d408d4b60c0105e5858df25b64af9b20cec973d66616da813e544b951bfedbc1f2f79214c900be9621611206aa8b5f5727c38372d4410576206a42908800d8520469b4a62fdb6633a4283fcc290d709b48dad426db1fbe6aff9dabfbf2537f0c0bfce550ce1af1269a65022d29e12268da51bee5f1c54c85be5782ccb6996c902ecfa9f6cc28d52d2e5710677fd076751af267405e8c5ae0"_shake128; 7 | 8 | constexpr cthash::shake128_value<32> calculated_32bit = cthash::shake128().update("hello there!").final<32>(); 9 | constexpr cthash::shake128_value<128> calculated_128bit = cthash::shake128().update("hello there!").final<128>(); 10 | constexpr cthash::shake128_value<512> calculated_512bit = cthash::shake128().update("hello there!").final<512>(); 11 | constexpr cthash::shake128_value<1024> calculated_1024bit = cthash::shake128().update("hello there!").final<1024>(); 12 | constexpr cthash::shake128_value<2048> calculated_2048bit = cthash::shake128().update("hello there!").final<2048>(); 13 | constexpr cthash::shake128_value<4096> calculated_4096bit = cthash::shake128().update("hello there!").final<4096>(); 14 | 15 | // it only checks common length of both operands 16 | static_assert(expected == calculated_32bit); 17 | static_assert(expected == calculated_128bit); 18 | static_assert(expected == calculated_512bit); 19 | static_assert(expected == calculated_1024bit); 20 | static_assert(expected == calculated_2048bit); 21 | static_assert(expected == calculated_4096bit); 22 | } -------------------------------------------------------------------------------- /examples/xxhash.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace cthash::literals; 5 | 6 | int main() { 7 | constexpr auto a = cthash::xxhash32{}.update("hello there!").final(); 8 | 9 | std::print("{:base32}", a); 10 | } 11 | -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(cthash INTERFACE) 2 | 3 | target_compile_features(cthash INTERFACE cxx_std_23) 4 | target_include_directories(cthash INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) 5 | 6 | target_sources(cthash INTERFACE FILE_SET headers TYPE HEADERS FILES 7 | cthash/cthash.hpp 8 | cthash/encoding/base.hpp 9 | cthash/encoding/bit-buffer.hpp 10 | cthash/encoding/chunk-of-bits.hpp 11 | cthash/encoding/concepts.hpp 12 | cthash/encoding/encodings.hpp 13 | cthash/fixed-string.hpp 14 | cthash/hasher.hpp 15 | cthash/simple.hpp 16 | cthash/value.hpp 17 | cthash/xxhash.hpp 18 | cthash/internal/algorithm.hpp 19 | cthash/internal/assert.hpp 20 | cthash/internal/bit.hpp 21 | cthash/internal/concepts.hpp 22 | cthash/internal/convert.hpp 23 | cthash/internal/deduce.hpp 24 | cthash/internal/hexdec.hpp 25 | cthash/sha2/common.hpp 26 | cthash/sha2/sha224.hpp 27 | cthash/sha2/sha256.hpp 28 | cthash/sha2/sha384.hpp 29 | cthash/sha2/sha512/t.hpp 30 | cthash/sha2/sha512.hpp 31 | cthash/sha3/common.hpp 32 | cthash/sha3/keccak.hpp 33 | cthash/sha3/sha3-224.hpp 34 | cthash/sha3/sha3-256.hpp 35 | cthash/sha3/sha3-384.hpp 36 | cthash/sha3/sha3-512.hpp 37 | cthash/sha3/shake128.hpp 38 | cthash/sha3/shake256.hpp 39 | ) 40 | 41 | add_custom_target(single-header DEPENDS single-header.hpp) 42 | 43 | add_custom_target(single-header.hpp COMMAND python3 -m quom ${CMAKE_CURRENT_SOURCE_DIR}/cthash/cthash.hpp ${CMAKE_CURRENT_SOURCE_DIR}/cthash-single-header.hpp) 44 | -------------------------------------------------------------------------------- /include/cthash/cthash.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_CTHASH_HPP 2 | #define CTHASH_CTHASH_HPP 3 | 4 | // SHA-2 family 5 | #include "sha2/sha224.hpp" 6 | #include "sha2/sha256.hpp" 7 | #include "sha2/sha384.hpp" 8 | #include "sha2/sha512.hpp" 9 | #include "sha2/sha512/t.hpp" 10 | 11 | // SHA-3 (keccak) family 12 | #include "sha3/sha3-224.hpp" 13 | #include "sha3/sha3-256.hpp" 14 | #include "sha3/sha3-384.hpp" 15 | #include "sha3/sha3-512.hpp" 16 | #include "sha3/shake128.hpp" 17 | #include "sha3/shake256.hpp" 18 | 19 | // xxhash (non-crypto fast hash) 20 | #include "xxhash.hpp" 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/cthash/encoding/base.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_ENCODING_BASE_HPP 2 | #define CTHASH_ENCODING_BASE_HPP 3 | 4 | #include "chunk-of-bits.hpp" 5 | #include "encodings.hpp" 6 | #include 7 | 8 | namespace cthash { 9 | 10 | template struct encoding_properties { 11 | static constexpr size_t size = std::size(Encoding::alphabet) - 1u; 12 | static_assert(std::popcount(size) == 1u, "Size of encoding's alphabet must be power-of-two"); 13 | 14 | static constexpr size_t bits = std::countr_zero(size); 15 | 16 | static constexpr bool has_padding = padded_encoding; 17 | 18 | static constexpr char padding = [] { 19 | if constexpr (has_padding) { 20 | return Encoding::padding; 21 | } else { 22 | return '\0'; 23 | } 24 | }(); 25 | }; 26 | 27 | template struct encode_to_view { 28 | using properties = encoding_properties; 29 | using chunk_view = cthash::chunk_of_bits_view; 30 | 31 | struct sentinel { 32 | [[no_unique_address]] chunk_view::sentinel end; 33 | }; 34 | 35 | template struct iterator { 36 | using difference_type = intptr_t; 37 | using value_type = CharT; 38 | 39 | chunk_view::template iterator it; 40 | 41 | constexpr iterator & operator++() noexcept { 42 | ++it; 43 | return *this; 44 | } 45 | constexpr iterator operator++(int) noexcept { 46 | auto copy = *this; 47 | ++it; 48 | return copy; 49 | } 50 | 51 | constexpr value_type operator*() const noexcept { 52 | const auto tmp = *it; 53 | if constexpr (!chunk_view::aligned) { 54 | // TODO: do without condition 55 | if (tmp.is_padding()) { 56 | return properties::padding; 57 | } 58 | } 59 | return static_cast(Encoding::alphabet[static_cast(tmp.value)]); 60 | } 61 | 62 | constexpr friend bool operator==(const iterator &, const iterator &) noexcept = default; 63 | 64 | constexpr friend bool operator==(const iterator & lhs, const sentinel & rhs) noexcept { 65 | return lhs.it == rhs.end; 66 | } 67 | }; 68 | 69 | chunk_view input; 70 | 71 | constexpr encode_to_view(R _input): input{_input} { } 72 | 73 | constexpr auto begin() const noexcept { 74 | return iterator{input.begin()}; 75 | } 76 | 77 | constexpr auto begin() noexcept { 78 | return iterator{input.begin()}; 79 | } 80 | 81 | constexpr auto end() const noexcept { 82 | return sentinel{input.end()}; 83 | } 84 | 85 | constexpr size_t size() const noexcept requires(std::ranges::sized_range) { 86 | return input.size(); 87 | } 88 | 89 | constexpr auto to_string() const requires(std::ranges::sized_range) { 90 | #if __cpp_lib_ranges_to_container >= 202202L 91 | return std::ranges::to>(*this); 92 | #else 93 | auto result = std::basic_string{}; 94 | result.resize(size()); 95 | auto [i, o] = std::ranges::copy(begin(), end(), result.begin()); 96 | assert(i == encoded.end()); 97 | assert(o == result.end()); 98 | return result; 99 | #endif 100 | } 101 | 102 | constexpr friend std::basic_ostream & operator<<(std::basic_ostream & out, encode_to_view in) { 103 | std::ranges::copy(in.begin(), in.end(), std::ostream_iterator(out)); 104 | return out; 105 | } 106 | }; 107 | 108 | template struct decode_from_view { 109 | R input; 110 | 111 | template struct iterator { }; 112 | struct sentinel { }; 113 | 114 | constexpr decode_from_view(R _input): input{_input} { } 115 | 116 | constexpr auto begin() const noexcept { 117 | return iterator{input.begin()}; 118 | } 119 | 120 | constexpr auto begin() noexcept { 121 | return iterator{input.begin()}; 122 | } 123 | 124 | constexpr auto end() const noexcept { 125 | return sentinel{input.end()}; 126 | } 127 | 128 | constexpr size_t size() const noexcept requires(std::ranges::sized_range) { 129 | return input.size(); 130 | } 131 | }; 132 | 133 | template struct encode_to_action { 134 | template constexpr friend auto operator|(R && input, encode_to_action action) { 135 | return action.operator()(std::forward(input)); 136 | } 137 | template constexpr auto operator()(R && input) const { 138 | return encode_to_view(std::forward(input)); 139 | } 140 | }; 141 | 142 | template struct decode_from_action { 143 | template constexpr friend auto operator|(R && input, decode_from_action action) { 144 | return action.operator()(std::forward(input)); 145 | } 146 | template constexpr auto operator()(R && input) const { 147 | return decode_from_view(std::forward(input)); 148 | } 149 | }; 150 | 151 | template constexpr auto encode_to = encode_to_action{}; 152 | template constexpr auto decode_from = decode_from_action{}; 153 | 154 | constexpr auto binary_encode = encode_to; 155 | constexpr auto base2_encode = encode_to; 156 | constexpr auto base4_encode = encode_to; 157 | constexpr auto base8_encode = encode_to; 158 | constexpr auto octal_encode = encode_to; 159 | constexpr auto hexdec_encode = encode_to; 160 | constexpr auto hexdec_uppercase_encode = encode_to; 161 | constexpr auto base16_encode = encode_to; 162 | constexpr auto base32_encode = encode_to; 163 | constexpr auto base32_no_padding_encode = encode_to; 164 | constexpr auto z_base32_encode = encode_to; 165 | constexpr auto base64_encode = encode_to; 166 | constexpr auto base64url_encode = encode_to; 167 | constexpr auto base64_no_padding_encode = encode_to; 168 | 169 | constexpr auto binary_decode = decode_from; 170 | constexpr auto base2_decode = decode_from; 171 | constexpr auto base4_decode = decode_from; 172 | constexpr auto base8_decode = decode_from; 173 | constexpr auto hexdec_decode = decode_from; 174 | constexpr auto base16_decode = decode_from; 175 | constexpr auto base32_decode = decode_from; 176 | constexpr auto z_base32_decode = decode_from; 177 | constexpr auto base64_decode = decode_from; 178 | constexpr auto base64url_decode = decode_from; 179 | constexpr auto base64_no_padding_decode = decode_from; 180 | 181 | } // namespace cthash 182 | 183 | namespace std { 184 | 185 | #if __cpp_lib_format >= 201907L 186 | #define CTHASH_STDFMT_AVAILABLE 1 187 | #endif 188 | 189 | #if _LIBCPP_VERSION >= 170000 190 | // libc++ will define __cpp_lib_format macro in 19.0 191 | // https://github.com/llvm/llvm-project/issues/77773 192 | #define CTHASH_STDFMT_AVAILABLE 1 193 | #endif 194 | 195 | // template struct encode_to_view 196 | 197 | #ifdef CTHASH_STDFMT_AVAILABLE 198 | template 199 | struct formatter, CharT> { 200 | using subject_type = cthash::encode_to_view; 201 | 202 | template constexpr auto parse(ParseContext & ctx) { 203 | return std::ranges::begin(ctx); 204 | } 205 | 206 | template constexpr auto format(const subject_type & value, FormatContext & ctx) const { 207 | return std::ranges::copy(value, ctx.out()).out; 208 | } 209 | }; 210 | 211 | #endif 212 | 213 | } // namespace std 214 | 215 | #endif 216 | -------------------------------------------------------------------------------- /include/cthash/encoding/bit-buffer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_ENCODING_BIT_BUFFER_HPP 2 | #define CTHASH_ENCODING_BIT_BUFFER_HPP 3 | 4 | #include "concepts.hpp" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace cthash { 14 | 15 | template struct select_bit_integer; 16 | 17 | template requires(Bits <= 8) struct select_bit_integer { 18 | using type = uint8_t; 19 | }; 20 | 21 | template requires(Bits > 8 && Bits <= 16) struct select_bit_integer { 22 | using type = uint16_t; 23 | }; 24 | 25 | template requires(Bits > 16 && Bits <= 32) struct select_bit_integer { 26 | using type = uint32_t; 27 | }; 28 | 29 | template requires(Bits > 32 && Bits <= 64) struct select_bit_integer { 30 | using type = uint64_t; 31 | }; 32 | 33 | template using select_bit_integer_t = select_bit_integer::type; 34 | 35 | template requires(std::popcount(V) == 1u) constexpr auto log2_of_power_of_2 = static_cast(std::countr_zero(V)); 36 | 37 | template constexpr auto mask = static_cast>((static_cast>(1u) << Bits) - 1u); 38 | 39 | template class basic_bit_buffer { 40 | public: 41 | static constexpr auto capacity = std::integral_constant{}; 42 | using storage_type = select_bit_integer_t; 43 | using size_type = select_bit_integer_t>; 44 | 45 | public: 46 | storage_type buffer{0}; 47 | size_type bits_available{0}; 48 | 49 | public: 50 | template static constexpr auto mask = static_cast((static_cast(1u) << Bits) - 1u); 51 | 52 | constexpr friend bool operator==(const basic_bit_buffer & lhs, const basic_bit_buffer & rhs) noexcept = default; 53 | 54 | constexpr size_type size() const noexcept { 55 | return bits_available; 56 | } 57 | 58 | constexpr size_type unused_size() const noexcept { 59 | return capacity() - bits_available; 60 | } 61 | 62 | constexpr bool empty() const noexcept { 63 | return bits_available == 0u; 64 | } 65 | 66 | constexpr bool full() const noexcept { 67 | return bits_available == capacity(); 68 | } 69 | 70 | template constexpr void push(select_bit_integer_t in) noexcept requires(Bits <= capacity()) { 71 | assert(size() <= capacity() - Bits); 72 | buffer = static_cast(buffer << Bits) | static_cast(in); 73 | bits_available += static_cast(Bits); 74 | } 75 | constexpr void push_empty_bits(size_t count) noexcept { 76 | buffer = static_cast(buffer << count); 77 | bits_available += static_cast(count); 78 | } 79 | 80 | template constexpr void pop() noexcept requires(Bits <= capacity()) { 81 | assert(size() >= Bits); 82 | bits_available -= static_cast(Bits); 83 | } 84 | 85 | template constexpr auto front() const noexcept -> select_bit_integer_t requires(Bits <= capacity()) { 86 | using output_type = select_bit_integer_t; 87 | assert(size() >= static_cast(Bits)); 88 | return static_cast((buffer >> (bits_available - Bits))) & mask; 89 | } 90 | }; 91 | 92 | constexpr size_t calculate_padding_bit_count(size_t number_of_bits_in_buffer, size_t output_size, size_t input_size) { 93 | size_t n = number_of_bits_in_buffer; 94 | size_t padding_bits = 0u; 95 | 96 | while (n != 0u) { 97 | padding_bits += input_size; 98 | n += input_size; 99 | 100 | while (n >= output_size) { 101 | n = n - output_size; 102 | } 103 | } 104 | 105 | return padding_bits; 106 | } 107 | 108 | template class bit_buffer: protected basic_bit_buffer { 109 | using super = basic_bit_buffer; 110 | 111 | public: 112 | constexpr bit_buffer() noexcept = default; 113 | 114 | using typename super::size_type; 115 | static constexpr auto out_bits = std::integral_constant{}; 116 | static constexpr auto in_bits = std::integral_constant{}; 117 | 118 | using out_type = select_bit_integer_t; 119 | using in_type = select_bit_integer_t; 120 | 121 | using super::capacity; 122 | static constexpr auto in_capacity = std::integral_constant{}; 123 | static constexpr auto out_capacity = std::integral_constant{}; 124 | 125 | static constexpr auto aligned = std::bool_constant{}; 126 | 127 | constexpr void push(in_type in) noexcept { 128 | super::template push(in); 129 | } 130 | 131 | constexpr void push_empty() noexcept { 132 | this->push(in_type{0u}); 133 | } 134 | 135 | constexpr size_type push_zeros_to_align() noexcept requires(aligned()) { 136 | return 0u; 137 | } 138 | 139 | constexpr size_type push_zeros_for_padding() noexcept requires(aligned()) { 140 | return 0u; 141 | } 142 | 143 | constexpr size_type push_zeros_to_align() noexcept requires(!aligned()) { 144 | if (empty()) { 145 | return 0u; 146 | } 147 | 148 | assert(out_bits > super::size()); 149 | const size_type missing_bits = static_cast(out_bits - super::size()); 150 | super::push_empty_bits(missing_bits); 151 | return missing_bits; 152 | } 153 | 154 | constexpr size_type push_zeros_for_padding() noexcept requires(!aligned()) { 155 | const size_type usable_bits = super::size(); 156 | const size_type missing_bits = static_cast(calculate_padding_bit_count(super::size(), out_bits, in_bits)); 157 | super::push_empty_bits(missing_bits); 158 | return usable_bits; 159 | } 160 | 161 | constexpr void pop() noexcept { 162 | super::template pop(); 163 | } 164 | 165 | constexpr auto front() const noexcept -> out_type { 166 | return super::template front(); 167 | } 168 | 169 | constexpr size_type size() const noexcept { 170 | return static_cast(super::size() / out_bits); 171 | } 172 | 173 | constexpr size_type unused_size() const noexcept { 174 | return static_cast(super::unused_size() / in_bits); 175 | } 176 | 177 | using super::empty; 178 | using super::full; 179 | 180 | constexpr bool has_bits_for_pop() const noexcept { 181 | return super::size() >= out_bits; 182 | } 183 | 184 | constexpr bool has_capacity_for_push() const noexcept { 185 | return super::size() <= (capacity() - in_bits); 186 | } 187 | }; 188 | 189 | } // namespace cthash 190 | 191 | #endif 192 | -------------------------------------------------------------------------------- /include/cthash/encoding/chunk-of-bits.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_ENCODING_CHUNK_OF_BITS_HPP 2 | #define CTHASH_ENCODING_CHUNK_OF_BITS_HPP 3 | 4 | #include "bit-buffer.hpp" 5 | #include 6 | #include 7 | 8 | namespace cthash { 9 | 10 | template struct buffer_result_type; 11 | 12 | template requires(Buffer::aligned()) struct buffer_result_type { 13 | typename Buffer::out_type value; 14 | static constexpr Buffer::size_type missing_bits = {0u}; 15 | 16 | constexpr bool is_padding() const noexcept { 17 | return false; 18 | } 19 | }; 20 | 21 | template requires(!Buffer::aligned()) struct buffer_result_type { 22 | typename Buffer::out_type value; 23 | typename Buffer::size_type missing_bits; 24 | 25 | constexpr bool is_padding() const noexcept { 26 | return missing_bits == Buffer::out_bits; 27 | } 28 | }; 29 | 30 | template struct buffer_with_missing_bits; 31 | 32 | template requires(Buffer::aligned()) struct buffer_with_missing_bits { 33 | Buffer buffer{}; 34 | 35 | struct result_type { 36 | typename Buffer::out_type value; 37 | static constexpr Buffer::size_type missing_bits = {0u}; 38 | 39 | constexpr bool is_padding() const noexcept { 40 | return false; 41 | } 42 | }; 43 | 44 | static constexpr bool aligned = Buffer::aligned(); 45 | 46 | constexpr friend bool operator==(const buffer_with_missing_bits & lhs, const buffer_with_missing_bits & rhs) noexcept = default; 47 | 48 | constexpr auto front() const noexcept { 49 | return result_type{buffer.front()}; 50 | } 51 | 52 | constexpr bool empty() const noexcept { 53 | return buffer.empty(); 54 | } 55 | 56 | constexpr void pop() noexcept { 57 | return buffer.pop(); 58 | } 59 | 60 | template constexpr void feed_buffer(It & it, End end) noexcept { 61 | using input_value_type = std::iterator_traits::value_type; 62 | 63 | while (!buffer.has_bits_for_pop() && (it != end)) { 64 | buffer.push(static_cast>(*it)); 65 | ++it; 66 | } 67 | } 68 | }; 69 | 70 | template requires(!Buffer::aligned()) struct buffer_with_missing_bits { 71 | Buffer buffer{}; 72 | Buffer::size_type missing_bits{0}; 73 | 74 | static constexpr bool aligned = Buffer::aligned(); 75 | 76 | struct result_type { 77 | typename Buffer::out_type value; 78 | typename Buffer::size_type missing_bits; 79 | 80 | constexpr bool is_padding() const noexcept { 81 | return missing_bits == Buffer::out_bits; 82 | } 83 | }; 84 | 85 | constexpr friend bool operator==(const buffer_with_missing_bits & lhs, const buffer_with_missing_bits & rhs) noexcept = default; 86 | 87 | constexpr auto front() const noexcept { 88 | assert(Buffer::out_bits >= missing_bits); 89 | return result_type{buffer.front(), missing_bits}; 90 | } 91 | 92 | constexpr bool empty() const noexcept { 93 | return buffer.empty(); 94 | } 95 | 96 | constexpr void pop() noexcept { 97 | return buffer.pop(); 98 | } 99 | 100 | constexpr void pad_buffer() noexcept requires(AllowPadding) { 101 | // full multi-chunk padding (for baseN encodings) 102 | missing_bits = (Buffer::out_bits - buffer.push_zeros_for_padding()); 103 | } 104 | 105 | constexpr void pad_buffer() noexcept requires(!AllowPadding) { 106 | // only add enough zero to finish current output chunk 107 | missing_bits = buffer.push_zeros_to_align(); 108 | } 109 | 110 | constexpr void saturate_missing_bits() noexcept requires(AllowPadding) { 111 | if (missing_bits) { 112 | missing_bits = Buffer::out_bits; 113 | } 114 | // missing_bits = static_cast((unsigned)(bool)missing_bits * output_value_bit_size); 115 | } 116 | 117 | constexpr void saturate_missing_bits() noexcept requires(!AllowPadding) { 118 | // do nothing :) 119 | } 120 | 121 | template constexpr void feed_buffer(It & it, End end) noexcept { 122 | using input_value_type = std::iterator_traits::value_type; 123 | 124 | for (;;) { 125 | if (it == end) { 126 | if (buffer.has_bits_for_pop()) { 127 | // if this is second pass after padding we can mark all bits as missing 128 | saturate_missing_bits(); 129 | } else { 130 | // fill remainder of buffer with zeros 131 | pad_buffer(); 132 | } 133 | 134 | return; 135 | } 136 | 137 | if (buffer.has_bits_for_pop()) { 138 | return; 139 | } 140 | 141 | buffer.push(static_cast>(*it)); 142 | ++it; 143 | } 144 | } 145 | }; 146 | 147 | template struct conditional; 148 | 149 | template <> struct conditional { 150 | template using type = T; 151 | }; 152 | 153 | template <> struct conditional { 154 | template using type = T; 155 | }; 156 | 157 | template using maybe_const = typename conditional::template type; 158 | 159 | template concept integral_like = std::integral || std::same_as; 160 | 161 | template requires integral_like> struct chunk_of_bits_view { 162 | using input_value_type = std::ranges::range_value_t; 163 | 164 | static constexpr size_t output_value_bit_size = Bits; 165 | static constexpr size_t input_value_bit_size = sizeof(input_value_type) * 8u; 166 | using buffer_t = cthash::bit_buffer; 167 | using buffer_size_t = buffer_t::size_type; 168 | Input input; 169 | 170 | static constexpr bool aligned = buffer_t::aligned; 171 | 172 | struct sentinel { }; 173 | 174 | template struct iterator { 175 | using parent = maybe_const; 176 | using storage_type = buffer_with_missing_bits; 177 | using value_type = storage_type::result_type; 178 | using difference_type = intptr_t; 179 | 180 | std::ranges::iterator_t it; 181 | [[no_unique_address]] std::ranges::sentinel_t end; 182 | 183 | storage_type buffer{}; 184 | 185 | constexpr iterator(parent & p) noexcept: it{std::ranges::begin(p)}, end{std::ranges::end(p)} { 186 | // initialize 187 | buffer.feed_buffer(it, end); 188 | } 189 | 190 | iterator(const iterator &) = default; 191 | iterator(iterator &&) = default; 192 | 193 | iterator & operator=(const iterator &) = default; 194 | iterator & operator=(iterator &&) = default; 195 | 196 | constexpr iterator & operator++() noexcept { 197 | buffer.pop(); 198 | buffer.feed_buffer(it, end); 199 | return *this; 200 | } 201 | 202 | constexpr iterator operator++(int) noexcept { 203 | auto copy = *this; 204 | this->operator++(); 205 | return copy; 206 | } 207 | 208 | constexpr auto operator*() const noexcept { 209 | return buffer.front(); 210 | } 211 | 212 | constexpr friend bool operator==(const iterator & lhs, const iterator & rhs) noexcept = default; 213 | 214 | constexpr friend bool operator==(const iterator & self, sentinel) noexcept { 215 | return self.buffer.empty(); 216 | } 217 | }; 218 | 219 | static_assert(std::input_iterator>); 220 | static_assert(std::input_iterator>); 221 | static_assert(std::sentinel_for>); 222 | static_assert(std::sentinel_for>); 223 | 224 | constexpr chunk_of_bits_view(Input _input) noexcept: input{_input} { } 225 | 226 | constexpr auto begin() const noexcept { 227 | return iterator{input}; 228 | } 229 | 230 | constexpr auto begin() noexcept { 231 | return iterator{input}; 232 | } 233 | 234 | constexpr auto end() const noexcept { 235 | return sentinel{}; 236 | } 237 | 238 | constexpr size_t size() const noexcept requires(std::ranges::sized_range && AllowPadding) { 239 | // calculate with blocks 240 | return ((std::ranges::size(input) + (buffer_t::in_capacity() - 1u)) / buffer_t::in_capacity()) * buffer_t::out_capacity(); 241 | } 242 | 243 | constexpr size_t size() const noexcept requires(std::ranges::sized_range && !AllowPadding) { 244 | // calculate with bits 245 | const size_t bit_size_of_input = std::ranges::size(input) * input_value_bit_size; 246 | return (bit_size_of_input + (output_value_bit_size - 1u)) / output_value_bit_size; 247 | } 248 | }; 249 | 250 | template struct chunk_of_bits_action { 251 | template constexpr friend auto operator|(R && input, chunk_of_bits_action action) { 252 | return action.operator()(std::forward(input)); 253 | } 254 | template constexpr auto operator()(R && input) { 255 | return chunk_of_bits_view(std::forward(input)); 256 | } 257 | }; 258 | 259 | template constexpr auto chunk_of_bits = chunk_of_bits_action{}; 260 | 261 | } // namespace cthash 262 | 263 | #endif 264 | -------------------------------------------------------------------------------- /include/cthash/encoding/concepts.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_ENCODING_CONCEPTS_HPP 2 | #define CTHASH_ENCODING_CONCEPTS_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace cthash { 9 | 10 | template struct fixed { }; 11 | template constexpr auto fixed_cast = fixed{}; 12 | 13 | template concept one_of = (std::same_as || ...); 14 | 15 | template concept byte = one_of, char, unsigned char, signed char, uint8_t, int8_t, std::byte>; 16 | 17 | template concept padded_encoding = requires() { 18 | { Encoding::padding } -> cthash::byte; 19 | }; 20 | 21 | template concept byte_range = requires() { 22 | requires std::ranges::range; 23 | requires cthash::byte>; 24 | }; 25 | 26 | } // namespace cthash 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/cthash/encoding/encodings.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_ENCODING_ENCODINGS_HPP 2 | #define CTHASH_ENCODING_ENCODINGS_HPP 3 | 4 | #include "concepts.hpp" 5 | #include 6 | 7 | namespace cthash { 8 | 9 | namespace encoding { 10 | 11 | template struct list { }; 12 | 13 | struct base64 { 14 | static constexpr std::string_view name = "base64"; 15 | 16 | static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 17 | static constexpr char padding = '='; 18 | }; 19 | 20 | struct base64_no_padding { 21 | static constexpr std::string_view name = "base64_no_padding"; 22 | 23 | static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 24 | }; 25 | 26 | struct base64url { 27 | static constexpr std::string_view name = "base64url"; 28 | static constexpr std::string_view alt_name = "base64_url"; 29 | 30 | static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; 31 | }; 32 | 33 | static_assert(padded_encoding); 34 | 35 | struct base32 { 36 | static constexpr std::string_view name = "base32"; 37 | 38 | static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; 39 | static constexpr char padding = '='; 40 | }; 41 | 42 | struct base32_no_padding { 43 | static constexpr std::string_view name = "base32_no_padding"; 44 | 45 | static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; 46 | }; 47 | 48 | struct z_base32 { 49 | static constexpr std::string_view name = "z_base32"; 50 | static constexpr std::string_view alt_name = "zbase32"; 51 | 52 | static constexpr char alphabet[] = "ybndrfg8ejkmcpqxot1uwisza345h769"; 53 | }; 54 | 55 | struct base16 { 56 | static constexpr std::string_view name = "base16"; 57 | static constexpr std::string_view alt_name = "hexdec"; 58 | 59 | static constexpr char alphabet[] = "0123456789abcdef"; 60 | }; 61 | 62 | using hexdec = base16; 63 | 64 | struct base16_uppercase { 65 | static constexpr std::string_view name = "BASE16"; 66 | static constexpr std::string_view alt_name = "HEXDEC"; 67 | 68 | static constexpr char alphabet[] = "0123456789ABCDEF"; 69 | }; 70 | 71 | using hexdec_uppercase = base16_uppercase; 72 | 73 | struct base8 { 74 | static constexpr std::string_view name = "base8"; 75 | static constexpr std::string_view alt_name = "octal"; 76 | 77 | static constexpr char alphabet[] = "01234567"; 78 | static constexpr char padding = '='; 79 | }; 80 | 81 | using octal = base8; 82 | 83 | struct base4 { 84 | static constexpr std::string_view name = "base4"; 85 | 86 | static constexpr char alphabet[] = "0123"; 87 | }; 88 | 89 | struct base2 { 90 | static constexpr std::string_view name = "base2"; 91 | static constexpr std::string_view alt_name = "binary"; 92 | 93 | static constexpr char alphabet[] = "01"; 94 | }; 95 | 96 | using binary = base2; 97 | 98 | using known_encodings = list; 99 | 100 | } // namespace encoding 101 | 102 | template struct dynamic_encodings; 103 | 104 | template concept has_alt_name = requires { 105 | { Encoding::alt_name } -> std::same_as; 106 | }; 107 | 108 | static_assert(has_alt_name); 109 | 110 | template concept one_from = (std::same_as || ... || false); 111 | 112 | template constexpr size_t longest_name_for = Encoding::name.size(); 113 | template constexpr size_t longest_name_for = std::max(Encoding::name.size(), Encoding::alt_name.size()); 114 | 115 | template constexpr bool match_encoding(std::string_view name) noexcept { 116 | return Encoding::name == name; 117 | } 118 | 119 | template constexpr bool match_encoding(std::string_view name) noexcept { 120 | return Encoding::name == name || Encoding::alt_name == name; 121 | } 122 | 123 | template struct dynamic_encodings>: std::variant { 124 | using super = std::variant; 125 | 126 | template static constexpr bool assign_encoding(std::string_view name, std::optional & output) noexcept { 127 | auto r = match_encoding(name); 128 | 129 | if (!r) { 130 | return false; 131 | } 132 | 133 | output = Encoding{}; 134 | return true; 135 | } 136 | 137 | static constexpr auto select_encoding(std::string_view name) -> super { 138 | std::optional output{std::nullopt}; 139 | 140 | // I'm not using bool to avoid warning to have better code coverage 141 | const auto success = (unsigned(assign_encoding(name, output)) | ... | 0u); 142 | 143 | if (!success) { 144 | throw std::invalid_argument{"unknown encoding name"}; 145 | } 146 | 147 | assert(output.has_value()); 148 | 149 | return *output; 150 | } 151 | 152 | static constexpr size_t longest_name_size = std::max({longest_name_for...}); 153 | 154 | constexpr dynamic_encodings(std::string_view name): super(select_encoding(name)) { } 155 | constexpr dynamic_encodings(one_from auto enc) noexcept: super(enc) { } 156 | 157 | template constexpr auto visit(Fnc && fnc) const { 158 | return std::visit(std::forward(fnc), static_cast(*this)); 159 | } 160 | }; 161 | 162 | template constexpr auto select_encoding(InputContext && input) { 163 | using iterator_t = decltype(std::ranges::begin(input)); 164 | 165 | struct result { 166 | Encoding encoding; 167 | iterator_t iterator; 168 | }; 169 | 170 | auto it = std::ranges::begin(input); 171 | 172 | if (it == std::ranges::end(input) || *it == '}') { 173 | return result{.encoding = DefaultEncoding{}, .iterator = it}; 174 | } 175 | 176 | // this will copy it into buffer to compare 177 | std::array buffer{}; 178 | auto out = buffer.begin(); 179 | 180 | for (;;) { 181 | if (it == std::ranges::end(input)) { 182 | break; 183 | } 184 | 185 | const char c = *it; 186 | 187 | if (c == '}') { 188 | break; 189 | } 190 | 191 | if (out != buffer.end()) { 192 | *out++ = c; 193 | } 194 | 195 | ++it; 196 | } 197 | 198 | const std::string_view name = std::string_view(buffer.data(), static_cast(std::distance(buffer.begin(), out))); 199 | 200 | return result{.encoding = Encoding(name), .iterator = it}; 201 | } 202 | 203 | using runtime_encoding = dynamic_encodings; 204 | 205 | template constexpr auto select_runtime_encoding(InputContext && input) { 206 | return select_encoding(std::forward(input)); 207 | } 208 | 209 | } // namespace cthash 210 | 211 | #endif 212 | -------------------------------------------------------------------------------- /include/cthash/fixed-string.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_FIXED_STRING_HPP 2 | #define CTHASH_FIXED_STRING_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace cthash { 9 | 10 | template struct fixed_string: std::array { 11 | using super = std::array; 12 | 13 | consteval static auto from_string_literal(const CharT (&in)[N + 1]) -> std::array { 14 | std::array out; 15 | std::copy_n(in, N, out.data()); 16 | return out; 17 | } 18 | 19 | explicit constexpr fixed_string(std::nullptr_t) noexcept: super{} { } 20 | 21 | consteval fixed_string(const CharT (&in)[N + 1]) noexcept: super{from_string_literal(in)} { } 22 | 23 | using super::data; 24 | using super::size; 25 | 26 | constexpr operator std::span() const noexcept { 27 | return std::span(data(), size()); 28 | } 29 | 30 | constexpr operator std::span() const noexcept { 31 | return std::span(data(), size()); 32 | } 33 | 34 | constexpr operator std::basic_string_view() const noexcept { 35 | return std::basic_string_view(data(), size()); 36 | } 37 | 38 | constexpr friend bool operator==(const fixed_string &, const fixed_string &) noexcept = default; 39 | constexpr friend bool operator==(const fixed_string & lhs, std::basic_string_view rhs) noexcept { 40 | return std::basic_string_view{lhs} == rhs; 41 | } 42 | constexpr friend bool operator==(const fixed_string & lhs, const CharT * rhs) noexcept { 43 | return std::basic_string_view{lhs} == std::basic_string_view{rhs}; 44 | } 45 | }; 46 | 47 | template fixed_string(const CharT (&)[N]) -> fixed_string; 48 | 49 | } // namespace cthash 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /include/cthash/hasher.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONSTEXPR_SHA2_HASHER_HPP 2 | #define CONSTEXPR_SHA2_HASHER_HPP 3 | 4 | #include "simple.hpp" 5 | #include "value.hpp" 6 | #include "internal/assert.hpp" 7 | #include "internal/bit.hpp" 8 | #include "internal/concepts.hpp" 9 | #include "internal/convert.hpp" 10 | #include "internal/deduce.hpp" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace cthash { 19 | 20 | template struct internal_hasher { 21 | static constexpr auto config = Config{}; 22 | static constexpr size_t block_size_bytes = config.block_bits / 8u; 23 | static constexpr size_t digest_bytes = internal::digest_bytes_length_of; 24 | 25 | // internal types 26 | using state_value_t = std::remove_cvref_t; 27 | using state_item_t = typename state_value_t::value_type; 28 | 29 | using block_value_t = std::array; 30 | using block_view_t = std::span; 31 | 32 | using staging_item_t = typename decltype(config.constants)::value_type; 33 | static constexpr size_t staging_size = config.constants.size(); 34 | using staging_value_t = std::array; 35 | using staging_view_t = std::span; 36 | 37 | using digest_span_t = std::span; 38 | using result_t = cthash::tagged_hash_value; 39 | using length_t = typename Config::length_type; 40 | 41 | // internal state 42 | state_value_t hash; 43 | length_t total_length; 44 | 45 | block_value_t block; 46 | unsigned block_used; 47 | 48 | // constructors 49 | constexpr internal_hasher() noexcept: hash{config.initial_values}, total_length{0u}, block_used{0u} { } 50 | constexpr internal_hasher(const internal_hasher &) noexcept = default; 51 | constexpr internal_hasher(internal_hasher &&) noexcept = default; 52 | constexpr ~internal_hasher() noexcept = default; 53 | 54 | // take buffer and build staging 55 | template [[gnu::always_inline]] static constexpr auto build_staging(std::span chunk) noexcept -> staging_value_t { 56 | staging_value_t w; 57 | 58 | constexpr auto first_part_size = block_size_bytes / sizeof(staging_item_t); 59 | 60 | // fill first part with chunk 61 | for (int i = 0; i != int(first_part_size); ++i) { 62 | w[static_cast(i)] = cast_from_bytes(chunk.subspan(static_cast(i) * sizeof(staging_item_t)).template first()); 63 | } 64 | 65 | // fill the rest (generify) 66 | for (int i = int(first_part_size); i != int(staging_size); ++i) { 67 | w[static_cast(i)] = w[static_cast(i - 16)] + config.sigma_0(w[static_cast(i - 15)]) + w[static_cast(i - 7)] + config.sigma_1(w[static_cast(i - 2)]); 68 | } 69 | 70 | return w; 71 | } 72 | 73 | [[gnu::always_inline]] static constexpr auto build_staging(std::span chunk) noexcept -> staging_value_t { 74 | return build_staging(chunk); 75 | } 76 | 77 | [[gnu::always_inline]] static constexpr void rounds(staging_view_t w, state_value_t & state) noexcept { 78 | config.rounds(w, state); 79 | } 80 | 81 | // this implementation works only with input size aligned to bytes (not bits) 82 | template [[gnu::always_inline]] constexpr void update_to_buffer_and_process(std::span in) noexcept { 83 | // if block is not used, we can build staging directly 84 | if (block_used) { 85 | const auto remaining_free_space = std::span(block).subspan(block_used); 86 | const auto to_copy = in.first(std::min(in.size(), remaining_free_space.size())); 87 | 88 | const auto it = byte_copy(to_copy.begin(), to_copy.end(), remaining_free_space.begin()); 89 | total_length += to_copy.size(); 90 | 91 | // we didn't fill the block 92 | if (it != remaining_free_space.end()) { 93 | CTHASH_ASSERT(to_copy.size() == in.size()); 94 | block_used += static_cast(to_copy.size()); 95 | return; 96 | } else { 97 | block_used = 0u; 98 | } 99 | 100 | // we have block! 101 | const staging_value_t w = build_staging(block); 102 | rounds(w, hash); 103 | 104 | // remove part we processed 105 | in = in.subspan(to_copy.size()); 106 | } 107 | 108 | // do the work over blocks without copy 109 | if (not block_used) { 110 | while (in.size() >= block_size_bytes) { 111 | const auto local_block = in.template first(); 112 | total_length += block_size_bytes; 113 | 114 | const staging_value_t w = build_staging(local_block); 115 | rounds(w, hash); 116 | 117 | // remove part we processed 118 | in = in.subspan(block_size_bytes); 119 | } 120 | } 121 | 122 | // remainder is put onto temporary block 123 | if (not in.empty()) { 124 | CTHASH_ASSERT(block_used == 0u); 125 | CTHASH_ASSERT(in.size() < block_size_bytes); 126 | 127 | // copy it to block and let it stay there 128 | byte_copy(in.begin(), in.end(), block.begin()); 129 | block_used = static_cast(in.size()); 130 | total_length += block_used; 131 | } 132 | } 133 | 134 | [[gnu::always_inline]] static constexpr bool finalize_buffer(block_value_t & block, size_t block_used) noexcept { 135 | CTHASH_ASSERT(block_used < block.size()); 136 | const auto free_space = std::span(block).subspan(block_used); 137 | 138 | auto it = free_space.data(); 139 | *it++ = std::byte{0b1000'0000u}; // first byte after data contains bit at MSB 140 | std::fill(it, (block.data() + block.size()), std::byte{0x0u}); // rest is filled with zeros 141 | 142 | // we don't have enough space to write length bits 143 | return free_space.size() < (1u + (config.length_size_bits / 8u)); 144 | } 145 | 146 | [[gnu::always_inline]] static constexpr void finalize_buffer_by_writing_length(block_value_t & block, length_t total_length) noexcept { 147 | unwrap_bigendian_number{std::span(block).template last()} = (total_length * 8u); 148 | } 149 | 150 | [[gnu::always_inline]] constexpr void finalize() noexcept { 151 | if (finalize_buffer(block, block_used)) { 152 | // we didn't have enough space, we need to process block 153 | const staging_value_t w = build_staging(block); 154 | rounds(w, hash); 155 | 156 | // zero it out 157 | std::fill(block.begin(), block.end(), std::byte{0x0u}); 158 | } 159 | 160 | // we either have space to write or we have zerod out block 161 | finalize_buffer_by_writing_length(block, total_length); 162 | 163 | // calculate last round 164 | const staging_value_t w = build_staging(block); 165 | rounds(w, hash); 166 | } 167 | 168 | [[gnu::always_inline]] constexpr void write_result_into(digest_span_t out) noexcept 169 | requires(digest_bytes % sizeof(state_item_t) == 0u) 170 | { 171 | // copy result to byte result 172 | constexpr size_t values_for_output = digest_bytes / sizeof(state_item_t); 173 | static_assert(values_for_output <= config.initial_values.size()); 174 | 175 | for (int i = 0; i != values_for_output; ++i) { 176 | unwrap_bigendian_number{out.subspan(static_cast(i) * sizeof(state_item_t)).template first()} = hash[static_cast(i)]; 177 | } 178 | } 179 | 180 | [[gnu::always_inline]] constexpr void write_result_into(digest_span_t out) noexcept 181 | requires(digest_bytes % sizeof(state_item_t) != 0u) 182 | { 183 | // this is only used when digest doesn't align with output buffer 184 | 185 | // make sure digest size is smaller than hash state 186 | static_assert(digest_bytes <= config.initial_values.size() * sizeof(state_item_t)); 187 | 188 | // copy result to byte result 189 | std::array tmp_buffer; 190 | 191 | for (int i = 0; i != (int)config.initial_values.size(); ++i) { 192 | unwrap_bigendian_number{std::span(tmp_buffer).subspan(static_cast(i) * sizeof(state_item_t)).template first()} = hash[static_cast(i)]; 193 | } 194 | 195 | std::copy_n(tmp_buffer.data(), digest_bytes, out.data()); 196 | } 197 | }; 198 | 199 | // this is a convinience type for nicer UX... 200 | template struct hasher: private internal_hasher { 201 | using super = internal_hasher; 202 | using result_t = typename super::result_t; 203 | using length_t = typename super::length_t; 204 | using digest_span_t = typename super::digest_span_t; 205 | 206 | constexpr hasher() noexcept: super() { } 207 | constexpr hasher(const hasher &) noexcept = default; 208 | constexpr hasher(hasher &&) noexcept = default; 209 | constexpr ~hasher() noexcept = default; 210 | 211 | // support for various input types 212 | constexpr hasher & update(std::span input) noexcept { 213 | super::update_to_buffer_and_process(input); 214 | return *this; 215 | } 216 | 217 | template constexpr hasher & update(const T & something) noexcept { 218 | using value_type = typename decltype(std::span(something))::value_type; 219 | super::update_to_buffer_and_process(std::span(something)); 220 | return *this; 221 | } 222 | 223 | template constexpr hasher & update(std::basic_string_view in) noexcept { 224 | super::update_to_buffer_and_process(std::span(in.data(), in.size())); 225 | return *this; 226 | } 227 | 228 | template constexpr hasher & update(const T & lit) noexcept { 229 | super::update_to_buffer_and_process(std::span(lit, std::size(lit) - 1u)); 230 | return *this; 231 | } 232 | 233 | // TODO: any range with value convertible to byte 234 | 235 | // output (by reference or by value) 236 | constexpr void final(digest_span_t digest) noexcept { 237 | super::finalize(); 238 | super::write_result_into(digest); 239 | } 240 | 241 | constexpr auto final() noexcept { 242 | result_t output; 243 | this->final(output); 244 | return output; 245 | } 246 | 247 | constexpr length_t size() const noexcept { 248 | return super::total_length; 249 | } 250 | }; 251 | 252 | } // namespace cthash 253 | 254 | #endif 255 | -------------------------------------------------------------------------------- /include/cthash/internal/algorithm.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_INTERNAL_ALGORITHM_HPP 2 | #define CTHASH_INTERNAL_ALGORITHM_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace cthash::internal { 10 | 11 | template constexpr auto threeway_compare_of_same_size(It1 lhs, It2 rhs, size_t length) -> std::strong_ordering { 12 | for (size_t i = 0; i != length; ++i) { 13 | if (const auto r = (*lhs++ <=> *rhs++); r != 0) { 14 | return r; 15 | } 16 | } 17 | 18 | return std::strong_ordering::equal; 19 | } 20 | 21 | template constexpr auto & push_to_stream_as(It1 f, It2 l, Stream & stream) { 22 | constexpr auto cast_and_shift = [](Stream * s, const auto & rhs) { (*s) << T{rhs}; return s; }; 23 | return *std::accumulate(f, l, &stream, cast_and_shift); 24 | } 25 | 26 | } // namespace cthash::internal 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/cthash/internal/assert.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_INTERNAL_ASSERT_HPP 2 | #define CTHASH_INTERNAL_ASSERT_HPP 3 | 4 | #ifndef NDEBUG 5 | #define CTHASH_ASSERT(e) cthash::assert_this(static_cast(e), #e, __FILE__, __LINE__); 6 | #else 7 | #define CTHASH_ASSERT(e) ((void)(0)) 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace cthash { 14 | 15 | constexpr void assert_this(bool value, const char * expression, const char * file, unsigned line) { 16 | if (!value) { 17 | printf("%s:%u: failed assertion '%s'\n", file, line, expression); 18 | std::abort(); 19 | } 20 | } 21 | 22 | } // namespace cthash 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/cthash/internal/bit.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_INTERNAL_BIT_HPP 2 | #define CTHASH_INTERNAL_BIT_HPP 3 | 4 | #include 5 | 6 | namespace cthash::internal { 7 | 8 | #if defined(__cpp_lib_byteswap) && __cpp_lib_byteswap >= 202110L 9 | 10 | template [[gnu::always_inline]] constexpr auto byteswap(T val) noexcept { 11 | return std::byteswap(val); 12 | } 13 | 14 | #else 15 | 16 | template concept unsigned_integral_of_size = (sizeof(T) == N) && std::unsigned_integral; 17 | 18 | template T> constexpr auto byteswap(T val) noexcept { 19 | return val; 20 | } 21 | 22 | template T> constexpr auto byteswap(T val) noexcept { 23 | return static_cast(__builtin_bswap16(val)); 24 | } 25 | 26 | template T> constexpr auto byteswap(T val) noexcept { 27 | return static_cast(__builtin_bswap32(val)); 28 | } 29 | 30 | template T> constexpr auto byteswap(T val) noexcept { 31 | return static_cast(__builtin_bswap64(val)); 32 | } 33 | 34 | #endif 35 | 36 | } // namespace cthash::internal 37 | 38 | #endif -------------------------------------------------------------------------------- /include/cthash/internal/concepts.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_CONCEPTS_HPP 2 | #define CTHASH_CONCEPTS_HPP 3 | 4 | #include 5 | 6 | namespace cthash { 7 | 8 | template concept one_byte_char = (sizeof(T) == 1u); 9 | 10 | template concept byte_like = (sizeof(T) == 1u) && (std::same_as || std::same_as || std::same_as || std::same_as || std::same_as || std::same_as); 11 | 12 | template void string_literal_helper(const CharT (&)[N]); 13 | 14 | template concept string_literal = requires(const T & in) // 15 | { 16 | string_literal_helper(in); 17 | }; 18 | 19 | template concept convertible_to_byte_span = requires(T && obj) // 20 | { 21 | { std::span(obj) }; 22 | requires byte_like; 23 | requires !string_literal; 24 | }; 25 | 26 | } // namespace cthash 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/cthash/internal/convert.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_INTERNAL_CONVERT_HPP 2 | #define CTHASH_INTERNAL_CONVERT_HPP 3 | 4 | #include "bit.hpp" 5 | #include "concepts.hpp" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace cthash { 13 | 14 | template constexpr auto byte_copy(It1 first, It2 last, It3 destination) { 15 | return std::transform(first, last, destination, [](byte_like auto v) { return static_cast(v); }); 16 | } 17 | 18 | template constexpr auto cast_from_bytes(std::span in) noexcept -> T { 19 | if consteval { 20 | return [&](std::index_sequence) -> T { 21 | return static_cast(((static_cast(in[Idx]) << ((sizeof(T) - 1u - Idx) * 8u)) | ...)); 22 | }(std::make_index_sequence()); 23 | } else { 24 | T t; 25 | std::memcpy(&t, in.data(), sizeof(T)); 26 | if constexpr (std::endian::native == std::endian::little) { 27 | return internal::byteswap(t); 28 | } else { 29 | return t; 30 | } 31 | } 32 | } 33 | 34 | template constexpr auto cast_from_le_bytes(std::span in) noexcept -> T { 35 | if consteval { 36 | return [&](std::index_sequence) -> T { 37 | return static_cast(((static_cast(in[Idx]) << static_cast(Idx * 8u)) | ...)); 38 | }(std::make_index_sequence()); 39 | } else { 40 | T t; 41 | std::memcpy(&t, in.data(), sizeof(T)); 42 | if constexpr (std::endian::native == std::endian::big) { 43 | return internal::byteswap(t); 44 | } else { 45 | return t; 46 | } 47 | } 48 | } 49 | 50 | template struct unwrap_littleendian_number { 51 | static constexpr size_t bytes = sizeof(T); 52 | static constexpr size_t bits = bytes * 8u; 53 | 54 | std::span ref; 55 | 56 | constexpr void operator=(T value) noexcept { 57 | [&](std::index_sequence) { 58 | ((ref[Idx] = static_cast(value >> (Idx * 8u))), ...); 59 | }(std::make_index_sequence()); 60 | } 61 | }; 62 | 63 | unwrap_littleendian_number(std::span) -> unwrap_littleendian_number; 64 | unwrap_littleendian_number(std::span) -> unwrap_littleendian_number; 65 | 66 | template struct unwrap_bigendian_number { 67 | static constexpr size_t bytes = sizeof(T); 68 | static constexpr size_t bits = bytes * 8u; 69 | 70 | std::span ref; 71 | 72 | constexpr void operator=(T value) noexcept { 73 | [&](std::index_sequence) { 74 | ((ref[Idx] = static_cast(value >> ((bits - 8u) - 8u * Idx))), ...); 75 | }(std::make_index_sequence()); 76 | } 77 | }; 78 | 79 | unwrap_bigendian_number(std::span) -> unwrap_bigendian_number; 80 | unwrap_bigendian_number(std::span) -> unwrap_bigendian_number; 81 | 82 | } // namespace cthash 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /include/cthash/internal/deduce.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_INTERNAL_DEDUCE_HPP 2 | #define CTHASH_INTERNAL_DEDUCE_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace cthash::internal { 8 | 9 | // support 10 | 11 | template concept digest_length_provided = requires() // 12 | { 13 | { static_cast(T::digest_length) } -> std::same_as; 14 | }; 15 | 16 | template concept digest_length_bit_provided = requires() // 17 | { 18 | { static_cast(T::digest_length_bit) } -> std::same_as; 19 | }; 20 | 21 | template concept initial_values_provided = requires() // 22 | { 23 | { static_cast(T::initial_values.size() * sizeof(typename decltype(T::initial_values)::value_type)) } -> std::same_as; 24 | }; 25 | 26 | template static constexpr bool dependent_false = false; 27 | 28 | template constexpr size_t digest_bytes_length_of = [] { 29 | if constexpr (digest_length_provided) { 30 | return static_cast(Config::digest_length); 31 | } else if constexpr (digest_length_bit_provided) { 32 | return static_cast(Config::digest_length_bit) / 8u; 33 | } else if constexpr (initial_values_provided) { 34 | return static_cast(Config::initial_values.size() * sizeof(typename decltype(Config::initial_values)::value_type)); 35 | } else { 36 | static_assert(dependent_false); 37 | } 38 | }(); 39 | 40 | } // namespace cthash::internal 41 | 42 | #endif -------------------------------------------------------------------------------- /include/cthash/internal/hexdec.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_INTERNAL_HEXDEC_HPP 2 | #define CTHASH_INTERNAL_HEXDEC_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace cthash::internal { 10 | 11 | consteval auto get_hexdec_table() noexcept { 12 | std::array result; 13 | 14 | auto char_to_hexdec = [](char c) { 15 | if (c >= '0' && c <= '9') { 16 | return static_cast(c - '0'); 17 | } else if (c >= 'a' && c <= 'f') { 18 | return static_cast(c - 'a' + 10); 19 | } else if (c >= 'A' && c <= 'F') { 20 | return static_cast(c - 'A' + 10); 21 | } else { 22 | return static_cast(0); 23 | } 24 | }; 25 | 26 | for (int i = 0; i != static_cast(result.size()); ++i) { 27 | result[static_cast(i)] = char_to_hexdec(static_cast(i)); 28 | } 29 | 30 | return result; 31 | } 32 | 33 | constexpr auto hexdec_to_value_alphabet = get_hexdec_table(); 34 | 35 | template constexpr auto value_to_hexdec_alphabet = std::array{CharT('0'), CharT('1'), CharT('2'), CharT('3'), CharT('4'), CharT('5'), CharT('6'), CharT('7'), CharT('8'), CharT('9'), CharT('a'), CharT('b'), CharT('c'), CharT('d'), CharT('e'), CharT('f')}; 36 | 37 | struct byte_hexdec_value { 38 | std::byte val; 39 | 40 | template friend auto & operator<<(std::basic_ostream & os, byte_hexdec_value rhs) { 41 | return os << value_to_hexdec_alphabet[unsigned(rhs.val >> 4u)] << value_to_hexdec_alphabet[unsigned(rhs.val) & 0b1111u]; 42 | } 43 | }; 44 | 45 | template constexpr auto hexdec_to_binary(std::span in) -> std::array { 46 | return [in](std::index_sequence) { 47 | return std::array{static_cast(hexdec_to_value_alphabet[static_cast(in[Idx * 2]) & 0b0111'1111u] << 4u | hexdec_to_value_alphabet[static_cast(in[Idx * 2u + 1u]) & 0b0111'1111u])...}; 48 | } 49 | (std::make_index_sequence()); 50 | } 51 | 52 | template 53 | requires((N - 1) % 2 == 0) // -1 because of zero terminator in literals 54 | constexpr auto literal_hexdec_to_binary(const CharT (&in)[N]) -> std::array { 55 | return hexdec_to_binary(std::span(in, N - 1)); 56 | } 57 | 58 | } // namespace cthash::internal 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /include/cthash/sha2/common.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA2_COMMON_HPP 2 | #define CTHASH_SHA2_COMMON_HPP 3 | 4 | #include "../hasher.hpp" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace cthash::sha2 { 11 | 12 | template [[gnu::always_inline]] constexpr auto choice(T e, T f, T g) noexcept -> T { 13 | return (e bitand f) xor (~e bitand g); 14 | } 15 | 16 | template [[gnu::always_inline]] constexpr auto majority(T a, T b, T c) noexcept -> T { 17 | return (a bitand b) xor (a bitand c) xor (b bitand c); 18 | } 19 | 20 | template 21 | [[gnu::always_inline]] constexpr void rounds(std::span w, std::array & state) noexcept { 22 | using state_t = std::array; 23 | 24 | // create copy of internal state 25 | auto wvar = state_t(state); 26 | 27 | // just give them names 28 | auto & [a, b, c, d, e, f, g, h] = wvar; 29 | 30 | // number of rounds is same as constants 31 | static_assert(StageLength == Config::constants.size()); 32 | 33 | for (int i = 0; i != Config::constants.size(); ++i) { 34 | const auto temp1 = h + Config::sum_e(e) + choice(e, f, g) + Config::constants[static_cast(i)] + w[static_cast(i)]; 35 | const auto temp2 = Config::sum_a(a) + majority(a, b, c); 36 | 37 | // move around (that's rotate) 38 | std::rotate(wvar.begin(), wvar.begin() + 7u, wvar.end()); 39 | 40 | e += temp1; 41 | a = temp1 + temp2; 42 | 43 | // originally it was: 44 | // h = g; 45 | // g = f; 46 | // f = e; 47 | // e = d + temp1; 48 | // d = c; 49 | // c = b; 50 | // b = a; 51 | // a = temp1 + temp2; 52 | } 53 | 54 | // add store back 55 | for (int i = 0; i != (int)state.size(); ++i) { 56 | state[static_cast(i)] += wvar[static_cast(i)]; 57 | } 58 | } 59 | 60 | } // namespace cthash::sha2 61 | 62 | #endif -------------------------------------------------------------------------------- /include/cthash/sha2/sha224.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA2_SHA224_HPP 2 | #define CTHASH_SHA2_SHA224_HPP 3 | 4 | #include "sha256.hpp" 5 | 6 | namespace cthash { 7 | 8 | struct sha224_config: sha256_config { 9 | // these are only changes against sha256 specification... 10 | 11 | static constexpr size_t digest_length = 28u; 12 | 13 | static constexpr auto initial_values = std::array{0xc1059ed8ul, 0x367cd507ul, 0x3070dd17ul, 0xf70e5939ul, 0xffc00b31ul, 0x68581511ul, 0x64f98fa7ul, 0xbefa4fa4ul}; 14 | }; 15 | 16 | static_assert(cthash::internal::digest_length_provided); 17 | static_assert(cthash::internal::digest_bytes_length_of == 28u); 18 | 19 | using sha224 = hasher; 20 | using sha224_value = tagged_hash_value; 21 | 22 | namespace literals { 23 | 24 | template 25 | consteval auto operator""_sha224() { 26 | return sha224_value(Value); 27 | } 28 | 29 | } // namespace literals 30 | 31 | } // namespace cthash 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /include/cthash/sha2/sha256.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA2_SHA256_HPP 2 | #define CTHASH_SHA2_SHA256_HPP 3 | 4 | #include "common.hpp" 5 | 6 | namespace cthash { 7 | 8 | struct sha256_config { 9 | using length_type = uint64_t; 10 | static constexpr size_t length_size_bits = 64; 11 | 12 | static constexpr size_t block_bits = 512u; 13 | 14 | static constexpr auto initial_values = std::array{0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul}; 15 | 16 | // staging sigmas 17 | [[gnu::always_inline]] static constexpr auto sigma_0(uint32_t w_15) noexcept -> uint32_t { 18 | return std::rotr(w_15, 7u) xor std::rotr(w_15, 18u) xor (w_15 >> 3u); 19 | } 20 | 21 | [[gnu::always_inline]] static constexpr auto sigma_1(uint32_t w_2) noexcept -> uint32_t { 22 | return std::rotr(w_2, 17u) xor std::rotr(w_2, 19u) xor (w_2 >> 10u); 23 | } 24 | 25 | // rounds constants... 26 | static constexpr auto constants = std::array{ 27 | 0x428a2f98ul, 0x71374491ul, 0xb5c0fbcful, 0xe9b5dba5ul, 0x3956c25bul, 0x59f111f1ul, 0x923f82a4ul, 0xab1c5ed5ul, 28 | 0xd807aa98ul, 0x12835b01ul, 0x243185beul, 0x550c7dc3ul, 0x72be5d74ul, 0x80deb1feul, 0x9bdc06a7ul, 0xc19bf174ul, 29 | 0xe49b69c1ul, 0xefbe4786ul, 0x0fc19dc6ul, 0x240ca1ccul, 0x2de92c6ful, 0x4a7484aaul, 0x5cb0a9dcul, 0x76f988daul, 30 | 0x983e5152ul, 0xa831c66dul, 0xb00327c8ul, 0xbf597fc7ul, 0xc6e00bf3ul, 0xd5a79147ul, 0x06ca6351ul, 0x14292967ul, 31 | 0x27b70a85ul, 0x2e1b2138ul, 0x4d2c6dfcul, 0x53380d13ul, 0x650a7354ul, 0x766a0abbul, 0x81c2c92eul, 0x92722c85ul, 32 | 0xa2bfe8a1ul, 0xa81a664bul, 0xc24b8b70ul, 0xc76c51a3ul, 0xd192e819ul, 0xd6990624ul, 0xf40e3585ul, 0x106aa070ul, 33 | 0x19a4c116ul, 0x1e376c08ul, 0x2748774cul, 0x34b0bcb5ul, 0x391c0cb3ul, 0x4ed8aa4aul, 0x5b9cca4ful, 0x682e6ff3ul, 34 | 0x748f82eeul, 0x78a5636ful, 0x84c87814ul, 0x8cc70208ul, 0x90befffaul, 0xa4506cebul, 0xbef9a3f7ul, 0xc67178f2ul}; 35 | 36 | // rounds sums 37 | [[gnu::always_inline]] static constexpr auto sum_a(uint32_t a) noexcept -> uint32_t { 38 | return std::rotr(a, 2u) xor std::rotr(a, 13u) xor std::rotr(a, 22u); 39 | } 40 | 41 | [[gnu::always_inline]] static constexpr auto sum_e(uint32_t e) noexcept -> uint32_t { 42 | return std::rotr(e, 6u) xor std::rotr(e, 11u) xor std::rotr(e, 25u); 43 | } 44 | 45 | // rounds 46 | [[gnu::always_inline]] static constexpr void rounds(std::span w, std::array & state) noexcept { 47 | return sha2::rounds(w, state); 48 | } 49 | }; 50 | 51 | static_assert(not cthash::internal::digest_length_provided); 52 | static_assert(cthash::internal::digest_bytes_length_of == 32u); 53 | 54 | using sha256 = hasher; 55 | using sha256_value = tagged_hash_value; 56 | 57 | namespace literals { 58 | 59 | template 60 | consteval auto operator""_sha256() { 61 | return sha256_value(Value); 62 | } 63 | 64 | } // namespace literals 65 | 66 | } // namespace cthash 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /include/cthash/sha2/sha384.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA2_SHA384_HPP 2 | #define CTHASH_SHA2_SHA384_HPP 3 | 4 | #include "sha512.hpp" 5 | 6 | namespace cthash { 7 | 8 | struct sha384_config: sha512_config { 9 | static constexpr size_t digest_length = 48u; 10 | 11 | static constexpr auto initial_values = std::array{0xcbbb9d5dc1059ed8ull, 0x629a292a367cd507ull, 0x9159015a3070dd17ull, 0x152fecd8f70e5939ull, 0x67332667ffc00b31ull, 0x8eb44a8768581511ull, 0xdb0c2e0d64f98fa7ull, 0x47b5481dbefa4fa4ull}; 12 | }; 13 | 14 | static_assert(cthash::internal::digest_length_provided); 15 | static_assert(cthash::internal::digest_bytes_length_of == 48u); 16 | 17 | using sha384 = hasher; 18 | using sha384_value = tagged_hash_value; 19 | 20 | namespace literals { 21 | 22 | template 23 | consteval auto operator""_sha384() { 24 | return sha384_value(Value); 25 | } 26 | 27 | } // namespace literals 28 | 29 | } // namespace cthash 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/cthash/sha2/sha512.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA2_SHA512_HPP 2 | #define CTHASH_SHA2_SHA512_HPP 3 | 4 | #include "common.hpp" 5 | 6 | namespace cthash { 7 | 8 | struct sha512_config { 9 | using length_type = uint64_t; 10 | static constexpr size_t length_size_bits = 128; 11 | 12 | static constexpr size_t block_bits = 1024u; 13 | 14 | static constexpr auto initial_values = std::array{0x6a09e667f3bcc908ull, 0xbb67ae8584caa73bull, 0x3c6ef372fe94f82bull, 0xa54ff53a5f1d36f1ull, 0x510e527fade682d1ull, 0x9b05688c2b3e6c1full, 0x1f83d9abfb41bd6bull, 0x5be0cd19137e2179ull}; 15 | 16 | // staging functions 17 | [[gnu::always_inline]] static constexpr auto sigma_0(uint64_t w_15) noexcept -> uint64_t { 18 | return std::rotr(w_15, 1u) xor std::rotr(w_15, 8u) xor (w_15 >> 7u); 19 | } 20 | 21 | [[gnu::always_inline]] static constexpr auto sigma_1(uint64_t w_2) noexcept -> uint64_t { 22 | return std::rotr(w_2, 19u) xor std::rotr(w_2, 61u) xor (w_2 >> 6u); 23 | } 24 | 25 | // rounds constants... 26 | static constexpr auto constants = std::array{ 27 | 0x428a2f98d728ae22ull, 0x7137449123ef65cdull, 0xb5c0fbcfec4d3b2full, 0xe9b5dba58189dbbcull, 0x3956c25bf348b538ull, 28 | 0x59f111f1b605d019ull, 0x923f82a4af194f9bull, 0xab1c5ed5da6d8118ull, 0xd807aa98a3030242ull, 0x12835b0145706fbeull, 29 | 0x243185be4ee4b28cull, 0x550c7dc3d5ffb4e2ull, 0x72be5d74f27b896full, 0x80deb1fe3b1696b1ull, 0x9bdc06a725c71235ull, 30 | 0xc19bf174cf692694ull, 0xe49b69c19ef14ad2ull, 0xefbe4786384f25e3ull, 0x0fc19dc68b8cd5b5ull, 0x240ca1cc77ac9c65ull, 31 | 0x2de92c6f592b0275ull, 0x4a7484aa6ea6e483ull, 0x5cb0a9dcbd41fbd4ull, 0x76f988da831153b5ull, 0x983e5152ee66dfabull, 32 | 0xa831c66d2db43210ull, 0xb00327c898fb213full, 0xbf597fc7beef0ee4ull, 0xc6e00bf33da88fc2ull, 0xd5a79147930aa725ull, 33 | 0x06ca6351e003826full, 0x142929670a0e6e70ull, 0x27b70a8546d22ffcull, 0x2e1b21385c26c926ull, 0x4d2c6dfc5ac42aedull, 34 | 0x53380d139d95b3dfull, 0x650a73548baf63deull, 0x766a0abb3c77b2a8ull, 0x81c2c92e47edaee6ull, 0x92722c851482353bull, 35 | 0xa2bfe8a14cf10364ull, 0xa81a664bbc423001ull, 0xc24b8b70d0f89791ull, 0xc76c51a30654be30ull, 0xd192e819d6ef5218ull, 36 | 0xd69906245565a910ull, 0xf40e35855771202aull, 0x106aa07032bbd1b8ull, 0x19a4c116b8d2d0c8ull, 0x1e376c085141ab53ull, 37 | 0x2748774cdf8eeb99ull, 0x34b0bcb5e19b48a8ull, 0x391c0cb3c5c95a63ull, 0x4ed8aa4ae3418acbull, 0x5b9cca4f7763e373ull, 38 | 0x682e6ff3d6b2b8a3ull, 0x748f82ee5defb2fcull, 0x78a5636f43172f60ull, 0x84c87814a1f0ab72ull, 0x8cc702081a6439ecull, 39 | 0x90befffa23631e28ull, 0xa4506cebde82bde9ull, 0xbef9a3f7b2c67915ull, 0xc67178f2e372532bull, 0xca273eceea26619cull, 40 | 0xd186b8c721c0c207ull, 0xeada7dd6cde0eb1eull, 0xf57d4f7fee6ed178ull, 0x06f067aa72176fbaull, 0x0a637dc5a2c898a6ull, 41 | 0x113f9804bef90daeull, 0x1b710b35131c471bull, 0x28db77f523047d84ull, 0x32caab7b40c72493ull, 0x3c9ebe0a15c9bebcull, 42 | 0x431d67c49c100d4cull, 0x4cc5d4becb3e42b6ull, 0x597f299cfc657e2aull, 0x5fcb6fab3ad6faecull, 0x6c44198c4a475817ull}; 43 | 44 | [[gnu::always_inline]] static constexpr auto sum_a(uint64_t a) noexcept -> uint64_t { 45 | return std::rotr(a, 28u) xor std::rotr(a, 34u) xor std::rotr(a, 39u); 46 | } 47 | 48 | [[gnu::always_inline]] static constexpr auto sum_e(uint64_t e) noexcept -> uint64_t { 49 | return std::rotr(e, 14u) xor std::rotr(e, 18u) xor std::rotr(e, 41u); 50 | } 51 | 52 | // rounds 53 | [[gnu::always_inline]] static constexpr void rounds(std::span w, std::array & state) noexcept { 54 | return sha2::rounds(w, state); 55 | } 56 | }; 57 | 58 | static_assert(not cthash::internal::digest_length_provided); 59 | static_assert(cthash::internal::digest_bytes_length_of == 64u); 60 | 61 | using sha512 = hasher; 62 | using sha512_value = tagged_hash_value; 63 | 64 | namespace literals { 65 | 66 | template 67 | consteval auto operator""_sha512() { 68 | return sha512_value(Value); 69 | } 70 | 71 | } // namespace literals 72 | 73 | } // namespace cthash 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /include/cthash/sha2/sha512/t.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA2_SHA512_T_HPP 2 | #define CTHASH_SHA2_SHA512_T_HPP 3 | 4 | #include "../sha512.hpp" 5 | 6 | namespace cthash { 7 | 8 | namespace sha256t_support { 9 | 10 | static consteval size_t width_of_decimal(unsigned t) { 11 | if (t < 10u) { 12 | return 1u; 13 | } else if (t < 100u) { 14 | return 2u; 15 | } else if (t < 1000u) { 16 | return 3u; 17 | } else { 18 | throw "we don't support more than three digits!"; 19 | } 20 | } 21 | 22 | template static consteval auto generate_signature(unsigned t) { 23 | const char a = '0' + static_cast((t / 100u) % 10u); 24 | const char b = '0' + static_cast((t / 10u) % 10u); 25 | const char c = '0' + static_cast((t / 1u) % 10u); 26 | 27 | if constexpr (Width == 1) { 28 | return std::array{'S', 'H', 'A', '-', '5', '1', '2', '/', c}; 29 | } else if constexpr (Width == 2) { 30 | return std::array{'S', 'H', 'A', '-', '5', '1', '2', '/', b, c}; 31 | } else if constexpr (Width == 3) { 32 | return std::array{'S', 'H', 'A', '-', '5', '1', '2', '/', a, b, c}; 33 | } else { 34 | throw "we don't support greater width than 3"; 35 | } 36 | } 37 | 38 | } // namespace sha256t_support 39 | 40 | static consteval auto calculate_sha512t_iv(std::span in) { 41 | auto sha512hasher = internal_hasher{}; 42 | 43 | // modify IV 44 | for (auto & val: sha512hasher.hash) { 45 | val = val xor 0xa5a5a5a5a5a5a5a5ull; 46 | } 47 | 48 | sha512hasher.update_to_buffer_and_process(in); 49 | sha512hasher.finalize(); 50 | return sha512hasher.hash; 51 | } 52 | 53 | template constexpr auto signature_for_sha512t = sha256t_support::generate_signature(T); 54 | template constexpr auto iv_for_sha512t = calculate_sha512t_iv(signature_for_sha512t); 55 | 56 | template struct sha512t_config: sha512_config { 57 | static_assert(T % 8u == 0u, "only hashes aligned to bytes are supported"); 58 | static_assert(T != 384u, "sha-512/384 is not allowed, use sha-384 instead"); 59 | static_assert(T <= 512u, "T can't be larger than 512"); 60 | static_assert(T != 0u, "T can't be zero"); 61 | 62 | static constexpr size_t digest_length = T / 8u; 63 | 64 | static constexpr std::array initial_values = iv_for_sha512t; 65 | }; 66 | 67 | static_assert(cthash::internal::digest_length_provided>); 68 | static_assert(cthash::internal::digest_length_provided>); 69 | static_assert(cthash::internal::digest_bytes_length_of> == 28u); 70 | static_assert(cthash::internal::digest_bytes_length_of> == 32u); 71 | 72 | template using sha512t = hasher>; 73 | template using sha512t_value = tagged_hash_value>; 74 | 75 | namespace literals { 76 | 77 | template 78 | consteval auto operator""_sha512_224() { 79 | return sha512t_value<224>(Value); 80 | } 81 | 82 | template 83 | consteval auto operator""_sha512_256() { 84 | return sha512t_value<256>(Value); 85 | } 86 | 87 | } // namespace literals 88 | 89 | } // namespace cthash 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /include/cthash/sha3/keccak.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA3_KECCAK_HPP 2 | #define CTHASH_SHA3_KECCAK_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace cthash::keccak { 13 | 14 | // inspired by tiny-keccak (https://github.com/debris/tiny-keccak from Marek Kotewicz) 15 | 16 | static constexpr auto rho = std::array{1u, 3u, 6u, 10u, 15u, 21u, 28u, 36u, 45u, 55u, 2u, 14u, 27u, 41u, 56u, 8u, 25u, 43u, 62u, 18u, 39u, 61u, 20u, 44u}; 17 | 18 | static constexpr auto pi = std::array{10u, 7u, 11u, 17u, 18u, 3u, 5u, 16u, 8u, 21u, 24u, 4u, 15u, 23u, 19u, 13u, 12u, 2u, 20u, 14u, 22u, 9u, 6u, 1u}; 19 | 20 | static constexpr auto rc = std::array{0x1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; 21 | 22 | struct state_1600: std::array { }; 23 | 24 | struct state_1600_ref: std::span { 25 | using super = std::span; 26 | using super::super; 27 | }; 28 | 29 | [[gnu::always_inline, gnu::flatten]] constexpr void theta(state_1600_ref state) noexcept { 30 | // xor of columns 31 | const auto b = std::array{ 32 | state[0] xor state[5] xor state[10] xor state[15] xor state[20], 33 | state[1] xor state[6] xor state[11] xor state[16] xor state[21], 34 | state[2] xor state[7] xor state[12] xor state[17] xor state[22], 35 | state[3] xor state[8] xor state[13] xor state[18] xor state[23], 36 | state[4] xor state[9] xor state[14] xor state[19] xor state[24], 37 | }; 38 | 39 | const auto tmp = std::array{ 40 | b[4] xor std::rotl(b[1], 1), 41 | b[0] xor std::rotl(b[2], 1), 42 | b[1] xor std::rotl(b[3], 1), 43 | b[2] xor std::rotl(b[4], 1), 44 | b[3] xor std::rotl(b[0], 1), 45 | }; 46 | 47 | [&](std::index_sequence) { 48 | ((state[Idx] ^= tmp[Idx % 5u]), ...); 49 | }(std::make_index_sequence<25>()); 50 | } 51 | 52 | [[gnu::always_inline, gnu::flatten]] constexpr void rho_pi(state_1600_ref state) noexcept { 53 | uint64_t tmp = state[1]; 54 | 55 | [&](std::index_sequence) { 56 | ((state[pi[Idx]] = std::rotl(std::exchange(tmp, state[pi[Idx]]), rho[Idx])), ...); 57 | }(std::make_index_sequence<24>()); 58 | } 59 | 60 | [[gnu::always_inline, gnu::flatten]] constexpr void chi(state_1600_ref state) noexcept { 61 | constexpr auto chi_helper = [](std::span row) { 62 | const auto b = std::array{row[0], row[1], row[2], row[3], row[4]}; 63 | 64 | row[0] = b[0] xor ((~b[1]) bitand b[2]); 65 | row[1] = b[1] xor ((~b[2]) bitand b[3]); 66 | row[2] = b[2] xor ((~b[3]) bitand b[4]); 67 | row[3] = b[3] xor ((~b[4]) bitand b[0]); 68 | row[4] = b[4] xor ((~b[0]) bitand b[1]); 69 | }; 70 | 71 | chi_helper(state.subspan<0>().first<5>()); 72 | chi_helper(state.subspan<5>().first<5>()); 73 | chi_helper(state.subspan<10>().first<5>()); 74 | chi_helper(state.subspan<15>().first<5>()); 75 | chi_helper(state.subspan<20>().first<5>()); 76 | } 77 | 78 | [[gnu::flatten]] constexpr void keccak_f(state_1600 & state) noexcept { 79 | // rounds 80 | for (int i = 0; i != 24; ++i) { 81 | // theta (xor each column together) 82 | theta(state); 83 | rho_pi(state); 84 | chi(state); 85 | state[0] ^= rc[static_cast(i)]; 86 | } 87 | } 88 | 89 | } // namespace cthash::keccak 90 | 91 | #endif -------------------------------------------------------------------------------- /include/cthash/sha3/sha3-224.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA3_SHA3_224_HPP 2 | #define CTHASH_SHA3_SHA3_224_HPP 3 | 4 | #include "common.hpp" 5 | 6 | namespace cthash { 7 | 8 | struct sha3_224_config { 9 | static constexpr size_t digest_length_bit = 224u; 10 | static constexpr size_t capacity_bit = digest_length_bit * 2u; 11 | static constexpr size_t rate_bit = 1600u - capacity_bit; 12 | 13 | static constexpr auto suffix = keccak_suffix(2, 0b0000'0010u); // in reverse 14 | }; 15 | 16 | static_assert((sha3_224_config::capacity_bit + sha3_224_config::rate_bit) == 1600u); 17 | 18 | using sha3_224 = cthash::keccak_hasher; 19 | using sha3_224_value = tagged_hash_value; 20 | 21 | namespace literals { 22 | 23 | template 24 | consteval auto operator""_sha3_224() { 25 | return sha3_224_value(Value); 26 | } 27 | 28 | } // namespace literals 29 | 30 | } // namespace cthash 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/cthash/sha3/sha3-256.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA3_SHA3_256_HPP 2 | #define CTHASH_SHA3_SHA3_256_HPP 3 | 4 | #include "common.hpp" 5 | 6 | namespace cthash { 7 | 8 | struct sha3_256_config { 9 | static constexpr size_t digest_length_bit = 256u; 10 | static constexpr size_t capacity_bit = digest_length_bit * 2u; 11 | static constexpr size_t rate_bit = 1600u - capacity_bit; 12 | 13 | static constexpr auto suffix = keccak_suffix(2, 0b0000'0010u); // in reverse 14 | }; 15 | 16 | static_assert((sha3_256_config::capacity_bit + sha3_256_config::rate_bit) == 1600u); 17 | 18 | using sha3_256 = cthash::keccak_hasher; 19 | using sha3_256_value = tagged_hash_value; 20 | 21 | namespace literals { 22 | 23 | template 24 | consteval auto operator""_sha3_256() { 25 | return sha3_256_value(Value); 26 | } 27 | 28 | } // namespace literals 29 | 30 | } // namespace cthash 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/cthash/sha3/sha3-384.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA3_SHA3_384_HPP 2 | #define CTHASH_SHA3_SHA3_384_HPP 3 | 4 | #include "common.hpp" 5 | 6 | namespace cthash { 7 | 8 | struct sha3_384_config { 9 | static constexpr size_t digest_length_bit = 384u; 10 | static constexpr size_t capacity_bit = digest_length_bit * 2u; 11 | static constexpr size_t rate_bit = 1600u - capacity_bit; 12 | 13 | static constexpr auto suffix = keccak_suffix(2, 0b0000'0010u); // in reverse 14 | }; 15 | 16 | static_assert((sha3_384_config::capacity_bit + sha3_384_config::rate_bit) == 1600u); 17 | 18 | using sha3_384 = cthash::keccak_hasher; 19 | using sha3_384_value = tagged_hash_value; 20 | 21 | namespace literals { 22 | 23 | template 24 | consteval auto operator""_sha3_384() { 25 | return sha3_384_value(Value); 26 | } 27 | 28 | } // namespace literals 29 | 30 | } // namespace cthash 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/cthash/sha3/sha3-512.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA3_SHA3_512_HPP 2 | #define CTHASH_SHA3_SHA3_512_HPP 3 | 4 | #include "common.hpp" 5 | 6 | namespace cthash { 7 | 8 | struct sha3_512_config { 9 | static constexpr size_t digest_length_bit = 512u; 10 | static constexpr size_t capacity_bit = digest_length_bit * 2u; 11 | static constexpr size_t rate_bit = 1600u - capacity_bit; 12 | 13 | static constexpr auto suffix = keccak_suffix(2, 0b0000'0010u); // in reverse 14 | }; 15 | 16 | static_assert((sha3_512_config::capacity_bit + sha3_512_config::rate_bit) == 1600u); 17 | 18 | using sha3_512 = cthash::keccak_hasher; 19 | using sha3_512_value = tagged_hash_value; 20 | 21 | namespace literals { 22 | 23 | template 24 | consteval auto operator""_sha3_512() { 25 | return sha3_512_value(Value); 26 | } 27 | 28 | } // namespace literals 29 | 30 | } // namespace cthash 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/cthash/sha3/shake128.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA3_SHAKE128_HPP 2 | #define CTHASH_SHA3_SHAKE128_HPP 3 | 4 | #include "common.hpp" 5 | 6 | namespace cthash { 7 | 8 | template struct shake128_value; 9 | 10 | struct shake128_config { 11 | template using variable_digest = shake128_value; 12 | 13 | static constexpr size_t digest_length_bit = 0; 14 | 15 | static constexpr size_t capacity_bit = 256; 16 | static constexpr size_t rate_bit = 1344; 17 | 18 | static constexpr auto suffix = keccak_suffix(4, 0b0000'1111u); // in reverse 19 | }; 20 | 21 | static_assert((shake128_config::capacity_bit + shake128_config::rate_bit) == 1600u); 22 | 23 | using shake128 = cthash::keccak_hasher; 24 | 25 | template struct shake128_value: tagged_hash_value> { 26 | static_assert(N > 0); 27 | using super = tagged_hash_value>; 28 | using super::super; 29 | 30 | template explicit constexpr shake128_value(const fixed_string & in) noexcept: super{in} { } 31 | 32 | template constexpr friend bool operator==(const shake128_value & lhs, const shake128_value & rhs) noexcept { 33 | static_assert(K > 0); 34 | constexpr auto smallest_n = std::min(N, K); 35 | const auto lhs_view = std::span(lhs.data(), smallest_n / 8u); 36 | const auto rhs_view = std::span(rhs.data(), smallest_n / 8u); 37 | return std::equal(lhs_view.begin(), lhs_view.end(), rhs_view.begin()); 38 | } 39 | 40 | template constexpr friend auto operator<=>(const shake128_value & lhs, const shake128_value & rhs) noexcept { 41 | static_assert(K > 0); 42 | constexpr auto smallest_n = std::min(N, K); 43 | return internal::threeway_compare_of_same_size(lhs.data(), rhs.data(), smallest_n / 8u); 44 | } 45 | }; 46 | 47 | template 48 | requires(N % 2 == 0) 49 | shake128_value(const fixed_string &) -> shake128_value; 50 | 51 | namespace literals { 52 | 53 | template 54 | consteval auto operator""_shake128() { 55 | return shake128_value(Value); 56 | } 57 | 58 | } // namespace literals 59 | 60 | } // namespace cthash 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /include/cthash/sha3/shake256.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SHA3_SHAKE256_HPP 2 | #define CTHASH_SHA3_SHAKE256_HPP 3 | 4 | #include "common.hpp" 5 | 6 | namespace cthash { 7 | 8 | template struct shake256_value; 9 | 10 | struct shake256_config { 11 | template using variable_digest = shake256_value; 12 | 13 | static constexpr size_t digest_length_bit = 0; 14 | 15 | static constexpr size_t capacity_bit = 512; 16 | static constexpr size_t rate_bit = 1088; 17 | 18 | static constexpr auto suffix = keccak_suffix(4, 0b0000'1111u); // in reverse 19 | }; 20 | 21 | static_assert((shake256_config::capacity_bit + shake256_config::rate_bit) == 1600u); 22 | 23 | using shake256 = cthash::keccak_hasher; 24 | 25 | template struct shake256_value: tagged_hash_value> { 26 | static_assert(N > 0); 27 | using super = tagged_hash_value>; 28 | using super::super; 29 | 30 | template explicit constexpr shake256_value(const fixed_string & in) noexcept: super{in} { } 31 | 32 | template constexpr friend bool operator==(const shake256_value & lhs, const shake256_value & rhs) noexcept { 33 | constexpr auto smallest_n = std::min(N, K); 34 | const auto lhs_view = std::span(lhs.data(), smallest_n / 8u); 35 | const auto rhs_view = std::span(rhs.data(), smallest_n / 8u); 36 | return std::equal(lhs_view.begin(), lhs_view.end(), rhs_view.begin()); 37 | } 38 | 39 | template constexpr friend auto operator<=>(const shake256_value & lhs, const shake256_value & rhs) noexcept { 40 | constexpr auto smallest_n = std::min(N, K); 41 | return internal::threeway_compare_of_same_size(lhs.data(), rhs.data(), smallest_n / 8u); 42 | } 43 | }; 44 | 45 | template 46 | requires(N % 2 == 0) 47 | shake256_value(const fixed_string &) -> shake256_value; 48 | 49 | namespace literals { 50 | 51 | template 52 | consteval auto operator""_shake256() { 53 | return shake256_value(Value); 54 | } 55 | 56 | } // namespace literals 57 | 58 | } // namespace cthash 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /include/cthash/simple.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_SIMPLE_HPP 2 | #define CTHASH_SIMPLE_HPP 3 | 4 | #include 5 | 6 | namespace cthash { 7 | 8 | template concept hasher_like = requires(Hasher & h, const In & in, Args &&... args) // 9 | { 10 | { Hasher{std::forward(args)...} }; 11 | { h.update(in) } -> std::same_as; 12 | { h.final() }; 13 | }; 14 | 15 | template concept direct_hasher = requires(Hasher & h, const In & in) // 16 | { 17 | { h.update_and_final(in) }; 18 | }; 19 | 20 | template 21 | requires hasher_like 22 | constexpr auto simple(const T & value, Args &&... args) noexcept { 23 | if constexpr (direct_hasher) { 24 | return Hasher{std::forward(args)...}.update_and_final(value); 25 | } else { 26 | return Hasher{std::forward(args)...}.update(value).final(); 27 | } 28 | } 29 | 30 | } // namespace cthash 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/cthash/value.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_VALUE_HPP 2 | #define CTHASH_VALUE_HPP 3 | 4 | #include "fixed-string.hpp" 5 | #include "encoding/base.hpp" 6 | #include "encoding/encodings.hpp" 7 | #include "internal/algorithm.hpp" 8 | #include "internal/deduce.hpp" 9 | #include "internal/hexdec.hpp" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace cthash { 18 | 19 | // hash_value 20 | 21 | template struct hash_value: std::array { 22 | using super = std::array; 23 | 24 | constexpr hash_value() noexcept: super{} { } 25 | explicit constexpr hash_value(super && s) noexcept: super(s) { } 26 | template explicit constexpr hash_value(const CharT (&in)[N * 2u + 1u]) noexcept: super{internal::hexdec_to_binary(std::span(in, N * 2u))} { } 27 | template explicit constexpr hash_value(const fixed_string & in) noexcept: super{internal::hexdec_to_binary(std::span(in.data(), in.size()))} { } 28 | 29 | // comparison support 30 | constexpr friend bool operator==(const hash_value & lhs, const hash_value & rhs) noexcept = default; 31 | constexpr friend auto operator<=>(const hash_value & lhs, const hash_value & rhs) noexcept -> std::strong_ordering { 32 | return internal::threeway_compare_of_same_size(lhs.data(), rhs.data(), N); 33 | } 34 | 35 | template constexpr auto & print_into(std::basic_ostream & os) const { 36 | auto hexdec_view = *this | cthash::encode_to; 37 | std::ranges::copy(hexdec_view, std::ostream_iterator(os)); 38 | return os; 39 | } 40 | 41 | // print to ostream support 42 | template constexpr friend auto & operator<<(std::basic_ostream & os, const hash_value & val) { 43 | return val.print_into(os); 44 | } 45 | 46 | template constexpr auto prefix() const noexcept requires(PrefixN <= N) { 47 | hash_value output{}; 48 | std::ranges::copy(this->begin(), this->begin() + PrefixN, output.begin()); 49 | return output; 50 | } 51 | 52 | template constexpr auto suffix() const noexcept requires(SuffixN <= N) { 53 | hash_value output{}; 54 | std::ranges::copy(this->end() - SuffixN, this->end(), output.begin()); 55 | return output; 56 | } 57 | template constexpr friend auto to_string(const hash_value & value) { 58 | const auto encoded = value | cthash::encode_to; 59 | #if __cpp_lib_ranges_to_container >= 202202L 60 | return std::ranges::to>(encoded); 61 | #else 62 | auto result = std::basic_string{}; 63 | result.resize(encoded.size()); 64 | auto [i, o] = std::ranges::copy(encoded.begin(), encoded.end(), result.begin()); 65 | assert(i == encoded.end()); 66 | assert(o == result.end()); 67 | return result; 68 | #endif 69 | } 70 | template constexpr friend auto to_fixed_string(const hash_value & value) { 71 | const auto encoded = value | cthash::encode_to; 72 | // it's type dependendent so we can calculate the size... 73 | constexpr size_t size_needed = (hash_value{} | cthash::encode_to).size(); 74 | 75 | auto result = cthash::fixed_string{nullptr}; 76 | 77 | auto [i, o] = std::ranges::copy(encoded.begin(), encoded.end(), result.begin()); 78 | assert(i == encoded.end()); 79 | assert(o == result.end()); 80 | 81 | return result; 82 | } 83 | }; 84 | 85 | template hash_value(const CharT (&)[N]) -> hash_value<(N - 1u) / 2u>; 86 | template hash_value(std::span) -> hash_value; 87 | template hash_value(const fixed_string &) -> hash_value; 88 | 89 | template struct default_encoding { 90 | using encoding = cthash::encoding::hexdec; 91 | }; 92 | 93 | template concept tag_with_encoding = requires() { 94 | typename Tag::encoding; 95 | }; 96 | 97 | template struct default_encoding { 98 | using encoding = Tag::encoding; 99 | }; 100 | 101 | template > struct tagged_hash_value: hash_value> { 102 | static constexpr size_t N = internal::digest_bytes_length_of; 103 | 104 | using super = hash_value; 105 | using super::super; 106 | template explicit constexpr tagged_hash_value(const fixed_string & in) noexcept: super{in} { } 107 | 108 | static constexpr size_t digest_length = N; 109 | 110 | template ::encoding, typename CharT, typename Traits> constexpr auto & print_into(std::basic_ostream & os) const { 111 | return super::template print_into(os); 112 | } 113 | 114 | template constexpr friend auto & operator<<(std::basic_ostream & os, const tagged_hash_value & val) { 115 | return val.print_into(os); 116 | } 117 | 118 | template ::encoding, typename CharT = char> constexpr friend auto to_string(const tagged_hash_value & value) { 119 | return to_string(static_cast(value)); 120 | } 121 | 122 | template ::encoding, typename CharT = char> constexpr friend auto to_fixed_string(const tagged_hash_value & value) { 123 | return to_fixed_string(static_cast(value)); 124 | } 125 | }; 126 | 127 | template concept variable_digest_length = T::digest_length_bit == 0u; 128 | 129 | template struct variable_bit_length_tag: Tag { 130 | static constexpr size_t digest_length_bit = N; 131 | }; 132 | 133 | template concept convertible_to_tagged_hash_value = requires(const T & obj) { 134 | { tagged_hash_value{obj} }; 135 | }; 136 | 137 | namespace literals { 138 | 139 | template 140 | constexpr auto operator""_hash() { 141 | return hash_value(Value); 142 | } 143 | 144 | } // namespace literals 145 | 146 | } // namespace cthash 147 | 148 | namespace std { 149 | 150 | #if __cpp_lib_format >= 201907L 151 | #define CTHASH_STDFMT_AVAILABLE 1 152 | #endif 153 | 154 | #if _LIBCPP_VERSION >= 170000 155 | // libc++ will define __cpp_lib_format macro in 19.0 156 | // https://github.com/llvm/llvm-project/issues/77773 157 | #define CTHASH_STDFMT_AVAILABLE 1 158 | #endif 159 | 160 | #ifdef CTHASH_STDFMT_AVAILABLE 161 | template 162 | struct formatter, CharT> { 163 | using subject_type = cthash::hash_value; 164 | using default_encoding = cthash::encoding::hexdec; 165 | 166 | cthash::runtime_encoding encoding{default_encoding{}}; 167 | 168 | template constexpr auto parse(ParseContext & ctx) { 169 | auto [enc, out] = cthash::select_encoding(ctx); 170 | this->encoding = enc; 171 | return out; 172 | } 173 | 174 | template constexpr auto format(const subject_type & value, FormatContext & ctx) const { 175 | return encoding.visit([&](SelectedEncoding) { 176 | return std::ranges::copy(value | cthash::encode_to, ctx.out()).out; 177 | }); 178 | } 179 | }; 180 | 181 | template 182 | struct formatter, CharT> { 183 | using subject_type = cthash::tagged_hash_value; 184 | using default_encoding = typename cthash::default_encoding::encoding; 185 | 186 | cthash::runtime_encoding encoding{default_encoding{}}; 187 | 188 | template constexpr auto parse(ParseContext & ctx) { 189 | auto [enc, out] = cthash::select_encoding(ctx); 190 | this->encoding = enc; 191 | return out; 192 | } 193 | 194 | template constexpr auto format(const subject_type & value, FormatContext & ctx) const { 195 | return encoding.visit([&](SelectedEncoding) { 196 | return std::ranges::copy(value | cthash::encode_to, ctx.out()).out; 197 | }); 198 | } 199 | }; 200 | 201 | template struct formatter: formatter()}), CharT> { 202 | }; 203 | 204 | #endif 205 | 206 | } // namespace std 207 | 208 | #endif 209 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Catch2 3 REQUIRED) 2 | 3 | 4 | add_executable(test-runner 5 | benchmark/sha3-256.cpp 6 | benchmark/sha512.cpp 7 | benchmark/sha256.cpp 8 | sha2/sha512.cpp 9 | sha2/sha256.cpp 10 | sha2/sha512t.cpp 11 | sha2/sha384.cpp 12 | sha2/sha224.cpp 13 | sha3/sha3-384.cpp 14 | sha3/sha3-224.cpp 15 | sha3/sha3-256.cpp 16 | sha3/shake256.cpp 17 | sha3/shake128.cpp 18 | sha3/sha3-512.cpp 19 | sha3/xor-overwrite.cpp 20 | encoding/bit-buffer.cpp 21 | encoding/base.cpp 22 | encoding/chunk-of-bits.cpp 23 | encoding/selection.cpp 24 | value.cpp 25 | xxhash/basics.cpp 26 | keccak.cpp 27 | hexdec.cpp 28 | ) 29 | 30 | option(MEASURE_OPENSSL "Measure also OpenSSL" OFF) 31 | 32 | if (MEASURE_OPENSSL) 33 | find_package(OpenSSL COMPONENTS Crypto) 34 | if (OpenSSL_FOUND) 35 | target_link_libraries(test-runner PRIVATE OpenSSL::Crypto) 36 | target_compile_definitions(test-runner PRIVATE OPENSSL_BENCHMARK OPENSSL_SUPPRESS_DEPRECATED) 37 | endif() 38 | endif() 39 | 40 | target_link_libraries(test-runner PRIVATE Catch2::Catch2WithMain cthash) 41 | target_compile_features(test-runner PUBLIC cxx_std_20) 42 | 43 | add_custom_target(test test-runner --skip-benchmarks --colour-mode ansi "" DEPENDS test-runner) 44 | add_custom_target(long-test test-runner --skip-benchmarks --colour-mode ansi "*,[.long]" DEPENDS test-runner) 45 | add_custom_target(benchmark test-runner --colour-mode ansi "" DEPENDS test-runner) 46 | 47 | 48 | if (CTHASH_COVERAGE) 49 | coverage_report_after(test test-runner) 50 | endif() -------------------------------------------------------------------------------- /tests/benchmark/sha256.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("sha256 measurements") { 9 | std::array input{}; 10 | 11 | for (int i = 0; i != (int)input.size(); ++i) { 12 | input[static_cast(i)] = static_cast(i); 13 | } 14 | 15 | BENCHMARK("16 byte input") { 16 | return cthash::sha256{}.update(std::span(runtime_pass(input)).first(16)).final(); 17 | }; 18 | 19 | BENCHMARK("32 byte input") { 20 | return cthash::sha256{}.update(std::span(runtime_pass(input)).first(32)).final(); 21 | }; 22 | 23 | BENCHMARK("48 byte input") { 24 | return cthash::sha256{}.update(std::span(runtime_pass(input)).first(48)).final(); 25 | }; 26 | 27 | BENCHMARK("64 byte input") { 28 | return cthash::sha256{}.update(std::span(runtime_pass(input)).first(64)).final(); 29 | }; 30 | 31 | BENCHMARK("96 byte input") { 32 | return cthash::sha256{}.update(std::span(runtime_pass(input)).first(96)).final(); 33 | }; 34 | 35 | BENCHMARK("10kB input") { 36 | auto h = cthash::sha256{}; 37 | for (int i = 0; i != 10; ++i) { 38 | h.update(std::span(runtime_pass(input)).first(1024)); 39 | } 40 | return h.final(); 41 | }; 42 | 43 | BENCHMARK("1MB input") { 44 | auto h = cthash::sha256{}; 45 | for (int i = 0; i != 1024; ++i) { 46 | h.update(std::span(runtime_pass(input)).first(1024)); 47 | } 48 | return h.final(); 49 | }; 50 | 51 | BENCHMARK("10MB input") { 52 | auto h = cthash::sha256{}; 53 | for (int i = 0; i != 10 * 1024; ++i) { 54 | h.update(std::span(runtime_pass(input)).first(1024)); 55 | } 56 | return h.final(); 57 | }; 58 | } 59 | 60 | #ifdef OPENSSL_BENCHMARK 61 | 62 | #include 63 | 64 | TEST_CASE("openssl sha256 measurements") { 65 | std::array input{}; 66 | 67 | for (int i = 0; i != (int)input.size(); ++i) { 68 | input[static_cast(i)] = static_cast(i); 69 | } 70 | 71 | BENCHMARK("16 byte input") { 72 | SHA256_CTX ctx; 73 | SHA256_Init(&ctx); 74 | const auto data = std::span(runtime_pass(input)).first(16); 75 | SHA256_Update(&ctx, data.data(), data.size()); 76 | std::array res; 77 | SHA256_Final(res.data(), &ctx); 78 | return res; 79 | }; 80 | 81 | BENCHMARK("32 byte input") { 82 | SHA256_CTX ctx; 83 | SHA256_Init(&ctx); 84 | const auto data = std::span(runtime_pass(input)).first(32); 85 | SHA256_Update(&ctx, data.data(), data.size()); 86 | std::array res; 87 | SHA256_Final(res.data(), &ctx); 88 | return res; 89 | }; 90 | 91 | BENCHMARK("48 byte input") { 92 | SHA256_CTX ctx; 93 | SHA256_Init(&ctx); 94 | const auto data = std::span(runtime_pass(input)).first(48); 95 | SHA256_Update(&ctx, data.data(), data.size()); 96 | std::array res; 97 | SHA256_Final(res.data(), &ctx); 98 | return res; 99 | }; 100 | 101 | BENCHMARK("64 byte input") { 102 | SHA256_CTX ctx; 103 | SHA256_Init(&ctx); 104 | const auto data = std::span(runtime_pass(input)).first(64); 105 | SHA256_Update(&ctx, data.data(), data.size()); 106 | std::array res; 107 | SHA256_Final(res.data(), &ctx); 108 | return res; 109 | }; 110 | 111 | BENCHMARK("96 byte input") { 112 | SHA256_CTX ctx; 113 | SHA256_Init(&ctx); 114 | const auto data = std::span(runtime_pass(input)).first(96); 115 | SHA256_Update(&ctx, data.data(), data.size()); 116 | std::array res; 117 | SHA256_Final(res.data(), &ctx); 118 | return res; 119 | }; 120 | 121 | BENCHMARK("10kB input") { 122 | SHA256_CTX ctx; 123 | SHA256_Init(&ctx); 124 | 125 | for (int i = 0; i != 10; ++i) { 126 | const auto data = std::span(runtime_pass(input)).first(1024); 127 | SHA256_Update(&ctx, data.data(), data.size()); 128 | } 129 | 130 | std::array res; 131 | SHA256_Final(res.data(), &ctx); 132 | return res; 133 | }; 134 | 135 | BENCHMARK("1MB input") { 136 | SHA256_CTX ctx; 137 | SHA256_Init(&ctx); 138 | 139 | for (int i = 0; i != 1024; ++i) { 140 | const auto data = std::span(runtime_pass(input)).first(1024); 141 | SHA256_Update(&ctx, data.data(), data.size()); 142 | } 143 | 144 | std::array res; 145 | SHA256_Final(res.data(), &ctx); 146 | return res; 147 | }; 148 | 149 | BENCHMARK("10MB input") { 150 | SHA256_CTX ctx; 151 | SHA256_Init(&ctx); 152 | 153 | for (int i = 0; i != 10 * 1024; ++i) { 154 | const auto data = std::span(runtime_pass(input)).first(1024); 155 | SHA256_Update(&ctx, data.data(), data.size()); 156 | } 157 | 158 | std::array res; 159 | SHA256_Final(res.data(), &ctx); 160 | return res; 161 | }; 162 | } 163 | 164 | #endif -------------------------------------------------------------------------------- /tests/benchmark/sha3-256.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace cthash::literals; 8 | 9 | TEST_CASE("sha3-256 measurements", "[keccak-bench]") { 10 | std::array input{}; 11 | 12 | for (int i = 0; i != (int)input.size(); ++i) { 13 | input[size_t(i)] = static_cast(i); 14 | } 15 | 16 | BENCHMARK("16 byte input") { 17 | return cthash::sha3_256{}.update(std::span(runtime_pass(input)).first(16)).final(); 18 | }; 19 | 20 | BENCHMARK("32 byte input") { 21 | return cthash::sha3_256{}.update(std::span(runtime_pass(input)).first(32)).final(); 22 | }; 23 | 24 | BENCHMARK("48 byte input") { 25 | return cthash::sha3_256{}.update(std::span(runtime_pass(input)).first(48)).final(); 26 | }; 27 | 28 | BENCHMARK("64 byte input") { 29 | return cthash::sha3_256{}.update(std::span(runtime_pass(input)).first(64)).final(); 30 | }; 31 | 32 | BENCHMARK("96 byte input") { 33 | return cthash::sha3_256{}.update(std::span(runtime_pass(input)).first(96)).final(); 34 | }; 35 | 36 | BENCHMARK("10kB input") { 37 | auto h = cthash::sha3_256{}; 38 | for (int i = 0; i != 10; ++i) { 39 | h.update(std::span(runtime_pass(input)).first(1024)); 40 | } 41 | return h.final(); 42 | }; 43 | 44 | BENCHMARK("1MB input") { 45 | auto h = cthash::sha3_256{}; 46 | for (int i = 0; i != 1024; ++i) { 47 | h.update(std::span(runtime_pass(input)).first(1024)); 48 | } 49 | return h.final(); 50 | }; 51 | 52 | BENCHMARK("2MB input") { 53 | auto h = cthash::sha3_256{}; 54 | for (int i = 0; i != 2 * 1024; ++i) { 55 | h.update(std::span(runtime_pass(input)).first(1024)); 56 | } 57 | return h.final(); 58 | }; 59 | 60 | BENCHMARK("4MB input") { 61 | auto h = cthash::sha3_256{}; 62 | for (int i = 0; i != 4 * 1024; ++i) { 63 | h.update(std::span(runtime_pass(input)).first(1024)); 64 | } 65 | return h.final(); 66 | }; 67 | 68 | BENCHMARK("8MB input") { 69 | auto h = cthash::sha3_256{}; 70 | for (int i = 0; i != 8 * 1024; ++i) { 71 | h.update(std::span(runtime_pass(input)).first(1024)); 72 | } 73 | return h.final(); 74 | }; 75 | } 76 | 77 | #ifdef OPENSSL_BENCHMARK 78 | 79 | #include 80 | #include 81 | 82 | struct EVP_destroy { 83 | void operator()(EVP_MD_CTX * ptr) noexcept { 84 | EVP_MD_CTX_destroy(ptr); 85 | } 86 | }; 87 | 88 | using unique_evp_ptr = std::unique_ptr; 89 | 90 | unique_evp_ptr openssl_sha3_256_init() { 91 | const EVP_MD * algorithm = EVP_sha3_256(); 92 | REQUIRE(algorithm != nullptr); 93 | EVP_MD_CTX * context = EVP_MD_CTX_create(); 94 | EVP_DigestInit_ex(context, algorithm, nullptr); 95 | return unique_evp_ptr(context); 96 | } 97 | 98 | template void openssl_sha3_256_update(unique_evp_ptr & ctx, std::span in) { 99 | EVP_DigestUpdate(ctx.get(), in.data(), in.size()); 100 | } 101 | 102 | auto openssl_sha3_256_final(unique_evp_ptr & ctx) -> cthash::sha3_256_value { 103 | cthash::sha3_256_value out; 104 | unsigned length{0}; 105 | EVP_DigestFinal_ex(ctx.get(), reinterpret_cast(out.data()), &length); 106 | REQUIRE(size_t(length) == out.size()); 107 | return out; 108 | } 109 | 110 | TEST_CASE("check openssl first", "[openssl-test]") { 111 | using namespace std::string_view_literals; 112 | 113 | auto ctx = openssl_sha3_256_init(); 114 | openssl_sha3_256_update(ctx, std::span("hanicka"sv)); 115 | const auto res = openssl_sha3_256_final(ctx); 116 | bool correct = res == "8f8b0b8af4c371e91791b1ddb2d0788661dd687060404af6320971bcc53b44fb"_sha3_256; 117 | REQUIRE(correct); 118 | } 119 | 120 | TEST_CASE("openssl sha3-256 measurements", "[keccak-bench][openssl]") { 121 | std::array input{}; 122 | 123 | for (int i = 0; i != (int)input.size(); ++i) { 124 | input[static_cast(i)] = static_cast(i); 125 | } 126 | 127 | BENCHMARK("16 byte input") { 128 | auto ctx = openssl_sha3_256_init(); 129 | const auto data = std::span(runtime_pass(input)).first(16); 130 | openssl_sha3_256_update(ctx, data); 131 | return openssl_sha3_256_final(ctx); 132 | }; 133 | 134 | BENCHMARK("32 byte input") { 135 | auto ctx = openssl_sha3_256_init(); 136 | const auto data = std::span(runtime_pass(input)).first(32); 137 | openssl_sha3_256_update(ctx, data); 138 | return openssl_sha3_256_final(ctx); 139 | }; 140 | 141 | BENCHMARK("48 byte input") { 142 | auto ctx = openssl_sha3_256_init(); 143 | const auto data = std::span(runtime_pass(input)).first(48); 144 | openssl_sha3_256_update(ctx, data); 145 | return openssl_sha3_256_final(ctx); 146 | }; 147 | 148 | BENCHMARK("64 byte input") { 149 | auto ctx = openssl_sha3_256_init(); 150 | const auto data = std::span(runtime_pass(input)).first(64); 151 | openssl_sha3_256_update(ctx, data); 152 | return openssl_sha3_256_final(ctx); 153 | }; 154 | 155 | BENCHMARK("96 byte input") { 156 | auto ctx = openssl_sha3_256_init(); 157 | const auto data = std::span(runtime_pass(input)).first(96); 158 | openssl_sha3_256_update(ctx, data); 159 | return openssl_sha3_256_final(ctx); 160 | }; 161 | 162 | BENCHMARK("10kB input") { 163 | auto ctx = openssl_sha3_256_init(); 164 | 165 | for (int i = 0; i != 10; ++i) { 166 | const auto data = std::span(runtime_pass(input)).first(1024); 167 | openssl_sha3_256_update(ctx, data); 168 | } 169 | 170 | return openssl_sha3_256_final(ctx); 171 | }; 172 | 173 | BENCHMARK("1MB input") { 174 | auto ctx = openssl_sha3_256_init(); 175 | 176 | for (int i = 0; i != 1024; ++i) { 177 | const auto data = std::span(runtime_pass(input)).first(1024); 178 | openssl_sha3_256_update(ctx, data); 179 | } 180 | 181 | return openssl_sha3_256_final(ctx); 182 | }; 183 | 184 | BENCHMARK("2MB input") { 185 | auto ctx = openssl_sha3_256_init(); 186 | 187 | for (int i = 0; i != 2 * 1024; ++i) { 188 | const auto data = std::span(runtime_pass(input)).first(1024); 189 | openssl_sha3_256_update(ctx, data); 190 | } 191 | 192 | return openssl_sha3_256_final(ctx); 193 | }; 194 | 195 | BENCHMARK("4MB input") { 196 | auto ctx = openssl_sha3_256_init(); 197 | 198 | for (int i = 0; i != 4 * 1024; ++i) { 199 | const auto data = std::span(runtime_pass(input)).first(1024); 200 | openssl_sha3_256_update(ctx, data); 201 | } 202 | 203 | return openssl_sha3_256_final(ctx); 204 | }; 205 | 206 | BENCHMARK("8MB input") { 207 | auto ctx = openssl_sha3_256_init(); 208 | 209 | for (int i = 0; i != 8 * 1024; ++i) { 210 | const auto data = std::span(runtime_pass(input)).first(1024); 211 | openssl_sha3_256_update(ctx, data); 212 | } 213 | 214 | return openssl_sha3_256_final(ctx); 215 | }; 216 | } 217 | 218 | #endif -------------------------------------------------------------------------------- /tests/benchmark/sha512.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("sha512 measurements") { 9 | std::array input{}; 10 | 11 | for (int i = 0; i != (int)input.size(); ++i) { 12 | input[static_cast(i)] = static_cast(i); 13 | } 14 | 15 | BENCHMARK("16 byte input") { 16 | return cthash::sha512{}.update(std::span(runtime_pass(input)).first(16)).final(); 17 | }; 18 | 19 | BENCHMARK("32 byte input") { 20 | return cthash::sha512{}.update(std::span(runtime_pass(input)).first(32)).final(); 21 | }; 22 | 23 | BENCHMARK("48 byte input") { 24 | return cthash::sha512{}.update(std::span(runtime_pass(input)).first(48)).final(); 25 | }; 26 | 27 | BENCHMARK("64 byte input") { 28 | return cthash::sha512{}.update(std::span(runtime_pass(input)).first(64)).final(); 29 | }; 30 | 31 | BENCHMARK("96 byte input") { 32 | return cthash::sha512{}.update(std::span(runtime_pass(input)).first(96)).final(); 33 | }; 34 | 35 | BENCHMARK("10kB input") { 36 | auto h = cthash::sha512{}; 37 | for (int i = 0; i != 10; ++i) { 38 | h.update(std::span(runtime_pass(input)).first(1024)); 39 | } 40 | return h.final(); 41 | }; 42 | 43 | BENCHMARK("1MB input") { 44 | auto h = cthash::sha512{}; 45 | for (int i = 0; i != 1024; ++i) { 46 | h.update(std::span(runtime_pass(input)).first(1024)); 47 | } 48 | return h.final(); 49 | }; 50 | 51 | BENCHMARK("10MB input") { 52 | auto h = cthash::sha512{}; 53 | for (int i = 0; i != 10 * 1024; ++i) { 54 | h.update(std::span(runtime_pass(input)).first(1024)); 55 | } 56 | return h.final(); 57 | }; 58 | } 59 | 60 | #ifdef OPENSSL_BENCHMARK 61 | 62 | #include 63 | 64 | TEST_CASE("openssl sha512 measurements") { 65 | std::array input{}; 66 | 67 | for (int i = 0; i != (int)input.size(); ++i) { 68 | input[static_cast(i)] = static_cast(i); 69 | } 70 | 71 | BENCHMARK("16 byte input") { 72 | SHA512_CTX ctx; 73 | SHA512_Init(&ctx); 74 | const auto data = std::span(runtime_pass(input)).first(16); 75 | SHA512_Update(&ctx, data.data(), data.size()); 76 | std::array res; 77 | SHA512_Final(res.data(), &ctx); 78 | return res; 79 | }; 80 | 81 | BENCHMARK("32 byte input") { 82 | SHA512_CTX ctx; 83 | SHA512_Init(&ctx); 84 | const auto data = std::span(runtime_pass(input)).first(32); 85 | SHA512_Update(&ctx, data.data(), data.size()); 86 | std::array res; 87 | SHA512_Final(res.data(), &ctx); 88 | return res; 89 | }; 90 | 91 | BENCHMARK("48 byte input") { 92 | SHA512_CTX ctx; 93 | SHA512_Init(&ctx); 94 | const auto data = std::span(runtime_pass(input)).first(48); 95 | SHA512_Update(&ctx, data.data(), data.size()); 96 | std::array res; 97 | SHA512_Final(res.data(), &ctx); 98 | return res; 99 | }; 100 | 101 | BENCHMARK("64 byte input") { 102 | SHA512_CTX ctx; 103 | SHA512_Init(&ctx); 104 | const auto data = std::span(runtime_pass(input)).first(64); 105 | SHA512_Update(&ctx, data.data(), data.size()); 106 | std::array res; 107 | SHA512_Final(res.data(), &ctx); 108 | return res; 109 | }; 110 | 111 | BENCHMARK("96 byte input") { 112 | SHA512_CTX ctx; 113 | SHA512_Init(&ctx); 114 | const auto data = std::span(runtime_pass(input)).first(96); 115 | SHA512_Update(&ctx, data.data(), data.size()); 116 | std::array res; 117 | SHA512_Final(res.data(), &ctx); 118 | return res; 119 | }; 120 | 121 | BENCHMARK("10kB input") { 122 | SHA512_CTX ctx; 123 | SHA512_Init(&ctx); 124 | 125 | for (int i = 0; i != 10; ++i) { 126 | const auto data = std::span(runtime_pass(input)).first(1024); 127 | SHA512_Update(&ctx, data.data(), data.size()); 128 | } 129 | 130 | std::array res; 131 | SHA512_Final(res.data(), &ctx); 132 | return res; 133 | }; 134 | 135 | BENCHMARK("1MB input") { 136 | SHA512_CTX ctx; 137 | SHA512_Init(&ctx); 138 | 139 | for (int i = 0; i != 1024; ++i) { 140 | const auto data = std::span(runtime_pass(input)).first(1024); 141 | SHA512_Update(&ctx, data.data(), data.size()); 142 | } 143 | 144 | std::array res; 145 | SHA512_Final(res.data(), &ctx); 146 | return res; 147 | }; 148 | 149 | BENCHMARK("10MB input") { 150 | SHA512_CTX ctx; 151 | SHA512_Init(&ctx); 152 | 153 | for (int i = 0; i != 10 * 1024; ++i) { 154 | const auto data = std::span(runtime_pass(input)).first(1024); 155 | SHA512_Update(&ctx, data.data(), data.size()); 156 | } 157 | 158 | std::array res; 159 | SHA512_Final(res.data(), &ctx); 160 | return res; 161 | }; 162 | } 163 | 164 | #endif -------------------------------------------------------------------------------- /tests/encoding/base.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std::string_view_literals; 6 | 7 | static auto materialize(const auto & range) { 8 | using char_type = std::ranges::range_value_t; 9 | std::basic_string output; 10 | for (char_type c: range) { 11 | output += c; 12 | } 13 | 14 | std::basic_string output2; 15 | output2.resize(range.size()); 16 | auto it = output2.begin(); 17 | const auto end = output2.end(); 18 | const auto [in, out] = std::ranges::copy(range.begin(), range.end(), it); 19 | 20 | REQUIRE(out == end); 21 | REQUIRE(in == range.end()); 22 | REQUIRE(output.size() == output2.size()); 23 | REQUIRE(range.size() == output2.size()); 24 | 25 | return output2; 26 | } 27 | 28 | static auto result_size(const auto & range) { 29 | return range.size(); 30 | } 31 | 32 | template auto build_array(Args... args) { 33 | return std::array{static_cast(args)...}; 34 | } 35 | 36 | TEST_CASE("lazy base64 basics") { 37 | const auto view1 = "Man"sv | cthash::base64_encode; 38 | REQUIRE(materialize(view1) == "TWFu"); 39 | 40 | const auto view2 = "Ma"sv | cthash::base64_encode; 41 | REQUIRE(materialize(view2) == "TWE="); 42 | 43 | const auto view3 = "M"sv | cthash::base64_encode; 44 | REQUIRE(materialize(view3) == "TQ=="); 45 | 46 | const auto empty = ""sv | cthash::base64_encode; 47 | REQUIRE(materialize(empty) == ""); 48 | } 49 | 50 | TEST_CASE("bytes to base64") { 51 | const auto bytes = build_array('M', 'a', 'n'); 52 | const auto view1 = std::span(bytes) | cthash::base64_encode; 53 | 54 | REQUIRE(materialize(view1) == "TWFu"); 55 | 56 | const auto view2 = std::span(bytes).first(2) | cthash::base64_encode; 57 | REQUIRE(materialize(view2) == "TWE="); 58 | 59 | const auto view3 = std::span(bytes).first(1) | cthash::base64_encode; 60 | REQUIRE(materialize(view3) == "TQ=="); 61 | 62 | const auto empty = std::span(bytes).first(0) | cthash::base64_encode; 63 | REQUIRE(materialize(empty) == ""); 64 | } 65 | 66 | TEST_CASE("lazy base64 without padding basics") { 67 | const auto view1 = "Man"sv | cthash::base64_no_padding_encode; 68 | REQUIRE(materialize(view1) == "TWFu"); 69 | 70 | const auto view2 = "Ma"sv | cthash::base64_no_padding_encode; 71 | REQUIRE(materialize(view2) == "TWE"); 72 | 73 | const auto view3 = "M"sv | cthash::base64_no_padding_encode; 74 | REQUIRE(materialize(view3) == "TQ"); 75 | 76 | const auto empty = ""sv | cthash::base64_no_padding_encode; 77 | REQUIRE(materialize(empty) == ""); 78 | } 79 | 80 | template constexpr auto make_array(std::convertible_to auto... values) { 81 | return std::array{static_cast(values)...}; 82 | } 83 | 84 | TEST_CASE("lazy base64 value corner-cases") { 85 | const auto arr = make_array(0, 0xFFu, 0, 0xFF, 0, 0xFF); 86 | const auto view1 = arr | cthash::base64_encode; 87 | static_assert(std::input_iterator); 88 | static_assert(std::ranges::input_range); 89 | REQUIRE(materialize(view1) == "AP8A/wD/"); 90 | } 91 | 92 | TEST_CASE("lazy base64url value corner-cases") { 93 | const auto arr = make_array(0, 0xFFu, 0, 0xFF, 0, 0xFF); 94 | const auto view1 = arr | cthash::base64url_encode; 95 | static_assert(std::input_iterator); 96 | static_assert(std::ranges::input_range); 97 | REQUIRE(materialize(view1) == "AP8A_wD_"); 98 | } 99 | 100 | TEST_CASE("lazy base64 value corner-cases (construct from temporary)") { 101 | const auto view1 = make_array(0, 0xFFu, 0, 0xFF, 0, 0xFF) | cthash::base64_encode; 102 | static_assert(std::input_iterator); 103 | static_assert(std::ranges::input_range); 104 | REQUIRE(materialize(view1) == "AP8A/wD/"); 105 | } 106 | 107 | TEST_CASE("lazy base64url basics") { 108 | const auto view1 = "Man"sv | cthash::base64url_encode; 109 | REQUIRE(materialize(view1) == "TWFu"); 110 | 111 | const auto view2 = "Ma"sv | cthash::base64url_encode; 112 | REQUIRE(materialize(view2) == "TWE"); 113 | 114 | const auto view3 = "M"sv | cthash::base64url_encode; 115 | REQUIRE(materialize(view3) == "TQ"); 116 | 117 | const auto view4 = "ab~"sv | cthash::base64url_encode; 118 | REQUIRE(materialize(view4) == "YWJ-"); 119 | 120 | const auto empty = ""sv | cthash::base64url_encode; 121 | REQUIRE(materialize(empty) == ""); 122 | } 123 | 124 | TEST_CASE("lazy base32 basics") { 125 | const auto view1 = "abcde"sv | cthash::base32_encode; 126 | REQUIRE(materialize(view1) == "MFRGGZDF"); 127 | 128 | const auto view2 = "abcd"sv | cthash::base32_encode; 129 | REQUIRE(materialize(view2) == "MFRGGZA="); 130 | 131 | const auto view3 = "abc"sv | cthash::base32_encode; 132 | REQUIRE(materialize(view3) == "MFRGG==="); 133 | 134 | const auto view4 = "ab"sv | cthash::base32_encode; 135 | REQUIRE(materialize(view4) == "MFRA===="); 136 | 137 | const auto view5 = "a"sv | cthash::base32_encode; 138 | REQUIRE(materialize(view5) == "ME======"); 139 | 140 | const auto empty = ""sv | cthash::base32_encode; 141 | REQUIRE(materialize(empty) == ""); 142 | } 143 | 144 | TEST_CASE("lazy z-base32 basics") { 145 | const auto view1 = "abcde"sv | cthash::z_base32_encode; 146 | REQUIRE(materialize(view1) == "cftgg3df"); 147 | 148 | const auto view2 = "abcd"sv | cthash::z_base32_encode; 149 | REQUIRE(materialize(view2) == "cftgg3y"); 150 | 151 | const auto view3 = "abc"sv | cthash::z_base32_encode; 152 | REQUIRE(materialize(view3) == "cftgg"); 153 | 154 | const auto view4 = "ab"sv | cthash::z_base32_encode; 155 | REQUIRE(materialize(view4) == "cfty"); 156 | 157 | const auto view5 = "a"sv | cthash::z_base32_encode; 158 | REQUIRE(materialize(view5) == "cr"); 159 | 160 | const auto empty = ""sv | cthash::z_base32_encode; 161 | REQUIRE(materialize(empty) == ""); 162 | } 163 | 164 | TEST_CASE("lazy hexdec basics") { 165 | const auto view1 = "Aloha"sv | cthash::hexdec_encode; 166 | REQUIRE(materialize(view1) == 167 | "41" 168 | "6c" 169 | "6f" 170 | "68" 171 | "61"); 172 | 173 | const auto empty = ""sv | cthash::hexdec_encode; 174 | REQUIRE(materialize(empty) == ""); 175 | } 176 | 177 | TEST_CASE("lazy binary basics") { 178 | const auto view1 = "Aloha"sv | cthash::binary_encode; 179 | REQUIRE(materialize(view1) == 180 | "01000001" 181 | "01101100" 182 | "01101111" 183 | "01101000" 184 | "01100001"); 185 | 186 | const auto empty = ""sv | cthash::binary_encode; 187 | REQUIRE(materialize(empty) == ""); 188 | } 189 | -------------------------------------------------------------------------------- /tests/encoding/bit-buffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std::string_view_literals; 5 | 6 | TEST_CASE("bit_buffer(1)") { 7 | auto buffer = cthash::bit_buffer<6, 8>{}; 8 | REQUIRE(buffer.empty()); 9 | REQUIRE(buffer.has_capacity_for_push()); 10 | buffer.push(0xFFu); 11 | REQUIRE(!buffer.empty()); 12 | REQUIRE(buffer.has_bits_for_pop()); 13 | REQUIRE(buffer.size() == 1u); 14 | 15 | const auto out1 = buffer.front(); 16 | buffer.pop(); 17 | REQUIRE(out1 == 0b111111u); 18 | } 19 | 20 | TEST_CASE("bit_buffer(2)") { 21 | auto buffer = cthash::bit_buffer<6, 8>{}; 22 | REQUIRE(buffer.empty()); 23 | REQUIRE(buffer.has_capacity_for_push()); 24 | 25 | buffer.push(0xFFu); 26 | REQUIRE(buffer.size() == 1u); 27 | 28 | REQUIRE(buffer.has_bits_for_pop()); 29 | REQUIRE_FALSE(buffer.empty()); 30 | REQUIRE(buffer.has_capacity_for_push()); 31 | buffer.push(0xFFu); 32 | REQUIRE(buffer.size() == 2u); 33 | 34 | REQUIRE(buffer.has_bits_for_pop()); 35 | REQUIRE_FALSE(buffer.empty()); 36 | REQUIRE(buffer.has_capacity_for_push()); 37 | buffer.push(0xFFu); 38 | REQUIRE(buffer.size() == 4u); 39 | 40 | REQUIRE(buffer.has_bits_for_pop()); 41 | REQUIRE_FALSE(buffer.empty()); 42 | REQUIRE_FALSE(buffer.has_capacity_for_push()); 43 | 44 | const auto out1 = buffer.front(); 45 | buffer.pop(); 46 | REQUIRE(out1 == 0b111111u); 47 | 48 | const auto out2 = buffer.front(); 49 | buffer.pop(); 50 | REQUIRE(out2 == 0b111111u); 51 | 52 | const auto out3 = buffer.front(); 53 | buffer.pop(); 54 | REQUIRE(out3 == 0b111111u); 55 | 56 | const auto out4 = buffer.front(); 57 | buffer.pop(); 58 | REQUIRE(out4 == 0b111111u); 59 | 60 | REQUIRE(buffer.empty()); 61 | REQUIRE(buffer.has_capacity_for_push()); 62 | REQUIRE_FALSE(buffer.has_bits_for_pop()); 63 | } 64 | 65 | TEST_CASE("bit_buffer(3) check patterns") { 66 | auto buffer = cthash::bit_buffer<6, 8>{}; 67 | REQUIRE(buffer.capacity() == 24); // bits 68 | 69 | REQUIRE(buffer.empty()); 70 | REQUIRE(buffer.has_capacity_for_push()); 71 | REQUIRE(buffer.size() == 0u); 72 | REQUIRE(buffer.unused_size() == 3u); 73 | 74 | REQUIRE_FALSE(buffer.full()); 75 | 76 | buffer.push(0x86u); 77 | REQUIRE(buffer.unused_size() == 2u); 78 | REQUIRE(buffer.size() == 1u); 79 | REQUIRE(buffer.has_capacity_for_push()); 80 | 81 | buffer.push(0x18u); 82 | REQUIRE(buffer.unused_size() == 1u); 83 | REQUIRE(buffer.size() == 2u); 84 | REQUIRE(buffer.has_capacity_for_push()); 85 | 86 | buffer.push(0x61u); 87 | REQUIRE(buffer.unused_size() == 0u); 88 | REQUIRE(buffer.size() == 4u); 89 | 90 | REQUIRE_FALSE(buffer.empty()); 91 | REQUIRE_FALSE(buffer.has_capacity_for_push()); 92 | REQUIRE(buffer.full()); 93 | 94 | auto front_and_pop = [&] { 95 | REQUIRE_FALSE(buffer.empty()); 96 | const auto out1 = buffer.front(); 97 | buffer.pop(); 98 | return out1; 99 | }; 100 | 101 | REQUIRE(front_and_pop() == 0b100001u); 102 | REQUIRE(front_and_pop() == 0b100001u); 103 | REQUIRE(front_and_pop() == 0b100001u); 104 | REQUIRE(front_and_pop() == 0b100001u); 105 | 106 | REQUIRE(buffer.empty()); 107 | } 108 | 109 | TEST_CASE("calculating capacity for typical BASE-n") { 110 | const auto base2 = cthash::bit_buffer<1>{}; 111 | REQUIRE(base2.capacity() == 8u); 112 | REQUIRE(base2.in_capacity() == 1u); 113 | REQUIRE(base2.out_capacity() == 8u); 114 | 115 | const auto base4 = cthash::bit_buffer<2>{}; 116 | REQUIRE(base4.capacity() == 8u); 117 | REQUIRE(base4.in_capacity() == 1u); 118 | REQUIRE(base4.out_capacity() == 4u); 119 | 120 | const auto base8 = cthash::bit_buffer<3>{}; 121 | REQUIRE(base8.capacity() == 24u); 122 | REQUIRE(base8.in_capacity() == 3u); 123 | REQUIRE(base8.out_capacity() == 8u); 124 | 125 | const auto base16 = cthash::bit_buffer<4>{}; 126 | REQUIRE(base16.capacity() == 8u); 127 | REQUIRE(base16.in_capacity() == 1u); 128 | REQUIRE(base16.out_capacity() == 2u); 129 | 130 | const auto base32 = cthash::bit_buffer<5>{}; 131 | REQUIRE(base32.capacity() == 40u); 132 | REQUIRE(base32.in_capacity() == 5u); 133 | REQUIRE(base32.out_capacity() == 8u); 134 | 135 | const auto base64 = cthash::bit_buffer<6>{}; 136 | REQUIRE(base64.capacity() == 24u); 137 | REQUIRE(base64.in_capacity() == 3u); 138 | REQUIRE(base64.out_capacity() == 4u); 139 | 140 | const auto base128 = cthash::bit_buffer<7>{}; 141 | REQUIRE(base128.capacity() == 56u); 142 | REQUIRE(base128.in_capacity() == 7u); 143 | REQUIRE(base128.out_capacity() == 8u); 144 | 145 | const auto base256 = cthash::bit_buffer<8>{}; 146 | REQUIRE(base256.capacity() == 8u); 147 | REQUIRE(base256.in_capacity() == 1u); 148 | REQUIRE(base256.out_capacity() == 1u); 149 | } 150 | 151 | TEST_CASE("calculate padding for base64") { 152 | REQUIRE(cthash::calculate_padding_bit_count(0, 6, 8) == 0); 153 | REQUIRE(cthash::calculate_padding_bit_count(2, 6, 8) == 16); 154 | REQUIRE(cthash::calculate_padding_bit_count(4, 6, 8) == 8); 155 | } 156 | -------------------------------------------------------------------------------- /tests/encoding/chunk-of-bits.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std::string_view_literals; 6 | 7 | auto convert_to_vector(auto && range) { 8 | std::vector>> output{}; 9 | 10 | for (auto && value: range) { 11 | output.emplace_back(value); 12 | } 13 | 14 | return output; 15 | } 16 | 17 | template struct identify; 18 | 19 | TEST_CASE("construction from a reference") { 20 | auto x = std::array{1, 2, 3, 4}; 21 | auto v = x | cthash::chunk_of_bits<4>; 22 | REQUIRE(v.size() == 8); 23 | } 24 | 25 | TEST_CASE("construction from a const reference") { 26 | const auto x = std::array{1, 2, 3, 4}; 27 | auto v = x | cthash::chunk_of_bits<4>; 28 | REQUIRE(v.size() == 8); 29 | } 30 | 31 | TEST_CASE("construction from a temporary") { 32 | auto v = std::array{1, 2, 3, 4} | cthash::chunk_of_bits<4>; 33 | REQUIRE(v.size() == 8); 34 | } 35 | 36 | TEST_CASE("construction of chunk view (8bit => 4bit)") { 37 | const auto v = "aloha"sv | cthash::chunk_of_bits<4>; 38 | 39 | static_assert(std::input_iterator>); 40 | static_assert(std::ranges::input_range>); 41 | 42 | const auto result = convert_to_vector(v); 43 | 44 | REQUIRE(result.size() == 10u); 45 | 46 | REQUIRE(result[0].value == 0x6); 47 | REQUIRE(result[1].value == 0x1); 48 | 49 | REQUIRE(result[2].value == 0x6); 50 | REQUIRE(result[3].value == 0xC); 51 | 52 | REQUIRE(result[4].value == 0x6); 53 | REQUIRE(result[5].value == 0xF); 54 | 55 | REQUIRE(result[6].value == 0x6); 56 | REQUIRE(result[7].value == 0x8); 57 | 58 | REQUIRE(result[8].value == 0x6); 59 | REQUIRE(result[9].value == 0x1); 60 | } 61 | 62 | TEST_CASE("construction of chunk view (8bit => 6bit)") { 63 | const auto v = "Man"sv | cthash::chunk_of_bits<6>; 64 | 65 | static_assert(std::input_iterator>); 66 | static_assert(std::ranges::input_range>); 67 | 68 | const auto result = convert_to_vector(v); 69 | 70 | REQUIRE(result.size() == 4u); 71 | 72 | REQUIRE(result[0].value == 0b010011u); 73 | REQUIRE(result[1].value == 0b010110u); 74 | REQUIRE(result[2].value == 0b000101u); 75 | REQUIRE(result[3].value == 0b101110u); 76 | } 77 | 78 | TEST_CASE("construction of chunk view (8bit => 6bit, unaligned, without padding)") { 79 | const auto v = "Ma"sv | cthash::chunk_of_bits<6, false>; 80 | 81 | static_assert(std::input_iterator>); 82 | static_assert(std::ranges::input_range>); 83 | 84 | const auto result = convert_to_vector(v); 85 | 86 | auto it = result.begin(); 87 | const auto end = result.end(); 88 | 89 | REQUIRE(it != end); 90 | REQUIRE(it->value == 0b010011u); 91 | REQUIRE(it->missing_bits == 0u); 92 | ++it; 93 | 94 | REQUIRE(it != end); 95 | REQUIRE(it->value == 0b010110u); 96 | REQUIRE(it->missing_bits == 0u); 97 | ++it; 98 | 99 | REQUIRE(it != end); 100 | REQUIRE(it->value == 0b000100u); 101 | REQUIRE(it->missing_bits == 2u); 102 | ++it; 103 | 104 | REQUIRE(it == end); 105 | } 106 | 107 | TEST_CASE("construction of chunk view (8bit => 6bit, unaligned, with padding)") { 108 | const auto v = "Ma"sv | cthash::chunk_of_bits<6, true>; 109 | 110 | static_assert(std::input_iterator>); 111 | static_assert(std::ranges::input_range>); 112 | 113 | const auto result = convert_to_vector(v); 114 | 115 | auto it = result.begin(); 116 | const auto end = result.end(); 117 | 118 | REQUIRE(it != end); 119 | REQUIRE(it->value == 0b010011u); 120 | REQUIRE(it->missing_bits == 0u); 121 | ++it; 122 | 123 | REQUIRE(it != end); 124 | REQUIRE(it->value == 0b010110u); 125 | REQUIRE(it->missing_bits == 0u); 126 | ++it; 127 | 128 | REQUIRE(it != end); 129 | REQUIRE(it->value == 0b000100u); 130 | REQUIRE(it->missing_bits == 2u); 131 | ++it; 132 | 133 | REQUIRE(it != end); 134 | REQUIRE(it->value == 0b000000u); 135 | // REQUIRE(it->missing_bits == 6u); 136 | // REQUIRE(it->is_padding()); 137 | ++it; 138 | 139 | REQUIRE(it == end); 140 | } 141 | 142 | TEST_CASE("construction of chunk view (8bit => 6bit, unaligned, with padding, second)") { 143 | const auto v = "M"sv | cthash::chunk_of_bits<6, true>; 144 | 145 | static_assert(std::input_iterator>); 146 | static_assert(std::ranges::input_range>); 147 | 148 | const auto result = convert_to_vector(v); 149 | 150 | auto it = result.begin(); 151 | const auto end = result.end(); 152 | 153 | REQUIRE(it != end); 154 | REQUIRE(it->value == 0b010011u); 155 | REQUIRE(it->missing_bits == 0u); 156 | ++it; 157 | 158 | REQUIRE(it != end); 159 | REQUIRE(it->value == 0b010000u); 160 | REQUIRE(it->missing_bits == 4u); 161 | ++it; 162 | 163 | REQUIRE(it != end); 164 | REQUIRE(it->value == 0b000000u); 165 | // REQUIRE(it->missing_bits == 6u); 166 | // REQUIRE(it->is_padding()); 167 | ++it; 168 | 169 | REQUIRE(it != end); 170 | REQUIRE(it->value == 0b000000u); 171 | // REQUIRE(it->missing_bits == 6u); 172 | // REQUIRE(it->is_padding()); 173 | ++it; 174 | 175 | REQUIRE(it == end); 176 | } 177 | 178 | TEST_CASE("construction of chunk view (8bit => 6bit, unaligned, with padding, empty)") { 179 | const auto v = ""sv | cthash::chunk_of_bits<6, true>; 180 | 181 | static_assert(std::input_iterator>); 182 | static_assert(std::ranges::input_range>); 183 | 184 | const auto result = convert_to_vector(v); 185 | 186 | auto it = result.begin(); 187 | const auto end = result.end(); 188 | 189 | REQUIRE(it == end); 190 | } 191 | 192 | TEST_CASE("construction of chunk view (8bit => 1bit)") { 193 | auto arr = std::array{0xF8}; 194 | const auto v = arr | cthash::chunk_of_bits<1>; 195 | 196 | static_assert(std::input_iterator>); 197 | static_assert(std::ranges::input_range>); 198 | 199 | const auto result = convert_to_vector(v); 200 | 201 | REQUIRE(result.size() == 8u); 202 | 203 | REQUIRE(result[0].value == 0b1); 204 | REQUIRE(result[1].value == 0b1); 205 | REQUIRE(result[2].value == 0b1); 206 | REQUIRE(result[3].value == 0b1); 207 | REQUIRE(result[4].value == 0b1); 208 | REQUIRE(result[5].value == 0b0); 209 | REQUIRE(result[6].value == 0b0); 210 | REQUIRE(result[7].value == 0b0); 211 | } -------------------------------------------------------------------------------- /tests/encoding/selection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std::string_view_literals; 6 | 7 | template struct identify; 8 | 9 | template bool match_encoding(E, std::string_view expected) { 10 | return cthash::match_encoding(expected); 11 | } 12 | 13 | TEST_CASE("select hexdec encoding") { 14 | const auto enc_default = cthash::select_runtime_encoding(""sv).encoding; 15 | enc_default.visit([](E e) { 16 | INFO(E::name); 17 | REQUIRE(match_encoding(e, "base16")); 18 | }); 19 | 20 | const auto enc1 = cthash::select_runtime_encoding("hexdec"sv).encoding; 21 | enc1.visit([](E e) { 22 | REQUIRE(match_encoding(e, "hexdec")); 23 | }); 24 | 25 | const auto enc2 = cthash::select_runtime_encoding("base64"sv).encoding; 26 | enc2.visit([](E e) { 27 | INFO(E::name); 28 | REQUIRE(match_encoding(e, "base64")); 29 | }); 30 | 31 | const auto enc3 = cthash::select_runtime_encoding("base64_no_padding"sv).encoding; 32 | enc3.visit([](E e) { 33 | INFO(E::name); 34 | REQUIRE(match_encoding(e, "base64_no_padding")); 35 | }); 36 | 37 | REQUIRE_THROWS_AS(cthash::select_runtime_encoding("unexisting"sv), std::invalid_argument); 38 | } 39 | -------------------------------------------------------------------------------- /tests/hexdec.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST_CASE("hexdec basics") { 5 | constexpr auto v1 = cthash::internal::literal_hexdec_to_binary(""); 6 | REQUIRE((v1 == std::array{})); 7 | 8 | constexpr auto v2 = cthash::internal::literal_hexdec_to_binary("00"); 9 | REQUIRE((v2 == std::array{std::byte{0x00}})); 10 | 11 | constexpr auto v3 = cthash::internal::literal_hexdec_to_binary("abcdef01"); 12 | REQUIRE((v3 == std::array{std::byte{0xab}, std::byte{0xcd}, std::byte{0xef}, std::byte{0x01}})); 13 | } 14 | 15 | template decltype(auto) runtime_pass(T && val) { 16 | return val; 17 | } 18 | 19 | TEST_CASE("hexdec conversion") { 20 | auto a = cthash::internal::literal_hexdec_to_binary(runtime_pass("")); 21 | REQUIRE((a == std::array{})); 22 | 23 | auto b = cthash::internal::literal_hexdec_to_binary(runtime_pass("ab")); 24 | REQUIRE((b == std::array{std::byte{0xab}})); 25 | } -------------------------------------------------------------------------------- /tests/internal/support.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CTHASH_TESTS_INTERNAL_SUPPORT_HPP 2 | #define CTHASH_TESTS_INTERNAL_SUPPORT_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | template const auto & runtime_pass(const T & val) { 10 | return val; 11 | } 12 | 13 | template auto runtime_pass(const std::array & val) { 14 | return std::span(val.data(), val.size()); 15 | } 16 | 17 | template consteval auto array_of(T value) { 18 | std::array output; 19 | for (T & val: output) val = value; 20 | return output; 21 | } 22 | 23 | template consteval auto array_of_zeros() { 24 | return array_of(T{0}); 25 | } 26 | 27 | template constexpr auto to_sv(const std::array & in) { 28 | return std::string_view{in.data(), in.size()}; 29 | } 30 | 31 | template constexpr auto to_str(const std::array & in) { 32 | return std::string{in.data(), in.size()}; 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /tests/keccak.cpp: -------------------------------------------------------------------------------- 1 | #include "internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | TEST_CASE("keccakF") { 7 | auto s = cthash::keccak::state_1600{}; 8 | cthash::keccak::keccak_f(s); 9 | const auto expected = cthash::keccak::state_1600{ 10 | 0xf1258f7940e1dde7ull, 11 | 0x84d5ccf933c0478aull, 12 | 0xd598261ea65aa9eeull, 13 | 0xbd1547306f80494dull, 14 | 0x8b284e056253d057ull, 15 | 0xff97a42d7f8e6fd4ull, 16 | 0x90fee5a0a44647c4ull, 17 | 0x8c5bda0cd6192e76ull, 18 | 0xad30a6f71b19059cull, 19 | 0x30935ab7d08ffc64ull, 20 | 0xeb5aa93f2317d635ull, 21 | 0xa9a6e6260d712103ull, 22 | 0x81a57c16dbcf555full, 23 | 0x43b831cd0347c826ull, 24 | 0x1f22f1a11a5569full, 25 | 0x05e5635a21d9ae61ull, 26 | 0x64befef28cc970f2ull, 27 | 0x613670957bc46611ull, 28 | 0xb87c5a554fd00ecbull, 29 | 0x8c3ee88a1ccf32c8ull, 30 | 0x940c7922ae3a2614ull, 31 | 0x1841f924a2c509e4ull, 32 | 0x16f53526e70465c2ull, 33 | 0x75f644e97f30a13bull, 34 | 0xeaf1ff7b5ceca249ull, 35 | }; 36 | REQUIRE(s == expected); 37 | } 38 | -------------------------------------------------------------------------------- /tests/sha2/sha224.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("sha224 basics") { 9 | constexpr auto v1 = cthash::sha224{}.update("").final(); 10 | auto v1r = cthash::sha224{}.update(runtime_pass("")).final(); 11 | REQUIRE(v1 == "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"_sha224); 12 | REQUIRE(v1 == v1r); 13 | 14 | constexpr auto v2 = cthash::sha224{}.update("hana").final(); 15 | auto v2r = cthash::sha224{}.update(runtime_pass("hana")).final(); 16 | REQUIRE(v2 == "a814c3122b1a3f2402bbcd0faffe28a9a7c24d389af78b596c752684"_sha224); 17 | REQUIRE(v2 == v2r); 18 | 19 | constexpr auto v3 = cthash::sha224{}.update(array_of_zeros<32>()).final(); 20 | auto v3r = cthash::sha224{}.update(runtime_pass(array_of_zeros<32>())).final(); 21 | REQUIRE(v3 == "b338c76bcffa1a0b3ead8de58dfbff47b63ab1150e10d8f17f2bafdf"_sha224); 22 | REQUIRE(v3 == v3r); 23 | 24 | constexpr auto v4 = cthash::sha224{}.update(array_of_zeros<64>()).final(); 25 | auto v4r = cthash::sha224{}.update(runtime_pass(array_of_zeros<64>())).final(); 26 | REQUIRE(v4 == "750d81a39c18d3ce27ff3e5ece30b0088f12d8fd0450fe435326294b"_sha224); 27 | REQUIRE(v4 == v4r); 28 | 29 | constexpr auto v5 = cthash::sha224{}.update(array_of_zeros<120>()).final(); 30 | auto v5r = cthash::sha224{}.update(runtime_pass(array_of_zeros<120>())).final(); 31 | REQUIRE(v5 == "83438028e7817c90b386a11c9a4e051f821b37c818bb4b5c08279584"_sha224); 32 | REQUIRE(v5 == v5r); 33 | 34 | constexpr auto v6 = cthash::sha224{}.update(array_of_zeros<128>()).final(); 35 | auto v6r = cthash::sha224{}.update(runtime_pass(array_of_zeros<128>())).final(); 36 | REQUIRE(v6 == "2fbd823ebcd9909d265827e4bce793a4fc572e3f39c7c3dd67749f3e"_sha224); 37 | REQUIRE(v6 == v6r); 38 | 39 | constexpr auto v7 = cthash::sha224{}.update(array_of_zeros<512>()).final(); 40 | auto v7r = cthash::sha224{}.update(runtime_pass(array_of_zeros<512, char>())).final(); 41 | REQUIRE(v7 == "4026dd4dbeb4d8a951dfd9a592897f46203ebe2d99c4a8837aa3afc9"_sha224); 42 | REQUIRE(v7 == v7r); 43 | } 44 | -------------------------------------------------------------------------------- /tests/sha2/sha256.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../internal/support.hpp" 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("sha256 size") { 9 | auto h = cthash::sha256{}; 10 | h.update("aloha"); 11 | REQUIRE(h.size() == 5u); 12 | h.update("hana"); 13 | REQUIRE(h.size() == 9u); 14 | } 15 | 16 | TEST_CASE("sha256 zero staging should be empty") { 17 | const auto block = array_of_zeros<64>(); 18 | const auto staging = cthash::internal_hasher::build_staging(block); 19 | 20 | for (auto val: staging) { 21 | REQUIRE(val == static_cast(0)); 22 | } 23 | } 24 | 25 | TEST_CASE("sha256 empty input") { 26 | const auto block = [] { 27 | auto r = array_of_zeros<64>(); 28 | r[0] = std::byte{0b1000'0000}; 29 | return r; 30 | }(); 31 | const auto staging = cthash::internal_hasher::build_staging(block); 32 | 33 | auto it = staging.begin(); 34 | 35 | // from the block 36 | REQUIRE(*it++ == 0x80000000ul); 37 | for (int i = 1; i != 16; ++i) { 38 | REQUIRE(*it++ == 0ull); 39 | } 40 | 41 | // calculated by staging function 42 | REQUIRE(staging[16] == 0b10000000000000000000000000000000ul); 43 | REQUIRE(staging[17] == 0b00000000000000000000000000000000ul); 44 | REQUIRE(staging[18] == 0b00000000001000000101000000000000ul); 45 | REQUIRE(staging[19] == 0b00000000000000000000000000000000ul); 46 | REQUIRE(staging[20] == 0b00100010000000000000100000000000ul); 47 | REQUIRE(staging[21] == 0b00000000000000000000000000000000ul); 48 | REQUIRE(staging[22] == 0b00000101000010001001010101000010ul); 49 | REQUIRE(staging[23] == 0b10000000000000000000000000000000ul); 50 | REQUIRE(staging[24] == 0b01011000000010000000000000000000ul); 51 | REQUIRE(staging[25] == 0b00000000010000001010000000000000ul); 52 | REQUIRE(staging[26] == 0b00000000000101100010010100000101ul); 53 | REQUIRE(staging[27] == 0b01100110000000000001100000000000ul); 54 | REQUIRE(staging[28] == 0b11010110001000100010010110000000ul); 55 | REQUIRE(staging[29] == 0b00010100001000100101010100001000ul); 56 | REQUIRE(staging[30] == 0b11010110010001011111100101011100ul); 57 | REQUIRE(staging[31] == 0b11001001001010000010000000000000ul); 58 | REQUIRE(staging[32] == 0b11000011111100010000000010010100ul); 59 | REQUIRE(staging[33] == 0b00101000010011001010011101100110ul); 60 | REQUIRE(staging[34] == 0b00000110100010000110110111000110ul); 61 | REQUIRE(staging[35] == 0b10100011011110111111000100010110ul); 62 | REQUIRE(staging[36] == 0b01110001011111001011111010010110ul); 63 | REQUIRE(staging[37] == 0b11111110110000101101011101001010ul); 64 | REQUIRE(staging[38] == 0b10100111101101100111111100000000ul); 65 | REQUIRE(staging[39] == 0b10000001000101011001011010100010ul); 66 | REQUIRE(staging[40] == 0b10011000101001101110011101101000ul); 67 | REQUIRE(staging[41] == 0b00000011101100100000110010000010ul); 68 | REQUIRE(staging[42] == 0b01011101000111011010011111001001ul); 69 | REQUIRE(staging[43] == 0b10110001010101101011100100110101ul); 70 | REQUIRE(staging[44] == 0b11000011110111011100101000010001ul); 71 | REQUIRE(staging[45] == 0b00100100100111000001000001111111ul); 72 | REQUIRE(staging[46] == 0b11000100100011010010010011101111ul); 73 | REQUIRE(staging[47] == 0b01011101111001010100110000110000ul); 74 | REQUIRE(staging[48] == 0b11011110111111101100111001100101ul); 75 | REQUIRE(staging[49] == 0b00101100101000010100100000001101ul); 76 | REQUIRE(staging[50] == 0b00111100000101010011001100101100ul); 77 | REQUIRE(staging[51] == 0b00000001110011101100100110101101ul); 78 | REQUIRE(staging[52] == 0b00010110000011001100110011010000ul); 79 | REQUIRE(staging[53] == 0b00001011101011001101101010011000ul); 80 | REQUIRE(staging[54] == 0b00110110000110111000111111100000ul); 81 | REQUIRE(staging[55] == 0b11010010001100100000101110100110ul); 82 | REQUIRE(staging[56] == 0b00000010100110110111000000000111ul); 83 | REQUIRE(staging[57] == 0b01110101010001100101100001111100ul); 84 | REQUIRE(staging[58] == 0b00000111111101010100111100111001ul); 85 | REQUIRE(staging[59] == 0b11111000000010001101110111000011ul); 86 | REQUIRE(staging[60] == 0b11011100110010100111011000001000ul); 87 | REQUIRE(staging[61] == 0b01011110010000100111000110001000ul); 88 | REQUIRE(staging[62] == 0b01000100101111001110110001011101ul); 89 | REQUIRE(staging[63] == 0b00111011010111101100010010011011ul); 90 | 91 | REQUIRE(64 == staging.size()); 92 | } 93 | 94 | TEST_CASE("sha256 basics (constexpr and runtime)") { 95 | constexpr auto v1 = cthash::sha256{}.update("").final(); 96 | auto v1r = cthash::sha256{}.update(runtime_pass("")).final(); 97 | REQUIRE(v1 == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"_sha256); 98 | REQUIRE(v1 == v1r); 99 | 100 | constexpr auto v2 = cthash::sha256{}.update("hana").final(); 101 | auto v2r = cthash::sha256{}.update(runtime_pass("hana")).final(); 102 | REQUIRE(v2 == "599ba25a0d7c7d671bee93172ca7e272fc87f0c0e02e44df9e9436819067ea28"_sha256); 103 | REQUIRE(v2 == v2r); 104 | 105 | constexpr auto v3 = cthash::sha256{}.update(array_of_zeros<96>()).final(); 106 | auto v3r = cthash::sha256{}.update(runtime_pass(array_of_zeros<96>())).final(); 107 | REQUIRE(v3 == "2ea9ab9198d1638007400cd2c3bef1cc745b864b76011a0e1bc52180ac6452d4"_sha256); 108 | REQUIRE(v3 == v3r); 109 | 110 | constexpr auto v4 = cthash::sha256{}.update(array_of_zeros<120>()).final(); 111 | auto v4r = cthash::sha256{}.update(runtime_pass(array_of_zeros<120>())).final(); 112 | auto v4b = cthash::sha256{}.update(runtime_pass(array_of_zeros<120, char>())).final(); 113 | REQUIRE(v4 == "6edd9f6f9cc92cded36e6c4a580933f9c9f1b90562b46903b806f21902a1a54f"_sha256); 114 | REQUIRE(v4 == v4r); 115 | REQUIRE(v4 == v4b); 116 | 117 | constexpr auto v5 = cthash::sha256{}.update(array_of_zeros<128>()).final(); 118 | auto v5r = cthash::sha256{}.update(runtime_pass(array_of_zeros<128>())).final(); 119 | REQUIRE(v5 == "38723a2e5e8a17aa7950dc008209944e898f69a7bd10a23c839d341e935fd5ca"_sha256); 120 | REQUIRE(v5 == v5r); 121 | } 122 | 123 | TEST_CASE("sha256 long hash over 512MB", "[.long]") { 124 | cthash::sha256 h{}; 125 | for (int i = 0; i != 512 * 1024; ++i) { 126 | h.update(array_of_zeros<1024>()); 127 | } 128 | REQUIRE(h.size() == 512u * 1024u * 1024u); 129 | const auto r = h.final(); 130 | 131 | REQUIRE(r == "9acca8e8c22201155389f65abbf6bc9723edc7384ead80503839f49dcc56d767"_sha256); 132 | } 133 | 134 | TEST_CASE("sha256 formatting") { 135 | auto hash = cthash::sha256().update("hi there!").final(); 136 | auto str = std::format("{:base64}", hash); 137 | 138 | REQUIRE(str == "PjbTYi9a2tAQgMwhILtywHFOzsYRjrlSNYZBC3Q1roA="); 139 | } 140 | 141 | TEST_CASE("sha256 to_string") { 142 | auto hash = cthash::sha256().update("hi there!").final(); 143 | auto str1 = to_string(hash); 144 | 145 | REQUIRE(str1 == "3e36d3622f5adad01080cc2120bb72c0714ecec6118eb9523586410b7435ae80"); 146 | 147 | auto str2 = to_string(hash); 148 | REQUIRE(str2 == "PjbTYi9a2tAQgMwhILtywHFOzsYRjrlSNYZBC3Q1roA="); 149 | } 150 | 151 | TEST_CASE("sha256 to_fixed_string") { 152 | constexpr auto hash = cthash::sha256().update("hi there!").final(); 153 | constexpr auto str1 = to_fixed_string(hash); 154 | 155 | REQUIRE(str1 == "3e36d3622f5adad01080cc2120bb72c0714ecec6118eb9523586410b7435ae80"); 156 | 157 | constexpr auto str2 = to_fixed_string(hash); 158 | REQUIRE(str2 == "PjbTYi9a2tAQgMwhILtywHFOzsYRjrlSNYZBC3Q1roA="); 159 | } 160 | -------------------------------------------------------------------------------- /tests/sha2/sha384.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("sha384 basics") { 9 | constexpr auto v1 = cthash::sha384{}.update("").final(); 10 | auto v1r = cthash::sha384{}.update(runtime_pass("")).final(); 11 | REQUIRE(v1 == "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"_sha384); 12 | REQUIRE(v1 == v1r); 13 | 14 | constexpr auto v2 = cthash::sha384{}.update("hana").final(); 15 | auto v2r = cthash::sha384{}.update(runtime_pass("hana")).final(); 16 | REQUIRE(v2 == "f365fd3e040e79a664d21de719128557b1188463d2d92be43522ccd4c316958b29f1189750b0f8d55aca50b8492982e8"_sha384); 17 | REQUIRE(v2 == v2r); 18 | 19 | constexpr auto v3 = cthash::sha384{}.update(array_of_zeros<32>()).final(); 20 | auto v3r = cthash::sha384{}.update(runtime_pass(array_of_zeros<32>())).final(); 21 | REQUIRE(v3 == "a38fff4ba26c15e4ac9cde8c03103ac89080fd47545fde9446c8f192729eab7bd03a4d5c3187f75fe2a71b0ee50a4a40"_sha384); 22 | REQUIRE(v3 == v3r); 23 | 24 | constexpr auto v4 = cthash::sha384{}.update(array_of_zeros<64>()).final(); 25 | auto v4r = cthash::sha384{}.update(runtime_pass(array_of_zeros<64>())).final(); 26 | REQUIRE(v4 == "c516aa8d3b457c636c6826937099c0d23a13f2c3701a388b3c8fe4bc2073281b0c4462610369884c4ababa8e97b6debe"_sha384); 27 | REQUIRE(v4 == v4r); 28 | 29 | constexpr auto v5 = cthash::sha384{}.update(array_of_zeros<120>()).final(); 30 | auto v5r = cthash::sha384{}.update(runtime_pass(array_of_zeros<120>())).final(); 31 | REQUIRE(v5 == "7212d895f4250ce1daa72e9e0caaef7132aed2e965885c55376818e45470de06fb6ebf7349c62fd342043f18010e46ac"_sha384); 32 | REQUIRE(v5 == v5r); 33 | 34 | constexpr auto v6 = cthash::sha384{}.update(array_of_zeros<128>()).final(); 35 | auto v6r = cthash::sha384{}.update(runtime_pass(array_of_zeros<128>())).final(); 36 | REQUIRE(v6 == "f809b88323411f24a6f152e5e9d9d1b5466b77e0f3c7550f8b242c31b6e7b99bcb45bdecb6124bc23283db3b9fc4f5b3"_sha384); 37 | REQUIRE(v6 == v6r); 38 | 39 | constexpr auto v7 = cthash::sha384{}.update(array_of_zeros<512, char>()).final(); 40 | auto v7r = cthash::sha384{}.update(runtime_pass(array_of_zeros<512, char>())).final(); 41 | REQUIRE(v7 == "d83d9a38c238ef3b7bc207bbea3287a8b37b37e731480a8d240d2a6953086c5ecbdf7ee4c72fec3a3e9d4a87f4f9b4fe"_sha384); 42 | REQUIRE(v7 == v7r); 43 | } 44 | -------------------------------------------------------------------------------- /tests/sha2/sha512.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | template struct identify; 9 | 10 | TEST_CASE("sha512 zero staging should be empty") { 11 | const auto block = array_of_zeros<128>(); 12 | const auto staging = cthash::internal_hasher::build_staging(block); 13 | 14 | for (auto val: staging) { 15 | REQUIRE(val == static_cast(0)); 16 | } 17 | } 18 | 19 | TEST_CASE("sha512 internal buffer at the end (two bytes)") { 20 | using sha512_hasher = cthash::internal_hasher; 21 | 22 | auto h = sha512_hasher{}; 23 | h.update_to_buffer_and_process(std::array{std::byte{'a'}, std::byte{'b'}}); 24 | h.finalize(); 25 | 26 | // message 27 | REQUIRE(unsigned(h.block[0]) == unsigned('a')); 28 | REQUIRE(unsigned(h.block[1]) == unsigned('b')); 29 | 30 | // terminator 31 | REQUIRE(unsigned(h.block[2]) == 0b1000'0000u); 32 | 33 | // bit length 34 | REQUIRE(unsigned(h.block[127]) == 16u); // 2*8 = 16 35 | 36 | STATIC_REQUIRE(h.block.size() == 128u); 37 | 38 | // rest of the block must be zeros 39 | for (int i = 0; i != 128; ++i) { 40 | if (i > 2 && i < 127) { 41 | REQUIRE(unsigned(h.block[static_cast(i)]) == unsigned{0b0000'0000u}); 42 | } 43 | } 44 | } 45 | 46 | TEST_CASE("sha512 internal buffer at the end (111B)") { 47 | using sha512_hasher = cthash::internal_hasher; 48 | 49 | auto h = sha512_hasher{}; 50 | h.update_to_buffer_and_process(array_of<111>(std::byte{42})); 51 | h.finalize(); 52 | 53 | // message 54 | for (int i = 0; i != 111; ++i) { 55 | REQUIRE(unsigned(h.block[static_cast(i)]) == unsigned(42)); 56 | } 57 | 58 | // terminator 59 | REQUIRE(unsigned(h.block[111]) == 0b1000'0000u); 60 | 61 | // bit length 62 | REQUIRE(unsigned(h.block[112]) == 0b0000'0000u); 63 | REQUIRE(unsigned(h.block[113]) == 0b0000'0000u); 64 | REQUIRE(unsigned(h.block[114]) == 0b0000'0000u); 65 | REQUIRE(unsigned(h.block[115]) == 0b0000'0000u); 66 | REQUIRE(unsigned(h.block[116]) == 0b0000'0000u); 67 | REQUIRE(unsigned(h.block[117]) == 0b0000'0000u); 68 | REQUIRE(unsigned(h.block[118]) == 0b0000'0000u); 69 | REQUIRE(unsigned(h.block[119]) == 0b0000'0000u); 70 | REQUIRE(unsigned(h.block[120]) == 0b0000'0000u); 71 | REQUIRE(unsigned(h.block[121]) == 0b0000'0000u); 72 | REQUIRE(unsigned(h.block[122]) == 0b0000'0000u); 73 | REQUIRE(unsigned(h.block[123]) == 0b0000'0000u); 74 | REQUIRE(unsigned(h.block[124]) == 0b0000'0000u); 75 | REQUIRE(unsigned(h.block[125]) == 0b0000'0000u); 76 | REQUIRE(unsigned(h.block[126]) == 0b0000'0011u); 77 | REQUIRE(unsigned(h.block[127]) == 0b0111'1000u); 78 | 79 | STATIC_REQUIRE(h.block.size() == 128u); 80 | } 81 | 82 | TEST_CASE("sha512 internal buffer at the end (112B, first block)") { 83 | using sha512_hasher = cthash::internal_hasher; 84 | 85 | auto h = sha512_hasher{}; 86 | h.update_to_buffer_and_process(array_of<112>(std::byte{42})); 87 | const bool overflow = sha512_hasher::finalize_buffer(h.block, h.block_used); 88 | REQUIRE(overflow); 89 | 90 | // there is no message (as it was in previous block) 91 | for (int i = 0; i != 112; ++i) { 92 | REQUIRE(unsigned(h.block[static_cast(i)]) == 42u); 93 | } 94 | 95 | // terminator 96 | REQUIRE(unsigned(h.block[112]) == 0b1000'0000u); 97 | 98 | // zero-padding 99 | for (int i = 113; i != 128; ++i) { 100 | REQUIRE(unsigned(h.block[static_cast(i)]) == 0u); 101 | } 102 | 103 | STATIC_REQUIRE(h.block.size() == 128u); 104 | } 105 | 106 | TEST_CASE("sha512 internal buffer at the end (112B, second block)") { 107 | using sha512_hasher = cthash::internal_hasher; 108 | 109 | auto h = sha512_hasher{}; 110 | h.update_to_buffer_and_process(array_of<112>(std::byte{42})); 111 | h.finalize(); 112 | 113 | // there is no message (as it was in previous block) 114 | for (int i = 0; i != 112; ++i) { 115 | REQUIRE(unsigned(h.block[static_cast(i)]) == unsigned(0)); 116 | } 117 | 118 | // bit length 119 | REQUIRE(unsigned(h.block[112]) == 0b0000'0000u); 120 | REQUIRE(unsigned(h.block[113]) == 0b0000'0000u); 121 | REQUIRE(unsigned(h.block[114]) == 0b0000'0000u); 122 | REQUIRE(unsigned(h.block[115]) == 0b0000'0000u); 123 | REQUIRE(unsigned(h.block[116]) == 0b0000'0000u); 124 | REQUIRE(unsigned(h.block[117]) == 0b0000'0000u); 125 | REQUIRE(unsigned(h.block[118]) == 0b0000'0000u); 126 | REQUIRE(unsigned(h.block[119]) == 0b0000'0000u); 127 | REQUIRE(unsigned(h.block[120]) == 0b0000'0000u); 128 | REQUIRE(unsigned(h.block[121]) == 0b0000'0000u); 129 | REQUIRE(unsigned(h.block[122]) == 0b0000'0000u); 130 | REQUIRE(unsigned(h.block[123]) == 0b0000'0000u); 131 | REQUIRE(unsigned(h.block[124]) == 0b0000'0000u); 132 | REQUIRE(unsigned(h.block[125]) == 0b0000'0000u); 133 | REQUIRE(unsigned(h.block[126]) == 0b0000'0011u); 134 | REQUIRE(unsigned(h.block[127]) == 0b1000'0000u); 135 | 136 | STATIC_REQUIRE(h.block.size() == 128u); 137 | } 138 | 139 | TEST_CASE("sha512 empty input") { 140 | const auto block = [] { 141 | auto r = array_of_zeros<128>(); 142 | r[0] = std::byte{0b1000'0000}; 143 | return r; 144 | }(); 145 | const auto staging = cthash::internal_hasher::build_staging(block); 146 | 147 | auto it = staging.begin(); 148 | 149 | // from the block 150 | REQUIRE(*it++ == 0x80000000'00000000ull); 151 | for (int i = 1; i != 16; ++i) { 152 | REQUIRE(*it++ == 0ull); 153 | } 154 | 155 | // calculated by staging function 156 | REQUIRE(staging[16] == 0x80000000'00000000ull); 157 | REQUIRE(80 == staging.size()); 158 | 159 | REQUIRE(staging[17] == 0x0000000000000000ull); 160 | REQUIRE(staging[18] == 0x0200100000000004ull); 161 | REQUIRE(staging[19] == 0x0000000000000000ull); 162 | REQUIRE(staging[20] == 0x1008000002000020ull); 163 | REQUIRE(staging[21] == 0x0000000000000000ull); 164 | REQUIRE(staging[22] == 0x8004220110080140ull); 165 | REQUIRE(staging[23] == 0x8000000000000000ull); 166 | REQUIRE(staging[24] == 0x0209108000400800ull); 167 | REQUIRE(staging[25] == 0x0400200000000008ull); 168 | REQUIRE(staging[26] == 0x1140a00320114028ull); 169 | REQUIRE(staging[27] == 0x3018000006000060ull); 170 | REQUIRE(staging[28] == 0xa24500b1180a2042ull); 171 | REQUIRE(staging[29] == 0x0010880440200500ull); 172 | REQUIRE(staging[30] == 0xd4a945c2a4270995ull); 173 | REQUIRE(staging[31] == 0x43ad128001402810ull); 174 | REQUIRE(staging[32] == 0xcb2a519703108414ull); 175 | REQUIRE(staging[33] == 0x2faad072c8658034ull); 176 | REQUIRE(staging[34] == 0x7d14cc9b14ba8338ull); 177 | REQUIRE(staging[35] == 0x9867c5d3eb13eeffull); 178 | REQUIRE(staging[36] == 0xc94dc04c92359678ull); 179 | REQUIRE(staging[37] == 0x92aba5ae1ee4675dull); 180 | REQUIRE(staging[38] == 0x00b560cd2d362129ull); 181 | REQUIRE(staging[39] == 0x682916bbbf1eb0d9ull); 182 | REQUIRE(staging[40] == 0xfd4ce54fb9c1fca2ull); 183 | REQUIRE(staging[41] == 0x389bbafedf01a2ffull); 184 | REQUIRE(staging[42] == 0xf80ad4187a704534ull); 185 | REQUIRE(staging[43] == 0xfc8a6db46b916fabull); 186 | REQUIRE(staging[44] == 0x0009308c4ca7d22bull); 187 | REQUIRE(staging[45] == 0x49437d8543e9c98cull); 188 | REQUIRE(staging[46] == 0x67f19b9756071662ull); 189 | REQUIRE(staging[47] == 0x23d1b6fd5980db71ull); 190 | REQUIRE(staging[48] == 0x044afa0ab38edb37ull); 191 | REQUIRE(staging[49] == 0x332fd4ee79f5c755ull); 192 | REQUIRE(staging[50] == 0xa55aa02bebfa6ad4ull); 193 | REQUIRE(staging[51] == 0xd7c6eb0c613c793aull); 194 | REQUIRE(staging[52] == 0x0d8e6b8077ea417cull); 195 | REQUIRE(staging[53] == 0xd647ca451bde7ccbull); 196 | REQUIRE(staging[54] == 0xb69eec4d0e03246full); 197 | REQUIRE(staging[55] == 0xc913f017b2ac853aull); 198 | REQUIRE(staging[56] == 0x66221af93a4225bbull); 199 | REQUIRE(staging[57] == 0x022066fa965f2dbfull); 200 | REQUIRE(staging[58] == 0x98519af83ac7c4d8ull); 201 | REQUIRE(staging[59] == 0xa9d9b257ea80f60full); 202 | REQUIRE(staging[60] == 0xb741f8b59c416c21ull); 203 | REQUIRE(staging[61] == 0xa3de4a86a2cdbefbull); 204 | REQUIRE(staging[62] == 0xa6e929fabf4b5fa6ull); 205 | REQUIRE(staging[63] == 0xeabfcd669f8d15a1ull); 206 | } 207 | 208 | TEST_CASE("sha512 basics", "") { 209 | constexpr auto v1 = cthash::sha512{}.update("").final(); 210 | auto v1r = cthash::sha512{}.update(runtime_pass("")).final(); 211 | REQUIRE(v1 == "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"_sha512); 212 | REQUIRE(v1 == v1r); 213 | 214 | constexpr auto v2 = cthash::sha512{}.update("hana").final(); 215 | auto v2r = cthash::sha512{}.update(runtime_pass("hana")).final(); 216 | REQUIRE(v2 == "74d15692038cd747dce0f4ff287ce1d5a7930c7e5948183419584f142039b3b25a94d1bf7f321f2fd2da37af1b6552f3e5bfc6c40d0bd8e16ecde338ee153a02"_sha512); 217 | REQUIRE(v2 == v2r); 218 | 219 | constexpr auto v3 = cthash::sha512{}.update(array_of_zeros<96>()).final(); 220 | auto v3r = cthash::sha512{}.update(array_of_zeros<96>()).final(); 221 | auto v3rb = cthash::sha512{}.update(array_of_zeros<96, char>()).final(); 222 | REQUIRE(v3 == "e866b15da9e5b18d4b3bde250fc08a208399440f37471313c5b4006e4151b0f4464b2cd7246899935d58660c0749cd11570bb8240760a6e46bb175be18cdaffe"_sha512); 223 | REQUIRE(v3 == v3r); 224 | REQUIRE(v3 == v3rb); 225 | 226 | constexpr auto v4 = cthash::sha512{}.update(array_of_zeros<120>()).final(); 227 | auto v4r = cthash::sha512{}.update(array_of_zeros<120, char>()).final(); 228 | REQUIRE(v4 == "c106c47ad6eb79cd2290681cb04cb183effbd0b49402151385b2d07be966e2d50bc9db78e00bf30bb567ccdd3a1c7847260c94173ba215a0feabb0edeb643ff0"_sha512); 229 | REQUIRE(v4 == v4r); 230 | 231 | constexpr auto v5 = cthash::sha512{}.update(array_of_zeros<128>()).final(); 232 | auto v5r = cthash::sha512{}.update(array_of_zeros<128, char>()).final(); 233 | REQUIRE(v5 == "ab942f526272e456ed68a979f50202905ca903a141ed98443567b11ef0bf25a552d639051a01be58558122c58e3de07d749ee59ded36acf0c55cd91924d6ba11"_sha512); 234 | REQUIRE(v5 == v5r); 235 | 236 | constexpr auto v6 = cthash::sha512{}.update(array_of_zeros<512>()).final(); 237 | auto v6r = cthash::sha512{}.update(array_of_zeros<512, char>()).final(); 238 | auto v6rb = cthash::sha512{}.update(array_of_zeros<512>()).final(); 239 | REQUIRE(v6 == "df40d4a774e0b453a5b87c00d6f0ef5d753143454e88ee5f7b607134598294c7905ccbcf94bbc46e474db6eb44e56a6dbb6d9a1be9d4fb5d1b5f2d0c6ed34bfe"_sha512); 240 | REQUIRE(v6 == v6r); 241 | REQUIRE(v6 == v6rb); 242 | } 243 | -------------------------------------------------------------------------------- /tests/sha2/sha512t.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | using namespace std::string_literals; 8 | 9 | TEST_CASE("sha512/t (init strings)") { 10 | REQUIRE(to_str(cthash::signature_for_sha512t<8>) == "SHA-512/8"s); 11 | REQUIRE(to_str(cthash::signature_for_sha512t<16>) == "SHA-512/16"s); 12 | REQUIRE(to_str(cthash::signature_for_sha512t<128>) == "SHA-512/128"s); 13 | REQUIRE(to_str(cthash::signature_for_sha512t<224>) == "SHA-512/224"s); 14 | REQUIRE(to_str(cthash::signature_for_sha512t<256>) == "SHA-512/256"s); 15 | } 16 | 17 | TEST_CASE("sha512/224 (iv)") { 18 | constexpr auto & iv = cthash::sha512t_config<224>::initial_values; 19 | REQUIRE(iv[0] == 0x8C3D37C819544DA2ull); 20 | REQUIRE(iv[1] == 0x73E1996689DCD4D6ull); 21 | REQUIRE(iv[2] == 0x1DFAB7AE32FF9C82ull); 22 | REQUIRE(iv[3] == 0x679DD514582F9FCFull); 23 | REQUIRE(iv[4] == 0x0F6D2B697BD44DA8ull); 24 | REQUIRE(iv[5] == 0x77E36F7304C48942ull); 25 | REQUIRE(iv[6] == 0x3F9D85A86A1D36C8ull); 26 | REQUIRE(iv[7] == 0x1112E6AD91D692A1ull); 27 | } 28 | 29 | TEST_CASE("sha512/256 (iv)") { 30 | constexpr auto & iv = cthash::sha512t_config<256>::initial_values; 31 | REQUIRE(iv[0] == 0x22312194FC2BF72Cull); 32 | REQUIRE(iv[1] == 0x9F555FA3C84C64C2ull); 33 | REQUIRE(iv[2] == 0x2393B86B6F53B151ull); 34 | REQUIRE(iv[3] == 0x963877195940EABDull); 35 | REQUIRE(iv[4] == 0x96283EE2A88EFFE3ull); 36 | REQUIRE(iv[5] == 0xBE5E1E2553863992ull); 37 | REQUIRE(iv[6] == 0x2B0199FC2C85B8AAull); 38 | REQUIRE(iv[7] == 0x0EB72DDC81C52CA2ull); 39 | } 40 | 41 | TEST_CASE("sha512/224 (literals)") { 42 | [[maybe_unused]] const auto v1 = "750d81a39c18d3ce27ff3e5ece30b0088f12d8fd0450fe435326294b"_sha512_224; 43 | } 44 | 45 | TEST_CASE("sha512/224 (basics)") { 46 | constexpr auto v1 = cthash::sha512t<224>{}.update("").final(); 47 | auto v1r = cthash::sha512t<224>{}.update(runtime_pass("")).final(); 48 | REQUIRE(v1 == "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4"_sha512_224); 49 | REQUIRE(v1 == v1r); 50 | 51 | constexpr auto v2 = cthash::sha512t<224>{}.update("hana").final(); 52 | auto v2r = cthash::sha512t<224>{}.update(runtime_pass("hana")).final(); 53 | REQUIRE(v2 == "53a276b702c0133dcec23f6ec5dc1ad56b224f386fdd57710dc53f9f"_sha512_224); 54 | REQUIRE(v2 == v2r); 55 | 56 | constexpr auto v3 = cthash::sha512t<224>{}.update(array_of_zeros<32>()).final(); 57 | auto v3r = cthash::sha512t<224>{}.update(runtime_pass(array_of_zeros<32, char>())).final(); 58 | REQUIRE(v3 == "9e7d6080def4e1ccf4aeaac6f7fad008d060a6cf87062038d6166774"_sha512_224); 59 | REQUIRE(v3 == v3r); 60 | 61 | constexpr auto v4 = cthash::sha512t<224>{}.update(array_of_zeros<64>()).final(); 62 | auto v4r = cthash::sha512t<224>{}.update(runtime_pass(array_of_zeros<64>())).final(); 63 | REQUIRE(v4 == "1319d9b322452068e6f43c0ed3da115fbeccc169711dbbaee2846f90"_sha512_224); 64 | REQUIRE(v4 == v4r); 65 | 66 | constexpr auto v5 = cthash::sha512t<224>{}.update(array_of_zeros<120>()).final(); 67 | auto v5r = cthash::sha512t<224>{}.update(runtime_pass(array_of_zeros<120, char>())).final(); 68 | REQUIRE(v5 == "d4dfc5c3449b4e3b180d9fda54e1bd86e2c40e2b790db950b4b3d297"_sha512_224); 69 | REQUIRE(v5 == v5r); 70 | 71 | constexpr auto v6 = cthash::sha512t<224>{}.update(array_of_zeros<128>()).final(); 72 | auto v6r = cthash::sha512t<224>{}.update(runtime_pass(array_of_zeros<128>())).final(); 73 | REQUIRE(v6 == "9ae639d7038fa1946a6f032dc72cb38afb0de1765a82a31621196f44"_sha512_224); 74 | REQUIRE(v6 == v6r); 75 | 76 | constexpr auto v7 = cthash::sha512t<224>{}.update(array_of_zeros<512>()).final(); 77 | auto v7r = cthash::sha512t<224>{}.update(runtime_pass(array_of_zeros<512>())).final(); 78 | REQUIRE(v7 == "6992572b245cb279973a119cb7f2859e75dff8c5fb9ace89566ae06d"_sha512_224); 79 | REQUIRE(v7 == v7r); 80 | } 81 | 82 | TEST_CASE("sha512/256 (basics)") { 83 | constexpr auto v1 = cthash::sha512t<256>{}.update("").final(); 84 | auto v1r = cthash::sha512t<256>{}.update(runtime_pass("")).final(); 85 | REQUIRE(v1 == "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"_sha512_256); 86 | REQUIRE(v1 == v1r); 87 | 88 | constexpr auto v2 = cthash::sha512t<256>{}.update("hana").final(); 89 | auto v2r = cthash::sha512t<256>{}.update(runtime_pass("hana")).final(); 90 | REQUIRE(v2 == "2a0e3f7643580859507710f4569a60a86c83c025955298e7a93d766f71e8e399"_sha512_256); 91 | REQUIRE(v2 == v2r); 92 | 93 | constexpr auto v3 = cthash::sha512t<256>{}.update(array_of_zeros<32>()).final(); 94 | auto v3r = cthash::sha512t<256>{}.update(runtime_pass(array_of_zeros<32, char>())).final(); 95 | REQUIRE(v3 == "af13c048991224a5e4c664446b688aaf48fb5456db3629601b00ec160c74e554"_sha512_256); 96 | REQUIRE(v3 == v3r); 97 | 98 | constexpr auto v4 = cthash::sha512t<256>{}.update(array_of_zeros<64>()).final(); 99 | auto v4r = cthash::sha512t<256>{}.update(runtime_pass(array_of_zeros<64>())).final(); 100 | REQUIRE(v4 == "8aeecfa0b9f2ac7818863b1362241e4f32d06b100ae9d1c0fbcc4ed61b91b17a"_sha512_256); 101 | REQUIRE(v4 == v4r); 102 | 103 | constexpr auto v5 = cthash::sha512t<256>{}.update(array_of_zeros<120>()).final(); 104 | auto v5r = cthash::sha512t<256>{}.update(runtime_pass(array_of_zeros<120, char>())).final(); 105 | REQUIRE(v5 == "067880a5256c0584cff10526ed4c9761e584bf0ecdb1b12c2ae7f1dcedaf3dbf"_sha512_256); 106 | REQUIRE(v5 == v5r); 107 | 108 | constexpr auto v6 = cthash::sha512t<256>{}.update(array_of_zeros<128>()).final(); 109 | auto v6r = cthash::sha512t<256>{}.update(runtime_pass(array_of_zeros<128>())).final(); 110 | REQUIRE(v6 == "fe3d375e149b888e08e2521007764b422d2cd6f7b0606881b7fe1b1370d5fa88"_sha512_256); 111 | REQUIRE(v6 == v6r); 112 | 113 | constexpr auto v7 = cthash::sha512t<256>{}.update(array_of_zeros<512>()).final(); 114 | auto v7r = cthash::sha512t<256>{}.update(runtime_pass(array_of_zeros<512>())).final(); 115 | REQUIRE(v7 == "552b405c9716945bfc0caee69baec21b2a05560bfbf58db8bd1a4c2cc42b42a6"_sha512_256); 116 | REQUIRE(v7 == v7r); 117 | } -------------------------------------------------------------------------------- /tests/sha3/sha3-224.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("sha3-224 basics") { 9 | const auto a = "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7"_sha3_224; 10 | REQUIRE(a.size() == 224u / 8u); 11 | } 12 | 13 | TEST_CASE("sha3-224 test strings") { 14 | SECTION("empty") { 15 | const auto r0 = cthash::sha3_224().update("").final(); 16 | REQUIRE(r0 == "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7"_sha3_224); 17 | } 18 | 19 | SECTION("empty with bytes") { 20 | const auto r0 = cthash::sha3_224().update(std::span()).final(); 21 | REQUIRE(r0 == "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7"_sha3_224); 22 | } 23 | 24 | SECTION("test") { 25 | const auto r0 = cthash::sha3_224().update("test").final(); 26 | REQUIRE(r0 == "3797bf0afbbfca4a7bbba7602a2b552746876517a7f9b7ce2db0ae7b"_sha3_224); 27 | } 28 | 29 | SECTION("hanicka") { 30 | const auto r0 = cthash::sha3_224().update("hanicka").final(); 31 | REQUIRE(r0 == "bb8c7c352111f9e6e024c9aae448a25da287590ce6ff9be8063b6206"_sha3_224); 32 | } 33 | 34 | SECTION("*136 characters (exactly block size)") { 35 | auto in = std::string(size_t(136), '*'); // size of block 36 | const auto r0 = cthash::sha3_224().update(in).final(); 37 | REQUIRE(r0 == "e6b935498d1db267b4eb1b71fcc6b0598f46ffb689ce2df273d70ee4"_sha3_224); 38 | } 39 | 40 | SECTION("*137 characters (exactly block + 1 size)") { 41 | auto in = std::string(size_t(137), '*'); // size of block + 1 42 | const auto r0 = cthash::sha3_224().update(in).final(); 43 | REQUIRE(r0 == "3527595762e032bc0cc0974f6df0c8f2454ab09b6139a117f2b78467"_sha3_224); 44 | } 45 | 46 | SECTION("*2500 characters") { 47 | auto in = std::string(size_t(2500), '*'); // size of block + 1 48 | const auto r0 = cthash::sha3_224().update(in).final(); 49 | REQUIRE(r0 == "7d4b80d6adeb7ba20723a0635b6582bd38c011389688305d381fa2cc"_sha3_224); 50 | } 51 | 52 | SECTION("*2500 by one") { 53 | auto h = cthash::sha3_224(); 54 | for (int i = 0; i != 2500; ++i) { 55 | h.update("*"); 56 | } 57 | const auto r0 = h.final(); 58 | REQUIRE(r0 == "7d4b80d6adeb7ba20723a0635b6582bd38c011389688305d381fa2cc"_sha3_224); 59 | } 60 | } 61 | 62 | TEST_CASE("sha3-224 stability") { 63 | auto h = cthash::sha3_224(); 64 | 65 | constexpr int end = int(h.rate) * 2; 66 | 67 | for (int i = 0; i != end; ++i) { 68 | const auto piece = std::string(size_t(i), '#'); 69 | h.update(piece); 70 | } 71 | 72 | const auto r0 = h.final(); 73 | REQUIRE(r0 == "2409c68f45c73652fef9ef6ca701560557fb01747b52f92ffffd0477"_sha3_224); 74 | } -------------------------------------------------------------------------------- /tests/sha3/sha3-256.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../internal/support.hpp" 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("sha3-256 basics") { 9 | const auto a = "5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03"_sha3_256; 10 | REQUIRE(a.size() == 256u / 8u); 11 | } 12 | 13 | TEST_CASE("sha3-256 test strings") { 14 | SECTION("empty") { 15 | constexpr auto calculation = []() { 16 | return cthash::sha3_256().update("").final(); 17 | }; 18 | 19 | auto r0 = calculation(); 20 | constexpr auto r1 = calculation(); 21 | 22 | REQUIRE(r0 == "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"_sha3_256); 23 | REQUIRE(r0 == r1); 24 | } 25 | 26 | SECTION("empty with bytes") { 27 | constexpr auto calculation = []() { 28 | return cthash::sha3_256().update(std::span()).final(); 29 | }; 30 | 31 | auto r0 = calculation(); 32 | constexpr auto r1 = calculation(); 33 | 34 | REQUIRE(r0 == "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"_sha3_256); 35 | REQUIRE(r0 == r1); 36 | } 37 | 38 | SECTION("test") { 39 | constexpr auto calculation = []() { 40 | return cthash::sha3_256().update("test").final(); 41 | }; 42 | 43 | auto r0 = calculation(); 44 | constexpr auto r1 = calculation(); 45 | 46 | REQUIRE(r0 == "36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80"_sha3_256); 47 | REQUIRE(r0 == r1); 48 | } 49 | 50 | SECTION("hanicka") { 51 | constexpr auto calculation = []() { 52 | return cthash::sha3_256().update("hanicka").final(); 53 | }; 54 | 55 | auto r0 = calculation(); 56 | constexpr auto r1 = calculation(); 57 | 58 | REQUIRE(r0 == "8f8b0b8af4c371e91791b1ddb2d0788661dd687060404af6320971bcc53b44fb"_sha3_256); 59 | REQUIRE(r0 == r1); 60 | } 61 | 62 | SECTION("*136 characters (exactly block size)") { 63 | constexpr auto calculation = []() { 64 | auto in = std::string(size_t(136), '*'); // size of block 65 | return cthash::sha3_256().update(in).final(); 66 | }; 67 | 68 | auto r0 = calculation(); 69 | constexpr auto r1 = calculation(); 70 | 71 | REQUIRE(r0 == "5224abc95021feafd89e36b41067884a08b39ff8e5ce0905c3a67d1857169e8a"_sha3_256); 72 | REQUIRE(r0 == r1); 73 | } 74 | 75 | SECTION("*137 characters (exactly block + 1 size)") { 76 | constexpr auto calculation = []() { 77 | auto in = std::string(size_t(136 + 1), '*'); // size of block 78 | return cthash::sha3_256().update(in).final(); 79 | }; 80 | 81 | auto r0 = calculation(); 82 | constexpr auto r1 = calculation(); 83 | 84 | REQUIRE(r0 == "596fe83ba2cb6199c98be88ca31fc21511e0e7244465c0bdfece933e9daa59bd"_sha3_256); 85 | REQUIRE(r0 == r1); 86 | } 87 | 88 | SECTION("*2500 characters") { 89 | auto in = std::string(size_t(2500), '*'); // size of block + 1 90 | const auto r0 = cthash::sha3_256().update(in).final(); 91 | REQUIRE(r0 == "d406a008de11740c60173ea37a9c67d4f1dea8fbfc3a41a2cbef8037b32e7541"_sha3_256); 92 | } 93 | 94 | SECTION("*2500 by one") { 95 | auto h = cthash::sha3_256(); 96 | for (int i = 0; i != 2500; ++i) { 97 | h.update("*"); 98 | } 99 | const auto r0 = h.final(); 100 | REQUIRE(r0 == "d406a008de11740c60173ea37a9c67d4f1dea8fbfc3a41a2cbef8037b32e7541"_sha3_256); 101 | } 102 | } 103 | 104 | TEST_CASE("sha3-256 stability") { 105 | auto h = cthash::sha3_256(); 106 | 107 | constexpr int end = int(h.rate) * 2; 108 | 109 | for (int i = 0; i != end; ++i) { 110 | const auto piece = std::string(size_t(i), '#'); 111 | h.update(piece); 112 | } 113 | 114 | const auto r0 = h.final(); 115 | REQUIRE(r0 == "af2e33605dbcb6f37facfcf7b999e068d25c38e12c86c33786cc207134812e6b"_sha3_256); 116 | } 117 | 118 | TEST_CASE("sha3-256 printing") { 119 | auto hash = cthash::sha3_256().final(); 120 | std::ostringstream ss; 121 | ss << hash; 122 | 123 | REQUIRE(ss.str() == "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"); 124 | } 125 | 126 | TEST_CASE("sha3-256 formatting") { 127 | auto hash = cthash::sha3_256().final(); 128 | auto str = std::format("{}", hash); 129 | 130 | REQUIRE(str == "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"); 131 | } 132 | 133 | TEST_CASE("sha3-256 formatting (hexdec explicitly)") { 134 | auto hash = cthash::sha3_256().final(); 135 | auto str = std::format("{:hexdec}", hash); 136 | 137 | REQUIRE(str == "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"); 138 | } 139 | 140 | TEST_CASE("sha3-256 formatting (z_base32 explicitly)") { 141 | auto hash = cthash::sha3_256().final(); 142 | auto str = std::format("{:zbase32}", hash); 143 | 144 | REQUIRE(str == "w99hp6f9d5mscwqbe7mkyaqscm4ab94pho7wu6wn5yfrzy8aepfy"); 145 | } 146 | 147 | TEST_CASE("sha3-256 formatting (base64url explicitly)") { 148 | auto hash = cthash::sha3_256().update("hanicka").final(); 149 | auto str = std::format("{:base64url}", hash); 150 | 151 | REQUIRE(str == "j4sLivTDcekXkbHdstB4hmHdaHBgQEr2MglxvMU7RPs"); 152 | } 153 | 154 | TEST_CASE("sha3-256 formatting (binary explicitly)") { 155 | auto hash = cthash::sha3_256().update("hanicka").final(); 156 | auto str = std::format("{:binary}", hash); 157 | 158 | REQUIRE(str == 159 | "1000111110001011000010111000101011110100110000110111000111101001000101111001" 160 | "0001101100011101110110110010110100000111100010000110011000011101110101101000" 161 | "0111000001100000010000000100101011110110001100100000100101110001101111001100" 162 | "0101001110110100010011111011"); 163 | } 164 | 165 | template auto materialize(auto && range) { 166 | auto result = Container{}; 167 | result.resize(range.size()); 168 | auto [in, out] = std::ranges::copy(range, result.begin()); 169 | REQUIRE(in == range.end()); 170 | REQUIRE(out == result.end()); 171 | return result; 172 | } 173 | 174 | TEST_CASE("static and dynamic path generates same results") { 175 | auto hash = cthash::sha3_256().update("hanicka").final(); 176 | 177 | REQUIRE(std::format("{:base2}", hash) == materialize(hash | cthash::base2_encode)); 178 | REQUIRE(std::format("{:binary}", hash) == materialize(hash | cthash::binary_encode)); 179 | REQUIRE(std::format("{:base4}", hash) == materialize(hash | cthash::base4_encode)); 180 | REQUIRE(std::format("{:base8}", hash) == materialize(hash | cthash::base8_encode)); 181 | REQUIRE(std::format("{:octal}", hash) == materialize(hash | cthash::octal_encode)); 182 | REQUIRE(std::format("{:base16}", hash) == materialize(hash | cthash::base16_encode)); 183 | REQUIRE(std::format("{:hexdec}", hash) == materialize(hash | cthash::hexdec_encode)); 184 | REQUIRE(std::format("{:base32}", hash) == materialize(hash | cthash::base32_encode)); 185 | REQUIRE(std::format("{:base32_no_padding}", hash) == materialize(hash | cthash::base32_no_padding_encode)); 186 | REQUIRE(std::format("{:z_base32}", hash) == materialize(hash | cthash::z_base32_encode)); 187 | REQUIRE(std::format("{:base64}", hash) == materialize(hash | cthash::base64_encode)); 188 | REQUIRE(std::format("{:base64url}", hash) == materialize(hash | cthash::base64url_encode)); 189 | REQUIRE(std::format("{:base64_no_padding}", hash) == materialize(hash | cthash::base64_no_padding_encode)); 190 | } 191 | 192 | TEST_CASE("sha3-256 formatting (shortening)") { 193 | auto hash = cthash::sha3_256().final(); 194 | auto str = std::format("{:hexdec}..{:hexdec}", hash.prefix<3>(), hash.suffix<3>()); 195 | 196 | REQUIRE(str == "a7ffc6..f8434a"); 197 | } 198 | -------------------------------------------------------------------------------- /tests/sha3/sha3-384.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("sha3-384 basics") { 9 | const auto a = "9c87cb0b9a8924030b93b4b3fd397c70030a57c6f98a051e0cc87d6d671e4da02e5fe4c6e8fe9d1ca46f085434092a99"_sha3_384; 10 | REQUIRE(a.size() == 384u / 8u); 11 | } 12 | 13 | TEST_CASE("sha3-384 test strings") { 14 | SECTION("empty") { 15 | const auto r0 = cthash::sha3_384().update("").final(); 16 | REQUIRE(r0 == "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"_sha3_384); 17 | } 18 | 19 | SECTION("empty with bytes") { 20 | const auto r0 = cthash::sha3_384().update(std::span()).final(); 21 | REQUIRE(r0 == "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"_sha3_384); 22 | } 23 | 24 | SECTION("test") { 25 | const auto r0 = cthash::sha3_384().update("test").final(); 26 | REQUIRE(r0 == "e516dabb23b6e30026863543282780a3ae0dccf05551cf0295178d7ff0f1b41eecb9db3ff219007c4e097260d58621bd"_sha3_384); 27 | } 28 | 29 | SECTION("hanicka") { 30 | const auto r0 = cthash::sha3_384().update("hanicka").final(); 31 | REQUIRE(r0 == "9c87cb0b9a8924030b93b4b3fd397c70030a57c6f98a051e0cc87d6d671e4da02e5fe4c6e8fe9d1ca46f085434092a99"_sha3_384); 32 | } 33 | 34 | SECTION("*136 characters (exactly block size)") { 35 | auto in = std::string(size_t(136), '*'); // size of block 36 | const auto r0 = cthash::sha3_384().update(in).final(); 37 | REQUIRE(r0 == "d86290cbc1abedee2f677b4938836ce984d8ddd955beefa2b421a55747ddcd3a2c5e5d0aae4e3173e92e2a2c80891980"_sha3_384); 38 | } 39 | 40 | SECTION("*137 characters (exactly block + 1 size)") { 41 | auto in = std::string(size_t(137), '*'); // size of block + 1 42 | const auto r0 = cthash::sha3_384().update(in).final(); 43 | REQUIRE(r0 == "23082738027c7f6aa5aaf64312869e586352ee0077aa246bb4ac7a9459210af9397af84160ee335f6585f86148a9d396"_sha3_384); 44 | } 45 | 46 | SECTION("*2500 characters") { 47 | auto in = std::string(size_t(2500), '*'); // size of block + 1 48 | const auto r0 = cthash::sha3_384().update(in).final(); 49 | REQUIRE(r0 == "2f5adba183a526a1c34e38575846001c5bc749c02af04beb6b0bd4bfc94f6f34ef1af3471fc438b28c78e652fc166129"_sha3_384); 50 | } 51 | 52 | SECTION("*2500 by one") { 53 | auto h = cthash::sha3_384(); 54 | for (int i = 0; i != 2500; ++i) { 55 | h.update("*"); 56 | } 57 | const auto r0 = h.final(); 58 | REQUIRE(r0 == "2f5adba183a526a1c34e38575846001c5bc749c02af04beb6b0bd4bfc94f6f34ef1af3471fc438b28c78e652fc166129"_sha3_384); 59 | } 60 | } 61 | 62 | TEST_CASE("sha3-384 stability") { 63 | auto h = cthash::sha3_384(); 64 | 65 | constexpr int end = int(h.rate) * 2; 66 | 67 | for (int i = 0; i != end; ++i) { 68 | const auto piece = std::string(size_t(i), '#'); 69 | h.update(piece); 70 | } 71 | 72 | const auto r0 = h.final(); 73 | REQUIRE(r0 == "83c6f40bf077d3f198ff2acc88eb2b82bab09bd9733e82fae081f7a50597160d02254357c352064a37104e8108d2d2bc"_sha3_384); 74 | } -------------------------------------------------------------------------------- /tests/sha3/sha3-512.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("sha3-512 basics") { 9 | const auto a = "5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be035891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03"_sha3_512; 10 | REQUIRE(a.size() == 512u / 8u); 11 | } 12 | 13 | TEST_CASE("sha3-512 test strings") { 14 | SECTION("empty") { 15 | const auto r0 = cthash::sha3_512().update("").final(); 16 | REQUIRE(r0 == "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"_sha3_512); 17 | } 18 | 19 | SECTION("empty with bytes") { 20 | const auto r0 = cthash::sha3_512().update(std::span()).final(); 21 | REQUIRE(r0 == "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"_sha3_512); 22 | } 23 | 24 | SECTION("test") { 25 | const auto r0 = cthash::sha3_512().update("test").final(); 26 | REQUIRE(r0 == "9ece086e9bac491fac5c1d1046ca11d737b92a2b2ebd93f005d7b710110c0a678288166e7fbe796883a4f2e9b3ca9f484f521d0ce464345cc1aec96779149c14"_sha3_512); 27 | } 28 | 29 | SECTION("hanicka") { 30 | const auto r0 = cthash::sha3_512().update("hanicka").final(); 31 | REQUIRE(r0 == "6d8826eec43e037dca9a7c92ffede543c067aa72d3aa55033f76f1789e0054a19f19f6636fc909744b85f26e334c77be8bea4cc70a520ca1ef6db88da98a9ecf"_sha3_512); 32 | } 33 | 34 | SECTION("*136 characters (exactly block size)") { 35 | auto in = std::string(size_t(136), '*'); // size of block 36 | const auto r0 = cthash::sha3_512().update(in).final(); 37 | REQUIRE(r0 == "0b5070207de47faf3fca6aa3c44cef2f79f970151f283d2a36857437002e0ae76543f3c5d9818d6341ea1562a4d2329e3d1a9f4dc821c792bc69e3b51aef76cc"_sha3_512); 38 | } 39 | 40 | SECTION("*137 characters (exactly block + 1 size)") { 41 | auto in = std::string(size_t(137), '*'); // size of block + 1 42 | const auto r0 = cthash::sha3_512().update(in).final(); 43 | REQUIRE(r0 == "844698f1032311721397d3189cfcfcb7199bc1309bc87bc20223cf6b7d27100dd37d21fde6557994aa330c0f493fc09eb600cbe0a8a6c63477d5f7a36077eb8b"_sha3_512); 44 | } 45 | 46 | SECTION("*2500 characters") { 47 | auto in = std::string(size_t(2500), '*'); // size of block + 1 48 | const auto r0 = cthash::sha3_512().update(in).final(); 49 | REQUIRE(r0 == "e4163add44fed59d52141fe016088b98a9716e0fde36c9f0fce75937414bdcb8b4211d1909a5ccd7f32df8af6d991a7fe1f65238e6da7e591d946b289b6b0a49"_sha3_512); 50 | } 51 | 52 | SECTION("*2500 by one") { 53 | const auto star = std::string_view{"*"}; 54 | REQUIRE(star.size() == 1u); 55 | auto h = cthash::sha3_512(); 56 | for (int i = 0; i != 2500; ++i) { 57 | h.update(star); 58 | } 59 | const auto r0 = h.final(); 60 | REQUIRE(r0 == "e4163add44fed59d52141fe016088b98a9716e0fde36c9f0fce75937414bdcb8b4211d1909a5ccd7f32df8af6d991a7fe1f65238e6da7e591d946b289b6b0a49"_sha3_512); 61 | } 62 | } 63 | 64 | TEST_CASE("sha3-512 stability") { 65 | auto h = cthash::sha3_512(); 66 | 67 | constexpr int end = int(h.rate) * 2; 68 | 69 | for (int i = 0; i != end; ++i) { 70 | const auto piece = std::string(size_t(i), '#'); 71 | h.update(piece); 72 | } 73 | 74 | const auto r0 = h.final(); 75 | REQUIRE(r0 == "62a8487cf7d35dd2688962c80581436171c93c7250da289944ac95abd597baa12cca5c022a19addfaaae48f144da2e6dd9f24c02c63c8ca25bb3fc288277179c"_sha3_512); 76 | } -------------------------------------------------------------------------------- /tests/sha3/shake128.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("shake128 literal basics") { 9 | const auto a = "1234"_shake128; 10 | REQUIRE(a.size() == 2u); 11 | 12 | const auto b = "12345678"_shake128; 13 | REQUIRE(b.size() == 4u); 14 | 15 | const auto c = "1234567890abcdef"_shake128; 16 | REQUIRE(c.size() == 8u); 17 | 18 | const auto d = "1234567800000000"_shake128; 19 | REQUIRE(d.size() == 8u); 20 | 21 | REQUIRE(a == b); 22 | REQUIRE(a == c); 23 | 24 | REQUIRE(a == d); 25 | REQUIRE(b == d); 26 | 27 | REQUIRE(c != d); 28 | 29 | REQUIRE((a <=> b) == 0); 30 | REQUIRE((a <=> c) == 0); 31 | } 32 | 33 | TEST_CASE("shake128 calculation") { 34 | const auto expected = "f4202e3c5852f9182a0430fd8144f0a74b95e7417ecae17db0f8cfeed0e3e66eb5585ec6f86021cacf272c798bcf97d368b886b18fec3a571f096086a523717a3732d50db2b0b7998b4117ae66a761ccf1847a1616f4c07d5178d0d965f9feba351420f8bfb6f5ab9a0cb102568eabf3dfa4e22279f8082dce8143eb78235a1a54914ab71abb07f2f3648468370b9fbb071e074f1c030a4030225f40c39480339f3dc71d0f04f71326de1381674cc89e259e219927fae8ea2799a03da862a55afafe670957a2af3318d919d0a3358f3b891236d6a8e8d19999d1076b529968faefbd880d77bb300829dca87e9c8e4c28e0800ff37490a5bd8c36c0b0bdb2701a"_shake128; 35 | 36 | SECTION("16 bits") { 37 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dog").final<16>(); 38 | 39 | REQUIRE(r0 == expected); 40 | } 41 | 42 | SECTION("32 bits") { 43 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dog").final<32>(); 44 | 45 | REQUIRE(r0 == expected); 46 | } 47 | 48 | SECTION("64 bits") { 49 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dog").final<64>(); 50 | 51 | REQUIRE(r0 == expected); 52 | } 53 | 54 | SECTION("128 bits") { 55 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dog").final<128>(); 56 | 57 | REQUIRE(r0 == expected); 58 | } 59 | 60 | SECTION("256 bits") { 61 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dog").final<256>(); 62 | 63 | REQUIRE(r0 == expected); 64 | } 65 | 66 | SECTION("2048 bits") { 67 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dog").final<2048>(); 68 | 69 | REQUIRE(r0 == expected); 70 | } 71 | } 72 | 73 | TEST_CASE("shake128 calculation (b)") { 74 | const auto expected = "853f4538be0db9621a6cea659a06c1107b1f83f02b13d18297bd39d7411cf10c79229b22a2d29332019fca1dde63ad893e9b2fb2cf1e710e591a7dfaab201f528373514e015d872edb70b59eb04480dc669851e9f72272e33e382701575e9cd0a3247ffd784d968801c3e40bf9c0ec3b118e838329d89f16a081a1201e8350f5c839c846ec0262a6dec85450e0b350786b2e47b93de4f9a566b5220300d19cb9783af4a6242c19e36881cbcf328e5419009af9906634c37a37fecb35b8a96476a7e3fae1be94b90a9a635fac947bf633f5280d580e571ec3b019086e8166fcceb2478a2834ce35651b662be28382ceb1b5f6f6f7263c57037e58336fd1c354bb"_shake128; 75 | 76 | SECTION("16 bits") { 77 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dof").final<16>(); 78 | 79 | REQUIRE(r0 == expected); 80 | } 81 | 82 | SECTION("32 bits") { 83 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dof").final<32>(); 84 | 85 | REQUIRE(r0 == expected); 86 | } 87 | 88 | SECTION("64 bits") { 89 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dof").final<64>(); 90 | 91 | REQUIRE(r0 == expected); 92 | } 93 | 94 | SECTION("128 bits") { 95 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dof").final<128>(); 96 | 97 | REQUIRE(r0 == expected); 98 | } 99 | 100 | SECTION("256 bits") { 101 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dof").final<256>(); 102 | 103 | REQUIRE(r0 == expected); 104 | } 105 | 106 | SECTION("2048 bits") { 107 | auto r0 = cthash::shake128().update("The quick brown fox jumps over the lazy dof").final<2048>(); 108 | 109 | REQUIRE(r0 == expected); 110 | } 111 | } -------------------------------------------------------------------------------- /tests/sha3/shake256.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("shake256 literal basics") { 9 | const auto a = "1234"_shake256; 10 | REQUIRE(a.size() == 2u); 11 | 12 | const auto b = "12345678"_shake256; 13 | REQUIRE(b.size() == 4u); 14 | 15 | const auto c = "1234567890abcdef"_shake256; 16 | REQUIRE(c.size() == 8u); 17 | 18 | REQUIRE(a == b); 19 | REQUIRE(a == c); 20 | 21 | REQUIRE((a <=> b) == 0); 22 | REQUIRE((a <=> c) == 0); 23 | } 24 | 25 | TEST_CASE("shake256 calculation") { 26 | const auto expected = "2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca1d01d1369a23539cd80f7c054b6e5daf9c962cad5b8ed5bd11998b40d5734442bed798f6e5c915bd8bb07e0188d0a55c1290074f1c287af06352299184492cbdec9acba737ee292e5adaa445547355e72a03a3bac3aac770fe5d6b66600ff15d37d5b4789994ea2aeb097f550aa5e88e4d8ff0ba07b88c1c88573063f5d96df820abc2abd177ab037f351c375e553af917132cf2f563c79a619e1bb76e8e2266b0c5617d695f2c496a25f4073b6840c1833757ebb386f16757a8e16a21e9355e9b248f3b33be672da700266be99b8f8725e8ab06075f0219e655ebc188976364"_shake256; 27 | 28 | SECTION("16 bits") { 29 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dog").final<16>(); 30 | 31 | REQUIRE(r0 == expected); 32 | } 33 | 34 | SECTION("32 bits") { 35 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dog").final<32>(); 36 | 37 | REQUIRE(r0 == expected); 38 | } 39 | 40 | SECTION("64 bits") { 41 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dog").final<64>(); 42 | 43 | REQUIRE(r0 == expected); 44 | } 45 | 46 | SECTION("128 bits") { 47 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dog").final<128>(); 48 | 49 | REQUIRE(r0 == expected); 50 | } 51 | 52 | SECTION("256 bits") { 53 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dog").final<256>(); 54 | 55 | REQUIRE(r0 == expected); 56 | } 57 | 58 | SECTION("2048 bits") { 59 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dog").final<2048>(); 60 | 61 | REQUIRE(r0 == expected); 62 | } 63 | } 64 | 65 | TEST_CASE("shake256 calculation (b)") { 66 | const auto expected = "46b1ebb2e142c38b9ac9081bef72877fe4723959640fa57119b366ce6899d4013af024f4222921320bee7d3bfaba07a758cd0fde5d27bbd2f8d709f4307d2c34a0baacb6f2ca73e5bdfe951c4f6f80ccf14a216c17512129d7afdccbc31aee975c41c66c24a2367820d2d5914fab194fea6b5749372aabf0276c3424d3145ec41645053272fe036dd13daab3b80e959290e885838a5e57a509d2785e99f83ce3efd810959d2a97f0e244a1b8382405ca3d6673f382054794f74d73af2765452442e72e6d199fe83ecf663cc6a14b57b2f16ccf3a83a613e7475c4b0761711e216e68051ca97c3b6cc9a91e35d442506443599f42921bba9558c62a5fdcf1ea42"_shake256; 67 | 68 | SECTION("16 bits") { 69 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dof").final<16>(); 70 | 71 | REQUIRE(r0 == expected); 72 | } 73 | 74 | SECTION("32 bits") { 75 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dof").final<32>(); 76 | 77 | REQUIRE(r0 == expected); 78 | } 79 | 80 | SECTION("64 bits") { 81 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dof").final<64>(); 82 | 83 | REQUIRE(r0 == expected); 84 | } 85 | 86 | SECTION("128 bits") { 87 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dof").final<128>(); 88 | 89 | REQUIRE(r0 == expected); 90 | } 91 | 92 | SECTION("256 bits") { 93 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dof").final<256>(); 94 | 95 | REQUIRE(r0 == expected); 96 | } 97 | 98 | SECTION("2048 bits") { 99 | auto r0 = cthash::shake256().update("The quick brown fox jumps over the lazy dof").final<2048>(); 100 | 101 | REQUIRE(r0 == expected); 102 | } 103 | } -------------------------------------------------------------------------------- /tests/value.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace cthash::literals; 6 | 7 | TEST_CASE("hash_value (constexpr basics)") { 8 | constexpr auto v1 = cthash::hash_value{"0011223300112233"}; 9 | constexpr auto v2 = cthash::hash_value{"00112233aabbccdd"}; 10 | 11 | STATIC_REQUIRE((v1 <=> v1) == 0); // appleclang doesn't have std::is_eq 12 | STATIC_REQUIRE(v1 == v1); 13 | STATIC_REQUIRE(v1 < v2); 14 | STATIC_REQUIRE(v2 > v1); 15 | STATIC_REQUIRE(v1 != v2); 16 | 17 | constexpr auto v3 = cthash::hash_value{u8"00112233aabbccdd"}; 18 | 19 | STATIC_REQUIRE(v1 != v2); 20 | STATIC_REQUIRE(v2 == v3); 21 | 22 | [[maybe_unused]] constexpr auto v4 = "599ba25a0d7c7d671bee93172ca7e272fc87f0c0e02e44df9e9436819067ea28"_hash; 23 | constexpr auto v5 = "00112233aabbccdd"_hash; 24 | 25 | STATIC_REQUIRE(v5 == v3); 26 | 27 | // constexpr bool comparable = requires(cthash::hash_value<8> l, cthash::hash_value<4> r) { v1 == v2; }; 28 | } 29 | 30 | TEST_CASE("hash_value (runtime basics)") { 31 | auto v1 = cthash::hash_value{"0011223300112233"}; 32 | auto v2 = cthash::hash_value{"00112233aabbccdd"}; 33 | 34 | REQUIRE((v1 <=> v1) == 0); // appleclang doesn't have std::is_eq 35 | REQUIRE(v1 == v1); 36 | REQUIRE(v1 < v2); 37 | REQUIRE(v2 > v1); 38 | REQUIRE(v1 != v2); 39 | 40 | auto v3 = cthash::hash_value{u8"00112233aabbccdd"}; 41 | 42 | REQUIRE(v1 != v2); 43 | REQUIRE(v2 == v3); 44 | 45 | [[maybe_unused]] auto v4 = "599ba25a0d7c7d671bee93172ca7e272fc87f0c0e02e44df9e9436819067ea28"_hash; 46 | auto v5 = "00112233aabbccdd"_hash; 47 | 48 | REQUIRE(v5 == v3); 49 | 50 | // constexpr bool comparable = requires(cthash::hash_value<8> l, cthash::hash_value<4> r) { v1 == v2; }; 51 | } 52 | 53 | auto convert_to_string(auto && val) { 54 | std::ostringstream os; 55 | os << val; 56 | return std::move(os).str(); 57 | } 58 | 59 | TEST_CASE("hash stringification") { 60 | auto v1 = cthash::hash_value{"00112233aabbccdd"}; 61 | REQUIRE(convert_to_string(v1) == "00112233aabbccdd"); 62 | } 63 | -------------------------------------------------------------------------------- /tests/xxhash/basics.cpp: -------------------------------------------------------------------------------- 1 | #include "../internal/support.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cthash::literals; 7 | 8 | TEST_CASE("xxhash update", "[xxh-basic]") { 9 | const auto arr = array_of<32>(std::byte(0xEF)); 10 | 11 | cthash::xxhash<32> h{}; 12 | 13 | // IV 14 | REQUIRE(h.seed == 0u); 15 | REQUIRE(h.internal_state[0] == cthash::xxhash_types<32>::primes[0] + cthash::xxhash_types<32>::primes[1]); 16 | REQUIRE(h.internal_state[1] == cthash::xxhash_types<32>::primes[1]); 17 | REQUIRE(h.internal_state[2] == 0u); 18 | REQUIRE(h.internal_state[3] == 0u - cthash::xxhash_types<32>::primes[0]); 19 | 20 | REQUIRE(h.length == 0u); 21 | REQUIRE(h.buffer_usage() == 0u); 22 | 23 | // process 24 | h.update(std::span(arr).first(1)); 25 | REQUIRE(h.length == 1u); 26 | REQUIRE(h.buffer_usage() == 1u); 27 | 28 | REQUIRE(h.buffer.size() == 16u); 29 | REQUIRE(unsigned(h.buffer[0]) == 0xEFu); 30 | for (int i = 1; i != h.buffer.size(); ++i) { 31 | REQUIRE(unsigned(h.buffer[static_cast(i)]) == 0u); 32 | } 33 | 34 | h.update(std::span(arr).first(1)); 35 | REQUIRE(h.length == 2u); 36 | REQUIRE(h.buffer_usage() == 2u); 37 | 38 | REQUIRE(unsigned(h.buffer[0]) == 0xEFu); 39 | REQUIRE(unsigned(h.buffer[1]) == 0xEFu); 40 | for (int i = 2; i != h.buffer.size(); ++i) { 41 | REQUIRE(unsigned(h.buffer[static_cast(i)]) == 0u); 42 | } 43 | 44 | h.update(std::span(arr).first(14)); 45 | REQUIRE(h.length == 16u); 46 | for (int i = 0; i != h.buffer.size(); ++i) { 47 | REQUIRE(unsigned(h.buffer[static_cast(i)]) == 0xEFu); 48 | } 49 | REQUIRE(h.buffer_usage() == 0u); 50 | 51 | // buffer is untouched 52 | REQUIRE(cthash::get_le_number_from(std::span(h.buffer)) == 0xEFEFEFEFu); 53 | REQUIRE(cthash::get_le_number_from(std::span(h.buffer)) == 0xEFEFEFEFu); 54 | REQUIRE(cthash::get_le_number_from(std::span(h.buffer)) == 0xEFEFEFEFu); 55 | REQUIRE(cthash::get_le_number_from(std::span(h.buffer)) == 0xEFEFEFEFu); 56 | 57 | // first step should be called here, so internal state is different than it was 58 | REQUIRE(h.internal_state[0] == 0x659373acu); 59 | REQUIRE(h.internal_state[1] == 0x6015b815u); 60 | REQUIRE(h.internal_state[2] == 0xd21cf068u); 61 | REQUIRE(h.internal_state[3] == 0xcc9f34d1u); 62 | 63 | // additional block 64 | h.update(std::span(arr).first(16)); 65 | REQUIRE(h.length == 32u); 66 | for (int i = 0; i != h.buffer.size(); ++i) { 67 | REQUIRE(unsigned(h.buffer[static_cast(i)]) == 0xEFu); 68 | } 69 | REQUIRE(h.buffer_usage() == 0u); 70 | 71 | REQUIRE(h.internal_state[0] == 0xd721597au); 72 | REQUIRE(h.internal_state[1] == 0xceb0cfcau); 73 | REQUIRE(h.internal_state[2] == 0x59c4a3bbu); 74 | REQUIRE(h.internal_state[3] == 0x51541a0bu); 75 | 76 | SECTION("stop now") { 77 | const auto c = h.converge_conditionaly(); 78 | REQUIRE(c == 0xb9139348u); 79 | const auto len = c + h.length; 80 | REQUIRE(len == 0xb9139368u); 81 | const auto cons = decltype(h)::config::consume_remaining(len, std::span(h.buffer).first(h.buffer_usage())); 82 | REQUIRE(cons == 0xb9139368u); 83 | const auto aval = decltype(h)::config::avalanche(cons); 84 | REQUIRE(aval == 0xbea54e50u); 85 | REQUIRE(h.final() == "bea54e50"_xxh32); 86 | } 87 | 88 | SECTION("continue") { 89 | // additional block 2 90 | const auto arr2 = array_of<32>(std::byte(0xAB)); 91 | REQUIRE(h.buffer_usage() == 0u); 92 | h.update(std::span(arr2).first(20)); 93 | REQUIRE(h.length == 52u); 94 | REQUIRE(h.buffer_usage() == 4u); 95 | REQUIRE(unsigned(h.buffer[0]) == 0xABu); 96 | REQUIRE(unsigned(h.buffer[1]) == 0xABu); 97 | REQUIRE(unsigned(h.buffer[2]) == 0xABu); 98 | REQUIRE(unsigned(h.buffer[3]) == 0xABu); 99 | 100 | REQUIRE(h.internal_state[0] == 0x3f316f5bu); 101 | REQUIRE(h.internal_state[1] == 0xf45916adu); 102 | REQUIRE(h.internal_state[2] == 0x73c86d6fu); 103 | REQUIRE(h.internal_state[3] == 0x28f014c1u); 104 | 105 | SECTION("finish") { 106 | const auto c = h.converge_conditionaly(); 107 | REQUIRE(c == 0x84c9d0acu); 108 | const auto len = c + h.length; 109 | REQUIRE(len == 0x84c9d0e0u); 110 | const auto cons = decltype(h)::config::consume_remaining(len, std::span(h.buffer).first(h.buffer_usage())); 111 | REQUIRE(cons == 0xeab6d685u); 112 | const auto aval = decltype(h)::config::avalanche(cons); 113 | REQUIRE(aval == 0x78c3c388u); 114 | REQUIRE(h.final() == "78c3c388"_xxh32); 115 | } 116 | 117 | // const auto iv3 = h.internal_state; 118 | } 119 | } 120 | 121 | TEST_CASE("xxhash_fnc basics", "[xxh]") { 122 | SECTION("empty string") { 123 | const std::string_view empty = ""; 124 | 125 | // REQUIRE(cthash::xxhash<32>{}.update(empty).final() == "02cc5d05"_xxh32); 126 | // REQUIRE(cthash::xxhash<64>{}.update(empty).final() == "ef46db3751d8e999"_xxh64); 127 | 128 | REQUIRE(cthash::simple>(empty, 0u) == "02cc5d05"_xxh32); 129 | REQUIRE(cthash::simple>(empty, 0u) == "ef46db3751d8e999"_xxh64); 130 | 131 | REQUIRE(cthash::simple>(empty, 42u) == "d5be6eb8"_xxh32); 132 | REQUIRE(cthash::simple>(empty, 42u) == "98b1582b0977e704"_xxh64); 133 | } 134 | 135 | SECTION("empty string") { 136 | const std::string_view in = "hello there"; 137 | 138 | REQUIRE(cthash::simple>(in, 0u) == "371c3e72"_xxh32); 139 | REQUIRE(cthash::simple>(in, 0u) == "08f296af889a203c"_xxh64); 140 | 141 | REQUIRE(cthash::simple>(in, 42u) == "4a90b3c2"_xxh32); 142 | REQUIRE(cthash::simple>(in, 42u) == "1a910e9618a06c28"_xxh64); 143 | } 144 | 145 | SECTION("longer string") { 146 | const std::string_view in = "hello there, from somehow long string! really this should be enought :)"; 147 | 148 | REQUIRE(cthash::simple>(in, 0u) == "2daeaacd"_xxh32); 149 | REQUIRE(cthash::simple>(in, 0u) == "4f6f14232e5ab579"_xxh64); 150 | 151 | REQUIRE(cthash::simple>(in, 42u) == "b66e8e53"_xxh32); 152 | REQUIRE(cthash::simple>(in, 42u) == "62eee52b8dbf7af9"_xxh64); 153 | } 154 | 155 | SECTION("longer string via multiple update") { 156 | cthash::xxhash<32> h1{}; 157 | cthash::xxhash<64> h2{}; 158 | 159 | h1.update("hello there, ").update("from somehow long string!").update(" really this should be enought :)"); 160 | h2.update("hello there, ").update("from somehow long string!").update(" really this should be enought :)"); 161 | 162 | SECTION("32 bits") { 163 | REQUIRE(h1.internal_state[0] == 0x2c7844f7u); 164 | REQUIRE(h1.internal_state[1] == 0xdf8adc4fu); 165 | REQUIRE(h1.internal_state[2] == 0x502598e7u); 166 | REQUIRE(h1.internal_state[3] == 0x032d3506u); 167 | 168 | REQUIRE(h1.final() == "2daeaacd"_xxh32); 169 | } 170 | 171 | SECTION("64 bits") { 172 | REQUIRE(h2.final() == "4f6f14232e5ab579"_xxh64); 173 | } 174 | } 175 | 176 | SECTION("longer string") { 177 | const std::string_view lit = "hello there, from somehow long string! really this should be enought :)"; 178 | 179 | cthash::xxhash<32> h1{}; 180 | cthash::xxhash<64> h2{}; 181 | 182 | for (int i = 0; i != 1000; ++i) { 183 | h1.update(lit); 184 | h2.update(lit); 185 | } 186 | 187 | SECTION("32 bits") { 188 | REQUIRE(h1.final() == "a7d7a81d"_xxh32); 189 | } 190 | 191 | SECTION("64 bits") { 192 | REQUIRE(h2.final() == "bd6f22acc408272d"_xxh64); 193 | } 194 | } 195 | } 196 | 197 | TEST_CASE("xxhash_fnc benchmarks", "[xxh]") { 198 | auto val = std::string(10u * 1024u * 1024u, '*'); 199 | 200 | BENCHMARK("really long string (32bit) (10MB)") { 201 | return cthash::simple>(std::string_view(val)); 202 | }; 203 | 204 | BENCHMARK("really long string (64bit) (10MB)") { 205 | return cthash::simple>(std::string_view(val)); 206 | }; 207 | 208 | auto val2 = std::string(1024u * 1024u * 1024u, '*'); 209 | 210 | BENCHMARK("really long string (32bit) (1GB)") { 211 | return cthash::simple>(std::string_view(val2)); 212 | }; 213 | 214 | BENCHMARK("really long string (64bit) (1GB)") { 215 | return cthash::simple>(std::string_view(val2)); 216 | }; 217 | } --------------------------------------------------------------------------------